Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2024-01-06 05:01:35 +00:00
commit 078f228085
767 changed files with 4608 additions and 8034 deletions

View file

@ -546,20 +546,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat);
let guard = arm.guard.as_ref().map(|cond| {
if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind {
hir::Guard::IfLet(self.arena.alloc(hir::Let {
hir_id: self.next_id(),
span: self.lower_span(*span),
pat: self.lower_pat(pat),
ty: None,
init: self.lower_expr(scrutinee),
is_recovered: *is_recovered,
}))
} else {
hir::Guard::If(self.lower_expr(cond))
}
});
let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
let hir_id = self.next_id();
let span = self.lower_span(arm.span);
self.lower_attrs(hir_id, &arm.attrs);

View file

@ -188,6 +188,9 @@ ast_passes_module_nonascii = trying to load file for module `{$name}` with non-a
ast_passes_negative_bound_not_supported =
negative bounds are not supported
ast_passes_negative_bound_with_parenthetical_notation =
parenthetical notation may not be used for negative bounds
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
.outer = outer `impl Trait`
.inner = nested `impl Trait` here

View file

@ -1312,13 +1312,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let GenericBound::Trait(trait_ref, modifiers) = bound
&& let BoundPolarity::Negative(_) = modifiers.polarity
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
{
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.dcx()
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
match segment.args.as_deref() {
Some(ast::GenericArgs::AngleBracketed(args)) => {
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
span: constraint.span,
});
}
}
}
// The lowered form of parenthesized generic args contains a type binding.
Some(ast::GenericArgs::Parenthesized(args)) => {
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
span: args.span,
});
}
None => {}
}
}

View file

