]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | // Validate AST before lowering it to HIR. |
3157f602 XL |
2 | // |
3 | // This pass is supposed to catch things that fit into AST data structures, | |
4 | // but not permitted by the language. It runs after expansion when AST is frozen, | |
5 | // so it can check for erroneous constructions produced by syntax extensions. | |
6 | // This pass is supposed to perform only simple checks not requiring name resolution | |
7 | // or type checking or some other kind of complex analysis. | |
8 | ||
ba9703b0 | 9 | use itertools::{Either, Itertools}; |
ba9703b0 | 10 | use rustc_ast::ptr::P; |
04454e1e | 11 | use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; |
74b04a01 | 12 | use rustc_ast::walk_list; |
3dfed10e | 13 | use rustc_ast::*; |
5e7ed085 | 14 | use rustc_ast_pretty::pprust::{self, State}; |
9fa01778 | 15 | use rustc_data_structures::fx::FxHashMap; |
2b03887a | 16 | use rustc_macros::Subdiagnostic; |
60c5eb7d | 17 | use rustc_parse::validate_attr; |
5e7ed085 FG |
18 | use rustc_session::lint::builtin::{ |
19 | DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, | |
20 | }; | |
5869c6ff | 21 | use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; |
dfeec247 | 22 | use rustc_session::Session; |
94222f64 | 23 | use rustc_span::source_map::Spanned; |
f9f354fc | 24 | use rustc_span::symbol::{kw, sym, Ident}; |
dfeec247 | 25 | use rustc_span::Span; |
94222f64 | 26 | use rustc_target::spec::abi; |
dfeec247 | 27 | use std::mem; |
a2a8927a | 28 | use std::ops::{Deref, DerefMut}; |
9ffffee4 | 29 | use thin_vec::thin_vec; |
74b04a01 | 30 | |
9ffffee4 FG |
31 | use crate::errors; |
32 | use crate::fluent_generated as fluent; | |
74b04a01 XL |
33 | |
34 | /// Is `self` allowed semantically as the first parameter in an `FnDecl`? | |
35 | enum SelfSemantic { | |
36 | Yes, | |
37 | No, | |
38 | } | |
dfeec247 | 39 | |
2b03887a FG |
40 | /// What is the context that prevents using `~const`? |
41 | enum DisallowTildeConstContext<'a> { | |
42 | TraitObject, | |
2b03887a FG |
43 | Fn(FnKind<'a>), |
44 | } | |
45 | ||
3157f602 XL |
46 | struct AstValidator<'a> { |
47 | session: &'a Session, | |
74b04a01 XL |
48 | |
49 | /// The span of the `extern` in an `extern { ... }` block, if any. | |
50 | extern_mod: Option<&'a Item>, | |
51 | ||
52 | /// Are we inside a trait impl? | |
53 | in_trait_impl: bool, | |
54 | ||
94222f64 XL |
55 | in_const_trait_impl: bool, |
56 | ||
9fa01778 | 57 | has_proc_macro_decls: bool, |
9fa01778 | 58 | |
48663c56 XL |
59 | /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. |
60 | /// Nested `impl Trait` _is_ allowed in associated type position, | |
dc9dc135 | 61 | /// e.g., `impl Iterator<Item = impl Debug>`. |
60c5eb7d | 62 | outer_impl_trait: Option<Span>, |
9fa01778 | 63 | |
2b03887a | 64 | disallow_tilde_const: Option<DisallowTildeConstContext<'a>>, |
dfeec247 | 65 | |
48663c56 XL |
66 | /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` |
67 | /// or `Foo::Bar<impl Trait>` | |
9fa01778 XL |
68 | is_impl_trait_banned: bool, |
69 | ||
5e7ed085 FG |
70 | /// See [ForbiddenLetReason] |
71 | forbidden_let_reason: Option<ForbiddenLetReason>, | |
94222f64 | 72 | |
dfeec247 | 73 | lint_buffer: &'a mut LintBuffer, |
3157f602 XL |
74 | } |
75 | ||
76 | impl<'a> AstValidator<'a> { | |
94222f64 XL |
77 | fn with_in_trait_impl( |
78 | &mut self, | |
79 | is_in: bool, | |
80 | constness: Option<Const>, | |
81 | f: impl FnOnce(&mut Self), | |
82 | ) { | |
74b04a01 | 83 | let old = mem::replace(&mut self.in_trait_impl, is_in); |
94222f64 XL |
84 | let old_const = |
85 | mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_)))); | |
74b04a01 XL |
86 | f(self); |
87 | self.in_trait_impl = old; | |
94222f64 | 88 | self.in_const_trait_impl = old_const; |
74b04a01 XL |
89 | } |
90 | ||
9fa01778 XL |
91 | fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { |
92 | let old = mem::replace(&mut self.is_impl_trait_banned, true); | |
93 | f(self); | |
94 | self.is_impl_trait_banned = old; | |
95 | } | |
96 | ||
2b03887a FG |
97 | fn with_tilde_const( |
98 | &mut self, | |
99 | disallowed: Option<DisallowTildeConstContext<'a>>, | |
100 | f: impl FnOnce(&mut Self), | |
101 | ) { | |
102 | let old = mem::replace(&mut self.disallow_tilde_const, disallowed); | |
94222f64 | 103 | f(self); |
2b03887a | 104 | self.disallow_tilde_const = old; |
94222f64 XL |
105 | } |
106 | ||
04454e1e | 107 | fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { |
2b03887a | 108 | self.with_tilde_const(None, f) |
04454e1e FG |
109 | } |
110 | ||
2b03887a FG |
111 | fn with_banned_tilde_const( |
112 | &mut self, | |
113 | ctx: DisallowTildeConstContext<'a>, | |
114 | f: impl FnOnce(&mut Self), | |
115 | ) { | |
116 | self.with_tilde_const(Some(ctx), f) | |
94222f64 XL |
117 | } |
118 | ||
5e7ed085 FG |
119 | fn with_let_management( |
120 | &mut self, | |
121 | forbidden_let_reason: Option<ForbiddenLetReason>, | |
122 | f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>), | |
123 | ) { | |
124 | let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason); | |
94222f64 | 125 | f(self, old); |
5e7ed085 | 126 | self.forbidden_let_reason = old; |
94222f64 XL |
127 | } |
128 | ||
129 | /// Emits an error banning the `let` expression provided in the given location. | |
5e7ed085 | 130 | fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { |
94222f64 XL |
131 | let sess = &self.session; |
132 | if sess.opts.unstable_features.is_nightly_build() { | |
9ffffee4 | 133 | sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); |
94222f64 | 134 | } else { |
9ffffee4 | 135 | sess.emit_err(errors::ForbiddenLetStable { span: expr.span }); |
94222f64 XL |
136 | } |
137 | } | |
138 | ||
5e7ed085 FG |
139 | fn check_gat_where( |
140 | &mut self, | |
141 | id: NodeId, | |
142 | before_predicates: &[WherePredicate], | |
143 | where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), | |
144 | ) { | |
145 | if !before_predicates.is_empty() { | |
146 | let mut state = State::new(); | |
147 | if !where_clauses.1.0 { | |
148 | state.space(); | |
149 | state.word_space("where"); | |
150 | } else { | |
151 | state.word_space(","); | |
152 | } | |
153 | let mut first = true; | |
154 | for p in before_predicates.iter() { | |
155 | if !first { | |
156 | state.word_space(","); | |
157 | } | |
158 | first = false; | |
159 | state.print_where_predicate(p); | |
160 | } | |
161 | let suggestion = state.s.eof(); | |
162 | self.lint_buffer.buffer_lint_with_diagnostic( | |
163 | DEPRECATED_WHERE_CLAUSE_LOCATION, | |
164 | id, | |
165 | where_clauses.0.1, | |
2b03887a | 166 | fluent::ast_passes_deprecated_where_clause_location, |
5e7ed085 FG |
167 | BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( |
168 | where_clauses.1.1.shrink_to_hi(), | |
169 | suggestion, | |
170 | ), | |
171 | ); | |
172 | } | |
173 | } | |
174 | ||
60c5eb7d | 175 | fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { |
9fa01778 | 176 | let old = mem::replace(&mut self.outer_impl_trait, outer); |
9c376795 | 177 | f(self); |
9fa01778 XL |
178 | self.outer_impl_trait = old; |
179 | } | |
180 | ||
dc9dc135 | 181 | // Mirrors `visit::walk_ty`, but tracks relevant state. |
9fa01778 | 182 | fn walk_ty(&mut self, t: &'a Ty) { |
487cf647 | 183 | match &t.kind { |
9fa01778 | 184 | TyKind::ImplTrait(..) => { |
60c5eb7d | 185 | self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) |
9fa01778 | 186 | } |
2b03887a FG |
187 | TyKind::TraitObject(..) => self |
188 | .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| { | |
189 | visit::walk_ty(this, t) | |
190 | }), | |
487cf647 | 191 | TyKind::Path(qself, path) => { |
9fa01778 XL |
192 | // We allow these: |
193 | // - `Option<impl Trait>` | |
194 | // - `option::Option<impl Trait>` | |
9ffffee4 | 195 | // - `option::Option<T>::Foo<impl Trait>` |
9fa01778 XL |
196 | // |
197 | // But not these: | |
198 | // - `<impl Trait>::Foo` | |
199 | // - `option::Option<impl Trait>::Foo`. | |
200 | // | |
201 | // To implement this, we disallow `impl Trait` from `qself` | |
202 | // (for cases like `<impl Trait>::Foo>`) | |
203 | // but we allow `impl Trait` in `GenericArgs` | |
204 | // iff there are no more PathSegments. | |
487cf647 | 205 | if let Some(qself) = qself { |
9fa01778 XL |
206 | // `impl Trait` in `qself` is always illegal |
207 | self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); | |
208 | } | |
209 | ||
210 | // Note that there should be a call to visit_path here, | |
211 | // so if any logic is added to process `Path`s a call to it should be | |
212 | // added both in visit_path and here. This code mirrors visit::walk_path. | |
213 | for (i, segment) in path.segments.iter().enumerate() { | |
214 | // Allow `impl Trait` iff we're on the final path segment | |
215 | if i == path.segments.len() - 1 { | |
f2b60f7d | 216 | self.visit_path_segment(segment); |
9fa01778 | 217 | } else { |
f2b60f7d | 218 | self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); |
9fa01778 XL |
219 | } |
220 | } | |
221 | } | |
222 | _ => visit::walk_ty(self, t), | |
223 | } | |
224 | } | |
225 | ||
dfeec247 | 226 | fn err_handler(&self) -> &rustc_errors::Handler { |
b7449926 | 227 | &self.session.diagnostic() |
3157f602 XL |
228 | } |
229 | ||
83c7162d | 230 | fn check_lifetime(&self, ident: Ident) { |
5869c6ff | 231 | let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; |
94b46f34 | 232 | if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { |
9ffffee4 | 233 | self.session.emit_err(errors::KeywordLifetime { span: ident.span }); |
ff7c6d11 XL |
234 | } |
235 | } | |
236 | ||
83c7162d | 237 | fn check_label(&self, ident: Ident) { |
94b46f34 | 238 | if ident.without_first_quote().is_reserved() { |
9ffffee4 | 239 | self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); |
3157f602 | 240 | } |
3157f602 XL |
241 | } |
242 | ||
9ffffee4 | 243 | fn invalid_visibility(&self, vis: &Visibility, note: Option<errors::InvalidVisibilityNote>) { |
1b1a35ee | 244 | if let VisibilityKind::Inherited = vis.kind { |
dfeec247 | 245 | return; |
8faf50e0 XL |
246 | } |
247 | ||
9ffffee4 | 248 | self.session.emit_err(errors::InvalidVisibility { |
f2b60f7d | 249 | span: vis.span, |
9ffffee4 | 250 | implied: vis.kind.is_pub().then_some(vis.span), |
f2b60f7d FG |
251 | note, |
252 | }); | |
3157f602 | 253 | } |
5bcae85e | 254 | |
5869c6ff | 255 | fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { |
60c5eb7d XL |
256 | for Param { pat, .. } in &decl.inputs { |
257 | match pat.kind { | |
f2b60f7d FG |
258 | PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {} |
259 | PatKind::Ident(BindingAnnotation::MUT, ident, None) => { | |
5869c6ff | 260 | report_err(pat.span, Some(ident), true) |
dfeec247 | 261 | } |
5869c6ff | 262 | _ => report_err(pat.span, None, false), |
5bcae85e SL |
263 | } |
264 | } | |
265 | } | |
9e0c209e | 266 | |
74b04a01 XL |
267 | fn check_trait_fn_not_const(&self, constness: Const) { |
268 | if let Const::Yes(span) = constness { | |
9ffffee4 | 269 | self.session.emit_err(errors::TraitFnConst { span }); |
0531ce1d XL |
270 | } |
271 | } | |
b7449926 | 272 | |
74b04a01 | 273 | fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { |
c295e0f8 | 274 | self.check_decl_num_args(fn_decl); |
74b04a01 XL |
275 | self.check_decl_cvaradic_pos(fn_decl); |
276 | self.check_decl_attrs(fn_decl); | |
277 | self.check_decl_self_param(fn_decl, self_semantic); | |
278 | } | |
279 | ||
c295e0f8 XL |
280 | /// Emits fatal error if function declaration has more than `u16::MAX` arguments |
281 | /// Error is fatal to prevent errors during typechecking | |
282 | fn check_decl_num_args(&self, fn_decl: &FnDecl) { | |
283 | let max_num_args: usize = u16::MAX.into(); | |
284 | if fn_decl.inputs.len() > max_num_args { | |
285 | let Param { span, .. } = fn_decl.inputs[0]; | |
9ffffee4 | 286 | self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args }); |
c295e0f8 XL |
287 | } |
288 | } | |
289 | ||
74b04a01 | 290 | fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) { |
dfeec247 XL |
291 | match &*fn_decl.inputs { |
292 | [Param { ty, span, .. }] => { | |
293 | if let TyKind::CVarArgs = ty.kind { | |
9ffffee4 | 294 | self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span }); |
dfeec247 XL |
295 | } |
296 | } | |
297 | [ps @ .., _] => { | |
298 | for Param { ty, span, .. } in ps { | |
299 | if let TyKind::CVarArgs = ty.kind { | |
9ffffee4 | 300 | self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span }); |
dfeec247 XL |
301 | } |
302 | } | |
303 | } | |
304 | _ => {} | |
305 | } | |
74b04a01 | 306 | } |
dfeec247 | 307 | |
74b04a01 | 308 | fn check_decl_attrs(&self, fn_decl: &FnDecl) { |
dc9dc135 XL |
309 | fn_decl |
310 | .inputs | |
311 | .iter() | |
312 | .flat_map(|i| i.attrs.as_ref()) | |
313 | .filter(|attr| { | |
923072b8 FG |
314 | let arr = [ |
315 | sym::allow, | |
316 | sym::cfg, | |
317 | sym::cfg_attr, | |
318 | sym::deny, | |
319 | sym::expect, | |
320 | sym::forbid, | |
321 | sym::warn, | |
322 | ]; | |
74b04a01 | 323 | !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) |
dc9dc135 | 324 | }) |
dfeec247 XL |
325 | .for_each(|attr| { |
326 | if attr.is_doc_comment() { | |
9ffffee4 | 327 | self.session.emit_err(errors::FnParamDocComment { span: attr.span }); |
dfeec247 | 328 | } else { |
9ffffee4 | 329 | self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span }); |
dfeec247 | 330 | } |
dc9dc135 | 331 | }); |
b7449926 | 332 | } |
dfeec247 | 333 | |
74b04a01 XL |
334 | fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { |
335 | if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { | |
336 | if param.is_self() { | |
9ffffee4 | 337 | self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span }); |
74b04a01 XL |
338 | } |
339 | } | |
340 | } | |
341 | ||
dfeec247 | 342 | fn check_defaultness(&self, span: Span, defaultness: Defaultness) { |
74b04a01 | 343 | if let Defaultness::Default(def_span) = defaultness { |
ba9703b0 | 344 | let span = self.session.source_map().guess_head_span(span); |
9ffffee4 | 345 | self.session.emit_err(errors::ForbiddenDefault { span, def_span }); |
dfeec247 XL |
346 | } |
347 | } | |
348 | ||
f2b60f7d FG |
349 | /// If `sp` ends with a semicolon, returns it as a `Span` |
350 | /// Otherwise, returns `sp.shrink_to_hi()` | |
351 | fn ending_semi_or_hi(&self, sp: Span) -> Span { | |
5e7ed085 FG |
352 | let source_map = self.session.source_map(); |
353 | let end = source_map.end_point(sp); | |
f2b60f7d FG |
354 | |
355 | if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { | |
5e7ed085 FG |
356 | end |
357 | } else { | |
358 | sp.shrink_to_hi() | |
74b04a01 XL |
359 | } |
360 | } | |
361 | ||
362 | fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { | |
dfeec247 XL |
363 | let span = match bounds { |
364 | [] => return, | |
365 | [b0] => b0.span(), | |
366 | [b0, .., bl] => b0.span().to(bl.span()), | |
367 | }; | |
9ffffee4 | 368 | self.err_handler().emit_err(errors::BoundInContext { span, ctx }); |
dfeec247 XL |
369 | } |
370 | ||
5e7ed085 | 371 | fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) { |
74b04a01 | 372 | let cannot_have = |span, descr, remove_descr| { |
9ffffee4 FG |
373 | self.err_handler().emit_err(errors::ExternTypesCannotHave { |
374 | span, | |
375 | descr, | |
376 | remove_descr, | |
377 | block_span: self.current_extern_span(), | |
378 | }); | |
74b04a01 XL |
379 | }; |
380 | ||
381 | if !generics.params.is_empty() { | |
382 | cannot_have(generics.span, "generic parameters", "generic parameters"); | |
383 | } | |
384 | ||
385 | if !generics.where_clause.predicates.is_empty() { | |
5e7ed085 | 386 | cannot_have(where_span, "`where` clauses", "`where` clause"); |
74b04a01 XL |
387 | } |
388 | } | |
389 | ||
390 | fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) { | |
5e7ed085 FG |
391 | let Some(body) = body else { |
392 | return; | |
74b04a01 | 393 | }; |
9ffffee4 FG |
394 | self.err_handler().emit_err(errors::BodyInExtern { |
395 | span: ident.span, | |
396 | body, | |
397 | block: self.current_extern_span(), | |
398 | kind, | |
399 | }); | |
74b04a01 XL |
400 | } |
401 | ||
402 | /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. | |
403 | fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) { | |
5e7ed085 FG |
404 | let Some(body) = body else { |
405 | return; | |
74b04a01 | 406 | }; |
9ffffee4 FG |
407 | self.err_handler().emit_err(errors::FnBodyInExtern { |
408 | span: ident.span, | |
409 | body: body.span, | |
410 | block: self.current_extern_span(), | |
411 | }); | |
74b04a01 XL |
412 | } |
413 | ||
414 | fn current_extern_span(&self) -> Span { | |
ba9703b0 | 415 | self.session.source_map().guess_head_span(self.extern_mod.unwrap().span) |
74b04a01 XL |
416 | } |
417 | ||
29967ef6 | 418 | /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. |
74b04a01 XL |
419 | fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { |
420 | if header.has_qualifiers() { | |
9ffffee4 FG |
421 | self.err_handler().emit_err(errors::FnQualifierInExtern { |
422 | span: ident.span, | |
423 | block: self.current_extern_span(), | |
424 | sugg_span: span.until(ident.span.shrink_to_lo()), | |
425 | }); | |
74b04a01 XL |
426 | } |
427 | } | |
428 | ||
cdc7bbd5 XL |
429 | /// An item in `extern { ... }` cannot use non-ascii identifier. |
430 | fn check_foreign_item_ascii_only(&self, ident: Ident) { | |
a2a8927a | 431 | if !ident.as_str().is_ascii() { |
9ffffee4 FG |
432 | self.err_handler().emit_err(errors::ExternItemAscii { |
433 | span: ident.span, | |
434 | block: self.current_extern_span(), | |
435 | }); | |
cdc7bbd5 XL |
436 | } |
437 | } | |
438 | ||
5e7ed085 | 439 | /// Reject C-variadic type unless the function is foreign, |
74b04a01 | 440 | /// or free and `unsafe extern "C"` semantically. |
5e7ed085 | 441 | fn check_c_variadic_type(&self, fk: FnKind<'a>) { |
74b04a01 XL |
442 | match (fk.ctxt(), fk.header()) { |
443 | (Some(FnCtxt::Foreign), _) => return, | |
444 | (Some(FnCtxt::Free), Some(header)) => match header.ext { | |
064997fb FG |
445 | Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) |
446 | | Extern::Implicit(_) | |
74b04a01 XL |
447 | if matches!(header.unsafety, Unsafe::Yes(_)) => |
448 | { | |
449 | return; | |
450 | } | |
451 | _ => {} | |
452 | }, | |
453 | _ => {} | |
454 | }; | |
455 | ||
456 | for Param { ty, span, .. } in &fk.decl().inputs { | |
dfeec247 | 457 | if let TyKind::CVarArgs = ty.kind { |
9ffffee4 | 458 | self.err_handler().emit_err(errors::BadCVariadic { span: *span }); |
dfeec247 XL |
459 | } |
460 | } | |
461 | } | |
9fa01778 | 462 | |
74b04a01 XL |
463 | fn check_item_named(&self, ident: Ident, kind: &str) { |
464 | if ident.name != kw::Underscore { | |
465 | return; | |
466 | } | |
9ffffee4 | 467 | self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind }); |
74b04a01 | 468 | } |
ba9703b0 | 469 | |
f9f354fc XL |
470 | fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) { |
471 | if ident.name.as_str().is_ascii() { | |
472 | return; | |
473 | } | |
9ffffee4 FG |
474 | let span = self.session.source_map().guess_head_span(item_span); |
475 | self.session.emit_err(errors::NoMangleAscii { span }); | |
f9f354fc XL |
476 | } |
477 | ||
478 | fn check_mod_file_item_asciionly(&self, ident: Ident) { | |
479 | if ident.name.as_str().is_ascii() { | |
480 | return; | |
481 | } | |
9ffffee4 | 482 | self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); |
f9f354fc XL |
483 | } |
484 | ||
9ffffee4 | 485 | fn deny_generic_params(&self, generics: &Generics, ident: Span) { |
ba9703b0 | 486 | if !generics.params.is_empty() { |
9ffffee4 | 487 | self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident }); |
ba9703b0 XL |
488 | } |
489 | } | |
490 | ||
9ffffee4 FG |
491 | fn emit_e0568(&self, span: Span, ident: Span) { |
492 | self.session.emit_err(errors::AutoTraitBounds { span, ident }); | |
c295e0f8 XL |
493 | } |
494 | ||
ba9703b0 | 495 | fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { |
c295e0f8 XL |
496 | if let [.., last] = &bounds[..] { |
497 | let span = ident_span.shrink_to_hi().to(last.span()); | |
498 | self.emit_e0568(span, ident_span); | |
499 | } | |
500 | } | |
501 | ||
502 | fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { | |
503 | if !where_clause.predicates.is_empty() { | |
504 | self.emit_e0568(where_clause.span, ident_span); | |
ba9703b0 XL |
505 | } |
506 | } | |
507 | ||
9ffffee4 | 508 | fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) { |
ba9703b0 XL |
509 | if !trait_items.is_empty() { |
510 | let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); | |
9ffffee4 FG |
511 | let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); |
512 | self.session.emit_err(errors::AutoTraitItems { spans, total, ident }); | |
ba9703b0 XL |
513 | } |
514 | } | |
515 | ||
516 | fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String { | |
517 | // Lifetimes always come first. | |
518 | let lt_sugg = data.args.iter().filter_map(|arg| match arg { | |
519 | AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => { | |
520 | Some(pprust::to_string(|s| s.print_generic_arg(lt))) | |
521 | } | |
522 | _ => None, | |
523 | }); | |
524 | let args_sugg = data.args.iter().filter_map(|a| match a { | |
525 | AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => { | |
526 | None | |
527 | } | |
528 | AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))), | |
529 | }); | |
530 | // Constraints always come last. | |
531 | let constraint_sugg = data.args.iter().filter_map(|a| match a { | |
532 | AngleBracketedArg::Arg(_) => None, | |
533 | AngleBracketedArg::Constraint(c) => { | |
534 | Some(pprust::to_string(|s| s.print_assoc_constraint(c))) | |
535 | } | |
536 | }); | |
537 | format!( | |
538 | "<{}>", | |
539 | lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ") | |
540 | ) | |
541 | } | |
542 | ||
543 | /// Enforce generic args coming before constraints in `<...>` of a path segment. | |
544 | fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { | |
545 | // Early exit in case it's partitioned as it should be. | |
546 | if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) { | |
547 | return; | |
548 | } | |
549 | // Find all generic argument coming after the first constraint... | |
550 | let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) = | |
551 | data.args.iter().partition_map(|arg| match arg { | |
552 | AngleBracketedArg::Constraint(c) => Either::Left(c.span), | |
553 | AngleBracketedArg::Arg(a) => Either::Right(a.span()), | |
554 | }); | |
555 | let args_len = arg_spans.len(); | |
556 | let constraint_len = constraint_spans.len(); | |
557 | // ...and then error: | |
9ffffee4 FG |
558 | self.err_handler().emit_err(errors::ArgsBeforeConstraint { |
559 | arg_spans: arg_spans.clone(), | |
560 | constraints: constraint_spans[0], | |
561 | args: *arg_spans.iter().last().unwrap(), | |
562 | data: data.span, | |
563 | constraint_spans: errors::EmptyLabelManySpans(constraint_spans), | |
564 | arg_spans2: errors::EmptyLabelManySpans(arg_spans), | |
565 | suggestion: self.correct_generic_order_suggestion(&data), | |
566 | constraint_len, | |
567 | args_len, | |
568 | }); | |
ba9703b0 | 569 | } |
17df50a5 XL |
570 | |
571 | fn visit_ty_common(&mut self, ty: &'a Ty) { | |
487cf647 FG |
572 | match &ty.kind { |
573 | TyKind::BareFn(bfty) => { | |
17df50a5 XL |
574 | self.check_fn_decl(&bfty.decl, SelfSemantic::No); |
575 | Self::check_decl_no_pat(&bfty.decl, |span, _, _| { | |
9ffffee4 | 576 | self.session.emit_err(errors::PatternFnPointer { span }); |
17df50a5 | 577 | }); |
064997fb | 578 | if let Extern::Implicit(_) = bfty.ext { |
94222f64 XL |
579 | let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); |
580 | self.maybe_lint_missing_abi(sig_span, ty.id); | |
581 | } | |
17df50a5 | 582 | } |
487cf647 | 583 | TyKind::TraitObject(bounds, ..) => { |
17df50a5 XL |
584 | let mut any_lifetime_bounds = false; |
585 | for bound in bounds { | |
487cf647 | 586 | if let GenericBound::Outlives(lifetime) = bound { |
17df50a5 | 587 | if any_lifetime_bounds { |
9ffffee4 FG |
588 | self.session |
589 | .emit_err(errors::TraitObjectBound { span: lifetime.ident.span }); | |
17df50a5 XL |
590 | break; |
591 | } | |
592 | any_lifetime_bounds = true; | |
593 | } | |
594 | } | |
17df50a5 | 595 | } |
487cf647 | 596 | TyKind::ImplTrait(_, bounds) => { |
17df50a5 | 597 | if self.is_impl_trait_banned { |
9ffffee4 | 598 | self.session.emit_err(errors::ImplTraitPath { span: ty.span }); |
17df50a5 XL |
599 | } |
600 | ||
601 | if let Some(outer_impl_trait_sp) = self.outer_impl_trait { | |
9ffffee4 FG |
602 | self.session.emit_err(errors::NestedImplTrait { |
603 | span: ty.span, | |
604 | outer: outer_impl_trait_sp, | |
605 | inner: ty.span, | |
606 | }); | |
17df50a5 XL |
607 | } |
608 | ||
609 | if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { | |
9ffffee4 | 610 | self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span }); |
17df50a5 XL |
611 | } |
612 | } | |
613 | _ => {} | |
614 | } | |
615 | } | |
94222f64 XL |
616 | |
617 | fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { | |
618 | // FIXME(davidtwco): This is a hack to detect macros which produce spans of the | |
619 | // call site which do not have a macro backtrace. See #61963. | |
620 | let is_macro_callsite = self | |
621 | .session | |
622 | .source_map() | |
623 | .span_to_snippet(span) | |
624 | .map(|snippet| snippet.starts_with("#[")) | |
625 | .unwrap_or(true); | |
626 | if !is_macro_callsite { | |
627 | self.lint_buffer.buffer_lint_with_diagnostic( | |
628 | MISSING_ABI, | |
629 | id, | |
630 | span, | |
9ffffee4 | 631 | fluent::ast_passes_extern_without_abi, |
94222f64 XL |
632 | BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK), |
633 | ) | |
634 | } | |
635 | } | |
9fa01778 | 636 | } |
b7449926 | 637 | |
ba9703b0 XL |
638 | /// Checks that generic parameters are in the correct order, |
639 | /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) | |
5869c6ff | 640 | fn validate_generic_param_order( |
dfeec247 | 641 | handler: &rustc_errors::Handler, |
5869c6ff | 642 | generics: &[GenericParam], |
9fa01778 XL |
643 | span: Span, |
644 | ) { | |
645 | let mut max_param: Option<ParamKindOrd> = None; | |
646 | let mut out_of_order = FxHashMap::default(); | |
136023e0 | 647 | let mut param_idents = Vec::with_capacity(generics.len()); |
9fa01778 | 648 | |
136023e0 XL |
649 | for (idx, param) in generics.iter().enumerate() { |
650 | let ident = param.ident; | |
651 | let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); | |
5869c6ff | 652 | let (ord_kind, ident) = match ¶m.kind { |
136023e0 | 653 | GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), |
487cf647 FG |
654 | GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()), |
655 | GenericParamKind::Const { ty, .. } => { | |
5869c6ff | 656 | let ty = pprust::ty_to_string(ty); |
f2b60f7d | 657 | (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty)) |
5869c6ff XL |
658 | } |
659 | }; | |
136023e0 | 660 | param_idents.push((kind, ord_kind, bounds, idx, ident)); |
9fa01778 | 661 | match max_param { |
136023e0 XL |
662 | Some(max_param) if max_param > ord_kind => { |
663 | let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![])); | |
9fa01778 XL |
664 | entry.1.push(span); |
665 | } | |
136023e0 | 666 | Some(_) | None => max_param = Some(ord_kind), |
9fa01778 XL |
667 | }; |
668 | } | |
669 | ||
9fa01778 | 670 | if !out_of_order.is_empty() { |
136023e0 | 671 | let mut ordered_params = "<".to_string(); |
5869c6ff | 672 | param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); |
9fa01778 | 673 | let mut first = true; |
5869c6ff | 674 | for (kind, _, bounds, _, ident) in param_idents { |
9fa01778 XL |
675 | if !first { |
676 | ordered_params += ", "; | |
677 | } | |
678 | ordered_params += &ident; | |
136023e0 XL |
679 | |
680 | if !bounds.is_empty() { | |
681 | ordered_params += ": "; | |
682 | ordered_params += &pprust::bounds_to_string(&bounds); | |
532ac7d7 | 683 | } |
136023e0 | 684 | |
5869c6ff XL |
685 | match kind { |
686 | GenericParamKind::Type { default: Some(default) } => { | |
687 | ordered_params += " = "; | |
688 | ordered_params += &pprust::ty_to_string(default); | |
689 | } | |
690 | GenericParamKind::Type { default: None } => (), | |
691 | GenericParamKind::Lifetime => (), | |
17df50a5 XL |
692 | GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { |
693 | ordered_params += " = "; | |
694 | ordered_params += &pprust::expr_to_string(&*default.value); | |
695 | } | |
696 | GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), | |
5869c6ff | 697 | } |
9fa01778 XL |
698 | first = false; |
699 | } | |
9fa01778 | 700 | |
136023e0 XL |
701 | ordered_params += ">"; |
702 | ||
703 | for (param_ord, (max_param, spans)) in &out_of_order { | |
9ffffee4 FG |
704 | handler.emit_err(errors::OutOfOrderParams { |
705 | spans: spans.clone(), | |
706 | sugg_span: span, | |
707 | param_ord, | |
708 | max_param, | |
709 | ordered_params: &ordered_params, | |
710 | }); | |
136023e0 | 711 | } |
9fa01778 | 712 | } |
3157f602 XL |
713 | } |
714 | ||
476ff2be | 715 | impl<'a> Visitor<'a> for AstValidator<'a> { |
60c5eb7d | 716 | fn visit_attribute(&mut self, attr: &Attribute) { |
487cf647 | 717 | validate_attr::check_attr(&self.session.parse_sess, attr); |
60c5eb7d XL |
718 | } |
719 | ||
476ff2be | 720 | fn visit_expr(&mut self, expr: &'a Expr) { |
5e7ed085 FG |
721 | self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| { |
722 | match &expr.kind { | |
723 | ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => { | |
04454e1e FG |
724 | let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span)); |
725 | this.with_let_management(local_reason, |this, _| this.visit_expr(lhs)); | |
726 | this.with_let_management(local_reason, |this, _| this.visit_expr(rhs)); | |
5e7ed085 FG |
727 | } |
728 | ExprKind::If(cond, then, opt_else) => { | |
729 | this.visit_block(then); | |
730 | walk_list!(this, visit_expr, opt_else); | |
731 | this.with_let_management(None, |this, _| this.visit_expr(cond)); | |
732 | return; | |
733 | } | |
734 | ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => { | |
735 | this.ban_let_expr(expr, elem); | |
736 | }, | |
737 | ExprKind::Match(scrutinee, arms) => { | |
738 | this.visit_expr(scrutinee); | |
739 | for arm in arms { | |
740 | this.visit_expr(&arm.body); | |
741 | this.visit_pat(&arm.pat); | |
742 | walk_list!(this, visit_attribute, &arm.attrs); | |
743 | if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind { | |
744 | this.with_let_management(None, |this, _| { | |
745 | this.visit_expr(guard_expr) | |
746 | }); | |
94222f64 XL |
747 | return; |
748 | } | |
749 | } | |
750 | } | |
04454e1e FG |
751 | ExprKind::Paren(local_expr) => { |
752 | fn has_let_expr(expr: &Expr) -> bool { | |
487cf647 FG |
753 | match &expr.kind { |
754 | ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), | |
04454e1e FG |
755 | ExprKind::Let(..) => true, |
756 | _ => false, | |
757 | } | |
758 | } | |
759 | let local_reason = if has_let_expr(local_expr) { | |
760 | Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span)) | |
761 | } | |
762 | else { | |
763 | forbidden_let_reason | |
764 | }; | |
765 | this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr)); | |
766 | } | |
767 | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => { | |
5e7ed085 FG |
768 | this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr)); |
769 | return; | |
770 | } | |
771 | ExprKind::While(cond, then, opt_label) => { | |
772 | walk_list!(this, visit_label, opt_label); | |
773 | this.visit_block(then); | |
774 | this.with_let_management(None, |this, _| this.visit_expr(cond)); | |
775 | return; | |
776 | } | |
777 | _ => visit::walk_expr(this, expr), | |
94222f64 | 778 | } |
94222f64 | 779 | }); |
3157f602 XL |
780 | } |
781 | ||
476ff2be | 782 | fn visit_ty(&mut self, ty: &'a Ty) { |
17df50a5 | 783 | self.visit_ty_common(ty); |
9fa01778 | 784 | self.walk_ty(ty) |
5bcae85e SL |
785 | } |
786 | ||
2c00a5a8 | 787 | fn visit_label(&mut self, label: &'a Label) { |
83c7162d | 788 | self.check_label(label.ident); |
2c00a5a8 XL |
789 | visit::walk_label(self, label); |
790 | } | |
791 | ||
923072b8 | 792 | fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { |
83c7162d | 793 | self.check_lifetime(lifetime.ident); |
ff7c6d11 | 794 | visit::walk_lifetime(self, lifetime); |
3157f602 XL |
795 | } |
796 | ||
2b03887a FG |
797 | fn visit_field_def(&mut self, field: &'a FieldDef) { |
798 | visit::walk_field_def(self, field) | |
17df50a5 XL |
799 | } |
800 | ||
476ff2be | 801 | fn visit_item(&mut self, item: &'a Item) { |
3dfed10e | 802 | if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) { |
9fa01778 XL |
803 | self.has_proc_macro_decls = true; |
804 | } | |
805 | ||
3dfed10e | 806 | if self.session.contains_name(&item.attrs, sym::no_mangle) { |
f9f354fc XL |
807 | self.check_nomangle_item_asciionly(item.ident, item.span); |
808 | } | |
809 | ||
487cf647 | 810 | match &item.kind { |
3c0e092e | 811 | ItemKind::Impl(box Impl { |
dfeec247 XL |
812 | unsafety, |
813 | polarity, | |
814 | defaultness: _, | |
94222f64 | 815 | constness, |
487cf647 FG |
816 | generics, |
817 | of_trait: Some(t), | |
818 | self_ty, | |
819 | items, | |
5869c6ff | 820 | }) => { |
487cf647 | 821 | self.with_in_trait_impl(true, Some(*constness), |this| { |
74b04a01 XL |
822 | this.invalid_visibility(&item.vis, None); |
823 | if let TyKind::Err = self_ty.kind { | |
9ffffee4 | 824 | this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span }); |
74b04a01 | 825 | } |
487cf647 FG |
826 | if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) |
827 | { | |
9ffffee4 FG |
828 | this.session.emit_err(errors::UnsafeNegativeImpl { |
829 | span: sp.to(t.path.span), | |
830 | negative: sp, | |
831 | r#unsafe: span, | |
832 | }); | |
9e0c209e | 833 | } |
74b04a01 | 834 | |
94222f64 XL |
835 | this.visit_vis(&item.vis); |
836 | this.visit_ident(item.ident); | |
837 | if let Const::Yes(_) = constness { | |
838 | this.with_tilde_const_allowed(|this| this.visit_generics(generics)); | |
839 | } else { | |
840 | this.visit_generics(generics); | |
841 | } | |
842 | this.visit_trait_ref(t); | |
843 | this.visit_ty(self_ty); | |
844 | ||
845 | walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); | |
74b04a01 | 846 | }); |
487cf647 | 847 | walk_list!(self, visit_attribute, &item.attrs); |
74b04a01 | 848 | return; // Avoid visiting again. |
3157f602 | 849 | } |
3c0e092e | 850 | ItemKind::Impl(box Impl { |
dfeec247 XL |
851 | unsafety, |
852 | polarity, | |
853 | defaultness, | |
854 | constness, | |
855 | generics: _, | |
856 | of_trait: None, | |
487cf647 | 857 | self_ty, |
dfeec247 | 858 | items: _, |
5869c6ff | 859 | }) => { |
9ffffee4 FG |
860 | let error = |
861 | |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot { | |
862 | span: self_ty.span, | |
863 | annotation_span, | |
864 | annotation, | |
865 | self_ty: self_ty.span, | |
866 | only_trait: only_trait.then_some(()), | |
867 | }; | |
ba9703b0 | 868 | |
dfeec247 XL |
869 | self.invalid_visibility( |
870 | &item.vis, | |
9ffffee4 | 871 | Some(errors::InvalidVisibilityNote::IndividualImplItems), |
dfeec247 | 872 | ); |
487cf647 | 873 | if let &Unsafe::Yes(span) = unsafety { |
9ffffee4 FG |
874 | self.err_handler().emit_err(errors::InherentImplCannotUnsafe { |
875 | span: self_ty.span, | |
876 | annotation_span: span, | |
877 | annotation: "unsafe", | |
878 | self_ty: self_ty.span, | |
879 | }); | |
2c00a5a8 | 880 | } |
487cf647 | 881 | if let &ImplPolarity::Negative(span) = polarity { |
9ffffee4 | 882 | self.err_handler().emit_err(error(span, "negative", false)); |
2c00a5a8 | 883 | } |
487cf647 | 884 | if let &Defaultness::Default(def_span) = defaultness { |
9ffffee4 | 885 | self.err_handler().emit_err(error(def_span, "`default`", true)); |
dfeec247 | 886 | } |
487cf647 | 887 | if let &Const::Yes(span) = constness { |
9ffffee4 | 888 | self.err_handler().emit_err(error(span, "`const`", true)); |
2c00a5a8 | 889 | } |
3157f602 | 890 | } |
487cf647 FG |
891 | ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => { |
892 | self.check_defaultness(item.span, *defaultness); | |
74b04a01 XL |
893 | |
894 | if body.is_none() { | |
9ffffee4 | 895 | self.session.emit_err(errors::FnWithoutBody { |
f2b60f7d FG |
896 | span: item.span, |
897 | replace_span: self.ending_semi_or_hi(item.span), | |
898 | extern_block_suggestion: match sig.header.ext { | |
899 | Extern::None => None, | |
9ffffee4 FG |
900 | Extern::Implicit(start_span) => { |
901 | Some(errors::ExternBlockSuggestion::Implicit { | |
902 | start_span, | |
903 | end_span: item.span.shrink_to_hi(), | |
904 | }) | |
905 | } | |
9c376795 | 906 | Extern::Explicit(abi, start_span) => { |
9ffffee4 | 907 | Some(errors::ExternBlockSuggestion::Explicit { |
9c376795 FG |
908 | start_span, |
909 | end_span: item.span.shrink_to_hi(), | |
910 | abi: abi.symbol_unescaped, | |
911 | }) | |
912 | } | |
f2b60f7d FG |
913 | }, |
914 | }); | |
dfeec247 | 915 | } |
064997fb | 916 | |
94222f64 XL |
917 | self.visit_vis(&item.vis); |
918 | self.visit_ident(item.ident); | |
04454e1e FG |
919 | let kind = |
920 | FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); | |
94222f64 XL |
921 | self.visit_fn(kind, item.span, item.id); |
922 | walk_list!(self, visit_attribute, &item.attrs); | |
923 | return; // Avoid visiting again. | |
9fa01778 | 924 | } |
94222f64 | 925 | ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => { |
74b04a01 | 926 | let old_item = mem::replace(&mut self.extern_mod, Some(item)); |
0531ce1d XL |
927 | self.invalid_visibility( |
928 | &item.vis, | |
9ffffee4 | 929 | Some(errors::InvalidVisibilityNote::IndividualForeignItems), |
0531ce1d | 930 | ); |
487cf647 | 931 | if let &Unsafe::Yes(span) = unsafety { |
9ffffee4 | 932 | self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" }); |
1b1a35ee | 933 | } |
94222f64 XL |
934 | if abi.is_none() { |
935 | self.maybe_lint_missing_abi(item.span, item.id); | |
936 | } | |
74b04a01 XL |
937 | visit::walk_item(self, item); |
938 | self.extern_mod = old_item; | |
939 | return; // Avoid visiting again. | |
3157f602 | 940 | } |
487cf647 | 941 | ItemKind::Enum(def, _) => { |
3157f602 | 942 | for variant in &def.variants { |
60c5eb7d | 943 | self.invalid_visibility(&variant.vis, None); |
e1599b0c | 944 | for field in variant.data.fields() { |
0531ce1d | 945 | self.invalid_visibility(&field.vis, None); |
3157f602 XL |
946 | } |
947 | } | |
948 | } | |
487cf647 FG |
949 | ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { |
950 | if *is_auto == IsAuto::Yes { | |
abe05a73 | 951 | // Auto traits cannot have generics, super traits nor contain items. |
ba9703b0 XL |
952 | self.deny_generic_params(generics, item.ident.span); |
953 | self.deny_super_traits(bounds, item.ident.span); | |
c295e0f8 | 954 | self.deny_where_clause(&generics.where_clause, item.ident.span); |
3c0e092e | 955 | self.deny_items(items, item.ident.span); |
abe05a73 | 956 | } |
dfeec247 XL |
957 | |
958 | // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound | |
959 | // context for the supertraits. | |
960 | self.visit_vis(&item.vis); | |
961 | self.visit_ident(item.ident); | |
962 | self.visit_generics(generics); | |
064997fb | 963 | self.with_tilde_const_allowed(|this| { |
04454e1e FG |
964 | walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) |
965 | }); | |
3c0e092e | 966 | walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); |
dfeec247 | 967 | walk_list!(self, visit_attribute, &item.attrs); |
487cf647 | 968 | return; // Avoid visiting again |
9e0c209e | 969 | } |
487cf647 FG |
970 | ItemKind::Mod(unsafety, mod_kind) => { |
971 | if let &Unsafe::Yes(span) = unsafety { | |
9ffffee4 | 972 | self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" }); |
1b1a35ee | 973 | } |
0731742a | 974 | // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). |
6a06907d XL |
975 | if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) |
976 | && !self.session.contains_name(&item.attrs, sym::path) | |
977 | { | |
f9f354fc XL |
978 | self.check_mod_file_item_asciionly(item.ident); |
979 | } | |
5bcae85e | 980 | } |
487cf647 | 981 | ItemKind::Union(vdata, ..) => { |
b7449926 | 982 | if vdata.fields().is_empty() { |
9ffffee4 | 983 | self.err_handler().emit_err(errors::FieldlessUnion { span: item.span }); |
9e0c209e SL |
984 | } |
985 | } | |
74b04a01 | 986 | ItemKind::Const(def, .., None) => { |
487cf647 | 987 | self.check_defaultness(item.span, *def); |
9ffffee4 | 988 | self.session.emit_err(errors::ConstWithoutBody { |
f2b60f7d FG |
989 | span: item.span, |
990 | replace_span: self.ending_semi_or_hi(item.span), | |
991 | }); | |
74b04a01 XL |
992 | } |
993 | ItemKind::Static(.., None) => { | |
9ffffee4 | 994 | self.session.emit_err(errors::StaticWithoutBody { |
f2b60f7d FG |
995 | span: item.span, |
996 | replace_span: self.ending_semi_or_hi(item.span), | |
997 | }); | |
74b04a01 | 998 | } |
487cf647 FG |
999 | ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => { |
1000 | self.check_defaultness(item.span, *defaultness); | |
3c0e092e | 1001 | if ty.is_none() { |
9ffffee4 | 1002 | self.session.emit_err(errors::TyAliasWithoutBody { |
f2b60f7d FG |
1003 | span: item.span, |
1004 | replace_span: self.ending_semi_or_hi(item.span), | |
1005 | }); | |
74b04a01 XL |
1006 | } |
1007 | self.check_type_no_bounds(bounds, "this context"); | |
5e7ed085 | 1008 | if where_clauses.1.0 { |
9ffffee4 FG |
1009 | self.err_handler() |
1010 | .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 }); | |
5e7ed085 | 1011 | } |
74b04a01 | 1012 | } |
3157f602 XL |
1013 | _ => {} |
1014 | } | |
1015 | ||
94222f64 | 1016 | visit::walk_item(self, item); |
3157f602 XL |
1017 | } |
1018 | ||
476ff2be | 1019 | fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { |
74b04a01 | 1020 | match &fi.kind { |
3c0e092e XL |
1021 | ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { |
1022 | self.check_defaultness(fi.span, *defaultness); | |
74b04a01 XL |
1023 | self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); |
1024 | self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); | |
cdc7bbd5 | 1025 | self.check_foreign_item_ascii_only(fi.ident); |
3157f602 | 1026 | } |
5e7ed085 FG |
1027 | ForeignItemKind::TyAlias(box TyAlias { |
1028 | defaultness, | |
1029 | generics, | |
1030 | where_clauses, | |
1031 | bounds, | |
1032 | ty, | |
1033 | .. | |
1034 | }) => { | |
3c0e092e XL |
1035 | self.check_defaultness(fi.span, *defaultness); |
1036 | self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); | |
74b04a01 | 1037 | self.check_type_no_bounds(bounds, "`extern` blocks"); |
5e7ed085 | 1038 | self.check_foreign_ty_genericless(generics, where_clauses.0.1); |
cdc7bbd5 | 1039 | self.check_foreign_item_ascii_only(fi.ident); |
74b04a01 XL |
1040 | } |
1041 | ForeignItemKind::Static(_, _, body) => { | |
1042 | self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); | |
cdc7bbd5 | 1043 | self.check_foreign_item_ascii_only(fi.ident); |
74b04a01 | 1044 | } |
ba9703b0 | 1045 | ForeignItemKind::MacCall(..) => {} |
3157f602 XL |
1046 | } |
1047 | ||
5bcae85e | 1048 | visit::walk_foreign_item(self, fi) |
3157f602 XL |
1049 | } |
1050 | ||
dc9dc135 | 1051 | // Mirrors `visit::walk_generic_args`, but tracks relevant state. |
f2b60f7d | 1052 | fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) { |
487cf647 FG |
1053 | match generic_args { |
1054 | GenericArgs::AngleBracketed(data) => { | |
ba9703b0 XL |
1055 | self.check_generic_args_before_constraints(data); |
1056 | ||
1057 | for arg in &data.args { | |
1058 | match arg { | |
1059 | AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), | |
1060 | // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>` | |
1061 | // are allowed to contain nested `impl Trait`. | |
1062 | AngleBracketedArg::Constraint(constraint) => { | |
1063 | self.with_impl_trait(None, |this| { | |
9ffffee4 | 1064 | this.visit_assoc_constraint(constraint); |
ba9703b0 XL |
1065 | }); |
1066 | } | |
1067 | } | |
1068 | } | |
9fa01778 | 1069 | } |
487cf647 | 1070 | GenericArgs::Parenthesized(data) => { |
9fa01778 | 1071 | walk_list!(self, visit_ty, &data.inputs); |
74b04a01 | 1072 | if let FnRetTy::Ty(ty) = &data.output { |
9fa01778 XL |
1073 | // `-> Foo` syntax is essentially an associated type binding, |
1074 | // so it is also allowed to contain nested `impl Trait`. | |
dfeec247 | 1075 | self.with_impl_trait(None, |this| this.visit_ty(ty)); |
9fa01778 XL |
1076 | } |
1077 | } | |
1078 | } | |
1079 | } | |
1080 | ||
8faf50e0 | 1081 | fn visit_generics(&mut self, generics: &'a Generics) { |
cdc7bbd5 | 1082 | let mut prev_param_default = None; |
8faf50e0 | 1083 | for param in &generics.params { |
3dfed10e XL |
1084 | match param.kind { |
1085 | GenericParamKind::Lifetime => (), | |
cdc7bbd5 XL |
1086 | GenericParamKind::Type { default: Some(_), .. } |
1087 | | GenericParamKind::Const { default: Some(_), .. } => { | |
1088 | prev_param_default = Some(param.ident.span); | |
3dfed10e XL |
1089 | } |
1090 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
cdc7bbd5 | 1091 | if let Some(span) = prev_param_default { |
9ffffee4 | 1092 | self.err_handler().emit_err(errors::GenericDefaultTrailing { span }); |
3dfed10e XL |
1093 | break; |
1094 | } | |
ff7c6d11 XL |
1095 | } |
1096 | } | |
32a655c1 | 1097 | } |
9fa01778 | 1098 | |
a2a8927a | 1099 | validate_generic_param_order(self.err_handler(), &generics.params, generics.span); |
9fa01778 | 1100 | |
8faf50e0 | 1101 | for predicate in &generics.where_clause.predicates { |
487cf647 | 1102 | if let WherePredicate::EqPredicate(predicate) = predicate { |
f9f354fc | 1103 | deny_equality_constraints(self, predicate, generics); |
32a655c1 SL |
1104 | } |
1105 | } | |
cdc7bbd5 XL |
1106 | walk_list!(self, visit_generic_param, &generics.params); |
1107 | for predicate in &generics.where_clause.predicates { | |
1108 | match predicate { | |
1109 | WherePredicate::BoundPredicate(bound_pred) => { | |
cdc7bbd5 XL |
1110 | // This is slightly complicated. Our representation for poly-trait-refs contains a single |
1111 | // binder and thus we only allow a single level of quantification. However, | |
1112 | // the syntax of Rust permits quantification in two places in where clauses, | |
1113 | // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are | |
1114 | // defined, then error. | |
1115 | if !bound_pred.bound_generic_params.is_empty() { | |
1116 | for bound in &bound_pred.bounds { | |
1117 | match bound { | |
1118 | GenericBound::Trait(t, _) => { | |
1119 | if !t.bound_generic_params.is_empty() { | |
9ffffee4 FG |
1120 | self.err_handler() |
1121 | .emit_err(errors::NestedLifetimes { span: t.span }); | |
cdc7bbd5 XL |
1122 | } |
1123 | } | |
1124 | GenericBound::Outlives(_) => {} | |
1125 | } | |
1126 | } | |
1127 | } | |
1128 | } | |
1129 | _ => {} | |
1130 | } | |
1131 | self.visit_where_predicate(predicate); | |
1132 | } | |
32a655c1 | 1133 | } |
041b39d2 | 1134 | |
94b46f34 | 1135 | fn visit_generic_param(&mut self, param: &'a GenericParam) { |
8faf50e0 XL |
1136 | if let GenericParamKind::Lifetime { .. } = param.kind { |
1137 | self.check_lifetime(param.ident); | |
94b46f34 XL |
1138 | } |
1139 | visit::walk_generic_param(self, param); | |
1140 | } | |
1141 | ||
04454e1e | 1142 | fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { |
487cf647 | 1143 | if let GenericBound::Trait(poly, modify) = bound { |
04454e1e FG |
1144 | match (ctxt, modify) { |
1145 | (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { | |
9ffffee4 FG |
1146 | self.err_handler().emit_err(errors::OptionalTraitSupertrait { |
1147 | span: poly.span, | |
1148 | path_str: pprust::path_to_string(&poly.trait_ref.path) | |
1149 | }); | |
04454e1e FG |
1150 | } |
1151 | (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { | |
9ffffee4 | 1152 | self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span}); |
04454e1e | 1153 | } |
2b03887a | 1154 | (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { |
9ffffee4 FG |
1155 | let reason = match reason { |
1156 | DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject, | |
1157 | DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure, | |
1158 | DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span }, | |
2b03887a | 1159 | }; |
9ffffee4 FG |
1160 | self.err_handler().emit_err(errors::TildeConstDisallowed { |
1161 | span: bound.span(), | |
1162 | reason | |
1163 | }); | |
04454e1e FG |
1164 | } |
1165 | (_, TraitBoundModifier::MaybeConstMaybe) => { | |
9ffffee4 | 1166 | self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()}); |
dfeec247 | 1167 | } |
04454e1e | 1168 | _ => {} |
dfeec247 | 1169 | } |
dfeec247 XL |
1170 | } |
1171 | ||
1172 | visit::walk_param_bound(self, bound) | |
1173 | } | |
1174 | ||
74b04a01 XL |
1175 | fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { |
1176 | // Only associated `fn`s can have `self` parameters. | |
1177 | let self_semantic = match fk.ctxt() { | |
1178 | Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes, | |
1179 | _ => SelfSemantic::No, | |
1180 | }; | |
1181 | self.check_fn_decl(fk.decl(), self_semantic); | |
1182 | ||
5e7ed085 | 1183 | self.check_c_variadic_type(fk); |
74b04a01 XL |
1184 | |
1185 | // Functions cannot both be `const async` | |
9ffffee4 | 1186 | if let Some(&FnHeader { |
74b04a01 XL |
1187 | constness: Const::Yes(cspan), |
1188 | asyncness: Async::Yes { span: aspan, .. }, | |
1189 | .. | |
1190 | }) = fk.header() | |
1191 | { | |
9ffffee4 FG |
1192 | self.err_handler().emit_err(errors::ConstAndAsync { |
1193 | spans: vec![cspan, aspan], | |
1194 | cspan, | |
1195 | aspan, | |
1196 | span, | |
1197 | }); | |
064997fb FG |
1198 | } |
1199 | ||
94222f64 XL |
1200 | if let FnKind::Fn( |
1201 | _, | |
1202 | _, | |
064997fb | 1203 | FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. }, |
94222f64 XL |
1204 | _, |
1205 | _, | |
04454e1e | 1206 | _, |
94222f64 XL |
1207 | ) = fk |
1208 | { | |
1209 | self.maybe_lint_missing_abi(*sig_span, id); | |
1210 | } | |
1211 | ||
74b04a01 | 1212 | // Functions without bodies cannot have patterns. |
04454e1e | 1213 | if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { |
5869c6ff | 1214 | Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { |
74b04a01 | 1215 | if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { |
5869c6ff | 1216 | if let Some(ident) = ident { |
9ffffee4 FG |
1217 | let msg = match ctxt { |
1218 | FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign, | |
1219 | _ => fluent::ast_passes_pattern_in_bodiless, | |
1220 | }; | |
5869c6ff XL |
1221 | let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident); |
1222 | self.lint_buffer.buffer_lint_with_diagnostic( | |
1223 | PATTERNS_IN_FNS_WITHOUT_BODY, | |
1224 | id, | |
1225 | span, | |
1226 | msg, | |
1227 | diag, | |
1228 | ) | |
1229 | } | |
74b04a01 | 1230 | } else { |
9ffffee4 FG |
1231 | match ctxt { |
1232 | FnCtxt::Foreign => { | |
1233 | self.err_handler().emit_err(errors::PatternInForeign { span }) | |
1234 | } | |
1235 | _ => self.err_handler().emit_err(errors::PatternInBodiless { span }), | |
1236 | }; | |
74b04a01 XL |
1237 | } |
1238 | }); | |
dfeec247 XL |
1239 | } |
1240 | ||
04454e1e | 1241 | let tilde_const_allowed = |
2b03887a | 1242 | matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) |
04454e1e FG |
1243 | || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); |
1244 | ||
2b03887a FG |
1245 | let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); |
1246 | ||
1247 | self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); | |
60c5eb7d | 1248 | } |
dfeec247 | 1249 | |
74b04a01 | 1250 | fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { |
94222f64 XL |
1251 | if self.session.contains_name(&item.attrs, sym::no_mangle) { |
1252 | self.check_nomangle_item_asciionly(item.ident, item.span); | |
1253 | } | |
1254 | ||
74b04a01 XL |
1255 | if ctxt == AssocCtxt::Trait || !self.in_trait_impl { |
1256 | self.check_defaultness(item.span, item.kind.defaultness()); | |
1257 | } | |
1258 | ||
1259 | if ctxt == AssocCtxt::Impl { | |
1260 | match &item.kind { | |
1261 | AssocItemKind::Const(_, _, body) => { | |
f2b60f7d | 1262 | if body.is_none() { |
9ffffee4 | 1263 | self.session.emit_err(errors::AssocConstWithoutBody { |
f2b60f7d FG |
1264 | span: item.span, |
1265 | replace_span: self.ending_semi_or_hi(item.span), | |
1266 | }); | |
1267 | } | |
74b04a01 | 1268 | } |
3c0e092e | 1269 | AssocItemKind::Fn(box Fn { body, .. }) => { |
f2b60f7d | 1270 | if body.is_none() { |
9ffffee4 | 1271 | self.session.emit_err(errors::AssocFnWithoutBody { |
f2b60f7d FG |
1272 | span: item.span, |
1273 | replace_span: self.ending_semi_or_hi(item.span), | |
1274 | }); | |
1275 | } | |
74b04a01 | 1276 | } |
2b03887a | 1277 | AssocItemKind::Type(box TyAlias { |
5e7ed085 FG |
1278 | generics, |
1279 | where_clauses, | |
1280 | where_predicates_split, | |
1281 | bounds, | |
1282 | ty, | |
1283 | .. | |
1284 | }) => { | |
f2b60f7d | 1285 | if ty.is_none() { |
9ffffee4 | 1286 | self.session.emit_err(errors::AssocTypeWithoutBody { |
f2b60f7d FG |
1287 | span: item.span, |
1288 | replace_span: self.ending_semi_or_hi(item.span), | |
1289 | }); | |
1290 | } | |
74b04a01 | 1291 | self.check_type_no_bounds(bounds, "`impl`s"); |
5e7ed085 FG |
1292 | if ty.is_some() { |
1293 | self.check_gat_where( | |
1294 | item.id, | |
1295 | generics.where_clause.predicates.split_at(*where_predicates_split).0, | |
1296 | *where_clauses, | |
1297 | ); | |
1298 | } | |
74b04a01 XL |
1299 | } |
1300 | _ => {} | |
1301 | } | |
dfeec247 | 1302 | } |
74b04a01 XL |
1303 | |
1304 | if ctxt == AssocCtxt::Trait || self.in_trait_impl { | |
1305 | self.invalid_visibility(&item.vis, None); | |
3c0e092e | 1306 | if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { |
74b04a01 | 1307 | self.check_trait_fn_not_const(sig.header.constness); |
74b04a01 XL |
1308 | } |
1309 | } | |
1310 | ||
1311 | if let AssocItemKind::Const(..) = item.kind { | |
1312 | self.check_item_named(item.ident, "const"); | |
1313 | } | |
1314 | ||
487cf647 FG |
1315 | match &item.kind { |
1316 | AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) | |
94222f64 XL |
1317 | if ctxt == AssocCtxt::Trait => |
1318 | { | |
1319 | self.visit_vis(&item.vis); | |
1320 | self.visit_ident(item.ident); | |
1321 | walk_list!(self, visit_attribute, &item.attrs); | |
1322 | self.with_tilde_const_allowed(|this| { | |
1323 | this.visit_generics(generics); | |
04454e1e | 1324 | walk_list!(this, visit_param_bound, bounds, BoundKind::Bound); |
94222f64 XL |
1325 | }); |
1326 | walk_list!(self, visit_ty, ty); | |
1327 | } | |
487cf647 | 1328 | AssocItemKind::Fn(box Fn { sig, generics, body, .. }) |
c295e0f8 XL |
1329 | if self.in_const_trait_impl |
1330 | || ctxt == AssocCtxt::Trait | |
1331 | || matches!(sig.header.constness, Const::Yes(_)) => | |
94222f64 XL |
1332 | { |
1333 | self.visit_vis(&item.vis); | |
1334 | self.visit_ident(item.ident); | |
04454e1e FG |
1335 | let kind = FnKind::Fn( |
1336 | FnCtxt::Assoc(ctxt), | |
1337 | item.ident, | |
1338 | sig, | |
1339 | &item.vis, | |
1340 | generics, | |
1341 | body.as_deref(), | |
1342 | ); | |
94222f64 XL |
1343 | self.visit_fn(kind, item.span, item.id); |
1344 | } | |
1345 | _ => self | |
1346 | .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), | |
1347 | } | |
dfeec247 | 1348 | } |
0531ce1d XL |
1349 | } |
1350 | ||
f9f354fc XL |
1351 | /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems |
1352 | /// like it's setting an associated type, provide an appropriate suggestion. | |
1353 | fn deny_equality_constraints( | |
1354 | this: &mut AstValidator<'_>, | |
1355 | predicate: &WhereEqPredicate, | |
1356 | generics: &Generics, | |
1357 | ) { | |
9ffffee4 | 1358 | let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None }; |
f9f354fc XL |
1359 | |
1360 | // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. | |
1361 | if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind { | |
1362 | if let TyKind::Path(None, path) = &qself.ty.kind { | |
1363 | match &path.segments[..] { | |
1364 | [PathSegment { ident, args: None, .. }] => { | |
1365 | for param in &generics.params { | |
1366 | if param.ident == *ident { | |
1367 | let param = ident; | |
1368 | match &full_path.segments[qself.position..] { | |
fc512014 | 1369 | [PathSegment { ident, args, .. }] => { |
f9f354fc XL |
1370 | // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`. |
1371 | let mut assoc_path = full_path.clone(); | |
1372 | // Remove `Bar` from `Foo::Bar`. | |
1373 | assoc_path.segments.pop(); | |
1374 | let len = assoc_path.segments.len() - 1; | |
487cf647 | 1375 | let gen_args = args.as_deref().cloned(); |
f9f354fc | 1376 | // Build `<Bar = RhsTy>`. |
5099ac24 | 1377 | let arg = AngleBracketedArg::Constraint(AssocConstraint { |
f9f354fc XL |
1378 | id: rustc_ast::node_id::DUMMY_NODE_ID, |
1379 | ident: *ident, | |
fc512014 | 1380 | gen_args, |
5099ac24 FG |
1381 | kind: AssocConstraintKind::Equality { |
1382 | term: predicate.rhs_ty.clone().into(), | |
f9f354fc XL |
1383 | }, |
1384 | span: ident.span, | |
1385 | }); | |
1386 | // Add `<Bar = RhsTy>` to `Foo`. | |
1387 | match &mut assoc_path.segments[len].args { | |
1388 | Some(args) => match args.deref_mut() { | |
1389 | GenericArgs::Parenthesized(_) => continue, | |
1390 | GenericArgs::AngleBracketed(args) => { | |
1391 | args.args.push(arg); | |
1392 | } | |
1393 | }, | |
1394 | empty_args => { | |
1395 | *empty_args = AngleBracketedArgs { | |
1396 | span: ident.span, | |
9ffffee4 | 1397 | args: thin_vec![arg], |
f9f354fc XL |
1398 | } |
1399 | .into(); | |
1400 | } | |
1401 | } | |
9ffffee4 FG |
1402 | err.assoc = Some(errors::AssociatedSuggestion { |
1403 | span: predicate.span, | |
1404 | ident: *ident, | |
1405 | param: *param, | |
1406 | path: pprust::path_to_string(&assoc_path), | |
1407 | }) | |
f9f354fc XL |
1408 | } |
1409 | _ => {} | |
1410 | }; | |
1411 | } | |
1412 | } | |
1413 | } | |
1414 | _ => {} | |
1415 | } | |
1416 | } | |
1417 | } | |
a2a8927a XL |
1418 | // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. |
1419 | if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { | |
1420 | if let [potential_param, potential_assoc] = &full_path.segments[..] { | |
1421 | for param in &generics.params { | |
1422 | if param.ident == potential_param.ident { | |
1423 | for bound in ¶m.bounds { | |
1424 | if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound | |
1425 | { | |
1426 | if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] { | |
1427 | let assoc = pprust::path_to_string(&ast::Path::from_ident( | |
1428 | potential_assoc.ident, | |
1429 | )); | |
1430 | let ty = pprust::ty_to_string(&predicate.rhs_ty); | |
1431 | let (args, span) = match &trait_segment.args { | |
1432 | Some(args) => match args.deref() { | |
1433 | ast::GenericArgs::AngleBracketed(args) => { | |
1434 | let Some(arg) = args.args.last() else { | |
1435 | continue; | |
1436 | }; | |
1437 | ( | |
1438 | format!(", {} = {}", assoc, ty), | |
1439 | arg.span().shrink_to_hi(), | |
1440 | ) | |
1441 | } | |
1442 | _ => continue, | |
1443 | }, | |
1444 | None => ( | |
1445 | format!("<{} = {}>", assoc, ty), | |
1446 | trait_segment.span().shrink_to_hi(), | |
1447 | ), | |
1448 | }; | |
9ffffee4 FG |
1449 | err.assoc2 = Some(errors::AssociatedSuggestion2 { |
1450 | span, | |
1451 | args, | |
1452 | predicate: predicate.span, | |
1453 | trait_segment: trait_segment.ident, | |
1454 | potential_assoc: potential_assoc.ident, | |
1455 | }); | |
a2a8927a XL |
1456 | } |
1457 | } | |
1458 | } | |
1459 | } | |
1460 | } | |
1461 | } | |
1462 | } | |
9ffffee4 | 1463 | this.err_handler().emit_err(err); |
f9f354fc XL |
1464 | } |
1465 | ||
dfeec247 | 1466 | pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { |
9fa01778 XL |
1467 | let mut validator = AstValidator { |
1468 | session, | |
74b04a01 XL |
1469 | extern_mod: None, |
1470 | in_trait_impl: false, | |
94222f64 | 1471 | in_const_trait_impl: false, |
9fa01778 | 1472 | has_proc_macro_decls: false, |
9fa01778 | 1473 | outer_impl_trait: None, |
2b03887a | 1474 | disallow_tilde_const: None, |
9fa01778 | 1475 | is_impl_trait_banned: false, |
5e7ed085 | 1476 | forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden), |
e74abb32 | 1477 | lint_buffer: lints, |
9fa01778 XL |
1478 | }; |
1479 | visit::walk_crate(&mut validator, krate); | |
1480 | ||
416331ca | 1481 | validator.has_proc_macro_decls |
3157f602 | 1482 | } |
5e7ed085 FG |
1483 | |
1484 | /// Used to forbid `let` expressions in certain syntactic locations. | |
2b03887a | 1485 | #[derive(Clone, Copy, Subdiagnostic)] |
f2b60f7d | 1486 | pub(crate) enum ForbiddenLetReason { |
5e7ed085 FG |
1487 | /// `let` is not valid and the source environment is not important |
1488 | GenericForbidden, | |
04454e1e | 1489 | /// A let chain with the `||` operator |
9ffffee4 | 1490 | #[note(ast_passes_not_supported_or)] |
2b03887a | 1491 | NotSupportedOr(#[primary_span] Span), |
04454e1e FG |
1492 | /// A let chain with invalid parentheses |
1493 | /// | |
f2b60f7d | 1494 | /// For example, `let 1 = 1 && (expr && expr)` is allowed |
04454e1e | 1495 | /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not |
9ffffee4 | 1496 | #[note(ast_passes_not_supported_parentheses)] |
2b03887a | 1497 | NotSupportedParentheses(#[primary_span] Span), |
5e7ed085 | 1498 | } |