Auto merge of #108473 - matthiaskrgr:rollup-qjyae58, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #107062 (Do some cleanup of doc/index.md)
 - #107890 (Lint against `Iterator::map` receiving a callable that returns `()`)
 - #108431 (Add regression test for #107918)
 - #108432 (test: drop unused deps)
 - #108436 (make "proc macro panicked" translatable)
 - #108444 (docs/test: add UI test and docs for `E0476`)
 - #108449 (Do not lint ineffective unstable trait impl for unresolved trait)
 - #108456 (Complete migrating `ast_passes` to derive diagnostics)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-02-26 02:04:23 +00:00
commit 70fd012439
43 changed files with 1394 additions and 514 deletions

View File

@ -5497,10 +5497,8 @@ dependencies = [
name = "test"
version = "0.0.0"
dependencies = [
"cfg-if",
"core",
"getopts",
"libc",
"panic_abort",
"panic_unwind",
"proc_macro",

View File

@ -87,3 +87,150 @@ ast_passes_fn_without_body =
.suggestion = provide a definition for the function
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
.suggestion = remove the {$remove_descr}
.label = `extern` block begins here
ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
.cannot_have = cannot have a body
.invalid = the invalid body
.existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
ast_passes_fn_body_extern = incorrect function inside `extern` block
.cannot_have = cannot have a body
.suggestion = remove the invalid body
.help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
.label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
.label = in this `extern` block
.suggestion = remove the qualifiers
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
.label = in this `extern` block
.note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
ast_passes_item_underscore = `{$kind}` items in this context need a name
.label = `_` is not a valid name for this `{$kind}` item
ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
.help = consider using the `#[path]` attribute to specify filesystem path
ast_passes_auto_generic = auto traits cannot have generic parameters
.label = auto trait cannot have generic parameters
.suggestion = remove the parameters
ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
.label = {ast_passes_auto_super_lifetime}
.suggestion = remove the super traits or lifetime bounds
ast_passes_auto_items = auto traits cannot have associated items
.label = {ast_passes_auto_items}
.suggestion = remove these associated items
ast_passes_generic_before_constraints = generic arguments must come before the first constraint
.constraints = {$constraint_len ->
[one] constraint
*[other] constraints
}
.args = generic {$args_len ->
[one] argument
*[other] arguments
}
.empty_string = {""},
.suggestion = move the {$constraint_len ->
[one] constraint
*[other] constraints
} after the generic {$args_len ->
[one] argument
*[other] arguments
}
ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
.outer = outer `impl Trait`
.inner = nested `impl Trait` here
ast_passes_at_least_one_trait = at least one trait must be specified
ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
.suggestion = reorder the parameters: lifetimes, then consts and types
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
.help = use `auto trait Trait {"{}"}` instead
ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
.negative = negative because of this
.unsafe = unsafe because of this
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
.because = {$annotation} because of this
.type = inherent impl for this type
.only_trait = only trait implementations may be annotated with {$annotation}
ast_passes_unsafe_item = {$kind} cannot be declared unsafe
ast_passes_fieldless_union = unions cannot have zero fields
ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
ast_passes_nested_lifetimes = nested quantification of lifetimes
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
.note = traits are `?{$path_str}` by default
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
ast_passes_tilde_const_disallowed = `~const` is not allowed here
.trait = trait objects cannot have `~const` trait bounds
.closure = closures cannot have `~const` trait bounds
.function = this function is not `const`, so it cannot have `~const` trait bounds
ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive
ast_passes_const_and_async = functions cannot be both `const` and `async`
.const = `const` because of this
.async = `async` because of this
.label = {""}
ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
.label = pattern not allowed in foreign function
ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
.label = pattern not allowed in function without body
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
.label = not supported
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
.suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
.note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
.suggestion = remove the attribute
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
ast_passes_incompatbile_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features
ast_passes_show_span = {$msg}

View File

@ -13,7 +13,6 @@ use rustc_ast::walk_list;
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
use rustc_macros::Subdiagnostic;
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{
@ -29,12 +28,9 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use thin_vec::thin_vec;
use crate::errors::*;
use crate::errors;
use crate::fluent_generated as fluent;
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
enum SelfSemantic {
Yes,
@ -134,9 +130,9 @@ impl<'a> AstValidator<'a> {
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
let sess = &self.session;
if sess.opts.unstable_features.is_nightly_build() {
sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
} else {
sess.emit_err(ForbiddenLetStable { span: expr.span });
sess.emit_err(errors::ForbiddenLetStable { span: expr.span });
}
}
@ -234,22 +230,22 @@ impl<'a> AstValidator<'a> {
fn check_lifetime(&self, ident: Ident) {
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
self.session.emit_err(KeywordLifetime { span: ident.span });
self.session.emit_err(errors::KeywordLifetime { span: ident.span });
}
}
fn check_label(&self, ident: Ident) {
if ident.without_first_quote().is_reserved() {
self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
}
}
fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
fn invalid_visibility(&self, vis: &Visibility, note: Option<errors::InvalidVisibilityNote>) {
if let VisibilityKind::Inherited = vis.kind {
return;
}
self.session.emit_err(InvalidVisibility {
self.session.emit_err(errors::InvalidVisibility {
span: vis.span,
implied: vis.kind.is_pub().then_some(vis.span),
note,
@ -270,7 +266,7 @@ impl<'a> AstValidator<'a> {
fn check_trait_fn_not_const(&self, constness: Const) {
if let Const::Yes(span) = constness {
self.session.emit_err(TraitFnConst { span });
self.session.emit_err(errors::TraitFnConst { span });
}
}
@ -287,7 +283,7 @@ impl<'a> AstValidator<'a> {
let max_num_args: usize = u16::MAX.into();
if fn_decl.inputs.len() > max_num_args {
let Param { span, .. } = fn_decl.inputs[0];
self.session.emit_fatal(FnParamTooMany { span, max_num_args });
self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args });
}
}
@ -295,13 +291,13 @@ impl<'a> AstValidator<'a> {
match &*fn_decl.inputs {
[Param { ty, span, .. }] => {
if let TyKind::CVarArgs = ty.kind {
self.session.emit_err(FnParamCVarArgsOnly { span: *span });
self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span });
}
}
[ps @ .., _] => {
for Param { ty, span, .. } in ps {
if let TyKind::CVarArgs = ty.kind {
self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span });
}
}
}
@ -328,9 +324,9 @@ impl<'a> AstValidator<'a> {
})
.for_each(|attr| {
if attr.is_doc_comment() {
self.session.emit_err(FnParamDocComment { span: attr.span });
self.session.emit_err(errors::FnParamDocComment { span: attr.span });
} else {
self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span });
}
});
}
@ -338,7 +334,7 @@ impl<'a> AstValidator<'a> {
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
if param.is_self() {
self.session.emit_err(FnParamForbiddenSelf { span: param.span });
self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span });
}
}
}
@ -346,7 +342,7 @@ impl<'a> AstValidator<'a> {
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
if let Defaultness::Default(def_span) = defaultness {
let span = self.session.source_map().guess_head_span(span);
self.session.emit_err(ForbiddenDefault { span, def_span });
self.session.emit_err(errors::ForbiddenDefault { span, def_span });
}
}
@ -369,27 +365,17 @@ impl<'a> AstValidator<'a> {
[b0] => b0.span(),
[b0, .., bl] => b0.span().to(bl.span()),
};
self.err_handler()
.struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
.emit();
self.err_handler().emit_err(errors::BoundInContext { span, ctx });
}
fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
let cannot_have = |span, descr, remove_descr| {
self.err_handler()
.struct_span_err(
span,
&format!("`type`s inside `extern` blocks cannot have {}", descr),
)
.span_suggestion(
span,
&format!("remove the {}", remove_descr),
"",
Applicability::MaybeIncorrect,
)
.span_label(self.current_extern_span(), "`extern` block begins here")
.note(MORE_EXTERN)
.emit();
self.err_handler().emit_err(errors::ExternTypesCannotHave {
span,
descr,
remove_descr,
block_span: self.current_extern_span(),
});
};
if !generics.params.is_empty() {
@ -405,20 +391,12 @@ impl<'a> AstValidator<'a> {
let Some(body) = body else {
return;
};
self.err_handler()
.struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
.span_label(ident.span, "cannot have a body")
.span_label(body, "the invalid body")
.span_label(
self.current_extern_span(),
format!(
"`extern` blocks define existing foreign {0}s and {0}s \
inside of them cannot have a body",
kind
),
)
.note(MORE_EXTERN)
.emit();
self.err_handler().emit_err(errors::BodyInExtern {
span: ident.span,
body,
block: self.current_extern_span(),
kind,
});
}
/// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
@ -426,26 +404,11 @@ impl<'a> AstValidator<'a> {
let Some(body) = body else {
return;
};
self.err_handler()
.struct_span_err(ident.span, "incorrect function inside `extern` block")
.span_label(ident.span, "cannot have a body")
.span_suggestion(
body.span,
"remove the invalid body",
";",
Applicability::MaybeIncorrect,
)
.help(
"you might have meant to write a function accessible through FFI, \
which can be done by writing `extern fn` outside of the `extern` block",
)
.span_label(
self.current_extern_span(),
"`extern` blocks define existing foreign functions and functions \
inside of them cannot have a body",
)
.note(MORE_EXTERN)
.emit();
self.err_handler().emit_err(errors::FnBodyInExtern {
span: ident.span,
body: body.span,
block: self.current_extern_span(),
});
}
fn current_extern_span(&self) -> Span {
@ -455,34 +418,21 @@ impl<'a> AstValidator<'a> {
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
if header.has_qualifiers() {
self.err_handler()
.struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
.span_label(self.current_extern_span(), "in this `extern` block")
.span_suggestion_verbose(
span.until(ident.span.shrink_to_lo()),
"remove the qualifiers",
"fn ",
Applicability::MaybeIncorrect,
)
.emit();
self.err_handler().emit_err(errors::FnQualifierInExtern {
span: ident.span,
block: self.current_extern_span(),
sugg_span: span.until(ident.span.shrink_to_lo()),
});
}
}
/// An item in `extern { ... }` cannot use non-ascii identifier.
fn check_foreign_item_ascii_only(&self, ident: Ident) {
if !ident.as_str().is_ascii() {
let n = 83942;
self.err_handler()
.struct_span_err(
ident.span,
"items in `extern` blocks cannot use non-ascii identifiers",
)
.span_label(self.current_extern_span(), "in this `extern` block")
.note(&format!(
"this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
n, n,
))
.emit();
self.err_handler().emit_err(errors::ExternItemAscii {
span: ident.span,
block: self.current_extern_span(),
});
}
}
@ -505,12 +455,7 @@ impl<'a> AstValidator<'a> {
for Param { ty, span, .. } in &fk.decl().inputs {
if let TyKind::CVarArgs = ty.kind {
self.err_handler()
.struct_span_err(
*span,
"only foreign or `unsafe extern \"C\"` functions may be C-variadic",
)
.emit();
self.err_handler().emit_err(errors::BadCVariadic { span: *span });
}
}
}
@ -519,75 +464,32 @@ impl<'a> AstValidator<'a> {
if ident.name != kw::Underscore {
return;
}
self.err_handler()
.struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
.span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
.emit();
self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind });
}
fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
if ident.name.as_str().is_ascii() {
return;
}
let head_span = self.session.source_map().guess_head_span(item_span);
struct_span_err!(
self.session,
head_span,
E0754,
"`#[no_mangle]` requires ASCII identifier"
)
.emit();
let span = self.session.source_map().guess_head_span(item_span);
self.session.emit_err(errors::NoMangleAscii { span });
}
fn check_mod_file_item_asciionly(&self, ident: Ident) {
if ident.name.as_str().is_ascii() {
return;
}
struct_span_err!(
self.session,
ident.span,
E0754,
"trying to load file for module `{}` with non-ascii identifier name",
ident.name
)
.help("consider using `#[path]` attribute to specify filesystem path")
.emit();
self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
}
fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
fn deny_generic_params(&self, generics: &Generics, ident: Span) {
if !generics.params.is_empty() {
struct_span_err!(
self.session,
generics.span,
E0567,
"auto traits cannot have generic parameters"
)
.span_label(ident_span, "auto trait cannot have generic parameters")
.span_suggestion(
generics.span,
"remove the parameters",
"",
Applicability::MachineApplicable,
)
.emit();
self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
}
}
fn emit_e0568(&self, span: Span, ident_span: Span) {
struct_span_err!(
self.session,
span,
E0568,
"auto traits cannot have super traits or lifetime bounds"
)
.span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
.span_suggestion(
span,
"remove the super traits or lifetime bounds",
"",
Applicability::MachineApplicable,
)
.emit();
fn emit_e0568(&self, span: Span, ident: Span) {
self.session.emit_err(errors::AutoTraitBounds { span, ident });
}
fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
@ -603,24 +505,11 @@ impl<'a> AstValidator<'a> {
}
}
fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) {
if !trait_items.is_empty() {
let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
struct_span_err!(
self.session,
spans,
E0380,
"auto traits cannot have associated items"
)
.span_suggestion(
total_span,
"remove these associated items",
"",
Applicability::MachineApplicable,
)
.span_label(ident_span, "auto trait cannot have associated items")
.emit();
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
self.session.emit_err(errors::AutoTraitItems { spans, total, ident });
}
}
@ -666,29 +555,17 @@ impl<'a> AstValidator<'a> {
let args_len = arg_spans.len();
let constraint_len = constraint_spans.len();
// ...and then error:
self.err_handler()
.struct_span_err(
arg_spans.clone(),
"generic arguments must come before the first constraint",
)
.span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
.span_label(
*arg_spans.iter().last().unwrap(),
&format!("generic argument{}", pluralize!(args_len)),
)
.span_labels(constraint_spans, "")
.span_labels(arg_spans, "")
.span_suggestion_verbose(
data.span,
&format!(
"move the constraint{} after the generic argument{}",
pluralize!(constraint_len),
pluralize!(args_len)
),
self.correct_generic_order_suggestion(&data),
Applicability::MachineApplicable,
)
.emit();
self.err_handler().emit_err(errors::ArgsBeforeConstraint {
arg_spans: arg_spans.clone(),
constraints: constraint_spans[0],
args: *arg_spans.iter().last().unwrap(),
data: data.span,
constraint_spans: errors::EmptyLabelManySpans(constraint_spans),
arg_spans2: errors::EmptyLabelManySpans(arg_spans),
suggestion: self.correct_generic_order_suggestion(&data),
constraint_len,
args_len,
});
}
fn visit_ty_common(&mut self, ty: &'a Ty) {
@ -696,13 +573,7 @@ impl<'a> AstValidator<'a> {
TyKind::BareFn(bfty) => {
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
struct_span_err!(
self.session,
span,
E0561,
"patterns aren't allowed in function pointer types"
)
.emit();
self.session.emit_err(errors::PatternFnPointer { span });
});
if let Extern::Implicit(_) = bfty.ext {
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
@ -714,13 +585,8 @@ impl<'a> AstValidator<'a> {
for bound in bounds {
if let GenericBound::Outlives(lifetime) = bound {
if any_lifetime_bounds {
struct_span_err!(
self.session,
lifetime.ident.span,
E0226,
"only a single explicit lifetime bound is permitted"
)
.emit();
self.session
.emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
break;
}
any_lifetime_bounds = true;
@ -729,29 +595,19 @@ impl<'a> AstValidator<'a> {
}
TyKind::ImplTrait(_, bounds) => {
if self.is_impl_trait_banned {
struct_span_err!(
self.session,
ty.span,
E0667,
"`impl Trait` is not allowed in path parameters"
)
.emit();
self.session.emit_err(errors::ImplTraitPath { span: ty.span });
}
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
struct_span_err!(
self.session,
ty.span,
E0666,
"nested `impl Trait` is not allowed"
)
.span_label(outer_impl_trait_sp, "outer `impl Trait`")
.span_label(ty.span, "nested `impl Trait` here")
.emit();
self.session.emit_err(errors::NestedImplTrait {
span: ty.span,
outer: outer_impl_trait_sp,
inner: ty.span,
});
}
if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
self.err_handler().span_err(ty.span, "at least one trait must be specified");
self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span });
}
}
_ => {}
@ -772,7 +628,7 @@ impl<'a> AstValidator<'a> {
MISSING_ABI,
id,
span,
"extern declarations without an explicit ABI are deprecated",
fluent::ast_passes_extern_without_abi,
BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
)
}
@ -845,20 +701,13 @@ fn validate_generic_param_order(
ordered_params += ">";
for (param_ord, (max_param, spans)) in &out_of_order {
let mut err = handler.struct_span_err(
spans.clone(),
&format!(
"{} parameters must be declared prior to {} parameters",
param_ord, max_param,
),
);
err.span_suggestion(
span,
"reorder the parameters: lifetimes, then consts and types",
&ordered_params,
Applicability::MachineApplicable,
);
err.emit();
handler.emit_err(errors::OutOfOrderParams {
spans: spans.clone(),
sugg_span: span,
param_ord,
max_param,
ordered_params: &ordered_params,
});
}
}
}
@ -972,25 +821,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.with_in_trait_impl(true, Some(*constness), |this| {
this.invalid_visibility(&item.vis, None);
if let TyKind::Err = self_ty.kind {
this.err_handler()
.struct_span_err(
item.span,
"`impl Trait for .. {}` is an obsolete syntax",
)
.help("use `auto trait Trait {}` instead")
.emit();
this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span });
}
if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
{
struct_span_err!(
this.session,
sp.to(t.path.span),
E0198,
"negative impls cannot be unsafe"
)
.span_label(sp, "negative because of this")
.span_label(span, "unsafe because of this")
.emit();
this.session.emit_err(errors::UnsafeNegativeImpl {
span: sp.to(t.path.span),
negative: sp,
r#unsafe: span,
});
}
this.visit_vis(&item.vis);
@ -1018,52 +857,54 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self_ty,
items: _,
}) => {
let error = |annotation_span, annotation| {
let mut err = self.err_handler().struct_span_err(
self_ty.span,
&format!("inherent impls cannot be {}", annotation),
);
err.span_label(annotation_span, &format!("{} because of this", annotation));
err.span_label(self_ty.span, "inherent impl for this type");
err
};
let error =
|annotation_span, annotation, only_trait: bool| errors::InherentImplCannot {
span: self_ty.span,
annotation_span,
annotation,
self_ty: self_ty.span,
only_trait: only_trait.then_some(()),
};
self.invalid_visibility(
&item.vis,
Some(InvalidVisibilityNote::IndividualImplItems),
Some(errors::InvalidVisibilityNote::IndividualImplItems),
);
if let &Unsafe::Yes(span) = unsafety {
error(span, "unsafe").code(error_code!(E0197)).emit();
self.err_handler().emit_err(errors::InherentImplCannotUnsafe {
span: self_ty.span,
annotation_span: span,
annotation: "unsafe",
self_ty: self_ty.span,
});
}
if let &ImplPolarity::Negative(span) = polarity {
error(span, "negative").emit();
self.err_handler().emit_err(error(span, "negative", false));
}
if let &Defaultness::Default(def_span) = defaultness {
error(def_span, "`default`")
.note("only trait implementations may be annotated with `default`")
.emit();
self.err_handler().emit_err(error(def_span, "`default`", true));
}
if let &Const::Yes(span) = constness {
error(span, "`const`")
.note("only trait implementations may be annotated with `const`")
.emit();
self.err_handler().emit_err(error(span, "`const`", true));
}
}
ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
self.check_defaultness(item.span, *defaultness);
if body.is_none() {
self.session.emit_err(FnWithoutBody {
self.session.emit_err(errors::FnWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
extern_block_suggestion: match sig.header.ext {
Extern::None => None,
Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit {
start_span,
end_span: item.span.shrink_to_hi(),
}),
Extern::Implicit(start_span) => {
Some(errors::ExternBlockSuggestion::Implicit {
start_span,
end_span: item.span.shrink_to_hi(),
})
}
Extern::Explicit(abi, start_span) => {
Some(ExternBlockSuggestion::Explicit {
Some(errors::ExternBlockSuggestion::Explicit {
start_span,
end_span: item.span.shrink_to_hi(),
abi: abi.symbol_unescaped,
@ -1085,10 +926,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
let old_item = mem::replace(&mut self.extern_mod, Some(item));
self.invalid_visibility(
&item.vis,
Some(InvalidVisibilityNote::IndividualForeignItems),
Some(errors::InvalidVisibilityNote::IndividualForeignItems),
);
if let &Unsafe::Yes(span) = unsafety {
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" });
}
if abi.is_none() {
self.maybe_lint_missing_abi(item.span, item.id);
@ -1128,7 +969,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::Mod(unsafety, mod_kind) => {
if let &Unsafe::Yes(span) = unsafety {
self.err_handler().span_err(span, "module cannot be declared unsafe");
self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" });
}
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
@ -1139,18 +980,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::Union(vdata, ..) => {
if vdata.fields().is_empty() {
self.err_handler().span_err(item.span, "unions cannot have zero fields");
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
}
}
ItemKind::Const(def, .., None) => {
self.check_defaultness(item.span, *def);
self.session.emit_err(ConstWithoutBody {
self.session.emit_err(errors::ConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
ItemKind::Static(.., None) => {
self.session.emit_err(StaticWithoutBody {
self.session.emit_err(errors::StaticWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
@ -1158,21 +999,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
self.check_defaultness(item.span, *defaultness);
if ty.is_none() {
self.session.emit_err(TyAliasWithoutBody {
self.session.emit_err(errors::TyAliasWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
self.check_type_no_bounds(bounds, "this context");
if where_clauses.1.0 {
let mut err = self.err_handler().struct_span_err(
where_clauses.1.1,
"where clauses are not allowed after the type for type aliases",
);
err.note(
"see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
);
err.emit();
self.err_handler()
.emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
}
}
_ => {}
@ -1254,11 +1089,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
if let Some(span) = prev_param_default {
let mut err = self.err_handler().struct_span_err(
span,
"generic parameters with a default must be trailing",
);
err.emit();
self.err_handler().emit_err(errors::GenericDefaultTrailing { span });
break;
}
}
@ -1286,13 +1117,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
match bound {
GenericBound::Trait(t, _) => {
if !t.bound_generic_params.is_empty() {
struct_span_err!(
self.err_handler(),
t.span,
E0316,
"nested quantification of lifetimes"
)
.emit();
self.err_handler()
.emit_err(errors::NestedLifetimes { span: t.span });
}
}
GenericBound::Outlives(_) => {}
@ -1317,32 +1143,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let GenericBound::Trait(poly, modify) = bound {
match (ctxt, modify) {
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
let mut err = self
.err_handler()
.struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
let path_str = pprust::path_to_string(&poly.trait_ref.path);
err.note(&format!("traits are `?{}` by default", path_str));
err.emit();
self.err_handler().emit_err(errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path)
});
}
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
let mut err = self.err_handler().struct_span_err(
poly.span,
"`?Trait` is not permitted in trait object types",
);
err.emit();
self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span});
}
(_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
match reason {
DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
let reason = match reason {
DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject,
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure,
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span },
};
err.emit();
self.err_handler().emit_err(errors::TildeConstDisallowed {
span: bound.span(),
reason
});
}
(_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler()
.span_err(bound.span(), "`~const` and `?` are mutually exclusive");
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()});
}
_ => {}
}
@ -1362,21 +1183,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_c_variadic_type(fk);
// Functions cannot both be `const async`
if let Some(FnHeader {
if let Some(&FnHeader {
constness: Const::Yes(cspan),
asyncness: Async::Yes { span: aspan, .. },
..
}) = fk.header()
{
self.err_handler()
.struct_span_err(
vec![*cspan, *aspan],
"functions cannot be both `const` and `async`",
)
.span_label(*cspan, "`const` because of this")
.span_label(*aspan, "`async` because of this")
.span_label(span, "") // Point at the fn header.
.emit();
self.err_handler().emit_err(errors::ConstAndAsync {
spans: vec![cspan, aspan],
cspan,
aspan,
span,
});
}
if let FnKind::Fn(
@ -1394,20 +1212,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
let (code, msg, label) = match ctxt {
FnCtxt::Foreign => (
error_code!(E0130),
"patterns aren't allowed in foreign function declarations",
"pattern not allowed in foreign function",
),
_ => (
error_code!(E0642),
"patterns aren't allowed in functions without bodies",
"pattern not allowed in function without body",
),
};
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
if let Some(ident) = ident {
let msg = match ctxt {
FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
_ => fluent::ast_passes_pattern_in_bodiless,
};
let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
self.lint_buffer.buffer_lint_with_diagnostic(
PATTERNS_IN_FNS_WITHOUT_BODY,
@ -1418,11 +1228,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
)
}
} else {
self.err_handler()
.struct_span_err(span, msg)
.span_label(span, label)
.code(code)
.emit();
match ctxt {
FnCtxt::Foreign => {
self.err_handler().emit_err(errors::PatternInForeign { span })
}
_ => self.err_handler().emit_err(errors::PatternInBodiless { span }),
};
}
});
}
@ -1449,7 +1260,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
match &item.kind {
AssocItemKind::Const(_, _, body) => {
if body.is_none() {
self.session.emit_err(AssocConstWithoutBody {
self.session.emit_err(errors::AssocConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
@ -1457,7 +1268,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() {
self.session.emit_err(AssocFnWithoutBody {
self.session.emit_err(errors::AssocFnWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
@ -1472,7 +1283,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
..
}) => {
if ty.is_none() {
self.session.emit_err(AssocTypeWithoutBody {
self.session.emit_err(errors::AssocTypeWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
@ -1544,11 +1355,7 @@ fn deny_equality_constraints(
predicate: &WhereEqPredicate,
generics: &Generics,
) {
let mut err = this.err_handler().struct_span_err(
predicate.span,
"equality constraints are not yet supported in `where` clauses",
);
err.span_label(predicate.span, "not supported");
let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None };
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
@ -1592,20 +1399,12 @@ fn deny_equality_constraints(
.into();
}
}
err.span_suggestion_verbose(
predicate.span,
&format!(
"if `{}` is an associated type you're trying to set, \
use the associated type binding syntax",
ident
),
format!(
"{}: {}",
param,
pprust::path_to_string(&assoc_path)
),
Applicability::MaybeIncorrect,
);
err.assoc = Some(errors::AssociatedSuggestion {
span: predicate.span,
ident: *ident,
param: *param,
path: pprust::path_to_string(&assoc_path),
})
}
_ => {}
};
@ -1647,15 +1446,13 @@ fn deny_equality_constraints(
trait_segment.span().shrink_to_hi(),
),
};
err.multipart_suggestion(
&format!(
"if `{}::{}` is an associated type you're trying to set, \
use the associated type binding syntax",
trait_segment.ident, potential_assoc.ident,
),
vec![(span, args), (predicate.span, String::new())],
Applicability::MaybeIncorrect,
);
err.assoc2 = Some(errors::AssociatedSuggestion2 {
span,
args,
predicate: predicate.span,
trait_segment: trait_segment.ident,
potential_assoc: potential_assoc.ident,
});
}
}
}
@ -1663,10 +1460,7 @@ fn deny_equality_constraints(
}
}
}
err.note(
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
);
err.emit();
this.err_handler().emit_err(err);
}
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {

View File

@ -1,9 +1,12 @@
//! Errors emitted by ast_passes.
use rustc_ast::ParamKindOrd;
use rustc_errors::AddToDiagnostic;
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use rustc_span::{symbol::Ident, Span, Symbol};
use crate::ast_validation::ForbiddenLetReason;
use crate::fluent_generated as fluent;
#[derive(Diagnostic)]
#[diag(ast_passes_forbidden_let)]
@ -217,3 +220,474 @@ pub enum ExternBlockSuggestion {
abi: Symbol,
},
}
#[derive(Diagnostic)]
#[diag(ast_passes_bound_in_context)]
pub struct BoundInContext<'a> {
#[primary_span]
pub span: Span,
pub ctx: &'a str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_extern_types_cannot)]
#[note(ast_passes_extern_keyword_link)]
pub struct ExternTypesCannotHave<'a> {
#[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect")]
pub span: Span,
pub descr: &'a str,
pub remove_descr: &'a str,
#[label]
pub block_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_body_in_extern)]
#[note(ast_passes_extern_keyword_link)]
pub struct BodyInExtern<'a> {
#[primary_span]
#[label(ast_passes_cannot_have)]
pub span: Span,
#[label(ast_passes_invalid)]
pub body: Span,
#[label(ast_passes_existing)]
pub block: Span,
pub kind: &'a str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_fn_body_extern)]
#[help]
#[note(ast_passes_extern_keyword_link)]
pub struct FnBodyInExtern {
#[primary_span]
#[label(ast_passes_cannot_have)]
pub span: Span,
#[suggestion(code = ";", applicability = "maybe-incorrect")]
pub body: Span,
#[label]
pub block: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_extern_fn_qualifiers)]
pub struct FnQualifierInExtern {
#[primary_span]
pub span: Span,
#[label]
pub block: Span,
#[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
pub sugg_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_extern_item_ascii)]
#[note]
pub struct ExternItemAscii {
#[primary_span]
pub span: Span,
#[label]
pub block: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_bad_c_variadic)]
pub struct BadCVariadic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_item_underscore)]
pub struct ItemUnderscore<'a> {
#[primary_span]
#[label]
pub span: Span,
pub kind: &'a str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_nomangle_ascii, code = "E0754")]
pub struct NoMangleAscii {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_module_nonascii, code = "E0754")]
#[help]
pub struct ModuleNonAscii {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(ast_passes_auto_generic, code = "E0567")]
pub struct AutoTraitGeneric {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
pub span: Span,
#[label]
pub ident: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_auto_super_lifetime, code = "E0568")]
pub struct AutoTraitBounds {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
pub span: Span,
#[label]
pub ident: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_auto_items, code = "E0380")]
pub struct AutoTraitItems {
#[primary_span]
pub spans: Vec<Span>,
#[suggestion(code = "", applicability = "machine-applicable")]
pub total: Span,
#[label]
pub ident: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_generic_before_constraints)]
pub struct ArgsBeforeConstraint {
#[primary_span]
pub arg_spans: Vec<Span>,
#[label(ast_passes_constraints)]
pub constraints: Span,
#[label(ast_passes_args)]
pub args: Span,
#[suggestion(code = "{suggestion}", applicability = "machine-applicable", style = "verbose")]
pub data: Span,
pub suggestion: String,
pub constraint_len: usize,
pub args_len: usize,
#[subdiagnostic]
pub constraint_spans: EmptyLabelManySpans,
#[subdiagnostic]
pub arg_spans2: EmptyLabelManySpans,
}
pub struct EmptyLabelManySpans(pub Vec<Span>);
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
impl AddToDiagnostic for EmptyLabelManySpans {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
where
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{
diag.span_labels(self.0, "");
}
}
#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")]
pub struct PatternFnPointer {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_trait_object_single_bound, code = "E0226")]
pub struct TraitObjectBound {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_impl_trait_path, code = "E0667")]
pub struct ImplTraitPath {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_nested_impl_trait, code = "E0666")]
pub struct NestedImplTrait {
#[primary_span]
pub span: Span,
#[label(ast_passes_outer)]
pub outer: Span,
#[label(ast_passes_inner)]
pub inner: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_at_least_one_trait)]
pub struct AtLeastOneTrait {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_out_of_order_params)]
pub struct OutOfOrderParams<'a> {
#[primary_span]
pub spans: Vec<Span>,
#[suggestion(code = "{ordered_params}", applicability = "machine-applicable")]
pub sugg_span: Span,
pub param_ord: &'a ParamKindOrd,
pub max_param: &'a ParamKindOrd,
pub ordered_params: &'a str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_obsolete_auto)]
#[help]
pub struct ObsoleteAuto {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_unsafe_negative_impl, code = "E0198")]
pub struct UnsafeNegativeImpl {
#[primary_span]
pub span: Span,
#[label(ast_passes_negative)]
pub negative: Span,
#[label(ast_passes_unsafe)]
pub r#unsafe: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_inherent_cannot_be)]
pub struct InherentImplCannot<'a> {
#[primary_span]
pub span: Span,
#[label(ast_passes_because)]
pub annotation_span: Span,
pub annotation: &'a str,
#[label(ast_passes_type)]
pub self_ty: Span,
#[note(ast_passes_only_trait)]
pub only_trait: Option<()>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_inherent_cannot_be, code = "E0197")]
pub struct InherentImplCannotUnsafe<'a> {
#[primary_span]
pub span: Span,
#[label(ast_passes_because)]
pub annotation_span: Span,
pub annotation: &'a str,
#[label(ast_passes_type)]
pub self_ty: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_unsafe_item)]
pub struct UnsafeItem {
#[primary_span]
pub span: Span,
pub kind: &'static str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_fieldless_union)]
pub struct FieldlessUnion {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_where_after_type_alias)]
#[note]
pub struct WhereAfterTypeAlias {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_generic_default_trailing)]
pub struct GenericDefaultTrailing {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_nested_lifetimes, code = "E0316")]
pub struct NestedLifetimes {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_optional_trait_supertrait)]
#[note]
pub struct OptionalTraitSupertrait {
#[primary_span]
pub span: Span,
pub path_str: String,
}
#[derive(Diagnostic)]
#[diag(ast_passes_optional_trait_object)]
pub struct OptionalTraitObject {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_tilde_const_disallowed)]
pub struct TildeConstDisallowed {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub reason: TildeConstReason,
}
#[derive(Subdiagnostic)]
pub enum TildeConstReason {
#[note(ast_passes_trait)]
TraitObject,
#[note(ast_passes_closure)]
Closure,
#[note(ast_passes_function)]
Function {
#[primary_span]
ident: Span,
},
}
#[derive(Diagnostic)]
#[diag(ast_passes_optional_const_exclusive)]
pub struct OptionalConstExclusive {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_const_and_async)]
pub struct ConstAndAsync {
#[primary_span]
pub spans: Vec<Span>,
#[label(ast_passes_const)]
pub cspan: Span,
#[label(ast_passes_async)]
pub aspan: Span,
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = "E0130")]
pub struct PatternInForeign {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_bodiless, code = "E0642")]
pub struct PatternInBodiless {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_equality_in_where)]
#[note]
pub struct EqualityInWhere {
#[primary_span]
#[label]
pub span: Span,
#[subdiagnostic]
pub assoc: Option<AssociatedSuggestion>,
#[subdiagnostic]
pub assoc2: Option<AssociatedSuggestion2>,
}
#[derive(Subdiagnostic)]
#[suggestion(
ast_passes_suggestion,
code = "{param}: {path}",
style = "verbose",
applicability = "maybe-incorrect"
)]
pub struct AssociatedSuggestion {
#[primary_span]
pub span: Span,
pub ident: Ident,
pub param: Ident,
pub path: String,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(ast_passes_suggestion_path, applicability = "maybe-incorrect")]
pub struct AssociatedSuggestion2 {
#[suggestion_part(code = "{args}")]
pub span: Span,
pub args: String,
#[suggestion_part(code = "")]
pub predicate: Span,
pub trait_segment: Ident,
pub potential_assoc: Ident,
}
#[derive(Diagnostic)]
#[diag(ast_passes_stability_outside_std, code = "E0734")]
pub struct StabilityOutsideStd {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_feature_on_non_nightly, code = "E0554")]
pub struct FeatureOnNonNightly {
#[primary_span]
pub span: Span,
pub channel: &'static str,
#[subdiagnostic]
pub stable_features: Vec<StableFeature>,
#[suggestion(code = "", applicability = "machine-applicable")]
pub sugg: Option<Span>,
}
pub struct StableFeature {
pub name: Symbol,
pub since: Symbol,
}
impl AddToDiagnostic for StableFeature {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
where
F: Fn(
&mut rustc_errors::Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{
diag.set_arg("name", self.name);
diag.set_arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);
}
}
#[derive(Diagnostic)]
#[diag(ast_passes_incompatbile_features)]
#[help]
pub struct IncompatibleFeatures {
#[primary_span]
pub spans: Vec<Span>,
pub f1: Symbol,
pub f2: Symbol,
}
#[derive(Diagnostic)]
#[diag(ast_passes_show_span)]
pub struct ShowSpan {
#[primary_span]
pub span: Span,
pub msg: &'static str,
}

