Repository: dtolnay/syn
Pull request #1354 (2023-02-04 22:56:22)

Implement restrictions
https://rust-lang.github.io/rfcs/3323-restrictions.html


Patch:
diff --git a/src/data.rs b/src/data.rs
index fbba41ab..de99dae4 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -140,6 +140,8 @@ ast_struct! {
 
         pub vis: Visibility,
 
+        pub mutability: FieldMutability,
+
         /// Name of the field, if any.
         ///
         /// Fields of tuple structs have no names.
@@ -215,6 +217,7 @@ pub mod parsing {
             Ok(Field {
                 attrs: input.call(Attribute::parse_outer)?,
                 vis: input.parse()?,
+                mutability: FieldMutability::None,
                 ident: Some(if input.peek(Token![_]) {
                     input.call(Ident::parse_any)
                 } else {
@@ -231,6 +234,7 @@ pub mod parsing {
             Ok(Field {
                 attrs: input.call(Attribute::parse_outer)?,
                 vis: input.parse()?,
+                mutability: FieldMutability::None,
                 ident: None,
                 colon_token: None,
                 ty: input.parse()?,
diff --git a/src/gen/clone.rs b/src/gen/clone.rs
index 2e1996fc..f239f9e5 100644
--- a/src/gen/clone.rs
+++ b/src/gen/clone.rs
@@ -779,12 +779,22 @@ impl Clone for Field {
         Field {
             attrs: self.attrs.clone(),
             vis: self.vis.clone(),
+            mutability: self.mutability.clone(),
             ident: self.ident.clone(),
             colon_token: self.colon_token.clone(),
             ty: self.ty.clone(),
         }
     }
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
+impl Clone for FieldMutability {
+    fn clone(&self) -> Self {
+        match self {
+            FieldMutability::None => FieldMutability::None,
+        }
+    }
+}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Clone for FieldPat {
@@ -1036,6 +1046,13 @@ impl Clone for ImplItemType {
         }
     }
 }
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
+impl Clone for ImplRestriction {
+    fn clone(&self) -> Self {
+        match *self {}
+    }
+}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Clone for Index {
@@ -1227,6 +1244,7 @@ impl Clone for ItemTrait {
             vis: self.vis.clone(),
             unsafety: self.unsafety.clone(),
             auto_token: self.auto_token.clone(),
+            restriction: self.restriction.clone(),
             trait_token: self.trait_token.clone(),
             ident: self.ident.clone(),
             generics: self.generics.clone(),
@@ -1706,6 +1724,16 @@ impl Clone for Signature {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
+impl Clone for StaticMutability {
+    fn clone(&self) -> Self {
+        match self {
+            StaticMutability::Mut(v0) => StaticMutability::Mut(v0.clone()),
+            StaticMutability::None => StaticMutability::None,
+        }
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
 impl Clone for Stmt {
     fn clone(&self) -> Self {
         match self {
diff --git a/src/gen/debug.rs b/src/gen/debug.rs
index a5e68051..82bd6f3b 100644
--- a/src/gen/debug.rs
+++ b/src/gen/debug.rs
@@ -1093,12 +1093,22 @@ impl Debug for Field {
         let mut formatter = formatter.debug_struct("Field");
         formatter.field("attrs", &self.attrs);
         formatter.field("vis", &self.vis);
+        formatter.field("mutability", &self.mutability);
         formatter.field("ident", &self.ident);
         formatter.field("colon_token", &self.colon_token);
         formatter.field("ty", &self.ty);
         formatter.finish()
     }
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Debug for FieldMutability {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            FieldMutability::None => formatter.write_str("None"),
+        }
+    }
+}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for FieldPat {
@@ -1442,6 +1452,13 @@ impl Debug for ImplItemType {
         formatter.finish()
     }
 }
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Debug for ImplRestriction {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        match *self {}
+    }
+}
 #[cfg(any(feature = "derive", feature = "full"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for Index {
@@ -1697,6 +1714,7 @@ impl Debug for ItemTrait {
         formatter.field("vis", &self.vis);
         formatter.field("unsafety", &self.unsafety);
         formatter.field("auto_token", &self.auto_token);
+        formatter.field("restriction", &self.restriction);
         formatter.field("trait_token", &self.trait_token);
         formatter.field("ident", &self.ident);
         formatter.field("generics", &self.generics);
@@ -2323,6 +2341,20 @@ impl Debug for Signature {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Debug for StaticMutability {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            StaticMutability::Mut(v0) => {
+                let mut formatter = formatter.debug_tuple("Mut");
+                formatter.field(v0);
+                formatter.finish()
+            }
+            StaticMutability::None => formatter.write_str("None"),
+        }
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Debug for Stmt {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         match self {
diff --git a/src/gen/eq.rs b/src/gen/eq.rs
index 6dfb96a8..891b8f8d 100644
--- a/src/gen/eq.rs
+++ b/src/gen/eq.rs
@@ -739,10 +739,23 @@ impl Eq for Field {}
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl PartialEq for Field {
     fn eq(&self, other: &Self) -> bool {
-        self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
+        self.attrs == other.attrs && self.vis == other.vis
+            && self.mutability == other.mutability && self.ident == other.ident
             && self.colon_token == other.colon_token && self.ty == other.ty
     }
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Eq for FieldMutability {}
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl PartialEq for FieldMutability {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (FieldMutability::None, FieldMutability::None) => true,
+        }
+    }
+}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for FieldPat {}
@@ -1014,6 +1027,16 @@ impl PartialEq for ImplItemType {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Eq for ImplRestriction {}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl PartialEq for ImplRestriction {
+    fn eq(&self, _other: &Self) -> bool {
+        match *self {}
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for Item {}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
@@ -1165,8 +1188,8 @@ impl PartialEq for ItemTrait {
     fn eq(&self, other: &Self) -> bool {
         self.attrs == other.attrs && self.vis == other.vis
             && self.unsafety == other.unsafety && self.auto_token == other.auto_token
-            && self.ident == other.ident && self.generics == other.generics
-            && self.colon_token == other.colon_token
+            && self.restriction == other.restriction && self.ident == other.ident
+            && self.generics == other.generics && self.colon_token == other.colon_token
             && self.supertraits == other.supertraits && self.items == other.items
     }
 }
@@ -1631,6 +1654,20 @@ impl PartialEq for Signature {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Eq for StaticMutability {}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl PartialEq for StaticMutability {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (StaticMutability::Mut(_), StaticMutability::Mut(_)) => true,
+            (StaticMutability::None, StaticMutability::None) => true,
+            _ => false,
+        }
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Eq for Stmt {}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 13b49dab..7bfb39af 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -270,6 +270,10 @@ pub trait Fold {
     fn fold_field(&mut self, i: Field) -> Field {
         fold_field(self, i)
     }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn fold_field_mutability(&mut self, i: FieldMutability) -> FieldMutability {
+        fold_field_mutability(self, i)
+    }
     #[cfg(feature = "full")]
     fn fold_field_pat(&mut self, i: FieldPat) -> FieldPat {
         fold_field_pat(self, i)
@@ -353,6 +357,10 @@ pub trait Fold {
     fn fold_impl_item_type(&mut self, i: ImplItemType) -> ImplItemType {
         fold_impl_item_type(self, i)
     }
+    #[cfg(feature = "full")]
+    fn fold_impl_restriction(&mut self, i: ImplRestriction) -> ImplRestriction {
+        fold_impl_restriction(self, i)
+    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn fold_index(&mut self, i: Index) -> Index {
         fold_index(self, i)
@@ -583,6 +591,10 @@ pub trait Fold {
         fold_span(self, i)
     }
     #[cfg(feature = "full")]
+    fn fold_static_mutability(&mut self, i: StaticMutability) -> StaticMutability {
+        fold_static_mutability(self, i)
+    }
+    #[cfg(feature = "full")]
     fn fold_stmt(&mut self, i: Stmt) -> Stmt {
         fold_stmt(self, i)
     }
@@ -1607,11 +1619,21 @@ where
     Field {
         attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
         vis: f.fold_visibility(node.vis),
+        mutability: f.fold_field_mutability(node.mutability),
         ident: (node.ident).map(|it| f.fold_ident(it)),
         colon_token: (node.colon_token).map(|it| Token![:](tokens_helper(f, &it.spans))),
         ty: f.fold_type(node.ty),
     }
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_field_mutability<F>(f: &mut F, node: FieldMutability) -> FieldMutability
+where
+    F: Fold + ?Sized,
+{
+    match node {
+        FieldMutability::None => FieldMutability::None,
+    }
+}
 #[cfg(feature = "full")]
 pub fn fold_field_pat<F>(f: &mut F, node: FieldPat) -> FieldPat
 where
@@ -1744,7 +1766,7 @@ where
         attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
         vis: f.fold_visibility(node.vis),
         static_token: Token![static](tokens_helper(f, &node.static_token.span)),
-        mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+        mutability: f.fold_static_mutability(node.mutability),
         ident: f.fold_ident(node.ident),
         colon_token: Token![:](tokens_helper(f, &node.colon_token.spans)),
         ty: Box::new(f.fold_type(*node.ty)),
@@ -1908,6 +1930,13 @@ where
         semi_token: Token![;](tokens_helper(f, &node.semi_token.spans)),
     }
 }
+#[cfg(feature = "full")]
+pub fn fold_impl_restriction<F>(f: &mut F, node: ImplRestriction) -> ImplRestriction
+where
+    F: Fold + ?Sized,
+{
+    match node {}
+}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn fold_index<F>(f: &mut F, node: Index) -> Index
 where
@@ -2086,7 +2115,7 @@ where
         attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
         vis: f.fold_visibility(node.vis),
         static_token: Token![static](tokens_helper(f, &node.static_token.span)),
-        mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+        mutability: f.fold_static_mutability(node.mutability),
         ident: f.fold_ident(node.ident),
         colon_token: Token![:](tokens_helper(f, &node.colon_token.spans)),
         ty: Box::new(f.fold_type(*node.ty)),
@@ -2120,6 +2149,7 @@ where
         vis: f.fold_visibility(node.vis),
         unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))),
         auto_token: (node.auto_token).map(|it| Token![auto](tokens_helper(f, &it.span))),
+        restriction: (node.restriction).map(|it| f.fold_impl_restriction(it)),
         trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)),
         ident: f.fold_ident(node.ident),
         generics: f.fold_generics(node.generics),
@@ -2715,6 +2745,18 @@ where
     node
 }
 #[cfg(feature = "full")]
+pub fn fold_static_mutability<F>(f: &mut F, node: StaticMutability) -> StaticMutability
+where
+    F: Fold + ?Sized,
+{
+    match node {
+        StaticMutability::Mut(_binding_0) => {
+            StaticMutability::Mut(Token![mut](tokens_helper(f, &_binding_0.span)))
+        }
+        StaticMutability::None => StaticMutability::None,
+    }
+}
+#[cfg(feature = "full")]
 pub fn fold_stmt<F>(f: &mut F, node: Stmt) -> Stmt
 where
     F: Fold + ?Sized,
diff --git a/src/gen/hash.rs b/src/gen/hash.rs
index fec790a2..84af5061 100644
--- a/src/gen/hash.rs
+++ b/src/gen/hash.rs
@@ -1007,11 +1007,26 @@ impl Hash for Field {
     {
         self.attrs.hash(state);
         self.vis.hash(state);
+        self.mutability.hash(state);
         self.ident.hash(state);
         self.colon_token.hash(state);
         self.ty.hash(state);
     }
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Hash for FieldMutability {
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        match self {
+            FieldMutability::None => {
+                state.write_u8(0u8);
+            }
+        }
+    }
+}
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for FieldPat {
@@ -1353,6 +1368,16 @@ impl Hash for ImplItemType {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Hash for ImplRestriction {
+    fn hash<H>(&self, _state: &mut H)
+    where
+        H: Hasher,
+    {
+        match *self {}
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for Item {
     fn hash<H>(&self, state: &mut H)
     where
@@ -1577,6 +1602,7 @@ impl Hash for ItemTrait {
         self.vis.hash(state);
         self.unsafety.hash(state);
         self.auto_token.hash(state);
+        self.restriction.hash(state);
         self.ident.hash(state);
         self.generics.hash(state);
         self.colon_token.hash(state);
@@ -2165,6 +2191,23 @@ impl Hash for Signature {
 }
 #[cfg(feature = "full")]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
+impl Hash for StaticMutability {
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        match self {
+            StaticMutability::Mut(_) => {
+                state.write_u8(0u8);
+            }
+            StaticMutability::None => {
+                state.write_u8(1u8);
+            }
+        }
+    }
+}
+#[cfg(feature = "full")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
 impl Hash for Stmt {
     fn hash<H>(&self, state: &mut H)
     where
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index 1d1f61db..b92829f1 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -272,6 +272,10 @@ pub trait Visit<'ast> {
     fn visit_field(&mut self, i: &'ast Field) {
         visit_field(self, i);
     }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_field_mutability(&mut self, i: &'ast FieldMutability) {
+        visit_field_mutability(self, i);
+    }
     #[cfg(feature = "full")]
     fn visit_field_pat(&mut self, i: &'ast FieldPat) {
         visit_field_pat(self, i);
@@ -355,6 +359,10 @@ pub trait Visit<'ast> {
     fn visit_impl_item_type(&mut self, i: &'ast ImplItemType) {
         visit_impl_item_type(self, i);
     }
+    #[cfg(feature = "full")]
+    fn visit_impl_restriction(&mut self, i: &'ast ImplRestriction) {
+        visit_impl_restriction(self, i);
+    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_index(&mut self, i: &'ast Index) {
         visit_index(self, i);
@@ -585,6 +593,10 @@ pub trait Visit<'ast> {
         visit_span(self, i);
     }
     #[cfg(feature = "full")]
+    fn visit_static_mutability(&mut self, i: &'ast StaticMutability) {
+        visit_static_mutability(self, i);
+    }
+    #[cfg(feature = "full")]
     fn visit_stmt(&mut self, i: &'ast Stmt) {
         visit_stmt(self, i);
     }
@@ -1780,6 +1792,7 @@ where
         v.visit_attribute(it);
     }
     v.visit_visibility(&node.vis);
+    v.visit_field_mutability(&node.mutability);
     if let Some(it) = &node.ident {
         v.visit_ident(it);
     }
@@ -1788,6 +1801,15 @@ where
     }
     v.visit_type(&node.ty);
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_field_mutability<'ast, V>(v: &mut V, node: &'ast FieldMutability)
+where
+    V: Visit<'ast> + ?Sized,
+{
+    match node {
+        FieldMutability::None => {}
+    }
+}
 #[cfg(feature = "full")]
 pub fn visit_field_pat<'ast, V>(v: &mut V, node: &'ast FieldPat)
 where
@@ -1944,9 +1966,7 @@ where
     }
     v.visit_visibility(&node.vis);
     tokens_helper(v, &node.static_token.span);
-    if let Some(it) = &node.mutability {
-        tokens_helper(v, &it.span);
-    }
+    v.visit_static_mutability(&node.mutability);
     v.visit_ident(&node.ident);
     tokens_helper(v, &node.colon_token.spans);
     v.visit_type(&*node.ty);
@@ -2127,6 +2147,13 @@ where
     v.visit_type(&node.ty);
     tokens_helper(v, &node.semi_token.spans);
 }
+#[cfg(feature = "full")]
+pub fn visit_impl_restriction<'ast, V>(v: &mut V, node: &'ast ImplRestriction)
+where
+    V: Visit<'ast> + ?Sized,
+{
+    match *node {}
+}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_index<'ast, V>(v: &mut V, node: &'ast Index)
 where
@@ -2350,9 +2377,7 @@ where
     }
     v.visit_visibility(&node.vis);
     tokens_helper(v, &node.static_token.span);
-    if let Some(it) = &node.mutability {
-        tokens_helper(v, &it.span);
-    }
+    v.visit_static_mutability(&node.mutability);
     v.visit_ident(&node.ident);
     tokens_helper(v, &node.colon_token.spans);
     v.visit_type(&*node.ty);
@@ -2392,6 +2417,9 @@ where
     if let Some(it) = &node.auto_token {
         tokens_helper(v, &it.span);
     }
+    if let Some(it) = &node.restriction {
+        v.visit_impl_restriction(it);
+    }
     tokens_helper(v, &node.trait_token.span);
     v.visit_ident(&node.ident);
     v.visit_generics(&node.generics);
@@ -3078,6 +3106,18 @@ where
     V: Visit<'ast> + ?Sized,
 {}
 #[cfg(feature = "full")]
+pub fn visit_static_mutability<'ast, V>(v: &mut V, node: &'ast StaticMutability)
+where
+    V: Visit<'ast> + ?Sized,
+{
+    match node {
+        StaticMutability::Mut(_binding_0) => {
+            tokens_helper(v, &_binding_0.span);
+        }
+        StaticMutability::None => {}
+    }
+}
+#[cfg(feature = "full")]
 pub fn visit_stmt<'ast, V>(v: &mut V, node: &'ast Stmt)
 where
     V: Visit<'ast> + ?Sized,
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index fcf7663d..8cd9b631 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -273,6 +273,10 @@ pub trait VisitMut {
     fn visit_field_mut(&mut self, i: &mut Field) {
         visit_field_mut(self, i);
     }
+    #[cfg(any(feature = "derive", feature = "full"))]
+    fn visit_field_mutability_mut(&mut self, i: &mut FieldMutability) {
+        visit_field_mutability_mut(self, i);
+    }
     #[cfg(feature = "full")]
     fn visit_field_pat_mut(&mut self, i: &mut FieldPat) {
         visit_field_pat_mut(self, i);
@@ -356,6 +360,10 @@ pub trait VisitMut {
     fn visit_impl_item_type_mut(&mut self, i: &mut ImplItemType) {
         visit_impl_item_type_mut(self, i);
     }
+    #[cfg(feature = "full")]
+    fn visit_impl_restriction_mut(&mut self, i: &mut ImplRestriction) {
+        visit_impl_restriction_mut(self, i);
+    }
     #[cfg(any(feature = "derive", feature = "full"))]
     fn visit_index_mut(&mut self, i: &mut Index) {
         visit_index_mut(self, i);
@@ -586,6 +594,10 @@ pub trait VisitMut {
         visit_span_mut(self, i);
     }
     #[cfg(feature = "full")]
+    fn visit_static_mutability_mut(&mut self, i: &mut StaticMutability) {
+        visit_static_mutability_mut(self, i);
+    }
+    #[cfg(feature = "full")]
     fn visit_stmt_mut(&mut self, i: &mut Stmt) {
         visit_stmt_mut(self, i);
     }
@@ -1781,6 +1793,7 @@ where
         v.visit_attribute_mut(it);
     }
     v.visit_visibility_mut(&mut node.vis);
+    v.visit_field_mutability_mut(&mut node.mutability);
     if let Some(it) = &mut node.ident {
         v.visit_ident_mut(it);
     }
@@ -1789,6 +1802,15 @@ where
     }
     v.visit_type_mut(&mut node.ty);
 }
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_field_mutability_mut<V>(v: &mut V, node: &mut FieldMutability)
+where
+    V: VisitMut + ?Sized,
+{
+    match node {
+        FieldMutability::None => {}
+    }
+}
 #[cfg(feature = "full")]
 pub fn visit_field_pat_mut<V>(v: &mut V, node: &mut FieldPat)
 where
@@ -1945,9 +1967,7 @@ where
     }
     v.visit_visibility_mut(&mut node.vis);
     tokens_helper(v, &mut node.static_token.span);
-    if let Some(it) = &mut node.mutability {
-        tokens_helper(v, &mut it.span);
-    }
+    v.visit_static_mutability_mut(&mut node.mutability);
     v.visit_ident_mut(&mut node.ident);
     tokens_helper(v, &mut node.colon_token.spans);
     v.visit_type_mut(&mut *node.ty);
@@ -2130,6 +2150,13 @@ where
     v.visit_type_mut(&mut node.ty);
     tokens_helper(v, &mut node.semi_token.spans);
 }
+#[cfg(feature = "full")]
+pub fn visit_impl_restriction_mut<V>(v: &mut V, node: &mut ImplRestriction)
+where
+    V: VisitMut + ?Sized,
+{
+    match *node {}
+}
 #[cfg(any(feature = "derive", feature = "full"))]
 pub fn visit_index_mut<V>(v: &mut V, node: &mut Index)
 where
@@ -2353,9 +2380,7 @@ where
     }
     v.visit_visibility_mut(&mut node.vis);
     tokens_helper(v, &mut node.static_token.span);
-    if let Some(it) = &mut node.mutability {
-        tokens_helper(v, &mut it.span);
-    }
+    v.visit_static_mutability_mut(&mut node.mutability);
     v.visit_ident_mut(&mut node.ident);
     tokens_helper(v, &mut node.colon_token.spans);
     v.visit_type_mut(&mut *node.ty);
@@ -2395,6 +2420,9 @@ where
     if let Some(it) = &mut node.auto_token {
         tokens_helper(v, &mut it.span);
     }
+    if let Some(it) = &mut node.restriction {
+        v.visit_impl_restriction_mut(it);
+    }
     tokens_helper(v, &mut node.trait_token.span);
     v.visit_ident_mut(&mut node.ident);
     v.visit_generics_mut(&mut node.generics);
@@ -3081,6 +3109,18 @@ where
     V: VisitMut + ?Sized,
 {}
 #[cfg(feature = "full")]
+pub fn visit_static_mutability_mut<V>(v: &mut V, node: &mut StaticMutability)
+where
+    V: VisitMut + ?Sized,
+{
+    match node {
+        StaticMutability::Mut(_binding_0) => {
+            tokens_helper(v, &mut _binding_0.span);
+        }
+        StaticMutability::None => {}
+    }
+}
+#[cfg(feature = "full")]
 pub fn visit_stmt_mut<V>(v: &mut V, node: &mut Stmt)
 where
     V: VisitMut + ?Sized,
diff --git a/src/item.rs b/src/item.rs
index ce6b1563..19db870e 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -204,7 +204,7 @@ ast_struct! {
         pub attrs: Vec<Attribute>,
         pub vis: Visibility,
         pub static_token: Token![static],
-        pub mutability: Option<Token![mut]>,
+        pub mutability: StaticMutability,
         pub ident: Ident,
         pub colon_token: Token![:],
         pub ty: Box<Type>,
@@ -236,6 +236,7 @@ ast_struct! {
         pub vis: Visibility,
         pub unsafety: Option<Token![unsafe]>,
         pub auto_token: Option<Token![auto]>,
+        pub restriction: Option<ImplRestriction>,
         pub trait_token: Token![trait],
         pub ident: Ident,
         pub generics: Generics,
@@ -541,7 +542,7 @@ ast_struct! {
         pub attrs: Vec<Attribute>,
         pub vis: Visibility,
         pub static_token: Token![static],
-        pub mutability: Option<Token![mut]>,
+        pub mutability: StaticMutability,
         pub ident: Ident,
         pub colon_token: Token![:],
         pub ty: Box<Type>,
@@ -852,6 +853,31 @@ ast_struct! {
     }
 }
 
+ast_enum! {
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
+    #[non_exhaustive]
+    pub enum StaticMutability {
+        Mut(Token![mut]),
+        None,
+    }
+}
+
+ast_enum! {
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
+    #[non_exhaustive]
+    pub enum ImplRestriction {}
+
+
+    // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
+    //
+    // pub struct ImplRestriction {
+    //     pub impl_token: Token![impl],
+    //     pub paren_token: token::Paren,
+    //     pub in_token: Option<Token![in]>,
+    //     pub path: Box<Path>,
+    // }
+}
+
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
@@ -2038,6 +2064,7 @@ pub mod parsing {
             vis,
             unsafety,
             auto_token,
+            restriction: None,
             trait_token,
             ident,
             generics,
@@ -2662,6 +2689,14 @@ pub mod parsing {
             }
         }
     }
+
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+    impl Parse for StaticMutability {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let mut_token: Option<Token![mut]> = input.parse()?;
+            Ok(mut_token.map_or(StaticMutability::None, StaticMutability::Mut))
+        }
+    }
 }
 
 #[cfg(feature = "printing")]
@@ -3185,4 +3220,14 @@ mod printing {
             self.comma.to_tokens(tokens);
         }
     }
+
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
+    impl ToTokens for StaticMutability {
+        fn to_tokens(&self, tokens: &mut TokenStream) {
+            match self {
+                StaticMutability::None => {}
+                StaticMutability::Mut(mut_token) => mut_token.to_tokens(tokens),
+            }
+        }
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index d8ede800..97f650ab 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -381,11 +381,11 @@ mod item;
 #[cfg(feature = "full")]
 pub use crate::item::{
     FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,
-    ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, Item, ItemConst, ItemEnum,
-    ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct,
-    ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, Signature, TraitItem,
-    TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, UseGlob, UseGroup, UseName,
-    UsePath, UseRename, UseTree, Variadic,
+    ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,
+    ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,
+    ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,
+    Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,
+    TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,
 };
 
 mod lifetime;
@@ -460,6 +460,11 @@ mod print;
 
 pub mod punctuated;
 
+#[cfg(any(feature = "full", feature = "derive"))]
+mod restriction;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};
+
 mod sealed;
 
 mod span;
@@ -490,11 +495,6 @@ pub use crate::ty::{
 #[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
 mod verbatim;
 
-#[cfg(any(feature = "full", feature = "derive"))]
-mod visibility;
-#[cfg(any(feature = "full", feature = "derive"))]
-pub use crate::visibility::{VisRestricted, Visibility};
-
 #[cfg(all(feature = "parsing", feature = "full"))]
 mod whitespace;
 
diff --git a/src/visibility.rs b/src/restriction.rs
similarity index 91%
rename from src/visibility.rs
rename to src/restriction.rs
index 2e8f576b..f4d26959 100644
--- a/src/visibility.rs
+++ b/src/restriction.rs
@@ -35,6 +35,24 @@ ast_struct! {
     }
 }
 
+ast_enum! {
+    #[non_exhaustive]
+    pub enum FieldMutability {
+        None,
+
+        // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
+        //
+        // FieldMutability::Restricted(MutRestricted)
+        //
+        // pub struct MutRestricted {
+        //     pub mut_token: Token![mut],
+        //     pub paren_token: token::Paren,
+        //     pub in_token: Option<Token![in]>,
+        //     pub path: Box<Path>,
+        // }
+    }
+}
+
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
diff --git a/syn.json b/syn.json
index f229837e..b366505a 100644
--- a/syn.json
+++ b/syn.json
@@ -1966,6 +1966,9 @@
         "vis": {
           "syn": "Visibility"
         },
+        "mutability": {
+          "syn": "FieldMutability"
+        },
         "ident": {
           "option": {
             "proc_macro2": "Ident"
@@ -1981,6 +1984,19 @@
         }
       }
     },
+    {
+      "ident": "FieldMutability",
+      "features": {
+        "any": [
+          "derive",
+          "full"
+        ]
+      },
+      "variants": {
+        "None": []
+      },
+      "exhaustive": false
+    },
     {
       "ident": "FieldPat",
       "features": {
@@ -2249,9 +2265,7 @@
           "token": "Static"
         },
         "mutability": {
-          "option": {
-            "token": "Mut"
-          }
+          "syn": "StaticMutability"
         },
         "ident": {
           "proc_macro2": "Ident"
@@ -2573,6 +2587,16 @@
         }
       }
     },
+    {
+      "ident": "ImplRestriction",
+      "features": {
+        "any": [
+          "full"
+        ]
+      },
+      "variants": {},
+      "exhaustive": false
+    },
     {
       "ident": "Index",
       "features": {
@@ -3011,9 +3035,7 @@
           "token": "Static"
         },
         "mutability": {
-          "option": {
-            "token": "Mut"
-          }
+          "syn": "StaticMutability"
         },
         "ident": {
           "proc_macro2": "Ident"
@@ -3100,6 +3122,11 @@
             "token": "Auto"
           }
         },
+        "restriction": {
+          "option": {
+            "syn": "ImplRestriction"
+          }
+        },
         "trait_token": {
           "token": "Trait"
         },
@@ -4311,6 +4338,23 @@
         }
       }
     },
+    {
+      "ident": "StaticMutability",
+      "features": {
+        "any": [
+          "full"
+        ]
+      },
+      "variants": {
+        "Mut": [
+          {
+            "token": "Mut"
+          }
+        ],
+        "None": []
+      },
+      "exhaustive": false
+    },
     {
       "ident": "Stmt",
       "features": {


Test patch:
diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs
index 54733b18..01ab7549 100644
--- a/tests/debug/gen.rs
+++ b/tests/debug/gen.rs
@@ -2057,6 +2057,12 @@ impl Debug for Lite<syn::Field> {
             formatter.field("attrs", Lite(&_val.attrs));
         }
         formatter.field("vis", Lite(&_val.vis));
+        match _val.mutability {
+            syn::FieldMutability::None => {}
+            _ => {
+                formatter.field("mutability", Lite(&_val.mutability));
+            }
+        }
         if let Some(val) = &_val.ident {
             #[derive(RefCast)]
             #[repr(transparent)]
@@ -2089,6 +2095,15 @@ impl Debug for Lite<syn::Field> {
         formatter.finish()
     }
 }
+impl Debug for Lite<syn::FieldMutability> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let _val = &self.value;
+        match _val {
+            syn::FieldMutability::None => formatter.write_str("FieldMutability::None"),
+            _ => unreachable!(),
+        }
+    }
+}
 impl Debug for Lite<syn::FieldPat> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;
@@ -2248,17 +2263,11 @@ impl Debug for Lite<syn::ForeignItem> {
                     formatter.field("attrs", Lite(&_val.attrs));
                 }
                 formatter.field("vis", Lite(&_val.vis));
-                if let Some(val) = &_val.mutability {
-                    #[derive(RefCast)]
-                    #[repr(transparent)]
-                    struct Print(syn::token::Mut);
-                    impl Debug for Print {
-                        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                            formatter.write_str("Some")?;
-                            Ok(())
-                        }
+                match _val.mutability {
+                    syn::StaticMutability::None => {}
+                    _ => {
+                        formatter.field("mutability", Lite(&_val.mutability));
                     }
-                    formatter.field("mutability", Print::ref_cast(val));
                 }
                 formatter.field("ident", Lite(&_val.ident));
                 formatter.field("ty", Lite(&_val.ty));
@@ -2347,17 +2356,11 @@ impl Debug for Lite<syn::ForeignItemStatic> {
             formatter.field("attrs", Lite(&_val.attrs));
         }
         formatter.field("vis", Lite(&_val.vis));
-        if let Some(val) = &_val.mutability {
-            #[derive(RefCast)]
-            #[repr(transparent)]
-            struct Print(syn::token::Mut);
-            impl Debug for Print {
-                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                    formatter.write_str("Some")?;
-                    Ok(())
-                }
+        match _val.mutability {
+            syn::StaticMutability::None => {}
+            _ => {
+                formatter.field("mutability", Lite(&_val.mutability));
             }
-            formatter.field("mutability", Print::ref_cast(val));
         }
         formatter.field("ident", Lite(&_val.ident));
         formatter.field("ty", Lite(&_val.ty));
@@ -2708,6 +2711,12 @@ impl Debug for Lite<syn::ImplItemType> {
         formatter.finish()
     }
 }
+impl Debug for Lite<syn::ImplRestriction> {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        let _val = &self.value;
+        unreachable!()
+    }
+}
 impl Debug for Lite<syn::Index> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;
@@ -2947,17 +2956,11 @@ impl Debug for Lite<syn::Item> {
                     formatter.field("attrs", Lite(&_val.attrs));
                 }
                 formatter.field("vis", Lite(&_val.vis));
-                if let Some(val) = &_val.mutability {
-                    #[derive(RefCast)]
-                    #[repr(transparent)]
-                    struct Print(syn::token::Mut);
-                    impl Debug for Print {
-                        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                            formatter.write_str("Some")?;
-                            Ok(())
-                        }
+                match _val.mutability {
+                    syn::StaticMutability::None => {}
+                    _ => {
+                        formatter.field("mutability", Lite(&_val.mutability));
                     }
-                    formatter.field("mutability", Print::ref_cast(val));
                 }
                 formatter.field("ident", Lite(&_val.ident));
                 formatter.field("ty", Lite(&_val.ty));
@@ -3017,6 +3020,22 @@ impl Debug for Lite<syn::Item> {
                     }
                     formatter.field("auto_token", Print::ref_cast(val));
                 }
+                if let Some(val) = &_val.restriction {
+                    #[derive(RefCast)]
+                    #[repr(transparent)]
+                    struct Print(syn::ImplRestriction);
+                    impl Debug for Print {
+                        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                            formatter.write_str("Some")?;
+                            let _val = &self.0;
+                            formatter.write_str("(")?;
+                            Debug::fmt(Lite(_val), formatter)?;
+                            formatter.write_str(")")?;
+                            Ok(())
+                        }
+                    }
+                    formatter.field("restriction", Print::ref_cast(val));
+                }
                 formatter.field("ident", Lite(&_val.ident));
                 formatter.field("generics", Lite(&_val.generics));
                 if let Some(val) = &_val.colon_token {
@@ -3359,17 +3378,11 @@ impl Debug for Lite<syn::ItemStatic> {
             formatter.field("attrs", Lite(&_val.attrs));
         }
         formatter.field("vis", Lite(&_val.vis));
-        if let Some(val) = &_val.mutability {
-            #[derive(RefCast)]
-            #[repr(transparent)]
-            struct Print(syn::token::Mut);
-            impl Debug for Print {
-                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-                    formatter.write_str("Some")?;
-                    Ok(())
-                }
+        match _val.mutability {
+            syn::StaticMutability::None => {}
+            _ => {
+                formatter.field("mutability", Lite(&_val.mutability));
             }
-            formatter.field("mutability", Print::ref_cast(val));
         }
         formatter.field("ident", Lite(&_val.ident));
         formatter.field("ty", Lite(&_val.ty));
@@ -3435,6 +3448,22 @@ impl Debug for Lite<syn::ItemTrait> {
             }
             formatter.field("auto_token", Print::ref_cast(val));
         }
+        if let Some(val) = &_val.restriction {
+            #[derive(RefCast)]
+            #[repr(transparent)]
+            struct Print(syn::ImplRestriction);
+            impl Debug for Print {
+                fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                    formatter.write_str("Some")?;
+                    let _val = &self.0;
+                    formatter.write_str("(")?;
+                    Debug::fmt(Lite(_val), formatter)?;
+                    formatter.write_str(")")?;
+                    Ok(())
+                }
+            }
+            formatter.field("restriction", Print::ref_cast(val));
+        }
         formatter.field("ident", Lite(&_val.ident));
         formatter.field("generics", Lite(&_val.generics));
         if let Some(val) = &_val.colon_token {
@@ -4594,6 +4623,19 @@ impl Debug for Lite<syn::Signature> {
         formatter.finish()
     }
 }
+impl Debug for Lite<syn::StaticMutability> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let _val = &self.value;
+        match _val {
+            syn::StaticMutability::Mut(_val) => {
+                formatter.write_str("StaticMutability::Mut")?;
+                Ok(())
+            }
+            syn::StaticMutability::None => formatter.write_str("StaticMutability::None"),
+            _ => unreachable!(),
+        }
+    }
+}
 impl Debug for Lite<syn::Stmt> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         let _val = &self.value;