@ -725,8 +725,8 @@ impl AddToDiagnostic for StableFeature {
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{
diag.set_arg("name", self.name);
diag.set_arg("since", self.since);
diag.arg("name", self.name);
diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);
}
}
@ -763,6 +763,13 @@ pub struct ConstraintOnNegativeBound {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_negative_bound_with_parenthetical_notation)]
pub struct NegativeBoundWithParentheticalNotation {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_invalid_unnamed_field_ty)]
pub struct InvalidUnnamedFieldTy {

View file

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

View file

@ -3590,7 +3590,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
));
} else if let Some(guard) = &arm.guard {
self.errors.push((
arm.pat.span.to(guard.body().span),
arm.pat.span.to(guard.span),
format!(
"if this pattern and condition are matched, {} is not \
initialized",

View file

@ -94,31 +94,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
debug!(
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
body.yield_ty(),
universal_regions.yield_ty
);
// We will not have a universal_regions.yield_ty if we yield (by accident)
// outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug
// because we don't want to panic in an assert here if we've already got errors.
if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
self.tcx().dcx().span_delayed_bug(
body.span,
format!(
"Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
body.yield_ty(),
universal_regions.yield_ty,
),
if let Some(mir_yield_ty) = body.yield_ty() {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(
universal_regions.yield_ty.unwrap(),
mir_yield_ty,
yield_span,
);
}
if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
(body.yield_ty(), universal_regions.yield_ty)
{
if let Some(mir_resume_ty) = body.resume_ty() {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
self.equate_normalized_input_or_output(
universal_regions.resume_ty.unwrap(),
mir_resume_ty,
yield_span,
);
}
// Return types are a bit more complex. They may contain opaque `impl Trait` types.

View file

@ -183,6 +183,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
match ty_context {
TyContext::ReturnTy(SourceInfo { span, .. })
| TyContext::YieldTy(SourceInfo { span, .. })
| TyContext::ResumeTy(SourceInfo { span, .. })
| TyContext::UserTy(span)
| TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);

View file

@ -1450,13 +1450,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
TerminatorKind::Yield { value, .. } => {
TerminatorKind::Yield { value, resume_arg, .. } => {
self.check_operand(value, term_location);
let value_ty = value.ty(body, tcx);
match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-coroutine"),
Some(ty) => {
let value_ty = value.ty(body, tcx);
if let Err(terr) = self.sub_types(
value_ty,
ty,
@ -1474,6 +1474,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
match body.resume_ty() {
None => span_mirbug!(self, term, "yield in non-coroutine"),
Some(ty) => {
let resume_ty = resume_arg.ty(body, tcx);
if let Err(terr) = self.sub_types(
ty,
resume_ty.ty,
term_location.to_locations(),
ConstraintCategory::Yield,
) {
span_mirbug!(
self,
term,
"type of resume place is {:?}, but the resume type is {:?}: {:?}",
resume_ty,
ty,
terr
);
}
}
}
}
}
}

View file

@ -76,6 +76,8 @@ pub struct UniversalRegions<'tcx> {
pub unnormalized_input_tys: &'tcx [Ty<'tcx>],
pub yield_ty: Option<Ty<'tcx>>,
pub resume_ty: Option<Ty<'tcx>>,
}
/// The "defining type" for this MIR. The key feature of the "defining
@ -525,9 +527,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
debug!("build: extern regions = {}..{}", first_extern_index, first_local_index);
debug!("build: local regions = {}..{}", first_local_index, num_universals);
let yield_ty = match defining_ty {
DefiningTy::Coroutine(_, args) => Some(args.as_coroutine().yield_ty()),
_ => None,
let (resume_ty, yield_ty) = match defining_ty {
DefiningTy::Coroutine(_, args) => {
let tys = args.as_coroutine();
(Some(tys.resume_ty()), Some(tys.yield_ty()))
}
_ => (None, None),
};
UniversalRegions {
@ -541,6 +546,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
unnormalized_output_ty: *unnormalized_output_ty,
unnormalized_input_tys,
yield_ty,
resume_ty,
}
}

View file

@ -454,7 +454,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMe
reason = "cannot translate user-provided messages"
)]
let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
diag.set_span(self.span);
diag.span(self.span);
diag
}
}
@ -618,7 +618,7 @@ impl AddToDiagnostic for FormatUnusedArg {
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());
diag.span_label(self.span, msg);
}
@ -808,7 +808,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
level,
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>`
let lbl1 = dcx.eagerly_translate_to_string(
crate::fluent_generated::builtin_macros_asm_clobber_abi,

View file

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

View file

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

View file

@ -6,7 +6,7 @@ use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::MemFlags;
@ -253,7 +253,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
bx.lifetime_end(llscratch, scratch_size);
}
} else {
OperandValue::Immediate(val).store(bx, dst);
OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
}
}

View file

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

View file

@ -558,10 +558,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
OperandValue::Immediate(self.to_immediate(llval, place.layout))
} else if let abi::Abi::ScalarPair(a, b) = place.layout.abi {
let b_offset = a.size(self).align_to(b.align(self).abi);
let pair_ty = place.layout.llvm_type(self);
let mut load = |i, scalar: abi::Scalar, layout, align, offset| {
let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
let llptr = if i == 0 {
place.llval
} else {
self.inbounds_gep(
self.type_i8(),
place.llval,
&[self.const_usize(b_offset.bytes())],
)
};
let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
let load = self.load(llty, llptr, align);
scalar_load_metadata(self, load, scalar, layout, offset);

View file

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

View file

@ -179,7 +179,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
unsafe {
llvm::LLVMSetAlignment(load, align);
}
self.to_immediate(load, self.layout_of(tp_ty))
if !result.layout.is_zst() {
self.store(load, result.llval, result.align);
}
return;
}
sym::volatile_store => {
let dst = args[0].deref(self.cx());

View file

@ -26,16 +26,7 @@ fn uncached_llvm_type<'a, 'tcx>(
let element = layout.scalar_llvm_type_at(cx, element);
return cx.type_vector(element, count);
}
Abi::ScalarPair(..) => {
return cx.type_struct(
&[
layout.scalar_pair_element_llvm_type(cx, 0, false),
layout.scalar_pair_element_llvm_type(cx, 1, false),
],
false,
);
}
Abi::Uninhabited | Abi::Aggregate { .. } => {}
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {}
}
let name = match layout.ty.kind() {
@ -275,11 +266,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
}
fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
if let Abi::Scalar(scalar) = self.abi {
if scalar.is_bool() {
return cx.type_i1();
match self.abi {
Abi::Scalar(scalar) => {
if scalar.is_bool() {
return cx.type_i1();
}
}
}
Abi::ScalarPair(..) => {
// An immediate pair always contains just the two elements, without any padding
// filler, as it should never be stored to memory.
return cx.type_struct(
&[
self.scalar_pair_element_llvm_type(cx, 0, true),
self.scalar_pair_element_llvm_type(cx, 1, true),
],
false,
);
}
_ => {}
};
self.llvm_type(cx)
}

View file

@ -3,7 +3,7 @@ use crate::base::allocator_kind_for_codegen;
use std::collections::hash_map::Entry::*;
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@ -393,10 +393,10 @@ fn exported_symbols_provider_local(
fn upstream_monomorphizations_provider(
tcx: TyCtxt<'_>,
(): (),
) -> DefIdMap<FxHashMap<GenericArgsRef<'_>, CrateNum>> {
) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> {
let cnums = tcx.crates(());
let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
@ -445,7 +445,7 @@ fn upstream_monomorphizations_provider(
fn upstream_monomorphizations_for_provider(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> Option<&FxHashMap<GenericArgsRef<'_>, CrateNum>> {
) -> Option<&UnordMap<GenericArgsRef<'_>, CrateNum>> {
debug_assert!(!def_id.is_local());
tcx.upstream_monomorphizations(()).get(&def_id)
}
@ -656,7 +656,7 @@ fn maybe_emutls_symbol_name<'tcx>(
}
}
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<String> {
// Build up a map from DefId to a `NativeLib` structure, where
// `NativeLib` internally contains information about
// `#[link(wasm_import_module = "...")]` for example.
@ -665,9 +665,9 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S
let def_id_to_native_lib = native_libs
.iter()
.filter_map(|lib| lib.foreign_module.map(|id| (id, lib)))
.collect::<FxHashMap<_, _>>();
.collect::<DefIdMap<_>>();
let mut ret = FxHashMap::default();
let mut ret = DefIdMap::default();
for (def_id, lib) in tcx.foreign_modules(cnum).iter() {
let module = def_id_to_native_lib.get(def_id).and_then(|s| s.wasm_import_module());
let Some(module) = module else { continue };

View file

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

View file

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

View file

@ -231,14 +231,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
bx: &mut Bx,
) -> V {
if let OperandValue::Pair(a, b) = self.val {
let llty = bx.cx().backend_type(self.layout);
let llty = bx.cx().immediate_backend_type(self.layout);
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty);
// Reconstruct the immediate aggregate.
let mut llpair = bx.cx().const_poison(llty);
let imm_a = bx.from_immediate(a);
let imm_b = bx.from_immediate(b);
llpair = bx.insert_value(llpair, imm_a, 0);
llpair = bx.insert_value(llpair, imm_b, 1);
llpair = bx.insert_value(llpair, a, 0);
llpair = bx.insert_value(llpair, b, 1);
llpair
} else {
self.immediate()
@ -251,14 +249,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
llval: V,
layout: TyAndLayout<'tcx>,
) -> Self {
let val = if let Abi::ScalarPair(a, b) = layout.abi {
let val = if let Abi::ScalarPair(..) = layout.abi {
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
// Deconstruct the immediate aggregate.
let a_llval = bx.extract_value(llval, 0);
let a_llval = bx.to_immediate_scalar(a_llval, a);
let b_llval = bx.extract_value(llval, 1);
let b_llval = bx.to_immediate_scalar(b_llval, b);
OperandValue::Pair(a_llval, b_llval)
} else {
OperandValue::Immediate(llval)
@ -435,15 +431,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else {
bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
};
let ty = bx.backend_type(dest.layout);
let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi);
let llptr = bx.struct_gep(ty, dest.llval, 0);
let val = bx.from_immediate(a);
let align = dest.align;
bx.store_with_flags(val, llptr, align, flags);
bx.store_with_flags(val, dest.llval, align, flags);
let llptr = bx.struct_gep(ty, dest.llval, 1);
let llptr =
bx.inbounds_gep(bx.type_i8(), dest.llval, &[bx.const_usize(b_offset.bytes())]);
let val = bx.from_immediate(b);
let align = dest.align.restrict_for_offset(b_offset);
bx.store_with_flags(val, llptr, align, flags);

View file

@ -108,20 +108,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
// Also handles the first field of Scalar, ScalarPair, and Vector layouts.
self.llval
}
Abi::ScalarPair(a, b)
if offset == a.size(bx.cx()).align_to(b.align(bx.cx()).abi) =>
{
// Offset matches second field.
let ty = bx.backend_type(self.layout);
bx.struct_gep(ty, self.llval, 1)
Abi::ScalarPair(..) => {
// FIXME(nikic): Generate this for all ABIs.
bx.inbounds_gep(bx.type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
}
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
Abi::Scalar(_) | Abi::Vector { .. } if field.is_zst() => {
// ZST fields (even some that require alignment) are not included in Scalar,
// ScalarPair, and Vector layouts, so manually offset the pointer.
bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
}
Abi::Scalar(_) | Abi::ScalarPair(..) => {
// All fields of Scalar and ScalarPair layouts must have been handled by this point.
Abi::Scalar(_) => {
// All fields of Scalar layouts must have been handled by this point.
// Vector layouts have additional fields for each element of the vector, so don't panic in that case.
bug!(
"offset of non-ZST field `{:?}` does not match layout `{:#?}`",

View file

@ -1,8 +1,8 @@
use crate::errors;
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@ -18,7 +18,7 @@ use rustc_span::Span;
pub fn from_target_feature(
tcx: TyCtxt<'_>,
attr: &ast::Attribute,
supported_target_features: &FxHashMap<String, Option<Symbol>>,
supported_target_features: &UnordMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
) {
let Some(list) = attr.meta_item_list() else { return };

View file

@ -518,7 +518,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
Ub(_) => {}
Custom(custom) => {
(custom.add_args)(&mut |name, value| {
builder.set_arg(name, value);
builder.arg(name, value);
});
}
ValidationError(e) => e.add_args(dcx, builder),
@ -536,65 +536,65 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
| UninhabitedEnumVariantWritten(_)
| UninhabitedEnumVariantRead(_) => {}
BoundsCheckFailed { len, index } => {
builder.set_arg("len", len);
builder.set_arg("index", index);
builder.arg("len", len);
builder.arg("index", index);
}
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
builder.set_arg("pointer", ptr);
builder.arg("pointer", ptr);
}
PointerUseAfterFree(alloc_id, msg) => {
builder
.set_arg("alloc_id", alloc_id)
.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx));
.arg("alloc_id", alloc_id)
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
}
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
builder
.set_arg("alloc_id", alloc_id)
.set_arg("alloc_size", alloc_size.bytes())
.set_arg("ptr_offset", ptr_offset)
.set_arg("ptr_size", ptr_size.bytes())
.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx));
.arg("alloc_id", alloc_id)
.arg("alloc_size", alloc_size.bytes())
.arg("ptr_offset", ptr_offset)
.arg("ptr_size", ptr_size.bytes())
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
}
DanglingIntPointer(ptr, msg) => {
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) => {
builder.set_arg("required", required.bytes());
builder.set_arg("has", has.bytes());
builder.set_arg("msg", format!("{msg:?}"));
builder.arg("required", required.bytes());
builder.arg("has", has.bytes());
builder.arg("msg", format!("{msg:?}"));
}
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
builder.set_arg("allocation", alloc);
builder.arg("allocation", alloc);
}
InvalidBool(b) => {
builder.set_arg("value", format!("{b:02x}"));
builder.arg("value", format!("{b:02x}"));
}
InvalidChar(c) => {
builder.set_arg("value", format!("{c:08x}"));
builder.arg("value", format!("{c:08x}"));
}
InvalidTag(tag) => {
builder.set_arg("tag", format!("{tag:x}"));
builder.arg("tag", format!("{tag:x}"));
}
InvalidStr(err) => {
builder.set_arg("err", format!("{err}"));
builder.arg("err", format!("{err}"));
}
InvalidUninitBytes(Some((alloc, info))) => {
builder.set_arg("alloc", alloc);
builder.set_arg("access", info.access);
builder.set_arg("uninit", info.bad);
builder.arg("alloc", alloc);
builder.arg("access", info.access);
builder.arg("uninit", info.bad);
}
ScalarSizeMismatch(info) => {
builder.set_arg("target_size", info.target_size);
builder.set_arg("data_size", info.data_size);
builder.arg("target_size", info.target_size);
builder.arg("data_size", info.data_size);
}
AbiMismatchArgument { caller_ty, callee_ty }
| AbiMismatchReturn { caller_ty, callee_ty } => {
builder.set_arg("caller_ty", caller_ty.to_string());
builder.set_arg("callee_ty", callee_ty.to_string());
builder.arg("caller_ty", caller_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>(
r: WrappingRange,
@ -725,12 +725,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
];
let args = args.iter().map(|(a, b)| (a, b));
let message = dcx.eagerly_translate_to_string(msg, args);
err.set_arg("in_range", message);
err.arg("in_range", message);
}
match self.kind {
PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
err.set_arg("ty", ty);
err.arg("ty", ty);
}
PointerAsInt { expected } | Uninit { expected } => {
let msg = match expected {
@ -747,28 +747,28 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
ExpectedKind::Str => fluent::const_eval_validation_expected_str,
};
let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
err.set_arg("expected", msg);
err.arg("expected", msg);
}
InvalidEnumTag { value }
| InvalidVTablePtr { value }
| InvalidBool { value }
| InvalidChar { value }
| InvalidFnPtr { value } => {
err.set_arg("value", value);
err.arg("value", value);
}
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
add_range_arg(range, max_value, dcx, err)
}
OutOfRange { range, max_value, value } => {
err.set_arg("value", value);
err.arg("value", value);
add_range_arg(range, max_value, dcx, err);
}
UnalignedPtr { required_bytes, found_bytes, .. } => {
err.set_arg("required_bytes", required_bytes);
err.set_arg("found_bytes", found_bytes);
err.arg("required_bytes", required_bytes);
err.arg("found_bytes", found_bytes);
}
DanglingPtrNoProvenance { pointer, .. } => {
err.set_arg("pointer", pointer);
err.arg("pointer", pointer);
}
NullPtr { .. }
| 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`.
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
builder.set_arg("ptr", ptr);
builder.arg("ptr", ptr);
}
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::ResourceExhaustion(e) => e.add_args(dcx, builder),
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<'_, ()> =
e.into_diagnostic().into_diagnostic(dcx, dummy_level);
for (name, val) in diag.args() {
builder.set_arg(name.clone(), val.clone());
builder.arg(name.clone(), val.clone());
}
diag.cancel();
}
InvalidProgramInfo::FnAbiAdjustForForeignAbi(
AdjustForForeignAbiError::Unsupported { arch, abi },
) => {
builder.set_arg("arch", arch);
builder.set_arg("abi", abi.name());
builder.arg("arch", arch);
builder.arg("abi", abi.name());
}
}
}

View file

@ -74,7 +74,6 @@ impl<'tcx> MirPass<'tcx> for Validator {
mir_phase,
unwind_edge_count: 0,
reachable_blocks: traversal::reachable_as_bitset(body),
place_cache: FxHashSet::default(),
value_cache: FxHashSet::default(),
can_unwind,
};
@ -106,7 +105,6 @@ struct CfgChecker<'a, 'tcx> {
mir_phase: MirPhase,
unwind_edge_count: usize,
reachable_blocks: BitSet<BasicBlock>,
place_cache: FxHashSet<PlaceRef<'tcx>>,
value_cache: FxHashSet<u128>,
// If `false`, then the MIR must not contain `UnwindAction::Continue` or
// `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) {
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(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
@ -341,7 +326,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.fail(location, format!("explicit `{kind:?}` is forbidden"));
}
}
StatementKind::StorageLive(_)
StatementKind::Assign(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Intrinsic(_)
| 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
// passed by a reference to the callee. Consequently they must be non-overlapping
// and cannot be packed. Currently this simply checks for duplicate places.
self.place_cache.clear();
self.place_cache.insert(destination.as_ref());
// passed by a reference to the callee. Consequently they cannot be packed.
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.
self.fail(
@ -418,10 +401,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
),
);
}
let mut has_duplicates = false;
for arg in args {
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() {
// This is bad! The callee will expect the memory to be aligned.
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, .. } => {
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(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {

View file

@ -245,6 +245,32 @@ unsafe impl<T: StableOrd> StableOrd for &T {
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
}
/// This is a companion trait to `StableOrd`. Some types like `Symbol` can be
/// compared in a cross-session stable way, but their `Ord` implementation is
/// not stable. In such cases, a `StableOrd` implementation can be provided
/// to offer a lightweight way for stable sorting. (The more heavyweight option
/// is to sort via `ToStableHashKey`, but then sorting needs to have access to
/// a stable hashing context and `ToStableHashKey` can also be expensive as in
/// the case of `Symbol` where it has to allocate a `String`.)
///
/// See the documentation of [StableOrd] for how stable sort order is defined.
/// The same definition applies here. Be careful when implementing this trait.
pub trait StableCompare {
const CAN_USE_UNSTABLE_SORT: bool;
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering;
}
/// `StableOrd` denotes that the type's `Ord` implementation is stable, so
/// we can implement `StableCompare` by just delegating to `Ord`.
impl<T: StableOrd> StableCompare for T {
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering {
self.cmp(other)
}
}
/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
/// that has the same requirements.
///

View file

@ -3,9 +3,8 @@
//! as required by the query system.
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec;
use std::{
borrow::Borrow,
borrow::{Borrow, BorrowMut},
collections::hash_map::Entry,
hash::Hash,
iter::{Product, Sum},
@ -14,7 +13,7 @@ use std::{
use crate::{
fingerprint::Fingerprint,
stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey},
stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey},
};
/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
@ -134,36 +133,78 @@ impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
}
}
impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
#[inline]
pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
where
T: ToStableHashKey<HCX>,
{
let mut items: Vec<T> = self.0.collect();
items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
items
self.collect_sorted(hcx, true)
}
#[inline]
pub fn into_sorted_stable_ord(self) -> Vec<T>
where
T: Ord + StableOrd,
T: StableCompare,
{
let mut items: Vec<T> = self.0.collect();
if !T::CAN_USE_UNSTABLE_SORT {
items.sort();
} else {
items.sort_unstable()
self.collect_stable_ord_by_key(|x| x)
}
#[inline]
pub fn into_sorted_stable_ord_by_key<K, C>(self, project_to_key: C) -> Vec<T>
where
K: StableCompare,
C: for<'a> Fn(&'a T) -> &'a K,
{
self.collect_stable_ord_by_key(project_to_key)
}
#[inline]
pub fn collect_sorted<HCX, C>(self, hcx: &HCX, cache_sort_key: bool) -> C
where
T: ToStableHashKey<HCX>,
C: FromIterator<T> + BorrowMut<[T]>,
{
let mut items: C = self.0.collect();
let slice = items.borrow_mut();
if slice.len() > 1 {
if cache_sort_key {
slice.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
} else {
slice.sort_by_key(|x| x.to_stable_hash_key(hcx));
}
}
items
}
pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
#[inline]
pub fn collect_stable_ord_by_key<K, C, P>(self, project_to_key: P) -> C
where
T: ToStableHashKey<HCX>,
K: StableCompare,
P: for<'a> Fn(&'a T) -> &'a K,
C: FromIterator<T> + BorrowMut<[T]>,
{
let mut items: SmallVec<[T; LEN]> = self.0.collect();
items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
let mut items: C = self.0.collect();
let slice = items.borrow_mut();
if slice.len() > 1 {
if !K::CAN_USE_UNSTABLE_SORT {
slice.sort_by(|a, b| {
let a_key = project_to_key(a);
let b_key = project_to_key(b);
a_key.stable_cmp(b_key)
});
} else {
slice.sort_unstable_by(|a, b| {
let a_key = project_to_key(a);
let b_key = project_to_key(b);
a_key.stable_cmp(b_key)
});
}
}
items
}
}
@ -268,16 +309,30 @@ impl<V: Eq + Hash> UnordSet<V> {
}
/// Returns the items of this set in stable sort order (as defined by
/// `StableOrd`). This method is much more efficient than
/// `StableCompare`). This method is much more efficient than
/// `into_sorted` because it does not need to transform keys to their
/// `ToStableHashKey` equivalent.
#[inline]
pub fn to_sorted_stable_ord(&self) -> Vec<V>
pub fn to_sorted_stable_ord(&self) -> Vec<&V>
where
V: Ord + StableOrd + Clone,
V: StableCompare,
{
let mut items: Vec<V> = self.inner.iter().cloned().collect();
items.sort_unstable();
let mut items: Vec<&V> = self.inner.iter().collect();
items.sort_unstable_by(|a, b| a.stable_cmp(*b));
items
}
/// Returns the items of this set in stable sort order (as defined by
/// `StableCompare`). This method is much more efficient than
/// `into_sorted` because it does not need to transform keys to their
/// `ToStableHashKey` equivalent.
#[inline]
pub fn into_sorted_stable_ord(self) -> Vec<V>
where
V: StableCompare,
{
let mut items: Vec<V> = self.inner.into_iter().collect();
items.sort_unstable_by(V::stable_cmp);
items
}
@ -483,16 +538,16 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
}
/// Returns the entries of this map in stable sort order (as defined by `StableOrd`).
/// Returns the entries of this map in stable sort order (as defined by `StableCompare`).
/// This method can be much more efficient than `into_sorted` because it does not need
/// to transform keys to their `ToStableHashKey` equivalent.
#[inline]
pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)>
pub fn to_sorted_stable_ord(&self) -> Vec<(&K, &V)>
where
K: Ord + StableOrd + Copy,
K: StableCompare,
{
let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect();
items.sort_unstable_by_key(|&(k, _)| k);
let mut items: Vec<_> = self.inner.iter().collect();
items.sort_unstable_by(|(a, _), (b, _)| a.stable_cmp(*b));
items
}
@ -510,6 +565,19 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k)
}
/// Returns the entries of this map in stable sort order (as defined by `StableCompare`).
/// This method can be much more efficient than `into_sorted` because it does not need
/// to transform keys to their `ToStableHashKey` equivalent.
#[inline]
pub fn into_sorted_stable_ord(self) -> Vec<(K, V)>
where
K: StableCompare,
{
let mut items: Vec<(K, V)> = self.inner.into_iter().collect();
items.sort_unstable_by(|a, b| a.0.stable_cmp(&b.0));
items
}
/// Returns the values of this map in stable sort order (as defined by K's
/// `ToStableHashKey` implementation).
///

