From 59ee333a0e952eb7b91d86447b489aa12efd0bd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 11 Apr 2018 13:19:10 +0100 Subject: Fix derive(PartialOrd) implementation --- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 92183c58eb2..2f66616d73f 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -214,14 +214,18 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), }; - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); + let strict_ineq = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - let not_cmp = cx.expr_unary(span, - ast::UnOp::Not, - cx.expr_binary(span, op, other_f.clone(), self_f)); + let deleg_cmp = if !equal { + cx.expr_unary(span, + ast::UnOp::Not, + cx.expr_binary(span, op, other_f.clone(), self_f)) + } else { + cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()) + }; - let and = cx.expr_binary(span, BinOpKind::And, not_cmp, subexpr); - cx.expr_binary(span, BinOpKind::Or, cmp, and) + let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr); + cx.expr_binary(span, BinOpKind::Or, strict_ineq, and) }, cx.expr_bool(span, equal), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { -- cgit 1.4.1-3-g733a5 From 44efb05edfcba3baf7a3abcf10085c7647a909ad Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 11 Apr 2018 15:16:54 +0100 Subject: Add cs_fold1 for better derives --- src/libsyntax_ext/deriving/generic/mod.rs | 109 +++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 17 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 4126ce79f35..11bd72691c5 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1676,12 +1676,55 @@ impl<'a> TraitDef<'a> { // helpful premade recipes +pub fn cs_fold_fields<'a, F>(use_foldl: bool, + mut f: F, + base: P, + cx: &mut ExtCtxt, + all_fields: &[FieldInfo<'a>]) + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P +{ + if use_foldl { + all_fields.iter().fold(base, |old, field| { + f(cx, field.span, old, field.self_.clone(), &field.other) + }) + } else { + all_fields.iter().rev().fold(base, |old, field| { + f(cx, field.span, old, field.self_.clone(), &field.other) + }) + } +} + +pub fn cs_fold_enumnonmatch(mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> P +{ + match *substructure.fields { + EnumNonMatchingCollapsed(ref all_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_args[..], tuple), + substructure.nonself_args) + } + _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed") + } +} + +pub fn cs_fold_static(cx: &mut ExtCtxt, + trait_span: Span) + -> P +{ + cx.span_bug(trait_span, "static function in `derive`") +} + /// Fold the fields. `use_foldl` controls whether this is done /// left-to-right (`true`) or right-to-left (`false`). pub fn cs_fold(use_foldl: bool, - mut f: F, + f: F, base: P, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, + enum_nonmatch_f: EnumNonMatchCollapsedFunc, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) @@ -1691,26 +1734,58 @@ pub fn cs_fold(use_foldl: bool, match *substructure.fields { EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - if use_foldl { - all_fields.iter().fold(base, |old, field| { - f(cx, field.span, old, field.self_.clone(), &field.other) - }) - } else { - all_fields.iter().rev().fold(base, |old, field| { - f(cx, field.span, old, field.self_.clone(), &field.other) - }) - } + cs_fold_fields(use_foldl, f, base, cx, all_fields) } - EnumNonMatchingCollapsed(ref all_args, _, tuple) => { - enum_nonmatch_f(cx, - trait_span, - (&all_args[..], tuple), - substructure.nonself_args) + EnumNonMatchingCollapsed(..) => { + cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) + } + StaticEnum(..) | StaticStruct(..) => { + cs_fold_static(cx, trait_span) } - StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } +/// Special version of `cs_fold` that uses the result of a function call on the first field +/// as the base case when is at least 1 field, and the usual base case when there are zero fields. +pub fn cs_fold1(use_foldl: bool, + f: F, + mut b: B, + enum_nonmatch_f: EnumNonMatchCollapsedFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, + B: FnMut(&mut ExtCtxt, Option<(Span, P, &[P])>) -> P +{ + match *substructure.fields { + EnumMatching(.., ref all_fields) | + Struct(_, ref all_fields) => { + let (base, all_fields) = match (all_fields.is_empty(), use_foldl) { + (false, true) => { + let field = &all_fields[0]; + let args = (field.span, field.self_.clone(), &field.other[..]); + (b(cx, Some(args)), &all_fields[1..]) + } + (false, false) => { + let idx = all_fields.len() - 1; + let field = &all_fields[idx]; + let args = (field.span, field.self_.clone(), &field.other[..]); + (b(cx, Some(args)), &all_fields[..idx]) + } + (true, _) => (b(cx, None), &all_fields[..]) + }; + + cs_fold_fields(use_foldl, f, base, cx, all_fields) + } + EnumNonMatchingCollapsed(..) => { + cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) + } + StaticEnum(..) | StaticStruct(..) => { + cs_fold_static(cx, trait_span) + } + } +} /// Call the method that is being derived on all the fields, and then /// process the collected results. i.e. -- cgit 1.4.1-3-g733a5 From 3238e0d098cfd798a8828ec053cf37836c6c927d Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 11 Apr 2018 15:54:27 +0100 Subject: Optimise the last field operations in derive[PartialOrd] --- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 123 +++++++++++++++----------- 1 file changed, 72 insertions(+), 51 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 2f66616d73f..605e8a2e6cd 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -190,58 +190,79 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< /// Strict inequality. fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - let op = if less { BinOpKind::Lt } else { BinOpKind::Gt }; - cs_fold(false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - // build up a series of chain ||'s and &&'s from the inside - // out (hence foldr) to get lexical ordering, i.e. for op == - // `ast::lt` - // - // ``` - // self.f1 < other.f1 || (!(other.f1 < self.f1) && - // (self.f2 < other.f2 || (!(other.f2 < self.f2) && - // (false) - // )) - // ) - // ``` - // - // The optimiser should remove the redundancy. We explicitly - // get use the binops to avoid auto-deref dereferencing too many - // layers of pointers, if the type includes pointers. - // - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let strict_ineq = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); + let strict_op = if less { BinOpKind::Lt } else { BinOpKind::Gt }; + cs_fold1(false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + // build up a series of chain ||'s and &&'s from the inside + // out (hence foldr) to get lexical ordering, i.e. for op == + // `ast::lt` + // + // ``` + // self.f1 < other.f1 || (!(other.f1 < self.f1) && + // (self.f2 < other.f2 || (!(other.f2 < self.f2) && + // (false) + // )) + // ) + // ``` + // + // The optimiser should remove the redundancy. We explicitly + // get use the binops to avoid auto-deref dereferencing too many + // layers of pointers, if the type includes pointers. + // + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; - let deleg_cmp = if !equal { - cx.expr_unary(span, - ast::UnOp::Not, - cx.expr_binary(span, op, other_f.clone(), self_f)) - } else { - cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()) - }; + let strict_ineq = cx.expr_binary(span, strict_op, self_f.clone(), other_f.clone()); - let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr); - cx.expr_binary(span, BinOpKind::Or, strict_ineq, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, - (true, false) => LtOp, - (false, true) => GeOp, - (false, false) => GtOp, + let deleg_cmp = if !equal { + cx.expr_unary(span, + ast::UnOp::Not, + cx.expr_binary(span, strict_op, other_f.clone(), self_f)) + } else { + cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()) }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, - span, - substr) + + let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr); + cx.expr_binary(span, BinOpKind::Or, strict_ineq, and) + }, + |cx, args| { + match args { + Some((span, self_f, other_fs)) => { + // Special-case the base case to generate cleaner code with + // fewer operations (e.g. `<=` instead of `<` and `==`). + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; + + let op = match (less, equal) { + (false, false) => BinOpKind::Gt, + (false, true) => BinOpKind::Ge, + (true, false) => BinOpKind::Lt, + (true, true) => BinOpKind::Le, + }; + + cx.expr_binary(span, op, self_f, other_f.clone()) + } + None => cx.expr_bool(span, equal) + } + }, + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + let op = match (less, equal) { + (false, false) => GtOp, + (false, true) => GeOp, + (true, false) => LtOp, + (true, true) => LeOp, + }; + some_ordering_collapsed(cx, span, op, tag_tuple) + } + }), + cx, + span, + substr) } -- cgit 1.4.1-3-g733a5 From 1ce06d09328c17a59cb8b02d12811d694b89662e Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 11 Apr 2018 16:06:56 +0100 Subject: Remove redundant operation in derive[PartialEq] --- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 86 +++++++++++++++++++--------- 1 file changed, 58 insertions(+), 28 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 75db7cc1e4c..f62140aa65f 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -27,40 +27,70 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold(true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), - }; + cs_fold1(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, - span, - substr) + cx.expr_binary(span, BinOpKind::And, subexpr, eq) + }, + |cx, args| { + match args { + Some((span, self_f, other_fs)) => { + // Special-case the base case to generate cleaner code. + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") + } + }; + + cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()) + } + None => cx.expr_bool(span, true), + } + }, + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, + span, + substr) } fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold(true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), - }; + cs_fold1(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; + + let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); - let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); + cx.expr_binary(span, BinOpKind::Or, subexpr, eq) + }, + |cx, args| { + match args { + Some((span, self_f, other_fs)) => { + // Special-case the base case to generate cleaner code. + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") + } + }; - cx.expr_binary(span, BinOpKind::Or, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, - span, - substr) + cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()) + } + None => cx.expr_bool(span, false), + } + }, + Box::new(|cx, span, _, _| cx.expr_bool(span, true)), + cx, + span, + substr) } macro_rules! md { -- cgit 1.4.1-3-g733a5 From 88a9c691212996b9dd8921c597182b137bb1771a Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 00:51:08 +0100 Subject: Update partial_ord codegen summary --- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 605e8a2e6cd..9560fd0570a 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -199,9 +199,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru // // ``` // self.f1 < other.f1 || (!(other.f1 < self.f1) && - // (self.f2 < other.f2 || (!(other.f2 < self.f2) && - // (false) - // )) + // self.f2 < other.f2 + // ) + // ``` + // + // and for op == + // `ast::le` + // + // ``` + // self.f1 < other.f1 || (self.f1 == other.f1 && + // self.f2 <= other.f2 // ) // ``` // -- cgit 1.4.1-3-g733a5 From 60dc4f8ec8729bd851b8ee8e3dac9abae1f62bef Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 01:33:52 +0100 Subject: Improve the comment for cs_fold1 --- src/libsyntax_ext/deriving/generic/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 11bd72691c5..82ed6a29b77 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1745,8 +1745,15 @@ pub fn cs_fold(use_foldl: bool, } } -/// Special version of `cs_fold` that uses the result of a function call on the first field -/// as the base case when is at least 1 field, and the usual base case when there are zero fields. +/// Function to fold over fields, with three cases, to generate more efficient and concise code. +/// When the `substructure` has grouped fields, there are two cases: +/// Zero fields: call the base case function with None (like the usual base case of `cs_fold`). +/// One or more fields: call the base case function on the first value (which depends on +/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the +/// fields. +/// When the `substructure` is a `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f` +/// is returned. Statics may not be folded over. +/// See `cs_op` in `partial_ord.rs` for a model example. pub fn cs_fold1(use_foldl: bool, f: F, mut b: B, -- cgit 1.4.1-3-g733a5 From 105c5180941f4034fd0d576a1d4c1bb71dd8e077 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 01:35:14 +0100 Subject: Abstract cs_eq for partial_eq --- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 77 ++++++++++------------------ 1 file changed, 27 insertions(+), 50 deletions(-) (limited to 'src/libsyntax_ext') diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index f62140aa65f..81ca7e73228 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -26,73 +26,50 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, push: &mut FnMut(Annotatable)) { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold1(true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), - }; + fn cs_op(cx: &mut ExtCtxt, + span: Span, + substr: &Substructure, + op: BinOpKind, + combiner: BinOpKind, + base: bool) + -> P + { + let op = |cx: &mut ExtCtxt, span: Span, self_f: P, other_fs: &[P]| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + cx.expr_binary(span, op, self_f, other_f.clone()) + }; - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - |cx, args| { - match args { - Some((span, self_f, other_fs)) => { - // Special-case the base case to generate cleaner code. - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - } - }; - - cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()) - } - None => cx.expr_bool(span, true), - } - }, - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, - span, - substr) - } - fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { cs_fold1(true, // use foldl |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), - }; - - let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); - - cx.expr_binary(span, BinOpKind::Or, subexpr, eq) + let eq = op(cx, span, self_f, other_fs); + cx.expr_binary(span, combiner, subexpr, eq) }, |cx, args| { match args { Some((span, self_f, other_fs)) => { // Special-case the base case to generate cleaner code. - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - } - }; - - cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()) + op(cx, span, self_f, other_fs) } - None => cx.expr_bool(span, false), + None => cx.expr_bool(span, base), } }, - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), + Box::new(|cx, span, _, _| cx.expr_bool(span, !base)), cx, span, substr) } + fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true) + } + fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false) + } + macro_rules! md { ($name:expr, $f:ident) => { { let inline = cx.meta_word(span, Symbol::intern("inline")); -- cgit 1.4.1-3-g733a5