Skip to content

Rollup of 6 pull requests #142689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::snippet::{
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
};
use crate::styled_buffer::StyledBuffer;
use crate::timings::TimingRecord;
use crate::translation::{Translate, to_fluent_args};
use crate::{
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
Expand Down Expand Up @@ -164,11 +165,16 @@ impl Margin {
}
}

pub enum TimingEvent {
Start,
End,
}

const ANONYMIZED_LINE_NUM: &str = "LL";

pub type DynEmitter = dyn Emitter + DynSend;

/// Emitter trait for emitting errors.
/// Emitter trait for emitting errors and other structured information.
pub trait Emitter: Translate {
/// Emit a structured diagnostic.
fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry);
Expand All @@ -177,6 +183,10 @@ pub trait Emitter: Translate {
/// Currently only supported for the JSON format.
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}

/// Emit a timestamp with start/end of a timing section.
/// Currently only supported for the JSON format.
fn emit_timing_section(&mut self, _record: TimingRecord, _event: TimingEvent) {}

/// Emit a report about future breakage.
/// Currently only supported for the JSON format.
fn emit_future_breakage_report(&mut self, _diags: Vec<DiagInner>, _registry: &Registry) {}
Expand Down
29 changes: 28 additions & 1 deletion compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ use termcolor::{ColorSpec, WriteColor};
use crate::diagnostic::IsLint;
use crate::emitter::{
ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme,
should_show_source_code,
TimingEvent, should_show_source_code,
};
use crate::registry::Registry;
use crate::timings::{TimingRecord, TimingSection};
use crate::translation::{Translate, to_fluent_args};
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions,
Expand Down Expand Up @@ -104,6 +105,7 @@ impl JsonEmitter {
enum EmitTyped<'a> {
Diagnostic(Diagnostic),
Artifact(ArtifactNotification<'a>),
SectionTiming(SectionTimestamp<'a>),
FutureIncompat(FutureIncompatReport<'a>),
UnusedExtern(UnusedExterns<'a>),
}
Expand Down Expand Up @@ -135,6 +137,21 @@ impl Emitter for JsonEmitter {
}
}

fn emit_timing_section(&mut self, record: TimingRecord, event: TimingEvent) {
let event = match event {
TimingEvent::Start => "start",
TimingEvent::End => "end",
};
let name = match record.section {
TimingSection::Linking => "link",
};
let data = SectionTimestamp { name, event, timestamp: record.timestamp };
let result = self.emit(EmitTyped::SectionTiming(data));
if let Err(e) = result {
panic!("failed to print timing section: {e:?}");
}
}

fn emit_future_breakage_report(&mut self, diags: Vec<crate::DiagInner>, registry: &Registry) {
let data: Vec<FutureBreakageItem<'_>> = diags
.into_iter()
Expand Down Expand Up @@ -263,6 +280,16 @@ struct ArtifactNotification<'a> {
emit: &'a str,
}

#[derive(Serialize)]
struct SectionTimestamp<'a> {
/// Name of the section
name: &'a str,
/// Start/end of the section
event: &'a str,
/// Opaque timestamp.
timestamp: u128,
}

#[derive(Serialize)]
struct FutureBreakageItem<'a> {
// Always EmitTyped::Diagnostic, but we want to make sure it gets serialized
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(array_windows)]
Expand Down Expand Up @@ -74,7 +75,9 @@ pub use snippet::Style;
pub use termcolor::{Color, ColorSpec, WriteColor};
use tracing::debug;

use crate::emitter::TimingEvent;
use crate::registry::Registry;
use crate::timings::TimingRecord;

pub mod annotate_snippet_emitter_writer;
pub mod codes;
Expand All @@ -90,6 +93,7 @@ mod snippet;
mod styled_buffer;
#[cfg(test)]
mod tests;
pub mod timings;
pub mod translation;

pub type PResult<'a, T> = Result<T, Diag<'a>>;
Expand Down Expand Up @@ -1156,6 +1160,14 @@ impl<'a> DiagCtxtHandle<'a> {
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
}

pub fn emit_timing_section_start(&self, record: TimingRecord) {
self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
}

pub fn emit_timing_section_end(&self, record: TimingRecord) {
self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
}

pub fn emit_future_breakage_report(&self) {
let inner = &mut *self.inner.borrow_mut();
let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
Expand Down
80 changes: 80 additions & 0 deletions compiler/rustc_errors/src/timings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::time::Instant;

use crate::DiagCtxtHandle;

/// A high-level section of the compilation process.
#[derive(Copy, Clone, Debug)]
pub enum TimingSection {
/// Time spent linking.
Linking,
}

/// Section with attached timestamp
#[derive(Copy, Clone, Debug)]
pub struct TimingRecord {
pub section: TimingSection,
/// Microseconds elapsed since some predetermined point in time (~start of the rustc process).
pub timestamp: u128,
}

impl TimingRecord {
fn from_origin(origin: Instant, section: TimingSection) -> Self {
Self { section, timestamp: Instant::now().duration_since(origin).as_micros() }
}

pub fn section(&self) -> TimingSection {
self.section
}

pub fn timestamp(&self) -> u128 {
self.timestamp
}
}

/// Manages emission of start/end section timings, enabled through `--json=timings`.
pub struct TimingSectionHandler {
/// Time when the compilation session started.
/// If `None`, timing is disabled.
origin: Option<Instant>,
}

impl TimingSectionHandler {
pub fn new(enabled: bool) -> Self {
let origin = if enabled { Some(Instant::now()) } else { None };
Self { origin }
}

/// Returns a RAII guard that will immediately emit a start the provided section, and then emit
/// its end when it is dropped.
pub fn start_section<'a>(
&self,
diag_ctxt: DiagCtxtHandle<'a>,
section: TimingSection,
) -> TimingSectionGuard<'a> {
TimingSectionGuard::create(diag_ctxt, section, self.origin)
}
}

