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:
commit
11035f9f52
133 changed files with 1560 additions and 1830 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
));
|
));
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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![];
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 == '(' {
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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('&', "&").replace('<', "<").replace('>', ">")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn escape_attr(s: &str) -> String {
|
|
||||||
s.replace('&', "&")
|
|
||||||
.replace('\"', """)
|
|
||||||
.replace('\'', "'")
|
|
||||||
.replace('<', "<")
|
|
||||||
.replace('>', ">")
|
|
||||||
}
|
|
|
@ -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`.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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],
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
));
|
));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
// ^ ~~~~
|
// ^ ~~~~
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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 }]> {
|
||||||
| +
|
| +
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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`),
|
||||||
|
|
|
@ -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}")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
13
tests/coverage/color.coverage
Normal file
13
tests/coverage/color.coverage
Normal 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| [0;35m1[0m| for [0;41m_i[0m in 0..0 [0;41m{}[0m
|
||||||
|
^0 ^0
|
||||||
|
LL| 1|}
|
||||||
|
|
11
tests/coverage/color.rs
Normal file
11
tests/coverage/color.rs
Normal 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 {}
|
||||||
|
}
|
4
tests/coverage/ignore_map.coverage
Normal file
4
tests/coverage/ignore_map.coverage
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
LL| |// ignore-mode-coverage-map
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn main() {}
|
||||||
|
|
3
tests/coverage/ignore_map.rs
Normal file
3
tests/coverage/ignore_map.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// ignore-mode-coverage-map
|
||||||
|
|
||||||
|
fn main() {}
|
8
tests/coverage/ignore_run.cov-map
Normal file
8
tests/coverage/ignore_run.cov-map
Normal 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)
|
||||||
|
|
3
tests/coverage/ignore_run.rs
Normal file
3
tests/coverage/ignore_run.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// ignore-mode-coverage-run
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue