From c6ce512015ed1ba84d413e57412981d40b70eba6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Sep 2021 19:13:01 -0700 Subject: [PATCH] Switch non exhaustive syntax tree enums to use #[non_exhaustive] This follows through on the comments on the __TestExhaustive variants promising that their purpose will be substituted with a deny(reachable) rustc lint once one is available. That lint is now landing as non_exhaustive_omitted_patterns in Rust 1.57. The correct way to use it for checking exhaustivity of a match is: match expr { Expr::Array(e) => {...} Expr::Assign(e) => {...} ... Expr::Yield(e) => {...} #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] _ => { /* some sane fallback */ } } --- build.rs | 4 ++ codegen/src/clone.rs | 10 ++++- codegen/src/debug.rs | 10 ++++- codegen/src/fold.rs | 5 ++- codegen/src/hash.rs | 10 ++++- codegen/src/visit.rs | 5 ++- codegen/src/visit_mut.rs | 5 ++- src/expr.rs | 25 +++++------- src/gen/clone.rs | 7 ++++ src/gen/debug.rs | 7 ++++ src/gen/fold.rs | 7 ++++ src/gen/hash.rs | 7 ++++ src/gen/visit.rs | 7 ++++ src/gen/visit_mut.rs | 7 ++++ src/item.rs | 84 +++++++++++++++------------------------- src/lib.rs | 3 -- src/macros.rs | 43 ++++++++++++-------- src/pat.rs | 17 ++++---- src/ty.rs | 17 ++++---- 19 files changed, 167 insertions(+), 113 deletions(-) diff --git a/build.rs b/build.rs index c705fc50fd..1a2c077bf0 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,10 @@ fn main() { println!("cargo:rustc-cfg=syn_no_const_vec_new"); } + if compiler.minor < 40 { + println!("cargo:rustc-cfg=syn_no_non_exhaustive"); + } + if compiler.minor < 56 { println!("cargo:rustc-cfg=syn_no_negative_literal_parse"); } diff --git a/codegen/src/clone.rs b/codegen/src/clone.rs index e5bcea1b81..7f6718ad04 100644 --- a/codegen/src/clone.rs +++ b/codegen/src/clone.rs @@ -42,8 +42,16 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream { }); let nonexhaustive = if node.exhaustive { None + } else if node.ident == "Expr" { + Some(quote! { + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] + _ => unreachable!(), + }) } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; quote! { match self { diff --git a/codegen/src/debug.rs b/codegen/src/debug.rs index 74c8412889..331421e672 100644 --- a/codegen/src/debug.rs +++ b/codegen/src/debug.rs @@ -42,8 +42,16 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream { }); let nonexhaustive = if node.exhaustive { None + } else if node.ident == "Expr" { + Some(quote! { + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] + _ => unreachable!(), + }) } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; quote! { match self { diff --git a/codegen/src/fold.rs b/codegen/src/fold.rs index 1da17c49dc..281c70df45 100644 --- a/codegen/src/fold.rs +++ b/codegen/src/fold.rs @@ -154,7 +154,10 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi let nonexhaustive = if s.exhaustive { None } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; fold_impl.extend(quote! { diff --git a/codegen/src/hash.rs b/codegen/src/hash.rs index 74ce152a3c..c378e9de0e 100644 --- a/codegen/src/hash.rs +++ b/codegen/src/hash.rs @@ -78,8 +78,16 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream { }); let nonexhaustive = if node.exhaustive { None + } else if node.ident == "Expr" { + Some(quote! { + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] + _ => unreachable!(), + }) } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; quote! { match self { diff --git a/codegen/src/visit.rs b/codegen/src/visit.rs index c78d9a45e3..9576d098be 100644 --- a/codegen/src/visit.rs +++ b/codegen/src/visit.rs @@ -166,7 +166,10 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi let nonexhaustive = if s.exhaustive { None } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; visit_impl.extend(quote! { diff --git a/codegen/src/visit_mut.rs b/codegen/src/visit_mut.rs index 5bd12ceab7..294d247f78 100644 --- a/codegen/src/visit_mut.rs +++ b/codegen/src/visit_mut.rs @@ -166,7 +166,10 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi let nonexhaustive = if s.exhaustive { None } else { - Some(quote!(_ => unreachable!())) + Some(quote! { + #[cfg(syn_no_non_exhaustive)] + _ => unreachable!(), + }) }; visit_mut_impl.extend(quote! { diff --git a/src/expr.rs b/src/expr.rs index 6de375d1af..b6d0616959 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -87,6 +87,7 @@ ast_enum_of_structs! { /// see names getting repeated in your code, like accessing /// `receiver.receiver` or `pat.pat` or `cond.cond`. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum Expr { /// A slice literal expression: `[a, b, c, d]`. Array(ExprArray), @@ -224,8 +225,9 @@ ast_enum_of_structs! { /// A yield expression: `yield expr`. Yield(ExprYield), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match expr { // Expr::Array(expr) => {...} @@ -233,9 +235,7 @@ ast_enum_of_structs! { // ... // Expr::Yield(expr) => {...} // - // #[cfg(test)] - // Expr::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -243,12 +243,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, Expr will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } @@ -838,9 +835,7 @@ impl Expr { | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), Expr::Verbatim(_) => Vec::new(), - #[cfg(test)] - Expr::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2510,9 +2505,7 @@ pub(crate) mod parsing { Pat::Verbatim(_) => {} Pat::Wild(pat) => pat.attrs = attrs, - #[cfg(test)] - Pat::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } Ok(pat) diff --git a/src/gen/clone.rs b/src/gen/clone.rs index 1c8814d679..8de1cd8c92 100644 --- a/src/gen/clone.rs +++ b/src/gen/clone.rs @@ -273,6 +273,7 @@ impl Clone for Expr { Expr::While(v0) => Expr::While(v0.clone()), #[cfg(feature = "full")] Expr::Yield(v0) => Expr::Yield(v0.clone()), + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] _ => unreachable!(), } } @@ -845,6 +846,7 @@ impl Clone for ForeignItem { ForeignItem::Type(v0) => ForeignItem::Type(v0.clone()), ForeignItem::Macro(v0) => ForeignItem::Macro(v0.clone()), ForeignItem::Verbatim(v0) => ForeignItem::Verbatim(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -957,6 +959,7 @@ impl Clone for ImplItem { ImplItem::Type(v0) => ImplItem::Type(v0.clone()), ImplItem::Macro(v0) => ImplItem::Macro(v0.clone()), ImplItem::Verbatim(v0) => ImplItem::Verbatim(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1052,6 +1055,7 @@ impl Clone for Item { Item::Union(v0) => Item::Union(v0.clone()), Item::Use(v0) => Item::Use(v0.clone()), Item::Verbatim(v0) => Item::Verbatim(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1474,6 +1478,7 @@ impl Clone for Pat { Pat::Type(v0) => Pat::Type(v0.clone()), Pat::Verbatim(v0) => Pat::Verbatim(v0.clone()), Pat::Wild(v0) => Pat::Wild(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1821,6 +1826,7 @@ impl Clone for TraitItem { TraitItem::Type(v0) => TraitItem::Type(v0.clone()), TraitItem::Macro(v0) => TraitItem::Macro(v0.clone()), TraitItem::Verbatim(v0) => TraitItem::Verbatim(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1899,6 +1905,7 @@ impl Clone for Type { Type::TraitObject(v0) => Type::TraitObject(v0.clone()), Type::Tuple(v0) => Type::Tuple(v0.clone()), Type::Verbatim(v0) => Type::Verbatim(v0.clone()), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/gen/debug.rs b/src/gen/debug.rs index 11e197eac2..4adf8c5936 100644 --- a/src/gen/debug.rs +++ b/src/gen/debug.rs @@ -587,6 +587,7 @@ impl Debug for Expr { formatter.field(v0); formatter.finish() } + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] _ => unreachable!(), } } @@ -1195,6 +1196,7 @@ impl Debug for ForeignItem { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1367,6 +1369,7 @@ impl Debug for ImplItem { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1530,6 +1533,7 @@ impl Debug for Item { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2088,6 +2092,7 @@ impl Debug for Pat { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2495,6 +2500,7 @@ impl Debug for TraitItem { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2633,6 +2639,7 @@ impl Debug for Type { formatter.field(v0); formatter.finish() } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/gen/fold.rs b/src/gen/fold.rs index 1e2cba4ad8..6e19e6f3a8 100644 --- a/src/gen/fold.rs +++ b/src/gen/fold.rs @@ -1130,6 +1130,7 @@ where Expr::Verbatim(_binding_0) => Expr::Verbatim(_binding_0), Expr::While(_binding_0) => Expr::While(full!(f.fold_expr_while(_binding_0))), Expr::Yield(_binding_0) => Expr::Yield(full!(f.fold_expr_yield(_binding_0))), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1715,6 +1716,7 @@ where ForeignItem::Macro(f.fold_foreign_item_macro(_binding_0)) } ForeignItem::Verbatim(_binding_0) => ForeignItem::Verbatim(_binding_0), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1868,6 +1870,7 @@ where ImplItem::Macro(f.fold_impl_item_macro(_binding_0)) } ImplItem::Verbatim(_binding_0) => ImplItem::Verbatim(_binding_0), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1972,6 +1975,7 @@ where Item::Union(_binding_0) => Item::Union(f.fold_item_union(_binding_0)), Item::Use(_binding_0) => Item::Use(f.fold_item_use(_binding_0)), Item::Verbatim(_binding_0) => Item::Verbatim(_binding_0), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2492,6 +2496,7 @@ where Pat::Type(_binding_0) => Pat::Type(f.fold_pat_type(_binding_0)), Pat::Verbatim(_binding_0) => Pat::Verbatim(_binding_0), Pat::Wild(_binding_0) => Pat::Wild(f.fold_pat_wild(_binding_0)), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2891,6 +2896,7 @@ where TraitItem::Macro(f.fold_trait_item_macro(_binding_0)) } TraitItem::Verbatim(_binding_0) => TraitItem::Verbatim(_binding_0), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2975,6 +2981,7 @@ where } Type::Tuple(_binding_0) => Type::Tuple(f.fold_type_tuple(_binding_0)), Type::Verbatim(_binding_0) => Type::Verbatim(_binding_0), + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/gen/hash.rs b/src/gen/hash.rs index 686ed86566..f68a7630e2 100644 --- a/src/gen/hash.rs +++ b/src/gen/hash.rs @@ -498,6 +498,7 @@ impl Hash for Expr { state.write_u8(39u8); v0.hash(state); } + #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] _ => unreachable!(), } } @@ -1112,6 +1113,7 @@ impl Hash for ForeignItem { state.write_u8(4u8); TokenStreamHelper(v0).hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1280,6 +1282,7 @@ impl Hash for ImplItem { state.write_u8(4u8); TokenStreamHelper(v0).hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1416,6 +1419,7 @@ impl Hash for Item { state.write_u8(16u8); TokenStreamHelper(v0).hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1920,6 +1924,7 @@ impl Hash for Pat { state.write_u8(15u8); v0.hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2339,6 +2344,7 @@ impl Hash for TraitItem { state.write_u8(4u8); TokenStreamHelper(v0).hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2464,6 +2470,7 @@ impl Hash for Type { state.write_u8(14u8); TokenStreamHelper(v0).hash(state); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/gen/visit.rs b/src/gen/visit.rs index fed46c9b5a..051b659368 100644 --- a/src/gen/visit.rs +++ b/src/gen/visit.rs @@ -1213,6 +1213,7 @@ where Expr::Yield(_binding_0) => { full!(v.visit_expr_yield(_binding_0)); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1901,6 +1902,7 @@ where ForeignItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2066,6 +2068,7 @@ where ImplItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2201,6 +2204,7 @@ where Item::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2800,6 +2804,7 @@ where Pat::Wild(_binding_0) => { v.visit_pat_wild(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -3255,6 +3260,7 @@ where TraitItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -3383,6 +3389,7 @@ where Type::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs index efb55eaecd..3ddbe9c067 100644 --- a/src/gen/visit_mut.rs +++ b/src/gen/visit_mut.rs @@ -1214,6 +1214,7 @@ where Expr::Yield(_binding_0) => { full!(v.visit_expr_yield_mut(_binding_0)); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -1902,6 +1903,7 @@ where ForeignItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2066,6 +2068,7 @@ where ImplItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2201,6 +2204,7 @@ where Item::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -2800,6 +2804,7 @@ where Pat::Wild(_binding_0) => { v.visit_pat_wild_mut(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -3255,6 +3260,7 @@ where TraitItem::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -3383,6 +3389,7 @@ where Type::Verbatim(_binding_0) => { skip!(_binding_0); } + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } diff --git a/src/item.rs b/src/item.rs index e9a8316a0b..1ce970ee2b 100644 --- a/src/item.rs +++ b/src/item.rs @@ -17,6 +17,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum Item { /// A constant item: `const MAX: u16 = 65535`. Const(ItemConst), @@ -71,8 +72,9 @@ ast_enum_of_structs! { /// Tokens forming an item not interpreted by Syn. Verbatim(TokenStream), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match item { // Item::Const(item) => {...} @@ -80,9 +82,7 @@ ast_enum_of_structs! { // ... // Item::Verbatim(item) => {...} // - // #[cfg(test)] - // Item::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -90,12 +90,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, Item will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } @@ -381,9 +378,7 @@ impl Item { | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), Item::Verbatim(_) => Vec::new(), - #[cfg(test)] - Item::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), } } @@ -564,6 +559,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum ForeignItem { /// A foreign function in an `extern` block. Fn(ForeignItemFn), @@ -580,8 +576,9 @@ ast_enum_of_structs! { /// Tokens in an `extern` block not interpreted by Syn. Verbatim(TokenStream), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match item { // ForeignItem::Fn(item) => {...} @@ -589,9 +586,7 @@ ast_enum_of_structs! { // ... // ForeignItem::Verbatim(item) => {...} // - // #[cfg(test)] - // ForeignItem::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -599,12 +594,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, ForeignItem will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } @@ -675,6 +667,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum TraitItem { /// An associated constant within the definition of a trait. Const(TraitItemConst), @@ -691,8 +684,9 @@ ast_enum_of_structs! { /// Tokens within the definition of a trait not interpreted by Syn. Verbatim(TokenStream), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match item { // TraitItem::Const(item) => {...} @@ -700,9 +694,7 @@ ast_enum_of_structs! { // ... // TraitItem::Verbatim(item) => {...} // - // #[cfg(test)] - // TraitItem::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -710,12 +702,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, TraitItem will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } @@ -788,6 +777,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum ImplItem { /// An associated constant within an impl block. Const(ImplItemConst), @@ -804,8 +794,9 @@ ast_enum_of_structs! { /// Tokens within an impl block not interpreted by Syn. Verbatim(TokenStream), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match item { // ImplItem::Const(item) => {...} @@ -813,9 +804,7 @@ ast_enum_of_structs! { // ... // ImplItem::Verbatim(item) => {...} // - // #[cfg(test)] - // ImplItem::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -823,12 +812,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, ImplItem will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } @@ -1828,9 +1814,7 @@ pub mod parsing { ForeignItem::Macro(item) => &mut item.attrs, ForeignItem::Verbatim(_) => return Ok(item), - #[cfg(test)] - ForeignItem::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), }; attrs.append(item_attrs); @@ -2264,9 +2248,7 @@ pub mod parsing { TraitItem::Macro(item) => &mut item.attrs, TraitItem::Verbatim(_) => unreachable!(), - #[cfg(test)] - TraitItem::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), }; attrs.append(item_attrs); @@ -2607,9 +2589,7 @@ pub mod parsing { ImplItem::Macro(item) => &mut item.attrs, ImplItem::Verbatim(_) => return Ok(item), - #[cfg(test)] - ImplItem::__TestExhaustive(_) => unimplemented!(), - #[cfg(not(test))] + #[cfg(syn_no_non_exhaustive)] _ => unreachable!(), }; attrs.append(item_attrs); diff --git a/src/lib.rs b/src/lib.rs index 84ae726a15..b7fb0c8c45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -829,9 +829,6 @@ mod verbatim; #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] mod print; -#[cfg(any(feature = "full", feature = "derive"))] -use crate::__private::private; - //////////////////////////////////////////////////////////////////////////////// // https://github.com/rust-lang/rust/issues/62830 diff --git a/src/macros.rs b/src/macros.rs index 5097da9481..939c601b40 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -76,7 +76,8 @@ macro_rules! ast_enum_of_structs_impl { ( $pub:ident $enum:ident $name:ident { $( - $(#[$variant_attr:meta])* + $(#[cfg $cfg_attr:tt])* + $(#[doc $($doc_attr:tt)*])* $variant:ident $( ($($member:ident)::+) )*, )* } @@ -95,7 +96,13 @@ macro_rules! ast_enum_of_structs_impl { $($remaining)* () tokens - $name { $($variant $($($member)::+)*,)* } + $name { + $( + $(#[cfg $cfg_attr])* + $(#[doc $($doc_attr)*])* + $variant $($($member)::+)*, + )* + } } }; } @@ -104,9 +111,6 @@ macro_rules! ast_enum_from_struct { // No From for verbatim variants. ($name:ident::Verbatim, $member:ident) => {}; - // No From for private variants. - ($name:ident::$variant:ident, crate::private) => {}; - ($name:ident::$variant:ident, $member:ident) => { impl From<$member> for $name { fn from(e: $member) -> $name { @@ -120,23 +124,30 @@ macro_rules! ast_enum_from_struct { macro_rules! generate_to_tokens { (do_not_generate_to_tokens $($foo:tt)*) => (); - (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => { - generate_to_tokens!( - ($($arms)* $name::$variant => {}) - $tokens $name { $($next)* } - ); - }; - - (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => { + ( + ($($arms:tt)*) $tokens:ident $name:ident { + $(#[cfg $cfg_attr:tt])* + $(#[doc $($doc_attr:tt)*])* + $variant:ident, + $($next:tt)* + } + ) => { generate_to_tokens!( - ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),) + ($($arms)* $(#[cfg $cfg_attr])* $name::$variant => {}) $tokens $name { $($next)* } ); }; - (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident crate::private, $($next:tt)*}) => { + ( + ($($arms:tt)*) $tokens:ident $name:ident { + $(#[cfg $cfg_attr:tt])* + $(#[doc $($doc_attr:tt)*])* + $variant:ident $member:ident, + $($next:tt)* + } + ) => { generate_to_tokens!( - ($($arms)* $name::$variant(_) => unreachable!(),) + ($($arms)* $(#[cfg $cfg_attr])* $name::$variant(_e) => _e.to_tokens($tokens),) $tokens $name { $($next)* } ); }; diff --git a/src/pat.rs b/src/pat.rs index 999434e549..630bf9d9ee 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -14,6 +14,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum Pat { /// A box pattern: `box v`. Box(PatBox), @@ -72,8 +73,9 @@ ast_enum_of_structs! { /// A pattern that matches any value: `_`. Wild(PatWild), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match pat { // Pat::Box(pat) => {...} @@ -81,9 +83,7 @@ ast_enum_of_structs! { // ... // Pat::Wild(pat) => {...} // - // #[cfg(test)] - // Pat::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -91,12 +91,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, Pat will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } } diff --git a/src/ty.rs b/src/ty.rs index d5236d10da..8249d997ef 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -14,6 +14,7 @@ ast_enum_of_structs! { /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] + #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] pub enum Type { /// A fixed size array type: `[T; n]`. Array(TypeArray), @@ -63,8 +64,9 @@ ast_enum_of_structs! { /// Tokens in type position not interpreted by Syn. Verbatim(TokenStream), - // The following is the only supported idiom for exhaustive matching of - // this enum. + // Not public API. + // + // For testing exhaustiveness in downstream code, use the following idiom: // // match ty { // Type::Array(ty) => {...} @@ -72,9 +74,7 @@ ast_enum_of_structs! { // ... // Type::Verbatim(ty) => {...} // - // #[cfg(test)] - // Type::__TestExhaustive(_) => unimplemented!(), - // #[cfg(not(test))] + // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* some sane fallback */ } // } // @@ -82,12 +82,9 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - // - // Once `deny(reachable)` is available in rustc, Type will be - // reimplemented as a non_exhaustive enum. - // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 + #[cfg(syn_no_non_exhaustive)] #[doc(hidden)] - __TestExhaustive(crate::private), + __NonExhaustive, } }