1
Fork 0

Auto merge of #119621 - compiler-errors:rollup-5mxtvuk, r=compiler-errors

Rollup of 10 pull requests

Successful merges:

 - #119034 (Allow coverage tests to ignore test modes, and to enable color in coverage reports)
 - #119148 (Tweak suggestions for bare trait used as a type)
 - #119538 (Cleanup error handlers: round 5)
 - #119566 (Remove `-Zdump-mir-spanview`)
 - #119567 (Remove `-Zreport-delayed-bugs`.)
 - #119577 (Migrate memory overlap check from validator to lint)
 - #119583 (Make `intrinsics::assume` const stable)
 - #119586 ([rustdoc] Fix invalid handling for static method calls in jump to definition feature)
 - #119588 (Move `i586-unknown-netbsd` from tier 2 to tier 3 platform support table)
 - #119601 (`Emitter` cleanups)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-01-05 16:31:05 +00:00
commit 11035f9f52
133 changed files with 1560 additions and 1830 deletions

View file

@ -725,8 +725,8 @@ impl AddToDiagnostic for StableFeature {
rustc_errors::SubdiagnosticMessage, rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage,
{ {
diag.set_arg("name", self.name); diag.arg("name", self.name);
diag.set_arg("since", self.since); diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since); diag.help(fluent::ast_passes_stable_since);
} }
} }

View file

@ -55,10 +55,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item);
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0541)); diag.code(error_code!(E0541));
diag.set_arg("item", self.item); diag.arg("item", self.item);
diag.set_arg("expected", expected.join(", ")); diag.arg("expected", expected.join(", "));
diag.span_label(self.span, fluent::attr_label); diag.span_label(self.span, fluent::attr_label);
diag diag
} }
@ -215,7 +215,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral {
} }
}, },
); );
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0565)); diag.code(error_code!(E0565));
if self.is_bytestr { if self.is_bytestr {
diag.span_suggestion( diag.span_suggestion(

View file

@ -454,7 +454,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMe
reason = "cannot translate user-provided messages" reason = "cannot translate user-provided messages"
)] )]
let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string()); let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
diag.set_span(self.span); diag.span(self.span);
diag diag
} }
} }
@ -618,7 +618,7 @@ impl AddToDiagnostic for FormatUnusedArg {
rustc_errors::SubdiagnosticMessage, rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage,
{ {
diag.set_arg("named", self.named); diag.arg("named", self.named);
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
diag.span_label(self.span, msg); diag.span_label(self.span, msg);
} }
@ -808,7 +808,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
level, level,
crate::fluent_generated::builtin_macros_asm_clobber_no_reg, crate::fluent_generated::builtin_macros_asm_clobber_no_reg,
); );
diag.set_span(self.spans.clone()); diag.span(self.spans.clone());
// eager translation as `span_labels` takes `AsRef<str>` // eager translation as `span_labels` takes `AsRef<str>`
let lbl1 = dcx.eagerly_translate_to_string( let lbl1 = dcx.eagerly_translate_to_string(
crate::fluent_generated::builtin_macros_asm_clobber_abi, crate::fluent_generated::builtin_macros_asm_clobber_abi,

View file

@ -395,10 +395,10 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
// These were a warning before #92959 and need to continue being that to avoid breaking // These were a warning before #92959 and need to continue being that to avoid breaking
// stable user code (#94508). // stable user code (#94508).
Some(ast::ItemKind::MacCall(_)) => Level::Warning(None), Some(ast::ItemKind::MacCall(_)) => Level::Warning(None),
_ => Level::Error { lint: false }, _ => Level::Error,
}; };
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg); let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
err.set_span(attr_sp); err.span(attr_sp);
if let Some(item) = item { if let Some(item) = item {
err.span_label( err.span_label(
item.span, item.span,

View file

@ -119,12 +119,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
fluent::codegen_gcc_target_feature_disable_or_enable fluent::codegen_gcc_target_feature_disable_or_enable
); );
if let Some(span) = self.span { if let Some(span) = self.span {
diag.set_span(span); diag.span(span);
}; };
if let Some(missing_features) = self.missing_features { if let Some(missing_features) = self.missing_features {
diag.subdiagnostic(missing_features); diag.subdiagnostic(missing_features);
} }
diag.set_arg("features", self.features.join(", ")); diag.arg("features", self.features.join(", "));
diag diag
} }
} }

View file

@ -416,7 +416,7 @@ fn report_inline_asm(
cookie = 0; cookie = 0;
} }
let level = match level { let level = match level {
llvm::DiagnosticLevel::Error => Level::Error { lint: false }, llvm::DiagnosticLevel::Error => Level::Error,
llvm::DiagnosticLevel::Warning => Level::Warning(None), llvm::DiagnosticLevel::Warning => Level::Warning(None),
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
}; };

View file

@ -107,7 +107,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_
let mut diag = let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config); DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config);
diag.set_arg("error", message); diag.arg("error", message);
diag diag
} }
} }
@ -130,12 +130,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
fluent::codegen_llvm_target_feature_disable_or_enable, fluent::codegen_llvm_target_feature_disable_or_enable,
); );
if let Some(span) = self.span { if let Some(span) = self.span {
diag.set_span(span); diag.span(span);
}; };
if let Some(missing_features) = self.missing_features { if let Some(missing_features) = self.missing_features {
diag.subdiagnostic(missing_features); diag.subdiagnostic(missing_features);
} }
diag.set_arg("features", self.features.join(", ")); diag.arg("features", self.features.join(", "));
diag diag
} }
} }
@ -205,8 +205,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
}; };
let mut diag = self.0.into_diagnostic(dcx, level); let mut diag = self.0.into_diagnostic(dcx, level);
diag.set_primary_message(msg_with_llvm_err); diag.primary_message(msg_with_llvm_err);
diag.set_arg("llvm_err", self.1); diag.arg("llvm_err", self.1);
diag diag
} }
} }

View file

@ -1848,9 +1848,9 @@ impl SharedEmitterMain {
} }
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
let err_level = match level { let err_level = match level {
Level::Error { lint: false } => rustc_errors::Level::Error { lint: false }, Level::Error => Level::Error,
Level::Warning(_) => rustc_errors::Level::Warning(None), Level::Warning(_) => Level::Warning(None),
Level::Note => rustc_errors::Level::Note, Level::Note => Level::Note,
_ => bug!("Invalid inline asm diagnostic level"), _ => bug!("Invalid inline asm diagnostic level"),
}; };
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
@ -1860,7 +1860,7 @@ impl SharedEmitterMain {
if cookie != 0 { if cookie != 0 {
let pos = BytePos::from_u32(cookie); let pos = BytePos::from_u32(cookie);
let span = Span::with_root_ctxt(pos, pos); let span = Span::with_root_ctxt(pos, pos);
err.set_span(span); err.span(span);
}; };
// Point to the generated assembly if it is available. // Point to the generated assembly if it is available.

View file

@ -244,30 +244,30 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::NamelessSection(_, offset) => { thorin::Error::NamelessSection(_, offset) => {
diag = build(fluent::codegen_ssa_thorin_section_without_name); diag = build(fluent::codegen_ssa_thorin_section_without_name);
diag.set_arg("offset", format!("0x{offset:08x}")); diag.arg("offset", format!("0x{offset:08x}"));
diag diag
} }
thorin::Error::RelocationWithInvalidSymbol(section, offset) => { thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
diag.set_arg("section", section); diag.arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}")); diag.arg("offset", format!("0x{offset:08x}"));
diag diag
} }
thorin::Error::MultipleRelocations(section, offset) => { thorin::Error::MultipleRelocations(section, offset) => {
diag = build(fluent::codegen_ssa_thorin_multiple_relocations); diag = build(fluent::codegen_ssa_thorin_multiple_relocations);
diag.set_arg("section", section); diag.arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}")); diag.arg("offset", format!("0x{offset:08x}"));
diag diag
} }
thorin::Error::UnsupportedRelocation(section, offset) => { thorin::Error::UnsupportedRelocation(section, offset) => {
diag = build(fluent::codegen_ssa_thorin_unsupported_relocation); diag = build(fluent::codegen_ssa_thorin_unsupported_relocation);
diag.set_arg("section", section); diag.arg("section", section);
diag.set_arg("offset", format!("0x{offset:08x}")); diag.arg("offset", format!("0x{offset:08x}"));
diag diag
} }
thorin::Error::MissingDwoName(id) => { thorin::Error::MissingDwoName(id) => {
diag = build(fluent::codegen_ssa_thorin_missing_dwo_name); diag = build(fluent::codegen_ssa_thorin_missing_dwo_name);
diag.set_arg("id", format!("0x{id:08x}")); diag.arg("id", format!("0x{id:08x}"));
diag diag
} }
thorin::Error::NoCompilationUnits => { thorin::Error::NoCompilationUnits => {
@ -284,7 +284,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::MissingRequiredSection(section) => { thorin::Error::MissingRequiredSection(section) => {
diag = build(fluent::codegen_ssa_thorin_missing_required_section); diag = build(fluent::codegen_ssa_thorin_missing_required_section);
diag.set_arg("section", section); diag.arg("section", section);
diag diag
} }
thorin::Error::ParseUnitAbbreviations(_) => { thorin::Error::ParseUnitAbbreviations(_) => {
@ -305,34 +305,34 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::IncompatibleIndexVersion(section, format, actual) => { thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
diag = build(fluent::codegen_ssa_thorin_incompatible_index_version); diag = build(fluent::codegen_ssa_thorin_incompatible_index_version);
diag.set_arg("section", section); diag.arg("section", section);
diag.set_arg("actual", actual); diag.arg("actual", actual);
diag.set_arg("format", format); diag.arg("format", format);
diag diag
} }
thorin::Error::OffsetAtIndex(_, index) => { thorin::Error::OffsetAtIndex(_, index) => {
diag = build(fluent::codegen_ssa_thorin_offset_at_index); diag = build(fluent::codegen_ssa_thorin_offset_at_index);
diag.set_arg("index", index); diag.arg("index", index);
diag diag
} }
thorin::Error::StrAtOffset(_, offset) => { thorin::Error::StrAtOffset(_, offset) => {
diag = build(fluent::codegen_ssa_thorin_str_at_offset); diag = build(fluent::codegen_ssa_thorin_str_at_offset);
diag.set_arg("offset", format!("0x{offset:08x}")); diag.arg("offset", format!("0x{offset:08x}"));
diag diag
} }
thorin::Error::ParseIndex(_, section) => { thorin::Error::ParseIndex(_, section) => {
diag = build(fluent::codegen_ssa_thorin_parse_index); diag = build(fluent::codegen_ssa_thorin_parse_index);
diag.set_arg("section", section); diag.arg("section", section);
diag diag
} }
thorin::Error::UnitNotInIndex(unit) => { thorin::Error::UnitNotInIndex(unit) => {
diag = build(fluent::codegen_ssa_thorin_unit_not_in_index); diag = build(fluent::codegen_ssa_thorin_unit_not_in_index);
diag.set_arg("unit", format!("0x{unit:08x}")); diag.arg("unit", format!("0x{unit:08x}"));
diag diag
} }
thorin::Error::RowNotInIndex(_, row) => { thorin::Error::RowNotInIndex(_, row) => {
diag = build(fluent::codegen_ssa_thorin_row_not_in_index); diag = build(fluent::codegen_ssa_thorin_row_not_in_index);
diag.set_arg("row", row); diag.arg("row", row);
diag diag
} }
thorin::Error::SectionNotInRow => { thorin::Error::SectionNotInRow => {
@ -341,7 +341,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::EmptyUnit(unit) => { thorin::Error::EmptyUnit(unit) => {
diag = build(fluent::codegen_ssa_thorin_empty_unit); diag = build(fluent::codegen_ssa_thorin_empty_unit);
diag.set_arg("unit", format!("0x{unit:08x}")); diag.arg("unit", format!("0x{unit:08x}"));
diag diag
} }
thorin::Error::MultipleDebugInfoSection => { thorin::Error::MultipleDebugInfoSection => {
@ -358,12 +358,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::DuplicateUnit(unit) => { thorin::Error::DuplicateUnit(unit) => {
diag = build(fluent::codegen_ssa_thorin_duplicate_unit); diag = build(fluent::codegen_ssa_thorin_duplicate_unit);
diag.set_arg("unit", format!("0x{unit:08x}")); diag.arg("unit", format!("0x{unit:08x}"));
diag diag
} }
thorin::Error::MissingReferencedUnit(unit) => { thorin::Error::MissingReferencedUnit(unit) => {
diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit); diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit);
diag.set_arg("unit", format!("0x{unit:08x}")); diag.arg("unit", format!("0x{unit:08x}"));
diag diag
} }
thorin::Error::NoOutputObjectCreated => { thorin::Error::NoOutputObjectCreated => {
@ -376,27 +376,27 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper {
} }
thorin::Error::Io(e) => { thorin::Error::Io(e) => {
diag = build(fluent::codegen_ssa_thorin_io); diag = build(fluent::codegen_ssa_thorin_io);
diag.set_arg("error", format!("{e}")); diag.arg("error", format!("{e}"));
diag diag
} }
thorin::Error::ObjectRead(e) => { thorin::Error::ObjectRead(e) => {
diag = build(fluent::codegen_ssa_thorin_object_read); diag = build(fluent::codegen_ssa_thorin_object_read);
diag.set_arg("error", format!("{e}")); diag.arg("error", format!("{e}"));
diag diag
} }
thorin::Error::ObjectWrite(e) => { thorin::Error::ObjectWrite(e) => {
diag = build(fluent::codegen_ssa_thorin_object_write); diag = build(fluent::codegen_ssa_thorin_object_write);
diag.set_arg("error", format!("{e}")); diag.arg("error", format!("{e}"));
diag diag
} }
thorin::Error::GimliRead(e) => { thorin::Error::GimliRead(e) => {
diag = build(fluent::codegen_ssa_thorin_gimli_read); diag = build(fluent::codegen_ssa_thorin_gimli_read);
diag.set_arg("error", format!("{e}")); diag.arg("error", format!("{e}"));
diag diag
} }
thorin::Error::GimliWrite(e) => { thorin::Error::GimliWrite(e) => {
diag = build(fluent::codegen_ssa_thorin_gimli_write); diag = build(fluent::codegen_ssa_thorin_gimli_write);
diag.set_arg("error", format!("{e}")); diag.arg("error", format!("{e}"));
diag diag
} }
_ => unimplemented!("Untranslated thorin error"), _ => unimplemented!("Untranslated thorin error"),
@ -414,8 +414,8 @@ pub struct LinkingFailed<'a> {
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> {
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_ssa_linking_failed); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_ssa_linking_failed);
diag.set_arg("linker_path", format!("{}", self.linker_path.display())); diag.arg("linker_path", format!("{}", self.linker_path.display()));
diag.set_arg("exit_status", format!("{}", self.exit_status)); diag.arg("exit_status", format!("{}", self.exit_status));
let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); let contains_undefined_ref = self.escaped_output.contains("undefined reference to");

View file

@ -518,7 +518,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
Ub(_) => {} Ub(_) => {}
Custom(custom) => { Custom(custom) => {
(custom.add_args)(&mut |name, value| { (custom.add_args)(&mut |name, value| {
builder.set_arg(name, value); builder.arg(name, value);
}); });
} }
ValidationError(e) => e.add_args(dcx, builder), ValidationError(e) => e.add_args(dcx, builder),
@ -536,65 +536,65 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
| UninhabitedEnumVariantWritten(_) | UninhabitedEnumVariantWritten(_)
| UninhabitedEnumVariantRead(_) => {} | UninhabitedEnumVariantRead(_) => {}
BoundsCheckFailed { len, index } => { BoundsCheckFailed { len, index } => {
builder.set_arg("len", len); builder.arg("len", len);
builder.set_arg("index", index); builder.arg("index", index);
} }
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
builder.set_arg("pointer", ptr); builder.arg("pointer", ptr);
} }
PointerUseAfterFree(alloc_id, msg) => { PointerUseAfterFree(alloc_id, msg) => {
builder builder
.set_arg("alloc_id", alloc_id) .arg("alloc_id", alloc_id)
.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
} }
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
builder builder
.set_arg("alloc_id", alloc_id) .arg("alloc_id", alloc_id)
.set_arg("alloc_size", alloc_size.bytes()) .arg("alloc_size", alloc_size.bytes())
.set_arg("ptr_offset", ptr_offset) .arg("ptr_offset", ptr_offset)
.set_arg("ptr_size", ptr_size.bytes()) .arg("ptr_size", ptr_size.bytes())
.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
} }
DanglingIntPointer(ptr, msg) => { DanglingIntPointer(ptr, msg) => {
if ptr != 0 { if ptr != 0 {
builder.set_arg("pointer", format!("{ptr:#x}[noalloc]")); builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
} }
builder.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
} }
AlignmentCheckFailed(Misalignment { required, has }, msg) => { AlignmentCheckFailed(Misalignment { required, has }, msg) => {
builder.set_arg("required", required.bytes()); builder.arg("required", required.bytes());
builder.set_arg("has", has.bytes()); builder.arg("has", has.bytes());
builder.set_arg("msg", format!("{msg:?}")); builder.arg("msg", format!("{msg:?}"));
} }
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
builder.set_arg("allocation", alloc); builder.arg("allocation", alloc);
} }
InvalidBool(b) => { InvalidBool(b) => {
builder.set_arg("value", format!("{b:02x}")); builder.arg("value", format!("{b:02x}"));
} }
InvalidChar(c) => { InvalidChar(c) => {
builder.set_arg("value", format!("{c:08x}")); builder.arg("value", format!("{c:08x}"));
} }
InvalidTag(tag) => { InvalidTag(tag) => {
builder.set_arg("tag", format!("{tag:x}")); builder.arg("tag", format!("{tag:x}"));
} }
InvalidStr(err) => { InvalidStr(err) => {
builder.set_arg("err", format!("{err}")); builder.arg("err", format!("{err}"));
} }
InvalidUninitBytes(Some((alloc, info))) => { InvalidUninitBytes(Some((alloc, info))) => {
builder.set_arg("alloc", alloc); builder.arg("alloc", alloc);
builder.set_arg("access", info.access); builder.arg("access", info.access);
builder.set_arg("uninit", info.bad); builder.arg("uninit", info.bad);
} }
ScalarSizeMismatch(info) => { ScalarSizeMismatch(info) => {
builder.set_arg("target_size", info.target_size); builder.arg("target_size", info.target_size);
builder.set_arg("data_size", info.data_size); builder.arg("data_size", info.data_size);
} }
AbiMismatchArgument { caller_ty, callee_ty } AbiMismatchArgument { caller_ty, callee_ty }
| AbiMismatchReturn { caller_ty, callee_ty } => { | AbiMismatchReturn { caller_ty, callee_ty } => {
builder.set_arg("caller_ty", caller_ty.to_string()); builder.arg("caller_ty", caller_ty.to_string());
builder.set_arg("callee_ty", callee_ty.to_string()); builder.arg("callee_ty", callee_ty.to_string());
} }
} }
} }
@ -695,7 +695,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
) )
}; };
err.set_arg("front_matter", message); err.arg("front_matter", message);
fn add_range_arg<G: EmissionGuarantee>( fn add_range_arg<G: EmissionGuarantee>(
r: WrappingRange, r: WrappingRange,
@ -725,12 +725,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
]; ];
let args = args.iter().map(|(a, b)| (a, b)); let args = args.iter().map(|(a, b)| (a, b));
let message = dcx.eagerly_translate_to_string(msg, args); let message = dcx.eagerly_translate_to_string(msg, args);
err.set_arg("in_range", message); err.arg("in_range", message);
} }
match self.kind { match self.kind {
PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
err.set_arg("ty", ty); err.arg("ty", ty);
} }
PointerAsInt { expected } | Uninit { expected } => { PointerAsInt { expected } | Uninit { expected } => {
let msg = match expected { let msg = match expected {
@ -747,28 +747,28 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
ExpectedKind::Str => fluent::const_eval_validation_expected_str, ExpectedKind::Str => fluent::const_eval_validation_expected_str,
}; };
let msg = dcx.eagerly_translate_to_string(msg, [].into_iter()); let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
err.set_arg("expected", msg); err.arg("expected", msg);
} }
InvalidEnumTag { value } InvalidEnumTag { value }
| InvalidVTablePtr { value } | InvalidVTablePtr { value }
| InvalidBool { value } | InvalidBool { value }
| InvalidChar { value } | InvalidChar { value }
| InvalidFnPtr { value } => { | InvalidFnPtr { value } => {
err.set_arg("value", value); err.arg("value", value);
} }
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
add_range_arg(range, max_value, dcx, err) add_range_arg(range, max_value, dcx, err)
} }
OutOfRange { range, max_value, value } => { OutOfRange { range, max_value, value } => {
err.set_arg("value", value); err.arg("value", value);
add_range_arg(range, max_value, dcx, err); add_range_arg(range, max_value, dcx, err);
} }
UnalignedPtr { required_bytes, found_bytes, .. } => { UnalignedPtr { required_bytes, found_bytes, .. } => {
err.set_arg("required_bytes", required_bytes); err.arg("required_bytes", required_bytes);
err.set_arg("found_bytes", found_bytes); err.arg("found_bytes", found_bytes);
} }
DanglingPtrNoProvenance { pointer, .. } => { DanglingPtrNoProvenance { pointer, .. } => {
err.set_arg("pointer", pointer); err.arg("pointer", pointer);
} }
NullPtr { .. } NullPtr { .. }
| PtrToStatic { .. } | PtrToStatic { .. }
@ -814,10 +814,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
// print. So it's not worth the effort of having diagnostics that can print the `info`. // print. So it's not worth the effort of having diagnostics that can print the `info`.
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
builder.set_arg("ptr", ptr); builder.arg("ptr", ptr);
} }
ThreadLocalStatic(did) | ReadExternStatic(did) => { ThreadLocalStatic(did) | ReadExternStatic(did) => {
builder.set_arg("did", format!("{did:?}")); builder.arg("did", format!("{did:?}"));
} }
} }
} }
@ -844,7 +844,7 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
InterpError::InvalidProgram(e) => e.add_args(dcx, builder), InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder), InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
InterpError::MachineStop(e) => e.add_args(&mut |name, value| { InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
builder.set_arg(name, value); builder.arg(name, value);
}), }),
} }
} }
@ -880,15 +880,15 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
let diag: DiagnosticBuilder<'_, ()> = let diag: DiagnosticBuilder<'_, ()> =
e.into_diagnostic().into_diagnostic(dcx, dummy_level); e.into_diagnostic().into_diagnostic(dcx, dummy_level);
for (name, val) in diag.args() { for (name, val) in diag.args() {
builder.set_arg(name.clone(), val.clone()); builder.arg(name.clone(), val.clone());
} }
diag.cancel(); diag.cancel();
} }
InvalidProgramInfo::FnAbiAdjustForForeignAbi( InvalidProgramInfo::FnAbiAdjustForForeignAbi(
AdjustForForeignAbiError::Unsupported { arch, abi }, AdjustForForeignAbiError::Unsupported { arch, abi },
) => { ) => {
builder.set_arg("arch", arch); builder.arg("arch", arch);
builder.set_arg("abi", abi.name()); builder.arg("abi", abi.name());
} }
} }
} }

