]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_passes/src/feature_gate.rs
Rollup merge of #100852 - Samyak2:samyak/100459, r=Mark-Simulacrum
[rust.git] / compiler / rustc_ast_passes / src / feature_gate.rs
1 use rustc_ast as ast;
2 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
3 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
4 use rustc_ast::{PatKind, RangeEnd, VariantData};
5 use rustc_errors::{struct_span_err, Applicability, StashKey};
6 use rustc_feature::Features;
7 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
8 use rustc_session::parse::{feature_err, feature_warn};
9 use rustc_session::Session;
10 use rustc_span::source_map::Spanned;
11 use rustc_span::symbol::sym;
12 use rustc_span::Span;
13
14 macro_rules! gate_feature_fn {
15     ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
16         let (visitor, has_feature, span, name, explain, help) =
17             (&*$visitor, $has_feature, $span, $name, $explain, $help);
18         let has_feature: bool = has_feature(visitor.features);
19         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
20         if !has_feature && !span.allows_unstable($name) {
21             feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit();
22         }
23     }};
24     ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
25         let (visitor, has_feature, span, name, explain) =
26             (&*$visitor, $has_feature, $span, $name, $explain);
27         let has_feature: bool = has_feature(visitor.features);
28         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
29         if !has_feature && !span.allows_unstable($name) {
30             feature_err(&visitor.sess.parse_sess, name, span, explain).emit();
31         }
32     }};
33     (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
34         let (visitor, has_feature, span, name, explain) =
35             (&*$visitor, $has_feature, $span, $name, $explain);
36         let has_feature: bool = has_feature(visitor.features);
37         debug!(
38             "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)",
39             name, span, has_feature
40         );
41         if !has_feature && !span.allows_unstable($name) {
42             feature_warn(&visitor.sess.parse_sess, name, span, explain);
43         }
44     }};
45 }
46
47 macro_rules! gate_feature_post {
48     ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => {
49         gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help)
50     };
51     ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
52         gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
53     };
54     (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
55         gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
56     };
57 }
58
59 pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
60     PostExpansionVisitor { sess, features }.visit_attribute(attr)
61 }
62
63 struct PostExpansionVisitor<'a> {
64     sess: &'a Session,
65
66     // `sess` contains a `Features`, but this might not be that one.
67     features: &'a Features,
68 }
69
70 impl<'a> PostExpansionVisitor<'a> {
71     fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) {
72         let ast::StrLit { symbol_unescaped, span, .. } = abi;
73
74         if let ast::Const::Yes(_) = constness {
75             match symbol_unescaped {
76                 // Stable
77                 sym::Rust | sym::C => {}
78                 abi => gate_feature_post!(
79                     &self,
80                     const_extern_fn,
81                     span,
82                     &format!("`{}` as a `const fn` ABI is unstable", abi)
83                 ),
84             }
85         }
86
87         match symbol_unescaped.as_str() {
88             // Stable
89             "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
90             | "system" => {}
91             "rust-intrinsic" => {
92                 gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
93             }
94             "platform-intrinsic" => {
95                 gate_feature_post!(
96                     &self,
97                     platform_intrinsics,
98                     span,
99                     "platform intrinsics are experimental and possibly buggy"
100                 );
101             }
102             "vectorcall" => {
103                 gate_feature_post!(
104                     &self,
105                     abi_vectorcall,
106                     span,
107                     "vectorcall is experimental and subject to change"
108                 );
109             }
110             "thiscall" => {
111                 gate_feature_post!(
112                     &self,
113                     abi_thiscall,
114                     span,
115                     "thiscall is experimental and subject to change"
116                 );
117             }
118             "rust-call" => {
119                 gate_feature_post!(
120                     &self,
121                     unboxed_closures,
122                     span,
123                     "rust-call ABI is subject to change"
124                 );
125             }
126             "rust-cold" => {
127                 gate_feature_post!(
128                     &self,
129                     rust_cold_cc,
130                     span,
131                     "rust-cold is experimental and subject to change"
132                 );
133             }
134             "ptx-kernel" => {
135                 gate_feature_post!(
136                     &self,
137                     abi_ptx,
138                     span,
139                     "PTX ABIs are experimental and subject to change"
140                 );
141             }
142             "unadjusted" => {
143                 gate_feature_post!(
144                     &self,
145                     abi_unadjusted,
146                     span,
147                     "unadjusted ABI is an implementation detail and perma-unstable"
148                 );
149             }
150             "msp430-interrupt" => {
151                 gate_feature_post!(
152                     &self,
153                     abi_msp430_interrupt,
154                     span,
155                     "msp430-interrupt ABI is experimental and subject to change"
156                 );
157             }
158             "x86-interrupt" => {
159                 gate_feature_post!(
160                     &self,
161                     abi_x86_interrupt,
162                     span,
163                     "x86-interrupt ABI is experimental and subject to change"
164                 );
165             }
166             "amdgpu-kernel" => {
167                 gate_feature_post!(
168                     &self,
169                     abi_amdgpu_kernel,
170                     span,
171                     "amdgpu-kernel ABI is experimental and subject to change"
172                 );
173             }
174             "avr-interrupt" | "avr-non-blocking-interrupt" => {
175                 gate_feature_post!(
176                     &self,
177                     abi_avr_interrupt,
178                     span,
179                     "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change"
180                 );
181             }
182             "efiapi" => {
183                 gate_feature_post!(
184                     &self,
185                     abi_efiapi,
186                     span,
187                     "efiapi ABI is experimental and subject to change"
188                 );
189             }
190             "C-cmse-nonsecure-call" => {
191                 gate_feature_post!(
192                     &self,
193                     abi_c_cmse_nonsecure_call,
194                     span,
195                     "C-cmse-nonsecure-call ABI is experimental and subject to change"
196                 );
197             }
198             "C-unwind" => {
199                 gate_feature_post!(
200                     &self,
201                     c_unwind,
202                     span,
203                     "C-unwind ABI is experimental and subject to change"
204                 );
205             }
206             "stdcall-unwind" => {
207                 gate_feature_post!(
208                     &self,
209                     c_unwind,
210                     span,
211                     "stdcall-unwind ABI is experimental and subject to change"
212                 );
213             }
214             "system-unwind" => {
215                 gate_feature_post!(
216                     &self,
217                     c_unwind,
218                     span,
219                     "system-unwind ABI is experimental and subject to change"
220                 );
221             }
222             "thiscall-unwind" => {
223                 gate_feature_post!(
224                     &self,
225                     c_unwind,
226                     span,
227                     "thiscall-unwind ABI is experimental and subject to change"
228                 );
229             }
230             "cdecl-unwind" => {
231                 gate_feature_post!(
232                     &self,
233                     c_unwind,
234                     span,
235                     "cdecl-unwind ABI is experimental and subject to change"
236                 );
237             }
238             "fastcall-unwind" => {
239                 gate_feature_post!(
240                     &self,
241                     c_unwind,
242                     span,
243                     "fastcall-unwind ABI is experimental and subject to change"
244                 );
245             }
246             "vectorcall-unwind" => {
247                 gate_feature_post!(
248                     &self,
249                     c_unwind,
250                     span,
251                     "vectorcall-unwind ABI is experimental and subject to change"
252                 );
253             }
254             "aapcs-unwind" => {
255                 gate_feature_post!(
256                     &self,
257                     c_unwind,
258                     span,
259                     "aapcs-unwind ABI is experimental and subject to change"
260                 );
261             }
262             "win64-unwind" => {
263                 gate_feature_post!(
264                     &self,
265                     c_unwind,
266                     span,
267                     "win64-unwind ABI is experimental and subject to change"
268                 );
269             }
270             "sysv64-unwind" => {
271                 gate_feature_post!(
272                     &self,
273                     c_unwind,
274                     span,
275                     "sysv64-unwind ABI is experimental and subject to change"
276                 );
277             }
278             "wasm" => {
279                 gate_feature_post!(
280                     &self,
281                     wasm_abi,
282                     span,
283                     "wasm ABI is experimental and subject to change"
284                 );
285             }
286             abi => {
287                 if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
288                     self.sess.parse_sess.span_diagnostic.delay_span_bug(
289                         span,
290                         &format!("unrecognized ABI not caught in lowering: {}", abi),
291                     );
292                 }
293             }
294         }
295     }
296
297     fn check_extern(&self, ext: ast::Extern, constness: ast::Const) {
298         if let ast::Extern::Explicit(abi, _) = ext {
299             self.check_abi(abi, constness);
300         }
301     }
302
303     fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
304         let has_fields = variants.iter().any(|variant| match variant.data {
305             VariantData::Tuple(..) | VariantData::Struct(..) => true,
306             VariantData::Unit(..) => false,
307         });
308
309         let discriminant_spans = variants
310             .iter()
311             .filter(|variant| match variant.data {
312                 VariantData::Tuple(..) | VariantData::Struct(..) => false,
313                 VariantData::Unit(..) => true,
314             })
315             .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
316             .collect::<Vec<_>>();
317
318         if !discriminant_spans.is_empty() && has_fields {
319             let mut err = feature_err(
320                 &self.sess.parse_sess,
321                 sym::arbitrary_enum_discriminant,
322                 discriminant_spans.clone(),
323                 "custom discriminant values are not allowed in enums with tuple or struct variants",
324             );
325             for sp in discriminant_spans {
326                 err.span_label(sp, "disallowed custom discriminant");
327             }
328             for variant in variants.iter() {
329                 match &variant.data {
330                     VariantData::Struct(..) => {
331                         err.span_label(variant.span, "struct variant defined here");
332                     }
333                     VariantData::Tuple(..) => {
334                         err.span_label(variant.span, "tuple variant defined here");
335                     }
336                     VariantData::Unit(..) => {}
337                 }
338             }
339             err.emit();
340         }
341     }
342
343     fn check_gat(&self, generics: &ast::Generics, span: Span) {
344         if !generics.params.is_empty() {
345             gate_feature_post!(
346                 &self,
347                 generic_associated_types,
348                 span,
349                 "generic associated types are unstable"
350             );
351         }
352         if !generics.where_clause.predicates.is_empty() {
353             gate_feature_post!(
354                 &self,
355                 generic_associated_types,
356                 span,
357                 "where clauses on associated types are unstable"
358             );
359         }
360     }
361
362     /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
363     fn check_impl_trait(&self, ty: &ast::Ty) {
364         struct ImplTraitVisitor<'a> {
365             vis: &'a PostExpansionVisitor<'a>,
366         }
367         impl Visitor<'_> for ImplTraitVisitor<'_> {
368             fn visit_ty(&mut self, ty: &ast::Ty) {
369                 if let ast::TyKind::ImplTrait(..) = ty.kind {
370                     gate_feature_post!(
371                         &self.vis,
372                         type_alias_impl_trait,
373                         ty.span,
374                         "`impl Trait` in type aliases is unstable"
375                     );
376                 }
377                 visit::walk_ty(self, ty);
378             }
379         }
380         ImplTraitVisitor { vis: self }.visit_ty(ty);
381     }
382 }
383
384 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
385     fn visit_attribute(&mut self, attr: &ast::Attribute) {
386         let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
387         // Check feature gates for built-in attributes.
388         if let Some(BuiltinAttribute {
389             gate: AttributeGate::Gated(_, name, descr, has_feature),
390             ..
391         }) = attr_info
392         {
393             gate_feature_fn!(self, has_feature, attr.span, *name, descr);
394         }
395         // Check unstable flavors of the `#[doc]` attribute.
396         if attr.has_name(sym::doc) {
397             for nested_meta in attr.meta_item_list().unwrap_or_default() {
398                 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
399                     $(if nested_meta.has_name(sym::$name) {
400                         let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
401                         gate_feature_post!(self, $feature, attr.span, msg);
402                     })*
403                 }}
404
405                 gate_doc!(
406                     cfg => doc_cfg
407                     cfg_hide => doc_cfg_hide
408                     masked => doc_masked
409                     notable_trait => doc_notable_trait
410                 );
411
412                 if nested_meta.has_name(sym::keyword) {
413                     let msg = "`#[doc(keyword)]` is meant for internal use only";
414                     gate_feature_post!(self, rustdoc_internals, attr.span, msg);
415                 }
416
417                 if nested_meta.has_name(sym::fake_variadic) {
418                     let msg = "`#[doc(fake_variadic)]` is meant for internal use only";
419                     gate_feature_post!(self, rustdoc_internals, attr.span, msg);
420                 }
421             }
422         }
423
424         // Emit errors for non-staged-api crates.
425         if !self.features.staged_api {
426             if attr.has_name(sym::unstable)
427                 || attr.has_name(sym::stable)
428                 || attr.has_name(sym::rustc_const_unstable)
429                 || attr.has_name(sym::rustc_const_stable)
430                 || attr.has_name(sym::rustc_default_body_unstable)
431             {
432                 struct_span_err!(
433                     self.sess,
434                     attr.span,
435                     E0734,
436                     "stability attributes may not be used outside of the standard library",
437                 )
438                 .emit();
439             }
440         }
441     }
442
443     fn visit_item(&mut self, i: &'a ast::Item) {
444         match i.kind {
445             ast::ItemKind::ForeignMod(ref foreign_module) => {
446                 if let Some(abi) = foreign_module.abi {
447                     self.check_abi(abi, ast::Const::No);
448                 }
449             }
450
451             ast::ItemKind::Fn(..) => {
452                 if self.sess.contains_name(&i.attrs, sym::start) {
453                     gate_feature_post!(
454                         &self,
455                         start,
456                         i.span,
457                         "`#[start]` functions are experimental \
458                          and their signature may change \
459                          over time"
460                     );
461                 }
462             }
463
464             ast::ItemKind::Struct(..) => {
465                 for attr in self.sess.filter_by_name(&i.attrs, sym::repr) {
466                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
467                         if item.has_name(sym::simd) {
468                             gate_feature_post!(
469                                 &self,
470                                 repr_simd,
471                                 attr.span,
472                                 "SIMD types are experimental and possibly buggy"
473                             );
474                         }
475                     }
476                 }
477             }
478
479             ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
480                 for variant in variants {
481                     match (&variant.data, &variant.disr_expr) {
482                         (ast::VariantData::Unit(..), _) => {}
483                         (_, Some(disr_expr)) => gate_feature_post!(
484                             &self,
485                             arbitrary_enum_discriminant,
486                             disr_expr.value.span,
487                             "discriminants on non-unit variants are experimental"
488                         ),
489                         _ => {}
490                     }
491                 }
492
493                 let has_feature = self.features.arbitrary_enum_discriminant;
494                 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
495                     self.maybe_report_invalid_custom_discriminants(&variants);
496                 }
497             }
498
499             ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
500                 if let ast::ImplPolarity::Negative(span) = polarity {
501                     gate_feature_post!(
502                         &self,
503                         negative_impls,
504                         span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
505                         "negative trait bounds are not yet fully implemented; \
506                          use marker types for now"
507                     );
508                 }
509
510                 if let ast::Defaultness::Default(_) = defaultness {
511                     gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
512                 }
513             }
514
515             ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
516                 gate_feature_post!(
517                     &self,
518                     auto_traits,
519                     i.span,
520                     "auto traits are experimental and possibly buggy"
521                 );
522             }
523
524             ast::ItemKind::TraitAlias(..) => {
525                 gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental");
526             }
527
528             ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => {
529                 let msg = "`macro` is experimental";
530                 gate_feature_post!(&self, decl_macro, i.span, msg);
531             }
532
533             ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ref ty), .. }) => {
534                 self.check_impl_trait(&ty)
535             }
536
537             _ => {}
538         }
539
540         visit::walk_item(self, i);
541     }
542
543     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
544         match i.kind {
545             ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
546                 let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
547                 let links_to_llvm =
548                     link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
549                 if links_to_llvm {
550                     gate_feature_post!(
551                         &self,
552                         link_llvm_intrinsics,
553                         i.span,
554                         "linking to LLVM intrinsics is experimental"
555                     );
556                 }
557             }
558             ast::ForeignItemKind::TyAlias(..) => {
559                 gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
560             }
561             ast::ForeignItemKind::MacCall(..) => {}
562         }
563
564         visit::walk_foreign_item(self, i)
565     }
566
567     fn visit_ty(&mut self, ty: &'a ast::Ty) {
568         match ty.kind {
569             ast::TyKind::BareFn(ref bare_fn_ty) => {
570                 // Function pointers cannot be `const`
571                 self.check_extern(bare_fn_ty.ext, ast::Const::No);
572             }
573             ast::TyKind::Never => {
574                 gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
575             }
576             _ => {}
577         }
578         visit::walk_ty(self, ty)
579     }
580
581     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
582         if let ast::FnRetTy::Ty(ref output_ty) = *ret_ty {
583             if let ast::TyKind::Never = output_ty.kind {
584                 // Do nothing.
585             } else {
586                 self.visit_ty(output_ty)
587             }
588         }
589     }
590
591     fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
592         if let ast::StmtKind::Semi(expr) = &stmt.kind
593             && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
594             && let ast::ExprKind::Type(..) = lhs.kind
595             && self.sess.parse_sess.span_diagnostic.err_count() == 0
596             && !self.features.type_ascription
597             && !lhs.span.allows_unstable(sym::type_ascription)
598         {
599             // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
600             // ascription error, but the likely intention was to write a `let` statement. (#78907).
601             feature_err(
602                 &self.sess.parse_sess,
603                 sym::type_ascription,
604                 lhs.span,
605                 "type ascription is experimental",
606             ).span_suggestion_verbose(
607                 lhs.span.shrink_to_lo(),
608                 "you might have meant to introduce a new binding",
609                 "let ".to_string(),
610                 Applicability::MachineApplicable,
611             ).emit();
612         }
613         visit::walk_stmt(self, stmt);
614     }
615
616     fn visit_expr(&mut self, e: &'a ast::Expr) {
617         match e.kind {
618             ast::ExprKind::Box(_) => {
619                 gate_feature_post!(
620                     &self,
621                     box_syntax,
622                     e.span,
623                     "box expression syntax is experimental; you can call `Box::new` instead"
624                 );
625             }
626             ast::ExprKind::Type(..) => {
627                 if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
628                     // To avoid noise about type ascription in common syntax errors,
629                     // only emit if it is the *only* error.
630                     gate_feature_post!(
631                         &self,
632                         type_ascription,
633                         e.span,
634                         "type ascription is experimental"
635                     );
636                 } else {
637                     // And if it isn't, cancel the early-pass warning.
638                     self.sess
639                         .parse_sess
640                         .span_diagnostic
641                         .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
642                         .map(|err| err.cancel());
643                 }
644             }
645             ast::ExprKind::TryBlock(_) => {
646                 gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
647             }
648             _ => {}
649         }
650         visit::walk_expr(self, e)
651     }
652
653     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
654         match &pattern.kind {
655             PatKind::Slice(pats) => {
656                 for pat in pats {
657                     let inner_pat = match &pat.kind {
658                         PatKind::Ident(.., Some(pat)) => pat,
659                         _ => pat,
660                     };
661                     if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
662                         gate_feature_post!(
663                             &self,
664                             half_open_range_patterns,
665                             pat.span,
666                             "`X..` patterns in slices are experimental"
667                         );
668                     }
669                 }
670             }
671             PatKind::Box(..) => {
672                 gate_feature_post!(
673                     &self,
674                     box_patterns,
675                     pattern.span,
676                     "box pattern syntax is experimental"
677                 );
678             }
679             PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
680                 gate_feature_post!(
681                     &self,
682                     exclusive_range_pattern,
683                     pattern.span,
684                     "exclusive range pattern syntax is experimental"
685                 );
686             }
687             _ => {}
688         }
689         visit::walk_pat(self, pattern)
690     }
691
692     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
693         if let Some(header) = fn_kind.header() {
694             // Stability of const fn methods are covered in `visit_assoc_item` below.
695             self.check_extern(header.ext, header.constness);
696         }
697
698         if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
699             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
700         }
701
702         visit::walk_fn(self, fn_kind, span)
703     }
704
705     fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
706         if let AssocConstraintKind::Bound { .. } = constraint.kind {
707             gate_feature_post!(
708                 &self,
709                 associated_type_bounds,
710                 constraint.span,
711                 "associated type bounds are unstable"
712             )
713         }
714         visit::walk_assoc_constraint(self, constraint)
715     }
716
717     fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
718         let is_fn = match i.kind {
719             ast::AssocItemKind::Fn(_) => true,
720             ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
721                 if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
722                     gate_feature_post!(
723                         &self,
724                         associated_type_defaults,
725                         i.span,
726                         "associated type defaults are unstable"
727                     );
728                 }
729                 if let Some(ty) = ty {
730                     self.check_impl_trait(ty);
731                 }
732                 self.check_gat(generics, i.span);
733                 false
734             }
735             _ => false,
736         };
737         if let ast::Defaultness::Default(_) = i.kind.defaultness() {
738             // Limit `min_specialization` to only specializing functions.
739             gate_feature_fn!(
740                 &self,
741                 |x: &Features| x.specialization || (is_fn && x.min_specialization),
742                 i.span,
743                 sym::specialization,
744                 "specialization is unstable"
745             );
746         }
747         visit::walk_assoc_item(self, i, ctxt)
748     }
749 }
750
751 pub fn check_crate(krate: &ast::Crate, sess: &Session) {
752     maybe_stage_features(sess, krate);
753     check_incompatible_features(sess);
754     let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
755
756     let spans = sess.parse_sess.gated_spans.spans.borrow();
757     macro_rules! gate_all {
758         ($gate:ident, $msg:literal, $help:literal) => {
759             if let Some(spans) = spans.get(&sym::$gate) {
760                 for span in spans {
761                     gate_feature_post!(&visitor, $gate, *span, $msg, $help);
762                 }
763             }
764         };
765         ($gate:ident, $msg:literal) => {
766             if let Some(spans) = spans.get(&sym::$gate) {
767                 for span in spans {
768                     gate_feature_post!(&visitor, $gate, *span, $msg);
769                 }
770             }
771         };
772     }
773     gate_all!(
774         if_let_guard,
775         "`if let` guards are experimental",
776         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
777     );
778     gate_all!(let_chains, "`let` expressions in this position are unstable");
779     gate_all!(
780         async_closure,
781         "async closures are unstable",
782         "to use an async block, remove the `||`: `async {`"
783     );
784     gate_all!(
785         closure_lifetime_binder,
786         "`for<...>` binders for closures are experimental",
787         "consider removing `for<...>`"
788     );
789     gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
790     gate_all!(generators, "yield syntax is experimental");
791     gate_all!(raw_ref_op, "raw address of syntax is experimental");
792     gate_all!(const_trait_impl, "const trait impls are experimental");
793     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
794     gate_all!(inline_const, "inline-const is experimental");
795     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
796     gate_all!(associated_const_equality, "associated const equality is incomplete");
797     gate_all!(yeet_expr, "`do yeet` expression is experimental");
798
799     // All uses of `gate_all!` below this point were added in #65742,
800     // and subsequently disabled (with the non-early gating readded).
801     // We emit an early future-incompatible warning for these.
802     // New syntax gates should go above here to get a hard error gate.
803     macro_rules! gate_all {
804         ($gate:ident, $msg:literal) => {
805             for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
806                 gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
807             }
808         };
809     }
810
811     gate_all!(trait_alias, "trait aliases are experimental");
812     gate_all!(associated_type_bounds, "associated type bounds are unstable");
813     gate_all!(decl_macro, "`macro` is experimental");
814     gate_all!(box_patterns, "box pattern syntax is experimental");
815     gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
816     gate_all!(try_blocks, "`try` blocks are unstable");
817     gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
818     gate_all!(type_ascription, "type ascription is experimental");
819
820     visit::walk_crate(&mut visitor, krate);
821 }
822
823 fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
824     // checks if `#![feature]` has been used to enable any lang feature
825     // does not check the same for lib features unless there's at least one
826     // declared lang feature
827     if !sess.opts.unstable_features.is_nightly_build() {
828         let lang_features = &sess.features_untracked().declared_lang_features;
829         if lang_features.len() == 0 {
830             return;
831         }
832         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
833             let mut err = struct_span_err!(
834                 sess.parse_sess.span_diagnostic,
835                 attr.span,
836                 E0554,
837                 "`#![feature]` may not be used on the {} release channel",
838                 option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
839             );
840             let mut all_stable = true;
841             for ident in
842                 attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
843             {
844                 let name = ident.name;
845                 let stable_since = lang_features
846                     .iter()
847                     .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
848                     .next();
849                 if let Some(since) = stable_since {
850                     err.help(&format!(
851                         "the feature `{}` has been stable since {} and no longer requires \
852                                   an attribute to enable",
853                         name, since
854                     ));
855                 } else {
856                     all_stable = false;
857                 }
858             }
859             if all_stable {
860                 err.span_suggestion(
861                     attr.span,
862                     "remove the attribute",
863                     "",
864                     Applicability::MachineApplicable,
865                 );
866             }
867             err.emit();
868         }
869     }
870 }
871
872 fn check_incompatible_features(sess: &Session) {
873     let features = sess.features_untracked();
874
875     let declared_features = features
876         .declared_lang_features
877         .iter()
878         .copied()
879         .map(|(name, span, _)| (name, span))
880         .chain(features.declared_lib_features.iter().copied());
881
882     for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
883         .iter()
884         .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2))
885     {
886         if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
887             if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
888             {
889                 let spans = vec![f1_span, f2_span];
890                 sess.struct_span_err(
891                     spans.clone(),
892                     &format!(
893                         "features `{}` and `{}` are incompatible, using them at the same time \
894                         is not allowed",
895                         f1_name, f2_name
896                     ),
897                 )
898                 .help("remove one of these features")
899                 .emit();
900             }
901         }
902     }
903 }