about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-25 06:18:09 +0200
committerGitHub <noreply@github.com>2019-10-25 06:18:09 +0200
commitd6a18b6baf40b48abce2de5747d187a7bbad293d (patch)
treec633afa2e2d4a69ce731623362fad60a23e526bb /src/libsyntax
parentfb602c7e4f5f01203c63e9c6939efa8c8f7c962a (diff)
parent15a6c09b6e8a977f2c6f5a73de01a20d00b37930 (diff)
downloadrust-d6a18b6baf40b48abce2de5747d187a7bbad293d.tar.gz
rust-d6a18b6baf40b48abce2de5747d187a7bbad293d.zip
Rollup merge of #65742 - Centril:gate-pre-expansion-subset, r=davidtwco
Pre-expansion gate most of the things

This is a subset of https://github.com/rust-lang/rust/pull/64672. A crater run has already been done and this PR implements conclusions according to https://github.com/rust-lang/rust/pull/64672#issuecomment-542703363.

r? @davidtwco
cc @petrochenkov
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/feature_gate/check.rs150
-rw-r--r--src/libsyntax/parse/parser.rs1
-rw-r--r--src/libsyntax/parse/parser/expr.rs13
-rw-r--r--src/libsyntax/parse/parser/generics.rs4
-rw-r--r--src/libsyntax/parse/parser/item.rs35
-rw-r--r--src/libsyntax/parse/parser/pat.rs13
-rw-r--r--src/libsyntax/parse/parser/path.rs12
-rw-r--r--src/libsyntax/sess.rs22
8 files changed, 124 insertions, 126 deletions
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 172511f0f09..502b1c0f743 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -3,12 +3,8 @@ use super::accepted::ACCEPTED_FEATURES;
 use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
 use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 
-use crate::ast::{
-    self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
-    PatKind, RangeEnd, VariantData,
-};
+use crate::ast::{self, NodeId, PatKind, VariantData};
 use crate::attr::{self, check_builtin_attribute};
-use crate::source_map::Spanned;
 use crate::edition::{ALL_EDITIONS, Edition};
 use crate::visit::{self, FnKind, Visitor};
 use crate::parse::token;
@@ -157,9 +153,6 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
 
 }
 
-const EXPLAIN_BOX_SYNTAX: &str =
-    "box expression syntax is experimental; you can call `Box::new` instead";
-
 pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
     "attributes on expressions are experimental";
 
@@ -291,6 +284,25 @@ impl<'a> PostExpansionVisitor<'a> {
             err.emit();
         }
     }
+
+    fn check_gat(&self, generics: &ast::Generics, span: Span) {
+        if !generics.params.is_empty() {
+            gate_feature_post!(
+                &self,
+                generic_associated_types,
+                span,
+                "generic associated types are unstable"
+            );
+        }
+        if !generics.where_clause.predicates.is_empty() {
+            gate_feature_post!(
+                &self,
+                generic_associated_types,
+                span,
+                "where clauses on associated types are unstable"
+            );
+        }
+    }
 }
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@@ -423,20 +435,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                                    "auto traits are experimental and possibly buggy");
             }
 
-            ast::ItemKind::TraitAlias(..) => {
-                gate_feature_post!(
-                    &self,
-                    trait_alias,
-                    i.span,
-                    "trait aliases are experimental"
-                );
-            }
-
-            ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
-                let msg = "`macro` is experimental";
-                gate_feature_post!(&self, decl_macro, i.span, msg);
-            }
-
             ast::ItemKind::OpaqueTy(..) => {
                 gate_feature_post!(
                     &self,
@@ -500,37 +498,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
     }
 
-    fn visit_expr(&mut self, e: &'a ast::Expr) {
-        match e.kind {
-            ast::ExprKind::Box(_) => {
-                gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
-            }
-            ast::ExprKind::Type(..) => {
-                // To avoid noise about type ascription in common syntax errors, only emit if it
-                // is the *only* error.
-                if self.parse_sess.span_diagnostic.err_count() == 0 {
-                    gate_feature_post!(&self, type_ascription, e.span,
-                                       "type ascription is experimental");
-                }
-            }
-            ast::ExprKind::TryBlock(_) => {
-                gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
-            }
-            ast::ExprKind::Block(_, opt_label) => {
-                if let Some(label) = opt_label {
-                    gate_feature_post!(&self, label_break_value, label.ident.span,
-                                    "labels on blocks are unstable");
-                }
-            }
-            _ => {}
-        }
-        visit::walk_expr(self, e)
-    }
-
-    fn visit_arm(&mut self, arm: &'a ast::Arm) {
-        visit::walk_arm(self, arm)
-    }
-
     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
         match &pattern.kind {
             PatKind::Slice(pats) => {
@@ -550,25 +517,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     }
                 }
             }
