]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast_passes/src/feature_gate.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_ast_passes / src / feature_gate.rs
CommitLineData
3dfed10e 1use rustc_ast as ast;
74b04a01 2use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
353b0b11 3use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
2b03887a 4use rustc_ast::{PatKind, RangeEnd};
9ffffee4 5use rustc_errors::{Applicability, StashKey};
2b03887a
FG
6use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
7use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
3dfed10e 8use rustc_session::Session;
dfeec247 9use rustc_span::source_map::Spanned;
cdc7bbd5 10use rustc_span::symbol::sym;
dfeec247 11use rustc_span::Span;
2b03887a 12use rustc_target::spec::abi;
9ffffee4
FG
13use thin_vec::ThinVec;
14use tracing::debug;
15
16use crate::errors;
dfeec247 17
dfeec247 18macro_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
51macro_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
63pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
64 PostExpansionVisitor { sess, features }.visit_attribute(attr)
dfeec247
XL
65}
66
67struct 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
74impl<'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,
49aad941 86 format!("`{}` as a `const fn` ABI is unstable", abi)
04454e1e
FG
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,
49aad941 107 format!(
2b03887a
FG
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
183impl<'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);
49aad941 320 let links_to_llvm = link_name.is_some_and(|val| val.as_str().starts_with("llvm."));
dfeec247
XL
321 if links_to_llvm {
322 gate_feature_post!(
323 &self,
324 link_llvm_intrinsics,
325 i.span,
326 "linking to LLVM intrinsics is experimental"
327 );
328 }
329 }
74b04a01 330 ast::ForeignItemKind::TyAlias(..) => {
dfeec247
XL
331 gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
332 }
ba9703b0 333 ast::ForeignItemKind::MacCall(..) => {}
dfeec247
XL
334 }
335
336 visit::walk_foreign_item(self, i)
337 }
338
339 fn visit_ty(&mut self, ty: &'a ast::Ty) {
487cf647
FG
340 match &ty.kind {
341 ast::TyKind::BareFn(bare_fn_ty) => {
04454e1e
FG
342 // Function pointers cannot be `const`
343 self.check_extern(bare_fn_ty.ext, ast::Const::No);
9ffffee4 344 self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
dfeec247
XL
345 }
346 ast::TyKind::Never => {
347 gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
348 }
349 _ => {}
350 }
351 visit::walk_ty(self, ty)
352 }
353
9ffffee4
FG
354 fn visit_generics(&mut self, g: &'a ast::Generics) {
355 for predicate in &g.where_clause.predicates {
356 match predicate {
357 ast::WherePredicate::BoundPredicate(bound_pred) => {
358 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
359 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
360 }
361 _ => {}
362 }
363 }
364 visit::walk_generics(self, g);
365 }
366
74b04a01 367 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
487cf647 368 if let ast::FnRetTy::Ty(output_ty) = ret_ty {
dfeec247
XL
369 if let ast::TyKind::Never = output_ty.kind {
370 // Do nothing.
371 } else {
372 self.visit_ty(output_ty)
373 }
374 }
375 }
376
064997fb
FG
377 fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
378 if let ast::StmtKind::Semi(expr) = &stmt.kind
379 && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
380 && let ast::ExprKind::Type(..) = lhs.kind
381 && self.sess.parse_sess.span_diagnostic.err_count() == 0
382 && !self.features.type_ascription
383 && !lhs.span.allows_unstable(sym::type_ascription)
384 {
385 // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
386 // ascription error, but the likely intention was to write a `let` statement. (#78907).
f2b60f7d 387 feature_err(
064997fb
FG
388 &self.sess.parse_sess,
389 sym::type_ascription,
390 lhs.span,
064997fb
FG
391 "type ascription is experimental",
392 ).span_suggestion_verbose(
393 lhs.span.shrink_to_lo(),
394 "you might have meant to introduce a new binding",
9ffffee4 395 "let ",
064997fb
FG
396 Applicability::MachineApplicable,
397 ).emit();
398 }
399 visit::walk_stmt(self, stmt);
400 }
401
dfeec247
XL
402 fn visit_expr(&mut self, e: &'a ast::Expr) {
403 match e.kind {
dfeec247 404 ast::ExprKind::Type(..) => {
3dfed10e 405 if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
f2b60f7d
FG
406 // To avoid noise about type ascription in common syntax errors,
407 // only emit if it is the *only* error.
dfeec247
XL
408 gate_feature_post!(
409 &self,
410 type_ascription,
411 e.span,
412 "type ascription is experimental"
413 );
f2b60f7d
FG
414 } else {
415 // And if it isn't, cancel the early-pass warning.
353b0b11
FG
416 if let Some(err) = self
417 .sess
f2b60f7d
FG
418 .parse_sess
419 .span_diagnostic
420 .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
353b0b11
FG
421 {
422 err.cancel()
423 }
dfeec247
XL
424 }
425 }
426 ast::ExprKind::TryBlock(_) => {
427 gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
428 }
dfeec247
XL
429 _ => {}
430 }
431 visit::walk_expr(self, e)
432 }
433
434 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
435 match &pattern.kind {
136023e0
XL
436 PatKind::Slice(pats) => {
437 for pat in pats {
438 let inner_pat = match &pat.kind {
439 PatKind::Ident(.., Some(pat)) => pat,
440 _ => pat,
441 };
442 if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
443 gate_feature_post!(
444 &self,
2b03887a 445 half_open_range_patterns_in_slices,
136023e0
XL
446 pat.span,
447 "`X..` patterns in slices are experimental"
448 );
449 }
450 }
451 }
dfeec247
XL
452 PatKind::Box(..) => {
453 gate_feature_post!(
454 &self,
455 box_patterns,
456 pattern.span,
457 "box pattern syntax is experimental"
458 );
459 }
136023e0 460 PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
dfeec247
XL
461 gate_feature_post!(
462 &self,
463 exclusive_range_pattern,
464 pattern.span,
465 "exclusive range pattern syntax is experimental"
466 );
467 }
468 _ => {}
469 }
470 visit::walk_pat(self, pattern)
471 }
472
9ffffee4
FG
473 fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
474 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
475 visit::walk_poly_trait_ref(self, t);
476 }
477
74b04a01 478 fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
dfeec247 479 if let Some(header) = fn_kind.header() {
74b04a01 480 // Stability of const fn methods are covered in `visit_assoc_item` below.
04454e1e 481 self.check_extern(header.ext, header.constness);
dfeec247
XL
482 }
483
9ffffee4
FG
484 if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
485 self.check_late_bound_lifetime_defs(generic_params);
486 }
487
74b04a01 488 if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
dfeec247
XL
489 gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
490 }
491
f2b60f7d 492 visit::walk_fn(self, fn_kind)
dfeec247
XL
493 }
494
5099ac24
FG
495 fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
496 if let AssocConstraintKind::Bound { .. } = constraint.kind {
353b0b11
FG
497 if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref()
498 && args.inputs.is_empty()
499 && matches!(args.output, ast::FnRetTy::Default(..))
500 {
501 gate_feature_post!(
502 &self,
503 return_type_notation,
504 constraint.span,
505 "return type notation is experimental"
506 );
507 } else {
508 gate_feature_post!(
509 &self,
510 associated_type_bounds,
511 constraint.span,
512 "associated type bounds are unstable"
513 );
514 }
dfeec247 515 }
5099ac24 516 visit::walk_assoc_constraint(self, constraint)
dfeec247
XL
517 }
518
74b04a01 519 fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
487cf647 520 let is_fn = match &i.kind {
cdc7bbd5 521 ast::AssocItemKind::Fn(_) => true,
487cf647 522 ast::AssocItemKind::Type(box ast::TyAlias { ty, .. }) => {
74b04a01 523 if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
dfeec247
XL
524 gate_feature_post!(
525 &self,
526 associated_type_defaults,
74b04a01 527 i.span,
dfeec247
XL
528 "associated type defaults are unstable"
529 );
530 }
dfeec247 531 if let Some(ty) = ty {
353b0b11 532 self.check_impl_trait(ty, true);
dfeec247 533 }
ba9703b0 534 false
dfeec247 535 }
ba9703b0
XL
536 _ => false,
537 };
538 if let ast::Defaultness::Default(_) = i.kind.defaultness() {
539 // Limit `min_specialization` to only specializing functions.
540 gate_feature_fn!(
541 &self,
542 |x: &Features| x.specialization || (is_fn && x.min_specialization),
543 i.span,
544 sym::specialization,
545 "specialization is unstable"
546 );
dfeec247 547 }
74b04a01 548 visit::walk_assoc_item(self, i, ctxt)
dfeec247 549 }
dfeec247
XL
550}
551
3dfed10e
XL
552pub fn check_crate(krate: &ast::Crate, sess: &Session) {
553 maybe_stage_features(sess, krate);
1b1a35ee 554 check_incompatible_features(sess);
3dfed10e 555 let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
dfeec247 556
3dfed10e 557 let spans = sess.parse_sess.gated_spans.spans.borrow();
dfeec247 558 macro_rules! gate_all {
5869c6ff
XL
559 ($gate:ident, $msg:literal, $help:literal) => {
560 if let Some(spans) = spans.get(&sym::$gate) {
561 for span in spans {
562 gate_feature_post!(&visitor, $gate, *span, $msg, $help);
563 }
564 }
565 };
dfeec247 566 ($gate:ident, $msg:literal) => {
3dfed10e
XL
567 if let Some(spans) = spans.get(&sym::$gate) {
568 for span in spans {
569 gate_feature_post!(&visitor, $gate, *span, $msg);
570 }
dfeec247
XL
571 }
572 };
573 }
49aad941 574 gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
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");
49aad941
FG
605 gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
606
607 if !visitor.features.negative_bounds {
608 for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
609 sess.emit_err(errors::NegativeBoundUnsupported { span });
610 }
611 }
dfeec247
XL
612
613 // All uses of `gate_all!` below this point were added in #65742,
614 // and subsequently disabled (with the non-early gating readded).
f2b60f7d
FG
615 // We emit an early future-incompatible warning for these.
616 // New syntax gates should go above here to get a hard error gate.
dfeec247
XL
617 macro_rules! gate_all {
618 ($gate:ident, $msg:literal) => {
f2b60f7d
FG
619 for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
620 gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
dfeec247
XL
621 }
622 };
623 }
624
625 gate_all!(trait_alias, "trait aliases are experimental");
626 gate_all!(associated_type_bounds, "associated type bounds are unstable");
353b0b11 627 gate_all!(return_type_notation, "return type notation is experimental");
dfeec247
XL
628 gate_all!(decl_macro, "`macro` is experimental");
629 gate_all!(box_patterns, "box pattern syntax is experimental");
630 gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
631 gate_all!(try_blocks, "`try` blocks are unstable");
f2b60f7d 632 gate_all!(type_ascription, "type ascription is experimental");
dfeec247
XL
633
634 visit::walk_crate(&mut visitor, krate);
635}
636
3dfed10e 637fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
c295e0f8
XL
638 // checks if `#![feature]` has been used to enable any lang feature
639 // does not check the same for lib features unless there's at least one
640 // declared lang feature
3dfed10e 641 if !sess.opts.unstable_features.is_nightly_build() {
cdc7bbd5 642 let lang_features = &sess.features_untracked().declared_lang_features;
c295e0f8
XL
643 if lang_features.len() == 0 {
644 return;
645 }
94222f64 646 for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
9ffffee4
FG
647 let mut err = errors::FeatureOnNonNightly {
648 span: attr.span,
649 channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
650 stable_features: vec![],
651 sugg: None,
652 };
653
cdc7bbd5
XL
654 let mut all_stable = true;
655 for ident in
5099ac24 656 attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
cdc7bbd5
XL
657 {
658 let name = ident.name;
659 let stable_since = lang_features
660 .iter()
661 .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
662 .next();
663 if let Some(since) = stable_since {
9ffffee4 664 err.stable_features.push(errors::StableFeature { name, since });
cdc7bbd5
XL
665 } else {
666 all_stable = false;
667 }
668 }
669 if all_stable {
9ffffee4 670 err.sugg = Some(attr.span);
cdc7bbd5 671 }
9ffffee4 672 sess.parse_sess.span_diagnostic.emit_err(err);
dfeec247
XL
673 }
674 }
675}
1b1a35ee
XL
676
677fn check_incompatible_features(sess: &Session) {
678 let features = sess.features_untracked();
679
680 let declared_features = features
681 .declared_lang_features
682 .iter()
683 .copied()
684 .map(|(name, span, _)| (name, span))
685 .chain(features.declared_lib_features.iter().copied());
686
687 for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
688 .iter()
689 .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2))
690 {
691 if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
692 if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
693 {
694 let spans = vec![f1_span, f2_span];
9ffffee4 695 sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
1b1a35ee
XL
696 }
697 }
698 }
699}