View file

@ -74,7 +74,6 @@ impl<'tcx> MirPass<'tcx> for Validator {
mir_phase, mir_phase,
unwind_edge_count: 0, unwind_edge_count: 0,
reachable_blocks: traversal::reachable_as_bitset(body), reachable_blocks: traversal::reachable_as_bitset(body),
place_cache: FxHashSet::default(),
value_cache: FxHashSet::default(), value_cache: FxHashSet::default(),
can_unwind, can_unwind,
}; };
@ -106,7 +105,6 @@ struct CfgChecker<'a, 'tcx> {
mir_phase: MirPhase, mir_phase: MirPhase,
unwind_edge_count: usize, unwind_edge_count: usize,
reachable_blocks: BitSet<BasicBlock>, reachable_blocks: BitSet<BasicBlock>,
place_cache: FxHashSet<PlaceRef<'tcx>>,
value_cache: FxHashSet<u128>, value_cache: FxHashSet<u128>,
// If `false`, then the MIR must not contain `UnwindAction::Continue` or // If `false`, then the MIR must not contain `UnwindAction::Continue` or
// `TerminatorKind::Resume`. // `TerminatorKind::Resume`.
@ -294,19 +292,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match &statement.kind { match &statement.kind {
StatementKind::Assign(box (dest, rvalue)) => {
// FIXME(JakobDegen): Check this for all rvalues, not just this one.
if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
// The sides of an assignment must not alias. Currently this just checks whether
// the places are identical.
if dest == src {
self.fail(
location,
"encountered `Assign` statement with overlapping memory",
);
}
}
}
StatementKind::AscribeUserType(..) => { StatementKind::AscribeUserType(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail( self.fail(
@ -341,7 +326,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.fail(location, format!("explicit `{kind:?}` is forbidden")); self.fail(location, format!("explicit `{kind:?}` is forbidden"));
} }
} }
StatementKind::StorageLive(_) StatementKind::Assign(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_) | StatementKind::StorageDead(_)
| StatementKind::Intrinsic(_) | StatementKind::Intrinsic(_)
| StatementKind::Coverage(_) | StatementKind::Coverage(_)
@ -404,10 +390,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
} }
// The call destination place and Operand::Move place used as an argument might be // The call destination place and Operand::Move place used as an argument might be
// passed by a reference to the callee. Consequently they must be non-overlapping // passed by a reference to the callee. Consequently they cannot be packed.
// and cannot be packed. Currently this simply checks for duplicate places.
self.place_cache.clear();
self.place_cache.insert(destination.as_ref());
if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() { if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() {
// This is bad! The callee will expect the memory to be aligned. // This is bad! The callee will expect the memory to be aligned.
self.fail( self.fail(
@ -418,10 +401,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
), ),
); );
} }
let mut has_duplicates = false;
for arg in args { for arg in args {
if let Operand::Move(place) = arg { if let Operand::Move(place) = arg {
has_duplicates |= !self.place_cache.insert(place.as_ref());
if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
// This is bad! The callee will expect the memory to be aligned. // This is bad! The callee will expect the memory to be aligned.
self.fail( self.fail(
@ -434,16 +415,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
} }
} }
} }
if has_duplicates {
self.fail(
location,
format!(
"encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}",
terminator.kind,
),
);
}
} }
TerminatorKind::Assert { target, unwind, .. } => { TerminatorKind::Assert { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal); self.check_edge(location, *target, EdgeKind::Normal);
@ -1112,17 +1083,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
) )
} }
} }
// FIXME(JakobDegen): Check this for all rvalues, not just this one.
if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
// The sides of an assignment must not alias. Currently this just checks whether
// the places are identical.
if dest == src {
self.fail(
location,
"encountered `Assign` statement with overlapping memory",
);
}
}
} }
StatementKind::AscribeUserType(..) => { StatementKind::AscribeUserType(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {

View file

@ -1393,7 +1393,7 @@ fn report_ice(
) { ) {
let fallback_bundle = let fallback_bundle =
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( let emitter = Box::new(rustc_errors::emitter::HumanEmitter::stderr(
rustc_errors::ColorConfig::Auto, rustc_errors::ColorConfig::Auto,
fallback_bundle, fallback_bundle,
)); ));

View file

@ -20,7 +20,7 @@ use rustc_span::source_map::SourceMap;
use rustc_span::SourceFile; use rustc_span::SourceFile;
/// Generates diagnostics using annotate-snippet /// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter { pub struct AnnotateSnippetEmitter {
source_map: Option<Lrc<SourceMap>>, source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>, fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle, fallback_bundle: LazyFallbackBundle,
@ -33,7 +33,7 @@ pub struct AnnotateSnippetEmitterWriter {
macro_backtrace: bool, macro_backtrace: bool,
} }
impl Translate for AnnotateSnippetEmitterWriter { impl Translate for AnnotateSnippetEmitter {
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref() self.fluent_bundle.as_ref()
} }
@ -43,7 +43,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
} }
} }
impl Emitter for AnnotateSnippetEmitterWriter { impl Emitter for AnnotateSnippetEmitter {
/// The entry point for the diagnostics generation /// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) { fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let fluent_args = to_fluent_args(diag.args()); let fluent_args = to_fluent_args(diag.args());
@ -86,9 +86,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
/// Maps `Diagnostic::Level` to `snippet::AnnotationType` /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType { fn annotation_type_for_level(level: Level) -> AnnotationType {
match level { match level {
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => { Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
AnnotationType::Error
}
Level::Warning(_) => AnnotationType::Warning, Level::Warning(_) => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note, Level::Note | Level::OnceNote => AnnotationType::Note,
Level::Help | Level::OnceHelp => AnnotationType::Help, Level::Help | Level::OnceHelp => AnnotationType::Help,
@ -99,7 +97,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
} }
} }
impl AnnotateSnippetEmitterWriter { impl AnnotateSnippetEmitter {
pub fn new( pub fn new(
source_map: Option<Lrc<SourceMap>>, source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>, fluent_bundle: Option<Lrc<FluentBundle>>,

View file

@ -212,6 +212,9 @@ impl StringPart {
} }
} }
// Note: most of these methods are setters that return `&mut Self`. The small
// number of simple getter functions all have `get_` prefixes to distinguish
// them from the setters.
impl Diagnostic { impl Diagnostic {
#[track_caller] #[track_caller]
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self { pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
@ -241,11 +244,9 @@ impl Diagnostic {
pub fn is_error(&self) -> bool { pub fn is_error(&self) -> bool {
match self.level { match self.level {
Level::Bug Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error | Level::FailureNote => {
| Level::DelayedBug true
| Level::Fatal }
| Level::Error { .. }
| Level::FailureNote => true,
Level::Warning(_) Level::Warning(_)
| Level::Note | Level::Note
@ -308,25 +309,27 @@ impl Diagnostic {
/// In the meantime, though, callsites are required to deal with the "bug" /// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense. /// locally in whichever way makes the most sense.
#[track_caller] #[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { pub fn downgrade_to_delayed_bug(&mut self) {
assert!( assert!(
self.is_error(), self.is_error(),
"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
self.level self.level
); );
self.level = Level::DelayedBug; self.level = Level::DelayedBug;
self
} }
/// Adds a span/label to be included in the resulting snippet. /// Appends a labeled span to the diagnostic.
/// ///
/// This is pushed onto the [`MultiSpan`] that was created when the diagnostic /// Labels are used to convey additional context for the diagnostic's primary span. They will
/// was first built. That means it will be shown together with the original /// be shown together with the original diagnostic's span, *not* with spans added by
/// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods. /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
/// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
/// either.
/// ///
/// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
/// the `Span` supplied when creating the diagnostic is primary. /// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self { pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label));
@ -344,7 +347,7 @@ impl Diagnostic {
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self { pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone(); let before = self.span.clone();
self.set_span(after); self.span(after);
for span_label in before.span_labels() { for span_label in before.span_labels() {
if let Some(label) = span_label.label { if let Some(label) = span_label.label {
if span_label.is_primary && keep_label { if span_label.is_primary && keep_label {
@ -876,7 +879,7 @@ impl Diagnostic {
self self
} }
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { pub fn span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into(); self.span = sp.into();
if let Some(span) = self.span.primary_span() { if let Some(span) = self.span.primary_span() {
self.sort_span = span; self.sort_span = span;
@ -884,7 +887,7 @@ impl Diagnostic {
self self
} }
pub fn set_is_lint(&mut self) -> &mut Self { pub fn is_lint(&mut self) -> &mut Self {
self.is_lint = true; self.is_lint = true;
self self
} }
@ -903,7 +906,7 @@ impl Diagnostic {
self.code.clone() self.code.clone()
} }
pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self { pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle); self.messages[0] = (msg.into(), Style::NoStyle);
self self
} }
@ -915,7 +918,7 @@ impl Diagnostic {
self.args.iter() self.args.iter()
} }
pub fn set_arg( pub fn arg(
&mut self, &mut self,
name: impl Into<Cow<'static, str>>, name: impl Into<Cow<'static, str>>,
arg: impl IntoDiagnosticArg, arg: impl IntoDiagnosticArg,

View file

@ -31,7 +31,7 @@ where
{ {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(dcx, level); let mut diag = self.node.into_diagnostic(dcx, level);
diag.set_span(self.span); diag.span(self.span);
diag diag
} }
} }
@ -207,11 +207,11 @@ macro_rules! forward {
// Forward pattern for &mut self -> &mut Self // Forward pattern for &mut self -> &mut Self
( (
$(#[$attrs:meta])* $(#[$attrs:meta])*
pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self pub fn $n:ident(&mut self $(, $name:ident: $ty:ty)* $(,)?) -> &mut Self
) => { ) => {
$(#[$attrs])* $(#[$attrs])*
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { pub fn $n(&mut self $(, $name: $ty)*) -> &mut Self {
self.diagnostic.$n($($name),*); self.diagnostic.$n($($name),*);
self self
} }
@ -356,35 +356,16 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
self.emit() self.emit()
} }
forward!( forward!(pub fn span_label(
#[track_caller] &mut self,
pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self span: Span,
); label: impl Into<SubdiagnosticMessage>
) -> &mut Self);
forward!( forward!(pub fn span_labels(
/// Appends a labeled span to the diagnostic.
///
/// Labels are used to convey additional context for the diagnostic's primary span. They will
/// be shown together with the original diagnostic's span, *not* with spans added by
/// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
/// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
/// either.
///
/// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
/// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(
/// Labels all the given spans with the provided label.
/// See [`Diagnostic::span_label()`] for more information.
pub fn span_labels(
&mut self, &mut self,
spans: impl IntoIterator<Item = Span>, spans: impl IntoIterator<Item = Span>,
label: &str, label: &str,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn note_expected_found( forward!(pub fn note_expected_found(
&mut self, &mut self,
expected_label: &dyn fmt::Display, expected_label: &dyn fmt::Display,
@ -392,7 +373,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
found_label: &dyn fmt::Display, found_label: &dyn fmt::Display,
found: DiagnosticStyledString, found: DiagnosticStyledString,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn note_expected_found_extra( forward!(pub fn note_expected_found_extra(
&mut self, &mut self,
expected_label: &dyn fmt::Display, expected_label: &dyn fmt::Display,
@ -402,7 +382,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
expected_extra: &dyn fmt::Display, expected_extra: &dyn fmt::Display,
found_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_note( forward!(pub fn span_note(
@ -428,10 +407,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
sp: impl Into<MultiSpan>, sp: impl Into<MultiSpan>,
msg: impl Into<SubdiagnosticMessage>, msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn is_lint(&mut self) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
forward!(pub fn multipart_suggestion( forward!(pub fn multipart_suggestion(
&mut self, &mut self,
msg: impl Into<SubdiagnosticMessage>, msg: impl Into<SubdiagnosticMessage>,
@ -498,16 +475,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
suggestion: impl ToString, suggestion: impl ToString,
applicability: Applicability, applicability: Applicability,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self); forward!(pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
forward!(pub fn set_arg( forward!(pub fn arg(
&mut self, &mut self,
name: impl Into<Cow<'static, str>>, name: impl Into<Cow<'static, str>>,
arg: impl IntoDiagnosticArg, arg: impl IntoDiagnosticArg,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn subdiagnostic( forward!(pub fn subdiagnostic(
&mut self, &mut self,
subdiagnostic: impl crate::AddToDiagnostic subdiagnostic: impl crate::AddToDiagnostic

View file

@ -254,29 +254,29 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_>
TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
diag = diag =
DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space); DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space);
diag.set_arg("addr_space", addr_space); diag.arg("addr_space", addr_space);
diag.set_arg("cause", cause); diag.arg("cause", cause);
diag.set_arg("err", err); diag.arg("err", err);
diag diag
} }
TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits); diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits);
diag.set_arg("kind", kind); diag.arg("kind", kind);
diag.set_arg("bit", bit); diag.arg("bit", bit);
diag.set_arg("cause", cause); diag.arg("cause", cause);
diag.set_arg("err", err); diag.arg("err", err);
diag diag
} }
TargetDataLayoutErrors::MissingAlignment { cause } => { TargetDataLayoutErrors::MissingAlignment { cause } => {
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment); diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment);
diag.set_arg("cause", cause); diag.arg("cause", cause);
diag diag
} }
TargetDataLayoutErrors::InvalidAlignment { cause, err } => { TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment); diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment);
diag.set_arg("cause", cause); diag.arg("cause", cause);
diag.set_arg("err_kind", err.diag_ident()); diag.arg("err_kind", err.diag_ident());
diag.set_arg("align", err.align()); diag.arg("align", err.align());
diag diag
} }
TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
@ -285,8 +285,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_>
level, level,
fluent::errors_target_inconsistent_architecture, fluent::errors_target_inconsistent_architecture,
); );
diag.set_arg("dl", dl); diag.arg("dl", dl);
diag.set_arg("target", target); diag.arg("target", target);
diag diag
} }
TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
@ -295,13 +295,13 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_>
level, level,
fluent::errors_target_inconsistent_pointer_width, fluent::errors_target_inconsistent_pointer_width,
); );
diag.set_arg("pointer_size", pointer_size); diag.arg("pointer_size", pointer_size);
diag.set_arg("target", target); diag.arg("target", target);
diag diag
} }
TargetDataLayoutErrors::InvalidBitsSize { err } => { TargetDataLayoutErrors::InvalidBitsSize { err } => {
diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size); diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size);
diag.set_arg("err", err); diag.arg("err", err);
diag diag
} }
} }

View file

@ -61,13 +61,13 @@ impl HumanReadableErrorType {
self, self,
mut dst: Box<dyn WriteColor + Send>, mut dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle, fallback_bundle: LazyFallbackBundle,
) -> EmitterWriter { ) -> HumanEmitter {
let (short, color_config) = self.unzip(); let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors(); let color = color_config.suggests_using_colors();
if !dst.supports_color() && color { if !dst.supports_color() && color {
dst = Box::new(Ansi::new(dst)); dst = Box::new(Ansi::new(dst));
} }
EmitterWriter::new(dst, fallback_bundle).short_message(short) HumanEmitter::new(dst, fallback_bundle).short_message(short)
} }
} }
@ -196,13 +196,15 @@ pub trait Emitter: Translate {
fn emit_diagnostic(&mut self, diag: &Diagnostic); fn emit_diagnostic(&mut self, diag: &Diagnostic);
/// Emit a notification that an artifact has been output. /// Emit a notification that an artifact has been output.
/// This is currently only supported for the JSON format, /// Currently only supported for the JSON format.
/// other formats can, and will, simply ignore it.
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
/// Emit a report about future breakage.
/// Currently only supported for the JSON format.
fn emit_future_breakage_report(&mut self, _diags: Vec<Diagnostic>) {} fn emit_future_breakage_report(&mut self, _diags: Vec<Diagnostic>) {}
/// Emit list of unused externs /// Emit list of unused externs.
/// Currently only supported for the JSON format.
fn emit_unused_externs( fn emit_unused_externs(
&mut self, &mut self,
_lint_level: rustc_lint_defs::Level, _lint_level: rustc_lint_defs::Level,
@ -501,7 +503,7 @@ pub trait Emitter: Translate {
} }
} }
impl Translate for EmitterWriter { impl Translate for HumanEmitter {
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref() self.fluent_bundle.as_ref()
} }
@ -511,7 +513,7 @@ impl Translate for EmitterWriter {
} }
} }
impl Emitter for EmitterWriter { impl Emitter for HumanEmitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>> { fn source_map(&self) -> Option<&Lrc<SourceMap>> {
self.sm.as_ref() self.sm.as_ref()
} }
@ -622,7 +624,7 @@ impl ColorConfig {
/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
#[derive(Setters)] #[derive(Setters)]
pub struct EmitterWriter { pub struct HumanEmitter {
#[setters(skip)] #[setters(skip)]
dst: IntoDynSyncSend<Destination>, dst: IntoDynSyncSend<Destination>,
sm: Option<Lrc<SourceMap>>, sm: Option<Lrc<SourceMap>>,
@ -647,14 +649,14 @@ pub struct FileWithAnnotatedLines {
multiline_depth: usize, multiline_depth: usize,
} }
impl EmitterWriter { impl HumanEmitter {
pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> HumanEmitter {
let dst = from_stderr(color_config); let dst = from_stderr(color_config);
Self::create(dst, fallback_bundle) Self::create(dst, fallback_bundle)
} }
fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter {
EmitterWriter { HumanEmitter {
dst: IntoDynSyncSend(dst), dst: IntoDynSyncSend(dst),
sm: None, sm: None,
fluent_bundle: None, fluent_bundle: None,
@ -673,7 +675,7 @@ impl EmitterWriter {
pub fn new( pub fn new(
dst: Box<dyn WriteColor + Send>, dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle, fallback_bundle: LazyFallbackBundle,
) -> EmitterWriter { ) -> HumanEmitter {
Self::create(dst, fallback_bundle) Self::create(dst, fallback_bundle)
} }

View file

@ -53,7 +53,7 @@ pub use snippet::Style;
pub use termcolor::{Color, ColorSpec, WriteColor}; pub use termcolor::{Color, ColorSpec, WriteColor};
use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline};
use emitter::{is_case_difference, DynEmitter, Emitter, EmitterWriter}; use emitter::{is_case_difference, DynEmitter, Emitter, HumanEmitter};
use registry::Registry; use registry::Registry;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
@ -525,9 +525,6 @@ pub struct DiagCtxtFlags {
/// If true, immediately emit diagnostics that would otherwise be buffered. /// If true, immediately emit diagnostics that would otherwise be buffered.
/// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
pub dont_buffer_diagnostics: bool, pub dont_buffer_diagnostics: bool,
/// If true, immediately print bugs registered with `span_delayed_bug`.
/// (rustc: see `-Z report-delayed-bugs`)
pub report_delayed_bugs: bool,
/// Show macro backtraces. /// Show macro backtraces.
/// (rustc: see `-Z macro-backtrace`) /// (rustc: see `-Z macro-backtrace`)
pub macro_backtrace: bool, pub macro_backtrace: bool,
@ -574,7 +571,7 @@ impl DiagCtxt {
sm: Option<Lrc<SourceMap>>, sm: Option<Lrc<SourceMap>>,
fallback_bundle: LazyFallbackBundle, fallback_bundle: LazyFallbackBundle,
) -> Self { ) -> Self {
let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm)); let emitter = Box::new(HumanEmitter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm));
Self::with_emitter(emitter) Self::with_emitter(emitter)
} }
pub fn disable_warnings(mut self) -> Self { pub fn disable_warnings(mut self) -> Self {
@ -673,7 +670,7 @@ impl DiagCtxt {
let key = (span.with_parent(None), key); let key = (span.with_parent(None), key);
if diag.is_error() { if diag.is_error() {
if matches!(diag.level, Error { lint: true }) { if diag.level == Error && diag.is_lint {
inner.lint_err_count += 1; inner.lint_err_count += 1;
} else { } else {
inner.err_count += 1; inner.err_count += 1;
@ -697,7 +694,7 @@ impl DiagCtxt {
let key = (span.with_parent(None), key); let key = (span.with_parent(None), key);
let diag = inner.stashed_diagnostics.remove(&key)?; let diag = inner.stashed_diagnostics.remove(&key)?;
if diag.is_error() { if diag.is_error() {
if matches!(diag.level, Error { lint: true }) { if diag.level == Error && diag.is_lint {
inner.lint_err_count -= 1; inner.lint_err_count -= 1;
} else { } else {
inner.err_count -= 1; inner.err_count -= 1;
@ -732,7 +729,7 @@ impl DiagCtxt {
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> { ) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_warn(msg); let mut result = self.struct_warn(msg);
result.set_span(span); result.span(span);
result result
} }
@ -789,7 +786,7 @@ impl DiagCtxt {
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_> { ) -> DiagnosticBuilder<'_> {
let mut result = self.struct_err(msg); let mut result = self.struct_err(msg);
result.set_span(span); result.span(span);
result result
} }
@ -812,7 +809,7 @@ impl DiagCtxt {
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
#[track_caller] #[track_caller]
pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> { pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Error { lint: false }, msg) DiagnosticBuilder::new(self, Error, msg)
} }
/// Construct a builder at the `Error` level with the `msg` and the `code`. /// Construct a builder at the `Error` level with the `msg` and the `code`.
@ -850,7 +847,7 @@ impl DiagCtxt {
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, FatalAbort> { ) -> DiagnosticBuilder<'_, FatalAbort> {
let mut result = self.struct_fatal(msg); let mut result = self.struct_fatal(msg);
result.set_span(span); result.span(span);
result result
} }
@ -878,16 +875,6 @@ impl DiagCtxt {
DiagnosticBuilder::new(self, Fatal, msg) DiagnosticBuilder::new(self, Fatal, msg)
} }
/// Construct a builder at the `Fatal` level with the `msg`, that doesn't abort.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_almost_fatal(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, FatalError> {
DiagnosticBuilder::new(self, Fatal, msg)
}
/// Construct a builder at the `Help` level with the `msg`. /// Construct a builder at the `Help` level with the `msg`.
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
@ -917,7 +904,7 @@ impl DiagCtxt {
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, BugAbort> { ) -> DiagnosticBuilder<'_, BugAbort> {
let mut result = self.struct_bug(msg); let mut result = self.struct_bug(msg);
result.set_span(span); result.span(span);
result result
} }
@ -1004,11 +991,10 @@ impl DiagCtxt {
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug(); let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug();
if treat_next_err_as_bug { if treat_next_err_as_bug {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg); self.span_bug(sp, msg);
} }
let mut diagnostic = Diagnostic::new(DelayedBug, msg); let mut diagnostic = Diagnostic::new(DelayedBug, msg);
diagnostic.set_span(sp); diagnostic.span(sp);
self.emit_diagnostic(diagnostic).unwrap() self.emit_diagnostic(diagnostic).unwrap()
} }
@ -1016,11 +1002,7 @@ impl DiagCtxt {
// where the explanation of what "good path" is (also, it should be renamed). // where the explanation of what "good path" is (also, it should be renamed).
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.borrow_mut();
let diagnostic = Diagnostic::new(DelayedBug, msg);
let mut diagnostic = Diagnostic::new(DelayedBug, msg);
if inner.flags.report_delayed_bugs {
inner.emit_diagnostic_without_consuming(&mut diagnostic);
}
let backtrace = std::backtrace::Backtrace::capture(); let backtrace = std::backtrace::Backtrace::capture();
inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
} }
@ -1039,7 +1021,7 @@ impl DiagCtxt {
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> { ) -> DiagnosticBuilder<'_, ()> {
let mut db = DiagnosticBuilder::new(self, Note, msg); let mut db = DiagnosticBuilder::new(self, Note, msg);
db.set_span(span); db.span(span);
db db
} }
@ -1222,7 +1204,7 @@ impl DiagCtxt {
#[track_caller] #[track_caller]
pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
err.into_diagnostic(self, Error { lint: false }) err.into_diagnostic(self, Error)
} }
#[track_caller] #[track_caller]
@ -1377,7 +1359,7 @@ impl DiagCtxtInner {
for diag in diags { for diag in diags {
// Decrement the count tracking the stash; emitting will increment it. // Decrement the count tracking the stash; emitting will increment it.
if diag.is_error() { if diag.is_error() {
if matches!(diag.level, Error { lint: true }) { if diag.level == Error && diag.is_lint {
self.lint_err_count -= 1; self.lint_err_count -= 1;
} else { } else {
self.err_count -= 1; self.err_count -= 1;
@ -1408,7 +1390,7 @@ impl DiagCtxtInner {
&mut self, &mut self,
diagnostic: &mut Diagnostic, diagnostic: &mut Diagnostic,
) -> Option<ErrorGuaranteed> { ) -> Option<ErrorGuaranteed> {
if matches!(diagnostic.level, Error { .. } | Fatal) && self.treat_err_as_bug() { if matches!(diagnostic.level, Error | Fatal) && self.treat_err_as_bug() {
diagnostic.level = Bug; diagnostic.level = Bug;
} }
@ -1430,10 +1412,8 @@ impl DiagCtxtInner {
self.span_delayed_bugs self.span_delayed_bugs
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
if !self.flags.report_delayed_bugs { #[allow(deprecated)]
#[allow(deprecated)] return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
}
} }
if diagnostic.has_future_breakage() { if diagnostic.has_future_breakage() {
@ -1509,7 +1489,7 @@ impl DiagCtxtInner {
} }
} }
if diagnostic.is_error() { if diagnostic.is_error() {
if matches!(diagnostic.level, Error { lint: true }) { if diagnostic.level == Error && diagnostic.is_lint {
self.bump_lint_err_count(); self.bump_lint_err_count();
} else { } else {
self.bump_err_count(); self.bump_err_count();
@ -1705,11 +1685,7 @@ pub enum Level {
/// most common case. /// most common case.
/// ///
/// Its `EmissionGuarantee` is `ErrorGuaranteed`. /// Its `EmissionGuarantee` is `ErrorGuaranteed`.
Error { Error,
/// If this error comes from a lint, don't abort compilation even when abort_if_errors() is
/// called.
lint: bool,
},
/// A warning about the code being compiled. Does not prevent compilation from finishing. /// A warning about the code being compiled. Does not prevent compilation from finishing.
/// ///
@ -1768,7 +1744,7 @@ impl Level {
fn color(self) -> ColorSpec { fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new(); let mut spec = ColorSpec::new();
match self { match self {
Bug | DelayedBug | Fatal | Error { .. } => { Bug | DelayedBug | Fatal | Error => {
spec.set_fg(Some(Color::Red)).set_intense(true); spec.set_fg(Some(Color::Red)).set_intense(true);
} }
Warning(_) => { Warning(_) => {
@ -1789,7 +1765,7 @@ impl Level {
pub fn to_str(self) -> &'static str { pub fn to_str(self) -> &'static str {
match self { match self {
Bug | DelayedBug => "error: internal compiler error", Bug | DelayedBug => "error: internal compiler error",
Fatal | Error { .. } => "error", Fatal | Error => "error",
Warning(_) => "warning", Warning(_) => "warning",
Note | OnceNote => "note", Note | OnceNote => "note",
Help | OnceHelp => "help", Help | OnceHelp => "help",

View file

@ -855,7 +855,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
Err(mut err) => { Err(mut err) => {
if err.span.is_dummy() { if err.span.is_dummy() {
err.set_span(span); err.span(span);
} }
annotate_err_with_kind(&mut err, kind, span); annotate_err_with_kind(&mut err, kind, span);
err.emit(); err.emit();

View file

@ -379,7 +379,7 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
impl ToInternal<rustc_errors::Level> for Level { impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level { fn to_internal(self) -> rustc_errors::Level {
match self { match self {
Level::Error => rustc_errors::Level::Error { lint: false }, Level::Error => rustc_errors::Level::Error,
Level::Warning => rustc_errors::Level::Warning(None), Level::Warning => rustc_errors::Level::Warning(None),
Level::Note => rustc_errors::Level::Note, Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help, Level::Help => rustc_errors::Level::Help,
@ -497,7 +497,7 @@ impl server::FreeFunctions for Rustc<'_, '_> {
fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) { fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) {
let mut diag = let mut diag =
rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message);
diag.set_span(MultiSpan::from_spans(diagnostic.spans)); diag.span(MultiSpan::from_spans(diagnostic.spans));
for child in diagnostic.children { for child in diagnostic.children {
diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans)); diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans));
} }

View file

@ -7,7 +7,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{BytePos, Span}; use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter; use rustc_errors::emitter::HumanEmitter;
use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use rustc_errors::{DiagCtxt, MultiSpan, PResult};
use termcolor::WriteColor; use termcolor::WriteColor;
@ -30,7 +30,7 @@ fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
false, false,
); );
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) let emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
.sm(Some(source_map.clone())) .sm(Some(source_map.clone()))
.diagnostic_width(Some(140)); .diagnostic_width(Some(140));
let dcx = DiagCtxt::with_emitter(Box::new(emitter)); let dcx = DiagCtxt::with_emitter(Box::new(emitter));

View file

@ -605,7 +605,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let violations = let violations =
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
if !violations.is_empty() { if !violations.is_empty() {
report_object_safety_error(tcx, *span, trait_def_id, &violations).emit(); report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit();
object_safety_violations = true; object_safety_violations = true;
} }
} }

View file

@ -70,7 +70,7 @@ fn generic_arg_mismatch_err(
Res::Err => { Res::Err => {
add_braces_suggestion(arg, &mut err); add_braces_suggestion(arg, &mut err);
return err return err
.set_primary_message("unresolved item provided when a constant was expected") .primary_message("unresolved item provided when a constant was expected")
.emit(); .emit();
} }
Res::Def(DefKind::TyParam, src_def_id) => { Res::Def(DefKind::TyParam, src_def_id) => {

View file

@ -1,7 +1,9 @@
use rustc_ast::TraitObjectSyntax; use rustc_ast::TraitObjectSyntax;
use rustc_errors::{Diagnostic, StashKey}; use rustc_errors::{Diagnostic, StashKey};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use super::AstConv; use super::AstConv;
@ -32,32 +34,146 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
let of_trait_span = of_trait_ref.path.span; let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation // make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
return;
};
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
return; return;
}; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
(span, format!(", {param_name}: {impl_trait_name}")) else {
} else { return;
(generics.span, format!("<{param_name}: {impl_trait_name}>")) };
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
if sugg.is_empty() {
return;
}; };
diag.multipart_suggestion( diag.multipart_suggestion(
format!( format!(
"alternatively use a blanket \ "alternatively use a blanket implementation to implement `{of_trait_name}` for \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`" all types that also implement `{impl_trait_name}`"
), ),
vec![(self_ty.span, param_name), add_generic_sugg], sugg,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
} }
fn add_generic_param_suggestion(
&self,
generics: &hir::Generics<'_>,
self_ty_span: Span,
impl_trait_name: &str,
) -> Vec<(Span, String)> {
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {param_name}: {impl_trait_name}"))
} else {
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
};
vec![(self_ty_span, param_name), add_generic_sugg]
}
/// Make sure that we are in the condition to suggest `impl Trait`.
fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. })
| hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
generics,
..
})) = tcx.hir_node_by_def_id(parent_id)
else {
return false;
};
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
return false;
};
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
let is_object_safe = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|o| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
_ => false,
})
}
_ => false,
};
if let hir::FnRetTy::Return(ty) = sig.decl.output
&& ty.hir_id == self_ty.hir_id
{
let pre = if !is_object_safe {
format!("`{trait_name}` is not object safe, ")
} else {
String::new()
};
let msg = format!(
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
single underlying type",
);
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
if is_object_safe {
diag.multipart_suggestion_verbose(
"alternatively, you can return an owned trait object",
vec![
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
(ty.span.shrink_to_hi(), ">".to_string()),
],
Applicability::MachineApplicable,
);
} else {
// We'll emit the object safety error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
return true;
}
for ty in sig.decl.inputs {
if ty.hir_id != self_ty.hir_id {
continue;
}
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
if !sugg.is_empty() {
diag.multipart_suggestion_verbose(
format!("use a new generic type parameter, constrained by `{trait_name}`"),
sugg,
Applicability::MachineApplicable,
);
diag.multipart_suggestion_verbose(
"you can also use an opaque type, but users won't be able to specify the type \
parameter when calling the `fn`, having to rely exclusively on type inference",
impl_sugg,
Applicability::MachineApplicable,
);
}
if !is_object_safe {
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
// We'll emit the object safety error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
} else {
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
// There are more than one trait bound, we need surrounding parentheses.
vec![
(self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
(self_ty.span.shrink_to_hi(), ")".to_string()),
]
} else {
vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
};
diag.multipart_suggestion_verbose(
format!(
"alternatively, use a trait object to accept any type that implements \
`{trait_name}`, accessing its methods at runtime using dynamic dispatch",
),
sugg,
Applicability::MachineApplicable,
);
}
return true;
}
false
}
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx(); let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@ -98,7 +214,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let label = "add `dyn` keyword before this trait"; let label = "add `dyn` keyword before this trait";
let mut diag = let mut diag =
rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions() { if self_ty.span.can_be_used_for_suggestions()
&& !self.maybe_lint_impl_trait(self_ty, &mut diag)
{
diag.multipart_suggestion_verbose( diag.multipart_suggestion_verbose(
label, label,
sugg, sugg,
@ -116,11 +234,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty.span, self_ty.span,
msg, msg,
|lint| { |lint| {
lint.multipart_suggestion_verbose( if self_ty.span.can_be_used_for_suggestions()
"use `dyn`", && !self.maybe_lint_impl_trait(self_ty, lint)
sugg, {
Applicability::MachineApplicable, lint.multipart_suggestion_verbose(
); "use `dyn`",
sugg,
Applicability::MachineApplicable,
);
}
self.maybe_lint_blanket_trait_impl(self_ty, lint); self.maybe_lint_blanket_trait_impl(self_ty, lint);
}, },
); );

View file

@ -140,6 +140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let reported = report_object_safety_error( let reported = report_object_safety_error(
tcx, tcx,
span, span,
Some(hir_id),
item.trait_ref().def_id(), item.trait_ref().def_id(),
&object_safety_violations, &object_safety_violations,
) )

View file

@ -319,10 +319,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params); let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params);
err.set_span(self.span); err.span(self.span);
err.code(error_code!(E0393)); err.code(error_code!(E0393));
err.set_arg("parameterCount", self.missing_type_params.len()); err.arg("parameterCount", self.missing_type_params.len());
err.set_arg( err.arg(
"parameters", "parameters",
self.missing_type_params self.missing_type_params
.iter() .iter()

View file

@ -73,7 +73,8 @@ pub(super) fn check_fn<'a, 'tcx>(
let inputs_fn = fn_sig.inputs().iter().copied(); let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// Check the pattern. // Check the pattern.
let ty_span = try { inputs_hir?.get(idx)?.span }; let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? };
let ty_span = ty.map(|ty| ty.span);
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
// Check that argument is Sized. // Check that argument is Sized.
@ -81,14 +82,14 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.require_type_is_sized( fcx.require_type_is_sized(
param_ty, param_ty,
param.pat.span, param.pat.span,
// ty_span == binding_span iff this is a closure parameter with no type ascription, // ty.span == binding_span iff this is a closure parameter with no type ascription,
// or if it's an implicit `self` parameter // or if it's an implicit `self` parameter
traits::SizedArgumentType( traits::SizedArgumentType(
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into()) if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
{ {
None None
} else { } else {
ty_span ty.map(|ty| ty.hir_id)
}, },
), ),
); );

View file

@ -215,7 +215,7 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
where where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
diag.set_arg("expr", self.expr.as_deref().unwrap_or("NONE")); diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
// Only explain that `a ..b` is a range if it's split up // Only explain that `a ..b` is a range if it's split up
if self.expr_span.between(self.fru_span).is_empty() { if self.expr_span.between(self.fru_span).is_empty() {

View file

@ -60,7 +60,7 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
// parameters are special cases of patterns, but we want to handle them as // parameters are special cases of patterns, but we want to handle them as
// *distinct* cases. so track when we are hitting a pattern *within* an fn // *distinct* cases. so track when we are hitting a pattern *within* an fn
// parameter. // parameter.
outermost_fn_param_pat: Option<Span>, outermost_fn_param_pat: Option<(Span, hir::HirId)>,
} }
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
@ -131,7 +131,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
} }
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span); let old_outermost_fn_param_pat =
self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id));
intravisit::walk_param(self, param); intravisit::walk_param(self, param);
self.outermost_fn_param_pat = old_outermost_fn_param_pat; self.outermost_fn_param_pat = old_outermost_fn_param_pat;
} }
@ -141,7 +142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
if let PatKind::Binding(_, _, ident, _) = p.kind { if let PatKind::Binding(_, _, ident, _) = p.kind {
let var_ty = self.assign(p.span, p.hir_id, None); let var_ty = self.assign(p.span, p.hir_id, None);
if let Some(ty_span) = self.outermost_fn_param_pat { if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat {
if !self.fcx.tcx.features().unsized_fn_params { if !self.fcx.tcx.features().unsized_fn_params {
self.fcx.require_type_is_sized( self.fcx.require_type_is_sized(
var_ty, var_ty,
@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
{ {
None None
} else { } else {
Some(ty_span) Some(hir_id)
}, },
), ),
); );

View file

@ -961,7 +961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
but its trait bounds were not satisfied" but its trait bounds were not satisfied"
) )
}); });
err.set_primary_message(primary_message); err.primary_message(primary_message);
if let Some(label) = label { if let Some(label) = label {
custom_span_label = true; custom_span_label = true;
err.span_label(span, label); err.span_label(span, label);

View file

@ -247,8 +247,8 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
} }
RegionOriginNote::WithName { span, msg, name, continues } => { RegionOriginNote::WithName { span, msg, name, continues } => {
label_or_note(span, msg); label_or_note(span, msg);
diag.set_arg("name", name); diag.arg("name", name);
diag.set_arg("continues", continues); diag.arg("continues", continues);
} }
RegionOriginNote::WithRequirement { RegionOriginNote::WithRequirement {
span, span,
@ -256,7 +256,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
expected_found: Some((expected, found)), expected_found: Some((expected, found)),
} => { } => {
label_or_note(span, fluent::infer_subtype); label_or_note(span, fluent::infer_subtype);
diag.set_arg("requirement", requirement); diag.arg("requirement", requirement);
diag.note_expected_found(&"", expected, &"", found); diag.note_expected_found(&"", expected, &"", found);
} }
@ -265,7 +265,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
// handling of region checking when type errors are present is // handling of region checking when type errors are present is
// *terrible*. // *terrible*.
label_or_note(span, fluent::infer_subtype_2); label_or_note(span, fluent::infer_subtype_2);
diag.set_arg("requirement", requirement); diag.arg("requirement", requirement);
} }
}; };
} }
@ -298,8 +298,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
diag.span_label(param_span, fluent::infer_declared_different); diag.span_label(param_span, fluent::infer_declared_different);
diag.span_label(ret_span, fluent::infer_nothing); diag.span_label(ret_span, fluent::infer_nothing);
diag.span_label(span, fluent::infer_data_returned); diag.span_label(span, fluent::infer_data_returned);
diag.set_arg("label_var1_exists", label_var1.is_some()); diag.arg("label_var1_exists", label_var1.is_some());
diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
} }
LifetimeMismatchLabels::Normal { LifetimeMismatchLabels::Normal {
hir_equal, hir_equal,
@ -317,16 +317,10 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
diag.span_label(ty_sup, fluent::infer_types_declared_different); diag.span_label(ty_sup, fluent::infer_types_declared_different);
diag.span_label(ty_sub, fluent::infer_nothing); diag.span_label(ty_sub, fluent::infer_nothing);
diag.span_label(span, fluent::infer_data_flows); diag.span_label(span, fluent::infer_data_flows);
diag.set_arg("label_var1_exists", label_var1.is_some()); diag.arg("label_var1_exists", label_var1.is_some());
diag.set_arg( diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
"label_var1", diag.arg("label_var2_exists", label_var2.is_some());
label_var1.map(|x| x.to_string()).unwrap_or_default(), diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default());
);
diag.set_arg("label_var2_exists", label_var2.is_some());
diag.set_arg(
"label_var2",
label_var2.map(|x| x.to_string()).unwrap_or_default(),
);
} }
} }
} }
@ -417,7 +411,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
suggestions, suggestions,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
diag.set_arg("is_impl", is_impl); diag.arg("is_impl", is_impl);
true true
}; };
if mk_suggestion() && self.add_note { if mk_suggestion() && self.add_note {
@ -878,8 +872,8 @@ impl AddToDiagnostic for MoreTargeted {
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
diag.code(rustc_errors::error_code!(E0772)); diag.code(rustc_errors::error_code!(E0772));
diag.set_primary_message(fluent::infer_more_targeted); diag.primary_message(fluent::infer_more_targeted);
diag.set_arg("ident", self.ident); diag.arg("ident", self.ident);
} }
} }
@ -1299,7 +1293,7 @@ impl AddToDiagnostic for SuggestTuplePatternMany {
where where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
diag.set_arg("path", self.path); diag.arg("path", self.path);
let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
diag.multipart_suggestions( diag.multipart_suggestions(
message, message,

View file

@ -164,10 +164,10 @@ impl AddToDiagnostic for RegionExplanation<'_> {
where where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
diag.set_arg("pref_kind", self.prefix); diag.arg("pref_kind", self.prefix);
diag.set_arg("suff_kind", self.suffix); diag.arg("suff_kind", self.suffix);
diag.set_arg("desc_kind", self.desc.kind); diag.arg("desc_kind", self.desc.kind);
diag.set_arg("desc_arg", self.desc.arg); diag.arg("desc_arg", self.desc.arg);
let msg = f(diag, fluent::infer_region_explanation.into()); let msg = f(diag, fluent::infer_region_explanation.into());
if let Some(span) = self.desc.span { if let Some(span) = self.desc.span {

View file

@ -2,9 +2,10 @@ use super::ObjectSafetyViolation;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{struct_span_err, DiagnosticBuilder, MultiSpan}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Map;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
@ -42,6 +43,7 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn report_object_safety_error<'tcx>( pub fn report_object_safety_error<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
span: Span, span: Span,
hir_id: Option<hir::HirId>,
trait_def_id: DefId, trait_def_id: DefId,
violations: &[ObjectSafetyViolation], violations: &[ObjectSafetyViolation],
) -> DiagnosticBuilder<'tcx> { ) -> DiagnosticBuilder<'tcx> {
@ -59,6 +61,24 @@ pub fn report_object_safety_error<'tcx>(
); );
err.span_label(span, format!("`{trait_str}` cannot be made into an object")); err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
if let Some(hir_id) = hir_id
&& let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id)
&& let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
{
let mut hir_id = hir_id;
while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) {
hir_id = ty.hir_id;
}
if tcx.hir().get_parent(hir_id).fn_sig().is_some() {
// Do not suggest `impl Trait` when dealing with things like super-traits.
err.span_suggestion_verbose(
ty.span.until(trait_ref.span),
"consider using an opaque type instead",
"impl ",
Applicability::MaybeIncorrect,
);
}
}
let mut reported_violations = FxIndexSet::default(); let mut reported_violations = FxIndexSet::default();
let mut multi_span = vec![]; let mut multi_span = vec![];
let mut messages = vec![]; let mut messages = vec![];

View file

@ -6,8 +6,8 @@ use rustc_session::config::{
build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, NextSolverConfig, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy,
OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
}; };
use rustc_session::lint::Level; use rustc_session::lint::Level;
@ -666,7 +666,6 @@ fn test_unstable_options_tracking_hash() {
untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true); untracked!(dump_mir_graphviz, true);
untracked!(dump_mir_spanview, Some(MirSpanview::Statement));
untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into()))); untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json); untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json);
untracked!(dylib_lto, true); untracked!(dylib_lto, true);
@ -806,7 +805,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(relax_elf_relocations, Some(true)); tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full)); tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS); tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_cfi_canonical_jump_tables, None); tracked!(sanitizer_cfi_canonical_jump_tables, None);
tracked!(sanitizer_cfi_generalize_pointers, Some(true)); tracked!(sanitizer_cfi_generalize_pointers, Some(true));

View file

@ -31,7 +31,7 @@ impl AddToDiagnostic for OverruledAttributeSub {
match self { match self {
OverruledAttributeSub::DefaultSource { id } => { OverruledAttributeSub::DefaultSource { id } => {
diag.note(fluent::lint_default_source); diag.note(fluent::lint_default_source);
diag.set_arg("id", id); diag.arg("id", id);
} }
OverruledAttributeSub::NodeSource { span, reason } => { OverruledAttributeSub::NodeSource { span, reason } => {
diag.span_label(span, fluent::lint_node_source); diag.span_label(span, fluent::lint_node_source);

View file

@ -1069,7 +1069,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
Some(span.into()), Some(span.into()),
fluent::lint_unknown_gated_lint, fluent::lint_unknown_gated_lint,
|lint| { |lint| {
lint.set_arg("name", lint_id.lint.name_lower()); lint.arg("name", lint_id.lint.name_lower());
lint.note(fluent::lint_note); lint.note(fluent::lint_note);
rustc_session::parse::add_feature_diagnostics_for_issue( rustc_session::parse::add_feature_diagnostics_for_issue(
lint, lint,

View file

@ -5,8 +5,8 @@ use std::num::NonZeroU32;
use crate::errors::RequestedLevel; use crate::errors::RequestedLevel;
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use rustc_errors::{ use rustc_errors::{
AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString, AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
SuggestionStyle, DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle,
}; };
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic};
@ -135,7 +135,7 @@ pub struct BuiltinMissingDebugImpl<'a> {
// Needed for def_path_str // Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> { impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("debug", self.tcx.def_path_str(self.def_id)); diag.arg("debug", self.tcx.def_path_str(self.def_id));
} }
fn msg(&self) -> DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
@ -239,7 +239,7 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
} }
impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.span_label(self.label, fluent::lint_label); diag.span_label(self.label, fluent::lint_label);
rustc_session::parse::add_feature_diagnostics( rustc_session::parse::add_feature_diagnostics(
diag, diag,
@ -268,12 +268,9 @@ pub struct SuggestChangingAssocTypes<'a, 'b> {
} }
impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
// bound. Let's see if this type does that. // bound. Let's see if this type does that.
@ -281,7 +278,7 @@ impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> {
// We use a HIR visitor to walk the type. // We use a HIR visitor to walk the type.
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
struct WalkAssocTypes<'a> { struct WalkAssocTypes<'a> {
err: &'a mut rustc_errors::Diagnostic, err: &'a mut Diagnostic,
} }
impl Visitor<'_> for WalkAssocTypes<'_> { impl Visitor<'_> for WalkAssocTypes<'_> {
fn visit_qpath( fn visit_qpath(
@ -326,12 +323,9 @@ pub struct BuiltinTypeAliasGenericBoundsSuggestion {
} }
impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
diag.multipart_suggestion( diag.multipart_suggestion(
fluent::lint_suggestion, fluent::lint_suggestion,
@ -425,8 +419,8 @@ pub struct BuiltinUnpermittedTypeInit<'a> {
} }
impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty); diag.arg("ty", self.ty);
diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) { if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) {
// Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited. // Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited.
@ -438,7 +432,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
self.sub.add_to_diagnostic(diag); self.sub.add_to_diagnostic(diag);
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
self.msg.clone() self.msg.clone()
} }
} }
@ -449,12 +443,9 @@ pub struct BuiltinUnpermittedTypeInitSub {
} }
impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
let mut err = self.err; let mut err = self.err;
loop { loop {
@ -506,12 +497,9 @@ pub struct BuiltinClashingExternSub<'a> {
} }
impl AddToDiagnostic for BuiltinClashingExternSub<'_> { impl AddToDiagnostic for BuiltinClashingExternSub<'_> {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
let mut expected_str = DiagnosticStyledString::new(); let mut expected_str = DiagnosticStyledString::new();
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
@ -779,12 +767,9 @@ pub struct HiddenUnicodeCodepointsDiagLabels {
} }
impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
for (c, span) in self.spans { for (c, span) in self.spans {
diag.span_label(span, format!("{c:?}")); diag.span_label(span, format!("{c:?}"));
@ -799,12 +784,9 @@ pub enum HiddenUnicodeCodepointsDiagSub {
// Used because of multiple multipart_suggestion and note // Used because of multiple multipart_suggestion and note
impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
match self { match self {
HiddenUnicodeCodepointsDiagSub::Escape { spans } => { HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
@ -830,7 +812,7 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
// should do the same here to provide the same good suggestions as we do for // should do the same here to provide the same good suggestions as we do for
// literals above. // literals above.
diag.set_arg( diag.arg(
"escaped", "escaped",
spans spans
.into_iter() .into_iter()
@ -953,12 +935,9 @@ pub struct NonBindingLetSub {
} }
impl AddToDiagnostic for NonBindingLetSub { impl AddToDiagnostic for NonBindingLetSub {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
self.suggestion, self.suggestion,
@ -1147,8 +1126,8 @@ pub struct NonFmtPanicUnused {
// Used because of two suggestions based on one Option<Span> // Used because of two suggestions based on one Option<Span>
impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("count", self.count); diag.arg("count", self.count);
diag.note(fluent::lint_note); diag.note(fluent::lint_note);
if let Some(span) = self.suggestion { if let Some(span) = self.suggestion {
diag.span_suggestion( diag.span_suggestion(
@ -1166,7 +1145,7 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
} }
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_non_fmt_panic_unused fluent::lint_non_fmt_panic_unused
} }
} }
@ -1224,12 +1203,9 @@ pub enum NonSnakeCaseDiagSub {
} }
impl AddToDiagnostic for NonSnakeCaseDiagSub { impl AddToDiagnostic for NonSnakeCaseDiagSub {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
match self { match self {
NonSnakeCaseDiagSub::Label { span } => { NonSnakeCaseDiagSub::Label { span } => {
@ -1342,12 +1318,12 @@ pub struct DropTraitConstraintsDiag<'a> {
// Needed for def_path_str // Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> { impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("predicate", self.predicate); diag.arg("predicate", self.predicate);
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); diag.arg("needs_drop", self.tcx.def_path_str(self.def_id));
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_drop_trait_constraints fluent::lint_drop_trait_constraints
} }
} }
@ -1359,11 +1335,11 @@ pub struct DropGlue<'a> {
// Needed for def_path_str // Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); diag.arg("needs_drop", self.tcx.def_path_str(self.def_id));
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_drop_glue fluent::lint_drop_glue
} }
} }
@ -1423,12 +1399,9 @@ pub enum OverflowingBinHexSign {
} }
impl AddToDiagnostic for OverflowingBinHexSign { impl AddToDiagnostic for OverflowingBinHexSign {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where where
F: Fn( F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{ {
match self { match self {
OverflowingBinHexSign::Positive => { OverflowingBinHexSign::Positive => {
@ -1633,9 +1606,9 @@ pub struct ImproperCTypes<'a> {
// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span> // Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span>
impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty); diag.arg("ty", self.ty);
diag.set_arg("desc", self.desc); diag.arg("desc", self.desc);
diag.span_label(self.label, fluent::lint_label); diag.span_label(self.label, fluent::lint_label);
if let Some(help) = self.help { if let Some(help) = self.help {
diag.help(help); diag.help(help);
@ -1646,7 +1619,7 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
} }
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_improper_ctypes fluent::lint_improper_ctypes
} }
} }
@ -1776,10 +1749,10 @@ pub enum UnusedDefSuggestion {
// Needed because of def_path_str // Needed because of def_path_str
impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.set_arg("pre", self.pre); diag.arg("pre", self.pre);
diag.set_arg("post", self.post); diag.arg("post", self.post);
diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); diag.arg("def", self.cx.tcx.def_path_str(self.def_id));
// check for #[must_use = "..."] // check for #[must_use = "..."]
if let Some(note) = self.note { if let Some(note) = self.note {
diag.note(note.to_string()); diag.note(note.to_string());
@ -1789,7 +1762,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
} }
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_unused_def fluent::lint_unused_def
} }
} }
@ -1859,14 +1832,14 @@ pub struct AsyncFnInTraitDiag {
} }
impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag { impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.note(fluent::lint_note); diag.note(fluent::lint_note);
if let Some(sugg) = self.sugg { if let Some(sugg) = self.sugg {
diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect);
} }
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> DiagnosticMessage {
fluent::lint_async_fn_in_trait fluent::lint_async_fn_in_trait
} }
} }

View file

@ -121,7 +121,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
#[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::diagnostic_outside_of_impl)]
cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
lint.set_arg("name", symbol); lint.arg("name", symbol);
lint.note(fluent::lint_note); lint.note(fluent::lint_note);
lint.note(fluent::lint_more_info_note); lint.note(fluent::lint_more_info_note);
if !is_arg_inside_call(arg_span, span) { if !is_arg_inside_call(arg_span, span) {
@ -180,7 +180,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
fmt_applicability, fmt_applicability,
); );
} else if suggest_debug { } else if suggest_debug {
lint.set_arg("ty", ty); lint.arg("ty", ty);
lint.span_suggestion_verbose( lint.span_suggestion_verbose(
arg_span.shrink_to_lo(), arg_span.shrink_to_lo(),
fluent::lint_debug_suggestion, fluent::lint_debug_suggestion,
@ -191,7 +191,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_panic_any { if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) { if let Some((open, close, del)) = find_delimiters(cx, span) {
lint.set_arg("already_suggested", suggest_display || suggest_debug); lint.arg("already_suggested", suggest_display || suggest_debug);
lint.multipart_suggestion( lint.multipart_suggestion(
fluent::lint_panic_suggestion, fluent::lint_panic_suggestion,
if del == '(' { if del == '(' {

View file

@ -5,8 +5,8 @@ use crate::diagnostics::error::{
}; };
use crate::diagnostics::utils::{ use crate::diagnostics::utils::{
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
should_generate_set_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, should_generate_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy,
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
}; };
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
@ -125,15 +125,15 @@ impl DiagnosticDeriveVariantBuilder {
} }
/// Generates calls to `span_label` and similar functions based on the attributes on fields or /// Generates calls to `span_label` and similar functions based on the attributes on fields or
/// calls to `set_arg` when no attributes are present. /// calls to `arg` when no attributes are present.
pub(crate) fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { pub(crate) fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream {
let mut body = quote! {}; let mut body = quote! {};
// Generate `set_arg` calls first.. // Generate `arg` calls first..
for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) { for binding in variant.bindings().iter().filter(|bi| should_generate_arg(bi.ast())) {
body.extend(self.generate_field_code(binding)); body.extend(self.generate_field_code(binding));
} }
// ..and then subdiagnostic additions. // ..and then subdiagnostic additions.
for binding in variant.bindings().iter().filter(|bi| !should_generate_set_arg(bi.ast())) { for binding in variant.bindings().iter().filter(|bi| !should_generate_arg(bi.ast())) {
body.extend(self.generate_field_attrs_code(binding)); body.extend(self.generate_field_attrs_code(binding));
} }
body body
@ -253,7 +253,7 @@ impl DiagnosticDeriveVariantBuilder {
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! { quote! {
diag.set_arg( diag.arg(
stringify!(#ident), stringify!(#ident),
#field_binding #field_binding
); );
@ -312,7 +312,7 @@ impl DiagnosticDeriveVariantBuilder {
let name = ident.to_string(); let name = ident.to_string();
match (&attr.meta, name.as_str()) { match (&attr.meta, name.as_str()) {
// Don't need to do anything - by virtue of the attribute existing, the // Don't need to do anything - by virtue of the attribute existing, the
// `set_arg` call will not be generated. // `arg` call will not be generated.
(Meta::Path(_), "skip_arg") => return Ok(quote! {}), (Meta::Path(_), "skip_arg") => return Ok(quote! {}),
(Meta::Path(_), "primary_span") => { (Meta::Path(_), "primary_span") => {
match self.kind { match self.kind {
@ -320,7 +320,7 @@ impl DiagnosticDeriveVariantBuilder {
report_error_if_not_applied_to_span(attr, &info)?; report_error_if_not_applied_to_span(attr, &info)?;
return Ok(quote! { return Ok(quote! {
diag.set_span(#binding); diag.span(#binding);
}); });
} }
DiagnosticDeriveKind::LintDiagnostic => { DiagnosticDeriveKind::LintDiagnostic => {

View file

@ -6,8 +6,8 @@ use crate::diagnostics::error::{
use crate::diagnostics::utils::{ use crate::diagnostics::utils::{
build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident, build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, should_generate_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap,
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, SetOnce, SpannedOption, SubdiagnosticKind,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -214,7 +214,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
} }
/// Generates the code for a field with no attributes. /// Generates the code for a field with no attributes.
fn generate_field_set_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
let diag = &self.parent.diag; let diag = &self.parent.diag;
let field = binding_info.ast(); let field = binding_info.ast();
@ -225,7 +225,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! { quote! {
#diag.set_arg( #diag.arg(
stringify!(#ident), stringify!(#ident),
#field_binding #field_binding
); );
@ -505,7 +505,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant .variant
.bindings() .bindings()
.iter() .iter()
.filter(|binding| !should_generate_set_arg(binding.ast())) .filter(|binding| !should_generate_arg(binding.ast()))
.map(|binding| self.generate_field_attr_code(binding, kind_stats)) .map(|binding| self.generate_field_attr_code(binding, kind_stats))
.collect(); .collect();
@ -593,8 +593,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant .variant
.bindings() .bindings()
.iter() .iter()
.filter(|binding| should_generate_set_arg(binding.ast())) .filter(|binding| should_generate_arg(binding.ast()))
.map(|binding| self.generate_field_set_arg(binding)) .map(|binding| self.generate_field_arg(binding))
.collect(); .collect();
let formatting_init = &self.formatting_init; let formatting_init = &self.formatting_init;

View file

@ -584,7 +584,7 @@ pub(super) enum SubdiagnosticKind {
suggestion_kind: SuggestionKind, suggestion_kind: SuggestionKind,
applicability: SpannedOption<Applicability>, applicability: SpannedOption<Applicability>,
/// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation /// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation
/// of formatting and diagnostic emission so that `set_arg` calls can happen in-between.. /// of formatting and diagnostic emission so that `arg` calls can happen in-between..
code_field: syn::Ident, code_field: syn::Ident,
/// Initialization logic for `code_field`'s variable, e.g. /// Initialization logic for `code_field`'s variable, e.g.
/// `let __formatted_code = /* whatever */;` /// `let __formatted_code = /* whatever */;`
@ -863,9 +863,9 @@ impl quote::IdentFragment for SubdiagnosticKind {
} }
} }
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic /// Returns `true` if `field` should generate a `arg` call rather than any other diagnostic
/// call (like `span_label`). /// call (like `span_label`).
pub(super) fn should_generate_set_arg(field: &Field) -> bool { pub(super) fn should_generate_arg(field: &Field) -> bool {
// Perhaps this should be an exhaustive list... // Perhaps this should be an exhaustive list...
field.attrs.iter().all(|attr| is_doc_comment(attr)) field.attrs.iter().all(|attr| is_doc_comment(attr))
} }

View file

@ -500,10 +500,10 @@ pub(crate) struct MultipleCandidates {
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for MultipleCandidates { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for MultipleCandidates {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates);
diag.set_arg("crate_name", self.crate_name); diag.arg("crate_name", self.crate_name);
diag.set_arg("flavor", self.flavor); diag.arg("flavor", self.flavor);
diag.code(error_code!(E0464)); diag.code(error_code!(E0464));
diag.set_span(self.span); diag.span(self.span);
for (i, candidate) in self.candidates.iter().enumerate() { for (i, candidate) in self.candidates.iter().enumerate() {
diag.note(format!("candidate #{}: {}", i + 1, candidate.display())); diag.note(format!("candidate #{}: {}", i + 1, candidate.display()));
} }
@ -596,10 +596,10 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidMetadataFiles {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files);
diag.set_arg("crate_name", self.crate_name); diag.arg("crate_name", self.crate_name);
diag.set_arg("add_info", self.add_info); diag.arg("add_info", self.add_info);
diag.code(error_code!(E0786)); diag.code(error_code!(E0786));
diag.set_span(self.span); diag.span(self.span);
for crate_rejection in self.crate_rejections { for crate_rejection in self.crate_rejections {
diag.note(crate_rejection); diag.note(crate_rejection);
} }
@ -623,12 +623,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for CannotFindCrate {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_cannot_find_crate); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_cannot_find_crate);
diag.set_arg("crate_name", self.crate_name); diag.arg("crate_name", self.crate_name);
diag.set_arg("current_crate", self.current_crate); diag.arg("current_crate", self.current_crate);
diag.set_arg("add_info", self.add_info); diag.arg("add_info", self.add_info);
diag.set_arg("locator_triple", self.locator_triple.triple()); diag.arg("locator_triple", self.locator_triple.triple());
diag.code(error_code!(E0463)); diag.code(error_code!(E0463));
diag.set_span(self.span); diag.span(self.span);
if (self.crate_name == sym::std || self.crate_name == sym::core) if (self.crate_name == sym::std || self.crate_name == sym::core)
&& self.locator_triple != TargetTriple::from_triple(config::host_triple()) && self.locator_triple != TargetTriple::from_triple(config::host_triple())
{ {

View file

@ -314,14 +314,14 @@ pub fn struct_lint_level(
} }
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)), Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None), Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None),
Level::Deny | Level::Forbid => rustc_errors::Level::Error { lint: true }, Level::Deny | Level::Forbid => rustc_errors::Level::Error,
}; };
let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, ""); let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
if let Some(span) = span { if let Some(span) = span {
err.set_span(span); err.span(span);
} }
err.set_is_lint(); err.is_lint();
// If this code originates in a foreign macro, aka something that this crate // If this code originates in a foreign macro, aka something that this crate
// did not itself author, then it's likely that there's nothing this crate // did not itself author, then it's likely that there's nothing this crate
@ -348,7 +348,7 @@ pub fn struct_lint_level(
// Delay evaluating and setting the primary message until after we've // Delay evaluating and setting the primary message until after we've
// suppressed the lint due to macros. // suppressed the lint due to macros.
err.set_primary_message(msg); err.primary_message(msg);
// Lint diagnostics that are covered by the expect level will not be emitted outside // Lint diagnostics that are covered by the expect level will not be emitted outside
// the compiler. It is therefore not necessary to add any information for the user. // the compiler. It is therefore not necessary to add any information for the user.

View file

@ -2,14 +2,10 @@ use super::{AllocId, AllocRange, Pointer, Scalar};
use crate::error; use crate::error;
use crate::mir::{ConstAlloc, ConstValue}; use crate::mir::{ConstAlloc, ConstValue};
use crate::query::TyCtxtAt;
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock; use rustc_data_structures::sync::Lock;
use rustc_errors::{ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
IntoDiagnosticArg,
};
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace; use rustc_session::CtfeBacktrace;
use rustc_span::{def_id::DefId, Span, DUMMY_SP}; use rustc_span::{def_id::DefId, Span, DUMMY_SP};
@ -90,10 +86,6 @@ pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
/// This is needed in `thir::pattern::lower_inline_const`. /// This is needed in `thir::pattern::lower_inline_const`.
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>; pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
struct_span_err!(tcx.dcx(), tcx.span, E0080, "{}", msg)
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(InterpErrorInfo<'_>, 8); static_assert_size!(InterpErrorInfo<'_>, 8);

View file

@ -142,12 +142,11 @@ use crate::ty::GenericArgKind;
use crate::ty::{self, Instance, Ty, TyCtxt}; use crate::ty::{self, Instance, Ty, TyCtxt};
pub use self::error::{ pub use self::error::{
struct_error, BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult,
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo,
InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind,
MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
ValidationErrorKind,
}; };
pub use self::value::Scalar; pub use self::value::Scalar;

View file

@ -55,7 +55,6 @@ pub mod mono;
pub mod patch; pub mod patch;
pub mod pretty; pub mod pretty;
mod query; mod query;
pub mod spanview;
mod statement; mod statement;
mod syntax; mod syntax;
pub mod tcx; pub mod tcx;

View file

@ -5,7 +5,6 @@ use std::io::{self, Write as _};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use super::graphviz::write_mir_fn_graphviz; use super::graphviz::write_mir_fn_graphviz;
use super::spanview::write_mir_fn_spanview;
use rustc_ast::InlineAsmTemplatePiece; use rustc_ast::InlineAsmTemplatePiece;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{
alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer,
@ -141,16 +140,6 @@ fn dump_matched_mir_node<'tcx, F>(
write_mir_fn_graphviz(tcx, body, false, &mut file)?; write_mir_fn_graphviz(tcx, body, false, &mut file)?;
}; };
} }
if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview {
let _: io::Result<()> = try {
let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body);
let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?;
if body.source.def_id().is_local() {
write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?;
}
};
}
} }
/// Returns the file basename portion (without extension) of a filename path /// Returns the file basename portion (without extension) of a filename path

View file

@ -1,642 +0,0 @@
use rustc_middle::hir;
use rustc_middle::mir::*;
use rustc_session::config::MirSpanview;
use rustc_span::{BytePos, Pos};
use std::cmp;
use std::io::{self, Write};
pub const TOOLTIP_INDENT: &str = " ";
const CARET: char = '\u{2038}'; // Unicode `CARET`
const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET`
const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET`
const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
const HEADER: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">"#;
const START_BODY: &str = r#"</head>
<body>"#;
const FOOTER: &str = r#"</body>
</html>"#;
const STYLE_SECTION: &str = r#"<style>
.line {
counter-increment: line;
}
.line:before {
content: counter(line) ": ";
font-family: Menlo, Monaco, monospace;
font-style: italic;
width: 3.8em;
display: inline-block;
text-align: right;
filter: opacity(50%);
-webkit-user-select: none;
}
.code {
color: #dddddd;
background-color: #222222;
font-family: Menlo, Monaco, monospace;
line-height: 1.4em;
border-bottom: 2px solid #222222;
white-space: pre;
display: inline-block;
}
.odd {
background-color: #55bbff;
color: #223311;
}
.even {
background-color: #ee7756;
color: #551133;
}
.code {
--index: calc(var(--layer) - 1);
padding-top: calc(var(--index) * 0.15em);
filter:
hue-rotate(calc(var(--index) * 25deg))
saturate(calc(100% - (var(--index) * 2%)))
brightness(calc(100% - (var(--index) * 1.5%)));
}
.annotation {
color: #4444ff;
font-family: monospace;
font-style: italic;
display: none;
-webkit-user-select: none;
}
body:active .annotation {
/* requires holding mouse down anywhere on the page */
display: inline-block;
}
span:hover .annotation {
/* requires hover over a span ONLY on its first line */
display: inline-block;
}
</style>"#;
/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator.
#[derive(Clone, Debug)]
pub struct SpanViewable {
pub bb: BasicBlock,
pub span: Span,
pub id: String,
pub tooltip: String,
}
/// Write a spanview HTML+CSS file to analyze MIR element spans.
pub fn write_mir_fn_spanview<'tcx, W>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
spanview: MirSpanview,
title: &str,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
let def_id = body.source.def_id();
let hir_body = hir_body(tcx, def_id);
if hir_body.is_none() {
return Ok(());
}
let body_span = hir_body.unwrap().value.span;
let mut span_viewables = Vec::new();
for (bb, data) in body.basic_blocks.iter_enumerated() {
match spanview {
MirSpanview::Statement => {
for (i, statement) in data.statements.iter().enumerate() {
if let Some(span_viewable) =
statement_span_viewable(tcx, body_span, bb, i, statement)
{
span_viewables.push(span_viewable);
}
}
if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
MirSpanview::Terminator => {
if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
MirSpanview::Block => {
if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
}
}
write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?;
Ok(())
}
/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated
/// list `SpanViewable`s.
pub fn write_document<'tcx, W>(
tcx: TyCtxt<'tcx>,
spanview_span: Span,
mut span_viewables: Vec<SpanViewable>,
title: &str,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
let mut from_pos = spanview_span.lo();
let end_pos = spanview_span.hi();
let source_map = tcx.sess.source_map();
let start = source_map.lookup_char_pos(from_pos);
let indent_to_initial_start_col = " ".repeat(start.col.to_usize());
debug!(
"spanview_span={:?}; source is:\n{}{}",
spanview_span,
indent_to_initial_start_col,
source_map.span_to_snippet(spanview_span).expect("function should have printable source")
);
writeln!(w, "{HEADER}")?;
writeln!(w, "<title>{title}</title>")?;
writeln!(w, "{STYLE_SECTION}")?;
writeln!(w, "{START_BODY}")?;
write!(
w,
r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
start.line - 1,
indent_to_initial_start_col,
)?;
span_viewables.sort_unstable_by(|a, b| {
let a = a.span;
let b = b.span;
if a.lo() == b.lo() {
// Sort hi() in reverse order so shorter spans are attempted after longer spans.
// This should give shorter spans a higher "layer", so they are not covered by
// the longer spans.
b.hi().partial_cmp(&a.hi())
} else {
a.lo().partial_cmp(&b.lo())
}
.unwrap()
});
let mut ordered_viewables = &span_viewables[..];
const LOWEST_VIEWABLE_LAYER: usize = 1;
let mut alt = false;
while ordered_viewables.len() > 0 {
debug!(
"calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}",
from_pos.to_usize(),
end_pos.to_usize(),
ordered_viewables.len()
);
let curr_id = &ordered_viewables[0].id;
let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps(
tcx,
from_pos,
end_pos,
ordered_viewables,
alt,
LOWEST_VIEWABLE_LAYER,
w,
)?;
debug!(
"DONE calling write_next_viewable, with new from_pos={}, \
and remaining viewables len={}",
next_from_pos.to_usize(),
next_ordered_viewables.len()
);
assert!(
from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(),
"write_next_viewable_with_overlaps() must make a state change"
);
from_pos = next_from_pos;
if next_ordered_viewables.len() != ordered_viewables.len() {
ordered_viewables = next_ordered_viewables;
if let Some(next_ordered_viewable) = ordered_viewables.first() {
if &next_ordered_viewable.id != curr_id {
alt = !alt;
}
}
}
}
if from_pos < end_pos {
write_coverage_gap(tcx, from_pos, end_pos, w)?;
}
writeln!(w, r#"</span></div>"#)?;
writeln!(w, "{FOOTER}")?;
Ok(())
}
/// Format a string showing the start line and column, and end line and column within a file.
pub fn source_range_no_file(tcx: TyCtxt<'_>, span: Span) -> String {
let source_map = tcx.sess.source_map();
let start = source_map.lookup_char_pos(span.lo());
let end = source_map.lookup_char_pos(span.hi());
format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1)
}
fn statement_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
i: usize,
statement: &Statement<'tcx>,
) -> Option<SpanViewable> {
let span = statement.source_info.span;
if !body_span.contains(span) {
return None;
}
let id = format!("{}[{}]", bb.index(), i);
let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None);
Some(SpanViewable { bb, span, id, tooltip })
}
fn terminator_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
data: &BasicBlockData<'tcx>,
) -> Option<SpanViewable> {
let term = data.terminator();
let span = term.source_info.span;
if !body_span.contains(span) {
return None;
}
let id = format!("{}:{}", bb.index(), term.kind.name());
let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator);
Some(SpanViewable { bb, span, id, tooltip })
}
fn block_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
data: &BasicBlockData<'tcx>,
) -> Option<SpanViewable> {
let span = compute_block_span(data, body_span);
if !body_span.contains(span) {
return None;
}
let id = format!("{}", bb.index());
let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator);
Some(SpanViewable { bb, span, id, tooltip })
}
fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span {
let mut span = data.terminator().source_info.span;
for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
// Only combine Spans from the root context, and within the function's body_span.
if statement_span.ctxt().is_root() && body_span.contains(statement_span) {
span = span.to(statement_span);
}
}
span
}
/// Recursively process each ordered span. Spans that overlap will have progressively varying
/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will
/// have alternating style choices, to help distinguish between them if, visually adjacent.
/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true
/// and false, for each adjacent non-overlapping span. Source code between the spans (code
/// that is not in any coverage region) has neutral styling.
fn write_next_viewable_with_overlaps<'tcx, 'b, W>(
tcx: TyCtxt<'tcx>,
mut from_pos: BytePos,
mut to_pos: BytePos,
ordered_viewables: &'b [SpanViewable],
alt: bool,
layer: usize,
w: &mut W,
) -> io::Result<(BytePos, &'b [SpanViewable])>
where
W: Write,
{
let debug_indent = " ".repeat(layer);
let (viewable, mut remaining_viewables) =
ordered_viewables.split_first().expect("ordered_viewables should have some");
if from_pos < viewable.span.lo() {
debug!(
"{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \
of {:?}), with to_pos={}",
debug_indent,
from_pos.to_usize(),
viewable.span.lo().to_usize(),
viewable.span,
to_pos.to_usize()
);
let hi = cmp::min(viewable.span.lo(), to_pos);
write_coverage_gap(tcx, from_pos, hi, w)?;
from_pos = hi;
if from_pos < viewable.span.lo() {
debug!(
"{}EARLY RETURN: stopped before getting to next SpanViewable, at {}",
debug_indent,
from_pos.to_usize()
);
return Ok((from_pos, ordered_viewables));
}
}
if from_pos < viewable.span.hi() {
// Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing
// with room to print the tail.
to_pos = cmp::min(viewable.span.hi(), to_pos);
debug!(
"{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}",
debug_indent,
viewable.span.hi().to_usize(),
to_pos.to_usize()
);
}
let mut subalt = false;
while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) {
let overlapping_viewable = &remaining_viewables[0];
debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span);
let span =
trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos));
let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() {
// `viewable` is not yet fully rendered, so start writing the span, up to either the
// `to_pos` or the next `overlapping_viewable`, whichever comes first.
debug!(
"{}make html_snippet (may not write it if early exit) for partial span {:?} \
of viewable.span {:?}",
debug_indent, span, viewable.span
);
from_pos = span.hi();
make_html_snippet(tcx, span, Some(viewable))
} else {
None
};
// Defer writing the HTML snippet (until after early return checks) ONLY for empty spans.
// An empty Span with Some(html_snippet) is probably a tail marker. If there is an early
// exit, there should be another opportunity to write the tail marker.
if !span.is_empty() {
if let Some(ref html_snippet) = some_html_snippet {
debug!(
"{}write html_snippet for that partial span of viewable.span {:?}",
debug_indent, viewable.span
);
write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
}
some_html_snippet = None;
}
if from_pos < overlapping_viewable.span.lo() {
debug!(
"{}EARLY RETURN: from_pos={} has not yet reached the \
overlapping_viewable.span {:?}",
debug_indent,
from_pos.to_usize(),
overlapping_viewable.span
);
// must have reached `to_pos` before reaching the start of the
// `overlapping_viewable.span`
return Ok((from_pos, ordered_viewables));
}
if from_pos == to_pos
&& !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty())
{
debug!(
"{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \
empty, or not from_pos",
debug_indent,
to_pos.to_usize(),
overlapping_viewable.span
);
// `to_pos` must have occurred before the overlapping viewable. Return
// `ordered_viewables` so we can continue rendering the `viewable`, from after the
// `to_pos`.
return Ok((from_pos, ordered_viewables));
}
if let Some(ref html_snippet) = some_html_snippet {
debug!(
"{}write html_snippet for that partial span of viewable.span {:?}",
debug_indent, viewable.span
);
write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
}
debug!(
"{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \
and viewables len={}",
debug_indent,
from_pos.to_usize(),
to_pos.to_usize(),
remaining_viewables.len()
);
// Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`.
let curr_id = &remaining_viewables[0].id;
let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps(
tcx,
from_pos,
to_pos,
remaining_viewables,
subalt,
layer + 1,
w,
)?;
debug!(
"{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \
viewables len={}",
debug_indent,
next_from_pos.to_usize(),
next_remaining_viewables.len()
);
assert!(
from_pos != next_from_pos
|| remaining_viewables.len() != next_remaining_viewables.len(),
"write_next_viewable_with_overlaps() must make a state change"
);
from_pos = next_from_pos;
if next_remaining_viewables.len() != remaining_viewables.len() {
remaining_viewables = next_remaining_viewables;
if let Some(next_ordered_viewable) = remaining_viewables.first() {
if &next_ordered_viewable.id != curr_id {
subalt = !subalt;
}
}
}
}
if from_pos <= viewable.span.hi() {
let span = trim_span(viewable.span, from_pos, to_pos);
debug!(
"{}After overlaps, writing (end span?) {:?} of viewable.span {:?}",
debug_indent, span, viewable.span
);
if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(viewable)) {
from_pos = span.hi();
write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
}
}
debug!("{}RETURN: No more overlap", debug_indent);
Ok((
from_pos,
if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables },
))
}
#[inline(always)]
fn write_coverage_gap<W>(tcx: TyCtxt<'_>, lo: BytePos, hi: BytePos, w: &mut W) -> io::Result<()>
where
W: Write,
{
let span = Span::with_root_ctxt(lo, hi);
if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) {
write_span(html_snippet, "", false, 0, w)
} else {
Ok(())
}
}
fn write_span<W>(
html_snippet: &str,
tooltip: &str,
alt: bool,
layer: usize,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
let maybe_alt_class = if layer > 0 { if alt { " odd" } else { " even" } } else { "" };
let maybe_title_attr = if !tooltip.is_empty() {
format!(" title=\"{}\"", escape_attr(tooltip))
} else {
"".to_owned()
};
if layer == 1 {
write!(w, "<span>")?;
}
for (i, line) in html_snippet.lines().enumerate() {
if i > 0 {
write!(w, "{NEW_LINE_SPAN}")?;
}
write!(
w,
r#"<span class="code{maybe_alt_class}" style="--layer: {layer}"{maybe_title_attr}>{line}</span>"#
)?;
}
// Check for and translate trailing newlines, because `str::lines()` ignores them
if html_snippet.ends_with('\n') {
write!(w, "{NEW_LINE_SPAN}")?;
}
if layer == 1 {
write!(w, "</span>")?;
}
Ok(())
}
fn make_html_snippet(
tcx: TyCtxt<'_>,
span: Span,
some_viewable: Option<&SpanViewable>,
) -> Option<String> {
let source_map = tcx.sess.source_map();
let snippet = source_map
.span_to_snippet(span)
.unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err));
let html_snippet = if let Some(viewable) = some_viewable {
let is_head = span.lo() == viewable.span.lo();
let is_tail = span.hi() == viewable.span.hi();
let mut labeled_snippet = if is_head {
format!(r#"<span class="annotation">{}{}</span>"#, viewable.id, ANNOTATION_LEFT_BRACKET)
} else {
"".to_owned()
};
if span.is_empty() {
if is_head && is_tail {
labeled_snippet.push(CARET);
}
} else {
labeled_snippet.push_str(&escape_html(&snippet));
};
if is_tail {
labeled_snippet.push_str(&format!(
r#"<span class="annotation">{}{}</span>"#,
ANNOTATION_RIGHT_BRACKET, viewable.id
));
}
labeled_snippet
} else {
escape_html(&snippet)
};
if html_snippet.is_empty() { None } else { Some(html_snippet) }
}
fn tooltip<'tcx>(
tcx: TyCtxt<'tcx>,
spanview_id: &str,
span: Span,
statements: Vec<Statement<'tcx>>,
terminator: &Option<Terminator<'tcx>>,
) -> String {
let source_map = tcx.sess.source_map();
let mut text = Vec::new();
text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span)));
for statement in statements {
let source_range = source_range_no_file(tcx, statement.source_info.span);
text.push(format!(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
statement.kind.name(),
statement
));
}
if let Some(term) = terminator {
let source_range = source_range_no_file(tcx, term.source_info.span);
text.push(format!(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
term.kind.name(),
term.kind
));
}
text.join("")
}
fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span {
trim_span_hi(trim_span_lo(span, from_pos), to_pos)
}
fn trim_span_lo(span: Span, from_pos: BytePos) -> Span {
if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) }
}
fn trim_span_hi(span: Span, to_pos: BytePos) -> Span {
if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) }
}
fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
let fn_decl_span = tcx.def_span(def_id);
if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
if fn_decl_span.eq_ctxt(body_span) { fn_decl_span.to(body_span) } else { body_span }
} else {
fn_decl_span
}
}
fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> {
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id))
}
fn escape_html(s: &str) -> String {
s.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;")
}
fn escape_attr(s: &str) -> String {
s.replace('&', "&amp;")
.replace('\"', "&quot;")
.replace('\'', "&#39;")
.replace('<', "&lt;")
.replace('>', "&gt;")
}

View file

@ -289,7 +289,7 @@ pub enum ObligationCauseCode<'tcx> {
/// Type of each variable must be `Sized`. /// Type of each variable must be `Sized`.
VariableType(hir::HirId), VariableType(hir::HirId),
/// Argument type must be `Sized`. /// Argument type must be `Sized`.
SizedArgumentType(Option<Span>), SizedArgumentType(Option<hir::HirId>),
/// Return type must be `Sized`. /// Return type must be `Sized`.
SizedReturnType, SizedReturnType,
/// Yield type must be `Sized`. /// Yield type must be `Sized`.

View file

@ -467,11 +467,11 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
level, level,
fluent::mir_build_non_exhaustive_patterns_type_not_empty, fluent::mir_build_non_exhaustive_patterns_type_not_empty,
); );
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0004)); diag.code(error_code!(E0004));
let peeled_ty = self.ty.peel_refs(); let peeled_ty = self.ty.peel_refs();
diag.set_arg("ty", self.ty); diag.arg("ty", self.ty);
diag.set_arg("peeled_ty", peeled_ty); diag.arg("peeled_ty", peeled_ty);
if let ty::Adt(def, _) = peeled_ty.kind() { if let ty::Adt(def, _) = peeled_ty.kind() {
let def_span = self let def_span = self
@ -855,7 +855,7 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
where where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{ {
diag.set_arg("ty", self.ty); diag.arg("ty", self.ty);
let mut spans = MultiSpan::from(self.adt_def_span); let mut spans = MultiSpan::from(self.adt_def_span);
for Variant { span } in self.variants { for Variant { span } in self.variants {

View file

@ -133,7 +133,6 @@
use std::collections::hash_map::{Entry, OccupiedEntry}; use std::collections::hash_map::{Entry, OccupiedEntry};
use crate::simplify::remove_dead_blocks;
use crate::MirPass; use crate::MirPass;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
@ -241,12 +240,6 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
apply_merges(body, tcx, &merges, &merged_locals); apply_merges(body, tcx, &merges, &merged_locals);
} }
if round_count != 0 {
// Merging can introduce overlap between moved arguments and/or call destination in an
// unreachable code, which validator considers to be ill-formed.
remove_dead_blocks(body);
}
trace!(round_count); trace!(round_count);
} }
} }

View file

@ -67,11 +67,11 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for RequiresUnsafe {
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe);
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
diag.set_span(self.span); diag.span(self.span);
diag.span_label(self.span, self.details.label()); diag.span_label(self.span, self.details.label());
let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
diag.set_arg("details", desc); diag.arg("details", desc);
diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
self.details.add_subdiagnostics(&mut diag); self.details.add_subdiagnostics(&mut diag);
if let Some(sp) = self.enclosing { if let Some(sp) = self.enclosing {
diag.span_label(sp, fluent::mir_transform_not_inherited); diag.span_label(sp, fluent::mir_transform_not_inherited);
@ -122,16 +122,16 @@ impl RequiresUnsafeDetail {
} }
CallToFunctionWith { ref missing, ref build_enabled } => { CallToFunctionWith { ref missing, ref build_enabled } => {
diag.help(fluent::mir_transform_target_feature_call_help); diag.help(fluent::mir_transform_target_feature_call_help);
diag.set_arg( diag.arg(
"missing_target_features", "missing_target_features",
DiagnosticArgValue::StrListSepByAnd( DiagnosticArgValue::StrListSepByAnd(
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
), ),
); );
diag.set_arg("missing_target_features_count", missing.len()); diag.arg("missing_target_features_count", missing.len());
if !build_enabled.is_empty() { if !build_enabled.is_empty() {
diag.note(fluent::mir_transform_target_feature_call_note); diag.note(fluent::mir_transform_target_feature_call_note);
diag.set_arg( diag.arg(
"build_target_features", "build_target_features",
DiagnosticArgValue::StrListSepByAnd( DiagnosticArgValue::StrListSepByAnd(
build_enabled build_enabled
@ -140,7 +140,7 @@ impl RequiresUnsafeDetail {
.collect(), .collect(),
), ),
); );
diag.set_arg("build_target_features_count", build_enabled.len()); diag.arg("build_target_features_count", build_enabled.len());
} }
} }
} }
@ -183,7 +183,7 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
let dcx = diag.dcx().expect("lint should not yet be emitted"); let dcx = diag.dcx().expect("lint should not yet be emitted");
let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
diag.set_arg("details", desc); diag.arg("details", desc);
diag.span_label(self.details.span, self.details.label()); diag.span_label(self.details.span, self.details.label());
self.details.add_subdiagnostics(diag); self.details.add_subdiagnostics(diag);
@ -213,7 +213,7 @@ impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
let assert_kind = self.panic(); let assert_kind = self.panic();
let message = assert_kind.diagnostic_message(); let message = assert_kind.diagnostic_message();
assert_kind.add_args(&mut |name, value| { assert_kind.add_args(&mut |name, value| {
diag.set_arg(name, value); diag.arg(name, value);
}); });
diag.span_label(span, message); diag.span_label(span, message);
} }
@ -280,9 +280,9 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> {
diag.subdiagnostic(reason); diag.subdiagnostic(reason);
} }
diag.span_help(self.src_sp, fluent::_subdiag::help); diag.span_help(self.src_sp, fluent::_subdiag::help);
diag.set_arg("pre", self.pre); diag.arg("pre", self.pre);
diag.set_arg("def_path", self.tcx.def_path_str(self.def_id)); diag.arg("def_path", self.tcx.def_path_str(self.def_id));
diag.set_arg("post", self.post); diag.arg("post", self.post);
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage { fn msg(&self) -> rustc_errors::DiagnosticMessage {

View file

@ -1,6 +1,7 @@
//! This pass statically detects code which has undefined behaviour or is likely to be erroneous. //! This pass statically detects code which has undefined behaviour or is likely to be erroneous.
//! It can be used to locate problems in MIR building or optimizations. It assumes that all code //! It can be used to locate problems in MIR building or optimizations. It assumes that all code
//! can be executed, so it has false positives. //! can be executed, so it has false positives.
use rustc_data_structures::fx::FxHashSet;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
@ -11,7 +12,6 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor};
use std::borrow::Cow; use std::borrow::Cow;
pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) {
let reachable_blocks = traversal::reachable_as_bitset(body);
let always_live_locals = &always_storage_live_locals(body); let always_live_locals = &always_storage_live_locals(body);
let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
@ -24,17 +24,19 @@ pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) {
.iterate_to_fixpoint() .iterate_to_fixpoint()
.into_results_cursor(body); .into_results_cursor(body);
Lint { let mut lint = Lint {
tcx, tcx,
when, when,
body, body,
is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(), is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(),
always_live_locals, always_live_locals,
reachable_blocks,
maybe_storage_live, maybe_storage_live,
maybe_storage_dead, maybe_storage_dead,
places: Default::default(),
};
for (bb, data) in traversal::reachable(body) {
lint.visit_basic_block_data(bb, data);
} }
.visit_body(body);
} }
struct Lint<'a, 'tcx> { struct Lint<'a, 'tcx> {
@ -43,9 +45,9 @@ struct Lint<'a, 'tcx> {
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
is_fn_like: bool, is_fn_like: bool,
always_live_locals: &'a BitSet<Local>, always_live_locals: &'a BitSet<Local>,
reachable_blocks: BitSet<BasicBlock>,
maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>,
maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>, maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>,
places: FxHashSet<PlaceRef<'tcx>>,
} }
impl<'a, 'tcx> Lint<'a, 'tcx> { impl<'a, 'tcx> Lint<'a, 'tcx> {
@ -67,7 +69,7 @@ impl<'a, 'tcx> Lint<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
if self.reachable_blocks.contains(location.block) && context.is_use() { if context.is_use() {
self.maybe_storage_dead.seek_after_primary_effect(location); self.maybe_storage_dead.seek_after_primary_effect(location);
if self.maybe_storage_dead.get().contains(local) { if self.maybe_storage_dead.get().contains(local) {
self.fail(location, format!("use of local {local:?}, which has no storage here")); self.fail(location, format!("use of local {local:?}, which has no storage here"));
@ -76,18 +78,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
} }
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind { match &statement.kind {
StatementKind::StorageLive(local) => { StatementKind::Assign(box (dest, rvalue)) => {
if self.reachable_blocks.contains(location.block) { if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
self.maybe_storage_live.seek_before_primary_effect(location); // The sides of an assignment must not alias. Currently this just checks whether
if self.maybe_storage_live.get().contains(local) { // the places are identical.
if dest == src {
self.fail( self.fail(
location, location,
format!("StorageLive({local:?}) which already has storage here"), "encountered `Assign` statement with overlapping memory",
); );
} }
} }
} }
StatementKind::StorageLive(local) => {
self.maybe_storage_live.seek_before_primary_effect(location);
if self.maybe_storage_live.get().contains(*local) {
self.fail(
location,
format!("StorageLive({local:?}) which already has storage here"),
);
}
}
_ => {} _ => {}
} }
@ -95,9 +107,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
} }
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
match terminator.kind { match &terminator.kind {
TerminatorKind::Return => { TerminatorKind::Return => {
if self.is_fn_like && self.reachable_blocks.contains(location.block) { if self.is_fn_like {
self.maybe_storage_live.seek_after_primary_effect(location); self.maybe_storage_live.seek_after_primary_effect(location);
for local in self.maybe_storage_live.get().iter() { for local in self.maybe_storage_live.get().iter() {
if !self.always_live_locals.contains(local) { if !self.always_live_locals.contains(local) {
@ -111,6 +123,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
} }
} }
} }
TerminatorKind::Call { args, destination, .. } => {
// The call destination place and Operand::Move place used as an argument might be
// passed by a reference to the callee. Consequently they must be non-overlapping.
// Currently this simply checks for duplicate places.
self.places.clear();
self.places.insert(destination.as_ref());
let mut has_duplicates = false;
for arg in args {
if let Operand::Move(place) = arg {
has_duplicates |= !self.places.insert(place.as_ref());
}
}
if has_duplicates {
self.fail(
location,
format!(
"encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}",
terminator.kind,
),
);
}
}
_ => {} _ => {}
} }

View file

@ -109,14 +109,15 @@ fn run_passes_inner<'tcx>(
phase_change: Option<MirPhase>, phase_change: Option<MirPhase>,
validate_each: bool, validate_each: bool,
) { ) {
let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip();
let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip();
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes); trace!(?overridden_passes);
let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));
if !body.should_skip() { if !body.should_skip() {
let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
let lint = tcx.sess.opts.unstable_opts.lint_mir;
for pass in passes { for pass in passes {
let name = pass.name(); let name = pass.name();
@ -162,7 +163,12 @@ fn run_passes_inner<'tcx>(
body.pass_count = 0; body.pass_count = 0;
dump_mir_for_phase_change(tcx, body); dump_mir_for_phase_change(tcx, body);
if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) {
let validate =
(validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip())
|| new_phase == MirPhase::Runtime(RuntimePhase::Optimized);
let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip();
if validate {
validate_body(tcx, body, format!("after phase change to {}", new_phase.name())); validate_body(tcx, body, format!("after phase change to {}", new_phase.name()));
} }
if lint { if lint {

View file

@ -51,7 +51,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for UnusedGenericParamsHint {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::monomorphize_unused_generic_params); DiagnosticBuilder::new(dcx, level, fluent::monomorphize_unused_generic_params);
diag.set_span(self.span); diag.span(self.span);
for (span, name) in self.param_spans.into_iter().zip(self.param_names) { 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, // 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 // or a label with a dynamic value in a hard-coded string, but I haven't figured out

View file

@ -1065,8 +1065,8 @@ impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
None => fluent::parse_expected_identifier_found_str, None => fluent::parse_expected_identifier_found_str,
}, },
); );
diag.set_span(self.span); diag.span(self.span);
diag.set_arg("token", self.token); diag.arg("token", self.token);
if let Some(sugg) = self.suggest_raw { if let Some(sugg) = self.suggest_raw {
sugg.add_to_diagnostic(&mut diag); sugg.add_to_diagnostic(&mut diag);
@ -1123,8 +1123,8 @@ impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
None => fluent::parse_expected_semi_found_str, None => fluent::parse_expected_semi_found_str,
}, },
); );
diag.set_span(self.span); diag.span(self.span);
diag.set_arg("token", self.token); diag.arg("token", self.token);
if let Some(unexpected_token_label) = self.unexpected_token_label { if let Some(unexpected_token_label) = self.unexpected_token_label {
diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token); diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token);

View file

@ -7,9 +7,7 @@ use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{ use rustc_errors::{error_code, Applicability, DiagCtxt, Diagnostic, StashKey};
error_code, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalAbort, StashKey,
};
use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::unescape::{self, EscapeError, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_lexer::{Cursor, LiteralKind}; use rustc_lexer::{Cursor, LiteralKind};
@ -252,7 +250,7 @@ impl<'a> StringReader<'a> {
if starts_with_number { if starts_with_number {
let span = self.mk_sp(start, self.pos); let span = self.mk_sp(start, self.pos);
let mut diag = self.dcx().struct_err("lifetimes cannot start with a number"); let mut diag = self.dcx().struct_err("lifetimes cannot start with a number");
diag.set_span(span); diag.span(span);
diag.stash(span, StashKey::LifetimeIsChar); diag.stash(span, StashKey::LifetimeIsChar);
} }
let ident = Symbol::intern(lifetime_name); let ident = Symbol::intern(lifetime_name);
@ -344,18 +342,6 @@ impl<'a> StringReader<'a> {
token::Ident(sym, false) token::Ident(sym, false)
} }
fn struct_fatal_span_char(
&self,
from_pos: BytePos,
to_pos: BytePos,
m: &str,
c: char,
) -> DiagnosticBuilder<'a, FatalAbort> {
self.sess
.dcx
.struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c)))
}
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
/// complain about it. /// complain about it.
fn lint_unicode_text_flow(&self, start: BytePos) { fn lint_unicode_text_flow(&self, start: BytePos) {
@ -568,13 +554,16 @@ impl<'a> StringReader<'a> {
} }
fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! { fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! {
self.struct_fatal_span_char( self.sess
start, .dcx
self.pos, .struct_span_fatal(
"found invalid character; only `#` is allowed in raw string delimitation", self.mk_sp(start, self.pos),
bad_char, format!(
) "found invalid character; only `#` is allowed in raw string delimitation: {}",
.emit() escaped_char(bad_char)
),
)
.emit()
} }
fn report_unterminated_raw_string( fn report_unterminated_raw_string(

View file

@ -154,7 +154,7 @@ fn try_file_to_source_file(
let msg = format!("couldn't read {}: {}", path.display(), e); let msg = format!("couldn't read {}: {}", path.display(), e);
let mut diag = Diagnostic::new(Level::Fatal, msg); let mut diag = Diagnostic::new(Level::Fatal, msg);
if let Some(sp) = spanopt { if let Some(sp) = spanopt {
diag.set_span(sp); diag.span(sp);
} }
diag diag
}) })

View file

@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
) { ) {
Ok(Some(item)) => { Ok(Some(item)) => {
// FIXME(#100717) // FIXME(#100717)
err.set_arg("item", item.kind.descr()); err.arg("item", item.kind.descr());
err.span_label(item.span, fluent::parse_label_does_not_annotate_this); err.span_label(item.span, fluent::parse_label_does_not_annotate_this);
err.span_suggestion_verbose( err.span_suggestion_verbose(
replacement_span, replacement_span,

View file

@ -846,7 +846,7 @@ impl<'a> Parser<'a> {
) => ) =>
{ {
let n_hashes: u8 = *n_hashes; let n_hashes: u8 = *n_hashes;
err.set_primary_message("too many `#` when terminating raw string"); err.primary_message("too many `#` when terminating raw string");
let str_span = self.prev_token.span; let str_span = self.prev_token.span;
let mut span = self.token.span; let mut span = self.token.span;
let mut count = 0; let mut count = 0;
@ -857,7 +857,7 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
count += 1; count += 1;
} }
err.set_span(span); err.span(span);
err.span_suggestion( err.span_suggestion(
span, span,
format!("remove the extra `#`{}", pluralize!(count)), format!("remove the extra `#`{}", pluralize!(count)),

View file

@ -925,9 +925,8 @@ impl<'a> Parser<'a> {
}); });
} }
expect_err.set_primary_message( expect_err
"closure bodies that contain statements must be surrounded by braces", .primary_message("closure bodies that contain statements must be surrounded by braces");
);
let preceding_pipe_span = closure_spans.closing_pipe; let preceding_pipe_span = closure_spans.closing_pipe;
let following_token_span = self.token.span; let following_token_span = self.token.span;
@ -951,7 +950,7 @@ impl<'a> Parser<'a> {
); );
expect_err.span_note(second_note, "the closure body may be incorrectly delimited"); expect_err.span_note(second_note, "the closure body may be incorrectly delimited");
expect_err.set_span(vec![preceding_pipe_span, following_token_span]); expect_err.span(vec![preceding_pipe_span, following_token_span]);
let opening_suggestion_str = " {".to_string(); let opening_suggestion_str = " {".to_string();
let closing_suggestion_str = "}".to_string(); let closing_suggestion_str = "}".to_string();

View file

@ -2341,17 +2341,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
match terr { match terr {
TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => { TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
if let Some(ty) = hir_sig.decl.inputs.get(idx) { if let Some(ty) = hir_sig.decl.inputs.get(idx) {
diag.set_span(ty.span); diag.span(ty.span);
cause.span = ty.span; cause.span = ty.span;
} else if idx == hir_sig.decl.inputs.len() { } else if idx == hir_sig.decl.inputs.len() {
let span = hir_sig.decl.output.span(); let span = hir_sig.decl.output.span();
diag.set_span(span); diag.span(span);
cause.span = span; cause.span = span;
} }
} }
TypeError::ArgCount => { TypeError::ArgCount => {
if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) { if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
diag.set_span(ty.span); diag.span(ty.span);
cause.span = ty.span; cause.span = ty.span;
} }
} }

View file

@ -868,8 +868,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::passes_invalid_attr_at_crate_level); DiagnosticBuilder::new(dcx, level, fluent::passes_invalid_attr_at_crate_level);
diag.set_span(self.span); diag.span(self.span);
diag.set_arg("name", self.name); diag.arg("name", self.name);
// Only emit an error with a suggestion if we can create a string out // Only emit an error with a suggestion if we can create a string out
// of the attribute span // of the attribute span
if let Some(span) = self.sugg_span { if let Some(span) = self.sugg_span {
@ -881,7 +881,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel {
); );
} }
if let Some(item) = self.item { if let Some(item) = self.item {
diag.set_arg("kind", item.kind); diag.arg("kind", item.kind);
diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item); diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item);
} }
diag diag
@ -1018,9 +1018,9 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop);
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0571)); diag.code(error_code!(E0571));
diag.set_arg("kind", self.kind); diag.arg("kind", self.kind);
diag.span_label(self.span, fluent::passes_label); diag.span_label(self.span, fluent::passes_label);
if let Some(head) = self.head { if let Some(head) = self.head {
diag.span_label(head, fluent::passes_label2); diag.span_label(head, fluent::passes_label2);
@ -1162,7 +1162,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block);
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0787)); diag.code(error_code!(E0787));
for span in self.multiple_asms.iter() { for span in self.multiple_asms.iter() {
diag.span_label(*span, fluent::passes_label_multiple_asm); diag.span_label(*span, fluent::passes_label_multiple_asm);
@ -1273,11 +1273,11 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function); let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function);
diag.set_span(DUMMY_SP); diag.span(DUMMY_SP);
diag.code(error_code!(E0601)); diag.code(error_code!(E0601));
diag.set_arg("crate_name", self.crate_name); diag.arg("crate_name", self.crate_name);
diag.set_arg("filename", self.filename); diag.arg("filename", self.filename);
diag.set_arg("has_filename", self.has_filename); diag.arg("has_filename", self.has_filename);
let note = if !self.non_main_fns.is_empty() { let note = if !self.non_main_fns.is_empty() {
for &span in &self.non_main_fns { for &span in &self.non_main_fns {
diag.span_note(span, fluent::passes_here_is_main); diag.span_note(span, fluent::passes_here_is_main);
@ -1294,7 +1294,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr {
if self.file_empty { if self.file_empty {
diag.note(note); diag.note(note);
} else { } else {
diag.set_span(self.sp.shrink_to_hi()); diag.span(self.sp.shrink_to_hi());
diag.span_label(self.sp.shrink_to_hi(), note); diag.span_label(self.sp.shrink_to_hi(), note);
} }
@ -1340,15 +1340,15 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for DuplicateLangItem {
}, },
); );
diag.code(error_code!(E0152)); diag.code(error_code!(E0152));
diag.set_arg("lang_item_name", self.lang_item_name); diag.arg("lang_item_name", self.lang_item_name);
diag.set_arg("crate_name", self.crate_name); diag.arg("crate_name", self.crate_name);
diag.set_arg("dependency_of", self.dependency_of); diag.arg("dependency_of", self.dependency_of);
diag.set_arg("path", self.path); diag.arg("path", self.path);
diag.set_arg("orig_crate_name", self.orig_crate_name); diag.arg("orig_crate_name", self.orig_crate_name);
diag.set_arg("orig_dependency_of", self.orig_dependency_of); diag.arg("orig_dependency_of", self.orig_dependency_of);
diag.set_arg("orig_path", self.orig_path); diag.arg("orig_path", self.orig_path);
if let Some(span) = self.local_span { if let Some(span) = self.local_span {
diag.set_span(span); diag.span(span);
} }
if let Some(span) = self.first_defined_span { if let Some(span) = self.first_defined_span {
diag.span_note(span, fluent::passes_first_defined_span); diag.span_note(span, fluent::passes_first_defined_span);

View file

@ -204,7 +204,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
use rustc_errors::DecorateLint; use rustc_errors::DecorateLint;
let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().unwrap().span, ""); let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().unwrap().span, "");
err.set_primary_message(decorator.msg()); err.primary_message(decorator.msg());
decorator.decorate_lint(&mut err); decorator.decorate_lint(&mut err);
err.emit(); err.emit();
} }