View file

@ -1393,7 +1393,7 @@ fn report_ice(
) {
let fallback_bundle =
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,
fallback_bundle,
));

View file

@ -20,7 +20,7 @@ use rustc_span::source_map::SourceMap;
use rustc_span::SourceFile;
/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter {
pub struct AnnotateSnippetEmitter {
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
@ -33,7 +33,7 @@ pub struct AnnotateSnippetEmitterWriter {
macro_backtrace: bool,
}
impl Translate for AnnotateSnippetEmitterWriter {
impl Translate for AnnotateSnippetEmitter {
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
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
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
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`
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => {
AnnotationType::Error
}
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
Level::Warning(_) => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note,
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(
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,

View file

@ -212,6 +212,9 @@ impl StringPart {
}
}
// Note: most of these methods are setters that return `&mut Self`. The small
// number of simple getter functions all have `get_` prefixes to distinguish
// them from the setters.
impl Diagnostic {
#[track_caller]
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
@ -241,11 +244,9 @@ impl Diagnostic {
pub fn is_error(&self) -> bool {
match self.level {
Level::Bug
| Level::DelayedBug
| Level::Fatal
| Level::Error { .. }
| Level::FailureNote => true,
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error | Level::FailureNote => {
true
}
Level::Warning(_)
| Level::Note
@ -308,25 +309,27 @@ impl Diagnostic {
/// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense.
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self {
pub fn downgrade_to_delayed_bug(&mut self) {
assert!(
self.is_error(),
"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
self.level
);
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
/// was first built. That means it will be shown together with the original
/// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods.
/// 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.
///
/// This span is *not* considered a ["primary span"][`MultiSpan`]; only
/// the `Span` supplied when creating the diagnostic is primary.
/// 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.
#[rustc_lint_diagnostics]
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));
@ -344,7 +347,7 @@ impl Diagnostic {
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.set_span(after);
self.span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
if span_label.is_primary && keep_label {
@ -876,7 +879,7 @@ impl Diagnostic {
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();
if let Some(span) = self.span.primary_span() {
self.sort_span = span;
@ -884,7 +887,7 @@ impl Diagnostic {
self
}
pub fn set_is_lint(&mut self) -> &mut Self {
pub fn is_lint(&mut self) -> &mut Self {
self.is_lint = true;
self
}
@ -903,7 +906,7 @@ impl Diagnostic {
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
}
@ -915,7 +918,7 @@ impl Diagnostic {
self.args.iter()
}
pub fn set_arg(
pub fn arg(
&mut self,
name: impl Into<Cow<'static, str>>,
arg: impl IntoDiagnosticArg,

View file

@ -31,7 +31,7 @@ where
{
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(dcx, level);
diag.set_span(self.span);
diag.span(self.span);
diag
}
}
@ -207,11 +207,11 @@ macro_rules! forward {
// Forward pattern for &mut self -> &mut Self
(
$(#[$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])*
#[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
}
@ -356,35 +356,16 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
self.emit()
}
forward!(
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self
);
forward!(
/// 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(
forward!(pub fn span_label(
&mut self,
span: Span,
label: impl Into<SubdiagnosticMessage>
) -> &mut Self);
forward!(pub fn span_labels(
&mut self,
spans: impl IntoIterator<Item = Span>,
label: &str,
) -> &mut Self);
forward!(pub fn note_expected_found(
&mut self,
expected_label: &dyn fmt::Display,
@ -392,7 +373,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
found_label: &dyn fmt::Display,
found: DiagnosticStyledString,
) -> &mut Self);
forward!(pub fn note_expected_found_extra(
&mut self,
expected_label: &dyn fmt::Display,
@ -402,7 +382,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
expected_extra: &dyn fmt::Display,
found_extra: &dyn fmt::Display,
) -> &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 span_note(
@ -428,10 +407,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
sp: impl Into<MultiSpan>,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
forward!(pub fn disable_suggestions(&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 multipart_suggestion(
&mut self,
msg: impl Into<SubdiagnosticMessage>,
@ -498,16 +475,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn 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 code(&mut self, s: DiagnosticId) -> &mut Self);
forward!(pub fn set_arg(
forward!(pub fn arg(
&mut self,
name: impl Into<Cow<'static, str>>,
arg: impl IntoDiagnosticArg,
) -> &mut Self);
forward!(pub fn subdiagnostic(
&mut self,
subdiagnostic: impl crate::AddToDiagnostic

View file

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

View file

@ -61,13 +61,13 @@ impl HumanReadableErrorType {
self,
mut dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle,
) -> EmitterWriter {
) -> HumanEmitter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
if !dst.supports_color() && color {
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);
/// Emit a notification that an artifact has been output.
/// This is currently only supported for the JSON format,
/// other formats can, and will, simply ignore it.
/// Currently only supported for the JSON format.
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>) {}
/// Emit list of unused externs
/// Emit list of unused externs.
/// Currently only supported for the JSON format.
fn emit_unused_externs(
&mut self,
_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>> {
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>> {
self.sm.as_ref()
}
@ -622,7 +624,7 @@ impl ColorConfig {
/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
#[derive(Setters)]
pub struct EmitterWriter {
pub struct HumanEmitter {
#[setters(skip)]
dst: IntoDynSyncSend<Destination>,
sm: Option<Lrc<SourceMap>>,
@ -647,14 +649,14 @@ pub struct FileWithAnnotatedLines {
multiline_depth: usize,
}
impl EmitterWriter {
pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
impl HumanEmitter {
pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> HumanEmitter {
let dst = from_stderr(color_config);
Self::create(dst, fallback_bundle)
}
fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
EmitterWriter {
fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter {
HumanEmitter {
dst: IntoDynSyncSend(dst),
sm: None,
fluent_bundle: None,
@ -673,7 +675,7 @@ impl EmitterWriter {
pub fn new(
dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle,
) -> EmitterWriter {
) -> HumanEmitter {
Self::create(dst, fallback_bundle)
}

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::emitter::HumanEmitter;
use rustc_errors::{DiagCtxt, MultiSpan, PResult};
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],
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()))
.diagnostic_width(Some(140));
let dcx = DiagCtxt::with_emitter(Box::new(emitter));

View file

@ -210,7 +210,7 @@ declare_features! (
/// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
(incomplete, negative_bounds, "1.71.0", None),
(internal, negative_bounds, "1.71.0", None),
/// Allows using `#[omit_gdb_pretty_printer_section]`.
(internal, omit_gdb_pretty_printer_section, "1.5.0", None),
/// Allows using `#[prelude_import]` on glob `use` items.

View file

@ -1258,7 +1258,7 @@ pub struct Arm<'hir> {
/// If this pattern and the optional guard matches, then `body` is evaluated.
pub pat: &'hir Pat<'hir>,
/// Optional guard clause.
pub guard: Option<Guard<'hir>>,
pub guard: Option<&'hir Expr<'hir>>,
/// The expression the arm evaluates to if this arm matches.
pub body: &'hir Expr<'hir>,
}
@ -1280,26 +1280,6 @@ pub struct Let<'hir> {
pub is_recovered: Option<ErrorGuaranteed>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Guard<'hir> {
If(&'hir Expr<'hir>),
IfLet(&'hir Let<'hir>),
}
impl<'hir> Guard<'hir> {
/// Returns the body of the guard
///
/// In other words, returns the e in either of the following:
///
/// - `if e`
/// - `if let x = e`
pub fn body(&self) -> &'hir Expr<'hir> {
match self {
Guard::If(e) | Guard::IfLet(Let { init: e, .. }) => e,
}
}
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ExprField<'hir> {
#[stable_hasher(ignore)]

View file

@ -619,13 +619,8 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
visitor.visit_id(arm.hir_id);
visitor.visit_pat(arm.pat);
if let Some(ref g) = arm.guard {
match g {
Guard::If(ref e) => visitor.visit_expr(e),
Guard::IfLet(ref l) => {
visitor.visit_let_expr(l);
}
}
if let Some(ref e) = arm.guard {
visitor.visit_expr(e);
}
visitor.visit_expr(arm.body);
}

View file

@ -26,23 +26,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
span: Span,
) {
let tcx = self.tcx();
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_negative_sized_bound = false;
// Try to find an unbound in bounds.
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
unbounds.push(ptr)
let hir::GenericBound::Trait(ptr, modifier) = ab else {
continue;
};
match modifier {
hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
hir::TraitBoundModifier::Negative => {
if let Some(sized_def_id) = sized_def_id
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_negative_sized_bound = true;
}
}
_ => {}
}
}
};
search_bounds(ast_bounds);
if let Some((self_ty, where_clause)) = self_ty_where_predicates {
for clause in where_clause {
if let hir::WherePredicate::BoundPredicate(pred) = clause {
if pred.is_param_bound(self_ty.to_def_id()) {
search_bounds(pred.bounds);
}
if let hir::WherePredicate::BoundPredicate(pred) = clause
&& pred.is_param_bound(self_ty.to_def_id())
{
search_bounds(pred.bounds);
}
}
}
@ -53,15 +66,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
});
}
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_sized_unbound = false;
for unbound in unbounds {
if let Some(sized_def_id) = sized_def_id {
if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) {
seen_sized_unbound = true;
continue;
}
if let Some(sized_def_id) = sized_def_id
&& unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_sized_unbound = true;
continue;
}
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.dcx().span_warn(
@ -71,15 +82,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
);
}
// If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available.
if sized_def_id.is_none() {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
if seen_sized_unbound {
// There was in fact a `?Sized` bound, return without doing anything
} else {
// There was no `?Sized` bound; add implicitly sized if `Sized` is available.
if seen_sized_unbound || seen_negative_sized_bound {
// There was in fact a `?Sized` or `!Sized` bound;
// we don't need to do anything.
} else if sized_def_id.is_some() {
// There was no `?Sized` or `!Sized` bound;
// add `Sized` if it's available.
bounds.push_sized(tcx, self_ty, span);
}
}

View file

@ -6,6 +6,7 @@ use crate::errors::{
use crate::fluent_generated as fluent;
use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -605,7 +606,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let violations =
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
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;
}
}
@ -673,7 +674,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}))
})
.flatten()
.collect::<FxHashMap<Symbol, &ty::AssocItem>>();
.collect::<UnordMap<Symbol, &ty::AssocItem>>();
let mut names = names
.into_iter()
@ -709,7 +710,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut where_constraints = vec![];
let mut already_has_generics_args_suggestion = false;
for (span, assoc_items) in &associated_types {
let mut names: FxHashMap<_, usize> = FxHashMap::default();
let mut names: UnordMap<_, usize> = Default::default();
for item in assoc_items {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;

View file

@ -70,7 +70,7 @@ fn generic_arg_mismatch_err(
Res::Err => {
add_braces_suggestion(arg, &mut 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();
}
Res::Def(DefKind::TyParam, src_def_id) => {

View file

@ -1,7 +1,9 @@
use rustc_ast::TraitObjectSyntax;
use rustc_errors::{Diagnostic, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use super::AstConv;
@ -32,32 +34,146 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
let of_trait_span = of_trait_ref.path.span;
// 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 {
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() {
(span, format!(", {param_name}: {impl_trait_name}"))
} else {
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
else {
return;
};
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
if sugg.is_empty() {
return;
};
diag.multipart_suggestion(
format!(
"alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"
),
vec![(self_ty.span, param_name), add_generic_sugg],
sugg,
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) {
let tcx = self.tcx();
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 mut diag =
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(
label,
sugg,
@ -116,11 +234,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty.span,
msg,
|lint| {
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
if self_ty.span.can_be_used_for_suggestions()
&& !self.maybe_lint_impl_trait(self_ty, lint)
{
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
}
self.maybe_lint_blanket_trait_impl(self_ty, lint);
},
);

View file

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

View file

@ -1,6 +1,6 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
@ -478,7 +478,7 @@ fn compare_asyncness<'tcx>(
pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m_def_id: LocalDefId,
) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref =
@ -706,7 +706,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
);
ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
let mut remapped_types = FxHashMap::default();
let mut remapped_types = DefIdMap::default();
for (def_id, (ty, args)) in collected_types {
match infcx.fully_resolve((ty, args)) {
Ok((ty, args)) => {

View file

@ -177,6 +177,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
}
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
fn has_let_expr(expr: &Expr<'_>) -> bool {
match &expr.kind {
hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
hir::ExprKind::Let(..) => true,
_ => false,
}
}
let prev_cx = visitor.cx;
visitor.terminating_scopes.insert(arm.hir_id.local_id);
@ -184,7 +192,9 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
visitor.cx.var_parent = visitor.cx.parent;
if let Some(hir::Guard::If(expr)) = arm.guard {
if let Some(expr) = arm.guard
&& !has_let_expr(expr)
{
visitor.terminating_scopes.insert(expr.hir_id.local_id);
}

View file

@ -16,6 +16,7 @@
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@ -979,7 +980,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
})
// Check for duplicates
.and_then(|list| {
let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
let mut set: UnordMap<Symbol, Span> = Default::default();
let mut no_dups = true;
for ident in &*list {

View file

@ -319,10 +319,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams {
#[track_caller]
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);
err.set_span(self.span);
err.span(self.span);
err.code(error_code!(E0393));
err.set_arg("parameterCount", self.missing_type_params.len());
err.set_arg(
err.arg("parameterCount", self.missing_type_params.len());
err.arg(
"parameters",
self.missing_type_params
.iter()

View file

@ -59,6 +59,17 @@ pub(super) fn infer_predicates(
}
}
DefKind::TyAlias if tcx.type_alias_is_lazy(item_did) => {
insert_required_predicates_to_be_wf(
tcx,
tcx.type_of(item_did).instantiate_identity(),
tcx.def_span(item_did),
&global_inferred_outlives,
&mut item_required_predicates,
&mut explicit_map,
);
}
_ => {}
};
@ -88,14 +99,14 @@ pub(super) fn infer_predicates(
fn insert_required_predicates_to_be_wf<'tcx>(
tcx: TyCtxt<'tcx>,
field_ty: Ty<'tcx>,
field_span: Span,
ty: Ty<'tcx>,
span: Span,
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) {
for arg in field_ty.walk() {
let ty = match arg.unpack() {
for arg in ty.walk() {
let leaf_ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,
// No predicates from lifetimes or constants, except potentially
@ -103,63 +114,26 @@ fn insert_required_predicates_to_be_wf<'tcx>(
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
};
match *ty.kind() {
// The field is of type &'a T which means that we will have
// a predicate requirement of T: 'a (T outlives 'a).
//
// We also want to calculate potential predicates for the T
match *leaf_ty.kind() {
ty::Ref(region, rty, _) => {
// The type is `&'a T` which means that we will have
// a predicate requirement of `T: 'a` (`T` outlives `'a`).
//
// We also want to calculate potential predicates for the `T`.
debug!("Ref");
insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates);
insert_outlives_predicate(tcx, rty.into(), region, span, required_predicates);
}
// For each Adt (struct/enum/union) type `Foo<'a, T>`, we
// can load the current set of inferred and explicit
// predicates from `global_inferred_outlives` and filter the
// ones that are TypeOutlives.
ty::Adt(def, args) => {
// First check the inferred predicates
//
// Example 1:
//
// struct Foo<'a, T> {
// field1: Bar<'a, T>
// }
//
// struct Bar<'b, U> {
// field2: &'b U
// }
//
// Here, when processing the type of `field1`, we would
// request the set of implicit predicates computed for `Bar`
// thus far. This will initially come back empty, but in next
// round we will get `U: 'b`. We then apply the substitution
// `['b => 'a, U => T]` and thus get the requirement that `T:
// 'a` holds for `Foo`.
// For ADTs (structs/enums/unions), we check inferred and explicit predicates.
debug!("Adt");
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
for (unsubstituted_predicate, &span) in
unsubstituted_predicates.as_ref().skip_binder()
{
// `unsubstituted_predicate` is `U: 'b` in the
// example above. So apply the substitution to
// get `T: 'a` (or `predicate`):
let predicate = unsubstituted_predicates
.rebind(*unsubstituted_predicate)
.instantiate(tcx, args);
insert_outlives_predicate(
tcx,
predicate.0,
predicate.1,
span,
required_predicates,
);
}
}
// Check if the type has any explicit predicates that need
// to be added to `required_predicates`
// let _: () = args.region_at(0);
check_inferred_predicates(
tcx,
def.did(),
args,
global_inferred_outlives,
required_predicates,
);
check_explicit_predicates(
tcx,
def.did(),
@ -170,13 +144,31 @@ fn insert_required_predicates_to_be_wf<'tcx>(
);
}
ty::Alias(ty::Weak, alias) => {
// This corresponds to a type like `Type<'a, T>`.
// We check inferred and explicit predicates.
debug!("Weak");
check_inferred_predicates(
tcx,
alias.def_id,
alias.args,
global_inferred_outlives,
required_predicates,
);
check_explicit_predicates(
tcx,
alias.def_id,
alias.args,
required_predicates,
explicit_map,
None,
);
}
ty::Dynamic(obj, ..) => {
// This corresponds to `dyn Trait<..>`. In this case, we should
// use the explicit predicates as well.
debug!("Dynamic");
debug!("field_ty = {}", &field_ty);
debug!("ty in field = {}", &ty);
if let Some(ex_trait_ref) = obj.principal() {
// Here, we are passing the type `usize` as a
// placeholder value with the function
@ -198,21 +190,22 @@ fn insert_required_predicates_to_be_wf<'tcx>(
}
}
ty::Alias(ty::Projection, obj) => {
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
ty::Alias(ty::Projection, alias) => {
// This corresponds to a type like `<() as Trait<'a, T>>::Type`.
// We only use the explicit predicates of the trait but
// not the ones of the associated type itself.
debug!("Projection");
check_explicit_predicates(
tcx,
tcx.parent(obj.def_id),
obj.args,
tcx.parent(alias.def_id),
alias.args,
required_predicates,
explicit_map,
None,
);
}
// FIXME(inherent_associated_types): Handle this case properly.
// FIXME(inherent_associated_types): Use the explicit predicates from the parent impl.
ty::Alias(ty::Inherent, _) => {}
_ => {}
@ -220,19 +213,21 @@ fn insert_required_predicates_to_be_wf<'tcx>(
}
}
/// We also have to check the explicit predicates
/// declared on the type.
/// Check the explicit predicates declared on the type.
///
/// ### Example
///
/// ```ignore (illustrative)
/// struct Foo<'a, T> {
/// field1: Bar<T>
/// struct Outer<'a, T> {
/// field: Inner<T>,
/// }
///
/// struct Bar<U> where U: 'static, U: Foo {
/// ...
/// struct Inner<U> where U: 'static, U: Outer {
/// // ...
/// }
/// ```
/// Here, we should fetch the explicit predicates, which
/// will give us `U: 'static` and `U: Foo`. The latter we
/// will give us `U: 'static` and `U: Outer`. The latter we
/// can ignore, but we will want to process `U: 'static`,
/// applying the substitution as above.
fn check_explicit_predicates<'tcx>(
@ -303,3 +298,45 @@ fn check_explicit_predicates<'tcx>(
insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
}
}
/// Check the inferred predicates declared on the type.
///
/// ### Example
///
/// ```ignore (illustrative)
/// struct Outer<'a, T> {
/// outer: Inner<'a, T>,
/// }
///
/// struct Inner<'b, U> {
/// inner: &'b U,
/// }
/// ```
///
/// Here, when processing the type of field `outer`, we would request the
/// set of implicit predicates computed for `Inner` thus far. This will
/// initially come back empty, but in next round we will get `U: 'b`.
/// We then apply the substitution `['b => 'a, U => T]` and thus get the
/// requirement that `T: 'a` holds for `Outer`.
fn check_inferred_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
required_predicates: &mut RequiredPredicates<'tcx>,
) {
// Load the current set of inferred and explicit predicates from `global_inferred_outlives`
// and filter the ones that are `TypeOutlives`.
let Some(predicates) = global_inferred_outlives.get(&def_id) else {
return;
};
for (&predicate, &span) in predicates.as_ref().skip_binder() {
// `predicate` is `U: 'b` in the example above.
// So apply the substitution to get `T: 'a`.
let ty::OutlivesPredicate(arg, region) =
predicates.rebind(predicate).instantiate(tcx, args);
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
}
}

View file

@ -21,6 +21,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
let crate_map = tcx.inferred_outlives_crate(());
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
}
DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => {
let crate_map = tcx.inferred_outlives_crate(());
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
}
DefKind::AnonConst if tcx.features().generic_const_exprs => {
let id = tcx.local_def_id_to_hir_id(item_def_id);
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
@ -47,8 +51,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
}
fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
// Compute a map from each struct/enum/union S to the **explicit**
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Compute a map from each ADT (struct/enum/union) and lazy type alias to
// the **explicit** outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Typically there won't be many of these, except in older code where
// they were mandatory. Nonetheless, we have to ensure that every such
// predicate is satisfied, so they form a kind of base set of requirements

View file

@ -1874,17 +1874,9 @@ impl<'a> State<'a> {
self.print_pat(arm.pat);
self.space();
if let Some(ref g) = arm.guard {
match *g {
hir::Guard::If(e) => {
self.word_space("if");
self.print_expr(e);
self.space();
}
hir::Guard::IfLet(&hir::Let { pat, ty, init, .. }) => {
self.word_nbsp("if");
self.print_let(pat, ty, init);
}
}
self.word_space("if");
self.print_expr(g);
self.space();
}
self.word_space("=>");

View file

@ -78,16 +78,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut other_arms = vec![]; // Used only for diagnostics.
let mut prior_arm = None;
for arm in arms {
if let Some(g) = &arm.guard {
if let Some(e) = &arm.guard {
self.diverges.set(Diverges::Maybe);
match g {
hir::Guard::If(e) => {
self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
}
hir::Guard::IfLet(l) => {
self.check_expr_let(l);
}
};
self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
}
self.diverges.set(Diverges::Maybe);

View file

@ -73,7 +73,8 @@ pub(super) fn check_fn<'a, 'tcx>(
let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// 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);
// Check that argument is Sized.
@ -81,14 +82,14 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.require_type_is_sized(
param_ty,
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
traits::SizedArgumentType(
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
{
None
} else {
ty_span
ty.map(|ty| ty.hir_id)
},
),
);

View file

@ -215,7 +215,7 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
where
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
if self.expr_span.between(self.fru_span).is_empty() {

View file

@ -669,12 +669,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
);
self.walk_pat(discr_place, arm.pat, arm.guard.is_some());
match arm.guard {
Some(hir::Guard::If(e)) => self.consume_expr(e),
Some(hir::Guard::IfLet(l)) => {
self.walk_local(l.init, l.pat, None, |t| t.borrow_expr(l.init, ty::ImmBorrow))
}
None => {}
if let Some(ref e) = arm.guard {
self.consume_expr(e)
}
self.consume_expr(arm.body);

View file

@ -60,7 +60,7 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
// parameters are special cases of patterns, but we want to handle them as
// *distinct* cases. so track when we are hitting a pattern *within* an fn
// parameter.
outermost_fn_param_pat: Option<Span>,
outermost_fn_param_pat: Option<(Span, hir::HirId)>,
}
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>) {
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);
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 {
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 {
self.fcx.require_type_is_sized(
var_ty,
@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
{
None
} else {
Some(ty_span)
Some(hir_id)
},
),
);

View file

@ -913,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
restrict_type_params = true;
// #74886: Sort here so that the output is always the same.
let obligations = obligations.to_sorted_stable_ord();
let obligations = obligations.into_sorted_stable_ord();
err.span_suggestion_verbose(
span,
format!(
@ -961,7 +961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
but its trait bounds were not satisfied"
)
});
err.set_primary_message(primary_message);
err.primary_message(primary_message);
if let Some(label) = label {
custom_span_label = true;
err.span_label(span, label);

View file

@ -912,7 +912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
drop_order: bool,
) -> MigrationWarningReason {
MigrationWarningReason {
auto_traits: auto_trait_reasons.to_sorted_stable_ord(),
auto_traits: auto_trait_reasons.into_sorted_stable_ord(),
drop_order,
}
}

View file

@ -473,7 +473,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord();
for local_id in fcx_coercion_casts {
for &local_id in fcx_coercion_casts {
self.typeck_results.set_coercion_cast(local_id);
}
}

View file

@ -103,7 +103,7 @@ pub fn save_work_product_index(
// deleted during invalidation. Some object files don't change their
// content, they are just not needed anymore.
let previous_work_products = dep_graph.previous_work_products();
for (id, wp) in previous_work_products.to_sorted_stable_ord().iter() {
for (id, wp) in previous_work_products.to_sorted_stable_ord() {
if !new_work_products.contains_key(id) {
work_product::delete_workproduct_files(sess, wp);
debug_assert!(

View file

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

View file

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

View file

@ -2,9 +2,10 @@ use super::ObjectSafetyViolation;
use crate::infer::InferCtxt;
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::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Map;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Span;
@ -42,6 +43,7 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn report_object_safety_error<'tcx>(
tcx: TyCtxt<'tcx>,
span: Span,
hir_id: Option<hir::HirId>,
trait_def_id: DefId,
violations: &[ObjectSafetyViolation],
) -> 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"));
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 multi_span = vec![];
let mut messages = vec![];
@ -132,7 +152,10 @@ pub fn report_object_safety_error<'tcx>(
};
let externally_visible = if !impls.is_empty()
&& let Some(def_id) = trait_def_id.as_local()
&& tcx.effective_visibilities(()).is_exported(def_id)
// We may be executing this during typeck, which would result in cycle
// if we used effective_visibilities query, which looks into opaque types
// (and therefore calls typeck).
&& tcx.resolutions(()).effective_visibilities.is_exported(def_id)
{
true
} else {

View file

@ -735,9 +735,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| {
// Run THIR unsafety check because it's responsible for stealing
// and deallocating THIR when enabled.
tcx.ensure().thir_check_unsafety(def_id);
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id)
});
});

View file

@ -6,8 +6,8 @@ use rustc_session::config::{
build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, NextSolverConfig,
OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy,
Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
};
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_exclude_pass_number, 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_format, DumpMonoStatsFormat::Json);
untracked!(dylib_lto, true);
@ -806,7 +805,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_cfi_canonical_jump_tables, None);
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
@ -822,7 +820,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(stack_protector, StackProtector::All);
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
tracked!(thir_unsafeck, false);
tracked!(tiny_const_eval_limit, true);
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(translate_remapped_path_to_local_path, false);

View file

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

View file

@ -1,5 +1,5 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::query::Providers;
@ -72,7 +72,7 @@ struct ClashingExternDeclarations {
/// the symbol should be reported as a clashing declaration.
// FIXME: Technically, we could just store a &'tcx str here without issue; however, the
// `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
seen_decls: FxHashMap<Symbol, hir::OwnerId>,
seen_decls: UnordMap<Symbol, hir::OwnerId>,
}
/// Differentiate between whether the name for an extern decl came from the link_name attribute or
@ -96,7 +96,7 @@ impl SymbolName {
impl ClashingExternDeclarations {
pub(crate) fn new() -> Self {
ClashingExternDeclarations { seen_decls: FxHashMap::default() }
ClashingExternDeclarations { seen_decls: Default::default() }
}
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
@ -209,12 +209,12 @@ fn structurally_same_type<'tcx>(
b: Ty<'tcx>,
ckind: types::CItemKind,
) -> bool {
let mut seen_types = FxHashSet::default();
let mut seen_types = UnordSet::default();
structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind)
}
fn structurally_same_type_impl<'tcx>(
seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
seen_types: &mut UnordSet<(Ty<'tcx>, Ty<'tcx>)>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: Ty<'tcx>,

View file

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

View file

@ -328,6 +328,7 @@ fn register_builtins(store: &mut LintStore) {
store.register_renamed("disjoint_capture_migration", "rust_2021_incompatible_closure_captures");
store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns");
store.register_renamed("non_fmt_panic", "non_fmt_panics");
store.register_renamed("unused_tuple_struct_fields", "dead_code");
// These were moved to tool lints, but rustc still sees them when compiling normally, before
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use

View file

@ -5,8 +5,8 @@ use std::num::NonZeroU32;
use crate::errors::RequestedLevel;
use crate::fluent_generated as fluent;
use rustc_errors::{
AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString,
SuggestionStyle,
AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle,
};
use rustc_hir::def_id::DefId;
use rustc_macros::{LintDiagnostic, Subdiagnostic};
@ -135,7 +135,7 @@ pub struct BuiltinMissingDebugImpl<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> {
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 {
@ -239,7 +239,7 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
}
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);
rustc_session::parse::add_feature_diagnostics(
diag,
@ -268,12 +268,9 @@ pub struct SuggestChangingAssocTypes<'a, 'b> {
}
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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
// 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.
use rustc_hir::intravisit::{self, Visitor};
struct WalkAssocTypes<'a> {
err: &'a mut rustc_errors::Diagnostic,
err: &'a mut Diagnostic,
}
impl Visitor<'_> for WalkAssocTypes<'_> {
fn visit_qpath(
@ -326,12 +323,9 @@ pub struct 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
diag.multipart_suggestion(
fluent::lint_suggestion,
@ -425,8 +419,8 @@ pub struct BuiltinUnpermittedTypeInit<'a> {
}
impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty);
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.arg("ty", self.ty);
diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) {
// 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);
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
fn msg(&self) -> DiagnosticMessage {
self.msg.clone()
}
}
@ -449,12 +443,9 @@ pub struct 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
let mut err = self.err;
loop {
@ -506,12 +497,9 @@ pub struct BuiltinClashingExternSub<'a> {
}
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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
let mut expected_str = DiagnosticStyledString::new();
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
@ -779,12 +767,9 @@ pub struct 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
for (c, span) in self.spans {
diag.span_label(span, format!("{c:?}"));
@ -799,12 +784,9 @@ pub enum HiddenUnicodeCodepointsDiagSub {
// Used because of multiple multipart_suggestion and note
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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
match self {
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
// should do the same here to provide the same good suggestions as we do for
// literals above.
diag.set_arg(
diag.arg(
"escaped",
spans
.into_iter()
@ -953,12 +935,9 @@ pub struct 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
diag.span_suggestion_verbose(
self.suggestion,
@ -1147,8 +1126,8 @@ pub struct NonFmtPanicUnused {
// Used because of two suggestions based on one Option<Span>
impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("count", self.count);
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.arg("count", self.count);
diag.note(fluent::lint_note);
if let Some(span) = self.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
}
}
@ -1224,12 +1203,9 @@ pub enum 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
match self {
NonSnakeCaseDiagSub::Label { span } => {
@ -1342,12 +1318,12 @@ pub struct DropTraitConstraintsDiag<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("predicate", self.predicate);
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id));
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.arg("predicate", self.predicate);
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
}
}
@ -1359,11 +1335,11 @@ pub struct DropGlue<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id));
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
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
}
}
@ -1423,12 +1399,9 @@ pub enum 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
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
match self {
OverflowingBinHexSign::Positive => {
@ -1633,9 +1606,9 @@ pub struct ImproperCTypes<'a> {
// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span>
impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty);
diag.set_arg("desc", self.desc);
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.arg("ty", self.ty);
diag.arg("desc", self.desc);
diag.span_label(self.label, fluent::lint_label);
if let Some(help) = self.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
}
}
@ -1776,10 +1749,10 @@ pub enum UnusedDefSuggestion {
// Needed because of def_path_str
impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("pre", self.pre);
diag.set_arg("post", self.post);
diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
diag.arg("pre", self.pre);
diag.arg("post", self.post);
diag.arg("def", self.cx.tcx.def_path_str(self.def_id));
// check for #[must_use = "..."]
if let Some(note) = self.note {
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
}
}
@ -1859,14 +1832,14 @@ pub struct 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);
if let Some(sugg) = self.sugg {
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
}
}

View file

@ -4,7 +4,8 @@ use crate::lints::{
};
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordMap;
use rustc_span::symbol::Symbol;
declare_lint! {
@ -194,8 +195,8 @@ impl EarlyLintPass for NonAsciiIdents {
}
if has_non_ascii_idents && check_confusable_idents {
let mut skeleton_map: FxHashMap<Symbol, (Symbol, Span, bool)> =
FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default());
let mut skeleton_map: UnordMap<Symbol, (Symbol, Span, bool)> =
UnordMap::with_capacity(symbols.len());
let mut skeleton_buf = String::new();
for (&symbol, &sp) in symbols.iter() {
@ -248,8 +249,8 @@ impl EarlyLintPass for NonAsciiIdents {
Verified,
}
let mut script_states: FxHashMap<AugmentedScriptSet, ScriptSetUsage> =
FxHashMap::default();
let mut script_states: FxIndexMap<AugmentedScriptSet, ScriptSetUsage> =
Default::default();
let latin_augmented_script_set = AugmentedScriptSet::for_char('A');
script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified);

View file

@ -121,7 +121,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
#[allow(rustc::diagnostic_outside_of_impl)]
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_more_info_note);
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,
);
} else if suggest_debug {
lint.set_arg("ty", ty);
lint.arg("ty", ty);
lint.span_suggestion_verbose(
arg_span.shrink_to_lo(),
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 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(
fluent::lint_panic_suggestion,
if del == '(' {

View file

@ -125,7 +125,6 @@ declare_lint_pass! {
UNUSED_MACROS,
UNUSED_MUT,
UNUSED_QUALIFICATIONS,
UNUSED_TUPLE_STRUCT_FIELDS,
UNUSED_UNSAFE,
UNUSED_VARIABLES,
USELESS_DEPRECATED,
@ -697,8 +696,13 @@ declare_lint! {
/// Dead code may signal a mistake or unfinished code. To silence the
/// warning for individual items, prefix the name with an underscore such
/// as `_foo`. If it was intended to expose the item outside of the crate,
/// consider adding a visibility modifier like `pub`. Otherwise consider
/// removing the unused code.
/// consider adding a visibility modifier like `pub`.
///
/// To preserve the numbering of tuple structs with unused fields,
/// change the unused fields to have unit type or use
/// `PhantomData`.
///
/// Otherwise consider removing the unused code.
pub DEAD_CODE,
Warn,
"detect unused, unexported items"
@ -732,32 +736,6 @@ declare_lint! {
"detects attributes that were not used by the compiler"
}
declare_lint! {
/// The `unused_tuple_struct_fields` lint detects fields of tuple structs
/// that are never read.
///
/// ### Example
///
/// ```rust
/// #[warn(unused_tuple_struct_fields)]
/// struct S(i32, i32, i32);
/// let s = S(1, 2, 3);
/// let _ = (s.0, s.2);
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Tuple struct fields that are never read anywhere may indicate a
/// mistake or unfinished code. To silence this warning, consider
/// removing the unused field(s) or, to preserve the numbering of the
/// remaining fields, change the unused field(s) to have unit type.
pub UNUSED_TUPLE_STRUCT_FIELDS,
Allow,
"detects tuple struct fields that are never read"
}
declare_lint! {
/// The `unreachable_code` lint detects unreachable code paths.
///

View file

@ -9,7 +9,9 @@ pub use self::Level::*;
use rustc_ast::node_id::NodeId;
use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::stable_hasher::{
HashStable, StableCompare, StableHasher, ToStableHashKey,
};
use rustc_error_messages::{DiagnosticMessage, MultiSpan};
use rustc_hir::HashStableContext;
use rustc_hir::HirId;
@ -541,6 +543,14 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
}
}
impl StableCompare for LintId {
const CAN_USE_UNSTABLE_SORT: bool = true;
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering {
self.lint_name_raw().cmp(&other.lint_name_raw())
}
}
#[derive(Debug)]
pub struct AmbiguityErrorDiag {
pub msg: String,

View file

@ -5,8 +5,8 @@ use crate::diagnostics::error::{
};
use crate::diagnostics::utils::{
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,
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
should_generate_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy,
FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
};
use proc_macro2::{Ident, Span, TokenStream};
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
/// 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 {
let mut body = quote! {};
// Generate `set_arg` calls first..
for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
// Generate `arg` calls first..
for binding in variant.bindings().iter().filter(|bi| should_generate_arg(bi.ast())) {
body.extend(self.generate_field_code(binding));
}
// ..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
@ -253,7 +253,7 @@ impl DiagnosticDeriveVariantBuilder {
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! {
diag.set_arg(
diag.arg(
stringify!(#ident),
#field_binding
);
@ -312,7 +312,7 @@ impl DiagnosticDeriveVariantBuilder {
let name = ident.to_string();
match (&attr.meta, name.as_str()) {
// 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(_), "primary_span") => {
match self.kind {
@ -320,7 +320,7 @@ impl DiagnosticDeriveVariantBuilder {
report_error_if_not_applied_to_span(attr, &info)?;
return Ok(quote! {
diag.set_span(#binding);
diag.span(#binding);
});
}
DiagnosticDeriveKind::LintDiagnostic => {

View file

@ -6,8 +6,8 @@ use crate::diagnostics::error::{
use crate::diagnostics::utils::{
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,
should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap,
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
should_generate_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap,
SetOnce, SpannedOption, SubdiagnosticKind,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
@ -214,7 +214,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
}
/// 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 field = binding_info.ast();
@ -225,7 +225,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! {
#diag.set_arg(
#diag.arg(
stringify!(#ident),
#field_binding
);
@ -505,7 +505,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant
.bindings()
.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))
.collect();
@ -593,8 +593,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant
.bindings()
.iter()
.filter(|binding| should_generate_set_arg(binding.ast()))
.map(|binding| self.generate_field_set_arg(binding))
.filter(|binding| should_generate_arg(binding.ast()))
.map(|binding| self.generate_field_arg(binding))
.collect();
let formatting_init = &self.formatting_init;

View file

@ -584,7 +584,7 @@ pub(super) enum SubdiagnosticKind {
suggestion_kind: SuggestionKind,
applicability: SpannedOption<Applicability>,
/// 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,
/// Initialization logic for `code_field`'s variable, e.g.
/// `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`).
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...
field.attrs.iter().all(|attr| is_doc_comment(attr))
}

View file

@ -196,6 +196,10 @@ impl CStore {
CrateMetadataRef { cdata, cstore: self }
}
pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {
self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
}
fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
self.metas[cnum] = Some(Box::new(data));
@ -207,6 +211,12 @@ impl CStore {
.filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
}
fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> {
self.metas
.iter_enumerated_mut()
.filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data)))
}
fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
if !deps.contains(&cnum) {
let data = self.get_crate_data(cnum);
@ -586,11 +596,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
match result {
(LoadResult::Previous(cnum), None) => {
let data = self.cstore.get_crate_data(cnum);
let data = self.cstore.get_crate_data_mut(cnum);
if data.is_proc_macro_crate() {
dep_kind = CrateDepKind::MacrosOnly;
}
data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind));
data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
if let Some(private_dep) = private_dep {
data.update_and_private_dep(private_dep);
}
@ -637,17 +647,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}))
}
fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
let cmeta = self.cstore.get_crate_data(cnum);
if cmeta.update_extern_crate(extern_crate) {
// Propagate the extern crate info to dependencies if it was updated.
let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
for dep_cnum in cmeta.dependencies() {
self.update_extern_crate(dep_cnum, extern_crate);
}
}
}
// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(
&mut self,
@ -726,17 +725,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let mut runtime_found = false;
let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
let mut panic_runtimes = Vec::new();
for (cnum, data) in self.cstore.iter_crate_data() {
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
if data.is_panic_runtime() {
// Inject a dependency from all #![needs_panic_runtime] to this
// #![panic_runtime] crate.
self.inject_dependency_if(cnum, "a panic runtime", &|data| {
data.needs_panic_runtime()
});
panic_runtimes.push(cnum);
runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
}
}
for cnum in panic_runtimes {
self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
}
// If an explicitly linked and matching panic runtime was found, or if
// we just don't need one at all, then we're done here and there's
@ -917,7 +918,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
fn inject_dependency_if(
&self,
&mut self,
krate: CrateNum,
what: &str,
needs_dep: &dyn Fn(&CrateMetadata) -> bool,
@ -947,7 +948,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// crate provided for this compile, but in order for this compilation to
// be successfully linked we need to inject a dependency (to order the
// crates on the command line correctly).
for (cnum, data) in self.cstore.iter_crate_data() {
for (cnum, data) in self.cstore.iter_crate_data_mut() {
if needs_dep(data) {
info!("injecting a dep from {} to {}", cnum, krate);
data.add_dependency(krate);
@ -1031,7 +1032,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let cnum = self.resolve_crate(name, item.span, dep_kind)?;
let path_len = definitions.def_path(def_id).data.len();
self.update_extern_crate(
self.cstore.update_extern_crate(
cnum,
ExternCrate {
src: ExternCrateSource::Extern(def_id.to_def_id()),
@ -1049,7 +1050,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
self.update_extern_crate(
self.cstore.update_extern_crate(
cnum,
ExternCrate {
src: ExternCrateSource::Path,

View file

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

View file

@ -8,7 +8,7 @@ use rustc_ast as ast;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::owned_slice::OwnedSlice;
use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc, OnceLock};
use rustc_data_structures::sync::{Lock, Lrc, OnceLock};
use rustc_data_structures::unhash::UnhashMap;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
@ -31,7 +31,6 @@ use rustc_span::{BytePos, Pos, SpanData, SyntaxContext, DUMMY_SP};
use proc_macro::bridge::client::ProcMacro;
use std::iter::TrustedLen;
use std::path::Path;
use std::sync::atomic::Ordering;
use std::{io, iter, mem};
pub(super) use cstore_impl::provide;
@ -96,15 +95,15 @@ pub(crate) struct CrateMetadata {
/// IDs as they are seen from the current compilation session.
cnum_map: CrateNumMap,
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
dependencies: AppendOnlyVec<CrateNum>,
dependencies: Vec<CrateNum>,
/// How to link (or not link) this crate to the currently compiled crate.
dep_kind: Lock<CrateDepKind>,
dep_kind: CrateDepKind,
/// Filesystem location of this crate.
source: Lrc<CrateSource>,
/// Whether or not this crate should be consider a private dependency.
/// Used by the 'exported_private_dependencies' lint, and for determining
/// whether to emit suggestions that reference this crate.
private_dep: AtomicBool,
private_dep: bool,
/// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
host_hash: Option<Svh>,
@ -118,7 +117,7 @@ pub(crate) struct CrateMetadata {
// --- Data used only for improving diagnostics ---
/// Information about the `extern crate` item or path that caused this crate to be loaded.
/// If this is `None`, then the crate was injected (e.g., by the allocator).
extern_crate: Lock<Option<ExternCrate>>,
extern_crate: Option<ExternCrate>,
}
/// Holds information about a rustc_span::SourceFile imported from another crate.
@ -1818,11 +1817,11 @@ impl CrateMetadata {
cnum,
cnum_map,
dependencies,
dep_kind: Lock::new(dep_kind),
dep_kind,
source: Lrc::new(source),
private_dep: AtomicBool::new(private_dep),
private_dep,
host_hash,
extern_crate: Lock::new(None),
extern_crate: None,
hygiene_context: Default::default(),
def_key_cache: Default::default(),
};
@ -1839,18 +1838,18 @@ impl CrateMetadata {
}
pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> + '_ {
self.dependencies.iter()
self.dependencies.iter().copied()
}
pub(crate) fn add_dependency(&self, cnum: CrateNum) {
pub(crate) fn add_dependency(&mut self, cnum: CrateNum) {
self.dependencies.push(cnum);
}
pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool {
let mut extern_crate = self.extern_crate.borrow_mut();
let update = Some(new_extern_crate.rank()) > extern_crate.as_ref().map(ExternCrate::rank);
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
let update =
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
if update {
*extern_crate = Some(new_extern_crate);
self.extern_crate = Some(new_extern_crate);
}
update
}
@ -1860,15 +1859,15 @@ impl CrateMetadata {
}
pub(crate) fn dep_kind(&self) -> CrateDepKind {
*self.dep_kind.lock()
self.dep_kind
}
pub(crate) fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) {
self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
pub(crate) fn set_dep_kind(&mut self, dep_kind: CrateDepKind) {
self.dep_kind = dep_kind;
}
pub(crate) fn update_and_private_dep(&self, private_dep: bool) {
self.private_dep.fetch_and(private_dep, Ordering::SeqCst);
pub(crate) fn update_and_private_dep(&mut self, private_dep: bool) {
self.private_dep &= private_dep;
}
pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> {

View file

@ -19,7 +19,7 @@ use rustc_middle::query::LocalCrate;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::util::Providers;
use rustc_session::cstore::CrateStore;
use rustc_session::cstore::{CrateStore, ExternCrate};
use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{ExpnHash, ExpnId};
use rustc_span::symbol::{kw, Symbol};
@ -290,13 +290,7 @@ provide! { tcx, def_id, other, cdata,
cross_crate_inlinable => { cdata.cross_crate_inlinable(def_id.index) }
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
is_private_dep => {
// Parallel compiler needs to synchronize type checking and linting (which use this flag)
// so that they happen strictly crate loading. Otherwise, the full list of available
// impls aren't loaded yet.
use std::sync::atomic::Ordering;
cdata.private_dep.load(Ordering::Acquire)
}
is_private_dep => { cdata.private_dep }
is_panic_runtime => { cdata.root.panic_runtime }
is_compiler_builtins => { cdata.root.compiler_builtins }
has_global_allocator => { cdata.root.has_global_allocator }
@ -305,10 +299,7 @@ provide! { tcx, def_id, other, cdata,
is_profiler_runtime => { cdata.root.profiler_runtime }
required_panic_strategy => { cdata.root.required_panic_strategy }
panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
extern_crate => {
let r = *cdata.extern_crate.lock();
r.map(|c| &*tcx.arena.alloc(c))
}
extern_crate => { cdata.extern_crate.map(|c| &*tcx.arena.alloc(c)) }
is_no_builtins => { cdata.root.no_builtins }
symbol_mangling_version => { cdata.root.symbol_mangling_version }
reachable_non_generics => {
@ -339,10 +330,7 @@ provide! { tcx, def_id, other, cdata,
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
dep_kind => {
let r = *cdata.dep_kind.lock();
r
}
dep_kind => { cdata.dep_kind }
module_children => {
tcx.arena.alloc_from_iter(cdata.get_module_children(def_id.index, tcx.sess))
}
@ -357,8 +345,7 @@ provide! { tcx, def_id, other, cdata,
missing_lang_items => { cdata.get_missing_lang_items(tcx) }
missing_extern_crate_item => {
let r = matches!(*cdata.extern_crate.borrow(), Some(extern_crate) if !extern_crate.is_direct());
r
matches!(cdata.extern_crate, Some(extern_crate) if !extern_crate.is_direct())
}
used_crate_source => { Lrc::clone(&cdata.source) }
@ -581,6 +568,19 @@ impl CStore {
) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}
pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) {
let cmeta = self.get_crate_data_mut(cnum);
if cmeta.update_extern_crate(extern_crate) {
// Propagate the extern crate info to dependencies if it was updated.
let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
let dependencies = std::mem::take(&mut cmeta.dependencies);
for &dep_cnum in &dependencies {
self.update_extern_crate(dep_cnum, extern_crate);
}
self.get_crate_data_mut(cnum).dependencies = dependencies;
}
}
}
impl CrateStore for CStore {

View file

@ -2,10 +2,8 @@ use crate::errors::{FailCreateFileEncoder, FailWriteFile};
use crate::rmeta::*;
use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{join, par_for_each_in, Lrc};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_hir as hir;
@ -1914,14 +1912,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
empty_proc_macro!(self);
let tcx = self.tcx;
let lib_features = tcx.lib_features(LOCAL_CRATE);
self.lazy_array(lib_features.to_vec())
self.lazy_array(lib_features.to_sorted_vec())
}
fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> {
empty_proc_macro!(self);
let tcx = self.tcx;
let implications = tcx.stability_implications(LOCAL_CRATE);
self.lazy_array(implications.iter().map(|(k, v)| (*k, *v)))
let sorted = implications.to_sorted_stable_ord();
self.lazy_array(sorted.into_iter().map(|(k, v)| (*k, *v)))
}
fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
@ -2033,14 +2032,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> {
empty_proc_macro!(self);
let tcx = self.tcx;
let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect();
tcx.with_stable_hashing_context(|mut ctx| {
all_impls.sort_by_cached_key(|&(&simp, _)| {
let mut hasher = StableHasher::new();
simp.hash_stable(&mut ctx, &mut hasher);
hasher.finish::<Fingerprint>()
})
let all_impls = tcx.with_stable_hashing_context(|hcx| {
tcx.crate_inherent_impls(()).incoherent_impls.to_sorted(&hcx, true)
});
let all_impls: Vec<_> = all_impls
.into_iter()
.map(|(&simp, impls)| {

View file

@ -12,7 +12,7 @@ use rustc_attr as attr;
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
@ -459,7 +459,7 @@ define_tables! {
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
proc_macro: Table<DefIndex, MacroKind>,
deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<ty::EarlyBinder<Ty<'static>>>>>,
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,

View file

@ -103,7 +103,7 @@ macro_rules! arena_types {
[] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
[decode] trait_impl_trait_tys:
rustc_data_structures::fx::FxHashMap<
rustc_data_structures::unord::UnordMap<
rustc_hir::def_id::DefId,
rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>>
>,

View file

@ -314,14 +314,14 @@ pub fn struct_lint_level(
}
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
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, "");
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
// 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
// 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
// the compiler. It is therefore not necessary to add any information for the user.

View file

@ -4,7 +4,7 @@ pub mod dependency_format;
pub mod exported_symbols;
pub mod lang_items;
pub mod lib_features {
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordMap;
use rustc_span::{symbol::Symbol, Span};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -16,15 +16,16 @@ pub mod lib_features {
#[derive(HashStable, Debug, Default)]
pub struct LibFeatures {
pub stability: FxHashMap<Symbol, (FeatureStability, Span)>,
pub stability: UnordMap<Symbol, (FeatureStability, Span)>,
}
impl LibFeatures {
pub fn to_vec(&self) -> Vec<(Symbol, FeatureStability)> {
let mut all_features: Vec<_> =
self.stability.iter().map(|(&sym, &(stab, _))| (sym, stab)).collect();
all_features.sort_unstable_by(|(a, _), (b, _)| a.as_str().cmp(b.as_str()));
all_features
pub fn to_sorted_vec(&self) -> Vec<(Symbol, FeatureStability)> {
self.stability
.to_sorted_stable_ord()
.iter()
.map(|(&sym, &(stab, _))| (sym, stab))
.collect()
}
}
}

View file

@ -7,12 +7,11 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use crate::ty::TyCtxt;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordMap;
use rustc_hir as hir;
use rustc_hir::{HirIdMap, Node};
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
use rustc_span::{Span, DUMMY_SP};
use std::fmt;
@ -205,7 +204,7 @@ impl Scope {
pub type ScopeDepth = u32;
/// The region scope tree encodes information about region relationships.
#[derive(Default, Debug)]
#[derive(Default, Debug, HashStable)]
pub struct ScopeTree {
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
@ -306,7 +305,7 @@ pub struct ScopeTree {
/// The reason is that semantically, until the `box` expression returns,
/// the values are still owned by their containing expressions. So
/// we'll see that `&x`.
pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
pub yield_in_scope: UnordMap<Scope, Vec<YieldData>>,
}
/// Identifies the reason that a given expression is an rvalue candidate
@ -404,23 +403,3 @@ impl ScopeTree {
self.yield_in_scope.get(&scope).map(Deref::deref)
}
}
impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ScopeTree {
root_body,
ref parent_map,
ref var_map,
ref destruction_scopes,
ref rvalue_candidates,
ref yield_in_scope,
} = *self;
root_body.hash_stable(hcx, hasher);
parent_map.hash_stable(hcx, hasher);
var_map.hash_stable(hcx, hasher);
destruction_scopes.hash_stable(hcx, hasher);
rvalue_candidates.hash_stable(hcx, hasher);
yield_in_scope.hash_stable(hcx, hasher);
}
}

View file

@ -2,7 +2,7 @@
use crate::ty;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_hir::{ItemLocalId, OwnerId};
@ -51,7 +51,7 @@ pub enum ObjectLifetimeDefault {
pub struct ResolveBoundVars {
/// Maps from every use of a named (not anonymous) lifetime to a
/// `Region` describing how that region is bound
pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, ResolvedArg>>,
pub defs: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, ResolvedArg>>,
pub late_bound_vars: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
pub late_bound_vars: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
}

View file

@ -8,11 +8,11 @@ use rustc_ast::NodeId;
use rustc_attr::{
self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
use rustc_hir::{self as hir, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
@ -61,10 +61,10 @@ impl DeprecationEntry {
pub struct Index {
/// This is mostly a cache, except the stabilities of local items
/// are filled by the annotator.
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
pub stab_map: LocalDefIdMap<Stability>,
pub const_stab_map: LocalDefIdMap<ConstStability>,
pub default_body_stab_map: LocalDefIdMap<DefaultBodyStability>,
pub depr_map: LocalDefIdMap<DeprecationEntry>,
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
/// exists, then this map will have a `impliee -> implier` entry.
@ -77,7 +77,7 @@ pub struct Index {
/// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
/// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
/// unstable feature" error for a feature that was implied.
pub implications: FxHashMap<Symbol, Symbol>,
pub implications: UnordMap<Symbol, Symbol>,
}
impl Index {

View file

@ -2,14 +2,10 @@ use super::{AllocId, AllocRange, Pointer, Scalar};
use crate::error;
use crate::mir::{ConstAlloc, ConstValue};
use crate::query::TyCtxtAt;
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{
struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
IntoDiagnosticArg,
};
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
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`.
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"))]
static_assert_size!(InterpErrorInfo<'_>, 8);

View file

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

View file

@ -55,7 +55,6 @@ pub mod mono;
pub mod patch;
pub mod pretty;
mod query;
pub mod spanview;
mod statement;
mod syntax;
pub mod tcx;
@ -250,6 +249,9 @@ pub struct CoroutineInfo<'tcx> {
/// The yield type of the function, if it is a coroutine.
pub yield_ty: Option<Ty<'tcx>>,
/// The resume type of the function, if it is a coroutine.
pub resume_ty: Option<Ty<'tcx>>,
/// Coroutine drop glue.
pub coroutine_drop: Option<Body<'tcx>>,
@ -385,6 +387,7 @@ impl<'tcx> Body<'tcx> {
coroutine: coroutine_kind.map(|coroutine_kind| {
Box::new(CoroutineInfo {
yield_ty: None,
resume_ty: None,
coroutine_drop: None,
coroutine_layout: None,
coroutine_kind,
@ -551,6 +554,11 @@ impl<'tcx> Body<'tcx> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.yield_ty)
}
#[inline]
pub fn resume_ty(&self) -> Option<Ty<'tcx>> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty)
}
#[inline]
pub fn coroutine_layout(&self) -> Option<&CoroutineLayout<'tcx>> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_layout.as_ref())
@ -720,7 +728,7 @@ pub struct SourceInfo {
pub span: Span,
/// The source scope, keeping track of which bindings can be
/// seen by debuginfo, active lint levels, `unsafe {...}`, etc.
/// seen by debuginfo, active lint levels, etc.
pub scope: SourceScope,
}
@ -942,7 +950,7 @@ pub struct LocalDecl<'tcx> {
/// Extra information about a some locals that's used for diagnostics and for
/// classifying variables into local variables, statics, etc, which is needed e.g.
/// for unsafety checking.
/// for borrow checking.
///
/// Not used for non-StaticRef temporaries, the return place, or anonymous
/// function parameters.

View file

@ -5,7 +5,6 @@ use std::io::{self, Write as _};
use std::path::{Path, PathBuf};
use super::graphviz::write_mir_fn_graphviz;
use super::spanview::write_mir_fn_spanview;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_middle::mir::interpret::{
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)?;
};
}
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

View file

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

View file

@ -996,6 +996,12 @@ macro_rules! super_body {
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
if let Some(resume_ty) = $(& $mutability)? gen.resume_ty {
$self.visit_ty(
resume_ty,
TyContext::ResumeTy(SourceInfo::outermost(span))
);
}
}
for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
@ -1244,6 +1250,8 @@ pub enum TyContext {
YieldTy(SourceInfo),
ResumeTy(SourceInfo),
/// A type found at some location.
Location(Location),
}

View file

@ -57,11 +57,11 @@ use rustc_ast as ast;
use rustc_ast::expand::{allocator::AllocatorKind, StrippedCfgItem};
use rustc_attr as attr;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::unord::UnordSet;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, DocLinkResMap};
@ -264,7 +264,7 @@ rustc_queries! {
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
-> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{
desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
cache_on_disk_if { key.is_local() }
@ -611,7 +611,7 @@ rustc_queries! {
desc { "erasing regions from `{}`", ty }
}
query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> {
query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> {
arena_cache
desc { "getting wasm import module map" }
}
@ -869,15 +869,14 @@ rustc_queries! {
desc { |tcx| "collecting all inherent impls for `{:?}`", key }
}
/// The result of unsafety-checking this `LocalDefId`.
query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
/// The result of unsafety-checking this `LocalDefId` with the old checker.
query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
/// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be
/// used with `-Zthir-unsafeck`.
query thir_check_unsafety(key: LocalDefId) {
/// Unsafety-check this `LocalDefId`.
query check_unsafety(key: LocalDefId) {
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@ -1538,7 +1537,7 @@ rustc_queries! {
/// added or removed in any upstream crate. Instead use the narrower
/// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
/// better, `Instance::upstream_monomorphization()`.
query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<GenericArgsRef<'tcx>, CrateNum>> {
query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> {
arena_cache
desc { "collecting available upstream monomorphizations" }
}
@ -1551,7 +1550,7 @@ rustc_queries! {
/// You likely want to call `Instance::upstream_monomorphization()`
/// instead of invoking this query directly.
query upstream_monomorphizations_for(def_id: DefId)
-> Option<&'tcx FxHashMap<GenericArgsRef<'tcx>, CrateNum>>
-> Option<&'tcx UnordMap<GenericArgsRef<'tcx>, CrateNum>>
{
desc { |tcx|
"collecting available upstream monomorphizations for `{}`",
@ -1663,7 +1662,7 @@ rustc_queries! {
desc { "resolving lifetimes" }
}
query named_variable_map(_: hir::OwnerId) ->
Option<&'tcx FxHashMap<ItemLocalId, ResolvedArg>> {
Option<&'tcx FxIndexMap<ItemLocalId, ResolvedArg>> {
desc { "looking up a named region" }
}
query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
@ -1679,7 +1678,7 @@ rustc_queries! {
separate_provide_extern
}
query late_bound_vars_map(_: hir::OwnerId)
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
-> Option<&'tcx FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
desc { "looking up late bound vars" }
}
@ -1735,7 +1734,7 @@ rustc_queries! {
separate_provide_extern
arena_cache
}
query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> {
query stability_implications(_: CrateNum) -> &'tcx UnordMap<Symbol, Symbol> {
arena_cache
desc { "calculating the implications between `#[unstable]` features defined in a crate" }
separate_provide_extern
@ -1787,7 +1786,7 @@ rustc_queries! {
}
/// Collects the "trimmed", shortest accessible paths to all items for diagnostics.
/// See the [provider docs](`rustc_middle::ty::print::trimmed_def_paths`) for more info.
query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> {
query trimmed_def_paths(_: ()) -> &'tcx DefIdMap<Symbol> {
arena_cache
desc { "calculating trimmed def paths" }
}
@ -2078,7 +2077,7 @@ rustc_queries! {
desc { "computing autoderef types for `{}`", goal.value.value }
}
query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
query supported_target_features(_: CrateNum) -> &'tcx UnordMap<String, Option<Symbol>> {
arena_cache
eval_always
desc { "looking up supported target features" }

View file

@ -2,7 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
use rustc_data_structures::unhash::UnhashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathHash;
use rustc_index::{Idx, IndexVec};
@ -764,7 +764,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId>
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
for &'tcx UnordMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
{
#[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {

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