Skip to content

Migrate rustc_monomorphize to use SessionDiagnostic #100730

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 9 commits into from
Aug 31, 2022
Merged
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
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -4253,8 +4253,10 @@ name = "rustc_monomorphize"
version = "0.0.0"
dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_middle",
"rustc_session",
"rustc_span",
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
@@ -925,8 +925,11 @@ pub(crate) fn codegen_panic_inner<'tcx>(
args: &[Value],
span: Span,
) {
let def_id =
fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
let def_id = fx
.tcx
.lang_items()
.require(lang_item)
.unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string()));

let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
let symbol_name = fx.tcx.symbol_name(instance).name;
26 changes: 26 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
monomorphize_recursion_limit =
reached the recursion limit while instantiating `{$shrunk}`
.note = `{$def_path_str}` defined here

monomorphize_written_to_path = the full type name has been written to '{$path}'

monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`

monomorphize_consider_type_length_limit =
consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate

monomorphize_fatal_error = {$error_message}

monomorphize_unknown_partition_strategy = unknown partitioning strategy

monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined

monomorphize_unused_generic_params = item has unused generic parameters

monomorphize_large_assignments =
moving {$size} bytes
.label = value moved from here
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`

monomorphize_requires_lang_item =
requires `{$lang_item}` lang_item
1 change: 1 addition & 0 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ fluent_messages! {
expand => "../locales/en-US/expand.ftl",
interface => "../locales/en-US/interface.ftl",
lint => "../locales/en-US/lint.ftl",
monomorphize => "../locales/en-US/monomorphize.ftl",
parser => "../locales/en-US/parser.ftl",
passes => "../locales/en-US/passes.ftl",
plugin_impl => "../locales/en-US/plugin_impl.ftl",
10 changes: 10 additions & 0 deletions compiler/rustc_hir/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::LangItem;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct LangItemError(pub LangItem);

impl ToString for LangItemError {
fn to_string(&self) -> String {
format!("requires `{}` lang_item", self.0.name())
}
}
7 changes: 4 additions & 3 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
//! * Functions called by the compiler itself.

use crate::def_id::DefId;
use crate::errors::LangItemError;
use crate::{MethodKind, Target};

use rustc_ast as ast;
@@ -115,9 +116,9 @@ macro_rules! language_item_table {

/// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
/// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
/// returns an error message as a string.
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
/// returns an error encapsulating the `LangItem`.
pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
self.items[it as usize].ok_or_else(|| LangItemError(it))
}

/// Returns the [`DefId`]s of all lang items in a group.
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ pub mod def;
pub mod def_path_hash_map;
pub mod definitions;
pub mod diagnostic_items;
pub mod errors;
pub use rustc_span::def_id;
mod hir;
pub mod hir_id;
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/middle/lang_items.rs
Original file line number Diff line number Diff line change
@@ -18,11 +18,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns the `DefId` for a given `LangItem`.
/// If not found, fatally aborts compilation.
pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
self.lang_items().require(lang_item).unwrap_or_else(|msg| {
self.lang_items().require(lang_item).unwrap_or_else(|err| {
if let Some(span) = span {
self.sess.span_fatal(span, &msg)
self.sess.span_fatal(span, err.to_string())
} else {
self.sess.fatal(&msg)
self.sess.fatal(err.to_string())
}
})
}
4 changes: 3 additions & 1 deletion compiler/rustc_monomorphize/Cargo.toml
Original file line number Diff line number Diff line change
@@ -7,11 +7,13 @@ edition = "2021"
doctest = false

[dependencies]
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
tracing = "0.1"
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
67 changes: 39 additions & 28 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
@@ -207,6 +207,8 @@ use std::iter;
use std::ops::Range;
use std::path::PathBuf;

use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit};

#[derive(PartialEq)]
pub enum MonoItemCollectionMode {
Eager,
@@ -604,17 +606,24 @@ fn check_recursion_limit<'tcx>(
// more than the recursion limit is assumed to be causing an
// infinite expansion.
if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
let def_span = tcx.def_span(def_id);
let def_path_str = tcx.def_path_str(def_id);
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
let mut err = tcx.sess.struct_span_fatal(span, &error);
err.span_note(
tcx.def_span(def_id),
&format!("`{}` defined here", tcx.def_path_str(def_id)),
);
if let Some(path) = written_to_path {
err.note(&format!("the full type name has been written to '{}'", path.display()));
}
err.emit()
let mut path = PathBuf::new();
let was_written = if written_to_path.is_some() {
path = written_to_path.unwrap();
Some(())
} else {
None
};
tcx.sess.emit_fatal(RecursionLimit {
span,
shrunk,
def_span,
def_path_str,
was_written,
path,
});
}

recursion_depths.insert(def_id, recursion_depth + 1);
@@ -642,16 +651,15 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
// Bail out in these cases to avoid that bad user experience.
if !tcx.type_length_limit().value_within_limit(type_length) {
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
if let Some(path) = written_to_path {
diag.note(&format!("the full type name has been written to '{}'", path.display()));
}
diag.help(&format!(
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
type_length
));
diag.emit()
let span = tcx.def_span(instance.def_id());
let mut path = PathBuf::new();
let was_written = if written_to_path.is_some() {
path = written_to_path.unwrap();
Some(())
} else {
None
};
tcx.sess.emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
}
}