-            PatKind::Box(..) => {
-                gate_feature_post!(&self, box_patterns,
-                                  pattern.span,
-                                  "box pattern syntax is experimental");
-            }
-            PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
-                gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
-                                   "exclusive range pattern syntax is experimental");
-            }
             _ => {}
         }
         visit::walk_pat(self, pattern)
     }
 
-    fn visit_fn(&mut self,
-                fn_kind: FnKind<'a>,
-                fn_decl: &'a ast::FnDecl,
-                span: Span,
-                _node_id: NodeId) {
+    fn visit_fn(&mut self, fn_kind: FnKind<'a>, fn_decl: &'a ast::FnDecl, span: Span, _: NodeId) {
         if let Some(header) = fn_kind.header() {
             // Stability of const fn methods are covered in
             // `visit_trait_item` and `visit_impl_item` below; this is
@@ -583,26 +537,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_fn(self, fn_kind, fn_decl, span)
     }
 
-    fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        match param.kind {
-            GenericParamKind::Const { .. } =>
-                gate_feature_post!(&self, const_generics, param.ident.span,
-                    "const generics are unstable"),
-            _ => {}
-        }
-        visit::walk_generic_param(self, param)
-    }
-
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
-        match constraint.kind {
-            AssocTyConstraintKind::Bound { .. } =>
-                gate_feature_post!(&self, associated_type_bounds, constraint.span,
-                    "associated type bounds are unstable"),
-            _ => {}
-        }
-        visit::walk_assoc_ty_constraint(self, constraint)
-    }
-
     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
         match ti.kind {
             ast::TraitItemKind::Method(ref sig, ref block) => {
@@ -624,14 +558,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     gate_feature_post!(&self, associated_type_defaults, ti.span,
                                        "associated type defaults are unstable");
                 }
-                if !ti.generics.params.is_empty() {
-                    gate_feature_post!(&self, generic_associated_types, ti.span,
-                                       "generic associated types are unstable");
-                }
-                if !ti.generics.where_clause.predicates.is_empty() {
-                    gate_feature_post!(&self, generic_associated_types, ti.span,
-                                       "where clauses on associated types are unstable");
-                }
+                self.check_gat(&ti.generics, ti.span);
             }
             _ => {}
         }
@@ -661,27 +588,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 );
             }
             ast::ImplItemKind::TyAlias(_) => {
-                if !ii.generics.params.is_empty() {
-                    gate_feature_post!(&self, generic_associated_types, ii.span,
-                                       "generic associated types are unstable");
-                }
-                if !ii.generics.where_clause.predicates.is_empty() {
-                    gate_feature_post!(&self, generic_associated_types, ii.span,
-                                       "where clauses on associated types are unstable");
-                }
+                self.check_gat(&ii.generics, ii.span);
             }
             _ => {}
         }
         visit::walk_impl_item(self, ii)
     }
-
-    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
-        if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
-            gate_feature_post!(&self, crate_visibility_modifier, vis.span,
-                               "`crate` visibility modifier is experimental");
-        }
-        visit::walk_vis(self, vis)
-    }
 }
 
 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
