1 use rustc_error_codes::*;
2 use rustc_errors::{struct_span_err, Handler};
3 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
4 use rustc_feature::{Features, GateIssue, UnstableFeatures};
5 use rustc_span::source_map::Spanned;
6 use rustc_span::symbol::sym;
8 use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
9 use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
11 use syntax::sess::{feature_err, leveled_feature_err, GateStrength, ParseSess};
12 use syntax::visit::{self, FnKind, Visitor};
16 macro_rules! gate_feature_fn {
17 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
18 let (cx, has_feature, span, name, explain, level) =
19 (&*$cx, $has_feature, $span, $name, $explain, $level);
20 let has_feature: bool = has_feature(&$cx.features);
21 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
22 if !has_feature && !span.allows_unstable($name) {
23 leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
29 macro_rules! gate_feature {
30 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
33 |x: &Features| x.$feature,
40 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
41 gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain, $level)
45 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
46 PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
49 struct PostExpansionVisitor<'a> {
50 parse_sess: &'a ParseSess,
51 features: &'a Features,
54 macro_rules! gate_feature_post {
55 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
56 let (cx, span) = ($cx, $span);
57 if !span.allows_unstable(sym::$feature) {
58 gate_feature!(cx, $feature, span, $explain)
61 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
62 let (cx, span) = ($cx, $span);
63 if !span.allows_unstable(sym::$feature) {
64 gate_feature!(cx, $feature, span, $explain, $level)
69 impl<'a> PostExpansionVisitor<'a> {
70 fn check_abi(&self, abi: ast::StrLit) {
71 let ast::StrLit { symbol_unescaped, span, .. } = abi;
73 match &*symbol_unescaped.as_str() {
75 "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
78 gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
80 "platform-intrinsic" => {
85 "platform intrinsics are experimental and possibly buggy"
93 "vectorcall is experimental and subject to change"
101 "thiscall is experimental and subject to change"
109 "rust-call ABI is subject to change"
117 "PTX ABIs are experimental and subject to change"
125 "unadjusted ABI is an implementation detail and perma-unstable"
128 "msp430-interrupt" => {
131 abi_msp430_interrupt,
133 "msp430-interrupt ABI is experimental and subject to change"
141 "x86-interrupt ABI is experimental and subject to change"
149 "amdgpu-kernel ABI is experimental and subject to change"
157 "efiapi ABI is experimental and subject to change"
163 .delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
167 fn check_extern(&self, ext: ast::Extern) {
168 if let ast::Extern::Explicit(abi) = ext {
173 fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
174 let has_fields = variants.iter().any(|variant| match variant.data {
175 VariantData::Tuple(..) | VariantData::Struct(..) => true,
176 VariantData::Unit(..) => false,
179 let discriminant_spans = variants
181 .filter(|variant| match variant.data {
182 VariantData::Tuple(..) | VariantData::Struct(..) => false,
183 VariantData::Unit(..) => true,
185 .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
186 .collect::<Vec<_>>();
188 if !discriminant_spans.is_empty() && has_fields {
189 let mut err = feature_err(
191 sym::arbitrary_enum_discriminant,
192 discriminant_spans.clone(),
193 "custom discriminant values are not allowed in enums with tuple or struct variants",
195 for sp in discriminant_spans {
196 err.span_label(sp, "disallowed custom discriminant");
198 for variant in variants.iter() {
199 match &variant.data {
200 VariantData::Struct(..) => {
201 err.span_label(variant.span, "struct variant defined here");
203 VariantData::Tuple(..) => {
204 err.span_label(variant.span, "tuple variant defined here");
206 VariantData::Unit(..) => {}
213 fn check_gat(&self, generics: &ast::Generics, span: Span) {
214 if !generics.params.is_empty() {
217 generic_associated_types,
219 "generic associated types are unstable"
222 if !generics.where_clause.predicates.is_empty() {
225 generic_associated_types,
227 "where clauses on associated types are unstable"
232 /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
233 fn check_impl_trait(&self, ty: &ast::Ty) {
234 struct ImplTraitVisitor<'a> {
235 vis: &'a PostExpansionVisitor<'a>,
237 impl Visitor<'_> for ImplTraitVisitor<'_> {
238 fn visit_ty(&mut self, ty: &ast::Ty) {
239 if let ast::TyKind::ImplTrait(..) = ty.kind {
242 type_alias_impl_trait,
244 "`impl Trait` in type aliases is unstable"
247 visit::walk_ty(self, ty);
250 ImplTraitVisitor { vis: self }.visit_ty(ty);
254 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
255 fn visit_attribute(&mut self, attr: &ast::Attribute) {
257 attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
258 // Check feature gates for built-in attributes.
259 if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
260 gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
262 // Check unstable flavors of the `#[doc]` attribute.
263 if attr.check_name(sym::doc) {
264 for nested_meta in attr.meta_item_list().unwrap_or_default() {
265 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
266 $(if nested_meta.check_name(sym::$name) {
267 let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
268 gate_feature!(self, $feature, attr.span, msg);
273 include => external_doc
276 spotlight => doc_spotlight
278 keyword => doc_keyword
284 fn visit_name(&mut self, sp: Span, name: ast::Name) {
285 if !name.as_str().is_ascii() {
289 self.parse_sess.source_map().def_span(sp),
290 "non-ascii idents are not fully supported"
295 fn visit_item(&mut self, i: &'a ast::Item) {
297 ast::ItemKind::ForeignMod(ref foreign_module) => {
298 if let Some(abi) = foreign_module.abi {
303 ast::ItemKind::Fn(..) => {
304 if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
309 "compiler plugins are experimental and possibly buggy"
312 if attr::contains_name(&i.attrs[..], sym::start) {
317 "`#[start]` functions are experimental \
318 and their signature may change \
322 if attr::contains_name(&i.attrs[..], sym::main) {
327 "declaration of a non-standard `#[main]` \
328 function may change over time, for now \
329 a top-level `fn main()` is required"
334 ast::ItemKind::Struct(..) => {
335 for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
336 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
337 if item.check_name(sym::simd) {
342 "SIMD types are experimental and possibly buggy"
349 ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
350 for variant in variants {
351 match (&variant.data, &variant.disr_expr) {
352 (ast::VariantData::Unit(..), _) => {}
353 (_, Some(disr_expr)) => gate_feature_post!(
355 arbitrary_enum_discriminant,
356 disr_expr.value.span,
357 "discriminants on non-unit variants are experimental"
363 let has_feature = self.features.arbitrary_enum_discriminant;
364 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
365 self.maybe_report_invalid_custom_discriminants(&variants);
369 ast::ItemKind::Impl(_, polarity, defaultness, ..) => {
370 if polarity == ast::ImplPolarity::Negative {
373 optin_builtin_traits,
375 "negative trait bounds are not yet fully implemented; \
376 use marker types for now"
380 if let ast::Defaultness::Default = defaultness {
381 gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
385 ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
388 optin_builtin_traits,
390 "auto traits are experimental and possibly buggy"
394 ast::ItemKind::TraitAlias(..) => {
395 gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental");
398 ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
399 let msg = "`macro` is experimental";
400 gate_feature_post!(&self, decl_macro, i.span, msg);
403 ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty),
408 visit::walk_item(self, i);
411 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
413 ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
414 let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
415 let links_to_llvm = match link_name {
416 Some(val) => val.as_str().starts_with("llvm."),
422 link_llvm_intrinsics,
424 "linking to LLVM intrinsics is experimental"
428 ast::ForeignItemKind::Ty => {
429 gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
431 ast::ForeignItemKind::Macro(..) => {}
434 visit::walk_foreign_item(self, i)
437 fn visit_ty(&mut self, ty: &'a ast::Ty) {
439 ast::TyKind::BareFn(ref bare_fn_ty) => {
440 self.check_extern(bare_fn_ty.ext);
442 ast::TyKind::Never => {
443 gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental");
447 visit::walk_ty(self, ty)
450 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
451 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
452 if let ast::TyKind::Never = output_ty.kind {
455 self.visit_ty(output_ty)
460 fn visit_expr(&mut self, e: &'a ast::Expr) {
462 ast::ExprKind::Box(_) => {
467 "box expression syntax is experimental; you can call `Box::new` instead"
470 ast::ExprKind::Type(..) => {
471 // To avoid noise about type ascription in common syntax errors, only emit if it
472 // is the *only* error.
473 if self.parse_sess.span_diagnostic.err_count() == 0 {
478 "type ascription is experimental"
482 ast::ExprKind::TryBlock(_) => {
483 gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
485 ast::ExprKind::Block(_, opt_label) => {
486 if let Some(label) = opt_label {
491 "labels on blocks are unstable"
497 visit::walk_expr(self, e)
500 fn visit_arm(&mut self, arm: &'a ast::Arm) {
501 visit::walk_arm(self, arm)
504 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
505 match &pattern.kind {
506 PatKind::Slice(pats) => {
509 let inner_pat = match &pat.kind {
510 PatKind::Ident(.., Some(pat)) => pat,
513 if inner_pat.is_rest() {
518 "subslice patterns are unstable"
523 PatKind::Box(..) => {
528 "box pattern syntax is experimental"
531 PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
534 exclusive_range_pattern,
536 "exclusive range pattern syntax is experimental"
541 visit::walk_pat(self, pattern)
547 fn_decl: &'a ast::FnDecl,
551 if let Some(header) = fn_kind.header() {
552 // Stability of const fn methods are covered in
553 // `visit_trait_item` and `visit_impl_item` below; this is
554 // because default methods don't pass through this point.
555 self.check_extern(header.ext);
558 if fn_decl.c_variadic() {
559 gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
562 visit::walk_fn(self, fn_kind, fn_decl, span)
565 fn visit_generic_param(&mut self, param: &'a GenericParam) {
567 GenericParamKind::Const { .. } => gate_feature_post!(
571 "const generics are unstable"
575 visit::walk_generic_param(self, param)
578 fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
579 match constraint.kind {
580 AssocTyConstraintKind::Bound { .. } => gate_feature_post!(
582 associated_type_bounds,
584 "associated type bounds are unstable"
588 visit::walk_assoc_ty_constraint(self, constraint)
591 fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
593 ast::AssocItemKind::Fn(ref sig, ref block) => {
595 self.check_extern(sig.header.ext);
597 if sig.header.constness.node == ast::Constness::Const {
598 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
601 ast::AssocItemKind::TyAlias(_, ref default) => {
602 if let Some(_) = default {
605 associated_type_defaults,
607 "associated type defaults are unstable"
613 visit::walk_trait_item(self, ti)
616 fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
617 if ii.defaultness == ast::Defaultness::Default {
618 gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
622 ast::AssocItemKind::Fn(ref sig, _) => {
623 if sig.decl.c_variadic() {
628 "C-variadic functions are unstable"
632 ast::AssocItemKind::TyAlias(_, ref ty) => {
633 if let Some(ty) = ty {
634 self.check_impl_trait(ty);
636 self.check_gat(&ii.generics, ii.span);
640 visit::walk_assoc_item(self, ii)
643 fn visit_vis(&mut self, vis: &'a ast::Visibility) {
644 if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
647 crate_visibility_modifier,
649 "`crate` visibility modifier is experimental"
652 visit::walk_vis(self, vis)
658 parse_sess: &ParseSess,
660 unstable: UnstableFeatures,
662 maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
663 let mut visitor = PostExpansionVisitor { parse_sess, features };
665 let spans = parse_sess.gated_spans.spans.borrow();
666 macro_rules! gate_all {
667 ($gate:ident, $msg:literal) => {
668 for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
669 gate_feature!(&visitor, $gate, *span, $msg);
673 gate_all!(let_chains, "`let` expressions in this position are experimental");
674 gate_all!(async_closure, "async closures are unstable");
675 gate_all!(generators, "yield syntax is experimental");
676 gate_all!(or_patterns, "or-patterns syntax is experimental");
677 gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
678 gate_all!(raw_ref_op, "raw address of syntax is experimental");
679 gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
680 gate_all!(const_trait_impl, "const trait impls are experimental");
681 gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
683 // All uses of `gate_all!` below this point were added in #65742,
684 // and subsequently disabled (with the non-early gating readded).
685 macro_rules! gate_all {
686 ($gate:ident, $msg:literal) => {
687 // FIXME(eddyb) do something more useful than always
688 // disabling these uses of early feature-gatings.
690 for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
691 gate_feature!(&visitor, $gate, *span, $msg);
697 gate_all!(trait_alias, "trait aliases are experimental");
698 gate_all!(associated_type_bounds, "associated type bounds are unstable");
699 gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
700 gate_all!(const_generics, "const generics are unstable");
701 gate_all!(decl_macro, "`macro` is experimental");
702 gate_all!(box_patterns, "box pattern syntax is experimental");
703 gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
704 gate_all!(try_blocks, "`try` blocks are unstable");
705 gate_all!(label_break_value, "labels on blocks are unstable");
706 gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
707 // To avoid noise about type ascription in common syntax errors,
708 // only emit if it is the *only* error. (Also check it last.)
709 if parse_sess.span_diagnostic.err_count() == 0 {
710 gate_all!(type_ascription, "type ascription is experimental");
713 visit::walk_crate(&mut visitor, krate);
716 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
717 if !unstable.is_nightly_build() {
718 for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
723 "`#![feature]` may not be used on the {} release channel",
724 option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")