Merge from rustc
This commit is contained in:
commit
55df622b35
81 changed files with 692 additions and 427 deletions
|
|
@ -44,6 +44,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::AArch64
|
||||
| asm::InlineAsmArch::RiscV32
|
||||
| asm::InlineAsmArch::RiscV64
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch {
|
||||
feature_err(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>(
|
|||
reason = "diagnostic message is specified by user"
|
||||
)]
|
||||
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
|
||||
cx.span_err(sp, var.as_str());
|
||||
cx.span_err(sp, var.to_string());
|
||||
|
||||
DummyResult::any(sp)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ pub fn expand_deriving_clone(
|
|||
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
|
||||
}
|
||||
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::Clone),
|
||||
|
|
@ -82,7 +81,7 @@ pub fn expand_deriving_clone(
|
|||
explicit_self: true,
|
||||
nonself_args: Vec::new(),
|
||||
ret_ty: Self_,
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: substructure,
|
||||
}],
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@ pub fn expand_deriving_eq(
|
|||
is_const: bool,
|
||||
) {
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
let attrs = thin_vec![
|
||||
cx.attr_word(sym::inline, span),
|
||||
cx.attr_nested_word(sym::doc, sym::hidden, span),
|
||||
cx.attr_word(sym::no_coverage, span)
|
||||
];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Eq),
|
||||
|
|
@ -36,7 +31,11 @@ pub fn expand_deriving_eq(
|
|||
explicit_self: true,
|
||||
nonself_args: vec![],
|
||||
ret_ty: Unit,
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![
|
||||
cx.attr_word(sym::inline, span),
|
||||
cx.attr_nested_word(sym::doc, sym::hidden, span),
|
||||
cx.attr_word(sym::no_coverage, span)
|
||||
],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
cs_total_eq_assert(a, b, c)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ pub fn expand_deriving_ord(
|
|||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Ord),
|
||||
|
|
@ -29,7 +28,7 @@ pub fn expand_deriving_ord(
|
|||
explicit_self: true,
|
||||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_std!(cmp::Ordering)),
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
|
||||
}],
|
||||
|
|
|
|||
|
|
@ -82,14 +82,13 @@ pub fn expand_deriving_partial_eq(
|
|||
|
||||
// No need to generate `ne`, the default suffices, and not generating it is
|
||||
// faster.
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
let methods = vec![MethodDef {
|
||||
name: sym::eq,
|
||||
generics: Bounds::empty(),
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_local!(bool)),
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ pub fn expand_deriving_partial_ord(
|
|||
let ret_ty =
|
||||
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
|
||||
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
|
||||
// Order in which to perform matching
|
||||
let tag_then_data = if let Annotatable::Item(item) = item
|
||||
&& let ItemKind::Enum(def, _) = &item.kind {
|
||||
|
|
@ -48,7 +46,7 @@ pub fn expand_deriving_partial_ord(
|
|||
explicit_self: true,
|
||||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty,
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
|
||||
cs_partial_cmp(cx, span, substr, tag_then_data)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ pub fn expand_deriving_default(
|
|||
) {
|
||||
item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
|
||||
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new(vec![kw::Default, sym::Default]),
|
||||
|
|
@ -34,7 +33,7 @@ pub fn expand_deriving_default(
|
|||
explicit_self: false,
|
||||
nonself_args: Vec::new(),
|
||||
ret_ty: Self_,
|
||||
attributes: attrs,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
|
||||
match substr.fields {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_std, pathvec_std};
|
||||
use rustc_ast::{AttrVec, MetaItem, Mutability};
|
||||
use rustc_ast::{MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -33,7 +33,7 @@ pub fn expand_deriving_hash(
|
|||
explicit_self: true,
|
||||
nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
|
||||
ret_ty: Unit,
|
||||
attributes: AttrVec::new(),
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
hash_substructure(a, b, c)
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
|
|||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
)]
|
||||
handler.struct_diagnostic(msg.as_str())
|
||||
handler.struct_diagnostic(msg.to_string())
|
||||
} else {
|
||||
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use rustc_session::utils::NativeLibKind;
|
|||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
|
||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
||||
|
||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
||||
|
|
@ -893,7 +893,7 @@ fn link_natively<'a>(
|
|||
linker_path: &linker_path,
|
||||
exit_status: prog.status,
|
||||
command: &cmd,
|
||||
escaped_output: &escaped_output,
|
||||
escaped_output,
|
||||
};
|
||||
sess.diagnostic().emit_err(err);
|
||||
// If MSVC's `link.exe` was expected but the return code
|
||||
|
|
@ -1302,44 +1302,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
|
||||
sess.emit_fatal(errors::LinkerFileStem);
|
||||
});
|
||||
|
||||
// Remove any version postfix.
|
||||
let stem = stem
|
||||
.rsplit_once('-')
|
||||
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
||||
.unwrap_or(stem);
|
||||
|
||||
// GCC/Clang can have an optional target prefix.
|
||||
let flavor = if stem == "emcc" {
|
||||
LinkerFlavor::EmCc
|
||||
} else if stem == "gcc"
|
||||
|| stem.ends_with("-gcc")
|
||||
|| stem == "g++"
|
||||
|| stem.ends_with("-g++")
|
||||
|| stem == "clang"
|
||||
|| stem.ends_with("-clang")
|
||||
|| stem == "clang++"
|
||||
|| stem.ends_with("-clang++")
|
||||
{
|
||||
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
|
||||
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
|
||||
LinkerFlavor::WasmLld(Cc::No)
|
||||
} else if stem == "ld" || stem.ends_with("-ld") {
|
||||
LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target)
|
||||
} else if stem == "ld.lld" {
|
||||
LinkerFlavor::Gnu(Cc::No, Lld::Yes)
|
||||
} else if stem == "link" {
|
||||
LinkerFlavor::Msvc(Lld::No)
|
||||
} else if stem == "lld-link" {
|
||||
LinkerFlavor::Msvc(Lld::Yes)
|
||||
} else if stem == "lld" || stem == "rust-lld" {
|
||||
let lld_flavor = sess.target.linker_flavor.lld_flavor();
|
||||
LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target)
|
||||
} else {
|
||||
// fall back to the value in the target spec
|
||||
sess.target.linker_flavor
|
||||
};
|
||||
|
||||
let flavor = sess.target.linker_flavor.with_linker_hints(stem);
|
||||
Some((linker, flavor))
|
||||
}
|
||||
(None, None) => None,
|
||||
|
|
@ -1349,7 +1312,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
// linker and linker flavor specified via command line have precedence over what the target
|
||||
// specification specifies
|
||||
let linker_flavor =
|
||||
sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target));
|
||||
sess.opts.cg.linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor));
|
||||
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1800,7 +1800,7 @@ impl SharedEmitterMain {
|
|||
handler.emit_diagnostic(&mut d);
|
||||
}
|
||||
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
|
||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
|
||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
|
||||
|
||||
let mut err = match level {
|
||||
Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(),
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ pub struct LinkingFailed<'a> {
|
|||
pub linker_path: &'a PathBuf,
|
||||
pub exit_status: ExitStatus,
|
||||
pub command: &'a Command,
|
||||
pub escaped_output: &'a str,
|
||||
pub escaped_output: String,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for LinkingFailed<'_> {
|
||||
|
|
@ -345,11 +345,13 @@ impl IntoDiagnostic<'_> for LinkingFailed<'_> {
|
|||
diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
|
||||
diag.set_arg("exit_status", format!("{}", self.exit_status));
|
||||
|
||||
diag.note(format!("{:?}", self.command)).note(self.escaped_output);
|
||||
let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
|
||||
|
||||
diag.note(format!("{:?}", self.command)).note(self.escaped_output.to_string());
|
||||
|
||||
// Trying to match an error from OS linkers
|
||||
// which by now we have no way to translate.
|
||||
if self.escaped_output.contains("undefined reference to") {
|
||||
if contains_undefined_ref {
|
||||
diag.note(fluent::codegen_ssa_extern_funcs_not_found)
|
||||
.note(fluent::codegen_ssa_specify_libraries_to_link)
|
||||
.note(fluent::codegen_ssa_use_cargo_directive);
|
||||
|
|
|
|||
|
|
@ -1258,7 +1258,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
|
|||
if let Some(msg) = info.payload().downcast_ref::<String>() {
|
||||
if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
|
||||
// the error code is already going to be reported when the panic unwinds up the stack
|
||||
let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str());
|
||||
let _ = early_error_no_abort(ErrorOutputType::default(), msg.clone());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Unsafe code was used outside of an unsafe function or block.
|
||||
Unsafe code was used outside of an unsafe block.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -30,4 +30,21 @@ fn main() {
|
|||
|
||||
See the [unsafe section][unsafe-section] of the Book for more details.
|
||||
|
||||
#### Unsafe code in functions
|
||||
|
||||
Unsafe code is currently accepted in unsafe functions, but that is being phased
|
||||
out in favor of requiring unsafe blocks here too.
|
||||
|
||||
```
|
||||
unsafe fn f() { return; }
|
||||
|
||||
unsafe fn g() {
|
||||
f(); // Is accepted, but no longer recommended
|
||||
unsafe { f(); } // Recommended way to write this
|
||||
}
|
||||
```
|
||||
|
||||
Linting against this is controlled via the `unsafe_op_in_unsafe_fn` lint, which
|
||||
is `allow` by default but will be upgraded to `warn` in a future edition.
|
||||
|
||||
[unsafe-section]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
|
|
|||
|
|
@ -263,8 +263,7 @@ type FluentId = Cow<'static, str>;
|
|||
#[rustc_diagnostic_item = "SubdiagnosticMessage"]
|
||||
pub enum SubdiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
Str(Cow<'static, str>),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
|
|
@ -275,8 +274,7 @@ pub enum SubdiagnosticMessage {
|
|||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
Eager(Cow<'static, str>),
|
||||
/// Identifier of a Fluent message. Instances of this variant are generated by the
|
||||
/// `Subdiagnostic` derive.
|
||||
FluentIdentifier(FluentId),
|
||||
|
|
@ -290,17 +288,17 @@ pub enum SubdiagnosticMessage {
|
|||
|
||||
impl From<String> for SubdiagnosticMessage {
|
||||
fn from(s: String) -> Self {
|
||||
SubdiagnosticMessage::Str(s)
|
||||
SubdiagnosticMessage::Str(Cow::Owned(s))
|
||||
}
|
||||
}
|
||||
impl<'a> From<&'a str> for SubdiagnosticMessage {
|
||||
fn from(s: &'a str) -> Self {
|
||||
SubdiagnosticMessage::Str(s.to_string())
|
||||
impl From<&'static str> for SubdiagnosticMessage {
|
||||
fn from(s: &'static str) -> Self {
|
||||
SubdiagnosticMessage::Str(Cow::Borrowed(s))
|
||||
}
|
||||
}
|
||||
impl From<Cow<'static, str>> for SubdiagnosticMessage {
|
||||
fn from(s: Cow<'static, str>) -> Self {
|
||||
SubdiagnosticMessage::Str(s.to_string())
|
||||
SubdiagnosticMessage::Str(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,8 +310,7 @@ impl From<Cow<'static, str>> for SubdiagnosticMessage {
|
|||
#[rustc_diagnostic_item = "DiagnosticMessage"]
|
||||
pub enum DiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
Str(Cow<'static, str>),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
|
|
@ -324,8 +321,7 @@ pub enum DiagnosticMessage {
|
|||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
Eager(Cow<'static, str>),
|
||||
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
|
||||
/// message.
|
||||
///
|
||||
|
|
@ -363,17 +359,17 @@ impl DiagnosticMessage {
|
|||
|
||||
impl From<String> for DiagnosticMessage {
|
||||
fn from(s: String) -> Self {
|
||||
DiagnosticMessage::Str(s)
|
||||
DiagnosticMessage::Str(Cow::Owned(s))
|
||||
}
|
||||
}
|
||||
impl<'a> From<&'a str> for DiagnosticMessage {
|
||||
fn from(s: &'a str) -> Self {
|
||||
DiagnosticMessage::Str(s.to_string())
|
||||
impl From<&'static str> for DiagnosticMessage {
|
||||
fn from(s: &'static str) -> Self {
|
||||
DiagnosticMessage::Str(Cow::Borrowed(s))
|
||||
}
|
||||
}
|
||||
impl From<Cow<'static, str>> for DiagnosticMessage {
|
||||
fn from(s: Cow<'static, str>) -> Self {
|
||||
DiagnosticMessage::Str(s.to_string())
|
||||
DiagnosticMessage::Str(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -352,14 +352,9 @@ impl Diagnostic {
|
|||
|
||||
/// Labels all the given spans with the provided label.
|
||||
/// See [`Self::span_label()`] for more information.
|
||||
pub fn span_labels(
|
||||
&mut self,
|
||||
spans: impl IntoIterator<Item = Span>,
|
||||
label: impl AsRef<str>,
|
||||
) -> &mut Self {
|
||||
let label = label.as_ref();
|
||||
pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
|
||||
for span in spans {
|
||||
self.span_label(span, label);
|
||||
self.span_label(span, label.to_string());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
|
@ -394,17 +389,18 @@ impl Diagnostic {
|
|||
expected: DiagnosticStyledString,
|
||||
found: DiagnosticStyledString,
|
||||
) -> &mut Self {
|
||||
let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)];
|
||||
let mut msg: Vec<_> =
|
||||
vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)];
|
||||
msg.extend(expected.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
|
||||
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
|
||||
}));
|
||||
msg.push(("` to type '", Style::NoStyle));
|
||||
msg.push((Cow::from("` to type '"), Style::NoStyle));
|
||||
msg.extend(found.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
|
||||
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
|
||||
}));
|
||||
msg.push(("`", Style::NoStyle));
|
||||
msg.push((Cow::from("`"), Style::NoStyle));
|
||||
|
||||
// For now, just attach these as notes
|
||||
self.highlighted_note(msg);
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
}
|
||||
|
||||
// Take the `Diagnostic` by replacing it with a dummy.
|
||||
let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::Str("".to_string()));
|
||||
let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::from(""));
|
||||
let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy);
|
||||
|
||||
// Disable the ICE on `Drop`.
|
||||
|
|
@ -627,7 +627,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
pub fn span_labels(
|
||||
&mut self,
|
||||
spans: impl IntoIterator<Item = Span>,
|
||||
label: impl AsRef<str>,
|
||||
label: &str,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn note_expected_found(
|
||||
|
|
@ -781,8 +781,8 @@ impl Drop for DiagnosticBuilderInner<'_> {
|
|||
if !panicking() {
|
||||
handler.emit_diagnostic(&mut Diagnostic::new(
|
||||
Level::Bug,
|
||||
DiagnosticMessage::Str(
|
||||
"the following error was constructed but not emitted".to_string(),
|
||||
DiagnosticMessage::from(
|
||||
"the following error was constructed but not emitted",
|
||||
),
|
||||
));
|
||||
handler.emit_diagnostic(&mut self.diagnostic);
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ pub trait Emitter: Translate {
|
|||
|
||||
children.push(SubDiagnostic {
|
||||
level: Level::Note,
|
||||
message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)],
|
||||
message: vec![(DiagnosticMessage::from(msg), Style::NoStyle)],
|
||||
span: MultiSpan::new(),
|
||||
render_span: None,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ impl Handler {
|
|||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
SubdiagnosticMessage::Eager(self.eagerly_translate_to_string(message, args))
|
||||
SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
|
|
@ -1450,14 +1450,14 @@ impl HandlerInner {
|
|||
self.emit_stashed_diagnostics();
|
||||
|
||||
let warnings = match self.deduplicated_warn_count {
|
||||
0 => String::new(),
|
||||
1 => "1 warning emitted".to_string(),
|
||||
count => format!("{count} warnings emitted"),
|
||||
0 => Cow::from(""),
|
||||
1 => Cow::from("1 warning emitted"),
|
||||
count => Cow::from(format!("{count} warnings emitted")),
|
||||
};
|
||||
let errors = match self.deduplicated_err_count {
|
||||
0 => String::new(),
|
||||
1 => "aborting due to previous error".to_string(),
|
||||
count => format!("aborting due to {count} previous errors"),
|
||||
0 => Cow::from(""),
|
||||
1 => Cow::from("aborting due to previous error"),
|
||||
count => Cow::from(format!("aborting due to {count} previous errors")),
|
||||
};
|
||||
if self.treat_err_as_bug() {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1154,7 +1154,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
// Fixme: does this result in errors?
|
||||
self.expansions.clear();
|
||||
}
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
pub fn bug(&self, msg: &'static str) -> ! {
|
||||
self.sess.parse_sess.span_diagnostic.bug(msg);
|
||||
}
|
||||
pub fn trace_macros(&self) -> bool {
|
||||
|
|
@ -1224,7 +1224,7 @@ pub fn resolve_path(
|
|||
pub fn expr_to_spanned_string<'a>(
|
||||
cx: &'a mut ExtCtxt<'_>,
|
||||
expr: P<ast::Expr>,
|
||||
err_msg: &str,
|
||||
err_msg: &'static str,
|
||||
) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorGuaranteed>, bool)>> {
|
||||
// Perform eager expansion on the expression.
|
||||
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
||||
|
|
@ -1262,7 +1262,7 @@ pub fn expr_to_spanned_string<'a>(
|
|||
pub fn expr_to_string(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
expr: P<ast::Expr>,
|
||||
err_msg: &str,
|
||||
err_msg: &'static str,
|
||||
) -> Option<(Symbol, ast::StrStyle)> {
|
||||
expr_to_spanned_string(cx, expr, err_msg)
|
||||
.map_err(|err| {
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
|
|||
}
|
||||
Error(err_sp, msg) => {
|
||||
let span = err_sp.substitute_dummy(self.root_span);
|
||||
self.cx.struct_span_err(span, msg.as_str()).emit();
|
||||
self.cx.struct_span_err(span, msg.clone()).emit();
|
||||
self.result = Some(DummyResult::any(span));
|
||||
}
|
||||
ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
|
||||
|
|
@ -222,7 +222,7 @@ pub(super) fn emit_frag_parse_err(
|
|||
{
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
DiagnosticMessage::Str(format!(
|
||||
DiagnosticMessage::from(format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
message.replace(", found `<eof>`", ""),
|
||||
)),
|
||||
|
|
@ -313,9 +313,9 @@ pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: S
|
|||
|
||||
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
||||
/// other tokens, this is "unexpected token...".
|
||||
pub(super) fn parse_failure_msg(tok: &Token) -> String {
|
||||
pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> {
|
||||
match tok.kind {
|
||||
token::Eof => "unexpected end of macro invocation".to_string(),
|
||||
_ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),),
|
||||
token::Eof => Cow::from("unexpected end of macro invocation"),
|
||||
_ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
|||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
|
||||
/// Checks that a method from an impl conforms to the signature of
|
||||
|
|
@ -684,7 +685,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
&cause,
|
||||
hir.get_if_local(impl_m.def_id)
|
||||
.and_then(|node| node.fn_decl())
|
||||
.map(|decl| (decl.output.span(), "return type in trait".to_owned())),
|
||||
.map(|decl| (decl.output.span(), Cow::from("return type in trait"))),
|
||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||
expected: trait_return_ty.into(),
|
||||
found: impl_return_ty.into(),
|
||||
|
|
@ -963,7 +964,7 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
|
||||
trait_err_span.map(|sp| (sp, Cow::from("type in trait"))),
|
||||
Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
|
||||
terr,
|
||||
false,
|
||||
|
|
@ -1731,7 +1732,7 @@ pub(super) fn compare_impl_const_raw(
|
|||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_c_span.map(|span| (span, "type in trait".to_owned())),
|
||||
trait_c_span.map(|span| (span, Cow::from("type in trait"))),
|
||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
||||
expected: trait_ty.into(),
|
||||
found: impl_ty.into(),
|
||||
|
|
|
|||
|
|
@ -121,10 +121,11 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
|
|||
if has_safe_attr != is_in_list {
|
||||
tcx.sess.struct_span_err(
|
||||
tcx.def_span(intrinsic_id),
|
||||
DiagnosticMessage::Str(format!(
|
||||
"intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
|
||||
tcx.item_name(intrinsic_id)
|
||||
))).emit();
|
||||
DiagnosticMessage::from(format!(
|
||||
"intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
|
||||
tcx.item_name(intrinsic_id)
|
||||
)
|
||||
)).emit();
|
||||
}
|
||||
|
||||
is_in_list
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
|
||||
self.fcx
|
||||
.need_type_info_err_in_generator(self.kind, span, unresolved_term)
|
||||
.span_note(yield_data.span, &*note)
|
||||
.span_note(yield_data.span, note)
|
||||
.emit();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -686,7 +686,7 @@ fn check_must_not_suspend_def(
|
|||
// Add optional reason note
|
||||
if let Some(note) = attr.value_str() {
|
||||
// FIXME(guswynn): consider formatting this better
|
||||
lint.span_note(data.source_span, note.as_str());
|
||||
lint.span_note(data.source_span, note.to_string());
|
||||
}
|
||||
|
||||
// Add some quick suggestions on what to do
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::borrow::Cow;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::path::PathBuf;
|
||||
use std::{cmp, fmt, iter};
|
||||
|
|
@ -1470,7 +1471,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
secondary_span: Option<(Span, String)>,
|
||||
secondary_span: Option<(Span, Cow<'static, str>)>,
|
||||
mut values: Option<ValuePairs<'tcx>>,
|
||||
terr: TypeError<'tcx>,
|
||||
swap_secondary_and_primary: bool,
|
||||
|
|
@ -1629,7 +1630,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let mut label_or_note = |span: Span, msg: &str| {
|
||||
let mut label_or_note = |span: Span, msg: Cow<'static, str>| {
|
||||
if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
|
||||
diag.span_label(span, msg);
|
||||
} else {
|
||||
|
|
@ -1643,15 +1644,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
..
|
||||
})) = values
|
||||
{
|
||||
format!("expected this to be `{}`", expected)
|
||||
Cow::from(format!("expected this to be `{}`", expected))
|
||||
} else {
|
||||
terr.to_string(self.tcx).to_string()
|
||||
terr.to_string(self.tcx)
|
||||
};
|
||||
label_or_note(sp, &terr);
|
||||
label_or_note(span, &msg);
|
||||
label_or_note(sp, terr);
|
||||
label_or_note(span, msg);
|
||||
} else {
|
||||
label_or_note(span, &terr.to_string(self.tcx));
|
||||
label_or_note(sp, &msg);
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
label_or_note(sp, msg);
|
||||
}
|
||||
} else {
|
||||
if let Some(values) = values
|
||||
|
|
@ -1663,12 +1664,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
|
||||
let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
|
||||
if expected == found {
|
||||
label_or_note(span, &terr.to_string(self.tcx));
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
} else {
|
||||
label_or_note(span, &format!("expected {expected}, found {found}"));
|
||||
label_or_note(span, Cow::from(format!("expected {expected}, found {found}")));
|
||||
}
|
||||
} else {
|
||||
label_or_note(span, &terr.to_string(self.tcx));
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,13 +234,13 @@ impl<T> Trait<T> for X {
|
|||
);
|
||||
}
|
||||
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
let msg = format!(
|
||||
let msg = || format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.found, values.expected,
|
||||
);
|
||||
if !(self.suggest_constraining_opaque_associated_type(
|
||||
diag,
|
||||
&msg,
|
||||
msg,
|
||||
proj_ty,
|
||||
values.expected,
|
||||
) || self.suggest_constraint(
|
||||
|
|
@ -250,7 +250,7 @@ impl<T> Trait<T> for X {
|
|||
proj_ty,
|
||||
values.expected,
|
||||
)) {
|
||||
diag.help(msg);
|
||||
diag.help(msg());
|
||||
diag.note(
|
||||
"for more information, visit \
|
||||
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
||||
|
|
@ -308,7 +308,7 @@ impl<T> Trait<T> for X {
|
|||
fn suggest_constraint(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
msg: &str,
|
||||
msg: impl Fn() -> String,
|
||||
body_owner_def_id: DefId,
|
||||
proj_ty: &ty::AliasTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
@ -340,7 +340,7 @@ impl<T> Trait<T> for X {
|
|||
assoc,
|
||||
assoc_substs,
|
||||
ty,
|
||||
msg,
|
||||
&msg,
|
||||
false,
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -374,10 +374,12 @@ impl<T> Trait<T> for X {
|
|||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let msg = format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.expected, values.found
|
||||
);
|
||||
let msg = || {
|
||||
format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.expected, values.found
|
||||
)
|
||||
};
|
||||
let body_owner = tcx.hir().get_if_local(body_owner_def_id);
|
||||
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
|
||||
|
||||
|
|
@ -428,10 +430,11 @@ impl<T> Trait<T> for X {
|
|||
if callable_scope {
|
||||
diag.help(format!(
|
||||
"{} or calling a method that returns `{}`",
|
||||
msg, values.expected
|
||||
msg(),
|
||||
values.expected
|
||||
));
|
||||
} else {
|
||||
diag.help(msg);
|
||||
diag.help(msg());
|
||||
}
|
||||
diag.note(
|
||||
"for more information, visit \
|
||||
|
|
@ -463,7 +466,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
fn suggest_constraining_opaque_associated_type(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
msg: &str,
|
||||
msg: impl Fn() -> String,
|
||||
proj_ty: &ty::AliasTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
|
|
@ -635,7 +638,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
assoc: ty::AssocItem,
|
||||
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||
ty: Ty<'tcx>,
|
||||
msg: &str,
|
||||
msg: impl Fn() -> String,
|
||||
is_bound_surely_present: bool,
|
||||
) -> bool {
|
||||
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
|
||||
|
|
@ -678,7 +681,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
assoc: ty::AssocItem,
|
||||
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||
ty: Ty<'tcx>,
|
||||
msg: &str,
|
||||
msg: impl Fn() -> String,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
|
||||
|
|
@ -693,7 +696,7 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
let item_args = self.format_generic_args(assoc_substs);
|
||||
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty))
|
||||
};
|
||||
diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
||||
diag.span_suggestion_verbose(span, msg(), sugg, MaybeIncorrect);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl AddToDiagnostic for OverruledAttributeSub {
|
|||
diag.span_label(span, fluent::lint_node_source);
|
||||
if let Some(rationale) = reason {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(rationale.as_str());
|
||||
diag.note(rationale.to_string());
|
||||
}
|
||||
}
|
||||
OverruledAttributeSub::CommandLineSource => {
|
||||
|
|
|
|||
|
|
@ -1527,7 +1527,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
|
|||
diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
|
||||
// check for #[must_use = "..."]
|
||||
if let Some(note) = self.note {
|
||||
diag.note(note.as_str());
|
||||
diag.note(note.to_string());
|
||||
}
|
||||
if let Some(sugg) = self.suggestion {
|
||||
diag.subdiagnostic(sugg);
|
||||
|
|
|
|||
|
|
@ -666,31 +666,30 @@ impl<'a> CrateLocator<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let root = metadata.get_root();
|
||||
if root.is_proc_macro_crate() != self.is_proc_macro {
|
||||
let header = metadata.get_header();
|
||||
if header.is_proc_macro_crate != self.is_proc_macro {
|
||||
info!(
|
||||
"Rejecting via proc macro: expected {} got {}",
|
||||
self.is_proc_macro,
|
||||
root.is_proc_macro_crate(),
|
||||
self.is_proc_macro, header.is_proc_macro_crate,
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.exact_paths.is_empty() && self.crate_name != root.name() {
|
||||
if self.exact_paths.is_empty() && self.crate_name != header.name {
|
||||
info!("Rejecting via crate name");
|
||||
return None;
|
||||
}
|
||||
|
||||
if root.triple() != &self.triple {
|
||||
info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple());
|
||||
if header.triple != self.triple {
|
||||
info!("Rejecting via crate triple: expected {} got {}", self.triple, header.triple);
|
||||
self.crate_rejections.via_triple.push(CrateMismatch {
|
||||
path: libpath.to_path_buf(),
|
||||
got: root.triple().to_string(),
|
||||
got: header.triple.to_string(),
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
let hash = root.hash();
|
||||
let hash = header.hash;
|
||||
if let Some(expected_hash) = self.hash {
|
||||
if hash != expected_hash {
|
||||
info!("Rejecting via hash: expected {} got {}", expected_hash, hash);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub(crate) struct CrateMetadata {
|
|||
blob: MetadataBlob,
|
||||
|
||||
// --- Some data pre-decoded from the metadata blob, usually for performance ---
|
||||
/// Data about the top-level items in a crate, as well as various crate-level metadata.
|
||||
root: CrateRoot,
|
||||
/// Trait impl data.
|
||||
/// FIXME: Used only from queries and can use query cache,
|
||||
|
|
@ -449,7 +450,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
|
|||
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`.");
|
||||
};
|
||||
|
||||
let cname = cdata.root.name;
|
||||
let cname = cdata.root.name();
|
||||
rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| {
|
||||
debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
|
||||
cdata
|
||||
|
|
@ -564,7 +565,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
|
|||
let cnum = u32::decode(decoder);
|
||||
panic!(
|
||||
"Decoding of crate {:?} tried to access proc-macro dep {:?}",
|
||||
decoder.cdata().root.name,
|
||||
decoder.cdata().root.header.name,
|
||||
cnum
|
||||
);
|
||||
}
|
||||
|
|
@ -671,6 +672,16 @@ impl MetadataBlob {
|
|||
.decode(self)
|
||||
}
|
||||
|
||||
pub(crate) fn get_header(&self) -> CrateHeader {
|
||||
let slice = &self.blob()[..];
|
||||
let offset = METADATA_HEADER.len();
|
||||
|
||||
let pos_bytes = slice[offset..][..4].try_into().unwrap();
|
||||
let pos = u32::from_be_bytes(pos_bytes) as usize;
|
||||
|
||||
LazyValue::<CrateHeader>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
|
||||
}
|
||||
|
||||
pub(crate) fn get_root(&self) -> CrateRoot {
|
||||
let slice = &self.blob()[..];
|
||||
let offset = METADATA_HEADER.len();
|
||||
|
|
@ -684,8 +695,8 @@ impl MetadataBlob {
|
|||
pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> {
|
||||
let root = self.get_root();
|
||||
writeln!(out, "Crate info:")?;
|
||||
writeln!(out, "name {}{}", root.name, root.extra_filename)?;
|
||||
writeln!(out, "hash {} stable_crate_id {:?}", root.hash, root.stable_crate_id)?;
|
||||
writeln!(out, "name {}{}", root.name(), root.extra_filename)?;
|
||||
writeln!(out, "hash {} stable_crate_id {:?}", root.hash(), root.stable_crate_id)?;
|
||||
writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?;
|
||||
writeln!(out, "=External Dependencies=")?;
|
||||
|
||||
|
|
@ -709,21 +720,17 @@ impl CrateRoot {
|
|||
}
|
||||
|
||||
pub(crate) fn name(&self) -> Symbol {
|
||||
self.name
|
||||
self.header.name
|
||||
}
|
||||
|
||||
pub(crate) fn hash(&self) -> Svh {
|
||||
self.hash
|
||||
self.header.hash
|
||||
}
|
||||
|
||||
pub(crate) fn stable_crate_id(&self) -> StableCrateId {
|
||||
self.stable_crate_id
|
||||
}
|
||||
|
||||
pub(crate) fn triple(&self) -> &TargetTriple {
|
||||
&self.triple
|
||||
}
|
||||
|
||||
pub(crate) fn decode_crate_deps<'a>(
|
||||
&self,
|
||||
metadata: &'a MetadataBlob,
|
||||
|
|
@ -794,7 +801,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
bug!(
|
||||
"CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
|
||||
item_id,
|
||||
self.root.name,
|
||||
self.root.name(),
|
||||
self.cnum,
|
||||
)
|
||||
})
|
||||
|
|
@ -1702,11 +1709,11 @@ impl CrateMetadata {
|
|||
}
|
||||
|
||||
pub(crate) fn name(&self) -> Symbol {
|
||||
self.root.name
|
||||
self.root.header.name
|
||||
}
|
||||
|
||||
pub(crate) fn hash(&self) -> Svh {
|
||||
self.root.hash
|
||||
self.root.header.hash
|
||||
}
|
||||
|
||||
fn num_def_ids(&self) -> usize {
|
||||
|
|
|
|||
|
|
@ -317,9 +317,9 @@ provide! { tcx, def_id, other, cdata,
|
|||
}
|
||||
native_libraries => { cdata.get_native_libraries(tcx.sess).collect() }
|
||||
foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() }
|
||||
crate_hash => { cdata.root.hash }
|
||||
crate_hash => { cdata.root.header.hash }
|
||||
crate_host_hash => { cdata.host_hash }
|
||||
crate_name => { cdata.root.name }
|
||||
crate_name => { cdata.root.header.name }
|
||||
|
||||
extra_filename => { cdata.root.extra_filename.clone() }
|
||||
|
||||
|
|
@ -581,7 +581,7 @@ impl CrateStore for CStore {
|
|||
}
|
||||
|
||||
fn crate_name(&self, cnum: CrateNum) -> Symbol {
|
||||
self.get_crate_data(cnum).root.name
|
||||
self.get_crate_data(cnum).root.header.name
|
||||
}
|
||||
|
||||
fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId {
|
||||
|
|
|
|||
|
|
@ -662,10 +662,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let root = stat!("final", || {
|
||||
let attrs = tcx.hir().krate_attrs();
|
||||
self.lazy(CrateRoot {
|
||||
name: tcx.crate_name(LOCAL_CRATE),
|
||||
header: CrateHeader {
|
||||
name: tcx.crate_name(LOCAL_CRATE),
|
||||
triple: tcx.sess.opts.target_triple.clone(),
|
||||
hash: tcx.crate_hash(LOCAL_CRATE),
|
||||
is_proc_macro_crate: proc_macro_data.is_some(),
|
||||
},
|
||||
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
|
||||
triple: tcx.sess.opts.target_triple.clone(),
|
||||
hash: tcx.crate_hash(LOCAL_CRATE),
|
||||
stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
|
||||
required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
|
||||
panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub(crate) fn rustc_version(cfg_version: &'static str) -> String {
|
|||
/// Metadata encoding version.
|
||||
/// N.B., increment this if you change the format of metadata such that
|
||||
/// the rustc version can't be found to compare with `rustc_version()`.
|
||||
const METADATA_VERSION: u8 = 7;
|
||||
const METADATA_VERSION: u8 = 8;
|
||||
|
||||
/// Metadata header which includes `METADATA_VERSION`.
|
||||
///
|
||||
|
|
@ -199,7 +199,27 @@ pub(crate) struct ProcMacroData {
|
|||
macros: LazyArray<DefIndex>,
|
||||
}
|
||||
|
||||
/// Serialized metadata for a crate.
|
||||
/// Serialized crate metadata.
|
||||
///
|
||||
/// This contains just enough information to determine if we should load the `CrateRoot` or not.
|
||||
/// Prefer [`CrateRoot`] whenever possible to avoid ICEs when using `omit-git-hash` locally.
|
||||
/// See #76720 for more details.
|
||||
///
|
||||
/// If you do modify this struct, also bump the [`METADATA_VERSION`] constant.
|
||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||
pub(crate) struct CrateHeader {
|
||||
pub(crate) triple: TargetTriple,
|
||||
pub(crate) hash: Svh,
|
||||
pub(crate) name: Symbol,
|
||||
/// Whether this is the header for a proc-macro crate.
|
||||
///
|
||||
/// This is separate from [`ProcMacroData`] to avoid having to update [`METADATA_VERSION`] every
|
||||
/// time ProcMacroData changes.
|
||||
pub(crate) is_proc_macro_crate: bool,
|
||||
}
|
||||
|
||||
/// Serialized `.rmeta` data for a crate.
|
||||
///
|
||||
/// When compiling a proc-macro crate, we encode many of
|
||||
/// the `LazyArray<T>` fields as `Lazy::empty()`. This serves two purposes:
|
||||
///
|
||||
|
|
@ -217,10 +237,10 @@ pub(crate) struct ProcMacroData {
|
|||
/// to being unused.
|
||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||
pub(crate) struct CrateRoot {
|
||||
name: Symbol,
|
||||
triple: TargetTriple,
|
||||
/// A header used to detect if this is the right crate to load.
|
||||
header: CrateHeader,
|
||||
|
||||
extra_filename: String,
|
||||
hash: Svh,
|
||||
stable_crate_id: StableCrateId,
|
||||
required_panic_strategy: Option<PanicStrategy>,
|
||||
panic_in_drop_strategy: PanicStrategy,
|
||||
|
|
@ -465,6 +485,7 @@ trivially_parameterized_over_tcx! {
|
|||
RawDefId,
|
||||
TraitImpls,
|
||||
IncoherentImpls,
|
||||
CrateHeader,
|
||||
CrateRoot,
|
||||
CrateDep,
|
||||
AttrFlags,
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ pub fn explain_lint_level_source(
|
|||
}
|
||||
LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
|
||||
if let Some(rationale) = reason {
|
||||
err.note(rationale.as_str());
|
||||
err.note(rationale.to_string());
|
||||
}
|
||||
err.span_note_once(span, "the lint level is defined here");
|
||||
if lint_attr_name.as_str() != name {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ pub fn report_unstable(
|
|||
suggestion: Option<(Span, String, String, Applicability)>,
|
||||
is_soft: bool,
|
||||
span: Span,
|
||||
soft_handler: impl FnOnce(&'static Lint, Span, &str),
|
||||
soft_handler: impl FnOnce(&'static Lint, Span, String),
|
||||
) {
|
||||
let msg = match reason {
|
||||
Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
|
||||
|
|
@ -112,7 +112,7 @@ pub fn report_unstable(
|
|||
};
|
||||
|
||||
if is_soft {
|
||||
soft_handler(SOFT_UNSTABLE, span, &msg)
|
||||
soft_handler(SOFT_UNSTABLE, span, msg)
|
||||
} else {
|
||||
let mut err =
|
||||
feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), msg);
|
||||
|
|
@ -225,7 +225,7 @@ pub fn deprecation_message_and_lint(
|
|||
|
||||
pub fn early_report_deprecation(
|
||||
lint_buffer: &mut LintBuffer,
|
||||
message: &str,
|
||||
message: String,
|
||||
suggestion: Option<Symbol>,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
|
|
@ -241,7 +241,7 @@ pub fn early_report_deprecation(
|
|||
|
||||
fn late_report_deprecation(
|
||||
tcx: TyCtxt<'_>,
|
||||
message: &str,
|
||||
message: String,
|
||||
suggestion: Option<Symbol>,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
|
|
@ -396,7 +396,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
late_report_deprecation(
|
||||
self,
|
||||
&deprecation_message(
|
||||
deprecation_message(
|
||||
is_in_effect,
|
||||
depr_attr.since,
|
||||
depr_attr.note,
|
||||
|
|
@ -619,7 +619,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
allow_unstable: AllowUnstable,
|
||||
unmarked: impl FnOnce(Span, DefId),
|
||||
) -> bool {
|
||||
let soft_handler = |lint, span, msg: &_| {
|
||||
let soft_handler = |lint, span, msg: String| {
|
||||
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint)
|
||||
};
|
||||
let eval_result =
|
||||
|
|
|
|||
|
|
@ -732,7 +732,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` with the given
|
||||
/// `msg` to ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn mk_re_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Region<'tcx> {
|
||||
pub fn mk_re_error_with_message<S: Into<MultiSpan>>(
|
||||
self,
|
||||
span: S,
|
||||
msg: &'static str,
|
||||
) -> Region<'tcx> {
|
||||
let reported = self.sess.delay_span_bug(span, msg);
|
||||
self.mk_re_error(reported)
|
||||
}
|
||||
|
|
@ -759,7 +763,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self,
|
||||
ty: Ty<'tcx>,
|
||||
span: S,
|
||||
msg: &str,
|
||||
msg: &'static str,
|
||||
) -> Const<'tcx> {
|
||||
let reported = self.sess.delay_span_bug(span, msg);
|
||||
self.mk_const(ty::ConstKind::Error(reported), ty)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Diagnostics related methods for `Ty`.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::ty::{
|
||||
|
|
@ -384,22 +385,18 @@ pub fn suggest_constraining_type_params<'a>(
|
|||
|
||||
if suggestions.len() == 1 {
|
||||
let (span, suggestion, msg) = suggestions.pop().unwrap();
|
||||
|
||||
let s;
|
||||
let msg = match msg {
|
||||
SuggestChangingConstraintsMessage::RestrictBoundFurther => {
|
||||
"consider further restricting this bound"
|
||||
Cow::from("consider further restricting this bound")
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RestrictType { ty } => {
|
||||
s = format!("consider restricting type parameter `{}`", ty);
|
||||
&s
|
||||
Cow::from(format!("consider restricting type parameter `{}`", ty))
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
|
||||
s = format!("consider further restricting type parameter `{}`", ty);
|
||||
&s
|
||||
Cow::from(format!("consider further restricting type parameter `{}`", ty))
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RemovingQSized => {
|
||||
"consider removing the `?Sized` bound to make the type parameter `Sized`"
|
||||
Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`")
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,15 @@ impl<'a> Parser<'a> {
|
|||
fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
|
||||
let ident = self.parse_ident()?;
|
||||
|
||||
// We might have a typo'd `Const` that was parsed as a type parameter.
|
||||
if self.may_recover()
|
||||
&& ident.name.as_str().to_ascii_lowercase() == kw::Const.as_str()
|
||||
&& self.check_ident()
|
||||
// `Const` followed by IDENT
|
||||
{
|
||||
return Ok(self.recover_const_param_with_mistyped_const(preceding_attrs, ident)?);
|
||||
}
|
||||
|
||||
// Parse optional colon and param bounds.
|
||||
let mut colon_span = None;
|
||||
let bounds = if self.eat(&token::Colon) {
|
||||
|
|
@ -120,6 +129,41 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn recover_const_param_with_mistyped_const(
|
||||
&mut self,
|
||||
preceding_attrs: AttrVec,
|
||||
mistyped_const_ident: Ident,
|
||||
) -> PResult<'a, GenericParam> {
|
||||
let ident = self.parse_ident()?;
|
||||
self.expect(&token::Colon)?;
|
||||
let ty = self.parse_ty()?;
|
||||
|
||||
// Parse optional const generics default value.
|
||||
let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
|
||||
|
||||
let mut err = self.struct_span_err(
|
||||
mistyped_const_ident.span,
|
||||
format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()),
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
mistyped_const_ident.span,
|
||||
"use the `const` keyword",
|
||||
kw::Const.as_str(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
|
||||
Ok(GenericParam {
|
||||
ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: preceding_attrs,
|
||||
bounds: Vec::new(),
|
||||
kind: GenericParamKind::Const { ty, kw_span: mistyped_const_ident.span, default },
|
||||
is_placeholder: false,
|
||||
colon_span: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a (possibly empty) list of lifetime and type parameters, possibly including
|
||||
/// a trailing comma and erroneous trailing attributes.
|
||||
pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
|||
use rustc_span::source_map::{BytePos, Span};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::mem;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
|
|
@ -364,7 +365,7 @@ impl<'a> Parser<'a> {
|
|||
// `let...else if`. Emit the same error that `parse_block()` would,
|
||||
// but explicitly point out that this pattern is not allowed.
|
||||
let msg = "conditional `else if` is not supported for `let...else`";
|
||||
return Err(self.error_block_no_opening_brace_msg(msg));
|
||||
return Err(self.error_block_no_opening_brace_msg(Cow::from(msg)));
|
||||
}
|
||||
let els = self.parse_block()?;
|
||||
self.check_let_else_init_bool_expr(&init);
|
||||
|
|
@ -438,7 +439,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn error_block_no_opening_brace_msg(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: Cow<'static, str>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let sp = self.token.span;
|
||||
let mut e = self.struct_span_err(sp, msg);
|
||||
|
|
@ -502,7 +503,7 @@ impl<'a> Parser<'a> {
|
|||
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let tok = super::token_descr(&self.token);
|
||||
let msg = format!("expected `{{`, found {}", tok);
|
||||
Err(self.error_block_no_opening_brace_msg(&msg))
|
||||
Err(self.error_block_no_opening_brace_msg(Cow::from(msg)))
|
||||
}
|
||||
|
||||
/// Parses a block. Inner attributes are allowed.
|
||||
|
|
|
|||
|
|
@ -2540,7 +2540,7 @@ fn show_candidates(
|
|||
err.note(msg);
|
||||
}
|
||||
if let Some(note) = (*note).as_deref() {
|
||||
err.note(note);
|
||||
err.note(note.to_string());
|
||||
}
|
||||
} else {
|
||||
let (_, descr_first, _, _) = &inaccessible_path_strings[0];
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use rustc_span::hygiene::MacroKind;
|
|||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
@ -1248,7 +1249,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
}),
|
||||
) if followed_by_brace => {
|
||||
if let Some(sp) = closing_brace {
|
||||
err.span_label(span, fallback_label);
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
err.multipart_suggestion(
|
||||
"surround the struct literal with parentheses",
|
||||
vec![
|
||||
|
|
@ -1320,7 +1321,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_label(span, fallback_label);
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1333,7 +1334,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
}))
|
||||
| PathSource::Struct,
|
||||
) => {
|
||||
err.span_label(span, fallback_label);
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"use `!` to invoke the macro",
|
||||
|
|
@ -1345,7 +1346,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
}
|
||||
}
|
||||
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
|
||||
err.span_label(span, fallback_label);
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
}
|
||||
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
|
||||
err.span_label(span, "type aliases cannot be used as traits");
|
||||
|
|
@ -1513,7 +1514,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
);
|
||||
}
|
||||
(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => {
|
||||
err.span_label(span, fallback_label);
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
err.note("can't use `Self` as a constructor, you must use the implemented struct");
|
||||
}
|
||||
(Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
|
||||
|
|
@ -2243,7 +2244,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
&self,
|
||||
err: &mut Diagnostic,
|
||||
name: Option<&str>,
|
||||
suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool,
|
||||
suggest: impl Fn(&mut Diagnostic, bool, Span, Cow<'static, str>, String) -> bool,
|
||||
) {
|
||||
let mut suggest_note = true;
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
|
|
@ -2288,22 +2289,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
(span, sugg)
|
||||
};
|
||||
if higher_ranked {
|
||||
let message = format!(
|
||||
let message = Cow::from(format!(
|
||||
"consider making the {} lifetime-generic with a new `{}` lifetime",
|
||||
kind.descr(),
|
||||
name.unwrap_or("'a"),
|
||||
);
|
||||
should_continue = suggest(err, true, span, &message, sugg);
|
||||
));
|
||||
should_continue = suggest(err, true, span, message, sugg);
|
||||
err.note_once(
|
||||
"for more information on higher-ranked polymorphism, visit \
|
||||
https://doc.rust-lang.org/nomicon/hrtb.html",
|
||||
);
|
||||
} else if let Some(name) = name {
|
||||
let message = format!("consider introducing lifetime `{}` here", name);
|
||||
should_continue = suggest(err, false, span, &message, sugg);
|
||||
let message =
|
||||
Cow::from(format!("consider introducing lifetime `{}` here", name));
|
||||
should_continue = suggest(err, false, span, message, sugg);
|
||||
} else {
|
||||
let message = "consider introducing a named lifetime parameter";
|
||||
should_continue = suggest(err, false, span, &message, sugg);
|
||||
let message = Cow::from("consider introducing a named lifetime parameter");
|
||||
should_continue = suggest(err, false, span, message, sugg);
|
||||
}
|
||||
}
|
||||
LifetimeRibKind::Item => break,
|
||||
|
|
|
|||
|
|
@ -827,7 +827,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
if !is_allowed(feature) && !allowed_by_implication {
|
||||
let lint_buffer = &mut self.lint_buffer;
|
||||
let soft_handler =
|
||||
|lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
|
||||
|lint, span, msg: String| lint_buffer.buffer_lint(lint, node_id, span, msg);
|
||||
stability::report_unstable(
|
||||
self.tcx.sess,
|
||||
feature,
|
||||
|
|
@ -846,7 +846,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path);
|
||||
stability::early_report_deprecation(
|
||||
&mut self.lint_buffer,
|
||||
&message,
|
||||
message,
|
||||
depr.suggestion,
|
||||
lint,
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ session_feature_gate_error = {$explain}
|
|||
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
|
||||
|
||||
session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
|
||||
|
||||
session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
|
||||
.note = compatible flavors are: {$compatible_list}
|
||||
|
||||
session_incorrect_cgu_reuse_type =
|
||||
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
|
||||
[one] {"at least "}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
|
||||
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
|
||||
use rustc_target::abi::Align;
|
||||
use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
|
||||
use rustc_target::spec::{LinkerFlavorCli, PanicStrategy, SanitizerSet, SplitDebuginfo};
|
||||
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
|
||||
|
||||
use crate::parse::{CrateCheckConfig, CrateConfig};
|
||||
|
|
@ -2525,6 +2525,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(flavor) = cg.linker_flavor {
|
||||
if matches!(flavor, LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker)
|
||||
&& !nightly_options::is_unstable_enabled(matches)
|
||||
{
|
||||
let msg = format!(
|
||||
"linker flavor `{}` is unstable, `-Z unstable-options` \
|
||||
flag must also be passed to explicitly use it",
|
||||
flavor.desc()
|
||||
);
|
||||
early_error(error_format, msg);
|
||||
}
|
||||
}
|
||||
|
||||
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
|
||||
|
||||
let cg = cg;
|
||||
|
|
|
|||
|
|
@ -422,3 +422,11 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
|
|||
pub struct OptimisationFuelExhausted {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_incompatible_linker_flavor)]
|
||||
#[note]
|
||||
pub struct IncompatibleLinkerFlavor {
|
||||
pub flavor: &'static str,
|
||||
pub compatible_list: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ pub fn feature_err_issue(
|
|||
/// Construct a future incompatibility diagnostic for a feature gate.
|
||||
///
|
||||
/// This diagnostic is only a warning and *does not cause compilation to fail*.
|
||||
pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &str) {
|
||||
pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &'static str) {
|
||||
feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ pub fn feature_warn_issue(
|
|||
feature: Symbol,
|
||||
span: Span,
|
||||
issue: GateIssue,
|
||||
explain: &str,
|
||||
explain: &'static str,
|
||||
) {
|
||||
let mut err = sess.span_diagnostic.struct_span_warn(span, explain);
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
|
||||
|
|
|
|||
|
|
@ -1675,6 +1675,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
|
||||
sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
|
||||
}
|
||||
|
||||
if let Some(flavor) = sess.opts.cg.linker_flavor {
|
||||
if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
|
||||
let flavor = flavor.desc();
|
||||
sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds data on the current incremental compilation session, if there is one.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
use core::fmt::Display;
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::DiagnosticMessage;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -534,10 +533,7 @@ fn encode_ty<'tcx>(
|
|||
tcx.sess
|
||||
.struct_span_err(
|
||||
cfi_encoding.span,
|
||||
DiagnosticMessage::Str(format!(
|
||||
"invalid `cfi_encoding` for `{:?}`",
|
||||
ty.kind()
|
||||
)),
|
||||
format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -589,10 +585,7 @@ fn encode_ty<'tcx>(
|
|||
tcx.sess
|
||||
.struct_span_err(
|
||||
cfi_encoding.span,
|
||||
DiagnosticMessage::Str(format!(
|
||||
"invalid `cfi_encoding` for `{:?}`",
|
||||
ty.kind()
|
||||
)),
|
||||
format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
|
|||
|
|
@ -205,15 +205,11 @@ impl ToJson for LldFlavor {
|
|||
}
|
||||
|
||||
impl LinkerFlavor {
|
||||
pub fn from_cli(cli: LinkerFlavorCli, target: &TargetOptions) -> LinkerFlavor {
|
||||
Self::from_cli_impl(cli, target.linker_flavor.lld_flavor(), target.linker_flavor.is_gnu())
|
||||
}
|
||||
|
||||
/// The passed CLI flavor is preferred over other args coming from the default target spec,
|
||||
/// so this function can produce a flavor that is incompatible with the current target.
|
||||
/// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible
|
||||
/// with the current target.
|
||||
fn from_cli_impl(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
|
||||
/// At this point the target's reference linker flavor doesn't yet exist and we need to infer
|
||||
/// it. The inference always succeds and gives some result, and we don't report any flavor
|
||||
/// incompatibility errors for json target specs. The CLI flavor is used as the main source
|
||||
/// of truth, other flags are used in case of ambiguities.
|
||||
fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
|
||||
match cli {
|
||||
LinkerFlavorCli::Gcc => match lld_flavor {
|
||||
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
|
|
@ -257,6 +253,85 @@ impl LinkerFlavor {
|
|||
}
|
||||
}
|
||||
|
||||
fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) {
|
||||
match cli {
|
||||
LinkerFlavorCli::Gcc | LinkerFlavorCli::Em => (Some(Cc::Yes), None),
|
||||
LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
|
||||
LinkerFlavorCli::Ld | LinkerFlavorCli::Msvc => (Some(Cc::No), Some(Lld::No)),
|
||||
LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None),
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) {
|
||||
// Remove any version postfix.
|
||||
let stem = linker_stem
|
||||
.rsplit_once('-')
|
||||
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
||||
.unwrap_or(linker_stem);
|
||||
|
||||
// GCC/Clang can have an optional target prefix.
|
||||
if stem == "emcc"
|
||||
|| stem == "gcc"
|
||||
|| stem.ends_with("-gcc")
|
||||
|| stem == "g++"
|
||||
|| stem.ends_with("-g++")
|
||||
|| stem == "clang"
|
||||
|| stem.ends_with("-clang")
|
||||
|| stem == "clang++"
|
||||
|| stem.ends_with("-clang++")
|
||||
{
|
||||
(Some(Cc::Yes), None)
|
||||
} else if stem == "wasm-ld"
|
||||
|| stem.ends_with("-wasm-ld")
|
||||
|| stem == "ld.lld"
|
||||
|| stem == "lld"
|
||||
|| stem == "rust-lld"
|
||||
|| stem == "lld-link"
|
||||
{
|
||||
(Some(Cc::No), Some(Lld::Yes))
|
||||
} else if stem == "ld" || stem.ends_with("-ld") || stem == "link" {
|
||||
(Some(Cc::No), Some(Lld::No))
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor {
|
||||
match self {
|
||||
LinkerFlavor::Gnu(cc, lld) => {
|
||||
LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
|
||||
}
|
||||
LinkerFlavor::Darwin(cc, lld) => {
|
||||
LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
|
||||
}
|
||||
LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)),
|
||||
LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)),
|
||||
LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)),
|
||||
LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor {
|
||||
self.with_hints(LinkerFlavor::infer_cli_hints(cli))
|
||||
}
|
||||
|
||||
pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor {
|
||||
self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem))
|
||||
}
|
||||
|
||||
pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> {
|
||||
// The CLI flavor should be compatible with the target if it survives this roundtrip.
|
||||
let compatible = |cli| cli == self.with_cli_hints(cli).to_cli();
|
||||
(!compatible(cli)).then(|| {
|
||||
LinkerFlavorCli::all()
|
||||
.iter()
|
||||
.filter(|cli| compatible(**cli))
|
||||
.map(|cli| cli.desc())
|
||||
.intersperse(", ")
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lld_flavor(self) -> LldFlavor {
|
||||
match self {
|
||||
LinkerFlavor::Gnu(..)
|
||||
|
|
@ -278,6 +353,10 @@ impl LinkerFlavor {
|
|||
macro_rules! linker_flavor_cli_impls {
|
||||
($(($($flavor:tt)*) $string:literal)*) => (
|
||||
impl LinkerFlavorCli {
|
||||
const fn all() -> &'static [LinkerFlavorCli] {
|
||||
&[$($($flavor)*,)*]
|
||||
}
|
||||
|
||||
pub const fn one_of() -> &'static str {
|
||||
concat!("one of: ", $($string, " ",)*)
|
||||
}
|
||||
|
|
@ -289,8 +368,8 @@ macro_rules! linker_flavor_cli_impls {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn desc(&self) -> &str {
|
||||
match *self {
|
||||
pub fn desc(self) -> &'static str {
|
||||
match self {
|
||||
$($($flavor)* => $string,)*
|
||||
}
|
||||
}
|
||||
|
|
@ -1801,7 +1880,7 @@ impl TargetOptions {
|
|||
}
|
||||
|
||||
fn update_from_cli(&mut self) {
|
||||
self.linker_flavor = LinkerFlavor::from_cli_impl(
|
||||
self.linker_flavor = LinkerFlavor::from_cli_json(
|
||||
self.linker_flavor_json,
|
||||
self.lld_flavor_json,
|
||||
self.linker_is_gnu_json,
|
||||
|
|
@ -1815,12 +1894,7 @@ impl TargetOptions {
|
|||
] {
|
||||
args.clear();
|
||||
for (flavor, args_json) in args_json {
|
||||
// Cannot use `from_cli` due to borrow checker.
|
||||
let linker_flavor = LinkerFlavor::from_cli_impl(
|
||||
*flavor,
|
||||
self.lld_flavor_json,
|
||||
self.linker_is_gnu_json,
|
||||
);
|
||||
let linker_flavor = self.linker_flavor.with_cli_hints(*flavor);
|
||||
// Normalize to no lld to avoid asserts.
|
||||
let linker_flavor = match linker_flavor {
|
||||
LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub fn target() -> Target {
|
|||
base.vendor = "pc".into();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::X86;
|
||||
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
|
||||
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
|
||||
|
||||
Target {
|
||||
llvm_target: "x86_64-pc-solaris".into(),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ pub fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]);
|
||||
base.cpu = "x86-64".into();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
|
||||
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
|
||||
|
||||
Target {
|
||||
// LLVM does not currently have a separate illumos target,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use rustc_session::Limit;
|
|||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{ExpnKind, Span, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
|
@ -1602,7 +1603,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}),
|
||||
) => Some((
|
||||
ty.span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
with_forced_trimmed_paths!(Cow::from(format!(
|
||||
"type mismatch resolving `{}`",
|
||||
self.resolve_vars_if_possible(predicate)
|
||||
.print(FmtPrinter::new_with_limit(
|
||||
|
|
@ -1612,7 +1613,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
))
|
||||
.unwrap()
|
||||
.into_buffer()
|
||||
)),
|
||||
))),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use rustc_span::def_id::LocalDefId;
|
|||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
@ -186,7 +187,12 @@ pub trait TypeErrCtxtExt<'tcx> {
|
|||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol>;
|
||||
fn get_closure_name(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
err: &mut Diagnostic,
|
||||
msg: Cow<'static, str>,
|
||||
) -> Option<Symbol>;
|
||||
|
||||
fn suggest_fn_call(
|
||||
&self,
|
||||
|
|
@ -857,7 +863,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
/// Given a closure's `DefId`, return the given name of the closure.
|
||||
///
|
||||
/// This doesn't account for reassignments, but it's only used for suggestions.
|
||||
fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol> {
|
||||
fn get_closure_name(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
err: &mut Diagnostic,
|
||||
msg: Cow<'static, str>,
|
||||
) -> Option<Symbol> {
|
||||
let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<Symbol> {
|
||||
// Get the local name of this closure. This can be inaccurate because
|
||||
// of the possibility of reassignment, but this should be good enough.
|
||||
|
|
@ -934,17 +945,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
let msg = match def_id_or_name {
|
||||
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
|
||||
DefKind::Ctor(CtorOf::Struct, _) => {
|
||||
"use parentheses to construct this tuple struct".to_string()
|
||||
Cow::from("use parentheses to construct this tuple struct")
|
||||
}
|
||||
DefKind::Ctor(CtorOf::Variant, _) => {
|
||||
"use parentheses to construct this tuple variant".to_string()
|
||||
Cow::from("use parentheses to construct this tuple variant")
|
||||
}
|
||||
kind => format!(
|
||||
kind => Cow::from(format!(
|
||||
"use parentheses to call this {}",
|
||||
self.tcx.def_kind_descr(kind, def_id)
|
||||
),
|
||||
)),
|
||||
},
|
||||
DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
|
||||
DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),
|
||||
};
|
||||
|
||||
let args = inputs
|
||||
|
|
@ -979,7 +990,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
..
|
||||
})) => {
|
||||
err.span_label(*fn_decl_span, "consider calling this closure");
|
||||
let Some(name) = self.get_closure_name(def_id, err, &msg) else {
|
||||
let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {
|
||||
return false;
|
||||
};
|
||||
name.to_string()
|
||||
|
|
@ -1341,7 +1352,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
err.note(msg);
|
||||
} else {
|
||||
err.message =
|
||||
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
|
||||
vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)];
|
||||
}
|
||||
err.span_label(
|
||||
span,
|
||||
|
|
@ -2958,7 +2969,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
for ty in bound_tys.skip_binder() {
|
||||
with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
|
||||
}
|
||||
err.note(msg.trim_end_matches(", "))
|
||||
err.note(msg.trim_end_matches(", ").to_string())
|
||||
}
|
||||
ty::GeneratorWitnessMIR(def_id, substs) => {
|
||||
use std::fmt::Write;
|
||||
|
|
@ -2972,7 +2983,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
let ty = bty.subst(tcx, substs);
|
||||
write!(msg, "`{}`, ", ty).unwrap();
|
||||
}
|
||||
err.note(msg.trim_end_matches(", "))
|
||||
err.note(msg.trim_end_matches(", ").to_string())
|
||||
}
|
||||
ty::Generator(def_id, _, _) => {
|
||||
let sp = self.tcx.def_span(def_id);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,12 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
|
|||
|
||||
/// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
|
||||
/// trait aliases.
|
||||
pub fn label_with_exp_info(&self, diag: &mut Diagnostic, top_label: &str, use_desc: &str) {
|
||||
pub fn label_with_exp_info(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
top_label: &'static str,
|
||||
use_desc: &str,
|
||||
) {
|
||||
diag.span_label(self.top().1, top_label);
|
||||
if self.path.len() > 1 {
|
||||
for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue