2024-04-17 19:21:11 +00:00
|
|
|
//! Validate AST before lowering it to HIR.
|
|
|
|
|
//!
|
|
|
|
|
//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest
|
|
|
|
|
//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing
|
2024-04-17 19:37:27 +00:00
|
|
|
//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a
|
|
|
|
|
//! function without body outside of a trait definition:
|
|
|
|
|
//!
|
|
|
|
|
//! ```ignore (illustrative)
|
|
|
|
|
//! #[my_attribute]
|
|
|
|
|
//! mod foo {
|
|
|
|
|
//! fn missing_body();
|
|
|
|
|
//! }
|
|
|
|
|
//! ```
|
2024-04-17 19:21:11 +00:00
|
|
|
//!
|
|
|
|
|
//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous
|
|
|
|
|
//! constructions produced by proc macros. This pass is only intended for simple checks that do not
|
|
|
|
|
//! require name resolution or type checking, or other kinds of complex analysis.
|
2016-05-22 17:51:22 +03:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
use std::mem;
|
2021-11-25 01:38:05 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2020-04-05 16:34:16 -07:00
|
|
|
use itertools::{Either, Itertools};
|
2025-02-05 12:22:28 -08:00
|
|
|
use rustc_abi::ExternAbi;
|
2020-03-11 09:17:55 -07:00
|
|
|
use rustc_ast::ptr::P;
|
2024-02-24 15:22:42 -05:00
|
|
|
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::*;
|
2021-10-19 18:45:48 -04:00
|
|
|
use rustc_ast_pretty::pprust::{self, State};
|
2023-03-04 12:39:54 +00:00
|
|
|
use rustc_data_structures::fx::FxIndexMap;
|
2024-06-18 10:35:56 +00:00
|
|
|
use rustc_errors::DiagCtxtHandle;
|
2023-08-09 20:28:00 +08:00
|
|
|
use rustc_feature::Features;
|
2019-10-15 22:48:13 +02:00
|
|
|
use rustc_parse::validate_attr;
|
2021-08-25 13:38:14 +00:00
|
|
|
use rustc_session::Session;
|
2022-02-07 01:23:37 -05:00
|
|
|
use rustc_session::lint::builtin::{
|
2024-05-21 12:27:21 -03:00
|
|
|
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
|
|
|
|
PATTERNS_IN_FNS_WITHOUT_BODY,
|
2022-02-07 01:23:37 -05:00
|
|
|
};
|
2024-02-29 16:40:44 +11:00
|
|
|
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
2024-12-13 10:29:23 +11:00
|
|
|
use rustc_span::{Ident, Span, kw, sym};
|
2023-01-30 14:37:06 +11:00
|
|
|
use thin_vec::thin_vec;
|
2016-05-22 17:51:22 +03:00
|
|
|
|
2024-07-09 09:54:19 +00:00
|
|
|
use crate::errors::{self, TildeConstReason};
|
2022-08-17 23:51:01 +09:00
|
|
|
|
2020-01-29 01:30:01 +01:00
|
|
|
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
|
|
|
|
|
enum SelfSemantic {
|
|
|
|
|
Yes,
|
|
|
|
|
No,
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-09 08:54:11 +00:00
|
|
|
enum TraitOrTraitImpl {
|
2025-04-02 14:21:33 +11:00
|
|
|
Trait { span: Span, constness_span: Option<Span> },
|
|
|
|
|
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
|
2024-01-02 00:57:30 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 08:54:11 +00:00
|
|
|
impl TraitOrTraitImpl {
|
2024-01-02 00:57:30 +01:00
|
|
|
fn constness(&self) -> Option<Span> {
|
|
|
|
|
match self {
|
2025-04-02 14:21:33 +11:00
|
|
|
Self::Trait { constness_span: Some(span), .. }
|
2024-01-02 00:57:30 +01:00
|
|
|
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-06 15:54:44 +03:00
|
|
|
struct AstValidator<'a> {
|
2024-09-16 09:30:45 +10:00
|
|
|
sess: &'a Session,
|
2023-08-09 20:28:00 +08:00
|
|
|
features: &'a Features,
|
2020-01-30 00:18:54 +01:00
|
|
|
|
|
|
|
|
/// The span of the `extern` in an `extern { ... }` block, if any.
|
2025-04-02 14:21:33 +11:00
|
|
|
extern_mod_span: Option<Span>,
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2024-07-09 08:54:11 +00:00
|
|
|
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
|
2021-08-25 11:53:16 +00:00
|
|
|
|
2019-01-17 07:28:39 +01:00
|
|
|
has_proc_macro_decls: bool,
|
2019-01-18 12:35:14 +01:00
|
|
|
|
2019-05-05 14:06:04 +02:00
|
|
|
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
|
|
|
|
|
/// Nested `impl Trait` _is_ allowed in associated type position,
|
2019-02-28 22:43:53 +00:00
|
|
|
/// e.g., `impl Iterator<Item = impl Debug>`.
|
2025-04-02 14:21:33 +11:00
|
|
|
outer_impl_trait_span: Option<Span>,
|
2019-01-18 12:35:14 +01:00
|
|
|
|
2024-07-09 09:54:19 +00:00
|
|
|
disallow_tilde_const: Option<TildeConstReason>,
|
2020-01-04 16:29:45 -08:00
|
|
|
|
2024-05-27 15:35:34 -03:00
|
|
|
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
|
|
|
|
extern_mod_safety: Option<Safety>,
|
|
|
|
|
|
2025-05-03 15:18:30 +02:00
|
|
|
lint_node_id: NodeId,
|
|
|
|
|
|
2024-09-30 21:07:36 +03:00
|
|
|
is_sdylib_interface: bool,
|
|
|
|
|
|
2020-01-05 09:40:16 +01:00
|
|
|
lint_buffer: &'a mut LintBuffer,
|
2019-05-15 16:02:51 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-06 15:54:44 +03:00
|
|
|
impl<'a> AstValidator<'a> {
|
2021-08-25 11:53:16 +00:00
|
|
|
fn with_in_trait_impl(
|
|
|
|
|
&mut self,
|
2024-01-02 00:57:30 +01:00
|
|
|
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
|
2021-08-25 11:53:16 +00:00
|
|
|
f: impl FnOnce(&mut Self),
|
|
|
|
|
) {
|
2024-01-02 00:57:30 +01:00
|
|
|
let old = mem::replace(
|
|
|
|
|
&mut self.outer_trait_or_trait_impl,
|
|
|
|
|
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
|
|
|
|
constness,
|
|
|
|
|
polarity,
|
2025-04-02 14:21:33 +11:00
|
|
|
trait_ref_span: trait_ref.path.span,
|
2024-01-02 00:57:30 +01:00
|
|
|
}),
|
2023-09-27 17:25:31 -04:00
|
|
|
);
|
2020-02-05 12:27:45 +01:00
|
|
|
f(self);
|
2024-01-02 00:57:30 +01:00
|
|
|
self.outer_trait_or_trait_impl = old;
|
2023-09-27 17:25:31 -04:00
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
fn with_in_trait(
|
|
|
|
|
&mut self,
|
|
|
|
|
span: Span,
|
|
|
|
|
constness_span: Option<Span>,
|
|
|
|
|
f: impl FnOnce(&mut Self),
|
|
|
|
|
) {
|
2024-01-02 00:57:30 +01:00
|
|
|
let old = mem::replace(
|
|
|
|
|
&mut self.outer_trait_or_trait_impl,
|
2025-04-02 14:21:33 +11:00
|
|
|
Some(TraitOrTraitImpl::Trait { span, constness_span }),
|
2024-01-02 00:57:30 +01:00
|
|
|
);
|
2023-09-27 17:25:31 -04:00
|
|
|
f(self);
|
2024-01-02 00:57:30 +01:00
|
|
|
self.outer_trait_or_trait_impl = old;
|
2020-02-05 12:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
2024-05-27 15:35:34 -03:00
|
|
|
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
|
|
|
|
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
|
|
|
|
f(self);
|
|
|
|
|
self.extern_mod_safety = old;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 19:32:16 +00:00
|
|
|
fn with_tilde_const(
|
|
|
|
|
&mut self,
|
2024-07-09 09:54:19 +00:00
|
|
|
disallowed: Option<TildeConstReason>,
|
2022-10-20 19:32:16 +00:00
|
|
|
f: impl FnOnce(&mut Self),
|
|
|
|
|
) {
|
|
|
|
|
let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
|
2021-08-25 11:53:16 +00:00
|
|
|
f(self);
|
2022-10-20 19:32:16 +00:00
|
|
|
self.disallow_tilde_const = old;
|
2021-08-25 11:53:16 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-09 16:44:06 +02:00
|
|
|
fn check_type_alias_where_clause_location(
|
2022-02-07 01:23:37 -05:00
|
|
|
&mut self,
|
2023-08-09 16:44:06 +02:00
|
|
|
ty_alias: &TyAlias,
|
|
|
|
|
) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
|
2024-02-20 04:41:01 +01:00
|
|
|
if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
|
2023-08-09 16:44:06 +02:00
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-20 04:41:01 +01:00
|
|
|
let (before_predicates, after_predicates) =
|
|
|
|
|
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
|
|
|
|
|
let span = ty_alias.where_clauses.before.span;
|
|
|
|
|
|
|
|
|
|
let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
|
|
|
|
|
{
|
|
|
|
|
let mut state = State::new();
|
|
|
|
|
|
|
|
|
|
if !ty_alias.where_clauses.after.has_where_token {
|
|
|
|
|
state.space();
|
|
|
|
|
state.word_space("where");
|
2021-10-19 18:45:48 -04:00
|
|
|
}
|
2023-08-09 16:44:06 +02:00
|
|
|
|
2024-02-20 04:41:01 +01:00
|
|
|
let mut first = after_predicates.is_empty();
|
|
|
|
|
for p in before_predicates {
|
|
|
|
|
if !first {
|
|
|
|
|
state.word_space(",");
|
|
|
|
|
}
|
|
|
|
|
first = false;
|
|
|
|
|
state.print_where_predicate(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors::WhereClauseBeforeTypeAliasSugg::Move {
|
2023-08-09 16:44:06 +02:00
|
|
|
left: span,
|
|
|
|
|
snippet: state.s.eof(),
|
2024-02-19 14:25:33 +01:00
|
|
|
right: ty_alias.where_clauses.after.span.shrink_to_hi(),
|
2024-02-20 04:41:01 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
|
2021-10-19 18:45:48 -04:00
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self)) {
|
|
|
|
|
let old = mem::replace(&mut self.outer_impl_trait_span, outer_span);
|
2022-12-15 00:51:34 +00:00
|
|
|
f(self);
|
2025-04-02 14:21:33 +11:00
|
|
|
self.outer_impl_trait_span = old;
|
2020-01-04 16:29:45 -08:00
|
|
|
}
|
|
|
|
|
|
2019-02-28 22:43:53 +00:00
|
|
|
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
2019-01-18 12:35:14 +01:00
|
|
|
fn walk_ty(&mut self, t: &'a Ty) {
|
2022-11-28 19:16:44 +00:00
|
|
|
match &t.kind {
|
2024-06-05 16:43:25 -04:00
|
|
|
TyKind::ImplTrait(_, bounds) => {
|
|
|
|
|
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
|
|
|
|
|
|
|
|
|
|
// FIXME(precise_capturing): If we were to allow `use` in other positions
|
|
|
|
|
// (e.g. GATs), then we must validate those as well. However, we don't have
|
|
|
|
|
// a good way of doing this with the current `Visitor` structure.
|
|
|
|
|
let mut use_bounds = bounds
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|bound| match bound {
|
|
|
|
|
GenericBound::Use(_, span) => Some(span),
|
|
|
|
|
_ => None,
|
|
|
|
|
})
|
|
|
|
|
.copied();
|
|
|
|
|
if let Some(bound1) = use_bounds.next()
|
|
|
|
|
&& let Some(bound2) = use_bounds.next()
|
|
|
|
|
{
|
|
|
|
|
self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });
|
|
|
|
|
}
|
2019-01-18 12:35:14 +01:00
|
|
|
}
|
2022-10-20 19:32:16 +00:00
|
|
|
TyKind::TraitObject(..) => self
|
2024-07-09 09:54:19 +00:00
|
|
|
.with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
|
2022-10-20 19:32:16 +00:00
|
|
|
visit::walk_ty(this, t)
|
|
|
|
|
}),
|
2019-01-18 12:35:14 +01:00
|
|
|
_ => visit::walk_ty(self, t),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 20:53:47 +08:00
|
|
|
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
2024-10-24 10:41:44 -03:00
|
|
|
if let Some(ref ident) = field.ident
|
2023-08-23 20:53:47 +08:00
|
|
|
&& ident.name == kw::Underscore
|
|
|
|
|
{
|
|
|
|
|
self.visit_vis(&field.vis);
|
|
|
|
|
self.visit_ident(ident);
|
|
|
|
|
self.visit_ty_common(&field.ty);
|
|
|
|
|
self.walk_ty(&field.ty);
|
|
|
|
|
walk_list!(self, visit_attribute, &field.attrs);
|
|
|
|
|
} else {
|
|
|
|
|
self.visit_field_def(field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-18 10:35:56 +00:00
|
|
|
fn dcx(&self) -> DiagCtxtHandle<'a> {
|
2024-09-16 09:30:45 +10:00
|
|
|
self.sess.dcx()
|
2016-05-22 17:51:22 +03:00
|
|
|
}
|
|
|
|
|
|
2023-04-03 21:09:06 -05:00
|
|
|
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
|
2020-08-21 19:11:00 -04:00
|
|
|
if let VisibilityKind::Inherited = vis.kind {
|
2019-12-24 17:38:22 -05:00
|
|
|
return;
|
2018-03-21 01:58:25 +03:00
|
|
|
}
|
|
|
|
|
|
2024-04-12 12:40:11 +09:00
|
|
|
self.dcx().emit_err(errors::VisibilityNotPermitted {
|
|
|
|
|
span: vis.span,
|
|
|
|
|
note,
|
|
|
|
|
remove_qualifier_sugg: vis.span,
|
|
|
|
|
});
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
2016-07-17 00:15:15 +03:00
|
|
|
|
2020-11-30 23:24:08 +09:00
|
|
|
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
2019-12-01 12:43:39 +01:00
|
|
|
for Param { pat, .. } in &decl.inputs {
|
|
|
|
|
match pat.kind {
|
Add `{ast,hir,thir}::PatKind::Missing` variants.
"Missing" patterns are possible in bare fn types (`fn f(u32)`) and
similar places. Currently these are represented in the AST with
`ast::PatKind::Ident` with no `by_ref`, no `mut`, an empty ident, and no
sub-pattern. This flows through to `{hir,thir}::PatKind::Binding` for
HIR and THIR.
This is a bit nasty. It's very non-obvious, and easy to forget to check
for the exceptional empty identifier case.
This commit adds a new variant, `PatKind::Missing`, to do it properly.
The process I followed:
- Add a `Missing` variant to `{ast,hir,thir}::PatKind`.
- Chang `parse_param_general` to produce `ast::PatKind::Missing`
instead of `ast::PatKind::Missing`.
- Look through `kw::Empty` occurrences to find functions where an
existing empty ident check needs replacing with a `PatKind::Missing`
check: `print_param`, `check_trait_item`, `is_named_param`.
- Add a `PatKind::Missing => unreachable!(),` arm to every exhaustive
match identified by the compiler.
- Find which arms are actually reachable by running the test suite,
changing them to something appropriate, usually by looking at what
would happen to a `PatKind::Ident`/`PatKind::Binding` with no ref, no
`mut`, an empty ident, and no subpattern.
Quite a few of the `unreachable!()` arms were never reached. This makes
sense because `PatKind::Missing` can't happen in every pattern, only
in places like bare fn tys and trait fn decls.
I also tried an alternative approach: modifying `ast::Param::pat` to
hold an `Option<P<Pat>>` instead of a `P<Pat>`, but that quickly turned
into a very large and painful change. Adding `PatKind::Missing` is much
easier.
2025-03-27 09:33:02 +11:00
|
|
|
PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
|
2024-04-16 19:23:30 -04:00
|
|
|
PatKind::Ident(BindingMode::MUT, ident, None) => {
|
2020-11-30 23:24:08 +09:00
|
|
|
report_err(pat.span, Some(ident), true)
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2020-11-30 23:24:08 +09:00
|
|
|
_ => report_err(pat.span, None, false),
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-07 14:33:35 -07:00
|
|
|
|
2024-07-09 08:54:11 +00:00
|
|
|
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
|
2024-01-02 00:57:30 +01:00
|
|
|
let Const::Yes(span) = constness else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
2024-10-09 09:01:57 +02:00
|
|
|
let const_trait_impl = self.features.const_trait_impl();
|
|
|
|
|
let make_impl_const_sugg = if const_trait_impl
|
2024-01-02 00:57:30 +01:00
|
|
|
&& let TraitOrTraitImpl::TraitImpl {
|
|
|
|
|
constness: Const::No,
|
|
|
|
|
polarity: ImplPolarity::Positive,
|
2025-04-02 14:21:33 +11:00
|
|
|
trait_ref_span,
|
2024-01-12 16:37:25 +01:00
|
|
|
..
|
2024-01-02 00:57:30 +01:00
|
|
|
} = parent
|
|
|
|
|
{
|
2025-04-02 14:21:33 +11:00
|
|
|
Some(trait_ref_span.shrink_to_lo())
|
2024-01-02 00:57:30 +01:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
let make_trait_const_sugg = if const_trait_impl
|
|
|
|
|
&& let TraitOrTraitImpl::Trait { span, constness_span: None } = parent
|
|
|
|
|
{
|
|
|
|
|
Some(span.shrink_to_lo())
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2024-01-02 00:57:30 +01:00
|
|
|
|
|
|
|
|
let parent_constness = parent.constness();
|
|
|
|
|
self.dcx().emit_err(errors::TraitFnConst {
|
|
|
|
|
span,
|
|
|
|
|
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
|
|
|
|
|
const_context_label: parent_constness,
|
|
|
|
|
remove_const_sugg: (
|
2024-09-16 09:30:45 +10:00
|
|
|
self.sess.source_map().span_extend_while_whitespace(span),
|
2024-01-02 00:57:30 +01:00
|
|
|
match parent_constness {
|
|
|
|
|
Some(_) => rustc_errors::Applicability::MachineApplicable,
|
|
|
|
|
None => rustc_errors::Applicability::MaybeIncorrect,
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
requires_multiple_changes: make_impl_const_sugg.is_some()
|
|
|
|
|
|| make_trait_const_sugg.is_some(),
|
|
|
|
|
make_impl_const_sugg,
|
|
|
|
|
make_trait_const_sugg,
|
|
|
|
|
});
|
2016-08-07 14:33:35 -07:00
|
|
|
}
|
2016-10-22 03:33:36 +03:00
|
|
|
|
2020-01-29 01:30:01 +01:00
|
|
|
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
2021-09-07 17:48:03 -04:00
|
|
|
self.check_decl_num_args(fn_decl);
|
2024-04-16 18:53:05 -04:00
|
|
|
self.check_decl_cvariadic_pos(fn_decl);
|
2020-01-29 01:30:01 +01:00
|
|
|
self.check_decl_attrs(fn_decl);
|
|
|
|
|
self.check_decl_self_param(fn_decl, self_semantic);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 17:48:03 -04:00
|
|
|
/// Emits fatal error if function declaration has more than `u16::MAX` arguments
|
|
|
|
|
/// Error is fatal to prevent errors during typechecking
|
|
|
|
|
fn check_decl_num_args(&self, fn_decl: &FnDecl) {
|
|
|
|
|
let max_num_args: usize = u16::MAX.into();
|
|
|
|
|
if fn_decl.inputs.len() > max_num_args {
|
|
|
|
|
let Param { span, .. } = fn_decl.inputs[0];
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args });
|
2021-09-07 17:48:03 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-16 18:53:05 -04:00
|
|
|
/// Emits an error if a function declaration has a variadic parameter in the
|
|
|
|
|
/// beginning or middle of parameter list.
|
|
|
|
|
/// Example: `fn foo(..., x: i32)` will emit an error.
|
|
|
|
|
fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) {
|
2019-12-02 03:16:12 +01:00
|
|
|
match &*fn_decl.inputs {
|
2019-12-24 17:38:22 -05:00
|
|
|
[ps @ .., _] => {
|
|
|
|
|
for Param { ty, span, .. } in ps {
|
|
|
|
|
if let TyKind::CVarArgs = ty.kind {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span });
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2019-12-02 03:16:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2020-01-29 01:30:01 +01:00
|
|
|
}
|
2019-12-02 03:16:12 +01:00
|
|
|
|
2020-01-29 01:30:01 +01:00
|
|
|
fn check_decl_attrs(&self, fn_decl: &FnDecl) {
|
2019-06-09 07:58:40 -03:00
|
|
|
fn_decl
|
|
|
|
|
.inputs
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|i| i.attrs.as_ref())
|
|
|
|
|
.filter(|attr| {
|
2022-06-04 00:04:19 +02:00
|
|
|
let arr = [
|
|
|
|
|
sym::allow,
|
2025-03-22 21:42:34 +03:00
|
|
|
sym::cfg_trace,
|
2025-03-14 20:34:43 +03:00
|
|
|
sym::cfg_attr_trace,
|
2022-06-04 00:04:19 +02:00
|
|
|
sym::deny,
|
|
|
|
|
sym::expect,
|
|
|
|
|
sym::forbid,
|
|
|
|
|
sym::warn,
|
|
|
|
|
];
|
2025-04-10 14:33:59 +10:00
|
|
|
!attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
|
2019-06-09 07:58:40 -03:00
|
|
|
})
|
2019-12-24 17:38:22 -05:00
|
|
|
.for_each(|attr| {
|
|
|
|
|
if attr.is_doc_comment() {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });
|
2019-12-24 17:38:22 -05:00
|
|
|
} else {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span });
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2019-06-09 07:58:40 -03:00
|
|
|
});
|
|
|
|
|
}
|
2019-11-30 18:25:44 +01:00
|
|
|
|
2020-01-29 01:30:01 +01:00
|
|
|
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() {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span });
|
2020-01-29 01:30:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-18 18:02:09 -04:00
|
|
|
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
|
|
|
|
|
/// blocks.
|
|
|
|
|
///
|
|
|
|
|
/// This additionally ensures that within extern blocks, items can only be
|
|
|
|
|
/// `safe`/`unsafe` inside of a `unsafe`-adorned extern block.
|
2024-06-20 16:19:43 -03:00
|
|
|
fn check_item_safety(&self, span: Span, safety: Safety) {
|
|
|
|
|
match self.extern_mod_safety {
|
|
|
|
|
Some(extern_safety) => {
|
2024-09-11 13:32:53 -04:00
|
|
|
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
|
|
|
|
|
&& extern_safety == Safety::Default
|
|
|
|
|
{
|
|
|
|
|
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
|
|
|
|
|
item_span: span,
|
|
|
|
|
block: Some(self.current_extern_span().shrink_to_lo()),
|
|
|
|
|
});
|
2024-06-20 16:19:43 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
if matches!(safety, Safety::Safe(_)) {
|
|
|
|
|
self.dcx().emit_err(errors::InvalidSafetyOnItem { span });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn check_bare_fn_safety(&self, span: Span, safety: Safety) {
|
|
|
|
|
if matches!(safety, Safety::Safe(_)) {
|
|
|
|
|
self.dcx().emit_err(errors::InvalidSafetyOnBareFn { span });
|
2024-05-27 15:35:34 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-30 18:25:44 +01:00
|
|
|
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
2020-02-22 02:01:53 +01:00
|
|
|
if let Defaultness::Default(def_span) = defaultness {
|
2024-09-16 09:30:45 +10:00
|
|
|
let span = self.sess.source_map().guess_head_span(span);
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
2019-11-30 18:25:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-12-01 07:24:07 +01:00
|
|
|
|
2022-08-19 02:43:01 +09:00
|
|
|
/// If `sp` ends with a semicolon, returns it as a `Span`
|
|
|
|
|
/// Otherwise, returns `sp.shrink_to_hi()`
|
|
|
|
|
fn ending_semi_or_hi(&self, sp: Span) -> Span {
|
2024-09-16 09:30:45 +10:00
|
|
|
let source_map = self.sess.source_map();
|
2022-03-22 15:29:07 -07:00
|
|
|
let end = source_map.end_point(sp);
|
2022-08-19 02:43:01 +09:00
|
|
|
|
2023-05-24 14:33:43 +00:00
|
|
|
if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
|
2022-03-22 15:29:07 -07:00
|
|
|
end
|
|
|
|
|
} else {
|
|
|
|
|
sp.shrink_to_hi()
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 12:55:42 +01:00
|
|
|
fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
|
2019-12-01 10:25:45 +01:00
|
|
|
let span = match bounds {
|
|
|
|
|
[] => return,
|
|
|
|
|
[b0] => b0.span(),
|
|
|
|
|
[b0, .., bl] => b0.span().to(bl.span()),
|
|
|
|
|
};
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::BoundInContext { span, ctx });
|
2020-02-14 12:55:42 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-08 16:14:54 +08:00
|
|
|
fn check_foreign_ty_genericless(
|
|
|
|
|
&self,
|
|
|
|
|
generics: &Generics,
|
2024-02-19 14:25:33 +01:00
|
|
|
where_clauses: &TyAliasWhereClauses,
|
2023-06-08 16:14:54 +08:00
|
|
|
) {
|
2020-02-14 12:55:42 +01:00
|
|
|
let cannot_have = |span, descr, remove_descr| {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::ExternTypesCannotHave {
|
2023-02-25 13:53:42 +00:00
|
|
|
span,
|
|
|
|
|
descr,
|
|
|
|
|
remove_descr,
|
|
|
|
|
block_span: self.current_extern_span(),
|
|
|
|
|
});
|
2020-02-14 12:55:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if !generics.params.is_empty() {
|
|
|
|
|
cannot_have(generics.span, "generic parameters", "generic parameters");
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 14:25:33 +01:00
|
|
|
let check_where_clause = |where_clause: TyAliasWhereClause| {
|
|
|
|
|
if where_clause.has_where_token {
|
|
|
|
|
cannot_have(where_clause.span, "`where` clauses", "`where` clause");
|
2023-06-08 16:14:54 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-19 14:25:33 +01:00
|
|
|
check_where_clause(where_clauses.before);
|
|
|
|
|
check_where_clause(where_clauses.after);
|
2020-02-14 12:55:42 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body_span: Option<Span>) {
|
|
|
|
|
let Some(body_span) = body_span else {
|
2022-02-19 00:48:49 +01:00
|
|
|
return;
|
2020-02-14 12:55:42 +01:00
|
|
|
};
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::BodyInExtern {
|
2023-02-25 13:53:42 +00:00
|
|
|
span: ident.span,
|
2025-04-02 14:21:33 +11:00
|
|
|
body: body_span,
|
2023-02-25 13:53:42 +00:00
|
|
|
block: self.current_extern_span(),
|
|
|
|
|
kind,
|
|
|
|
|
});
|
2019-12-01 10:25:45 +01:00
|
|
|
}
|
2019-12-02 02:38:33 +01:00
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
/// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
|
|
|
|
|
fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
|
2022-02-19 00:48:49 +01:00
|
|
|
let Some(body) = body else {
|
|
|
|
|
return;
|
2020-01-30 00:18:54 +01:00
|
|
|
};
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::FnBodyInExtern {
|
2023-02-25 13:53:42 +00:00
|
|
|
span: ident.span,
|
|
|
|
|
body: body.span,
|
|
|
|
|
block: self.current_extern_span(),
|
|
|
|
|
});
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_extern_span(&self) -> Span {
|
2025-04-02 14:21:33 +11:00
|
|
|
self.sess.source_map().guess_head_span(self.extern_mod_span.unwrap())
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-29 16:51:46 +01:00
|
|
|
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
|
2024-04-03 02:43:54 +02:00
|
|
|
fn check_foreign_fn_headerless(
|
|
|
|
|
&self,
|
|
|
|
|
// Deconstruct to ensure exhaustiveness
|
2024-04-26 18:35:54 -03:00
|
|
|
FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
|
2024-04-03 02:43:54 +02:00
|
|
|
) {
|
2024-10-11 11:30:03 -04:00
|
|
|
let report_err = |span, kw| {
|
|
|
|
|
self.dcx().emit_err(errors::FnQualifierInExtern {
|
|
|
|
|
span,
|
|
|
|
|
kw,
|
|
|
|
|
block: self.current_extern_span(),
|
|
|
|
|
});
|
2024-04-03 02:43:54 +02:00
|
|
|
};
|
|
|
|
|
match coroutine_kind {
|
2024-10-11 11:30:03 -04:00
|
|
|
Some(kind) => report_err(kind.span(), kind.as_str()),
|
2024-04-03 02:43:54 +02:00
|
|
|
None => (),
|
|
|
|
|
}
|
|
|
|
|
match constness {
|
2024-10-11 11:30:03 -04:00
|
|
|
Const::Yes(span) => report_err(span, "const"),
|
2024-04-03 02:43:54 +02:00
|
|
|
Const::No => (),
|
|
|
|
|
}
|
|
|
|
|
match ext {
|
|
|
|
|
Extern::None => (),
|
2024-10-11 11:30:03 -04:00
|
|
|
Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span, "extern"),
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-06 23:49:59 +08:00
|
|
|
/// An item in `extern { ... }` cannot use non-ascii identifier.
|
|
|
|
|
fn check_foreign_item_ascii_only(&self, ident: Ident) {
|
2021-12-15 16:13:11 +11:00
|
|
|
if !ident.as_str().is_ascii() {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::ExternItemAscii {
|
2023-02-25 13:53:42 +00:00
|
|
|
span: ident.span,
|
|
|
|
|
block: self.current_extern_span(),
|
|
|
|
|
});
|
2021-04-06 23:49:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-29 17:28:56 -04:00
|
|
|
/// Reject invalid C-variadic types.
|
|
|
|
|
///
|
|
|
|
|
/// C-variadics must be:
|
|
|
|
|
/// - Non-const
|
|
|
|
|
/// - Either foreign, or free and `unsafe extern "C"` semantically
|
2022-03-30 01:42:10 -04:00
|
|
|
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
2023-10-29 17:04:52 -04:00
|
|
|
let variadic_spans: Vec<_> = fk
|
|
|
|
|
.decl()
|
|
|
|
|
.inputs
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
|
|
|
|
|
.map(|arg| arg.span)
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
if variadic_spans.is_empty() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-29 17:28:56 -04:00
|
|
|
if let Some(header) = fk.header() {
|
|
|
|
|
if let Const::Yes(const_span) = header.constness {
|
|
|
|
|
let mut spans = variadic_spans.clone();
|
|
|
|
|
spans.push(const_span);
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::ConstAndCVariadic {
|
2023-10-29 17:28:56 -04:00
|
|
|
spans,
|
|
|
|
|
const_span,
|
|
|
|
|
variadic_spans: variadic_spans.clone(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
match (fk.ctxt(), fk.header()) {
|
|
|
|
|
(Some(FnCtxt::Foreign), _) => return,
|
|
|
|
|
(Some(FnCtxt::Free), Some(header)) => match header.ext {
|
2022-07-02 18:25:55 +01:00
|
|
|
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
|
2024-06-22 14:42:26 -07:00
|
|
|
| Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
|
2022-07-02 18:25:55 +01:00
|
|
|
| Extern::Implicit(_)
|
2024-05-17 14:17:48 -03:00
|
|
|
if matches!(header.safety, Safety::Unsafe(_)) =>
|
2020-01-30 00:18:54 +01:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
|
2019-12-02 02:38:33 +01:00
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2020-02-14 15:56:05 +01:00
|
|
|
fn check_item_named(&self, ident: Ident, kind: &str) {
|
|
|
|
|
if ident.name != kw::Underscore {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind });
|
2020-02-14 15:56:05 +01:00
|
|
|
}
|
2020-03-11 09:17:55 -07:00
|
|
|
|
2020-05-16 14:09:01 +08:00
|
|
|
fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
|
|
|
|
|
if ident.name.as_str().is_ascii() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-09-16 09:30:45 +10:00
|
|
|
let span = self.sess.source_map().guess_head_span(item_span);
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::NoMangleAscii { span });
|
2020-05-16 14:09:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn check_mod_file_item_asciionly(&self, ident: Ident) {
|
|
|
|
|
if ident.name.as_str().is_ascii() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
|
2020-05-16 14:09:01 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
|
2020-03-11 09:17:55 -07:00
|
|
|
if !generics.params.is_empty() {
|
2025-04-02 14:21:33 +11:00
|
|
|
self.dcx()
|
|
|
|
|
.emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span });
|
2020-03-11 09:17:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
|
2021-10-03 17:58:10 +02:00
|
|
|
if let [.., last] = &bounds[..] {
|
|
|
|
|
let span = ident_span.shrink_to_hi().to(last.span());
|
2024-04-25 03:11:19 +02:00
|
|
|
self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span });
|
2021-10-03 17:58:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
|
|
|
|
|
if !where_clause.predicates.is_empty() {
|
2024-04-25 03:11:19 +02:00
|
|
|
// FIXME: The current diagnostic is misleading since it only talks about
|
|
|
|
|
// super trait and lifetime bounds while we should just say “bounds”.
|
|
|
|
|
self.dcx()
|
|
|
|
|
.emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span });
|
2020-03-11 09:17:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 14:21:33 +11:00
|
|
|
fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
|
2020-03-11 09:17:55 -07:00
|
|
|
if !trait_items.is_empty() {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
|
2023-02-25 13:53:42 +00:00
|
|
|
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
|
2025-04-02 14:21:33 +11:00
|
|
|
self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span });
|
2020-03-11 09:17:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 04:40:05 +01:00
|
|
|
|
2020-04-05 16:34:16 -07:00
|
|
|
fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
|
2020-03-29 11:31:58 -07:00
|
|
|
// Lifetimes always come first.
|
|
|
|
|
let lt_sugg = data.args.iter().filter_map(|arg| match arg {
|
|
|
|
|
AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
|
|
|
|
|
Some(pprust::to_string(|s| s.print_generic_arg(lt)))
|
|
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
});
|
|
|
|
|
let args_sugg = data.args.iter().filter_map(|a| match a {
|
2020-04-05 16:34:16 -07:00
|
|
|
AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
|
|
|
|
|
None
|
|
|
|
|
}
|
2020-03-29 11:31:58 -07:00
|
|
|
AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
|
|
|
|
|
});
|
2020-04-05 16:34:16 -07:00
|
|
|
// Constraints always come last.
|
2020-03-29 11:31:58 -07:00
|
|
|
let constraint_sugg = data.args.iter().filter_map(|a| match a {
|
|
|
|
|
AngleBracketedArg::Arg(_) => None,
|
|
|
|
|
AngleBracketedArg::Constraint(c) => {
|
2024-05-27 23:53:46 +02:00
|
|
|
Some(pprust::to_string(|s| s.print_assoc_item_constraint(c)))
|
2020-03-29 11:31:58 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
format!(
|
|
|
|
|
"<{}>",
|
|
|
|
|
lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 04:40:05 +01:00
|
|
|
/// Enforce generic args coming before constraints in `<...>` of a path segment.
|
|
|
|
|
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
|
|
|
|
|
// Early exit in case it's partitioned as it should be.
|
|
|
|
|
if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Find all generic argument coming after the first constraint...
|
2020-04-05 16:34:16 -07:00
|
|
|
let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
|
|
|
|
|
data.args.iter().partition_map(|arg| match arg {
|
|
|
|
|
AngleBracketedArg::Constraint(c) => Either::Left(c.span),
|
|
|
|
|
AngleBracketedArg::Arg(a) => Either::Right(a.span()),
|
|
|
|
|
});
|
2020-03-29 11:31:58 -07:00
|
|
|
let args_len = arg_spans.len();
|
2020-03-28 13:48:04 -07:00
|
|
|
let constraint_len = constraint_spans.len();
|
2020-03-22 04:40:05 +01:00
|
|
|
// ...and then error:
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::ArgsBeforeConstraint {
|
2023-02-25 13:53:42 +00:00
|
|
|
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),
|
2023-11-21 20:07:32 +01:00
|
|
|
suggestion: self.correct_generic_order_suggestion(data),
|
2023-02-25 13:53:42 +00:00
|
|
|
constraint_len,
|
|
|
|
|
args_len,
|
|
|
|
|
});
|
2020-03-22 04:40:05 +01:00
|
|
|
}
|
2021-05-16 09:51:00 -05:00
|
|
|
|
|
|
|
|
fn visit_ty_common(&mut self, ty: &'a Ty) {
|
2022-11-28 19:16:44 +00:00
|
|
|
match &ty.kind {
|
|
|
|
|
TyKind::BareFn(bfty) => {
|
2024-06-20 16:19:43 -03:00
|
|
|
self.check_bare_fn_safety(bfty.decl_span, bfty.safety);
|
2021-05-16 09:51:00 -05:00
|
|
|
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
|
|
|
|
|
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::PatternFnPointer { span });
|
2021-05-16 09:51:00 -05:00
|
|
|
});
|
2024-10-30 13:12:08 +01:00
|
|
|
if let Extern::Implicit(extern_span) = bfty.ext {
|
2025-04-08 05:30:21 +03:00
|
|
|
self.handle_missing_abi(extern_span, ty.id);
|
2021-07-08 21:58:05 +02:00
|
|
|
}
|
2021-05-16 09:51:00 -05:00
|
|
|
}
|
2022-11-28 19:16:44 +00:00
|
|
|
TyKind::TraitObject(bounds, ..) => {
|
2021-05-16 09:51:00 -05:00
|
|
|
let mut any_lifetime_bounds = false;
|
|
|
|
|
for bound in bounds {
|
2022-11-28 19:16:44 +00:00
|
|
|
if let GenericBound::Outlives(lifetime) = bound {
|
2021-05-16 09:51:00 -05:00
|
|
|
if any_lifetime_bounds {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx()
|
2023-02-25 13:53:42 +00:00
|
|
|
.emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
|
2021-05-16 09:51:00 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
any_lifetime_bounds = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-05 16:18:52 -04:00
|
|
|
TyKind::ImplTrait(_, bounds) => {
|
2025-04-02 14:21:33 +11:00
|
|
|
if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::NestedImplTrait {
|
2023-02-25 13:53:42 +00:00
|
|
|
span: ty.span,
|
|
|
|
|
outer: outer_impl_trait_sp,
|
|
|
|
|
inner: ty.span,
|
|
|
|
|
});
|
2021-05-16 09:51:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span });
|
2021-05-16 09:51:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-08 21:58:05 +02:00
|
|
|
|
2025-04-08 05:30:21 +03:00
|
|
|
fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
|
2021-07-08 21:58:05 +02:00
|
|
|
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
|
|
|
|
|
// call site which do not have a macro backtrace. See #61963.
|
2025-04-08 05:30:21 +03:00
|
|
|
if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
|
|
|
|
|
self.dcx().emit_err(errors::MissingAbi { span });
|
|
|
|
|
} else if self
|
2024-09-16 09:30:45 +10:00
|
|
|
.sess
|
2021-07-08 21:58:05 +02:00
|
|
|
.source_map()
|
|
|
|
|
.span_to_snippet(span)
|
2023-06-27 07:40:47 +00:00
|
|
|
.is_ok_and(|snippet| !snippet.starts_with("#["))
|
|
|
|
|
{
|
2024-05-20 17:47:54 +00:00
|
|
|
self.lint_buffer.buffer_lint(
|
2021-07-08 21:58:05 +02:00
|
|
|
MISSING_ABI,
|
|
|
|
|
id,
|
|
|
|
|
span,
|
2025-02-05 12:22:28 -08:00
|
|
|
BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK),
|
2021-07-08 21:58:05 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-01 12:04:56 +11:00
|
|
|
|
|
|
|
|
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
|
|
|
|
fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) {
|
|
|
|
|
walk_list!(self, visit_attribute, attrs);
|
|
|
|
|
self.visit_vis(vis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
|
|
|
|
fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) {
|
|
|
|
|
walk_list!(self, visit_attribute, attrs);
|
|
|
|
|
self.visit_vis(vis);
|
|
|
|
|
self.visit_ident(ident);
|
|
|
|
|
}
|
2019-02-05 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-19 20:20:09 +01:00
|
|
|
/// Checks that generic parameters are in the correct order,
|
|
|
|
|
/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
|
2024-06-18 10:35:56 +00:00
|
|
|
fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) {
|
2019-02-05 16:52:17 +01:00
|
|
|
let mut max_param: Option<ParamKindOrd> = None;
|
2023-03-04 12:39:54 +00:00
|
|
|
let mut out_of_order = FxIndexMap::default();
|
2021-06-10 00:09:12 +03:00
|
|
|
let mut param_idents = Vec::with_capacity(generics.len());
|
2019-02-05 16:52:17 +01:00
|
|
|
|
2021-06-10 00:09:12 +03:00
|
|
|
for (idx, param) in generics.iter().enumerate() {
|
|
|
|
|
let ident = param.ident;
|
|
|
|
|
let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
|
2020-12-30 11:43:30 -05:00
|
|
|
let (ord_kind, ident) = match ¶m.kind {
|
2021-06-10 00:09:12 +03:00
|
|
|
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
|
2022-11-28 19:16:44 +00:00
|
|
|
GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
|
|
|
|
|
GenericParamKind::Const { ty, .. } => {
|
2020-12-30 11:43:30 -05:00
|
|
|
let ty = pprust::ty_to_string(ty);
|
2023-07-25 22:00:13 +02:00
|
|
|
(ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))
|
2020-12-30 11:43:30 -05:00
|
|
|
}
|
|
|
|
|
};
|
2021-06-10 00:09:12 +03:00
|
|
|
param_idents.push((kind, ord_kind, bounds, idx, ident));
|
2019-02-05 16:52:17 +01:00
|
|
|
match max_param {
|
2021-06-10 00:09:12 +03:00
|
|
|
Some(max_param) if max_param > ord_kind => {
|
|
|
|
|
let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
|
2019-02-05 16:52:17 +01:00
|
|
|
entry.1.push(span);
|
|
|
|
|
}
|
2021-06-10 00:09:12 +03:00
|
|
|
Some(_) | None => max_param = Some(ord_kind),
|
2019-02-05 16:52:17 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !out_of_order.is_empty() {
|
2021-06-10 00:09:12 +03:00
|
|
|
let mut ordered_params = "<".to_string();
|
2020-12-30 11:43:30 -05:00
|
|
|
param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
|
2019-02-05 16:52:17 +01:00
|
|
|
let mut first = true;
|
2020-12-30 11:43:30 -05:00
|
|
|
for (kind, _, bounds, _, ident) in param_idents {
|
2019-02-05 16:52:17 +01:00
|
|
|
if !first {
|
|
|
|
|
ordered_params += ", ";
|
|
|
|
|
}
|
2019-02-05 19:00:07 +01:00
|
|
|
ordered_params += &ident;
|
2021-06-10 00:09:12 +03:00
|
|
|
|
|
|
|
|
if !bounds.is_empty() {
|
|
|
|
|
ordered_params += ": ";
|
2023-11-21 20:07:32 +01:00
|
|
|
ordered_params += &pprust::bounds_to_string(bounds);
|
2019-03-30 20:30:36 +01:00
|
|
|
}
|
2021-06-10 00:09:12 +03:00
|
|
|
|
2020-12-30 11:43:30 -05:00
|
|
|
match kind {
|
|
|
|
|
GenericParamKind::Type { default: Some(default) } => {
|
|
|
|
|
ordered_params += " = ";
|
|
|
|
|
ordered_params += &pprust::ty_to_string(default);
|
|
|
|
|
}
|
|
|
|
|
GenericParamKind::Type { default: None } => (),
|
|
|
|
|
GenericParamKind::Lifetime => (),
|
2021-05-29 03:54:32 +01:00
|
|
|
GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
|
|
|
|
|
ordered_params += " = ";
|
2023-04-09 23:07:18 +02:00
|
|
|
ordered_params += &pprust::expr_to_string(&default.value);
|
2021-05-29 03:54:32 +01:00
|
|
|
}
|
|
|
|
|
GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
|
2020-12-30 11:43:30 -05:00
|
|
|
}
|
2019-02-05 16:52:17 +01:00
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 00:09:12 +03:00
|
|
|
ordered_params += ">";
|
|
|
|
|
|
|
|
|
|
for (param_ord, (max_param, spans)) in &out_of_order {
|
2023-12-18 10:15:45 +11:00
|
|
|
dcx.emit_err(errors::OutOfOrderParams {
|
2023-02-25 13:53:42 +00:00
|
|
|
spans: spans.clone(),
|
|
|
|
|
sugg_span: span,
|
|
|
|
|
param_ord,
|
|
|
|
|
max_param,
|
|
|
|
|
ordered_params: &ordered_params,
|
|
|
|
|
});
|
2021-06-10 00:09:12 +03:00
|
|
|
}
|
2019-02-05 16:52:17 +01:00
|
|
|
}
|
2016-05-22 17:51:22 +03:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
impl<'a> Visitor<'a> for AstValidator<'a> {
|
2019-10-11 21:00:09 +02:00
|
|
|
fn visit_attribute(&mut self, attr: &Attribute) {
|
2025-05-03 15:19:08 +02:00
|
|
|
validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id);
|
2019-10-11 21:00:09 +02:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
2021-05-16 09:51:00 -05:00
|
|
|
self.visit_ty_common(ty);
|
2019-01-18 12:35:14 +01:00
|
|
|
self.walk_ty(ty)
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_item(&mut self, item: &'a Item) {
|
2023-03-19 21:32:34 +04:00
|
|
|
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
|
2019-01-17 07:28:39 +01:00
|
|
|
self.has_proc_macro_decls = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-03 15:18:30 +02:00
|
|
|
let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id);
|
|
|
|
|
|
2025-04-01 14:49:58 +11:00
|
|
|
if let Some(ident) = item.kind.ident()
|
|
|
|
|
&& attr::contains_name(&item.attrs, sym::no_mangle)
|
|
|
|
|
{
|
|
|
|
|
self.check_nomangle_item_asciionly(ident, item.span);
|
2020-05-16 14:09:01 +08:00
|
|
|
}
|
|
|
|
|
|
2022-11-28 19:16:44 +00:00
|
|
|
match &item.kind {
|
2021-11-07 16:43:49 +08:00
|
|
|
ItemKind::Impl(box Impl {
|
2024-05-17 14:17:48 -03:00
|
|
|
safety,
|
2020-01-13 20:30:20 -08:00
|
|
|
polarity,
|
|
|
|
|
defaultness: _,
|
2021-08-25 11:53:16 +00:00
|
|
|
constness,
|
2022-11-28 19:16:44 +00:00
|
|
|
generics,
|
|
|
|
|
of_trait: Some(t),
|
|
|
|
|
self_ty,
|
|
|
|
|
items,
|
2021-01-29 08:31:08 +01:00
|
|
|
}) => {
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis(&item.attrs, &item.vis);
|
2025-04-02 14:31:27 +11:00
|
|
|
self.visibility_not_permitted(
|
|
|
|
|
&item.vis,
|
|
|
|
|
errors::VisibilityNotPermittedNote::TraitImpl,
|
|
|
|
|
);
|
|
|
|
|
if let TyKind::Dummy = self_ty.kind {
|
|
|
|
|
// Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,
|
|
|
|
|
// which isn't allowed. Not a problem for this obscure, obsolete syntax.
|
|
|
|
|
self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
|
|
|
|
|
}
|
|
|
|
|
if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) {
|
|
|
|
|
self.dcx().emit_err(errors::UnsafeNegativeImpl {
|
|
|
|
|
span: sp.to(t.path.span),
|
|
|
|
|
negative: sp,
|
|
|
|
|
r#unsafe: span,
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2025-04-02 14:31:27 +11:00
|
|
|
let disallowed = matches!(constness, Const::No)
|
|
|
|
|
.then(|| TildeConstReason::TraitImpl { span: item.span });
|
|
|
|
|
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
|
|
|
|
self.visit_trait_ref(t);
|
|
|
|
|
self.visit_ty(self_ty);
|
2021-08-25 11:53:16 +00:00
|
|
|
|
2025-04-02 14:31:27 +11:00
|
|
|
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
2025-03-25 09:00:35 +00:00
|
|
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
|
2020-02-05 12:27:45 +01:00
|
|
|
});
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
2021-11-07 16:43:49 +08:00
|
|
|
ItemKind::Impl(box Impl {
|
2024-05-17 14:17:48 -03:00
|
|
|
safety,
|
2020-01-13 20:30:20 -08:00
|
|
|
polarity,
|
|
|
|
|
defaultness,
|
2020-01-13 20:30:25 -08:00
|
|
|
constness,
|
2023-11-11 15:01:58 +01:00
|
|
|
generics,
|
2020-01-13 20:30:20 -08:00
|
|
|
of_trait: None,
|
2022-11-28 19:16:44 +00:00
|
|
|
self_ty,
|
2023-11-11 15:01:58 +01:00
|
|
|
items,
|
2021-01-29 08:31:08 +01:00
|
|
|
}) => {
|
2024-08-21 00:57:58 -04:00
|
|
|
let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
|
|
|
|
|
span: self_ty.span,
|
|
|
|
|
annotation_span,
|
|
|
|
|
annotation,
|
|
|
|
|
self_ty: self_ty.span,
|
|
|
|
|
only_trait,
|
|
|
|
|
};
|
2020-03-05 15:39:35 -08:00
|
|
|
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis(&item.attrs, &item.vis);
|
2025-04-02 14:31:27 +11:00
|
|
|
self.visibility_not_permitted(
|
|
|
|
|
&item.vis,
|
|
|
|
|
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
|
|
|
|
);
|
|
|
|
|
if let &Safety::Unsafe(span) = safety {
|
|
|
|
|
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
|
|
|
|
span: self_ty.span,
|
|
|
|
|
annotation_span: span,
|
|
|
|
|
annotation: "unsafe",
|
|
|
|
|
self_ty: self_ty.span,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if let &ImplPolarity::Negative(span) = polarity {
|
|
|
|
|
self.dcx().emit_err(error(span, "negative", false));
|
|
|
|
|
}
|
|
|
|
|
if let &Defaultness::Default(def_span) = defaultness {
|
|
|
|
|
self.dcx().emit_err(error(def_span, "`default`", true));
|
|
|
|
|
}
|
|
|
|
|
if let &Const::Yes(span) = constness {
|
|
|
|
|
self.dcx().emit_err(error(span, "`const`", true));
|
|
|
|
|
}
|
2023-11-11 15:01:58 +01:00
|
|
|
|
2025-04-02 14:31:27 +11:00
|
|
|
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
|
|
|
|
|
this.visit_generics(generics)
|
|
|
|
|
});
|
|
|
|
|
self.visit_ty(self_ty);
|
|
|
|
|
self.with_in_trait_impl(None, |this| {
|
2025-03-25 09:00:35 +00:00
|
|
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
|
2023-12-18 01:10:16 +01:00
|
|
|
});
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
2024-07-26 10:04:02 +00:00
|
|
|
ItemKind::Fn(
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
func @ box Fn {
|
|
|
|
|
defaultness,
|
|
|
|
|
ident,
|
|
|
|
|
generics: _,
|
|
|
|
|
sig,
|
|
|
|
|
contract: _,
|
|
|
|
|
body,
|
|
|
|
|
define_opaque: _,
|
|
|
|
|
},
|
2024-07-26 10:04:02 +00:00
|
|
|
) => {
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
2022-11-28 19:16:44 +00:00
|
|
|
self.check_defaultness(item.span, *defaultness);
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2025-04-10 14:33:59 +10:00
|
|
|
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
2024-09-30 21:07:36 +03:00
|
|
|
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::FnWithoutBody {
|
2022-08-19 02:43:01 +09:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
extern_block_suggestion: match sig.header.ext {
|
|
|
|
|
Extern::None => None,
|
2023-02-25 13:53:42 +00:00
|
|
|
Extern::Implicit(start_span) => {
|
|
|
|
|
Some(errors::ExternBlockSuggestion::Implicit {
|
|
|
|
|
start_span,
|
|
|
|
|
end_span: item.span.shrink_to_hi(),
|
|
|
|
|
})
|
|
|
|
|
}
|
2023-01-19 13:52:15 +01:00
|
|
|
Extern::Explicit(abi, start_span) => {
|
2023-02-25 13:53:42 +00:00
|
|
|
Some(errors::ExternBlockSuggestion::Explicit {
|
2023-01-19 13:52:15 +01:00
|
|
|
start_span,
|
|
|
|
|
end_span: item.span.shrink_to_hi(),
|
|
|
|
|
abi: abi.symbol_unescaped,
|
|
|
|
|
})
|
|
|
|
|
}
|
2022-08-19 02:43:01 +09:00
|
|
|
},
|
|
|
|
|
});
|
2019-12-02 02:38:33 +01:00
|
|
|
}
|
2022-07-02 18:53:16 +01:00
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
|
2021-08-25 11:53:16 +00:00
|
|
|
self.visit_fn(kind, item.span, item.id);
|
2019-02-05 16:52:17 +01:00
|
|
|
}
|
2024-10-30 13:12:08 +01:00
|
|
|
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
|
2025-04-02 14:31:27 +11:00
|
|
|
let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
|
|
|
|
|
self.visibility_not_permitted(
|
|
|
|
|
&item.vis,
|
|
|
|
|
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if &Safety::Default == safety {
|
|
|
|
|
if item.span.at_least_rust_2024() {
|
|
|
|
|
self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
|
|
|
|
|
} else {
|
|
|
|
|
self.lint_buffer.buffer_lint(
|
|
|
|
|
MISSING_UNSAFE_ON_EXTERN,
|
|
|
|
|
item.id,
|
|
|
|
|
item.span,
|
|
|
|
|
BuiltinLintDiag::MissingUnsafeOnExtern {
|
|
|
|
|
suggestion: item.span.shrink_to_lo(),
|
|
|
|
|
},
|
|
|
|
|
);
|
2024-05-27 15:35:34 -03:00
|
|
|
}
|
2025-04-02 14:31:27 +11:00
|
|
|
}
|
2024-05-27 15:35:34 -03:00
|
|
|
|
2025-04-02 14:31:27 +11:00
|
|
|
if abi.is_none() {
|
2025-04-08 05:30:21 +03:00
|
|
|
self.handle_missing_abi(*extern_span, item.id);
|
2025-04-02 14:31:27 +11:00
|
|
|
}
|
|
|
|
|
self.with_in_extern_mod(*safety, |this| {
|
2024-05-27 15:35:34 -03:00
|
|
|
visit::walk_item(this, item);
|
|
|
|
|
});
|
2025-04-02 14:31:27 +11:00
|
|
|
self.extern_mod_span = old_item;
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Enum(_, def, _) => {
|
2016-05-22 18:07:28 +03:00
|
|
|
for variant in &def.variants {
|
2023-04-03 21:09:06 -05:00
|
|
|
self.visibility_not_permitted(
|
|
|
|
|
&variant.vis,
|
|
|
|
|
errors::VisibilityNotPermittedNote::EnumVariant,
|
|
|
|
|
);
|
2019-08-13 21:40:21 -03:00
|
|
|
for field in variant.data.fields() {
|
2023-04-03 21:09:06 -05:00
|
|
|
self.visibility_not_permitted(
|
|
|
|
|
&field.vis,
|
|
|
|
|
errors::VisibilityNotPermittedNote::EnumVariant,
|
|
|
|
|
);
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
visit::walk_item(self, item)
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => {
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
2024-01-02 00:57:30 +01:00
|
|
|
let is_const_trait =
|
|
|
|
|
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
|
2025-04-02 14:31:27 +11:00
|
|
|
if *is_auto == IsAuto::Yes {
|
|
|
|
|
// Auto traits cannot have generics, super traits nor contain items.
|
|
|
|
|
self.deny_generic_params(generics, ident.span);
|
|
|
|
|
self.deny_super_traits(bounds, ident.span);
|
|
|
|
|
self.deny_where_clause(&generics.where_clause, ident.span);
|
|
|
|
|
self.deny_items(items, ident.span);
|
|
|
|
|
}
|
2020-01-04 16:29:45 -08:00
|
|
|
|
2025-04-02 14:31:27 +11:00
|
|
|
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
|
|
|
|
// context for the supertraits.
|
|
|
|
|
let disallowed =
|
|
|
|
|
is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span });
|
|
|
|
|
self.with_tilde_const(disallowed, |this| {
|
|
|
|
|
this.visit_generics(generics);
|
|
|
|
|
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
|
|
|
|
});
|
|
|
|
|
self.with_in_trait(item.span, is_const_trait, |this| {
|
2023-09-27 17:25:31 -04:00
|
|
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
|
2022-04-20 19:06:32 +08:00
|
|
|
});
|
2016-08-07 14:33:35 -07:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Mod(safety, ident, mod_kind) => {
|
2024-05-17 14:17:48 -03:00
|
|
|
if let &Safety::Unsafe(span) = safety {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
|
2020-08-23 03:42:19 -07:00
|
|
|
}
|
2018-11-27 02:59:49 +00:00
|
|
|
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
2024-12-05 21:19:08 +00:00
|
|
|
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
|
2023-03-19 21:32:34 +04:00
|
|
|
&& !attr::contains_name(&item.attrs, sym::path)
|
2021-02-17 00:56:07 +03:00
|
|
|
{
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_mod_file_item_asciionly(*ident);
|
2020-05-16 14:09:01 +08:00
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
visit::walk_item(self, item)
|
2016-08-12 08:15:40 +00:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Struct(ident, vdata, generics) => match vdata {
|
2023-12-19 22:47:30 +00:00
|
|
|
VariantData::Struct { fields, .. } => {
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
2023-08-23 20:53:47 +08:00
|
|
|
self.visit_generics(generics);
|
2023-11-11 15:01:58 +01:00
|
|
|
// Permit `Anon{Struct,Union}` as field type.
|
2023-08-23 20:53:47 +08:00
|
|
|
walk_list!(self, visit_struct_field_def, fields);
|
|
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
_ => visit::walk_item(self, item),
|
2023-08-23 20:53:47 +08:00
|
|
|
},
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Union(ident, vdata, generics) => {
|
2018-09-07 15:10:16 +02:00
|
|
|
if vdata.fields().is_empty() {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
2023-08-23 20:53:47 +08:00
|
|
|
match vdata {
|
2023-12-19 22:47:30 +00:00
|
|
|
VariantData::Struct { fields, .. } => {
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
2023-08-23 20:53:47 +08:00
|
|
|
self.visit_generics(generics);
|
2023-11-11 15:01:58 +01:00
|
|
|
// Permit `Anon{Struct,Union}` as field type.
|
2023-08-23 20:53:47 +08:00
|
|
|
walk_list!(self, visit_struct_field_def, fields);
|
|
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
_ => visit::walk_item(self, item),
|
2023-08-23 20:53:47 +08:00
|
|
|
}
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
2023-11-11 15:30:25 +01:00
|
|
|
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
2023-03-29 09:20:45 +00:00
|
|
|
self.check_defaultness(item.span, *defaultness);
|
2023-11-11 15:30:25 +01:00
|
|
|
if expr.is_none() {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::ConstWithoutBody {
|
2023-11-11 15:30:25 +01:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
visit::walk_item(self, item);
|
2020-02-14 14:21:02 +01:00
|
|
|
}
|
2024-06-20 16:19:43 -03:00
|
|
|
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
|
|
|
|
self.check_item_safety(item.span, *safety);
|
2024-07-18 18:02:09 -04:00
|
|
|
if matches!(safety, Safety::Unsafe(_)) {
|
|
|
|
|
self.dcx().emit_err(errors::UnsafeStatic { span: item.span });
|
|
|
|
|
}
|
2024-06-20 16:19:43 -03:00
|
|
|
|
|
|
|
|
if expr.is_none() {
|
|
|
|
|
self.dcx().emit_err(errors::StaticWithoutBody {
|
|
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
visit::walk_item(self, item);
|
2020-02-14 14:21:02 +01:00
|
|
|
}
|
2023-08-09 16:44:06 +02:00
|
|
|
ItemKind::TyAlias(
|
|
|
|
|
ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
|
|
|
|
|
) => {
|
2022-11-28 19:16:44 +00:00
|
|
|
self.check_defaultness(item.span, *defaultness);
|
2021-11-07 16:43:49 +08:00
|
|
|
if ty.is_none() {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
2022-08-19 02:43:01 +09:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
2020-02-21 23:00:27 +01:00
|
|
|
}
|
|
|
|
|
self.check_type_no_bounds(bounds, "this context");
|
2023-08-09 16:44:06 +02:00
|
|
|
|
2024-10-09 09:01:57 +02:00
|
|
|
if self.features.lazy_type_alias() {
|
2023-08-09 16:44:06 +02:00
|
|
|
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(err);
|
2023-08-09 16:44:06 +02:00
|
|
|
}
|
2024-02-19 14:25:33 +01:00
|
|
|
} else if where_clauses.after.has_where_token {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
|
2024-02-19 14:25:33 +01:00
|
|
|
span: where_clauses.after.span,
|
2024-09-16 09:30:45 +10:00
|
|
|
help: self.sess.is_nightly_build(),
|
2023-08-09 16:44:06 +02:00
|
|
|
});
|
2021-10-19 18:45:48 -04:00
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
visit::walk_item(self, item);
|
2020-02-21 23:00:27 +01:00
|
|
|
}
|
2025-04-01 09:55:38 +11:00
|
|
|
_ => visit::walk_item(self, item),
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
2025-05-03 15:18:30 +02:00
|
|
|
|
|
|
|
|
self.lint_node_id = previous_lint_node_id;
|
2016-05-22 18:07:28 +03:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
2020-01-30 00:18:54 +01:00
|
|
|
match &fi.kind {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
2021-11-07 16:43:49 +08:00
|
|
|
self.check_defaultness(fi.span, *defaultness);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
2024-04-03 02:43:54 +02:00
|
|
|
self.check_foreign_fn_headerless(sig.header);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_foreign_item_ascii_only(*ident);
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
2021-10-19 18:45:48 -04:00
|
|
|
ForeignItemKind::TyAlias(box TyAlias {
|
|
|
|
|
defaultness,
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ident,
|
2021-10-19 18:45:48 -04:00
|
|
|
generics,
|
|
|
|
|
where_clauses,
|
|
|
|
|
bounds,
|
|
|
|
|
ty,
|
|
|
|
|
..
|
|
|
|
|
}) => {
|
2021-11-07 16:43:49 +08:00
|
|
|
self.check_defaultness(fi.span, *defaultness);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
2020-02-14 12:55:42 +01:00
|
|
|
self.check_type_no_bounds(bounds, "`extern` blocks");
|
2024-02-19 14:25:33 +01:00
|
|
|
self.check_foreign_ty_genericless(generics, where_clauses);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_foreign_item_ascii_only(*ident);
|
2020-02-14 12:55:42 +01:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => {
|
2024-06-20 16:19:43 -03:00
|
|
|
self.check_item_safety(fi.span, *safety);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span));
|
|
|
|
|
self.check_foreign_item_ascii_only(*ident);
|
2020-02-14 15:56:05 +01:00
|
|
|
}
|
2020-02-29 19:32:20 +03:00
|
|
|
ForeignItemKind::MacCall(..) => {}
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
|
|
|
|
|
2024-04-24 20:31:51 +03:00
|
|
|
visit::walk_item(self, fi)
|
2016-07-17 00:15:15 +03:00
|
|
|
}
|
|
|
|
|
|
2019-02-28 22:43:53 +00:00
|
|
|
// Mirrors `visit::walk_generic_args`, but tracks relevant state.
|
2022-09-12 10:43:34 +10:00
|
|
|
fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
|
2022-11-28 19:16:44 +00:00
|
|
|
match generic_args {
|
|
|
|
|
GenericArgs::AngleBracketed(data) => {
|
2020-03-22 04:40:05 +01:00
|
|
|
self.check_generic_args_before_constraints(data);
|
|
|
|
|
|
|
|
|
|
for arg in &data.args {
|
|
|
|
|
match arg {
|
|
|
|
|
AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
|
2024-05-27 23:53:46 +02:00
|
|
|
// Associated type bindings such as `Item = impl Debug` in
|
|
|
|
|
// `Iterator<Item = Debug>` are allowed to contain nested `impl Trait`.
|
2020-03-22 04:40:05 +01:00
|
|
|
AngleBracketedArg::Constraint(constraint) => {
|
|
|
|
|
self.with_impl_trait(None, |this| {
|
2024-05-27 23:53:46 +02:00
|
|
|
this.visit_assoc_item_constraint(constraint);
|
2020-03-22 04:40:05 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-18 12:35:14 +01:00
|
|
|
}
|
2022-11-28 19:16:44 +00:00
|
|
|
GenericArgs::Parenthesized(data) => {
|
2019-01-18 12:35:14 +01:00
|
|
|
walk_list!(self, visit_ty, &data.inputs);
|
2020-02-15 12:10:59 +09:00
|
|
|
if let FnRetTy::Ty(ty) = &data.output {
|
2019-03-11 15:14:24 +01:00
|
|
|
// `-> Foo` syntax is essentially an associated type binding,
|
|
|
|
|
// so it is also allowed to contain nested `impl Trait`.
|
2019-12-01 16:00:08 +01:00
|
|
|
self.with_impl_trait(None, |this| this.visit_ty(ty));
|
2019-01-18 12:35:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-06-28 11:49:16 -04:00
|
|
|
GenericArgs::ParenthesizedElided(_span) => {}
|
2019-01-18 12:35:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-27 16:56:01 +01:00
|
|
|
fn visit_generics(&mut self, generics: &'a Generics) {
|
2021-03-01 12:50:09 +01:00
|
|
|
let mut prev_param_default = None;
|
2018-05-27 16:56:01 +01:00
|
|
|
for param in &generics.params {
|
2020-07-22 22:58:54 +02:00
|
|
|
match param.kind {
|
|
|
|
|
GenericParamKind::Lifetime => (),
|
2021-03-01 12:50:09 +01:00
|
|
|
GenericParamKind::Type { default: Some(_), .. }
|
|
|
|
|
| GenericParamKind::Const { default: Some(_), .. } => {
|
|
|
|
|
prev_param_default = Some(param.ident.span);
|
2020-07-22 22:58:54 +02:00
|
|
|
}
|
|
|
|
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
2021-03-01 12:50:09 +01:00
|
|
|
if let Some(span) = prev_param_default {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx().emit_err(errors::GenericDefaultTrailing { span });
|
2020-07-22 22:58:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2017-10-16 21:07:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-01-17 21:18:29 +03:00
|
|
|
}
|
2019-02-05 16:52:17 +01:00
|
|
|
|
2023-12-18 08:33:03 +11:00
|
|
|
validate_generic_param_order(self.dcx(), &generics.params, generics.span);
|
2019-02-05 16:52:17 +01:00
|
|
|
|
2018-05-27 16:56:01 +01:00
|
|
|
for predicate in &generics.where_clause.predicates {
|
2024-11-25 16:38:35 +08:00
|
|
|
let span = predicate.span;
|
|
|
|
|
if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {
|
|
|
|
|
deny_equality_constraints(self, predicate, span, generics);
|
2017-01-17 21:18:29 +03:00
|
|
|
}
|
|
|
|
|
}
|
2021-04-21 03:12:04 -04:00
|
|
|
walk_list!(self, visit_generic_param, &generics.params);
|
|
|
|
|
for predicate in &generics.where_clause.predicates {
|
2024-11-25 16:38:35 +08:00
|
|
|
match &predicate.kind {
|
|
|
|
|
WherePredicateKind::BoundPredicate(bound_pred) => {
|
2021-04-21 11:49:59 -04:00
|
|
|
// This is slightly complicated. Our representation for poly-trait-refs contains a single
|
|
|
|
|
// binder and thus we only allow a single level of quantification. However,
|
|
|
|
|
// the syntax of Rust permits quantification in two places in where clauses,
|
|
|
|
|
// e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
|
|
|
|
|
// defined, then error.
|
|
|
|
|
if !bound_pred.bound_generic_params.is_empty() {
|
|
|
|
|
for bound in &bound_pred.bounds {
|
|
|
|
|
match bound {
|
2024-10-13 09:31:22 -04:00
|
|
|
GenericBound::Trait(t) => {
|
2021-04-21 11:49:59 -04:00
|
|
|
if !t.bound_generic_params.is_empty() {
|
2023-12-18 08:33:03 +11:00
|
|
|
self.dcx()
|
2023-02-25 13:53:42 +00:00
|
|
|
.emit_err(errors::NestedLifetimes { span: t.span });
|
2021-04-21 11:49:59 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GenericBound::Outlives(_) => {}
|
2024-06-05 16:18:52 -04:00
|
|
|
GenericBound::Use(..) => {}
|
2021-04-21 11:49:59 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-21 03:12:04 -04:00
|
|
|
}
|
2021-04-21 11:49:59 -04:00
|
|
|
_ => {}
|
2021-04-21 03:12:04 -04:00
|
|
|
}
|
2021-04-21 11:49:59 -04:00
|
|
|
self.visit_where_predicate(predicate);
|
2021-04-21 03:12:04 -04:00
|
|
|
}
|
2017-01-17 21:18:29 +03:00
|
|
|
}
|
2017-06-24 18:26:04 +00:00
|
|
|
|
2022-04-21 10:09:32 +08:00
|
|
|
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
2024-06-05 16:18:52 -04:00
|
|
|
match bound {
|
2024-10-13 09:31:22 -04:00
|
|
|
GenericBound::Trait(trait_ref) => {
|
|
|
|
|
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
|
2024-02-23 16:39:57 +03:00
|
|
|
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
|
2024-10-09 09:01:57 +02:00
|
|
|
if !self.features.more_maybe_bounds() =>
|
2024-02-23 16:39:57 +03:00
|
|
|
{
|
2024-09-16 09:30:45 +10:00
|
|
|
self.sess
|
2024-02-23 16:39:57 +03:00
|
|
|
.create_feature_err(
|
|
|
|
|
errors::OptionalTraitSupertrait {
|
|
|
|
|
span: trait_ref.span,
|
|
|
|
|
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
|
|
|
|
|
},
|
|
|
|
|
sym::more_maybe_bounds,
|
|
|
|
|
)
|
|
|
|
|
.emit();
|
2024-06-05 16:18:52 -04:00
|
|
|
}
|
2024-02-23 16:39:57 +03:00
|
|
|
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
|
2024-10-09 09:01:57 +02:00
|
|
|
if !self.features.more_maybe_bounds() =>
|
2024-02-23 16:39:57 +03:00
|
|
|
{
|
2024-09-16 09:30:45 +10:00
|
|
|
self.sess
|
2024-02-23 16:39:57 +03:00
|
|
|
.create_feature_err(
|
|
|
|
|
errors::OptionalTraitObject { span: trait_ref.span },
|
|
|
|
|
sym::more_maybe_bounds,
|
|
|
|
|
)
|
|
|
|
|
.emit();
|
2024-06-05 16:18:52 -04:00
|
|
|
}
|
|
|
|
|
(
|
|
|
|
|
BoundKind::TraitObject,
|
|
|
|
|
BoundConstness::Always(_),
|
|
|
|
|
BoundPolarity::Positive,
|
|
|
|
|
) => {
|
|
|
|
|
self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
|
|
|
|
|
}
|
|
|
|
|
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
2024-07-09 09:54:19 +00:00
|
|
|
if let Some(reason) = self.disallow_tilde_const =>
|
2024-06-05 16:18:52 -04:00
|
|
|
{
|
|
|
|
|
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
2023-12-18 17:55:55 +01:00
|
|
|
}
|
2024-06-05 16:18:52 -04:00
|
|
|
|
|
|
|
|
// Negative trait bounds are not allowed to have associated constraints
|
2024-10-13 09:31:22 -04:00
|
|
|
if let BoundPolarity::Negative(_) = trait_ref.modifiers.polarity
|
2024-06-05 16:18:52 -04:00
|
|
|
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
2022-10-20 19:32:16 +00:00
|
|
|
{
|
2024-06-05 16:18:52 -04:00
|
|
|
match segment.args.as_deref() {
|
|
|
|
|
Some(ast::GenericArgs::AngleBracketed(args)) => {
|
|
|
|
|
for arg in &args.args {
|
|
|
|
|
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
|
|
|
|
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
|
|
|
|
|
span: constraint.span,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-11 15:01:58 +01:00
|
|
|
}
|
2024-06-05 16:18:52 -04:00
|
|
|
// The lowered form of parenthesized generic args contains an associated type binding.
|
|
|
|
|
Some(ast::GenericArgs::Parenthesized(args)) => {
|
|
|
|
|
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
|
|
|
|
|
span: args.span,
|
2023-12-27 17:57:19 +01:00
|
|
|
});
|
|
|
|
|
}
|
2024-06-28 11:49:16 -04:00
|
|
|
Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {}
|
2023-12-27 17:57:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-04-25 05:47:05 +00:00
|
|
|
}
|
2024-06-05 16:18:52 -04:00
|
|
|
GenericBound::Outlives(_) => {}
|
|
|
|
|
GenericBound::Use(_, span) => match ctxt {
|
|
|
|
|
BoundKind::Impl => {}
|
|
|
|
|
BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {
|
|
|
|
|
self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {
|
|
|
|
|
loc: ctxt.descr(),
|
|
|
|
|
span: *span,
|
2024-06-05 16:31:12 -04:00
|
|
|
});
|
2024-06-05 16:18:52 -04:00
|
|
|
}
|
|
|
|
|
},
|
2023-04-25 05:47:05 +00:00
|
|
|
}
|
2020-01-04 16:29:45 -08:00
|
|
|
|
|
|
|
|
visit::walk_param_bound(self, bound)
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
|
|
|
|
// Only associated `fn`s can have `self` parameters.
|
|
|
|
|
let self_semantic = match fk.ctxt() {
|
|
|
|
|
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
|
|
|
|
|
_ => SelfSemantic::No,
|
|
|
|
|
};
|
|
|
|
|
self.check_fn_decl(fk.decl(), self_semantic);
|
|
|
|
|
|
2024-06-20 16:19:43 -03:00
|
|
|
if let Some(&FnHeader { safety, .. }) = fk.header() {
|
|
|
|
|
self.check_item_safety(span, safety);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 01:42:10 -04:00
|
|
|
self.check_c_variadic_type(fk);
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2023-11-30 16:39:56 -08:00
|
|
|
// Functions cannot both be `const async` or `const gen`
|
2023-02-25 13:53:42 +00:00
|
|
|
if let Some(&FnHeader {
|
2024-09-11 18:22:37 -04:00
|
|
|
constness: Const::Yes(const_span),
|
2023-12-08 21:46:30 +00:00
|
|
|
coroutine_kind: Some(coroutine_kind),
|
2020-01-30 13:02:06 +01:00
|
|
|
..
|
|
|
|
|
}) = fk.header()
|
|
|
|
|
{
|
2024-09-11 18:22:37 -04:00
|
|
|
self.dcx().emit_err(errors::ConstAndCoroutine {
|
|
|
|
|
spans: vec![coroutine_kind.span(), const_span],
|
|
|
|
|
const_span,
|
|
|
|
|
coroutine_span: coroutine_kind.span(),
|
|
|
|
|
coroutine_kind: coroutine_kind.as_str(),
|
2023-02-25 13:53:42 +00:00
|
|
|
span,
|
|
|
|
|
});
|
2020-01-30 13:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
2021-07-08 21:58:05 +02:00
|
|
|
if let FnKind::Fn(
|
|
|
|
|
_,
|
2021-11-19 22:03:43 +01:00
|
|
|
_,
|
2025-01-27 16:30:02 -08:00
|
|
|
Fn {
|
|
|
|
|
sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
|
|
|
|
|
..
|
|
|
|
|
},
|
2021-07-08 21:58:05 +02:00
|
|
|
) = fk
|
|
|
|
|
{
|
2025-04-08 05:30:21 +03:00
|
|
|
self.handle_missing_abi(*extern_span, id);
|
2021-07-08 21:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
// Functions without bodies cannot have patterns.
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk {
|
2020-11-30 23:24:08 +09:00
|
|
|
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
|
2020-01-30 00:18:54 +01:00
|
|
|
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
|
2020-11-30 23:24:08 +09:00
|
|
|
if let Some(ident) = ident {
|
2024-05-20 17:47:54 +00:00
|
|
|
self.lint_buffer.buffer_lint(
|
2020-11-30 23:24:08 +09:00
|
|
|
PATTERNS_IN_FNS_WITHOUT_BODY,
|
|
|
|
|
id,
|
|
|
|
|
span,
|
2024-04-14 17:59:54 +00:00
|
|
|
BuiltinLintDiag::PatternsInFnsWithoutBody {
|
|
|
|
|
span,
|
|
|
|
|
ident,
|
|
|
|
|
is_foreign: matches!(ctxt, FnCtxt::Foreign),
|
|
|
|
|
},
|
2020-11-30 23:24:08 +09:00
|
|
|
)
|
|
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
} else {
|
2023-02-25 13:53:42 +00:00
|
|
|
match ctxt {
|
2023-12-18 08:33:03 +11:00
|
|
|
FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }),
|
|
|
|
|
_ => self.dcx().emit_err(errors::PatternInBodiless { span }),
|
2023-02-25 13:53:42 +00:00
|
|
|
};
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
});
|
2019-06-09 07:58:40 -03:00
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
|
2022-10-20 19:32:16 +00:00
|
|
|
let tilde_const_allowed =
|
|
|
|
|
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|
2024-01-02 00:57:30 +01:00
|
|
|
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
|
|
|
|
|
&& self
|
|
|
|
|
.outer_trait_or_trait_impl
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(TraitOrTraitImpl::constness)
|
|
|
|
|
.is_some();
|
2022-10-20 19:32:16 +00:00
|
|
|
|
2024-07-09 09:54:19 +00:00
|
|
|
let disallowed = (!tilde_const_allowed).then(|| match fk {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span },
|
2024-08-24 01:44:52 +00:00
|
|
|
FnKind::Closure(..) => TildeConstReason::Closure,
|
2024-07-09 09:54:19 +00:00
|
|
|
});
|
2022-10-20 19:32:16 +00:00
|
|
|
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
2019-06-09 07:58:40 -03:00
|
|
|
}
|
2019-11-07 11:26:36 +01:00
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
2025-04-01 14:49:58 +11:00
|
|
|
if let Some(ident) = item.kind.ident()
|
|
|
|
|
&& attr::contains_name(&item.attrs, sym::no_mangle)
|
|
|
|
|
{
|
|
|
|
|
self.check_nomangle_item_asciionly(ident, item.span);
|
2021-08-08 02:10:57 +08:00
|
|
|
}
|
|
|
|
|
|
2024-01-02 00:57:30 +01:00
|
|
|
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
2020-02-23 10:24:30 +01:00
|
|
|
self.check_defaultness(item.span, item.kind.defaultness());
|
2019-12-02 02:53:18 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-25 09:00:35 +00:00
|
|
|
if let AssocCtxt::Impl { .. } = ctxt {
|
2020-01-30 00:18:54 +01:00
|
|
|
match &item.kind {
|
2023-03-29 12:34:05 +00:00
|
|
|
AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
2023-03-29 09:20:45 +00:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
2021-11-07 16:43:49 +08:00
|
|
|
AssocItemKind::Fn(box Fn { body, .. }) => {
|
2024-09-30 21:07:36 +03:00
|
|
|
if body.is_none() && !self.is_sdylib_interface {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
2022-08-19 02:43:01 +09:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
2023-07-11 01:11:21 +02:00
|
|
|
AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
|
2022-08-19 02:43:01 +09:00
|
|
|
if ty.is_none() {
|
2023-12-18 22:21:37 +11:00
|
|
|
self.dcx().emit_err(errors::AssocTypeWithoutBody {
|
2022-08-19 02:43:01 +09:00
|
|
|
span: item.span,
|
|
|
|
|
replace_span: self.ending_semi_or_hi(item.span),
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-02-14 12:55:42 +01:00
|
|
|
self.check_type_no_bounds(bounds, "`impl`s");
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-02 02:38:33 +01:00
|
|
|
|
2023-08-09 16:44:06 +02:00
|
|
|
if let AssocItemKind::Type(ty_alias) = &item.kind
|
|
|
|
|
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
|
2023-07-11 01:11:21 +02:00
|
|
|
{
|
2024-02-20 04:41:01 +01:00
|
|
|
let sugg = match err.sugg {
|
|
|
|
|
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
|
|
|
|
|
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
|
|
|
|
|
Some((right, snippet))
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-05-20 17:47:54 +00:00
|
|
|
self.lint_buffer.buffer_lint(
|
2023-08-09 16:44:06 +02:00
|
|
|
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
2023-07-11 01:11:21 +02:00
|
|
|
item.id,
|
2023-08-09 16:44:06 +02:00
|
|
|
err.span,
|
2024-04-15 18:07:22 +00:00
|
|
|
BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
|
2023-07-11 01:11:21 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-02 00:57:30 +01:00
|
|
|
if let Some(parent) = &self.outer_trait_or_trait_impl {
|
2023-04-03 21:09:06 -05:00
|
|
|
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
2021-11-07 16:43:49 +08:00
|
|
|
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
2024-01-02 00:57:30 +01:00
|
|
|
self.check_trait_fn_not_const(sig.header.constness, parent);
|
2020-01-30 00:18:54 +01:00
|
|
|
}
|
2019-12-02 02:38:33 +01:00
|
|
|
}
|
2020-01-30 00:18:54 +01:00
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
if let AssocItemKind::Const(ci) = &item.kind {
|
|
|
|
|
self.check_item_named(ci.ident, "const");
|
2020-02-14 15:56:05 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:37:25 +01:00
|
|
|
let parent_is_const =
|
|
|
|
|
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
|
|
|
|
|
|
2022-11-28 19:16:44 +00:00
|
|
|
match &item.kind {
|
2025-01-27 16:30:02 -08:00
|
|
|
AssocItemKind::Fn(func)
|
2024-01-12 16:37:25 +01:00
|
|
|
if parent_is_const
|
2021-09-03 10:37:57 +00:00
|
|
|
|| ctxt == AssocCtxt::Trait
|
2025-01-27 16:30:02 -08:00
|
|
|
|| matches!(func.sig.header.constness, Const::Yes(_)) =>
|
2021-08-25 11:53:16 +00:00
|
|
|
{
|
2025-04-01 12:04:56 +11:00
|
|
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
|
2021-08-25 11:53:16 +00:00
|
|
|
self.visit_fn(kind, item.span, item.id);
|
|
|
|
|
}
|
2024-01-12 16:37:25 +01:00
|
|
|
AssocItemKind::Type(_) => {
|
|
|
|
|
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
|
|
|
|
Some(TraitOrTraitImpl::Trait { .. }) => {
|
2024-07-09 09:54:19 +00:00
|
|
|
TildeConstReason::TraitAssocTy { span: item.span }
|
2024-01-12 16:37:25 +01:00
|
|
|
}
|
|
|
|
|
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
|
2024-07-09 09:54:19 +00:00
|
|
|
TildeConstReason::TraitImplAssocTy { span: item.span }
|
2024-01-12 16:37:25 +01:00
|
|
|
}
|
2024-07-09 09:54:19 +00:00
|
|
|
None => TildeConstReason::InherentAssocTy { span: item.span },
|
2024-01-12 16:37:25 +01:00
|
|
|
});
|
|
|
|
|
self.with_tilde_const(disallowed, |this| {
|
|
|
|
|
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-01-02 00:57:30 +01:00
|
|
|
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
2021-08-25 11:53:16 +00:00
|
|
|
}
|
2019-12-02 02:38:33 +01:00
|
|
|
}
|
2016-05-22 17:51:22 +03:00
|
|
|
}
|
|
|
|
|
|
2020-05-04 11:09:10 -07:00
|
|
|
/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
|
|
|
|
|
/// like it's setting an associated type, provide an appropriate suggestion.
|
2020-04-08 11:10:16 -07:00
|
|
|
fn deny_equality_constraints(
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_session\src\config.rs:2013:16
|
2013 | early_dcx: &mut EarlyDiagCtxt,
| ^^^^^^^^^^^^^^^^^^ help: consider changing to: `&EarlyDiagCtxt`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_ast_passes\src\ast_validation.rs:1555:11
|
1555 | this: &mut AstValidator<'_>,
| ^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&AstValidator<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_infer\src\infer\snapshot\fudge.rs:16:12
|
16 | table: &mut UnificationTable<'_, 'tcx, T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&UnificationTable<'_, 'tcx, T>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_expand\src\expand.rs:961:13
|
961 | parser: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= warning: changing this function will impact semver compatibility
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 11:30:49 +03:00
|
|
|
this: &AstValidator<'_>,
|
2020-04-08 11:10:16 -07:00
|
|
|
predicate: &WhereEqPredicate,
|
2024-11-25 16:38:35 +08:00
|
|
|
predicate_span: Span,
|
2020-04-08 11:10:16 -07:00
|
|
|
generics: &Generics,
|
|
|
|
|
) {
|
2024-11-25 16:38:35 +08:00
|
|
|
let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };
|
2020-04-08 11:10:16 -07:00
|
|
|
|
|
|
|
|
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
2023-10-26 16:49:03 +11:00
|
|
|
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
|
|
|
|
|
&& let TyKind::Path(None, path) = &qself.ty.kind
|
|
|
|
|
&& let [PathSegment { ident, args: None, .. }] = &path.segments[..]
|
|
|
|
|
{
|
|
|
|
|
for param in &generics.params {
|
|
|
|
|
if param.ident == *ident
|
|
|
|
|
&& let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..]
|
|
|
|
|
{
|
|
|
|
|
// Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
|
|
|
|
|
let mut assoc_path = full_path.clone();
|
|
|
|
|
// Remove `Bar` from `Foo::Bar`.
|
|
|
|
|
assoc_path.segments.pop();
|
|
|
|
|
let len = assoc_path.segments.len() - 1;
|
|
|
|
|
let gen_args = args.as_deref().cloned();
|
|
|
|
|
// Build `<Bar = RhsTy>`.
|
2024-05-27 23:53:46 +02:00
|
|
|
let arg = AngleBracketedArg::Constraint(AssocItemConstraint {
|
2023-10-26 16:49:03 +11:00
|
|
|
id: rustc_ast::node_id::DUMMY_NODE_ID,
|
|
|
|
|
ident: *ident,
|
|
|
|
|
gen_args,
|
2024-05-27 23:53:46 +02:00
|
|
|
kind: AssocItemConstraintKind::Equality {
|
|
|
|
|
term: predicate.rhs_ty.clone().into(),
|
|
|
|
|
},
|
2023-10-26 16:49:03 +11:00
|
|
|
span: ident.span,
|
|
|
|
|
});
|
|
|
|
|
// Add `<Bar = RhsTy>` to `Foo`.
|
|
|
|
|
match &mut assoc_path.segments[len].args {
|
|
|
|
|
Some(args) => match args.deref_mut() {
|
2024-06-28 11:49:16 -04:00
|
|
|
GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-10-26 16:49:03 +11:00
|
|
|
GenericArgs::AngleBracketed(args) => {
|
|
|
|
|
args.args.push(arg);
|
2020-04-08 11:10:16 -07:00
|
|
|
}
|
2023-10-26 16:49:03 +11:00
|
|
|
},
|
|
|
|
|
empty_args => {
|
|
|
|
|
*empty_args = Some(
|
2023-11-13 08:24:55 -05:00
|
|
|
AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(),
|
2023-10-26 16:49:03 +11:00
|
|
|
);
|
2020-04-08 11:10:16 -07:00
|
|
|
}
|
|
|
|
|
}
|
2023-10-26 16:49:03 +11:00
|
|
|
err.assoc = Some(errors::AssociatedSuggestion {
|
2024-11-25 16:38:35 +08:00
|
|
|
span: predicate_span,
|
2023-10-26 16:49:03 +11:00
|
|
|
ident: *ident,
|
|
|
|
|
param: param.ident,
|
|
|
|
|
path: pprust::path_to_string(&assoc_path),
|
|
|
|
|
})
|
2020-04-08 11:10:16 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-08 00:26:42 +00:00
|
|
|
|
|
|
|
|
let mut suggest =
|
|
|
|
|
|poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
|
|
|
|
|
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
|
|
|
|
|
let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
|
|
|
|
|
let ty = pprust::ty_to_string(&predicate.rhs_ty);
|
|
|
|
|
let (args, span) = match &trait_segment.args {
|
|
|
|
|
Some(args) => match args.deref() {
|
|
|
|
|
ast::GenericArgs::AngleBracketed(args) => {
|
|
|
|
|
let Some(arg) = args.args.last() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
|
|
|
|
|
}
|
|
|
|
|
_ => return,
|
|
|
|
|
},
|
|
|
|
|
None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
|
|
|
|
|
};
|
|
|
|
|
let removal_span = if generics.where_clause.predicates.len() == 1 {
|
|
|
|
|
// We're removing th eonly where bound left, remove the whole thing.
|
|
|
|
|
generics.where_clause.span
|
|
|
|
|
} else {
|
2024-11-25 16:38:35 +08:00
|
|
|
let mut span = predicate_span;
|
2025-04-02 14:21:33 +11:00
|
|
|
let mut prev_span: Option<Span> = None;
|
2024-02-08 00:26:42 +00:00
|
|
|
let mut preds = generics.where_clause.predicates.iter().peekable();
|
|
|
|
|
// Find the predicate that shouldn't have been in the where bound list.
|
|
|
|
|
while let Some(pred) = preds.next() {
|
2024-11-25 16:38:35 +08:00
|
|
|
if let WherePredicateKind::EqPredicate(_) = pred.kind
|
|
|
|
|
&& pred.span == predicate_span
|
2021-11-25 01:38:05 +00:00
|
|
|
{
|
2024-02-08 00:26:42 +00:00
|
|
|
if let Some(next) = preds.peek() {
|
|
|
|
|
// This is the first predicate, remove the trailing comma as well.
|
2024-11-25 16:38:35 +08:00
|
|
|
span = span.with_hi(next.span.lo());
|
2025-04-02 14:21:33 +11:00
|
|
|
} else if let Some(prev_span) = prev_span {
|
2024-02-08 00:26:42 +00:00
|
|
|
// Remove the previous comma as well.
|
2025-04-02 14:21:33 +11:00
|
|
|
span = span.with_lo(prev_span.hi());
|
2021-11-25 01:38:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 14:21:33 +11:00
|
|
|
prev_span = Some(pred.span);
|
2024-02-08 00:26:42 +00:00
|
|
|
}
|
|
|
|
|
span
|
|
|
|
|
};
|
|
|
|
|
err.assoc2 = Some(errors::AssociatedSuggestion2 {
|
|
|
|
|
span,
|
|
|
|
|
args,
|
|
|
|
|
predicate: removal_span,
|
|
|
|
|
trait_segment: trait_segment.ident,
|
|
|
|
|
potential_assoc: potential_assoc.ident,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-11-25 01:38:05 +00:00
|
|
|
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
2024-02-07 20:01:09 +00:00
|
|
|
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
|
|
|
|
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
|
2024-11-25 16:38:35 +08:00
|
|
|
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
|
|
|
|
WherePredicateKind::BoundPredicate(p) => Some(&p.bounds),
|
2024-02-07 20:01:09 +00:00
|
|
|
_ => None,
|
|
|
|
|
}),
|
|
|
|
|
) {
|
|
|
|
|
for bound in bounds {
|
2024-10-13 09:31:22 -04:00
|
|
|
if let GenericBound::Trait(poly) = bound
|
|
|
|
|
&& poly.modifiers == TraitBoundModifiers::NONE
|
|
|
|
|
{
|
2024-02-07 20:01:09 +00:00
|
|
|
if full_path.segments[..full_path.segments.len() - 1]
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|segment| segment.ident.name)
|
|
|
|
|
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
|
|
|
|
|
.all(|(a, b)| a == b)
|
2024-02-08 00:26:42 +00:00
|
|
|
&& let Some(potential_assoc) = full_path.segments.iter().last()
|
2024-02-07 20:01:09 +00:00
|
|
|
{
|
2024-02-08 00:26:42 +00:00
|
|
|
suggest(poly, potential_assoc, predicate);
|
2024-02-07 20:01:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
2021-11-25 01:38:05 +00:00
|
|
|
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
2024-02-07 20:01:09 +00:00
|
|
|
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
|
2024-11-25 16:38:35 +08:00
|
|
|
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
|
|
|
|
WherePredicateKind::BoundPredicate(p)
|
2024-02-07 20:01:09 +00:00
|
|
|
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
|
|
|
|
|
&& let [segment] = &path.segments[..] =>
|
|
|
|
|
{
|
|
|
|
|
Some((segment.ident, &p.bounds))
|
|
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
}),
|
|
|
|
|
) {
|
|
|
|
|
if ident == potential_param.ident {
|
|
|
|
|
for bound in bounds {
|
2024-10-13 09:31:22 -04:00
|
|
|
if let ast::GenericBound::Trait(poly) = bound
|
|
|
|
|
&& poly.modifiers == TraitBoundModifiers::NONE
|
|
|
|
|
{
|
2024-02-08 00:26:42 +00:00
|
|
|
suggest(poly, potential_assoc, predicate);
|
2021-11-25 01:38:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-18 08:33:03 +11:00
|
|
|
this.dcx().emit_err(err);
|
2020-04-08 11:10:16 -07:00
|
|
|
}
|
|
|
|
|
|
2023-08-09 20:28:00 +08:00
|
|
|
pub fn check_crate(
|
2024-09-16 09:30:45 +10:00
|
|
|
sess: &Session,
|
2023-08-09 20:28:00 +08:00
|
|
|
features: &Features,
|
|
|
|
|
krate: &Crate,
|
2024-09-30 21:07:36 +03:00
|
|
|
is_sdylib_interface: bool,
|
2023-08-09 20:28:00 +08:00
|
|
|
lints: &mut LintBuffer,
|
|
|
|
|
) -> bool {
|
2019-01-17 07:28:39 +01:00
|
|
|
let mut validator = AstValidator {
|
2024-09-16 09:30:45 +10:00
|
|
|
sess,
|
2023-08-09 20:28:00 +08:00
|
|
|
features,
|
2025-04-02 14:21:33 +11:00
|
|
|
extern_mod_span: None,
|
2024-01-02 00:57:30 +01:00
|
|
|
outer_trait_or_trait_impl: None,
|
2019-01-17 07:28:39 +01:00
|
|
|
has_proc_macro_decls: false,
|
2025-04-02 14:21:33 +11:00
|
|
|
outer_impl_trait_span: None,
|
2024-07-09 09:54:19 +00:00
|
|
|
disallow_tilde_const: Some(TildeConstReason::Item),
|
2024-05-27 15:35:34 -03:00
|
|
|
extern_mod_safety: None,
|
2025-05-03 15:18:30 +02:00
|
|
|
lint_node_id: CRATE_NODE_ID,
|
2024-09-30 21:07:36 +03:00
|
|
|
is_sdylib_interface,
|
2019-10-25 09:15:33 -04:00
|
|
|
lint_buffer: lints,
|
2019-01-17 07:28:39 +01:00
|
|
|
};
|
|
|
|
|
visit::walk_crate(&mut validator, krate);
|
|
|
|
|
|
2019-07-19 00:24:58 +03:00
|
|
|
validator.has_proc_macro_decls
|
2016-05-22 17:51:22 +03:00
|
|
|
}
|