2 use rustc_ast
::visit
::{self, AssocCtxt, FnCtxt, FnKind, Visitor}
;
3 use rustc_ast
::{AssocTyConstraint, AssocTyConstraintKind, NodeId}
;
4 use rustc_ast
::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}
;
5 use rustc_errors
::struct_span_err
;
6 use rustc_feature
::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}
;
7 use rustc_feature
::{Features, GateIssue}
;
8 use rustc_session
::parse
::{feature_err, feature_err_issue}
;
9 use rustc_session
::Session
;
10 use rustc_span
::source_map
::Spanned
;
11 use rustc_span
::symbol
::{sym, Symbol}
;
16 macro_rules
! gate_feature_fn
{
17 ($visitor
: expr
, $has_feature
: expr
, $span
: expr
, $name
: expr
, $explain
: expr
) => {{
18 let (visitor
, has_feature
, span
, name
, explain
) =
19 (&*$visitor
, $has_feature
, $span
, $name
, $explain
);
20 let has_feature
: bool
= has_feature(visitor
.features
);
21 debug
!("gate_feature(feature = {:?}, span = {:?}); has? {}", name
, span
, has_feature
);
22 if !has_feature
&& !span
.allows_unstable($name
) {
23 feature_err_issue(&visitor
.sess
.parse_sess
, name
, span
, GateIssue
::Language
, explain
)
29 macro_rules
! gate_feature_post
{
30 ($visitor
: expr
, $feature
: ident
, $span
: expr
, $explain
: expr
) => {
31 gate_feature_fn
!($visitor
, |x
: &Features
| x
.$feature
, $span
, sym
::$feature
, $explain
)
35 pub fn check_attribute(attr
: &ast
::Attribute
, sess
: &Session
, features
: &Features
) {
36 PostExpansionVisitor { sess, features }
.visit_attribute(attr
)
39 struct PostExpansionVisitor
<'a
> {
42 // `sess` contains a `Features`, but this might not be that one.
43 features
: &'a Features
,
46 impl<'a
> PostExpansionVisitor
<'a
> {
47 fn check_abi(&self, abi
: ast
::StrLit
) {
48 let ast
::StrLit { symbol_unescaped, span, .. }
= abi
;
50 match &*symbol_unescaped
.as_str() {
52 "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
55 gate_feature_post
!(&self, intrinsics
, span
, "intrinsics are subject to change");
57 "platform-intrinsic" => {
62 "platform intrinsics are experimental and possibly buggy"
70 "vectorcall is experimental and subject to change"
78 "thiscall is experimental and subject to change"
86 "rust-call ABI is subject to change"
94 "PTX ABIs are experimental and subject to change"
102 "unadjusted ABI is an implementation detail and perma-unstable"
105 "msp430-interrupt" => {
108 abi_msp430_interrupt
,
110 "msp430-interrupt ABI is experimental and subject to change"
118 "x86-interrupt ABI is experimental and subject to change"
126 "amdgpu-kernel ABI is experimental and subject to change"
129 "avr-interrupt" | "avr-non-blocking-interrupt" => {
134 "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change"
142 "efiapi ABI is experimental and subject to change"
149 .delay_span_bug(span
, &format
!("unrecognized ABI not caught in lowering: {}", abi
)),
153 fn check_extern(&self, ext
: ast
::Extern
) {
154 if let ast
::Extern
::Explicit(abi
) = ext
{
159 fn maybe_report_invalid_custom_discriminants(&self, variants
: &[ast
::Variant
]) {
160 let has_fields
= variants
.iter().any(|variant
| match variant
.data
{
161 VariantData
::Tuple(..) | VariantData
::Struct(..) => true,
162 VariantData
::Unit(..) => false,
165 let discriminant_spans
= variants
167 .filter(|variant
| match variant
.data
{
168 VariantData
::Tuple(..) | VariantData
::Struct(..) => false,
169 VariantData
::Unit(..) => true,
171 .filter_map(|variant
| variant
.disr_expr
.as_ref().map(|c
| c
.value
.span
))
172 .collect
::<Vec
<_
>>();
174 if !discriminant_spans
.is_empty() && has_fields
{
175 let mut err
= feature_err(
176 &self.sess
.parse_sess
,
177 sym
::arbitrary_enum_discriminant
,
178 discriminant_spans
.clone(),
179 "custom discriminant values are not allowed in enums with tuple or struct variants",
181 for sp
in discriminant_spans
{
182 err
.span_label(sp
, "disallowed custom discriminant");
184 for variant
in variants
.iter() {
185 match &variant
.data
{
186 VariantData
::Struct(..) => {
187 err
.span_label(variant
.span
, "struct variant defined here");
189 VariantData
::Tuple(..) => {
190 err
.span_label(variant
.span
, "tuple variant defined here");
192 VariantData
::Unit(..) => {}
199 fn check_gat(&self, generics
: &ast
::Generics
, span
: Span
) {
200 if !generics
.params
.is_empty() {
203 generic_associated_types
,
205 "generic associated types are unstable"
208 if !generics
.where_clause
.predicates
.is_empty() {
211 generic_associated_types
,
213 "where clauses on associated types are unstable"
218 /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
219 fn check_impl_trait(&self, ty
: &ast
::Ty
) {
220 struct ImplTraitVisitor
<'a
> {
221 vis
: &'a PostExpansionVisitor
<'a
>,
223 impl Visitor
<'_
> for ImplTraitVisitor
<'_
> {
224 fn visit_ty(&mut self, ty
: &ast
::Ty
) {
225 if let ast
::TyKind
::ImplTrait(..) = ty
.kind
{
228 type_alias_impl_trait
,
230 "`impl Trait` in type aliases is unstable"
233 visit
::walk_ty(self, ty
);
236 ImplTraitVisitor { vis: self }
.visit_ty(ty
);
240 impl<'a
> Visitor
<'a
> for PostExpansionVisitor
<'a
> {
241 fn visit_attribute(&mut self, attr
: &ast
::Attribute
) {
243 attr
.ident().and_then(|ident
| BUILTIN_ATTRIBUTE_MAP
.get(&ident
.name
)).map(|a
| **a
);
244 // Check feature gates for built-in attributes.
245 if let Some((.., AttributeGate
::Gated(_
, name
, descr
, has_feature
))) = attr_info
{
246 gate_feature_fn
!(self, has_feature
, attr
.span
, name
, descr
);
248 // Check unstable flavors of the `#[doc]` attribute.
249 if self.sess
.check_name(attr
, sym
::doc
) {
250 for nested_meta
in attr
.meta_item_list().unwrap_or_default() {
251 macro_rules
! gate_doc
{ ($
($name
:ident
=> $feature
:ident
)*) => {
252 $
(if nested_meta
.has_name(sym
::$name
) {
253 let msg
= concat
!("`#[doc(", stringify
!($name
), ")]` is experimental");
254 gate_feature_post
!(self, $feature
, attr
.span
, msg
);
259 include
=> external_doc
262 spotlight
=> doc_spotlight
263 keyword
=> doc_keyword
269 fn visit_name(&mut self, sp
: Span
, name
: Symbol
) {
270 if !name
.as_str().is_ascii() {
274 self.sess
.parse_sess
.source_map().guess_head_span(sp
),
275 "non-ascii idents are not fully supported"
280 fn visit_item(&mut self, i
: &'a ast
::Item
) {
282 ast
::ItemKind
::ForeignMod(ref foreign_module
) => {
283 if let Some(abi
) = foreign_module
.abi
{
288 ast
::ItemKind
::Fn(..) => {
289 if self.sess
.contains_name(&i
.attrs
[..], sym
::plugin_registrar
) {
294 "compiler plugins are experimental and possibly buggy"
297 if self.sess
.contains_name(&i
.attrs
[..], sym
::start
) {
302 "`#[start]` functions are experimental \
303 and their signature may change \
307 if self.sess
.contains_name(&i
.attrs
[..], sym
::main
) {
312 "declaration of a non-standard `#[main]` \
313 function may change over time, for now \
314 a top-level `fn main()` is required"
319 ast
::ItemKind
::Struct(..) => {
320 for attr
in self.sess
.filter_by_name(&i
.attrs
[..], sym
::repr
) {
321 for item
in attr
.meta_item_list().unwrap_or_else(Vec
::new
) {
322 if item
.has_name(sym
::simd
) {
327 "SIMD types are experimental and possibly buggy"
334 ast
::ItemKind
::Enum(ast
::EnumDef { ref variants, .. }
, ..) => {
335 for variant
in variants
{
336 match (&variant
.data
, &variant
.disr_expr
) {
337 (ast
::VariantData
::Unit(..), _
) => {}
338 (_
, Some(disr_expr
)) => gate_feature_post
!(
340 arbitrary_enum_discriminant
,
341 disr_expr
.value
.span
,
342 "discriminants on non-unit variants are experimental"
348 let has_feature
= self.features
.arbitrary_enum_discriminant
;
349 if !has_feature
&& !i
.span
.allows_unstable(sym
::arbitrary_enum_discriminant
) {
350 self.maybe_report_invalid_custom_discriminants(&variants
);
354 ast
::ItemKind
::Impl { polarity, defaultness, ref of_trait, .. }
=> {
355 if let ast
::ImplPolarity
::Negative(span
) = polarity
{
359 span
.to(of_trait
.as_ref().map(|t
| t
.path
.span
).unwrap_or(span
)),
360 "negative trait bounds are not yet fully implemented; \
361 use marker types for now"
365 if let ast
::Defaultness
::Default(_
) = defaultness
{
366 gate_feature_post
!(&self, specialization
, i
.span
, "specialization is unstable");
370 ast
::ItemKind
::Trait(ast
::IsAuto
::Yes
, ..) => {
373 optin_builtin_traits
,
375 "auto traits are experimental and possibly buggy"
379 ast
::ItemKind
::TraitAlias(..) => {
380 gate_feature_post
!(&self, trait_alias
, i
.span
, "trait aliases are experimental");
383 ast
::ItemKind
::MacroDef(ast
::MacroDef { macro_rules: false, .. }
) => {
384 let msg
= "`macro` is experimental";
385 gate_feature_post
!(&self, decl_macro
, i
.span
, msg
);
388 ast
::ItemKind
::TyAlias(_
, _
, _
, Some(ref ty
)) => self.check_impl_trait(&ty
),
393 visit
::walk_item(self, i
);
396 fn visit_foreign_item(&mut self, i
: &'a ast
::ForeignItem
) {
398 ast
::ForeignItemKind
::Fn(..) | ast
::ForeignItemKind
::Static(..) => {
399 let link_name
= self.sess
.first_attr_value_str_by_name(&i
.attrs
, sym
::link_name
);
400 let links_to_llvm
= match link_name
{
401 Some(val
) => val
.as_str().starts_with("llvm."),
407 link_llvm_intrinsics
,
409 "linking to LLVM intrinsics is experimental"
413 ast
::ForeignItemKind
::TyAlias(..) => {
414 gate_feature_post
!(&self, extern_types
, i
.span
, "extern types are experimental");
416 ast
::ForeignItemKind
::MacCall(..) => {}
419 visit
::walk_foreign_item(self, i
)
422 fn visit_ty(&mut self, ty
: &'a ast
::Ty
) {
424 ast
::TyKind
::BareFn(ref bare_fn_ty
) => {
425 self.check_extern(bare_fn_ty
.ext
);
427 ast
::TyKind
::Never
=> {
428 gate_feature_post
!(&self, never_type
, ty
.span
, "the `!` type is experimental");
432 visit
::walk_ty(self, ty
)
435 fn visit_fn_ret_ty(&mut self, ret_ty
: &'a ast
::FnRetTy
) {
436 if let ast
::FnRetTy
::Ty(ref output_ty
) = *ret_ty
{
437 if let ast
::TyKind
::Never
= output_ty
.kind
{
440 self.visit_ty(output_ty
)
445 fn visit_expr(&mut self, e
: &'a ast
::Expr
) {
447 ast
::ExprKind
::Box(_
) => {
452 "box expression syntax is experimental; you can call `Box::new` instead"
455 ast
::ExprKind
::Type(..) => {
456 // To avoid noise about type ascription in common syntax errors, only emit if it
457 // is the *only* error.
458 if self.sess
.parse_sess
.span_diagnostic
.err_count() == 0 {
463 "type ascription is experimental"
467 ast
::ExprKind
::TryBlock(_
) => {
468 gate_feature_post
!(&self, try_blocks
, e
.span
, "`try` expression is experimental");
470 ast
::ExprKind
::Block(_
, opt_label
) => {
471 if let Some(label
) = opt_label
{
476 "labels on blocks are unstable"
482 visit
::walk_expr(self, e
)
485 fn visit_pat(&mut self, pattern
: &'a ast
::Pat
) {
486 match &pattern
.kind
{
487 PatKind
::Box(..) => {
492 "box pattern syntax is experimental"
495 PatKind
::Range(_
, _
, Spanned { node: RangeEnd::Excluded, .. }
) => {
498 exclusive_range_pattern
,
500 "exclusive range pattern syntax is experimental"
505 visit
::walk_pat(self, pattern
)
508 fn visit_fn(&mut self, fn_kind
: FnKind
<'a
>, span
: Span
, _
: NodeId
) {
509 if let Some(header
) = fn_kind
.header() {
510 // Stability of const fn methods are covered in `visit_assoc_item` below.
511 self.check_extern(header
.ext
);
513 if let (ast
::Const
::Yes(_
), ast
::Extern
::Implicit
)
514 | (ast
::Const
::Yes(_
), ast
::Extern
::Explicit(_
)) = (header
.constness
, header
.ext
)
520 "`const extern fn` definitions are unstable"
525 if fn_kind
.ctxt() != Some(FnCtxt
::Foreign
) && fn_kind
.decl().c_variadic() {
526 gate_feature_post
!(&self, c_variadic
, span
, "C-variadic functions are unstable");
529 visit
::walk_fn(self, fn_kind
, span
)
532 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
533 if let GenericParamKind
::Const { .. }
= param
.kind
{
536 |x
: &Features
| x
.const_generics
|| x
.min_const_generics
,
538 sym
::min_const_generics
,
539 "const generics are unstable"
542 visit
::walk_generic_param(self, param
)
545 fn visit_assoc_ty_constraint(&mut self, constraint
: &'a AssocTyConstraint
) {
546 if let AssocTyConstraintKind
::Bound { .. }
= constraint
.kind
{
549 associated_type_bounds
,
551 "associated type bounds are unstable"
554 visit
::walk_assoc_ty_constraint(self, constraint
)
557 fn visit_assoc_item(&mut self, i
: &'a ast
::AssocItem
, ctxt
: AssocCtxt
) {
558 let is_fn
= match i
.kind
{
559 ast
::AssocItemKind
::Fn(_
, ref sig
, _
, _
) => {
560 if let (ast
::Const
::Yes(_
), AssocCtxt
::Trait
) = (sig
.header
.constness
, ctxt
) {
561 gate_feature_post
!(&self, const_fn
, i
.span
, "const fn is unstable");
565 ast
::AssocItemKind
::TyAlias(_
, ref generics
, _
, ref ty
) => {
566 if let (Some(_
), AssocCtxt
::Trait
) = (ty
, ctxt
) {
569 associated_type_defaults
,
571 "associated type defaults are unstable"
574 if let Some(ty
) = ty
{
575 self.check_impl_trait(ty
);
577 self.check_gat(generics
, i
.span
);
582 if let ast
::Defaultness
::Default(_
) = i
.kind
.defaultness() {
583 // Limit `min_specialization` to only specializing functions.
586 |x
: &Features
| x
.specialization
|| (is_fn
&& x
.min_specialization
),
589 "specialization is unstable"
592 visit
::walk_assoc_item(self, i
, ctxt
)
595 fn visit_vis(&mut self, vis
: &'a ast
::Visibility
) {
596 if let ast
::VisibilityKind
::Crate(ast
::CrateSugar
::JustCrate
) = vis
.kind
{
599 crate_visibility_modifier
,
601 "`crate` visibility modifier is experimental"
604 visit
::walk_vis(self, vis
)
608 pub fn check_crate(krate
: &ast
::Crate
, sess
: &Session
) {
609 maybe_stage_features(sess
, krate
);
610 check_incompatible_features(sess
);
611 let mut visitor
= PostExpansionVisitor { sess, features: &sess.features_untracked() }
;
613 let spans
= sess
.parse_sess
.gated_spans
.spans
.borrow();
614 macro_rules
! gate_all
{
615 ($gate
:ident
, $msg
:literal
) => {
616 if let Some(spans
) = spans
.get(&sym
::$gate
) {
618 gate_feature_post
!(&visitor
, $gate
, *span
, $msg
);
623 gate_all
!(if_let_guard
, "`if let` guard is not implemented");
624 gate_all
!(let_chains
, "`let` expressions in this position are experimental");
625 gate_all
!(async_closure
, "async closures are unstable");
626 gate_all
!(generators
, "yield syntax is experimental");
627 gate_all
!(or_patterns
, "or-patterns syntax is experimental");
628 gate_all
!(raw_ref_op
, "raw address of syntax is experimental");
629 gate_all
!(const_trait_bound_opt_out
, "`?const` on trait bounds is experimental");
630 gate_all
!(const_trait_impl
, "const trait impls are experimental");
631 gate_all
!(half_open_range_patterns
, "half-open range patterns are unstable");
633 // All uses of `gate_all!` below this point were added in #65742,
634 // and subsequently disabled (with the non-early gating readded).
635 macro_rules
! gate_all
{
636 ($gate
:ident
, $msg
:literal
) => {
637 // FIXME(eddyb) do something more useful than always
638 // disabling these uses of early feature-gatings.
640 for span
in spans
.get(&sym
::$gate
).unwrap_or(&vec
![]) {
641 gate_feature_post
!(&visitor
, $gate
, *span
, $msg
);
647 gate_all
!(trait_alias
, "trait aliases are experimental");
648 gate_all
!(associated_type_bounds
, "associated type bounds are unstable");
649 gate_all
!(crate_visibility_modifier
, "`crate` visibility modifier is experimental");
650 gate_all
!(const_generics
, "const generics are unstable");
651 gate_all
!(decl_macro
, "`macro` is experimental");
652 gate_all
!(box_patterns
, "box pattern syntax is experimental");
653 gate_all
!(exclusive_range_pattern
, "exclusive range pattern syntax is experimental");
654 gate_all
!(try_blocks
, "`try` blocks are unstable");
655 gate_all
!(label_break_value
, "labels on blocks are unstable");
656 gate_all
!(box_syntax
, "box expression syntax is experimental; you can call `Box::new` instead");
657 // To avoid noise about type ascription in common syntax errors,
658 // only emit if it is the *only* error. (Also check it last.)
659 if sess
.parse_sess
.span_diagnostic
.err_count() == 0 {
660 gate_all
!(type_ascription
, "type ascription is experimental");
663 visit
::walk_crate(&mut visitor
, krate
);
666 fn maybe_stage_features(sess
: &Session
, krate
: &ast
::Crate
) {
667 if !sess
.opts
.unstable_features
.is_nightly_build() {
668 for attr
in krate
.attrs
.iter().filter(|attr
| sess
.check_name(attr
, sym
::feature
)) {
670 sess
.parse_sess
.span_diagnostic
,
673 "`#![feature]` may not be used on the {} release channel",
674 option_env
!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
681 fn check_incompatible_features(sess
: &Session
) {
682 let features
= sess
.features_untracked();
684 let declared_features
= features
685 .declared_lang_features
688 .map(|(name
, span
, _
)| (name
, span
))
689 .chain(features
.declared_lib_features
.iter().copied());
691 for (f1
, f2
) in rustc_feature
::INCOMPATIBLE_FEATURES
693 .filter(|&&(f1
, f2
)| features
.enabled(f1
) && features
.enabled(f2
))
695 if let Some((f1_name
, f1_span
)) = declared_features
.clone().find(|(name
, _
)| name
== f1
) {
696 if let Some((f2_name
, f2_span
)) = declared_features
.clone().find(|(name
, _
)| name
== f2
)
698 let spans
= vec
![f1_span
, f2_span
];
699 sess
.struct_span_err(
702 "features `{}` and `{}` are incompatible, using them at the same time \
707 .help("remove one of these features")