View File

@ -2,7 +2,7 @@ use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd};
use rustc_errors::{struct_span_err, Applicability, StashKey};
use rustc_errors::{Applicability, StashKey};
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
use rustc_session::Session;
@ -13,7 +13,7 @@ use rustc_target::spec::abi;
use thin_vec::ThinVec;
use tracing::debug;
use crate::errors::ForbiddenLifetimeBound;
use crate::errors;
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
@ -164,7 +164,7 @@ impl<'a> PostExpansionVisitor<'a> {
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.sess.emit_err(ForbiddenLifetimeBound { spans });
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
}
}
}
@ -218,13 +218,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|| attr.has_name(sym::rustc_const_stable)
|| attr.has_name(sym::rustc_default_body_unstable)
{
struct_span_err!(
self.sess,
attr.span,
E0734,
"stability attributes may not be used outside of the standard library",
)
.emit();
self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span });
}
}
}
@ -635,13 +629,13 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
return;
}
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
let mut err = struct_span_err!(
sess.parse_sess.span_diagnostic,
attr.span,
E0554,
"`#![feature]` may not be used on the {} release channel",
option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
);
let mut err = errors::FeatureOnNonNightly {
span: attr.span,
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
stable_features: vec![],
sugg: None,
};
let mut all_stable = true;
for ident in
attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
@ -652,24 +646,15 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
.next();
if let Some(since) = stable_since {
err.help(&format!(
"the feature `{}` has been stable since {} and no longer requires \
an attribute to enable",
name, since
));
err.stable_features.push(errors::StableFeature { name, since });
} else {
all_stable = false;
}
}
if all_stable {
err.span_suggestion(
attr.span,
"remove the attribute",
"",
Applicability::MachineApplicable,
);
err.sugg = Some(attr.span);
}
err.emit();
sess.parse_sess.span_diagnostic.emit_err(err);
}
}
}
@ -692,16 +677,7 @@ fn check_incompatible_features(sess: &Session) {
if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
{
let spans = vec![f1_span, f2_span];
sess.struct_span_err(
spans,
&format!(
"features `{}` and `{}` are incompatible, using them at the same time \
is not allowed",
f1_name, f2_name
),
)
.help("remove one of these features")
.emit();
sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
}
}
}

