Restrict From<S> for {D,Subd}iagnosticMessage.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
This commit is contained in:
@@ -175,7 +175,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
}
|
||||
// Generic statics are rejected, but we still reach this case.
|
||||
Err(e) => {
|
||||
tcx.sess.delay_span_bug(span, &e.to_string());
|
||||
tcx.sess.delay_span_bug(span, e.to_string());
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -334,7 +334,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::impl_trait_projections,
|
||||
span,
|
||||
&format!(
|
||||
format!(
|
||||
"`{}` return type cannot contain a projection or `Self` that references \
|
||||
lifetimes from a parent scope",
|
||||
if is_async { "async fn" } else { "impl Trait" },
|
||||
@@ -428,7 +428,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
let ty_err = ty_err.to_string(tcx);
|
||||
tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
|
||||
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -618,11 +618,11 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
E0044,
|
||||
"foreign items may not have {kinds} parameters",
|
||||
)
|
||||
.span_label(item.span, &format!("can't have {kinds} parameters"))
|
||||
.span_label(item.span, format!("can't have {kinds} parameters"))
|
||||
.help(
|
||||
// FIXME: once we start storing spans for type arguments, turn this
|
||||
// into a suggestion.
|
||||
&format!(
|
||||
format!(
|
||||
"replace the {} parameters with concrete {}{}",
|
||||
kinds,
|
||||
kinds_pl,
|
||||
@@ -985,10 +985,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
|
||||
|
||||
err.span_note(
|
||||
tcx.def_span(def_spans[0].0),
|
||||
&format!(
|
||||
"`{}` has a `#[repr(align)]` attribute",
|
||||
tcx.item_name(def_spans[0].0)
|
||||
),
|
||||
format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),
|
||||
);
|
||||
|
||||
if def_spans.len() > 2 {
|
||||
@@ -997,7 +994,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
|
||||
let ident = tcx.item_name(*adt_def);
|
||||
err.span_note(
|
||||
*span,
|
||||
&if first {
|
||||
if first {
|
||||
format!(
|
||||
"`{}` contains a field of type `{}`",
|
||||
tcx.type_of(def.did()).subst_identity(),
|
||||
@@ -1466,10 +1463,10 @@ fn opaque_type_cycle_error(
|
||||
let ty_span = tcx.def_span(def_id);
|
||||
if !seen.contains(&ty_span) {
|
||||
let descr = if ty.is_impl_trait() { "opaque " } else { "" };
|
||||
err.span_label(ty_span, &format!("returning this {descr}type `{ty}`"));
|
||||
err.span_label(ty_span, format!("returning this {descr}type `{ty}`"));
|
||||
seen.insert(ty_span);
|
||||
}
|
||||
err.span_label(sp, &format!("returning here with type `{ty}`"));
|
||||
err.span_label(sp, format!("returning here with type `{ty}`"));
|
||||
}
|
||||
|
||||
for closure_def_id in visitor.closures {
|
||||
|
||||
@@ -1273,7 +1273,7 @@ fn compare_number_of_generics<'tcx>(
|
||||
|
||||
let mut err = tcx.sess.struct_span_err_with_code(
|
||||
spans,
|
||||
&format!(
|
||||
format!(
|
||||
"{} `{}` has {} {kind} parameter{} but its trait \
|
||||
declaration has {} {kind} parameter{}",
|
||||
item_kind,
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
|
||||
let span = tcx.def_span(drop_impl_did);
|
||||
let reported = tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!("should have been rejected by coherence check: {dtor_self_type}"),
|
||||
format!("should have been rejected by coherence check: {dtor_self_type}"),
|
||||
);
|
||||
Err(reported)
|
||||
}
|
||||
@@ -76,15 +76,15 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized");
|
||||
match arg {
|
||||
ty::util::NotUniqueParam::DuplicateParam(arg) => {
|
||||
err.note(&format!("`{arg}` is mentioned multiple times"))
|
||||
err.note(format!("`{arg}` is mentioned multiple times"))
|
||||
}
|
||||
ty::util::NotUniqueParam::NotParam(arg) => {
|
||||
err.note(&format!("`{arg}` is not a generic parameter"))
|
||||
err.note(format!("`{arg}` is not a generic parameter"))
|
||||
}
|
||||
};
|
||||
err.span_note(
|
||||
item_span,
|
||||
&format!(
|
||||
format!(
|
||||
"use the same sequence of generic lifetime, type and const parameters \
|
||||
as the {self_descr} definition",
|
||||
),
|
||||
|
||||
@@ -547,14 +547,14 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
|
||||
Err(_) => {
|
||||
let msg =
|
||||
format!("unrecognized platform-specific intrinsic function: `{name}`");
|
||||
tcx.sess.struct_span_err(it.span, &msg).emit();
|
||||
tcx.sess.struct_span_err(it.span, msg).emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
|
||||
tcx.sess.struct_span_err(it.span, &msg).emit();
|
||||
tcx.sess.struct_span_err(it.span, msg).emit();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,7 +130,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
_ => None,
|
||||
};
|
||||
let Some(asm_ty) = asm_ty else {
|
||||
let msg = &format!("cannot use value of type `{ty}` for inline assembly");
|
||||
let msg = format!("cannot use value of type `{ty}` for inline assembly");
|
||||
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
||||
err.note(
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
@@ -145,7 +145,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
|
||||
let msg = "arguments for inline assembly must be copyable";
|
||||
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
||||
err.note(&format!("`{ty}` does not implement the Copy trait"));
|
||||
err.note(format!("`{ty}` does not implement the Copy trait"));
|
||||
err.emit();
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);
|
||||
|
||||
let in_expr_ty = (self.get_operand_ty)(in_expr);
|
||||
err.span_label(in_expr.span, &format!("type `{in_expr_ty}`"));
|
||||
err.span_label(expr.span, &format!("type `{ty}`"));
|
||||
err.span_label(in_expr.span, format!("type `{in_expr_ty}`"));
|
||||
err.span_label(expr.span, format!("type `{ty}`"));
|
||||
err.note(
|
||||
"asm inout arguments must have the same type, \
|
||||
unless they are both pointers or integers of the same size",
|
||||
@@ -184,17 +184,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
let reg_class = reg.reg_class();
|
||||
let supported_tys = reg_class.supported_types(asm_arch);
|
||||
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
|
||||
let msg = &format!("type `{ty}` cannot be used with this register class");
|
||||
let msg = format!("type `{ty}` cannot be used with this register class");
|
||||
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
||||
let supported_tys: Vec<_> =
|
||||
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
|
||||
err.note(&format!(
|
||||
err.note(format!(
|
||||
"register class `{}` supports these types: {}",
|
||||
reg_class.name(),
|
||||
supported_tys.join(", "),
|
||||
));
|
||||
if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
|
||||
err.help(&format!(
|
||||
err.help(format!(
|
||||
"consider using the `{}` register class instead",
|
||||
suggest.name()
|
||||
));
|
||||
@@ -215,9 +215,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
// register class is usable at all.
|
||||
if let Some(feature) = feature {
|
||||
if !target_features.contains(feature) {
|
||||
let msg = &format!("`{}` target feature is not enabled", feature);
|
||||
let msg = format!("`{}` target feature is not enabled", feature);
|
||||
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
||||
err.note(&format!(
|
||||
err.note(format!(
|
||||
"this is required to use type `{}` with register class `{}`",
|
||||
ty,
|
||||
reg_class.name(),
|
||||
@@ -252,10 +252,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
"formatting may not be suitable for sub-register argument",
|
||||
|lint| {
|
||||
lint.span_label(expr.span, "for this argument");
|
||||
lint.help(&format!(
|
||||
lint.help(format!(
|
||||
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
|
||||
));
|
||||
lint.help(&format!(
|
||||
lint.help(format!(
|
||||
"or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
|
||||
));
|
||||
lint
|
||||
@@ -301,7 +301,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
op.is_clobber(),
|
||||
) {
|
||||
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
|
||||
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
|
||||
self.tcx.sess.struct_span_err(*op_sp, msg).emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
reg_class.name(),
|
||||
feature
|
||||
);
|
||||
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
|
||||
self.tcx.sess.struct_span_err(*op_sp, msg).emit();
|
||||
// register isn't enabled, don't do more checks
|
||||
continue;
|
||||
}
|
||||
@@ -354,7 +354,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
.intersperse(", ")
|
||||
.collect::<String>(),
|
||||
);
|
||||
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
|
||||
self.tcx.sess.struct_span_err(*op_sp, msg).emit();
|
||||
// register isn't enabled, don't do more checks
|
||||
continue;
|
||||
}
|
||||
@@ -436,7 +436,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand");
|
||||
err.span_label(
|
||||
self.tcx.def_span(anon_const.def_id),
|
||||
&format!("is {} `{}`", ty.kind().article(), ty),
|
||||
format!("is {} `{}`", ty.kind().article(), ty),
|
||||
);
|
||||
err.help("`sym` operands must refer to either a function or a static");
|
||||
err.emit();
|
||||
|
||||
@@ -445,7 +445,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
||||
let plural = pluralize!(unsatisfied_bounds.len());
|
||||
let mut err = tcx.sess.struct_span_err(
|
||||
gat_item_hir.span,
|
||||
&format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
|
||||
format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
|
||||
);
|
||||
|
||||
let suggestion = format!(
|
||||
@@ -455,14 +455,14 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
||||
);
|
||||
err.span_suggestion(
|
||||
gat_item_hir.generics.tail_span_for_predicate_suggestion(),
|
||||
&format!("add the required where clause{plural}"),
|
||||
format!("add the required where clause{plural}"),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
let bound =
|
||||
if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" };
|
||||
err.note(&format!(
|
||||
err.note(format!(
|
||||
"{} currently required to ensure that impls have maximum flexibility",
|
||||
bound
|
||||
));
|
||||
@@ -916,14 +916,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
||||
if is_ptr {
|
||||
tcx.sess.span_err(
|
||||
hir_ty.span,
|
||||
&format!(
|
||||
format!(
|
||||
"using {unsupported_type} as const generic parameters is forbidden",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
let mut err = tcx.sess.struct_span_err(
|
||||
hir_ty.span,
|
||||
&format!(
|
||||
format!(
|
||||
"{unsupported_type} is forbidden as the type of a const generic parameter",
|
||||
),
|
||||
);
|
||||
@@ -1029,7 +1029,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
|
||||
let ty = tcx.erase_regions(ty);
|
||||
if ty.has_infer() {
|
||||
tcx.sess
|
||||
.delay_span_bug(item.span, &format!("inference variables in {:?}", ty));
|
||||
.delay_span_bug(item.span, format!("inference variables in {:?}", ty));
|
||||
// Just treat unresolved type expression as if it needs drop.
|
||||
true
|
||||
} else {
|
||||
@@ -1651,7 +1651,7 @@ fn check_method_receiver<'tcx>(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::arbitrary_self_types,
|
||||
span,
|
||||
&format!(
|
||||
format!(
|
||||
"`{receiver_ty}` cannot be used as the type of `self` without \
|
||||
the `arbitrary_self_types` feature",
|
||||
),
|
||||
@@ -1874,10 +1874,10 @@ fn report_bivariance(
|
||||
} else {
|
||||
format!("consider removing `{param_name}` or referring to it in a field")
|
||||
};
|
||||
err.help(&msg);
|
||||
err.help(msg);
|
||||
|
||||
if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
|
||||
err.help(&format!(
|
||||
err.help(format!(
|
||||
"if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
|
||||
param_name
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user