/// RAII wrapper for starting and ending section timings.
pub struct TimingSectionGuard<'a> {
dcx: DiagCtxtHandle<'a>,
section: TimingSection,
origin: Option<Instant>,
}

impl<'a> TimingSectionGuard<'a> {
fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, origin: Option<Instant>) -> Self {
if let Some(origin) = origin {
dcx.emit_timing_section_start(TimingRecord::from_origin(origin, section));
}
Self { dcx, section, origin }
}
}

impl<'a> Drop for TimingSectionGuard<'a> {
fn drop(&mut self) {
if let Some(origin) = self.origin {
self.dcx.emit_timing_section_end(TimingRecord::from_origin(origin, self.section));
}
}
}
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_interface/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::Arc;
use rustc_codegen_ssa::CodegenResults;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::svh::Svh;
use rustc_errors::timings::TimingSection;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::DepGraph;
Expand Down Expand Up @@ -88,6 +89,7 @@ impl Linker {
}

let _timer = sess.prof.verbose_generic_activity("link_crate");
let _timing = sess.timings.start_section(sess.dcx(), TimingSection::Linking);
codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames)
}
}
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(force_unstable_if_unmarked, true);
tracked!(function_return, FunctionReturn::ThunkExtern);
tracked!(function_sections, Some(false));
tracked!(hint_mostly_unused, true);
tracked!(human_readable_cgu_names, true);
tracked!(incremental_ignore_spans, true);
tracked!(inline_mir, Some(true));
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,9 @@ lint_tykind = usage of `ty::TyKind`
lint_tykind_kind = usage of `ty::TyKind::<kind>`
.suggestion = try using `ty::<kind>` directly
lint_type_ir_direct_use = do not use `rustc_type_ir` unless you are implementing type system internals
.note = use `rustc_middle::ty` instead
lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're inside of the trait solver
.note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler
Expand Down
31 changes: 28 additions & 3 deletions compiler/rustc_lint/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use {rustc_ast as ast, rustc_hir as hir};
use crate::lints::{
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand,
NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag,
SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrInherentUsage,
TypeIrTraitUsage, UntranslatableDiag,
SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
TypeIrInherentUsage, TypeIrTraitUsage, UntranslatableDiag,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};

Expand Down Expand Up @@ -301,8 +301,18 @@ declare_tool_lint! {
"usage `rustc_type_ir`-specific abstraction traits outside of trait system",
report_in_external_macro: true
}
declare_tool_lint! {
/// The `direct_use_of_rustc_type_ir` lint detects usage of `rustc_type_ir`.
///
/// This module should only be used within the trait solver and some desirable
/// crates like rustc_middle.
pub rustc::DIRECT_USE_OF_RUSTC_TYPE_IR,
Allow,
"usage `rustc_type_ir` abstraction outside of trait system",
report_in_external_macro: true
}

declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]);
declare_lint_pass!(TypeIr => [DIRECT_USE_OF_RUSTC_TYPE_IR, NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]);

impl<'tcx> LateLintPass<'tcx> for TypeIr {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
Expand Down Expand Up @@ -372,6 +382,21 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr {
NonGlobImportTypeIrInherent { suggestion: lo.eq_ctxt(hi).then(|| lo.to(hi)), snippet },
);
}

fn check_path(
&mut self,
cx: &LateContext<'tcx>,
path: &rustc_hir::Path<'tcx>,
_: rustc_hir::HirId,
) {
if let Some(seg) = path.segments.iter().find(|seg| {
seg.res
.opt_def_id()
.is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir, def_id))
}) {
cx.emit_span_lint(DIRECT_USE_OF_RUSTC_TYPE_IR, seg.ident.span, TypeIrDirectUse);
}
}
}

declare_tool_lint! {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ fn register_internals(store: &mut LintStore) {
LintId::of(USAGE_OF_TYPE_IR_TRAITS),
LintId::of(BAD_OPT_ACCESS),
LintId::of(SPAN_USE_EQ_CTXT),
LintId::of(DIRECT_USE_OF_RUSTC_TYPE_IR),
],
);
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,11 @@ pub(crate) struct TypeIrInherentUsage;
#[note]
pub(crate) struct TypeIrTraitUsage;

#[derive(LintDiagnostic)]
#[diag(lint_type_ir_direct_use)]
#[note]
pub(crate) struct TypeIrDirectUse;

#[derive(LintDiagnostic)]
#[diag(lint_non_glob_import_type_ir_inherent)]
pub(crate) struct NonGlobImportTypeIrInherent {
Expand Down
Loading