@@ -867,6 +779,22 @@ pub fn check_crate(krate: &ast::Crate,
     gate_all!(yields, generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
     gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
+    gate_all!(trait_alias, "trait aliases are experimental");
+    gate_all!(associated_type_bounds, "associated type bounds are unstable");
+    gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
+    gate_all!(const_generics, "const generics are unstable");
+    gate_all!(decl_macro, "`macro` is experimental");
+    gate_all!(box_patterns, "box pattern syntax is experimental");
+    gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
+    gate_all!(try_blocks, "`try` blocks are unstable");
+    gate_all!(label_break_value, "labels on blocks are unstable");
+    gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
+
+    // To avoid noise about type ascription in common syntax errors,
+    // only emit if it is the *only* error. (Also check it last.)
+    if parse_sess.span_diagnostic.err_count() == 0 {
+        gate_all!(type_ascription, "type ascription is experimental");
+    }
 
     visit::walk_crate(&mut visitor, krate);
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2ce0046ca27..f25224d1e36 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1122,6 +1122,7 @@ impl<'a> Parser<'a> {
         self.expected_tokens.push(TokenType::Keyword(kw::Crate));
         if self.is_crate_vis() {
             self.bump(); // `crate`
+            self.sess.gated_spans.crate_visibility_modifier.borrow_mut().push(self.prev_span);
             return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate)));
         }
 
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 67a530ec683..97b1092452a 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -252,6 +252,7 @@ impl<'a> Parser<'a> {
                 self.last_type_ascription = Some((self.prev_span, maybe_path));
 
                 lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
+                self.sess.gated_spans.type_ascription.borrow_mut().push(lhs.span);
                 continue
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
                 // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to
@@ -453,7 +454,9 @@ impl<'a> Parser<'a> {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (lo.to(span), ExprKind::Box(e))
+                let span = lo.to(span);
+                self.sess.gated_spans.box_syntax.borrow_mut().push(span);
+                (span, ExprKind::Box(e))
             }
             token::Ident(..) if self.token.is_ident_named(sym::not) => {
                 // `not` is just an ordinary identifier in Rust-the-language,
@@ -1260,6 +1263,10 @@ impl<'a> Parser<'a> {
         blk_mode: BlockCheckMode,
         outer_attrs: ThinVec<Attribute>,
     ) -> PResult<'a, P<Expr>> {
+        if let Some(label) = opt_label {
+            self.sess.gated_spans.label_break_value.borrow_mut().push(label.ident.span);
+        }
+
         self.expect(&token::OpenDelim(token::Brace))?;
 
         let mut attrs = outer_attrs;
@@ -1646,7 +1653,9 @@ impl<'a> Parser<'a> {
             error.emit();
             Err(error)
         } else {
-            Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs))
+            let span = span_lo.to(body.span);
+            self.sess.gated_spans.try_blocks.borrow_mut().push(span);
+            Ok(self.mk_expr(span, ExprKind::TryBlock(body), attrs))
         }
     }
 
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs
index bfcb0042a75..51caae69c86 100644
--- a/src/libsyntax/parse/parser/generics.rs
+++ b/src/libsyntax/parse/parser/generics.rs
@@ -55,11 +55,15 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+        let lo = self.token.span;
+
         self.expect_keyword(kw::Const)?;
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
+        self.sess.gated_spans.const_generics.borrow_mut().push(lo.to(self.prev_span));
+
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 73bd80e2a21..95bddb5afdd 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -211,7 +211,7 @@ impl<'a> Parser<'a> {
         {
             // UNSAFE TRAIT ITEM
             self.bump(); // `unsafe`
-            let info = self.parse_item_trait(Unsafety::Unsafe)?;
+            let info = self.parse_item_trait(lo, Unsafety::Unsafe)?;
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
@@ -289,7 +289,7 @@ impl<'a> Parser<'a> {
                 && self.is_keyword_ahead(1, &[kw::Trait]))
         {
             // TRAIT ITEM
-            let info = self.parse_item_trait(Unsafety::Normal)?;
+            let info = self.parse_item_trait(lo, Unsafety::Normal)?;
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
@@ -780,7 +780,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
-    fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
+    fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) {
             IsAuto::Yes
@@ -793,29 +793,43 @@ impl<'a> Parser<'a> {
         let mut tps = self.parse_generics()?;
 
         // Parse optional colon and supertrait bounds.
-        let bounds = if self.eat(&token::Colon) {
+        let had_colon = self.eat(&token::Colon);
+        let span_at_colon = self.prev_span;
+        let bounds = if had_colon {
             self.parse_generic_bounds(Some(self.prev_span))?
         } else {
             Vec::new()
         };
 
+        let span_before_eq = self.prev_span;
         if self.eat(&token::Eq) {
             // It's a trait alias.
+            if had_colon {
+                let span = span_at_colon.to(span_before_eq);
+                self.struct_span_err(span, "bounds are not allowed on trait aliases")
+                    .emit();
+            }
+
             let bounds = self.parse_generic_bounds(None)?;
             tps.where_clause = self.parse_where_clause()?;
             self.expect(&token::Semi)?;
+
+            let whole_span = lo.to(self.prev_span);
             if is_auto == IsAuto::Yes {
                 let msg = "trait aliases cannot be `auto`";
-                self.struct_span_err(self.prev_span, msg)
-                    .span_label(self.prev_span, msg)
+                self.struct_span_err(whole_span, msg)
+                    .span_label(whole_span, msg)
                     .emit();
             }
             if unsafety != Unsafety::Normal {
                 let msg = "trait aliases cannot be `unsafe`";
-                self.struct_span_err(self.prev_span, msg)
-                    .span_label(self.prev_span, msg)
+                self.struct_span_err(whole_span, msg)
+                    .span_label(whole_span, msg)
                     .emit();
             }
+
+            self.sess.gated_spans.trait_alias.borrow_mut().push(whole_span);
+
             Ok((ident, ItemKind::TraitAlias(tps, bounds), None))
         } else {
             // It's a normal trait.
@@ -1692,6 +1706,11 @@ impl<'a> Parser<'a> {
         };
 
         let span = lo.to(self.prev_span);
+
+        if !def.legacy {
+            self.sess.gated_spans.decl_macro.borrow_mut().push(span);
+        }
+
         Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec())))
     }
 
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index af795e51792..969d5dd8374 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -324,7 +324,9 @@ impl<'a> Parser<'a> {
                 self.parse_pat_ident(BindingMode::ByRef(mutbl))?
             } else if self.eat_keyword(kw::Box) {
                 // Parse `box pat`
-                PatKind::Box(self.parse_pat_with_range_pat(false, None)?)
+                let pat = self.parse_pat_with_range_pat(false, None)?;
+                self.sess.gated_spans.box_patterns.borrow_mut().push(lo.to(self.prev_span));
+                PatKind::Box(pat)
             } else if self.can_be_ident_pat() {
                 // Parse `ident @ pat`
                 // This can give false positives and parse nullary enums,
@@ -609,6 +611,11 @@ impl<'a> Parser<'a> {
         Ok(PatKind::Mac(mac))
     }
 
+    fn excluded_range_end(&self, span: Span) -> RangeEnd {
+        self.sess.gated_spans.exclusive_range_pattern.borrow_mut().push(span);
+        RangeEnd::Excluded
+    }
+
     /// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`.
     /// The `$path` has already been parsed and the next token is the `$form`.
     fn parse_pat_range_starting_with_path(
@@ -618,7 +625,7 @@ impl<'a> Parser<'a> {
         path: Path
     ) -> PResult<'a, PatKind> {
         let (end_kind, form) = match self.token.kind {
-            token::DotDot => (RangeEnd::Excluded, ".."),
+            token::DotDot => (self.excluded_range_end(self.token.span), ".."),
             token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
             token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
             _ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"),
@@ -641,7 +648,7 @@ impl<'a> Parser<'a> {
         } else if self.eat(&token::DotDotEq) {
             (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
         } else if self.eat(&token::DotDot) {
-            (RangeEnd::Excluded, "..")
+            (self.excluded_range_end(op_span), "..")
         } else {
             panic!("impossible case: we already matched on a range-operator token")
         };
diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index 639d61a2b5c..77709a22953 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -404,8 +404,9 @@ impl<'a> Parser<'a> {
                 // Parse lifetime argument.
                 args.push(GenericArg::Lifetime(self.expect_lifetime()));
                 misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
-            } else if self.check_ident() && self.look_ahead(1,
-                    |t| t == &token::Eq || t == &token::Colon) {
+            } else if self.check_ident()
+                && self.look_ahead(1, |t| t == &token::Eq || t == &token::Colon)
+            {
                 // Parse associated type constraint.
                 let lo = self.token.span;
                 let ident = self.parse_ident()?;
@@ -420,7 +421,14 @@ impl<'a> Parser<'a> {
                 } else {
                     unreachable!();
                 };
+
                 let span = lo.to(self.prev_span);
+
+                // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
+                if let AssocTyConstraintKind::Bound { .. } = kind {
+                    self.sess.gated_spans.associated_type_bounds.borrow_mut().push(span);
+                }
+
                 constraints.push(AssocTyConstraint {
                     id: ast::DUMMY_NODE_ID,
                     ident,
diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs
index e49d3954f8e..28a0868d5dd 100644
--- a/src/libsyntax/sess.rs
+++ b/src/libsyntax/sess.rs
@@ -30,6 +30,28 @@ crate struct GatedSpans {
     crate or_patterns: Lock<Vec<Span>>,
     /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`.
     crate const_extern_fn: Lock<Vec<Span>>,
+    /// Spans collected for gating `trait_alias`, e.g. `trait Foo = Ord + Eq;`.
+    pub trait_alias: Lock<Vec<Span>>,
+    /// Spans collected for gating `associated_type_bounds`, e.g. `Iterator<Item: Ord>`.
+    pub associated_type_bounds: Lock<Vec<Span>>,
+    /// Spans collected for gating `crate_visibility_modifier`, e.g. `crate fn`.
+    pub crate_visibility_modifier: Lock<Vec<Span>>,
+    /// Spans collected for gating `const_generics`, e.g. `const N: usize`.
+    pub const_generics: Lock<Vec<Span>>,
+    /// Spans collected for gating `decl_macro`, e.g. `macro m() {}`.
+    pub decl_macro: Lock<Vec<Span>>,
+    /// Spans collected for gating `box_patterns`, e.g. `box 0`.
+    pub box_patterns: Lock<Vec<Span>>,
+    /// Spans collected for gating `exclusive_range_pattern`, e.g. `0..2`.
+    pub exclusive_range_pattern: Lock<Vec<Span>>,
+    /// Spans collected for gating `try_blocks`, e.g. `try { a? + b? }`.
+    pub try_blocks: Lock<Vec<Span>>,
+    /// Spans collected for gating `label_break_value`, e.g. `'label: { ... }`.
+    pub label_break_value: Lock<Vec<Span>>,
+    /// Spans collected for gating `box_syntax`, e.g. `box $expr`.
+    pub box_syntax: Lock<Vec<Span>>,
+    /// Spans collected for gating `type_ascription`, e.g. `42: usize`.
+    pub type_ascription: Lock<Vec<Span>>,
 }
 
 /// Info about a parsing session.