View file

@ -1383,7 +1383,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
| PathSource::TupleStruct(span, _) => { | PathSource::TupleStruct(span, _) => {
// We want the main underline to cover the suggested code as well for // We want the main underline to cover the suggested code as well for
// cleaner output. // cleaner output.
err.set_span(*span); err.span(*span);
*span *span
} }
_ => span, _ => span,
@ -1615,7 +1615,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let field_spans = match source { let field_spans = match source {
// e.g. `if let Enum::TupleVariant(field1, field2) = _` // e.g. `if let Enum::TupleVariant(field1, field2) = _`
PathSource::TupleStruct(_, pattern_spans) => { PathSource::TupleStruct(_, pattern_spans) => {
err.set_primary_message( err.primary_message(
"cannot match against a tuple struct which contains private fields", "cannot match against a tuple struct which contains private fields",
); );
@ -1628,7 +1628,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
span: call_span, span: call_span,
.. ..
})) => { })) => {
err.set_primary_message( err.primary_message(
"cannot initialize a tuple struct which contains private fields", "cannot initialize a tuple struct which contains private fields",
); );
self.suggest_alternative_construction_methods( self.suggest_alternative_construction_methods(

View file

@ -125,21 +125,6 @@ pub enum LtoCli {
Unspecified, Unspecified,
} }
/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
/// document highlighting each span of every statement (including terminators). `Terminator` and
/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
/// computed span for the block, representing the entire range, covering the block's terminator and
/// all of its statements.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum MirSpanview {
/// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
Statement,
/// `-Z dump_mir_spanview=terminator`
Terminator,
/// `-Z dump_mir_spanview=block`
Block,
}
/// The different settings that the `-C instrument-coverage` flag can have. /// The different settings that the `-C instrument-coverage` flag can have.
/// ///
/// Coverage instrumentation now supports combining `-C instrument-coverage` /// Coverage instrumentation now supports combining `-C instrument-coverage`
@ -1162,7 +1147,6 @@ impl UnstableOptions {
can_emit_warnings, can_emit_warnings,
treat_err_as_bug: self.treat_err_as_bug, treat_err_as_bug: self.treat_err_as_bug,
dont_buffer_diagnostics: self.dont_buffer_diagnostics, dont_buffer_diagnostics: self.dont_buffer_diagnostics,
report_delayed_bugs: self.report_delayed_bugs,
macro_backtrace: self.macro_backtrace, macro_backtrace: self.macro_backtrace,
deduplicate_diagnostics: self.deduplicate_diagnostics, deduplicate_diagnostics: self.deduplicate_diagnostics,
track_diagnostics: self.track_diagnostics, track_diagnostics: self.track_diagnostics,
@ -2051,23 +2035,14 @@ fn check_error_format_stability(
early_dcx: &mut EarlyDiagCtxt, early_dcx: &mut EarlyDiagCtxt,
unstable_opts: &UnstableOptions, unstable_opts: &UnstableOptions,
error_format: ErrorOutputType, error_format: ErrorOutputType,
json_rendered: HumanReadableErrorType,
) { ) {
if !unstable_opts.unstable_options { if !unstable_opts.unstable_options {
if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { if let ErrorOutputType::Json { pretty: true, .. } = error_format {
early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json {
pretty: false,
json_rendered,
});
early_dcx.early_fatal("`--error-format=pretty-json` is unstable"); early_dcx.early_fatal("`--error-format=pretty-json` is unstable");
} }
if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
error_format error_format
{ {
early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json {
pretty: false,
json_rendered,
});
early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable"); early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable");
} }
} }
@ -2665,7 +2640,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let mut unstable_opts = UnstableOptions::build(early_dcx, matches); let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
check_error_format_stability(early_dcx, &unstable_opts, error_format, json_rendered); check_error_format_stability(early_dcx, &unstable_opts, error_format);
if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
early_dcx.early_fatal( early_dcx.early_fatal(

View file

@ -19,7 +19,7 @@ impl<'a> IntoDiagnostic<'a> for FeatureGateError {
#[track_caller] #[track_caller]
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> {
let mut diag = DiagnosticBuilder::new(dcx, level, self.explain); let mut diag = DiagnosticBuilder::new(dcx, level, self.explain);
diag.set_span(self.span); diag.span(self.span);
diag.code(error_code!(E0658)); diag.code(error_code!(E0658));
diag diag
} }

View file

@ -391,7 +391,6 @@ mod desc {
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub const parse_instrument_coverage: &str = pub const parse_instrument_coverage: &str =
"`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`"; "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`";
@ -866,29 +865,6 @@ mod parse {
} }
} }
pub(crate) fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
if v.is_some() {
let mut bool_arg = None;
if parse_opt_bool(&mut bool_arg, v) {
*slot = bool_arg.unwrap().then_some(MirSpanview::Statement);
return true;
}
}
let Some(v) = v else {
*slot = Some(MirSpanview::Statement);
return true;
};
*slot = Some(match v.trim_end_matches('s') {
"statement" | "stmt" => MirSpanview::Statement,
"terminator" | "term" => MirSpanview::Terminator,
"block" | "basicblock" => MirSpanview::Block,
_ => return false,
});
true
}
pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool { pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
match v { match v {
None => true, None => true,
@ -1601,11 +1577,6 @@ options! {
"exclude the pass number when dumping MIR (used in tests) (default: no)"), "exclude the pass number when dumping MIR (used in tests) (default: no)"),
dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
"in addition to `.mir` files, create graphviz `.dot` files (default: no)"), "in addition to `.mir` files, create graphviz `.dot` files (default: no)"),
dump_mir_spanview: Option<MirSpanview> = (None, parse_mir_spanview, [UNTRACKED],
"in addition to `.mir` files, create `.html` files to view spans for \
all `statement`s (including terminators), only `terminator` spans, or \
computed `block` spans (one span encompassing a block's terminator and \
all statements)."),
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled, dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
parse_switch_with_opt_path, [UNTRACKED], parse_switch_with_opt_path, [UNTRACKED],
"output statistics about monomorphization collection"), "output statistics about monomorphization collection"),
@ -1841,8 +1812,6 @@ options! {
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"directory into which to write optimization remarks (if not specified, they will be \ "directory into which to write optimization remarks (if not specified, they will be \
written to standard error output)"), written to standard error output)"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `span_delayed_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"), "use a sanitizer"),
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED], sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],

View file

@ -17,8 +17,8 @@ use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef};
use rustc_data_structures::sync::{ use rustc_data_structures::sync::{
AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst, AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst,
}; };
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_errors::emitter::{DynEmitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType};
use rustc_errors::json::JsonEmitter; use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_errors::{ use rustc_errors::{
@ -1000,7 +1000,7 @@ fn default_emitter(
let (short, color_config) = kind.unzip(); let (short, color_config) = kind.unzip();
if let HumanReadableErrorType::AnnotateSnippet(_) = kind { if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
let emitter = AnnotateSnippetEmitterWriter::new( let emitter = AnnotateSnippetEmitter::new(
Some(source_map), Some(source_map),
bundle, bundle,
fallback_bundle, fallback_bundle,
@ -1009,7 +1009,7 @@ fn default_emitter(
); );
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
} else { } else {
let emitter = EmitterWriter::stderr(color_config, fallback_bundle) let emitter = HumanEmitter::stderr(color_config, fallback_bundle)
.fluent_bundle(bundle) .fluent_bundle(bundle)
.sm(Some(source_map)) .sm(Some(source_map))
.short_message(short) .short_message(short)
@ -1504,7 +1504,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
let emitter: Box<DynEmitter> = match output { let emitter: Box<DynEmitter> = match output {
config::ErrorOutputType::HumanReadable(kind) => { config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip(); let (short, color_config) = kind.unzip();
Box::new(EmitterWriter::stderr(color_config, fallback_bundle).short_message(short)) Box::new(HumanEmitter::stderr(color_config, fallback_bundle).short_message(short))
} }
config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic( config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
pretty, pretty,

View file

@ -19,7 +19,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TestOutput {
#[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::untranslatable_diagnostic)]
let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")); let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})"));
diag.set_span(span); diag.span(span);
diag diag
} }
} }

View file

@ -66,12 +66,9 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_
) -> rustc_errors::DiagnosticBuilder<'_, G> { ) -> rustc_errors::DiagnosticBuilder<'_, G> {
let mut diag = let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict); DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict);
diag.set_arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string());
diag.set_arg( diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string()));
"self_desc", diag.span(self.impl_span);
self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string()),
);
diag.set_span(self.impl_span);
diag.code(rustc_errors::error_code!(E0751)); diag.code(rustc_errors::error_code!(E0751));
match self.negative_impl_span { match self.negative_impl_span {
Ok(span) => { Ok(span) => {
@ -79,7 +76,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_
} }
Err(cname) => { Err(cname) => {
diag.note(fluent::trait_selection_negative_implementation_in_crate); diag.note(fluent::trait_selection_negative_implementation_in_crate);
diag.set_arg("negative_impl_cname", cname.to_string()); diag.arg("negative_impl_cname", cname.to_string());
} }
} }
match self.positive_impl_span { match self.positive_impl_span {
@ -88,7 +85,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_
} }
Err(cname) => { Err(cname) => {
diag.note(fluent::trait_selection_positive_implementation_in_crate); diag.note(fluent::trait_selection_positive_implementation_in_crate);
diag.set_arg("positive_impl_cname", cname.to_string()); diag.arg("positive_impl_cname", cname.to_string());
} }
} }
diag diag
@ -115,7 +112,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow {
{ {
match self { match self {
AdjustSignatureBorrow::Borrow { to_borrow } => { AdjustSignatureBorrow::Borrow { to_borrow } => {
diag.set_arg("len", to_borrow.len()); diag.arg("len", to_borrow.len());
diag.multipart_suggestion_verbose( diag.multipart_suggestion_verbose(
fluent::trait_selection_adjust_signature_borrow, fluent::trait_selection_adjust_signature_borrow,
to_borrow, to_borrow,
@ -123,7 +120,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow {
); );
} }
AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => { AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => {
diag.set_arg("len", remove_borrow.len()); diag.arg("len", remove_borrow.len());
diag.multipart_suggestion_verbose( diag.multipart_suggestion_verbose(
fluent::trait_selection_adjust_signature_remove_borrow, fluent::trait_selection_adjust_signature_remove_borrow,
remove_borrow, remove_borrow,

View file

@ -19,11 +19,10 @@ use rustc_errors::{
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::{Map, Visitor};
use rustc_hir::is_range_literal; use rustc_hir::is_range_literal;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
use rustc_hir::{Expr, HirId};
use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
@ -2008,7 +2007,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}; };
err.code(error_code!(E0746)); err.code(error_code!(E0746));
err.set_primary_message("return type cannot have an unboxed trait object"); err.primary_message("return type cannot have an unboxed trait object");
err.children.clear(); err.children.clear();
let span = obligation.cause.span; let span = obligation.cause.span;
@ -2713,7 +2712,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
err.clear_code(); err.clear_code();
err.set_primary_message(format!( err.primary_message(format!(
"{future_or_coroutine} cannot be {trait_verb} between threads safely" "{future_or_coroutine} cannot be {trait_verb} between threads safely"
)); ));
@ -2801,7 +2800,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}")); .unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}"));
span.push_span_label(original_span, message); span.push_span_label(original_span, message);
err.set_span(span); err.span(span);
format!("is not {trait_name}") format!("is not {trait_name}")
} else { } else {
@ -3200,35 +3199,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.help("unsized locals are gated as an unstable feature"); err.help("unsized locals are gated as an unstable feature");
} }
} }
ObligationCauseCode::SizedArgumentType(ty_span) => { ObligationCauseCode::SizedArgumentType(hir_id) => {
if let Some(span) = ty_span { let mut ty = None;
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() let borrowed_msg = "function arguments must have a statically known size, borrowed \
&& let ty::ClauseKind::Trait(trait_pred) = clause types always have a known size";
&& let ty::Dynamic(..) = trait_pred.self_ty().kind() if let Some(hir_id) = hir_id
{ && let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id)
let span = if let Ok(snippet) = && let Some(item) = self.tcx.hir().find_parent(hir_id)
self.tcx.sess.source_map().span_to_snippet(span) && let Some(decl) = item.fn_decl()
&& snippet.starts_with("dyn ") && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
{ {
let pos = snippet.len() - snippet[3..].trim_start().len(); // We use `contains` because the type might be surrounded by parentheses,
span.with_hi(span.lo() + BytePos(pos as u32)) // which makes `ty_span` and `t.span` disagree with each other, but one
} else { // fully contains the other: `foo: (dyn Foo + Bar)`
span.shrink_to_lo() // ^-------------^
}; // ||
err.span_suggestion_verbose( // |t.span
span, // param._ty_span
"you can use `impl Trait` as the argument type", ty = Some(t);
"impl ".to_string(), } else if let Some(hir_id) = hir_id
Applicability::MaybeIncorrect, && let Some(hir::Node::Ty(t)) = self.tcx.hir().find(hir_id)
); {
ty = Some(t);
}
if let Some(ty) = ty {
match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => {
let (span, kw) = match traits {
[first, ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object.
(ty.span.shrink_to_lo(), "dyn ")
}
[first, ..] => (ty.span.until(first.span), ""),
[] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
};
let needs_parens = traits.len() != 1;
err.span_suggestion_verbose(
span,
"you can use `impl Trait` as the argument type",
"impl ".to_string(),
Applicability::MaybeIncorrect,
);
let sugg = if !needs_parens {
vec![(span.shrink_to_lo(), format!("&{kw}"))]
} else {
vec![
(span.shrink_to_lo(), format!("&({kw}")),
(ty.span.shrink_to_hi(), ")".to_string()),
]
};
err.multipart_suggestion_verbose(
borrowed_msg,
sugg,
Applicability::MachineApplicable,
);
}
hir::TyKind::Slice(_ty) => {
err.span_suggestion_verbose(
ty.span.shrink_to_lo(),
"function arguments must have a statically known size, borrowed \
slices always have a known size",
"&",
Applicability::MachineApplicable,
);
}
hir::TyKind::Path(_) => {
err.span_suggestion_verbose(
ty.span.shrink_to_lo(),
borrowed_msg,
"&",
Applicability::MachineApplicable,
);
}
_ => {}
} }
err.span_suggestion_verbose(
span.shrink_to_lo(),
"function arguments must have a statically known size, borrowed types \
always have a known size",
"&",
Applicability::MachineApplicable,
);
} else { } else {
err.note("all function arguments must have a statically known size"); err.note("all function arguments must have a statically known size");
} }

View file

@ -816,7 +816,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::ObjectSafe(trait_def_id) => { ty::PredicateKind::ObjectSafe(trait_def_id) => {
let violations = self.tcx.object_safety_violations(trait_def_id); let violations = self.tcx.object_safety_violations(trait_def_id);
report_object_safety_error(self.tcx, span, trait_def_id, violations) report_object_safety_error(self.tcx, span, None, trait_def_id, violations)
} }
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
@ -924,7 +924,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
TraitNotObjectSafe(did) => { TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did); let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations) report_object_safety_error(self.tcx, span, None, did, violations)
} }
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
@ -3163,14 +3163,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) { ) {
match obligation_cause_code { match obligation_cause_code {
ObligationCauseCode::RustCall => { ObligationCauseCode::RustCall => {
err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); err.primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
} }
ObligationCauseCode::BindingObligation(def_id, _) ObligationCauseCode::BindingObligation(def_id, _)
| ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ItemObligation(def_id)
if self.tcx.is_fn_trait(*def_id) => if self.tcx.is_fn_trait(*def_id) =>
{ {
err.code(rustc_errors::error_code!(E0059)); err.code(rustc_errors::error_code!(E0059));
err.set_primary_message(format!( err.primary_message(format!(
"type parameter to bare `{}` trait must be a tuple", "type parameter to bare `{}` trait must be a tuple",
self.tcx.def_path_str(*def_id) self.tcx.def_path_str(*def_id)
)); ));

View file

@ -947,7 +947,7 @@ extern "rust-intrinsic" {
/// own, or if it does not enable any significant optimizations. /// own, or if it does not enable any significant optimizations.
/// ///
/// This intrinsic does not have a stable counterpart. /// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assume", issue = "76972")] #[rustc_const_stable(feature = "const_assume", since = "CURRENT_RUSTC_VERSION")]
#[rustc_nounwind] #[rustc_nounwind]
pub fn assume(b: bool); pub fn assume(b: bool);

View file

@ -119,7 +119,6 @@
#![feature(const_arguments_as_str)] #![feature(const_arguments_as_str)]
#![feature(const_array_from_ref)] #![feature(const_array_from_ref)]
#![feature(const_array_into_iter_constructors)] #![feature(const_array_into_iter_constructors)]
#![feature(const_assume)]
#![feature(const_bigint_helper_methods)] #![feature(const_bigint_helper_methods)]
#![feature(const_black_box)] #![feature(const_black_box)]
#![feature(const_caller_location)] #![feature(const_caller_location)]

View file

@ -9,7 +9,6 @@
#![feature(bigint_helper_methods)] #![feature(bigint_helper_methods)]
#![feature(cell_update)] #![feature(cell_update)]
#![feature(const_align_offset)] #![feature(const_align_offset)]
#![feature(const_assume)]
#![feature(const_align_of_val_raw)] #![feature(const_align_of_val_raw)]
#![feature(const_black_box)] #![feature(const_black_box)]
#![feature(const_caller_location)] #![feature(const_caller_location)]

View file

@ -1976,7 +1976,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
} }
if builder.config.profiler_enabled(target) { if builder.config.profiler_enabled(target) {
cmd.env("RUSTC_PROFILER_SUPPORT", "1"); cmd.arg("--profiler-support");
} }
cmd.env("RUST_TEST_TMPDIR", builder.tempdir()); cmd.env("RUST_TEST_TMPDIR", builder.tempdir());

View file

@ -151,7 +151,6 @@ target | std | notes
`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87]
`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87]
`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87]
[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | 32-bit x86, restricted to Pentium
[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI]
`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI]
`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL [^x86_32-floats-return-ABI]
@ -272,6 +271,7 @@ target | std | host | notes
`hexagon-unknown-linux-musl` | ? | | `hexagon-unknown-linux-musl` | ? | |
`i386-apple-ios` | ✓ | | 32-bit x86 iOS [^x86_32-floats-return-ABI] `i386-apple-ios` | ✓ | | 32-bit x86 iOS [^x86_32-floats-return-ABI]
[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS [^x86_32-floats-return-ABI] [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS [^x86_32-floats-return-ABI]
[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86, restricted to Pentium
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI] `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
`i686-pc-windows-msvc` | * | | 32-bit Windows XP support [^x86_32-floats-return-ABI] `i686-pc-windows-msvc` | * | | 32-bit Windows XP support [^x86_32-floats-return-ABI]
[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | [^x86_32-floats-return-ABI]

View file

@ -1,7 +1,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_errors::emitter::{DynEmitter, EmitterWriter}; use rustc_errors::emitter::{DynEmitter, HumanEmitter};
use rustc_errors::json::JsonEmitter; use rustc_errors::json::JsonEmitter;
use rustc_errors::TerminalUrl; use rustc_errors::TerminalUrl;
use rustc_feature::UnstableFeatures; use rustc_feature::UnstableFeatures;
@ -138,7 +138,7 @@ pub(crate) fn new_dcx(
ErrorOutputType::HumanReadable(kind) => { ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip(); let (short, color_config) = kind.unzip();
Box::new( Box::new(
EmitterWriter::stderr(color_config, fallback_bundle) HumanEmitter::stderr(color_config, fallback_bundle)
.sm(source_map.map(|sm| sm as _)) .sm(source_map.map(|sm| sm as _))
.short_message(short) .short_message(short)
.teach(unstable_opts.teach) .teach(unstable_opts.teach)

View file

@ -557,7 +557,7 @@ pub(crate) fn make_test(
// crate already is included. // crate already is included.
let result = rustc_driver::catch_fatal_errors(|| { let result = rustc_driver::catch_fatal_errors(|| {
rustc_span::create_session_if_not_set_then(edition, |_| { rustc_span::create_session_if_not_set_then(edition, |_| {
use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::emitter::{Emitter, HumanEmitter};
use rustc_errors::DiagCtxt; use rustc_errors::DiagCtxt;
use rustc_parse::parser::ForceCollect; use rustc_parse::parser::ForceCollect;
use rustc_span::source_map::FilePathMapping; use rustc_span::source_map::FilePathMapping;
@ -572,11 +572,11 @@ pub(crate) fn make_test(
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
false, false,
); );
supports_color = EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle.clone()) supports_color = HumanEmitter::stderr(ColorConfig::Auto, fallback_bundle.clone())
.diagnostic_width(Some(80)) .diagnostic_width(Some(80))
.supports_color(); .supports_color();
let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
@ -739,7 +739,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
} }
rustc_driver::catch_fatal_errors(|| { rustc_driver::catch_fatal_errors(|| {
rustc_span::create_session_if_not_set_then(edition, |_| { rustc_span::create_session_if_not_set_then(edition, |_| {
use rustc_errors::emitter::EmitterWriter; use rustc_errors::emitter::HumanEmitter;
use rustc_errors::DiagCtxt; use rustc_errors::DiagCtxt;
use rustc_span::source_map::FilePathMapping; use rustc_span::source_map::FilePathMapping;
@ -752,7 +752,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
false, false,
); );
let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
let sess = ParseSess::with_dcx(dcx, sm); let sess = ParseSess::with_dcx(dcx, sm);

View file

@ -154,6 +154,28 @@ impl<'tcx> SpanMapVisitor<'tcx> {
self.matches.insert(new_span, link_from_src); self.matches.insert(new_span, link_from_src);
true true
} }
fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
let hir = self.tcx.hir();
let body_id = hir.enclosing_body_owner(hir_id);
// FIXME: this is showing error messages for parts of the code that are not
// compiled (because of cfg)!
//
// See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
let typeck_results = self
.tcx
.typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
// Interestingly enough, for method calls, we need the whole expression whereas for static
// method/function calls, we need the call expression specifically.
if let Some(def_id) = typeck_results.type_dependent_def_id(expr_hir_id.unwrap_or(hir_id)) {
let link = if def_id.as_local().is_some() {
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
} else {
LinkFromSrc::External(def_id)
};
self.matches.insert(span, link);
}
}
} }
impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@ -191,27 +213,17 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
} }
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let ExprKind::MethodCall(segment, ..) = expr.kind { match expr.kind {
let hir = self.tcx.hir(); ExprKind::MethodCall(segment, ..) => {
let body_id = hir.enclosing_body_owner(segment.hir_id); self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span)
// FIXME: this is showing error messages for parts of the code that are not }
// compiled (because of cfg)! ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span),
// _ => {
// See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 if self.handle_macro(expr.span) {
let typeck_results = self // We don't want to go deeper into the macro.
.tcx return;
.typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body")); }
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
let link = if def_id.as_local().is_some() {
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
} else {
LinkFromSrc::External(def_id)
};
self.matches.insert(segment.ident.span, link);
} }
} else if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
return;
} }
intravisit::walk_expr(self, expr); intravisit::walk_expr(self, expr);
} }

View file

@ -1733,7 +1733,7 @@ fn report_diagnostic(
}; };
if let Some(sp) = span { if let Some(sp) = span {
lint.set_span(sp); lint.span(sp);
} else { } else {
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
// ^ ~~~~ // ^ ~~~~

View file

@ -5,7 +5,7 @@ use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter; use rustc_errors::emitter::HumanEmitter;
use rustc_errors::DiagCtxt; use rustc_errors::DiagCtxt;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::maybe_new_parser_from_source_str;
@ -44,7 +44,7 @@ pub fn check(
let fallback_bundle = let fallback_bundle =
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
#[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));

View file

@ -6,7 +6,7 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
| |
= help: the trait `std::marker::Sized` is not implemented for `[u8]` = help: the trait `std::marker::Sized` is not implemented for `[u8]`
= help: unsized fn params are gated as an unstable feature = help: unsized fn params are gated as an unstable feature
help: function arguments must have a statically known size, borrowed types always have a known size help: function arguments must have a statically known size, borrowed slices always have a known size
| |
LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: &[u8]| x }]> { LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: &[u8]| x }]> {
| + | +

View file

@ -387,6 +387,10 @@ pub struct Config {
// Needed both to construct build_helper::git::GitConfig // Needed both to construct build_helper::git::GitConfig
pub git_repository: String, pub git_repository: String,
pub nightly_branch: String, pub nightly_branch: String,
/// True if the profiler runtime is enabled for this target.
/// Used by the "needs-profiler-support" header in test files.
pub profiler_support: bool,
} }
impl Config { impl Config {

View file

@ -178,6 +178,9 @@ pub struct TestProps {
// Whether to tell `rustc` to remap the "src base" directory to a fake // Whether to tell `rustc` to remap the "src base" directory to a fake
// directory. // directory.
pub remap_src_base: bool, pub remap_src_base: bool,
/// Extra flags to pass to `llvm-cov` when producing coverage reports.
/// Only used by the "coverage-run" test mode.
pub llvm_cov_flags: Vec<String>,
} }
mod directives { mod directives {
@ -216,6 +219,7 @@ mod directives {
pub const MIR_UNIT_TEST: &'static str = "unit-test"; pub const MIR_UNIT_TEST: &'static str = "unit-test";
pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; pub const REMAP_SRC_BASE: &'static str = "remap-src-base";
pub const COMPARE_OUTPUT_LINES_BY_SUBSET: &'static str = "compare-output-lines-by-subset"; pub const COMPARE_OUTPUT_LINES_BY_SUBSET: &'static str = "compare-output-lines-by-subset";
pub const LLVM_COV_FLAGS: &'static str = "llvm-cov-flags";
// This isn't a real directive, just one that is probably mistyped often // This isn't a real directive, just one that is probably mistyped often
pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
} }
@ -265,6 +269,7 @@ impl TestProps {
stderr_per_bitwidth: false, stderr_per_bitwidth: false,
mir_unit_test: None, mir_unit_test: None,
remap_src_base: false, remap_src_base: false,
llvm_cov_flags: vec![],
} }
} }
@ -321,16 +326,23 @@ impl TestProps {
|r| r, |r| r,
); );
if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { fn split_flags(flags: &str) -> Vec<String> {
self.compile_flags.extend( // Individual flags can be single-quoted to preserve spaces; see
flags // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
.split("'") flags
.enumerate() .split("'")
.flat_map(|(i, f)| { .enumerate()
.flat_map(
|(i, f)| {
if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
}) },
.map(|s| s.to_owned()), )
); .map(move |s| s.to_owned())
.collect::<Vec<_>>()
}
if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
self.compile_flags.extend(split_flags(&flags));
} }
if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
panic!("`compiler-flags` directive should be spelled `compile-flags`"); panic!("`compiler-flags` directive should be spelled `compile-flags`");
@ -488,6 +500,10 @@ impl TestProps {
COMPARE_OUTPUT_LINES_BY_SUBSET, COMPARE_OUTPUT_LINES_BY_SUBSET,
&mut self.compare_output_lines_by_subset, &mut self.compare_output_lines_by_subset,
); );
if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) {
self.llvm_cov_flags.extend(split_flags(&flags));
}
}); });
} }

View file

@ -1,4 +1,4 @@
use crate::common::{CompareMode, Config, Debugger}; use crate::common::{CompareMode, Config, Debugger, Mode};
use crate::header::IgnoreDecision; use crate::header::IgnoreDecision;
use std::collections::HashSet; use std::collections::HashSet;
@ -208,6 +208,17 @@ pub(super) fn parse_cfg_name_directive<'a>(
}, },
message: "when comparing with {name}", message: "when comparing with {name}",
} }
// Coverage tests run the same test file in multiple modes.
// If a particular test should not be run in one of the modes, ignore it
// with "ignore-mode-coverage-map" or "ignore-mode-coverage-run".
condition! {
name: format!("mode-{}", config.mode.to_str()),
allowed_names: ContainsPrefixed {
prefix: "mode-",
inner: Mode::STR_VARIANTS,
},
message: "when the test mode is {name}",
}
if prefix == "ignore" && outcome == MatchOutcome::Invalid { if prefix == "ignore" && outcome == MatchOutcome::Invalid {
// Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest. // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.

View file

@ -238,7 +238,7 @@ impl CachedNeedsConditions {
sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag), sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag),
sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack), sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack),
sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack), sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack),
profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(), profiler_support: config.profiler_support,
xray: config.target_cfg().xray, xray: config.target_cfg().xray,
// For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`), // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`),

View file

@ -1,7 +1,8 @@
use std::io::Read; use std::io::Read;
use std::path::Path; use std::path::Path;
use std::str::FromStr;
use crate::common::{Config, Debugger}; use crate::common::{Config, Debugger, Mode};
use crate::header::{parse_normalization_string, EarlyProps, HeadersCache}; use crate::header::{parse_normalization_string, EarlyProps, HeadersCache};
fn make_test_description<R: Read>( fn make_test_description<R: Read>(
@ -55,6 +56,7 @@ fn test_parse_normalization_string() {
#[derive(Default)] #[derive(Default)]
struct ConfigBuilder { struct ConfigBuilder {
mode: Option<String>,
channel: Option<String>, channel: Option<String>,
host: Option<String>, host: Option<String>,
target: Option<String>, target: Option<String>,
@ -62,9 +64,15 @@ struct ConfigBuilder {
llvm_version: Option<String>, llvm_version: Option<String>,
git_hash: bool, git_hash: bool,
system_llvm: bool, system_llvm: bool,
profiler_support: bool,
} }
impl ConfigBuilder { impl ConfigBuilder {
fn mode(&mut self, s: &str) -> &mut Self {
self.mode = Some(s.to_owned());
self
}
fn channel(&mut self, s: &str) -> &mut Self { fn channel(&mut self, s: &str) -> &mut Self {
self.channel = Some(s.to_owned()); self.channel = Some(s.to_owned());
self self
@ -100,10 +108,16 @@ impl ConfigBuilder {
self self
} }
fn profiler_support(&mut self, s: bool) -> &mut Self {
self.profiler_support = s;
self
}
fn build(&mut self) -> Config { fn build(&mut self) -> Config {
let args = &[ let args = &[
"compiletest", "compiletest",
"--mode=ui", "--mode",
self.mode.as_deref().unwrap_or("ui"),
"--suite=ui", "--suite=ui",
"--compile-lib-path=", "--compile-lib-path=",
"--run-lib-path=", "--run-lib-path=",
@ -142,6 +156,9 @@ impl ConfigBuilder {
if self.system_llvm { if self.system_llvm {
args.push("--system-llvm".to_owned()); args.push("--system-llvm".to_owned());
} }
if self.profiler_support {
args.push("--profiler-support".to_owned());
}
args.push("--rustc-path".to_string()); args.push("--rustc-path".to_string());
// This is a subtle/fragile thing. On rust-lang CI, there is no global // This is a subtle/fragile thing. On rust-lang CI, there is no global
@ -340,6 +357,15 @@ fn sanitizers() {
assert!(check_ignore(&config, "// needs-sanitizer-thread")); assert!(check_ignore(&config, "// needs-sanitizer-thread"));
} }
#[test]
fn profiler_support() {
let config: Config = cfg().profiler_support(false).build();
assert!(check_ignore(&config, "// needs-profiler-support"));
let config: Config = cfg().profiler_support(true).build();
assert!(!check_ignore(&config, "// needs-profiler-support"));
}
#[test] #[test]
fn asm_support() { fn asm_support() {
let asms = [ let asms = [
@ -530,3 +556,17 @@ fn families() {
assert!(!check_ignore(&config, &format!("// ignore-{other}"))); assert!(!check_ignore(&config, &format!("// ignore-{other}")));
} }
} }
#[test]
fn ignore_mode() {
for &mode in Mode::STR_VARIANTS {
// Indicate profiler support so that "coverage-run" tests aren't skipped.
let config: Config = cfg().mode(mode).profiler_support(true).build();
let other = if mode == "coverage-run" { "coverage-map" } else { "coverage-run" };
assert_ne!(mode, other);
assert_eq!(config.mode, Mode::from_str(mode).unwrap());
assert_ne!(config.mode, Mode::from_str(other).unwrap());
assert!(check_ignore(&config, &format!("// ignore-mode-{mode}")));
assert!(!check_ignore(&config, &format!("// ignore-mode-{other}")));
}
}

View file

@ -142,6 +142,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
.optflag("", "only-modified", "only run tests that result been modified") .optflag("", "only-modified", "only run tests that result been modified")
.optflag("", "nocapture", "") .optflag("", "nocapture", "")
.optflag("", "profiler-support", "is the profiler runtime enabled for this target")
.optflag("h", "help", "show this message") .optflag("h", "help", "show this message")
.reqopt("", "channel", "current Rust channel", "CHANNEL") .reqopt("", "channel", "current Rust channel", "CHANNEL")
.optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries")
@ -315,6 +316,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
git_repository: matches.opt_str("git-repository").unwrap(), git_repository: matches.opt_str("git-repository").unwrap(),
nightly_branch: matches.opt_str("nightly-branch").unwrap(), nightly_branch: matches.opt_str("nightly-branch").unwrap(),
profiler_support: matches.opt_present("profiler-support"),
} }
} }

View file

@ -575,6 +575,8 @@ impl<'test> TestCx<'test> {
cmd.arg("--object"); cmd.arg("--object");
cmd.arg(bin); cmd.arg(bin);
} }
cmd.args(&self.props.llvm_cov_flags);
}); });
if !proc_res.status.success() { if !proc_res.status.success() {
self.fatal_proc_rec("llvm-cov show failed!", &proc_res); self.fatal_proc_rec("llvm-cov show failed!", &proc_res);

View file

@ -454,12 +454,12 @@ pub fn report_msg<'tcx>(
let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
let sess = machine.tcx.sess; let sess = machine.tcx.sess;
let level = match diag_level { let level = match diag_level {
DiagLevel::Error => Level::Error { lint: false }, DiagLevel::Error => Level::Error,
DiagLevel::Warning => Level::Warning(None), DiagLevel::Warning => Level::Warning(None),
DiagLevel::Note => Level::Note, DiagLevel::Note => Level::Note,
}; };
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title); let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);
err.set_span(span); err.span(span);
// Show main message. // Show main message.
if span != DUMMY_SP { if span != DUMMY_SP {

View file

@ -2,7 +2,7 @@ use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
use rustc_errors::emitter::{DynEmitter, Emitter, EmitterWriter}; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter};
use rustc_errors::translation::Translate; use rustc_errors::translation::Translate;
use rustc_errors::{ColorConfig, DiagCtxt, Diagnostic, Level as DiagnosticLevel}; use rustc_errors::{ColorConfig, DiagCtxt, Diagnostic, Level as DiagnosticLevel};
use rustc_session::parse::ParseSess as RawParseSess; use rustc_session::parse::ParseSess as RawParseSess;
@ -139,7 +139,7 @@ fn default_dcx(
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
false, false,
); );
Box::new(EmitterWriter::stderr(emit_color, fallback_bundle).sm(Some(source_map.clone()))) Box::new(HumanEmitter::stderr(emit_color, fallback_bundle).sm(Some(source_map.clone())))
}; };
DiagCtxt::with_emitter(Box::new(SilentOnIgnoredFilesEmitter { DiagCtxt::with_emitter(Box::new(SilentOnIgnoredFilesEmitter {
has_non_ignorable_parser_errors: false, has_non_ignorable_parser_errors: false,

View file

@ -0,0 +1,13 @@
LL| |// edition: 2021
LL| |// ignore-mode-coverage-map
LL| |// ignore-windows
LL| |// llvm-cov-flags: --use-color
LL| |
LL| |// Verify that telling `llvm-cov` to use colored output actually works.
LL| |// Ignored on Windows because we can't tell the tool to use ANSI escapes.
LL| |
LL| 1|fn main() {
LL| 1| for _i in 0..0 {}
^0 ^0
LL| 1|}

11
tests/coverage/color.rs Normal file
View file

@ -0,0 +1,11 @@
// edition: 2021
// ignore-mode-coverage-map
// ignore-windows
// llvm-cov-flags: --use-color
// Verify that telling `llvm-cov` to use colored output actually works.
// Ignored on Windows because we can't tell the tool to use ANSI escapes.
fn main() {
for _i in 0..0 {}
}

View file

@ -0,0 +1,4 @@
LL| |// ignore-mode-coverage-map
LL| |
LL| 1|fn main() {}

View file

@ -0,0 +1,3 @@
// ignore-mode-coverage-map
fn main() {}

View file

@ -0,0 +1,8 @@
Function name: ignore_run::main
Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13)

View file

@ -0,0 +1,3 @@
// ignore-mode-coverage-run
fn main() {}

View file

@ -8,14 +8,14 @@
bb0: { bb0: {
- _2 = _1; - _2 = _1;
- _0 = opaque::<NotCopy>(move _1) -> [return: bb1, unwind continue]; - _0 = opaque::<NotCopy>(move _1) -> [return: bb1, unwind unreachable];
+ _0 = opaque::<NotCopy>(_1) -> [return: bb1, unwind continue]; + _0 = opaque::<NotCopy>(_1) -> [return: bb1, unwind unreachable];
} }
bb1: { bb1: {
- _3 = move _2; - _3 = move _2;
- _0 = opaque::<NotCopy>(_3) -> [return: bb2, unwind continue]; - _0 = opaque::<NotCopy>(_3) -> [return: bb2, unwind unreachable];
+ _0 = opaque::<NotCopy>(_1) -> [return: bb2, unwind continue]; + _0 = opaque::<NotCopy>(_1) -> [return: bb2, unwind unreachable];
} }
bb2: { bb2: {

Some files were not shown because too many files have changed in this diff Show more