]>
Commit | Line | Data |
---|---|---|
3dfed10e | 1 | use rustc_ast as ast; |
74b04a01 | 2 | use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; |
353b0b11 | 3 | use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId}; |
2b03887a | 4 | use rustc_ast::{PatKind, RangeEnd}; |
9ffffee4 | 5 | use rustc_errors::{Applicability, StashKey}; |
2b03887a FG |
6 | use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; |
7 | use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; | |
3dfed10e | 8 | use rustc_session::Session; |
dfeec247 | 9 | use rustc_span::source_map::Spanned; |
cdc7bbd5 | 10 | use rustc_span::symbol::sym; |
dfeec247 | 11 | use rustc_span::Span; |
2b03887a | 12 | use rustc_target::spec::abi; |
9ffffee4 FG |
13 | use thin_vec::ThinVec; |
14 | use tracing::debug; | |
15 | ||
16 | use crate::errors; | |
dfeec247 | 17 | |
dfeec247 | 18 | macro_rules! gate_feature_fn { |
5869c6ff XL |
19 | ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ |
20 | let (visitor, has_feature, span, name, explain, help) = | |
21 | (&*$visitor, $has_feature, $span, $name, $explain, $help); | |
22 | let has_feature: bool = has_feature(visitor.features); | |
23 | debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); | |
24 | if !has_feature && !span.allows_unstable($name) { | |
f2b60f7d | 25 | feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit(); |
5869c6ff XL |
26 | } |
27 | }}; | |
3dfed10e XL |
28 | ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ |
29 | let (visitor, has_feature, span, name, explain) = | |
30 | (&*$visitor, $has_feature, $span, $name, $explain); | |
31 | let has_feature: bool = has_feature(visitor.features); | |
dfeec247 XL |
32 | debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); |
33 | if !has_feature && !span.allows_unstable($name) { | |
f2b60f7d FG |
34 | feature_err(&visitor.sess.parse_sess, name, span, explain).emit(); |
35 | } | |
36 | }}; | |
37 | (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ | |
38 | let (visitor, has_feature, span, name, explain) = | |
39 | (&*$visitor, $has_feature, $span, $name, $explain); | |
40 | let has_feature: bool = has_feature(visitor.features); | |
41 | debug!( | |
42 | "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)", | |
43 | name, span, has_feature | |
44 | ); | |
45 | if !has_feature && !span.allows_unstable($name) { | |
46 | feature_warn(&visitor.sess.parse_sess, name, span, explain); | |
dfeec247 XL |
47 | } |
48 | }}; | |
49 | } | |
50 | ||
51 | macro_rules! gate_feature_post { | |
5869c6ff XL |
52 | ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => { |
53 | gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help) | |
54 | }; | |
3dfed10e XL |
55 | ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { |
56 | gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) | |
dfeec247 | 57 | }; |
f2b60f7d FG |
58 | (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { |
59 | gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) | |
60 | }; | |
dfeec247 XL |
61 | } |
62 | ||
3dfed10e XL |
63 | pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { |
64 | PostExpansionVisitor { sess, features }.visit_attribute(attr) | |
dfeec247 XL |
65 | } |
66 | ||
67 | struct PostExpansionVisitor<'a> { | |
3dfed10e XL |
68 | sess: &'a Session, |
69 | ||
70 | // `sess` contains a `Features`, but this might not be that one. | |
dfeec247 XL |
71 | features: &'a Features, |
72 | } | |
73 | ||
74 | impl<'a> PostExpansionVisitor<'a> { | |
04454e1e | 75 | fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { |
dfeec247 XL |
76 | let ast::StrLit { symbol_unescaped, span, .. } = abi; |
77 | ||
04454e1e | 78 | if let ast::Const::Yes(_) = constness { |
064997fb | 79 | match symbol_unescaped { |
04454e1e | 80 | // Stable |
064997fb | 81 | sym::Rust | sym::C => {} |
04454e1e FG |
82 | abi => gate_feature_post!( |
83 | &self, | |
84 | const_extern_fn, | |
85 | span, | |
86 | &format!("`{}` as a `const fn` ABI is unstable", abi) | |
87 | ), | |
88 | } | |
89 | } | |
90 | ||
2b03887a FG |
91 | match abi::is_enabled(&self.features, span, symbol_unescaped.as_str()) { |
92 | Ok(()) => (), | |
93 | Err(abi::AbiDisabled::Unstable { feature, explain }) => { | |
94 | feature_err_issue( | |
95 | &self.sess.parse_sess, | |
96 | feature, | |
5099ac24 | 97 | span, |
2b03887a FG |
98 | GateIssue::Language, |
99 | explain, | |
100 | ) | |
101 | .emit(); | |
cdc7bbd5 | 102 | } |
2b03887a | 103 | Err(abi::AbiDisabled::Unrecognized) => { |
064997fb FG |
104 | if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { |
105 | self.sess.parse_sess.span_diagnostic.delay_span_bug( | |
106 | span, | |
2b03887a FG |
107 | &format!( |
108 | "unrecognized ABI not caught in lowering: {}", | |
109 | symbol_unescaped.as_str() | |
110 | ), | |
064997fb FG |
111 | ); |
112 | } | |
5e7ed085 | 113 | } |
dfeec247 XL |
114 | } |
115 | } | |
116 | ||
04454e1e | 117 | fn check_extern(&self, ext: ast::Extern, constness: ast::Const) { |
064997fb | 118 | if let ast::Extern::Explicit(abi, _) = ext { |
04454e1e | 119 | self.check_abi(abi, constness); |
dfeec247 XL |
120 | } |
121 | } | |
122 | ||
dfeec247 | 123 | /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. |
353b0b11 | 124 | fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) { |
dfeec247 XL |
125 | struct ImplTraitVisitor<'a> { |
126 | vis: &'a PostExpansionVisitor<'a>, | |
353b0b11 | 127 | in_associated_ty: bool, |
dfeec247 XL |
128 | } |
129 | impl Visitor<'_> for ImplTraitVisitor<'_> { | |
130 | fn visit_ty(&mut self, ty: &ast::Ty) { | |
131 | if let ast::TyKind::ImplTrait(..) = ty.kind { | |
353b0b11 FG |
132 | if self.in_associated_ty { |
133 | gate_feature_post!( | |
134 | &self.vis, | |
135 | impl_trait_in_assoc_type, | |
136 | ty.span, | |
137 | "`impl Trait` in associated types is unstable" | |
138 | ); | |
139 | } else { | |
140 | gate_feature_post!( | |
141 | &self.vis, | |
142 | type_alias_impl_trait, | |
143 | ty.span, | |
144 | "`impl Trait` in type aliases is unstable" | |
145 | ); | |
146 | } | |
dfeec247 XL |
147 | } |
148 | visit::walk_ty(self, ty); | |
149 | } | |
150 | } | |
353b0b11 | 151 | ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty); |
dfeec247 | 152 | } |
9ffffee4 FG |
153 | |
154 | fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { | |
155 | // Check only lifetime parameters are present and that the lifetime | |
156 | // parameters that are present have no bounds. | |
157 | let non_lt_param_spans: Vec<_> = params | |
158 | .iter() | |
159 | .filter_map(|param| match param.kind { | |
160 | ast::GenericParamKind::Lifetime { .. } => None, | |
161 | _ => Some(param.ident.span), | |
162 | }) | |
163 | .collect(); | |
164 | // FIXME: gate_feature_post doesn't really handle multispans... | |
165 | if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders { | |
166 | feature_err( | |
167 | &self.sess.parse_sess, | |
168 | sym::non_lifetime_binders, | |
169 | non_lt_param_spans, | |
170 | crate::fluent_generated::ast_passes_forbidden_non_lifetime_param, | |
171 | ) | |
172 | .emit(); | |
173 | } | |
174 | for param in params { | |
175 | if !param.bounds.is_empty() { | |
176 | let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); | |
177 | self.sess.emit_err(errors::ForbiddenLifetimeBound { spans }); | |
178 | } | |
179 | } | |
180 | } | |
dfeec247 XL |
181 | } |
182 | ||
183 | impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { | |
184 | fn visit_attribute(&mut self, attr: &ast::Attribute) { | |
3c0e092e | 185 | let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); |
dfeec247 | 186 | // Check feature gates for built-in attributes. |
3c0e092e XL |
187 | if let Some(BuiltinAttribute { |
188 | gate: AttributeGate::Gated(_, name, descr, has_feature), | |
189 | .. | |
190 | }) = attr_info | |
191 | { | |
9ffffee4 | 192 | gate_feature_fn!(self, has_feature, attr.span, *name, *descr); |
dfeec247 XL |
193 | } |
194 | // Check unstable flavors of the `#[doc]` attribute. | |
94222f64 | 195 | if attr.has_name(sym::doc) { |
dfeec247 XL |
196 | for nested_meta in attr.meta_item_list().unwrap_or_default() { |
197 | macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { | |
3dfed10e | 198 | $(if nested_meta.has_name(sym::$name) { |
dfeec247 XL |
199 | let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental"); |
200 | gate_feature_post!(self, $feature, attr.span, msg); | |
201 | })* | |
202 | }} | |
203 | ||
204 | gate_doc!( | |
dfeec247 | 205 | cfg => doc_cfg |
c295e0f8 | 206 | cfg_hide => doc_cfg_hide |
dfeec247 | 207 | masked => doc_masked |
cdc7bbd5 | 208 | notable_trait => doc_notable_trait |
dfeec247 | 209 | ); |
3c0e092e XL |
210 | |
211 | if nested_meta.has_name(sym::keyword) { | |
212 | let msg = "`#[doc(keyword)]` is meant for internal use only"; | |
213 | gate_feature_post!(self, rustdoc_internals, attr.span, msg); | |
214 | } | |
17df50a5 | 215 | |
064997fb FG |
216 | if nested_meta.has_name(sym::fake_variadic) { |
217 | let msg = "`#[doc(fake_variadic)]` is meant for internal use only"; | |
923072b8 | 218 | gate_feature_post!(self, rustdoc_internals, attr.span, msg); |
17df50a5 XL |
219 | } |
220 | } | |
221 | } | |
5e7ed085 FG |
222 | |
223 | // Emit errors for non-staged-api crates. | |
224 | if !self.features.staged_api { | |
923072b8 | 225 | if attr.has_name(sym::unstable) |
5e7ed085 FG |
226 | || attr.has_name(sym::stable) |
227 | || attr.has_name(sym::rustc_const_unstable) | |
228 | || attr.has_name(sym::rustc_const_stable) | |
f2b60f7d | 229 | || attr.has_name(sym::rustc_default_body_unstable) |
5e7ed085 | 230 | { |
9ffffee4 | 231 | self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span }); |
5e7ed085 FG |
232 | } |
233 | } | |
dfeec247 XL |
234 | } |
235 | ||
dfeec247 | 236 | fn visit_item(&mut self, i: &'a ast::Item) { |
487cf647 FG |
237 | match &i.kind { |
238 | ast::ItemKind::ForeignMod(foreign_module) => { | |
dfeec247 | 239 | if let Some(abi) = foreign_module.abi { |
04454e1e | 240 | self.check_abi(abi, ast::Const::No); |
dfeec247 XL |
241 | } |
242 | } | |
243 | ||
244 | ast::ItemKind::Fn(..) => { | |
353b0b11 | 245 | if attr::contains_name(&i.attrs, sym::start) { |
dfeec247 XL |
246 | gate_feature_post!( |
247 | &self, | |
248 | start, | |
249 | i.span, | |
250 | "`#[start]` functions are experimental \ | |
ba9703b0 XL |
251 | and their signature may change \ |
252 | over time" | |
dfeec247 XL |
253 | ); |
254 | } | |
dfeec247 XL |
255 | } |
256 | ||
257 | ast::ItemKind::Struct(..) => { | |
353b0b11 | 258 | for attr in attr::filter_by_name(&i.attrs, sym::repr) { |
9ffffee4 | 259 | for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { |
3dfed10e | 260 | if item.has_name(sym::simd) { |
dfeec247 XL |
261 | gate_feature_post!( |
262 | &self, | |
263 | repr_simd, | |
264 | attr.span, | |
265 | "SIMD types are experimental and possibly buggy" | |
266 | ); | |
267 | } | |
268 | } | |
269 | } | |
270 | } | |
271 | ||
487cf647 FG |
272 | ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => { |
273 | if let &ast::ImplPolarity::Negative(span) = polarity { | |
dfeec247 XL |
274 | gate_feature_post!( |
275 | &self, | |
ba9703b0 | 276 | negative_impls, |
5869c6ff | 277 | span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), |
dfeec247 | 278 | "negative trait bounds are not yet fully implemented; \ |
ba9703b0 | 279 | use marker types for now" |
dfeec247 XL |
280 | ); |
281 | } | |
282 | ||
74b04a01 | 283 | if let ast::Defaultness::Default(_) = defaultness { |
dfeec247 XL |
284 | gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); |
285 | } | |
286 | } | |
287 | ||
3c0e092e | 288 | ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => { |
dfeec247 XL |
289 | gate_feature_post!( |
290 | &self, | |
fc512014 | 291 | auto_traits, |
dfeec247 XL |
292 | i.span, |
293 | "auto traits are experimental and possibly buggy" | |
294 | ); | |
295 | } | |
296 | ||
297 | ast::ItemKind::TraitAlias(..) => { | |
298 | gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental"); | |
299 | } | |
300 | ||
ba9703b0 | 301 | ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { |
dfeec247 XL |
302 | let msg = "`macro` is experimental"; |
303 | gate_feature_post!(&self, decl_macro, i.span, msg); | |
304 | } | |
305 | ||
487cf647 | 306 | ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => { |
353b0b11 | 307 | self.check_impl_trait(&ty, false) |
5869c6ff | 308 | } |
dfeec247 XL |
309 | |
310 | _ => {} | |
311 | } | |
312 | ||
313 | visit::walk_item(self, i); | |
314 | } | |
315 | ||
316 | fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { | |
317 | match i.kind { | |
318 | ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { | |
353b0b11 | 319 | let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); |
5869c6ff XL |
320 | let links_to_llvm = |
321 | link_name.map_or(false, |val| val.as_str().starts_with("llvm.")); | |
dfeec247 XL |
322 | if links_to_llvm { |
323 | gate_feature_post!( | |
324 | &self, | |
325 | link_llvm_intrinsics, | |
326 | i.span, | |
327 | "linking to LLVM intrinsics is experimental" | |
328 | ); | |
329 | } | |
330 | } | |
74b04a01 | 331 | ast::ForeignItemKind::TyAlias(..) => { |
dfeec247 XL |
332 | gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); |
333 | } | |
ba9703b0 | 334 | ast::ForeignItemKind::MacCall(..) => {} |
dfeec247 XL |
335 | } |
336 | ||
337 | visit::walk_foreign_item(self, i) | |
338 | } | |
339 | ||
340 | fn visit_ty(&mut self, ty: &'a ast::Ty) { | |
487cf647 FG |
341 | match &ty.kind { |
342 | ast::TyKind::BareFn(bare_fn_ty) => { | |
04454e1e FG |
343 | // Function pointers cannot be `const` |
344 | self.check_extern(bare_fn_ty.ext, ast::Const::No); | |
9ffffee4 | 345 | self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); |
dfeec247 XL |
346 | } |
347 | ast::TyKind::Never => { | |
348 | gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); | |
349 | } | |
350 | _ => {} | |
351 | } | |
352 | visit::walk_ty(self, ty) | |
353 | } | |
354 | ||
9ffffee4 FG |
355 | fn visit_generics(&mut self, g: &'a ast::Generics) { |
356 | for predicate in &g.where_clause.predicates { | |
357 | match predicate { | |
358 | ast::WherePredicate::BoundPredicate(bound_pred) => { | |
359 | // A type binding, eg `for<'c> Foo: Send+Clone+'c` | |
360 | self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); | |
361 | } | |
362 | _ => {} | |
363 | } | |
364 | } | |
365 | visit::walk_generics(self, g); | |
366 | } | |
367 | ||
74b04a01 | 368 | fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { |
487cf647 | 369 | if let ast::FnRetTy::Ty(output_ty) = ret_ty { |
dfeec247 XL |
370 | if let ast::TyKind::Never = output_ty.kind { |
371 | // Do nothing. | |
372 | } else { | |
373 | self.visit_ty(output_ty) | |
374 | } | |
375 | } | |
376 | } | |
377 | ||
064997fb FG |
378 | fn visit_stmt(&mut self, stmt: &'a ast::Stmt) { |
379 | if let ast::StmtKind::Semi(expr) = &stmt.kind | |
380 | && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind | |
381 | && let ast::ExprKind::Type(..) = lhs.kind | |
382 | && self.sess.parse_sess.span_diagnostic.err_count() == 0 | |
383 | && !self.features.type_ascription | |
384 | && !lhs.span.allows_unstable(sym::type_ascription) | |
385 | { | |
386 | // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type | |
387 | // ascription error, but the likely intention was to write a `let` statement. (#78907). | |
f2b60f7d | 388 | feature_err( |
064997fb FG |
389 | &self.sess.parse_sess, |
390 | sym::type_ascription, | |
391 | lhs.span, | |
064997fb FG |
392 | "type ascription is experimental", |
393 | ).span_suggestion_verbose( | |
394 | lhs.span.shrink_to_lo(), | |
395 | "you might have meant to introduce a new binding", | |
9ffffee4 | 396 | "let ", |
064997fb FG |
397 | Applicability::MachineApplicable, |
398 | ).emit(); | |
399 | } | |
400 | visit::walk_stmt(self, stmt); | |
401 | } | |
402 | ||
dfeec247 XL |
403 | fn visit_expr(&mut self, e: &'a ast::Expr) { |
404 | match e.kind { | |
dfeec247 | 405 | ast::ExprKind::Type(..) => { |
3dfed10e | 406 | if self.sess.parse_sess.span_diagnostic.err_count() == 0 { |
f2b60f7d FG |
407 | // To avoid noise about type ascription in common syntax errors, |
408 | // only emit if it is the *only* error. | |
dfeec247 XL |
409 | gate_feature_post!( |
410 | &self, | |
411 | type_ascription, | |
412 | e.span, | |
413 | "type ascription is experimental" | |
414 | ); | |
f2b60f7d FG |
415 | } else { |
416 | // And if it isn't, cancel the early-pass warning. | |
353b0b11 FG |
417 | if let Some(err) = self |
418 | .sess | |
f2b60f7d FG |
419 | .parse_sess |
420 | .span_diagnostic | |
421 | .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) | |
353b0b11 FG |
422 | { |
423 | err.cancel() | |
424 | } | |
dfeec247 XL |
425 | } |
426 | } | |
427 | ast::ExprKind::TryBlock(_) => { | |
428 | gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); | |
429 | } | |
dfeec247 XL |
430 | _ => {} |
431 | } | |
432 | visit::walk_expr(self, e) | |
433 | } | |
434 | ||
435 | fn visit_pat(&mut self, pattern: &'a ast::Pat) { | |
436 | match &pattern.kind { | |
136023e0 XL |
437 | PatKind::Slice(pats) => { |
438 | for pat in pats { | |
439 | let inner_pat = match &pat.kind { | |
440 | PatKind::Ident(.., Some(pat)) => pat, | |
441 | _ => pat, | |
442 | }; | |
443 | if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind { | |
444 | gate_feature_post!( | |
445 | &self, | |
2b03887a | 446 | half_open_range_patterns_in_slices, |
136023e0 XL |
447 | pat.span, |
448 | "`X..` patterns in slices are experimental" | |
449 | ); | |
450 | } | |
451 | } | |
452 | } | |
dfeec247 XL |
453 | PatKind::Box(..) => { |
454 | gate_feature_post!( | |
455 | &self, | |
456 | box_patterns, | |
457 | pattern.span, | |
458 | "box pattern syntax is experimental" | |
459 | ); | |
460 | } | |
136023e0 | 461 | PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { |
dfeec247 XL |
462 | gate_feature_post!( |
463 | &self, | |
464 | exclusive_range_pattern, | |
465 | pattern.span, | |
466 | "exclusive range pattern syntax is experimental" | |
467 | ); | |
468 | } | |
469 | _ => {} | |
470 | } | |
471 | visit::walk_pat(self, pattern) | |
472 | } | |
473 | ||
9ffffee4 FG |
474 | fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { |
475 | self.check_late_bound_lifetime_defs(&t.bound_generic_params); | |
476 | visit::walk_poly_trait_ref(self, t); | |
477 | } | |
478 | ||
74b04a01 | 479 | fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { |
dfeec247 | 480 | if let Some(header) = fn_kind.header() { |
74b04a01 | 481 | // Stability of const fn methods are covered in `visit_assoc_item` below. |
04454e1e | 482 | self.check_extern(header.ext, header.constness); |
dfeec247 XL |
483 | } |
484 | ||
9ffffee4 FG |
485 | if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { |
486 | self.check_late_bound_lifetime_defs(generic_params); | |
487 | } | |
488 | ||
74b04a01 | 489 | if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { |
dfeec247 XL |
490 | gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); |
491 | } | |
492 | ||
f2b60f7d | 493 | visit::walk_fn(self, fn_kind) |
dfeec247 XL |
494 | } |
495 | ||
5099ac24 FG |
496 | fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { |
497 | if let AssocConstraintKind::Bound { .. } = constraint.kind { | |
353b0b11 FG |
498 | if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref() |
499 | && args.inputs.is_empty() | |
500 | && matches!(args.output, ast::FnRetTy::Default(..)) | |
501 | { | |
502 | gate_feature_post!( | |
503 | &self, | |
504 | return_type_notation, | |
505 | constraint.span, | |
506 | "return type notation is experimental" | |
507 | ); | |
508 | } else { | |
509 | gate_feature_post!( | |
510 | &self, | |
511 | associated_type_bounds, | |
512 | constraint.span, | |
513 | "associated type bounds are unstable" | |
514 | ); | |
515 | } | |
dfeec247 | 516 | } |
5099ac24 | 517 | visit::walk_assoc_constraint(self, constraint) |
dfeec247 XL |
518 | } |
519 | ||
74b04a01 | 520 | fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { |
487cf647 | 521 | let is_fn = match &i.kind { |
cdc7bbd5 | 522 | ast::AssocItemKind::Fn(_) => true, |
487cf647 | 523 | ast::AssocItemKind::Type(box ast::TyAlias { ty, .. }) => { |
74b04a01 | 524 | if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { |
dfeec247 XL |
525 | gate_feature_post!( |
526 | &self, | |
527 | associated_type_defaults, | |
74b04a01 | 528 | i.span, |
dfeec247 XL |
529 | "associated type defaults are unstable" |
530 | ); | |
531 | } | |
dfeec247 | 532 | if let Some(ty) = ty { |
353b0b11 | 533 | self.check_impl_trait(ty, true); |
dfeec247 | 534 | } |
ba9703b0 | 535 | false |
dfeec247 | 536 | } |
ba9703b0 XL |
537 | _ => false, |
538 | }; | |
539 | if let ast::Defaultness::Default(_) = i.kind.defaultness() { | |
540 | // Limit `min_specialization` to only specializing functions. | |
541 | gate_feature_fn!( | |
542 | &self, | |
543 | |x: &Features| x.specialization || (is_fn && x.min_specialization), | |
544 | i.span, | |
545 | sym::specialization, | |
546 | "specialization is unstable" | |
547 | ); | |
dfeec247 | 548 | } |
74b04a01 | 549 | visit::walk_assoc_item(self, i, ctxt) |
dfeec247 | 550 | } |
dfeec247 XL |
551 | } |
552 | ||
3dfed10e XL |
553 | pub fn check_crate(krate: &ast::Crate, sess: &Session) { |
554 | maybe_stage_features(sess, krate); | |
1b1a35ee | 555 | check_incompatible_features(sess); |
3dfed10e | 556 | let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() }; |
dfeec247 | 557 | |
3dfed10e | 558 | let spans = sess.parse_sess.gated_spans.spans.borrow(); |
dfeec247 | 559 | macro_rules! gate_all { |
5869c6ff XL |
560 | ($gate:ident, $msg:literal, $help:literal) => { |
561 | if let Some(spans) = spans.get(&sym::$gate) { | |
562 | for span in spans { | |
563 | gate_feature_post!(&visitor, $gate, *span, $msg, $help); | |
564 | } | |
565 | } | |
566 | }; | |
dfeec247 | 567 | ($gate:ident, $msg:literal) => { |
3dfed10e XL |
568 | if let Some(spans) = spans.get(&sym::$gate) { |
569 | for span in spans { | |
570 | gate_feature_post!(&visitor, $gate, *span, $msg); | |
571 | } | |
dfeec247 XL |
572 | } |
573 | }; | |
574 | } | |
6a06907d XL |
575 | gate_all!( |
576 | if_let_guard, | |
577 | "`if let` guards are experimental", | |
578 | "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`" | |
579 | ); | |
5099ac24 | 580 | gate_all!(let_chains, "`let` expressions in this position are unstable"); |
5869c6ff XL |
581 | gate_all!( |
582 | async_closure, | |
583 | "async closures are unstable", | |
584 | "to use an async block, remove the `||`: `async {`" | |
585 | ); | |
064997fb FG |
586 | gate_all!( |
587 | closure_lifetime_binder, | |
588 | "`for<...>` binders for closures are experimental", | |
589 | "consider removing `for<...>`" | |
590 | ); | |
17df50a5 | 591 | gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); |
dfeec247 | 592 | gate_all!(generators, "yield syntax is experimental"); |
dfeec247 | 593 | gate_all!(raw_ref_op, "raw address of syntax is experimental"); |
dfeec247 | 594 | gate_all!(const_trait_impl, "const trait impls are experimental"); |
2b03887a FG |
595 | gate_all!( |
596 | half_open_range_patterns_in_slices, | |
597 | "half-open range patterns in slices are unstable" | |
598 | ); | |
29967ef6 | 599 | gate_all!(inline_const, "inline-const is experimental"); |
3c0e092e | 600 | gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); |
5099ac24 | 601 | gate_all!(associated_const_equality, "associated const equality is incomplete"); |
04454e1e | 602 | gate_all!(yeet_expr, "`do yeet` expression is experimental"); |
353b0b11 FG |
603 | gate_all!(dyn_star, "`dyn*` trait objects are experimental"); |
604 | gate_all!(const_closures, "const closures are experimental"); | |
dfeec247 XL |
605 | |
606 | // All uses of `gate_all!` below this point were added in #65742, | |
607 | // and subsequently disabled (with the non-early gating readded). | |
f2b60f7d FG |
608 | // We emit an early future-incompatible warning for these. |
609 | // New syntax gates should go above here to get a hard error gate. | |
dfeec247 XL |
610 | macro_rules! gate_all { |
611 | ($gate:ident, $msg:literal) => { | |
f2b60f7d FG |
612 | for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { |
613 | gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg); | |
dfeec247 XL |
614 | } |
615 | }; | |
616 | } | |
617 | ||
618 | gate_all!(trait_alias, "trait aliases are experimental"); | |
619 | gate_all!(associated_type_bounds, "associated type bounds are unstable"); | |
353b0b11 | 620 | gate_all!(return_type_notation, "return type notation is experimental"); |
dfeec247 XL |
621 | gate_all!(decl_macro, "`macro` is experimental"); |
622 | gate_all!(box_patterns, "box pattern syntax is experimental"); | |
623 | gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); | |
624 | gate_all!(try_blocks, "`try` blocks are unstable"); | |
f2b60f7d | 625 | gate_all!(type_ascription, "type ascription is experimental"); |
dfeec247 XL |
626 | |
627 | visit::walk_crate(&mut visitor, krate); | |
628 | } | |
629 | ||
3dfed10e | 630 | fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { |
c295e0f8 XL |
631 | // checks if `#![feature]` has been used to enable any lang feature |
632 | // does not check the same for lib features unless there's at least one | |
633 | // declared lang feature | |
3dfed10e | 634 | if !sess.opts.unstable_features.is_nightly_build() { |
cdc7bbd5 | 635 | let lang_features = &sess.features_untracked().declared_lang_features; |
c295e0f8 XL |
636 | if lang_features.len() == 0 { |
637 | return; | |
638 | } | |
94222f64 | 639 | for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { |
9ffffee4 FG |
640 | let mut err = errors::FeatureOnNonNightly { |
641 | span: attr.span, | |
642 | channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), | |
643 | stable_features: vec![], | |
644 | sugg: None, | |
645 | }; | |
646 | ||
cdc7bbd5 XL |
647 | let mut all_stable = true; |
648 | for ident in | |
5099ac24 | 649 | attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) |
cdc7bbd5 XL |
650 | { |
651 | let name = ident.name; | |
652 | let stable_since = lang_features | |
653 | .iter() | |
654 | .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) | |
655 | .next(); | |
656 | if let Some(since) = stable_since { | |
9ffffee4 | 657 | err.stable_features.push(errors::StableFeature { name, since }); |
cdc7bbd5 XL |
658 | } else { |
659 | all_stable = false; | |
660 | } | |
661 | } | |
662 | if all_stable { | |
9ffffee4 | 663 | err.sugg = Some(attr.span); |
cdc7bbd5 | 664 | } |
9ffffee4 | 665 | sess.parse_sess.span_diagnostic.emit_err(err); |
dfeec247 XL |
666 | } |
667 | } | |
668 | } | |
1b1a35ee XL |
669 | |
670 | fn check_incompatible_features(sess: &Session) { | |
671 | let features = sess.features_untracked(); | |
672 | ||
673 | let declared_features = features | |
674 | .declared_lang_features | |
675 | .iter() | |
676 | .copied() | |
677 | .map(|(name, span, _)| (name, span)) | |
678 | .chain(features.declared_lib_features.iter().copied()); | |
679 | ||
680 | for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES | |
681 | .iter() | |
682 | .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) | |
683 | { | |
684 | if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { | |
685 | if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) | |
686 | { | |
687 | let spans = vec![f1_span, f2_span]; | |
9ffffee4 | 688 | sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name }); |
1b1a35ee XL |
689 | } |
690 | } | |
691 | } | |
692 | } |