View File

@ -10,6 +10,8 @@
#![feature(iter_is_partitioned)]
#![feature(let_chains)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_macros::fluent_messages;

View File

@ -9,6 +9,8 @@ use rustc_ast as ast;
use rustc_ast::visit;
use rustc_ast::visit::Visitor;
use crate::errors;
enum Mode {
Expression,
Pattern,
@ -36,21 +38,21 @@ struct ShowSpanVisitor<'a> {
impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
fn visit_expr(&mut self, e: &'a ast::Expr) {
if let Mode::Expression = self.mode {
self.span_diagnostic.span_warn(e.span, "expression");
self.span_diagnostic.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" });
}
visit::walk_expr(self, e);
}
fn visit_pat(&mut self, p: &'a ast::Pat) {
if let Mode::Pattern = self.mode {
self.span_diagnostic.span_warn(p.span, "pattern");
self.span_diagnostic.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" });
}
visit::walk_pat(self, p);
}
fn visit_ty(&mut self, t: &'a ast::Ty) {
if let Mode::Type = self.mode {
self.span_diagnostic.span_warn(t.span, "type");
self.span_diagnostic.emit_warning(errors::ShowSpan { span: t.span, msg: "type" });
}
visit::walk_ty(self, t);
}

View File

@ -253,6 +253,7 @@ E0466: include_str!("./error_codes/E0466.md"),
E0468: include_str!("./error_codes/E0468.md"),
E0469: include_str!("./error_codes/E0469.md"),
E0472: include_str!("./error_codes/E0472.md"),
E0476: include_str!("./error_codes/E0476.md"),
E0477: include_str!("./error_codes/E0477.md"),
E0478: include_str!("./error_codes/E0478.md"),
E0482: include_str!("./error_codes/E0482.md"),
@ -611,7 +612,6 @@ E0793: include_str!("./error_codes/E0793.md"),
// E0473, // dereference of reference outside its lifetime
// E0474, // captured variable `..` does not outlive the enclosing closure
// E0475, // index of slice outside its lifetime
E0476, // lifetime of the source pointer does not outlive lifetime bound...
// E0479, // the type `..` (provided as the value of a type parameter) is...
// E0480, // lifetime of method receiver does not outlive the method call
// E0481, // lifetime of function argument does not outlive the function call

View File

@ -0,0 +1,21 @@
The coerced type does not outlive the value being coerced to.
Example of erroneous code:
```compile_fail,E0476
#![feature(coerce_unsized)]
#![feature(unsize)]
use std::marker::Unsize;
use std::ops::CoerceUnsized;
// error: lifetime of the source pointer does not outlive lifetime bound of the
// object type
impl<'a, 'b, T, S> CoerceUnsized<&'a T> for &'b S where S: Unsize<T> {}
```
During a coercion, the "source pointer" (the coerced type) did not outlive the
"object type" (value being coerced to). In the above example, `'b` is not a
subtype of `'a`. This error can currently only be encountered with the unstable
`CoerceUnsized` trait which allows custom coercions of unsized types behind a
smart pointer to be implemented.

View File

@ -54,6 +54,7 @@ macro_rules! into_diagnostic_arg_using_display {
}
into_diagnostic_arg_using_display!(
ast::ParamKindOrd,
i8,
u8,
i16,

View File

@ -129,3 +129,7 @@ expand_module_multiple_candidates =
.help = delete or rename one of them to remove the ambiguity
expand_trace_macro = trace_macro
expand_proc_macro_panicked =
proc macro panicked
.help = message: {$message}

View File

@ -375,3 +375,18 @@ pub struct TraceMacro {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_proc_macro_panicked)]
pub(crate) struct ProcMacroPanicked {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub message: Option<ProcMacroPanickedHelp>,
}
#[derive(Subdiagnostic)]
#[help(expand_help)]
pub(crate) struct ProcMacroPanickedHelp {
pub message: String,
}

View File

@ -1,4 +1,5 @@
use crate::base::{self, *};
use crate::errors;
use crate::proc_macro_server;
use rustc_ast as ast;
@ -60,11 +61,12 @@ impl base::BangProcMacro for BangProcMacro {
let strategy = exec_strategy(ecx);
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
let mut err = ecx.struct_span_err(span, "proc macro panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
}
err.emit()
ecx.sess.emit_err(errors::ProcMacroPanicked {
span,
message: e
.as_str()
.map(|message| errors::ProcMacroPanickedHelp { message: message.into() }),
})
})
}
}

