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