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:
Nicholas Nethercote
2023-04-20 13:26:58 +10:00
parent a368898de7
commit 6b62f37402
177 changed files with 791 additions and 787 deletions

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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",
),

View File

@@ -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;
}
};

View File

@@ -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();

View File

@@ -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
));