View File

@ -24,6 +24,13 @@ lint_for_loops_over_fallibles =
.use_while_let = to check pattern in a loop use `while let`
.use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
.note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
.function_label = this function returns `()`, which is likely not what you wanted
.argument_label = called `Iterator::map` with callable that returns `()`
.map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
.suggestion = you might have meant to use `Iterator::for_each`
lint_non_binding_let_on_sync_lock =
non-binding let on a synchronization lock

View File

@ -63,6 +63,7 @@ mod late;
mod let_underscore;
mod levels;
mod lints;
mod map_unit_fn;
mod methods;
mod multiple_supertrait_upcastable;
mod non_ascii_idents;
@ -100,6 +101,7 @@ use for_loops_over_fallibles::*;
use hidden_unicode_codepoints::*;
use internal::*;
use let_underscore::*;
use map_unit_fn::*;
use methods::*;
use multiple_supertrait_upcastable::*;
use non_ascii_idents::*;
@ -239,6 +241,7 @@ late_lint_methods!(
NamedAsmLabels: NamedAsmLabels,
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
MapUnitFn: MapUnitFn,
]
]
);
@ -298,7 +301,8 @@ fn register_builtins(store: &mut LintStore) {
UNUSED_LABELS,
UNUSED_PARENS,
UNUSED_BRACES,
REDUNDANT_SEMICOLONS
REDUNDANT_SEMICOLONS,
MAP_UNIT_FN
);
add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK);