@@ -914,17 +922,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// but correct span? This would make the lint at least accept crate-level lint attributes.
return;
};
self.tcx.struct_span_lint_hir(
self.tcx.emit_spanned_lint(
LARGE_ASSIGNMENTS,
lint_root,
source_info.span,
|lint| {
let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes()));
err.span_label(source_info.span, "value moved from here");
err.note(&format!(r#"The current maximum size is {}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`"#, limit.bytes()));
err.emit();
LargeAssignmentsLint {
span: source_info.span,
size: layout.size.bytes(),
limit: limit.bytes(),
},
);
)
}
}
}
@@ -1321,7 +1328,11 @@ impl<'v> RootCollector<'_, 'v> {

let start_def_id = match self.tcx.lang_items().require(LangItem::Start) {
Ok(s) => s,
Err(err) => self.tcx.sess.fatal(&err),
Err(lang_item_err) => {
self.tcx
.sess
.emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() });
}
};
let main_ret_ty = self.tcx.fn_sig(main_def_id).output();

84 changes: 84 additions & 0 deletions compiler/rustc_monomorphize/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::path::PathBuf;

use rustc_errors::ErrorGuaranteed;
use rustc_macros::{LintDiagnostic, SessionDiagnostic};
use rustc_session::SessionDiagnostic;
use rustc_span::Span;

#[derive(SessionDiagnostic)]
#[diag(monomorphize::recursion_limit)]
pub struct RecursionLimit {
#[primary_span]
pub span: Span,
pub shrunk: String,
#[note]
pub def_span: Span,
pub def_path_str: String,
#[note(monomorphize::written_to_path)]
pub was_written: Option<()>,
pub path: PathBuf,
}

#[derive(SessionDiagnostic)]
#[diag(monomorphize::type_length_limit)]
#[help(monomorphize::consider_type_length_limit)]
pub struct TypeLengthLimit {
#[primary_span]
pub span: Span,
pub shrunk: String,
#[note(monomorphize::written_to_path)]
pub was_written: Option<()>,
pub path: PathBuf,
pub type_length: usize,
}

#[derive(SessionDiagnostic)]
#[diag(monomorphize::requires_lang_item)]
pub struct RequiresLangItem {
pub lang_item: String,
}

pub struct UnusedGenericParams {
pub span: Span,
pub param_spans: Vec<Span>,
pub param_names: Vec<String>,
}

impl SessionDiagnostic<'_> for UnusedGenericParams {
fn into_diagnostic(
self,
sess: &'_ rustc_session::parse::ParseSess,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
diag.set_span(self.span);
for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
// or a label with a dynamic value in a hard-coded string, but I haven't figured out
// how to combine the two. 😢
diag.span_label(span, format!("generic parameter `{}` is unused", name));
}
diag
}
}

#[derive(LintDiagnostic)]
#[diag(monomorphize::large_assignments)]
#[note]
pub struct LargeAssignmentsLint {
#[label]
pub span: Span,
pub size: u64,
pub limit: u64,
}

#[derive(SessionDiagnostic)]
#[diag(monomorphize::unknown_partition_strategy)]
pub struct UnknownPartitionStrategy;

#[derive(SessionDiagnostic)]
#[diag(monomorphize::symbol_already_defined)]
pub struct SymbolAlreadyDefined {
#[primary_span]
pub span: Option<Span>,
pub symbol: String,
}
3 changes: 3 additions & 0 deletions compiler/rustc_monomorphize/src/lib.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
#![feature(let_else)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]

#[macro_use]
extern crate tracing;
@@ -16,6 +18,7 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};

mod collector;
mod errors;
mod partitioning;
mod polymorphize;
mod util;
13 changes: 5 additions & 8 deletions compiler/rustc_monomorphize/src/partitioning/mod.rs
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@ use rustc_span::symbol::Symbol;

use crate::collector::InliningMap;
use crate::collector::{self, MonoItemCollectionMode};
use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};

pub struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
@@ -149,7 +150,9 @@ fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> {

match strategy {
"default" => Box::new(default::DefaultPartitioning),
_ => tcx.sess.fatal("unknown partitioning strategy"),
_ => {
tcx.sess.emit_fatal(UnknownPartitionStrategy);
}
}
}

@@ -331,13 +334,7 @@ where
(span1, span2) => span1.or(span2),
};

let error_message = format!("symbol `{}` is already defined", sym1);

if let Some(span) = span {
tcx.sess.span_fatal(span, &error_message)
} else {
tcx.sess.fatal(&error_message)
}
tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() });
}
}
}
Loading