View File

@ -748,6 +748,22 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
}
}
// map_unit_fn.rs
#[derive(LintDiagnostic)]
#[diag(lint_map_unit_fn)]
#[note]
pub struct MappingToUnit {
#[label(lint_function_label)]
pub function_label: Span,
#[label(lint_argument_label)]
pub argument_label: Span,
#[label(lint_map_label)]
pub map_label: Span,
#[suggestion(style = "verbose", code = "{replace}", applicability = "maybe-incorrect")]
pub suggestion: Span,
pub replace: String,
}
// internal.rs
#[derive(LintDiagnostic)]
#[diag(lint_default_hash_types)]

View File

@ -0,0 +1,120 @@
use crate::lints::MappingToUnit;
use crate::{LateContext, LateLintPass, LintContext};
use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind};
use rustc_middle::{
query::Key,
ty::{self, Ty},
};
declare_lint! {
/// The `map_unit_fn` lint checks for `Iterator::map` receive
/// a callable that returns `()`.
///
/// ### Example
///
/// ```rust
/// fn foo(items: &mut Vec<u8>) {
/// items.sort();
/// }
///
/// fn main() {
/// let mut x: Vec<Vec<u8>> = vec![
/// vec![0, 2, 1],
/// vec![5, 4, 3],
/// ];
/// x.iter_mut().map(foo);
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Mapping to `()` is almost always a mistake.
pub MAP_UNIT_FN,
Warn,
"`Iterator::map` call that discard the iterator's values"
}
declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]);
impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
if stmt.span.from_expansion() {
return;
}
if let StmtKind::Semi(expr) = stmt.kind {
if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind {
if path.ident.name.as_str() == "map" {
if receiver.span.from_expansion()
|| args.iter().any(|e| e.span.from_expansion())
|| !is_impl_slice(cx, receiver)
|| !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
{
return;
}
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
if let ty::FnDef(id, _) = arg_ty.kind() {
let fn_ty = cx.tcx.fn_sig(id).skip_binder();
let ret_ty = fn_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_spanned_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx.tcx.span_of_impl(*id).unwrap(),
argument_label: args[0].span,
map_label: arg_ty.default_span(cx.tcx),
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
} else if let ty::Closure(id, subs) = arg_ty.kind() {
let cl_ty = subs.as_closure().sig();
let ret_ty = cl_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_spanned_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx.tcx.span_of_impl(*id).unwrap(),
argument_label: args[0].span,
map_label: arg_ty.default_span(cx.tcx),
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
}
}
}
}
}
}
fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if let Some(impl_id) = cx.tcx.impl_of_method(method_id) {
return cx.tcx.type_of(impl_id).skip_binder().is_slice();
}
}
false
}
fn is_unit_type(ty: Ty<'_>) -> bool {
ty.is_unit() || ty.is_never()
}
fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool {
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) {
if let Some(item) = cx.tcx.get_diagnostic_name(def_id) {
if item.as_str() == name {
return true;
}
}
}
false
}

View File

@ -748,7 +748,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty(self_ty);
c.visit_trait_ref(t);
if c.fully_stable {
// do not lint when the trait isn't resolved, since resolution error should
// be fixed first
if t.path.res != Res::Err && c.fully_stable {
self.tcx.struct_span_lint_hir(
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(),

View File

@ -278,6 +278,7 @@
//!
//! ```
//! # #![allow(unused_must_use)]
//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))]
//! let v = vec![1, 2, 3, 4, 5];
//! v.iter().map(|x| println!("{x}"));
//! ```

View File

@ -789,6 +789,7 @@ pub trait Iterator {
/// println!("{x}");
/// }
/// ```
#[rustc_diagnostic_item = "IteratorMap"]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_do_not_const_check]

View File

@ -7,11 +7,9 @@ edition = "2021"
crate-type = ["dylib", "rlib"]
[dependencies]
cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
std = { path = "../std" }
core = { path = "../core" }
libc = { version = "0.2", default-features = false }
panic_unwind = { path = "../panic_unwind" }
panic_abort = { path = "../panic_abort" }

View File

@ -4,6 +4,20 @@
nav {
display: none;
}
body {
font-family: serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: sans-serif;
}
h3 {
font-size: 1.35rem;
}
h4 {
font-size: 1.1rem;
}
/* Formatting for docs search bar */
#search-input {
width: calc(100% - 58px);
}
@ -21,53 +35,74 @@ nav {
#search-but:hover, #search-input:focus {
border-color: #55a9ff;
}
h2 {
font-size: 18px;
/* Formatting for external link icon */
svg.external-link {
display: inline-block;
position: relative;
vertical-align: super;
width: 0.7rem;
height: 0.7rem;
padding-left: 2px;
top: 3px;
}
</style>
Welcome to an overview of the documentation provided by the [Rust project].
All of these projects are managed by the Docs Team; there are other
unofficial documentation resources as well!
Welcome to an overview of the documentation provided by the [Rust
project]. This page contains links to various helpful references,
most of which are available offline (if opened with `rustup doc`). Many of these
resources take the form of "books"; we collectively call these "The Rust
Bookshelf." Some are large, some are small.
Many of these resources take the form of "books"; we collectively call these
"The Rust Bookshelf." Some are large, some are small.
All of these books are managed by the Rust Organization, but other unofficial
documentation resources are included here as well!
# Learn Rust
If you're just looking for the standard library reference, here it is:
[Rust API documentation](std/index.html)
If you'd like to learn Rust, this is the spot for you! All of these resources
## Learning Rust
If you'd like to learn Rust, this is the section for you! All of these resources
assume that you have programmed before, but not in any specific language:
## The Rust Programming Language
### The Rust Programming Language
Affectionately nicknamed "the book," [The Rust Programming
Language](book/index.html) will give you an overview of the language from
first principles. You'll build a few projects along the way, and by the end,
you'll have a solid grasp of the language.
Affectionately nicknamed "the book," [The Rust Programming Language](book/index.html)
will give you an overview of the language from first principles. You'll build a
few projects along the way, and by the end, you'll have a solid grasp of how to
use the language.
## Rust By Example
### Rust By Example
If reading multiple hundreds of pages about a language isn't your style, then
[Rust By Example](rust-by-example/index.html) has you covered. While the book talks about code with
a lot of words, RBE shows off a bunch of code, and keeps the talking to a
minimum. It also includes exercises!
[Rust By Example](rust-by-example/index.html) has you covered. RBE shows off a
bunch of code without using a lot of words. It also includes exercises!
## Rustlings
### Rustlings
[Rustlings](https://github.com/rust-lang/rustlings) guides you through downloading and setting up the Rust toolchain,
and teaches you the basics of reading and writing Rust syntax. It's an
alternative to Rust by Example that works with your own environment.
[Rustlings](https://github.com/rust-lang/rustlings) guides you
through downloading and setting up the Rust toolchain, then provides an
interactive tool that teaches you how to solve coding challenges in Rust.
# Use Rust
### Rust Playground
Once you've gotten familiar with the language, these resources can help you
when you're actually using it day-to-day.
The [Rust Playground](https://play.rust-lang.org) is a great place
to try out and share small bits of code, or experiment with some of the most
popular crates.
## The Standard Library
Rust's standard library has [extensive API documentation](std/index.html),
with explanations of how to use various things, as well as example code for
accomplishing various tasks.
## Using Rust
Once you've gotten familiar with the language, these resources can help you put
it to work.
### The Standard Library
Rust's standard library has [extensive API documentation](std/index.html), with
explanations of how to use various things, as well as example code for
accomplishing various tasks. Code examples have a "Run" button on hover that
opens the sample in the playground.
<div>
<form action="std/index.html" method="get">
@ -77,76 +112,143 @@ accomplishing various tasks.
</form>
</div>
## The Edition Guide
### Your Personal Documentation
[The Edition Guide](edition-guide/index.html) describes the Rust editions.
Whenever you are working in a crate, `cargo doc --open` will generate
documentation for your project _and_ all its dependencies in their correct
version, and open it in your browser. Add the flag `--document-private-items` to
also show items not marked `pub`.
## The Rustc Book
### The Edition Guide
[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`.
[The Edition Guide](edition-guide/index.html) describes the Rust editions and
their differences.
## The Cargo Book
### The `rustc` Book
[The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and dependency manager.
[The `rustc` Book](rustc/index.html) describes the Rust compiler, `rustc`.
## The Rustdoc Book
### The Cargo Book
[The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and
dependency manager.
### The Rustdoc Book
[The Rustdoc Book](rustdoc/index.html) describes our documentation tool, `rustdoc`.
## The Clippy Book
### The Clippy Book
[The Clippy Book](clippy/index.html) describes our static analyzer, Clippy.
## Extended Error Listing
### Extended Error Listing
Many of Rust's errors come with error codes, and you can request extended
diagnostics from the compiler on those errors. You can also [read them
here](error_codes/index.html), if you prefer to read them that way.
diagnostics from the compiler on those errors (with `rustc --explain`). You can
also read them here if you prefer: [rustc error codes](error_codes/index.html)
# Master Rust
## Mastering Rust
Once you're quite familiar with the language, you may find these advanced
resources useful.
## The Reference
### The Reference
[The Reference](reference/index.html) is not a formal spec, but is more detailed and
comprehensive than the book.
[The Reference](reference/index.html) is not a formal spec, but is more detailed
and comprehensive than the book.
## The Style Guide
### The Style Guide
[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
code. Most developers use rustfmt to format their code, and rustfmt's default
formatting matches this style guide.
[The Rust Style Guide](style-guide/index.html) describes the standard formatting
of Rust code. Most developers use `cargo fmt` to invoke `rustfmt` and format the
code automatically (the result matches this style guide).
## The Rustonomicon
### The Rustonomicon
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
Rust. It's also sometimes called "the 'nomicon."
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of
unsafe Rust. It's also sometimes called "the 'nomicon."
## The Unstable Book
### The Unstable Book
[The Unstable Book](unstable-book/index.html) has documentation for unstable features.
[The Unstable Book](unstable-book/index.html) has documentation for unstable
features.
## The `rustc` Contribution Guide
### The `rustc` Contribution Guide
[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/) documents how
the compiler works and how to contribute to it. This is useful if you want to build
or modify the Rust compiler from source (e.g. to target something non-standard).
[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/)
documents how the compiler works and how to contribute to it. This is useful if
you want to build or modify the Rust compiler from source (e.g. to target
something non-standard).
# Specialize Rust
When using Rust in specific domain areas, consider using the following resources tailored to each domain.
## Specialized Rust
## Embedded Systems
When using Rust in specific domains, consider using the following resources
tailored to each area.
When developing for Bare Metal or Embedded Linux systems, you may find these resources maintained by the [Embedded Working Group] useful.
### Embedded Systems
When developing for Bare Metal or Embedded Linux systems, you may find these
resources maintained by the [Embedded Working Group] useful.
[Embedded Working Group]: https://github.com/rust-embedded
### The Embedded Rust Book
#### The Embedded Rust Book
[The Embedded Rust Book] is targeted at developers familiar with embedded development and familiar with Rust, but have not used Rust for embedded development.
[The Embedded Rust Book] is targeted at developers familiar with embedded
development and familiar with Rust, but have not used Rust for embedded
development.
[The Embedded Rust Book]: embedded-book/index.html
[Rust project]: https://www.rust-lang.org
<script>
// check if a given link is external
function isExternalLink(url) {
const tmp = document.createElement('a');
tmp.href = url;
return tmp.host !== window.location.host;
}
// Add the `external` class to all <a> tags with external links and append the external link SVG
function updateExternalAnchors() {
/*
External link SVG from Font-Awesome
CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0
via Wikimedia Commons
*/
const svgText = `<svg
class='external-link'
xmlns='http://www.w3.org/2000/svg'
viewBox='0 -256 1850 1850'
width='100%'
height='100%'>
<g transform='matrix(1,0,0,-1,30,1427)'>
<path d='M 1408,608 V 288 Q 1408,169 1323.5,84.5 1239,0 1120,
0 H 288 Q 169,0 84.5,84.5 0,169 0,288 v 832 Q 0,1239 84.5,1323.5 169,
1408 288,1408 h 704 q 14,0 23,-9 9,-9 9,-23 v -64 q 0,-14 -9,-23 -9,
-9 -23,-9 H 288 q -66,0 -113,-47 -47,-47 -47,-113 V 288 q 0,-66 47,
-113 47,-47 113,-47 h 832 q 66,0 113,47 47,47 47,113 v 320 q 0,14 9,
23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 384,864 V 960 q 0,
-26 -19,-45 -19,-19 -45,-19 -26,0 -45,19 L 1507,1091 855,439 q -10,
-10 -23,-10 -13,0 -23,10 L 695,553 q -10,10 -10,23 0,13 10,23 l 652,
652 -176,176 q -19,19 -19,45 0,26 19,45 19,19 45,19 h 512 q 26,0 45,
-19 19,-19 19,-45 z' style='fill:currentColor' />
</g>
</svg>`;
let allAnchors = document.getElementsByTagName("a");
for (var i = 0; i < allAnchors.length; ++i) {
let anchor = allAnchors[i];
if (isExternalLink(anchor.href)) {
anchor.classList.add("external");
anchor.innerHTML += svgText;
}
}
}
// on page load, update external anchors
document.addEventListener("DOMContentLoaded", updateExternalAnchors);
</script>

View File

@ -22,7 +22,7 @@ macro_rules! register_diagnostics {
pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> {
let mut errors: Vec<(&str, Option<&str>)> = vec![
$((stringify!($error_code), Some($message)),)+
$((stringify!($undocumented), None),)+
$((stringify!($undocumented), None),)*
];
errors.sort();
errors

View File

@ -31,7 +31,7 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E06
// Error codes that don't yet have a UI test. This list will eventually be removed.
const IGNORE_UI_TEST_CHECK: &[&str] =
&["E0461", "E0465", "E0476", "E0514", "E0554", "E0640", "E0717", "E0729"];
&["E0461", "E0465", "E0514", "E0554", "E0640", "E0717", "E0729"];
macro_rules! verbose_print {
($verbose:expr, $($fmt:tt)*) => {

View File

@ -0,0 +1,9 @@
// compile-flags: -C panic=abort
#![no_std]
#![no_main]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}

View File

@ -0,0 +1,12 @@
// aux-build:panic-handler.rs
// compile-flags: --document-private-items
// build-pass
// ignore-windows
#![no_std]
#![no_main]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}

View File

@ -12,7 +12,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Bound : Copy {}
| -----^^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error[E0568]: auto traits cannot have super traits or lifetime bounds
--> $DIR/auto-trait-validation.rs:9:25
@ -20,7 +20,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait LifetimeBound : 'static {}
| -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error[E0380]: auto traits cannot have associated items
--> $DIR/auto-trait-validation.rs:11:25
@ -29,7 +29,7 @@ LL | auto trait MyTrait { fn foo() {} }
| ------- ---^^^-----
| | |
| | help: remove these associated items
| auto trait cannot have associated items
| auto traits cannot have associated items
error: aborting due to 4 previous errors

View File

@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
--> $DIR/issue-23080-2.rs:5:10
|
LL | unsafe auto trait Trait {
| ----- auto trait cannot have associated items
| ----- auto traits cannot have associated items
LL | type Output;
| -----^^^^^^- help: remove these associated items

View File

@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
--> $DIR/issue-23080.rs:5:8
|
LL | unsafe auto trait Trait {
| ----- auto trait cannot have associated items
| ----- auto traits cannot have associated items
LL | fn method(&self) {
| _____- ^^^^^^
LL | | println!("Hello");

View File

@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Magic where Self: Copy {}
| ----- ^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error: aborting due to previous error

View File

@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Magic : Sized where Option<Self> : Magic {}
| -----^^^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error[E0568]: auto traits cannot have super traits or lifetime bounds
--> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:26
@ -12,7 +12,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Magic : Sized where Option<Self> : Magic {}
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error: aborting due to 2 previous errors

View File

@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Magic: Copy {}
| -----^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error: aborting due to previous error

View File

@ -0,0 +1,13 @@
#![feature(coerce_unsized)]
#![feature(unsize)]
use std::marker::Unsize;
use std::ops::CoerceUnsized;
struct Wrapper<T>(T);
impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
//~^ ERROR lifetime of the source pointer does not outlive lifetime bound of the object type [E0476]
//~^^ ERROR E0119
fn main() {}

View File

@ -0,0 +1,31 @@
error[E0119]: conflicting implementations of trait `CoerceUnsized<&Wrapper<_>>` for type `&Wrapper<_>`
--> $DIR/E0476.rs:9:1
|
LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
where 'b: 'a, T: Unsize<U>, T: ?Sized, U: ?Sized;
error[E0476]: lifetime of the source pointer does not outlive lifetime bound of the object type
--> $DIR/E0476.rs:9:1
|
LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: object type is valid for the lifetime `'a` as defined here
--> $DIR/E0476.rs:9:6
|
LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
| ^^
note: source pointer is only valid for the lifetime `'b` as defined here
--> $DIR/E0476.rs:9:10
|
LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
| ^^
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0119, E0476.
For more information about an error, try `rustc --explain E0119`.

View File

@ -0,0 +1,13 @@
fn foo(items: &mut Vec<u8>) {
items.sort();
}
fn bar() -> impl Iterator<Item = i32> {
//~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271]
let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
x.iter_mut().map(foo)
}
fn main() {
bar();
}

View File

@ -0,0 +1,11 @@
error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()`
--> $DIR/issue-106991.rs:5:13
|
LL | fn bar() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32`
|
= note: required for `Map<std::slice::IterMut<'_, Vec<u8>>, for<'a> fn(&'a mut Vec<u8>) {foo}>` to implement `Iterator`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.

View File

@ -0,0 +1,20 @@
#![deny(map_unit_fn)]
fn foo(items: &mut Vec<u8>) {
items.sort();
}
fn main() {
let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
x.iter_mut().map(foo);
//~^ ERROR `Iterator::map` call that discard the iterator's values
x.iter_mut().map(|items| {
//~^ ERROR `Iterator::map` call that discard the iterator's values
items.sort();
});
let f = |items: &mut Vec<u8>| {
items.sort();
};
x.iter_mut().map(f);
//~^ ERROR `Iterator::map` call that discard the iterator's values
}

View File

@ -0,0 +1,66 @@
error: `Iterator::map` call that discard the iterator's values
--> $DIR/lint_map_unit_fn.rs:9:18
|
LL | fn foo(items: &mut Vec<u8>) {
| --------------------------- this function returns `()`, which is likely not what you wanted
...
LL | x.iter_mut().map(foo);
| ^^^^---^
| | |
| | called `Iterator::map` with callable that returns `()`
| after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
|
= note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
note: the lint level is defined here
--> $DIR/lint_map_unit_fn.rs:1:9
|
LL | #![deny(map_unit_fn)]
| ^^^^^^^^^^^
help: you might have meant to use `Iterator::for_each`
|
LL | x.iter_mut().for_each(foo);
| ~~~~~~~~
error: `Iterator::map` call that discard the iterator's values
--> $DIR/lint_map_unit_fn.rs:11:18
|
LL | x.iter_mut().map(|items| {
| ^ -------
| | |
| ____________________|___this function returns `()`, which is likely not what you wanted
| | __________________|
| | |
LL | | |
LL | | | items.sort();
LL | | | });
| | | -^ after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
| | |_____||
| |_______|
| called `Iterator::map` with callable that returns `()`
|
= note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
help: you might have meant to use `Iterator::for_each`
|
LL | x.iter_mut().for_each(|items| {
| ~~~~~~~~
error: `Iterator::map` call that discard the iterator's values
--> $DIR/lint_map_unit_fn.rs:18:18
|
LL | let f = |items: &mut Vec<u8>| {
| --------------------- this function returns `()`, which is likely not what you wanted
...
LL | x.iter_mut().map(f);
| ^^^^-^
| | |
| | called `Iterator::map` with callable that returns `()`
| after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
|
= note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
help: you might have meant to use `Iterator::for_each`
|
LL | x.iter_mut().for_each(f);
| ~~~~~~~~
error: aborting due to 3 previous errors

View File

@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
--> $DIR/issue-105732.rs:4:8
|
LL | auto trait Foo {
| --- auto trait cannot have associated items
| --- auto traits cannot have associated items
LL | fn g(&self);
| ---^-------- help: remove these associated items

View File

@ -12,7 +12,7 @@ error[E0754]: trying to load file for module `řųśť` with non-ascii identifie
LL | mod řųśť;
| ^^^^
|
= help: consider using `#[path]` attribute to specify filesystem path
= help: consider using the `#[path]` attribute to specify filesystem path
error: aborting due to 2 previous errors

View File

@ -0,0 +1,8 @@
#![feature(staged_api)]
#![stable(feature = "uwu", since = "1.0.0")]
#[unstable(feature = "foo", issue = "none")]
impl Foo for () {}
//~^ ERROR cannot find trait `Foo` in this scope
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0405]: cannot find trait `Foo` in this scope
--> $DIR/unresolved_stability_lint.rs:5:6
|
LL | impl Foo for () {}
| ^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0405`.

View File

@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
LL | auto trait Magic: Copy {}
| -----^^^^^^ help: remove the super traits or lifetime bounds
| |
| auto trait cannot have super traits or lifetime bounds
| auto traits cannot have super traits or lifetime bounds
error[E0277]: the trait bound `NoClone: Copy` is not satisfied
--> $DIR/supertrait-auto-trait.rs:16:23