From 6eb4f0f7fd44026a2353a620dee39d379a8e4a29 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 16 Apr 2018 23:32:28 +0100 Subject: [PATCH 01/26] Ensure derive(PartialOrd) is no longer accidentally exponential Previously, two comparison operations would be generated for each field, each of which could delegate to another derived PartialOrd. Now we use ordering and optional chaining to ensure each pair of fields is only compared once. --- src/etc/generate-deriving-span-tests.py | 2 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 153 ++++++++++-------- ...ves-span-PartialOrd-enum-struct-variant.rs | 3 - .../derives-span-PartialOrd-enum.rs | 3 - .../derives-span-PartialOrd-struct.rs | 3 - .../derives-span-PartialOrd-tuple-struct.rs | 3 - src/test/compile-fail/range_traits-1.rs | 20 +-- 7 files changed, 90 insertions(+), 97 deletions(-) diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index edb9389c00c5..e248f471395a 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -122,7 +122,7 @@ traits = { for (trait, supers, errs) in [('Clone', [], 1), ('PartialEq', [], 2), - ('PartialOrd', ['PartialEq'], 5), + ('PartialOrd', ['PartialEq'], 2), ('Eq', ['PartialEq'], 1), ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1), ('Debug', [], 1), diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index d71527fd0ed0..b352e4b0a7eb 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -14,7 +14,7 @@ use deriving::{path_local, pathvec_std, path_std}; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{self, BinOpKind, Expr, MetaItem}; +use syntax::ast::{self, BinOpKind, Expr, MetaItem, Ident}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; @@ -147,34 +147,37 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< // as the outermost one, and the last as the innermost. false, |cx, span, old, self_f, other_fs| { - // match new { - // Some(::std::cmp::Ordering::Equal) => old, - // cmp => cmp - // } + // match new { + // Some(::std::cmp::Ordering::Equal) => old, + // cmp => cmp + // } - let new = { - 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 new = { + 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 args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; + let args = vec![ + cx.expr_addr_of(span, self_f), + cx.expr_addr_of(span, other_f.clone()), + ]; - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; + cx.expr_call_global(span, partial_cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], - old); - let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], - cx.expr_ident(span, test_id)); + let eq_arm = cx.arm(span, + vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, + cx.expr_match(span, new, vec![eq_arm, neq_arm]) + }, equals_expr.clone(), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { @@ -189,78 +192,77 @@ 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 strict_op = if less { BinOpKind::Lt } else { BinOpKind::Gt }; - cs_fold1(false, // need foldr, +fn cs_op(less: bool, + inclusive: bool, + cx: &mut ExtCtxt, + span: Span, + substr: &Substructure) -> P { + let ordering_path = |cx: &mut ExtCtxt, name: &str| { + cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", "Ordering", name]))) + }; + + let par_cmp = |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(PartialOrd)`"), + }; + + // `self.fi.partial_cmp(other.fi)` + let cmp = cx.expr_method_call(span, + cx.expr_addr_of(span, self_f), + Ident::from_str("partial_cmp"), + vec![cx.expr_addr_of(span, other_f.clone())]); + + let default = ordering_path(cx, if less { "Greater" } else { "Less" }); + // `_.unwrap_or(Ordering::Greater/Less)` + cx.expr_method_call(span, cmp, Ident::from_str("unwrap_or"), vec![default]) + }; + + let fold = cs_fold1(false, // need foldr |cx, span, subexpr, self_f, other_fs| { - // build up a series of chain ||'s and &&'s from the inside + // build up a series of `partial_cmp`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 - // ) + // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Greater) + // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Greater)) + // == Ordering::Less // ``` // // and for op == // `ast::le` // // ``` - // self.f1 < other.f1 || (self.f1 == other.f1 && - // self.f2 <= other.f2 - // ) + // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Greater) + // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Greater)) + // != Ordering::Greater // ``` // // 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, strict_op, self_f.clone(), other_f.clone()); + // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less)` + let par_cmp = par_cmp(cx, span, self_f, other_fs); - 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()) - }; - - let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr); - cx.expr_binary(span, BinOpKind::Or, strict_ineq, and) + // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less).then_with(...)` + cx.expr_method_call(span, + par_cmp, + Ident::from_str("then_with"), + vec![cx.lambda0(span, subexpr)]) }, |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) + Some((span, self_f, other_fs)) => par_cmp(cx, span, self_f, other_fs), + None => ordering_path(cx, if less { "Less" } else { "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) { + let op = match (less, inclusive) { (false, false) => GtOp, (false, true) => GeOp, (true, false) => LtOp, @@ -271,5 +273,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru }), cx, span, - substr) + substr); + + match *substr.fields { + EnumMatching(..) | + Struct(..) => { + let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" }); + let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq }; + + cx.expr_binary(span, comp_op, fold, ordering) + } + _ => fold + } } diff --git a/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs b/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs index dcf02f308307..37e638c05533 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs @@ -18,9 +18,6 @@ enum Enum { A { x: Error //~ ERROR //~^ ERROR -//~^^ ERROR -//~^^^ ERROR -//~^^^^ ERROR } } diff --git a/src/test/compile-fail/derives-span-PartialOrd-enum.rs b/src/test/compile-fail/derives-span-PartialOrd-enum.rs index 7eb44c7e19e8..da1281fc1c10 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-enum.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-enum.rs @@ -18,9 +18,6 @@ enum Enum { A( Error //~ ERROR //~^ ERROR -//~^^ ERROR -//~^^^ ERROR -//~^^^^ ERROR ) } diff --git a/src/test/compile-fail/derives-span-PartialOrd-struct.rs b/src/test/compile-fail/derives-span-PartialOrd-struct.rs index 36dae0124ce9..fcc0593ab5e4 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-struct.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-struct.rs @@ -17,9 +17,6 @@ struct Error; struct Struct { x: Error //~ ERROR //~^ ERROR -//~^^ ERROR -//~^^^ ERROR -//~^^^^ ERROR } fn main() {} diff --git a/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs b/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs index fd2df0967545..24f75213e3f7 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs @@ -17,9 +17,6 @@ struct Error; struct Struct( Error //~ ERROR //~^ ERROR -//~^^ ERROR -//~^^^ ERROR -//~^^^^ ERROR ); fn main() {} diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index df766e361d5b..434ad3c4f079 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -15,35 +15,27 @@ struct AllTheRanges { a: Range, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type + //~^^^ the trait bound b: RangeTo, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type + //~^^^ no method named `partial_cmp` c: RangeFrom, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type + //~^^^ the trait bound d: RangeFull, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type + //~^^^ no method named `partial_cmp` e: RangeInclusive, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type + //~^^^ the trait bound f: RangeToInclusive, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ ERROR binary operation `<` cannot be applied to type - //~^^^^ ERROR binary operation `>` cannot be applied to type - //~^^^^^ ERROR binary operation `<=` cannot be applied to type - //~^^^^^^ ERROR binary operation `>=` cannot be applied to type + //~^^^ no method named `partial_cmp` } fn main() {} From 6330bf24fe2641cec2045fdfaab439f96c35652a Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 17 Apr 2018 01:22:43 +0100 Subject: [PATCH 02/26] Fix handling of None --- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index b352e4b0a7eb..b6f36582f3c7 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -213,8 +213,8 @@ fn cs_op(less: bool, Ident::from_str("partial_cmp"), vec![cx.expr_addr_of(span, other_f.clone())]); - let default = ordering_path(cx, if less { "Greater" } else { "Less" }); - // `_.unwrap_or(Ordering::Greater/Less)` + let default = ordering_path(cx, "Equal"); + // `_.unwrap_or(Ordering::Equal)` cx.expr_method_call(span, cmp, Ident::from_str("unwrap_or"), vec![default]) }; @@ -225,8 +225,8 @@ fn cs_op(less: bool, // `ast::lt` // // ``` - // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Greater) - // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Greater)) + // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Equal) + // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Equal)) // == Ordering::Less // ``` // @@ -234,8 +234,8 @@ fn cs_op(less: bool, // `ast::le` // // ``` - // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Greater) - // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Greater)) + // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Equal) + // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Equal)) // != Ordering::Greater // ``` // @@ -243,10 +243,10 @@ fn cs_op(less: bool, // get use the binops to avoid auto-deref dereferencing too many // layers of pointers, if the type includes pointers. - // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less)` + // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal)` let par_cmp = par_cmp(cx, span, self_f, other_fs); - // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less).then_with(...)` + // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal).then_with(...)` cx.expr_method_call(span, par_cmp, Ident::from_str("then_with"), @@ -255,7 +255,7 @@ fn cs_op(less: bool, |cx, args| { match args { Some((span, self_f, other_fs)) => par_cmp(cx, span, self_f, other_fs), - None => ordering_path(cx, if less { "Less" } else { "Equal" }) + None => cx.expr_bool(span, inclusive) } }, Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { @@ -276,8 +276,8 @@ fn cs_op(less: bool, substr); match *substr.fields { - EnumMatching(..) | - Struct(..) => { + EnumMatching(.., ref all_fields) | + Struct(.., ref all_fields) if !all_fields.is_empty() => { let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" }); let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq }; From 98e3e82ecea8b3b2100362e6fa87dc76779855bc Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 17 Apr 2018 19:52:58 +0100 Subject: [PATCH 03/26] Use UFCS --- src/etc/generate-deriving-span-tests.py | 2 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 31 ++++++++++++------- ...ves-span-PartialOrd-enum-struct-variant.rs | 1 - .../derives-span-PartialOrd-enum.rs | 1 - .../derives-span-PartialOrd-struct.rs | 1 - .../derives-span-PartialOrd-tuple-struct.rs | 1 - src/test/compile-fail/range_traits-1.rs | 6 ---- 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index e248f471395a..2e9169ce5b94 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -122,7 +122,7 @@ traits = { for (trait, supers, errs) in [('Clone', [], 1), ('PartialEq', [], 2), - ('PartialOrd', ['PartialEq'], 2), + ('PartialOrd', ['PartialEq'], 1), ('Eq', ['PartialEq'], 1), ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1), ('Debug', [], 1), diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index b6f36582f3c7..f8c27bf42a94 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -201,21 +201,27 @@ fn cs_op(less: bool, cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", "Ordering", name]))) }; - let par_cmp = |cx: &mut ExtCtxt, span: Span, self_f: P, other_fs: &[P]| { + let par_cmp = |cx: &mut ExtCtxt, span, self_f: P, other_fs: &[P], default| { 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)`"), }; - // `self.fi.partial_cmp(other.fi)` - let cmp = cx.expr_method_call(span, - cx.expr_addr_of(span, self_f), - Ident::from_str("partial_cmp"), - vec![cx.expr_addr_of(span, other_f.clone())]); + // `PartialOrd::partial_cmp(self.fi, other.fi)` + let cmp_path = cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", + "PartialOrd", + "partial_cmp"]))); + let cmp = cx.expr_call(span, + cmp_path, + vec![cx.expr_addr_of(span, self_f), + cx.expr_addr_of(span, other_f.clone())]); - let default = ordering_path(cx, "Equal"); - // `_.unwrap_or(Ordering::Equal)` - cx.expr_method_call(span, cmp, Ident::from_str("unwrap_or"), vec![default]) + let default = ordering_path(cx, default); + // `Option::unwrap_or(_, Ordering::Equal)` + let unwrap_path = cx.expr_path(cx.path_global(span, cx.std_path(&["option", + "Option", + "unwrap_or"]))); + cx.expr_call(span, unwrap_path, vec![cmp, default]) }; let fold = cs_fold1(false, // need foldr @@ -244,7 +250,7 @@ fn cs_op(less: bool, // layers of pointers, if the type includes pointers. // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal)` - let par_cmp = par_cmp(cx, span, self_f, other_fs); + let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal"); // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal).then_with(...)` cx.expr_method_call(span, @@ -254,7 +260,10 @@ fn cs_op(less: bool, }, |cx, args| { match args { - Some((span, self_f, other_fs)) => par_cmp(cx, span, self_f, other_fs), + Some((span, self_f, other_fs)) => { + let opposite = if less { "Greater" } else { "Less" }; + par_cmp(cx, span, self_f, other_fs, opposite) + }, None => cx.expr_bool(span, inclusive) } }, diff --git a/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs b/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs index 37e638c05533..a5df717e06ba 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-enum-struct-variant.rs @@ -17,7 +17,6 @@ struct Error; enum Enum { A { x: Error //~ ERROR -//~^ ERROR } } diff --git a/src/test/compile-fail/derives-span-PartialOrd-enum.rs b/src/test/compile-fail/derives-span-PartialOrd-enum.rs index da1281fc1c10..3411d2f3119e 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-enum.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-enum.rs @@ -17,7 +17,6 @@ struct Error; enum Enum { A( Error //~ ERROR -//~^ ERROR ) } diff --git a/src/test/compile-fail/derives-span-PartialOrd-struct.rs b/src/test/compile-fail/derives-span-PartialOrd-struct.rs index fcc0593ab5e4..1feadc2fd83b 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-struct.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-struct.rs @@ -16,7 +16,6 @@ struct Error; #[derive(PartialOrd,PartialEq)] struct Struct { x: Error //~ ERROR -//~^ ERROR } fn main() {} diff --git a/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs b/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs index 24f75213e3f7..9db0fed2d9e9 100644 --- a/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs +++ b/src/test/compile-fail/derives-span-PartialOrd-tuple-struct.rs @@ -16,7 +16,6 @@ struct Error; #[derive(PartialOrd,PartialEq)] struct Struct( Error //~ ERROR -//~^ ERROR ); fn main() {} diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index 434ad3c4f079..32f9b83b6e2c 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -15,27 +15,21 @@ struct AllTheRanges { a: Range, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ the trait bound b: RangeTo, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ no method named `partial_cmp` c: RangeFrom, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ the trait bound d: RangeFull, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ no method named `partial_cmp` e: RangeInclusive, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ the trait bound f: RangeToInclusive, //~^ ERROR PartialOrd //~^^ ERROR Ord - //~^^^ no method named `partial_cmp` } fn main() {} From 6805e5abd2a6fbdca75ff3c96ee58398dcbdfd04 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Apr 2018 21:56:57 +0100 Subject: [PATCH 04/26] Update comments to UFCS style --- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index f8c27bf42a94..2b3930063f36 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -14,7 +14,7 @@ use deriving::{path_local, pathvec_std, path_std}; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{self, BinOpKind, Expr, MetaItem, Ident}; +use syntax::ast::{self, BinOpKind, Expr, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; @@ -231,8 +231,14 @@ fn cs_op(less: bool, // `ast::lt` // // ``` - // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Equal) - // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Equal)) + // Ordering::then_with( + // Option::unwrap_or( + // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal) + // ), + // Option::unwrap_or( + // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater) + // ) + // ) // == Ordering::Less // ``` // @@ -240,8 +246,14 @@ fn cs_op(less: bool, // `ast::le` // // ``` - // self.f1.partial_cmp(other.f1).unwrap_or(Ordering::Equal) - // .then_with(|| self.f2.partial_cmp(other.f2).unwrap_or(Ordering::Equal)) + // Ordering::then_with( + // Option::unwrap_or( + // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal) + // ), + // Option::unwrap_or( + // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater) + // ) + // ) // != Ordering::Greater // ``` // @@ -249,14 +261,15 @@ fn cs_op(less: bool, // get use the binops to avoid auto-deref dereferencing too many // layers of pointers, if the type includes pointers. - // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal)` + // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)` let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal"); - // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Equal).then_with(...)` - cx.expr_method_call(span, - par_cmp, - Ident::from_str("then_with"), - vec![cx.lambda0(span, subexpr)]) + // `Ordering::then_with(Option::unwrap_or(..), ..)` + let then_with_path = cx.expr_path(cx.path_global(span, + cx.std_path(&["cmp", + "Ordering", + "then_with"]))); + cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)]) }, |cx, args| { match args { From 9b2890196eba62fdfec09447305e197642d1c612 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 30 Apr 2018 22:43:33 +0100 Subject: [PATCH 05/26] Remove vestigial diverging !-coercion Such conversions are no longer permitted. --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 24 +++++--------------- src/librustc_typeck/check/mod.rs | 32 +++++++++------------------ 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7b4dc60409b1..6a76e170a625 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -690,7 +690,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); arm_span: arm.body.span, source: match_src }); - coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get()); + coercion.coerce(self, &cause, &arm.body, arm_ty); } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8c69608a2617..770a44a9b8b8 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::{Diverges, FnCtxt, Needs}; +use check::{FnCtxt, Needs}; use rustc::hir; use rustc::hir::def_id::DefId; @@ -798,8 +798,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { exprs: &[E], prev_ty: Ty<'tcx>, new: &hir::Expr, - new_ty: Ty<'tcx>, - new_diverges: Diverges) + new_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> where E: AsCoercionSite { @@ -807,13 +806,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); - // Special-ish case: we can coerce any type `T` into the `!` - // type, but only if the source expression diverges. - if prev_ty.is_never() && new_diverges.always() { - debug!("permit coercion to `!` because expr diverges"); - return Ok(prev_ty); - } - // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) { @@ -1052,14 +1044,12 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: &'gcx hir::Expr, - expression_ty: Ty<'tcx>, - expression_diverges: Diverges) + expression_ty: Ty<'tcx>) { self.coerce_inner(fcx, cause, Some(expression), expression_ty, - expression_diverges, None, false) } @@ -1085,7 +1075,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause, None, fcx.tcx.mk_nil(), - Diverges::Maybe, Some(augment_error), label_unit_as_expected) } @@ -1098,7 +1087,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, mut expression_ty: Ty<'tcx>, - expression_diverges: Diverges, augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>, label_expression_as_expected: bool) { @@ -1132,15 +1120,13 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> exprs, self.merged_ty(), expression, - expression_ty, - expression_diverges), + expression_ty), Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub(cause, &coercion_sites[0..self.pushed], self.merged_ty(), expression, - expression_ty, - expression_diverges), + expression_ty), } } } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db859e42057e..9c73e5a8ce7a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -542,7 +542,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// you get indicates whether any subexpression that was /// evaluating up to and including `X` diverged. /// - /// We use this flag for two purposes: + /// We currently use this flag only for diagnostic purposes: /// /// - To warn about unreachable code: if, after processing a /// sub-expression but before we have applied the effects of the @@ -556,16 +556,8 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// foo();}` or `{return; 22}`, where we would warn on the /// `foo()` or `22`. /// - /// - To permit assignment into a local variable or other place - /// (including the "return slot") of type `!`. This is allowed - /// if **either** the type of value being assigned is `!`, which - /// means the current code is dead, **or** the expression's - /// diverging flag is true, which means that a diverging value was - /// wrapped (e.g., `let x: ! = foo(return)`). - /// - /// To repeat the last point: an expression represents dead-code - /// if, after checking it, **either** its type is `!` OR the - /// diverges flag is set to something other than `Maybe`. + /// An expression represents dead-code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. diverges: Cell, /// Whether any child nodes have any type errors. @@ -2999,8 +2991,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.cause(return_expr.span, ObligationCauseCode::ReturnType(return_expr.id)), return_expr, - return_expr_ty, - self.diverges.get()); + return_expr_ty); } @@ -3031,13 +3022,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); - coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges); + coerce.coerce(self, &if_cause, then_expr, then_ty); if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges); + coerce.coerce(self, &if_cause, else_expr, else_ty); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); @@ -3722,7 +3713,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprBreak(destination, ref expr_opt) => { if let Some(target_id) = destination.target_id.opt_id() { - let (e_ty, e_diverges, cause); + let (e_ty, cause); if let Some(ref e) = *expr_opt { // If this is a break with a value, we need to type-check // the expression. Get an expected type from the loop context. @@ -3741,13 +3732,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); - e_diverges = self.diverges.get(); cause = self.misc(e.span); } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. e_ty = tcx.mk_nil(); - e_diverges = Diverges::Maybe; cause = self.misc(expr.span); } @@ -3758,7 +3747,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ctxt = enclosing_breakables.find_breakable(target_id); if let Some(ref mut coerce) = ctxt.coerce { if let Some(ref e) = *expr_opt { - coerce.coerce(self, &cause, e, e_ty, e_diverges); + coerce.coerce(self, &cause, e, e_ty); } else { assert!(e_ty.is_nil()); coerce.coerce_forced_unit(self, &cause, &mut |_| (), true); @@ -3964,7 +3953,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); - coerce.coerce(self, &cause, e, e_ty, self.diverges.get()); + coerce.coerce(self, &cause, e, e_ty); } coerce.complete(self) } else { @@ -4375,8 +4364,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { coerce.coerce(self, &cause, tail_expr, - tail_expr_ty, - self.diverges.get()); + tail_expr_ty); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression From 5a013b2fbcd2eebc8345ccd1611e39b867b4c1f8 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 1 May 2018 00:23:34 +0100 Subject: [PATCH 06/26] Fix coerce-to-bang test This was explicitly testing the behaviour which is now no longer permitted. --- src/test/compile-fail/coerce-to-bang.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 62ff09f4616b..4a0e31d2deb4 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -56,9 +56,8 @@ fn call_foo_f() { } fn array_a() { - // Accepted: return is coerced to `!` just fine, and then `22` can be - // because we already diverged. - let x: [!; 2] = [return, 22]; + // Accepted: return is coerced to `!` just fine, but `22` cannot be. + let x: [!; 2] = [return, 22]; //~ ERROR mismatched types } fn array_b() { From 5489969fa18cc74d4b72077940a5c05491ec681f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 1 May 2018 12:27:09 -0400 Subject: [PATCH 07/26] Test is no longer "accepted" --- src/test/compile-fail/coerce-to-bang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 4a0e31d2deb4..8b4e2c3c051e 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -56,7 +56,7 @@ fn call_foo_f() { } fn array_a() { - // Accepted: return is coerced to `!` just fine, but `22` cannot be. + // Return is coerced to `!` just fine, but `22` cannot be. let x: [!; 2] = [return, 22]; //~ ERROR mismatched types } From cf9209f87274548f25e01621a712afcb036ede6e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Apr 2018 00:36:00 +0200 Subject: [PATCH 08/26] Improve results --- src/librustdoc/html/static/main.js | 75 +++++++++++++++++--------- src/librustdoc/html/static/rustdoc.css | 4 ++ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8569abeb09cc..ba92ac7bd306 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -454,12 +454,16 @@ var obj = searchIndex[results[i].id]; obj.lev = results[i].lev; if (isType !== true || obj.type) { + var res = buildHrefAndPath(obj); + obj.displayPath = pathSplitter(res[0]); + obj.fullPath = obj.displayPath + obj.name; + obj.href = res[1]; out.push(obj); + if (out.length >= MAX_RESULTS) { + break; + } } } - if (out.length >= MAX_RESULTS) { - break; - } } return out; } @@ -1017,6 +1021,12 @@ ALIASES[window.currentCrate][query.raw]) { var aliases = ALIASES[window.currentCrate][query.raw]; for (var i = 0; i < aliases.length; ++i) { + aliases[i].is_alias = true; + aliases[i].alias = query.raw; + var res = buildHrefAndPath(aliases[i]); + aliases[i].displayPath = pathSplitter(res[0]); + aliases[i].fullPath = aliases[i].displayPath + aliases[i].name; + aliases[i].href = res[1]; ret['others'].unshift(aliases[i]); if (ret['others'].length > MAX_RESULTS) { ret['others'].pop(); @@ -1179,16 +1189,6 @@ }; } - function escape(content) { - var h1 = document.createElement('h1'); - h1.textContent = content; - return h1.innerHTML; - } - - function pathSplitter(path) { - return '' + path.replace(/::/g, '::'); - } - function buildHrefAndPath(item) { var displayPath; var href; @@ -1227,6 +1227,16 @@ return [displayPath, href]; } + function escape(content) { + var h1 = document.createElement('h1'); + h1.textContent = content; + return h1.innerHTML; + } + + function pathSplitter(path) { + return '' + path.replace(/::/g, '::'); + } + function addTab(array, query, display) { var extraStyle = ''; if (display === false) { @@ -1234,12 +1244,13 @@ } var output = ''; + var duplicates = {}; if (array.length > 0) { output = ''; var shown = []; array.forEach(function(item) { - var name, type, href, displayPath; + var name, type; var id_ty = item.ty + item.path + item.name; if (shown.indexOf(id_ty) !== -1) { @@ -1250,15 +1261,23 @@ name = item.name; type = itemTypes[item.ty]; - var res = buildHrefAndPath(item); - var href = res[1]; - var displayPath = res[0]; + if (item.is_alias !== true) { + var fullPath = item.displayPath + name; + + if (duplicates[fullPath]) { + return; + } + duplicates[fullPath] = true; + } output += ''; }); @@ -1284,8 +1303,7 @@ if (results['others'].length === 1 && getCurrentValue('rustdoc-go-to-only-result') === "true") { var elem = document.createElement('a'); - var res = buildHrefAndPath(results['others'][0]); - elem.href = res[1]; + elem.href = results['others'][0].href; elem.style.display = 'none'; // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); @@ -1347,12 +1365,13 @@ } } if (queries.length > 1) { - function getSmallest(arrays, positions) { + function getSmallest(arrays, positions, notDuplicates) { var start = null; for (var it = 0; it < positions.length; ++it) { if (arrays[it].length > positions[it] && - (start === null || start > arrays[it][positions[it]].lev)) { + (start === null || start > arrays[it][positions[it]].lev) && + !notDuplicates[arrays[it][positions[it]].fullPath]) { start = arrays[it][positions[it]].lev; } } @@ -1362,19 +1381,23 @@ function mergeArrays(arrays) { var ret = []; var positions = []; + var notDuplicates = {}; for (var x = 0; x < arrays.length; ++x) { positions.push(0); } while (ret.length < MAX_RESULTS) { - var smallest = getSmallest(arrays, positions); + var smallest = getSmallest(arrays, positions, notDuplicates); + if (smallest === null) { break; } for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) { if (arrays[x].length > positions[x] && - arrays[x][positions[x]].lev === smallest) { + arrays[x][positions[x]].lev === smallest && + !notDuplicates[arrays[x][positions[x]].fullPath]) { ret.push(arrays[x][positions[x]]); + notDuplicates[arrays[x][positions[x]].fullPath] = true; positions[x] += 1; } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d6b3ab26af8a..08df4adf57d3 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1326,4 +1326,8 @@ kbd { } #all-types > p { margin: 5px 0; +} + +.search-results td span.grey { + color: #ccc; } \ No newline at end of file From e81b59bba88d216dcbc7bdf3f6aef8098fe3a7d7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Apr 2018 21:14:10 +0200 Subject: [PATCH 09/26] Improve alias rendering --- src/librustdoc/html/static/main.js | 2 +- src/librustdoc/html/static/rustdoc.css | 4 ---- src/librustdoc/html/static/themes/dark.css | 9 ++++++++- src/librustdoc/html/static/themes/light.css | 7 +++++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ba92ac7bd306..8c4dac9238ce 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1273,7 +1273,7 @@ output += '
' + - '' + - pathSplitter(displayPath) + '' + + '' + + (item.is_alias === true ? + ('' + item.alias + '  - see ') : '') + + item.displayPath + '' + name + '' + - '' + + '' + '' + escape(item.desc) + ' 
' + '' + (item.is_alias === true ? - ('' + item.alias + ' ' + item.alias + '  - see ') : '') + item.displayPath + '' + name + '' + diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 08df4adf57d3..d6b3ab26af8a 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1326,8 +1326,4 @@ kbd { } #all-types > p { margin: 5px 0; -} - -.search-results td span.grey { - color: #ccc; } \ No newline at end of file diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index da4be7db5aa9..493a75e25211 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -382,7 +382,7 @@ kbd { } #theme-choices > button:hover, #theme-choices > button:focus { - background-color: #444; + background-color: #4e4e4e; } @media (max-width: 700px) { @@ -397,3 +397,10 @@ kbd { #all-types:hover { background-color: #606060; } + +.search-results td span.alias { + color: #fff; +} +.search-results td span.grey { + color: #ccc; +} \ No newline at end of file diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 12af01d2e249..22f4635fb02e 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -390,4 +390,11 @@ kbd { } #all-types:hover { background-color: #f9f9f9; +} + +.search-results td span.alias { + color: #000; +} +.search-results td span.grey { + color: #999; } \ No newline at end of file From 8c80124fef9c2d9afceafc4f154b98390974670a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Apr 2018 22:27:12 +0200 Subject: [PATCH 10/26] Add missing description in alias items --- src/librustdoc/html/render.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 21de2db1dfe7..7fff981d0909 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -879,8 +879,8 @@ themePicker.onclick = function() {{ } fn show_item(item: &IndexItem, krate: &str) -> String { - format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}", - krate, item.ty as usize, item.name, item.path, + format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','path':'{}'{}}}", + krate, item.ty as usize, item.name, item.desc, item.path, if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { @@ -1442,7 +1442,7 @@ impl<'a> Cache { ty: item.type_(), name: item_name.to_string(), path: path.clone(), - desc: String::new(), + desc: plain_summary_line(item.doc_value()), parent: None, parent_idx: None, search_type: get_index_search_type(&item), From 9483e9b56474788e6549a1922e57f4a65c1c0bb0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Apr 2018 23:44:25 +0200 Subject: [PATCH 11/26] Handle blur on theme buttons nicely --- src/librustdoc/html/render.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 7fff981d0909..d6ea9b00a487 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -789,7 +789,8 @@ fn write_shared(cx: &Context, format!( r#"var themes = document.getElementById("theme-choices"); var themePicker = document.getElementById("theme-picker"); -themePicker.onclick = function() {{ + +function switchThemeButtonState() {{ if (themes.style.display === "block") {{ themes.style.display = "none"; themePicker.style.borderBottomRightRadius = "3px"; @@ -800,12 +801,29 @@ themePicker.onclick = function() {{ themePicker.style.borderBottomLeftRadius = "0"; }} }}; + +function handleThemeButtonsBlur(e) {{ + var active = document.activeElement; + var related = e.relatedTarget; + + if (active.id !== "themePicker" && + (!active.parentNode || active.parentNode.id !== "theme-choices") && + (!related || + (related.id !== "themePicker" && + (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{ + switchThemeButtonState(); + }} +}} + +themePicker.onclick = switchThemeButtonState; +themePicker.onblur = handleThemeButtonsBlur; [{}].forEach(function(item) {{ var but = document.createElement('button'); but.innerHTML = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item); }}; + but.onblur = handleThemeButtonsBlur; themes.appendChild(but); }});"#, themes.iter() From 72b7c8d2912b062e421bf17a584835e2ac66c124 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 May 2018 16:36:49 +0200 Subject: [PATCH 12/26] Remove extra span tags --- src/librustdoc/html/static/main.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8c4dac9238ce..b8d861d376f2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -57,6 +57,12 @@ return this.indexOf(searchString, position) === position; }; } + if (!String.prototype.endsWith) { + String.prototype.endsWith = function(suffix, length) { + var l = length || this.length; + return this.indexOf(suffix, l - suffix.length) !== -1; + }; + } function getPageId() { var id = document.location.href.split('#')[1]; @@ -1234,7 +1240,11 @@ } function pathSplitter(path) { - return '' + path.replace(/::/g, '::'); + var tmp = '' + path.replace(/::/g, '::'); + if (tmp.endsWith("")) { + return tmp.slice(0, tmp.length - 6); + } + return tmp; } function addTab(array, query, display) { From 6a4bdda87bc09ba080f42ffe30cb488b3740ca9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 May 2018 17:06:08 +0200 Subject: [PATCH 13/26] Reduce js files size --- src/librustdoc/html/render.rs | 16 +++++++----- src/librustdoc/html/static/main.js | 41 +++++++++++++++--------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d6ea9b00a487..7bddeb2f33f7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -413,9 +413,9 @@ impl ToJson for Type { match self.name { Some(ref name) => { let mut data = BTreeMap::new(); - data.insert("name".to_owned(), name.to_json()); + data.insert("n".to_owned(), name.to_json()); if let Some(ref generics) = self.generics { - data.insert("generics".to_owned(), generics.to_json()); + data.insert("g".to_owned(), generics.to_json()); } Json::Object(data) }, @@ -438,8 +438,12 @@ impl ToJson for IndexItemFunctionType { Json::Null } else { let mut data = BTreeMap::new(); - data.insert("inputs".to_owned(), self.inputs.to_json()); - data.insert("output".to_owned(), self.output.to_json()); + if !self.inputs.is_empty() { + data.insert("i".to_owned(), self.inputs.to_json()); + } + if let Some(ref output) = self.output { + data.insert("o".to_owned(), output.to_json()); + } Json::Object(data) } } @@ -897,8 +901,8 @@ themePicker.onblur = handleThemeButtonsBlur; } fn show_item(item: &IndexItem, krate: &str) -> String { - format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','path':'{}'{}}}", - krate, item.ty as usize, item.name, item.desc, item.path, + format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", + krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path, if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index b8d861d376f2..527c880b34ff 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -462,7 +462,7 @@ if (isType !== true || obj.type) { var res = buildHrefAndPath(obj); obj.displayPath = pathSplitter(res[0]); - obj.fullPath = obj.displayPath + obj.name; + obj.fullPath = obj.displayPath + obj.n; obj.href = res[1]; out.push(obj); if (out.length >= MAX_RESULTS) { @@ -597,8 +597,8 @@ // match as well. var lev_distance = MAX_LEV_DISTANCE + 1; if (val.generics.length > 0) { - if (obj.generics && obj.generics.length >= val.generics.length) { - var elems = obj.generics.slice(0); + if (obj.g && obj.g.length >= val.generics.length) { + var elems = obj.g.slice(0); var total = 0; var done = 0; // We need to find the type that matches the most to remove it in order @@ -630,11 +630,11 @@ // Check for type name and type generics (if any). function checkType(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj.name === val.name) { + if (obj.n === val.name) { if (literalSearch === true) { if (val.generics && val.generics.length !== 0) { - if (obj.generics && obj.length >= val.generics.length) { - var elems = obj.generics.slice(0); + if (obj.g && obj.length >= val.generics.length) { + var elems = obj.g.slice(0); var allFound = true; var x; @@ -658,7 +658,7 @@ } // If the type has generics but don't match, then it won't return at this point. // Otherwise, `checkGenerics` will return 0 and it'll return. - if (obj.generics && obj.generics.length !== 0) { + if (obj.g && obj.g.length !== 0) { var tmp_lev = checkGenerics(obj, val); if (tmp_lev <= MAX_LEV_DISTANCE) { return tmp_lev; @@ -669,22 +669,22 @@ } // Names didn't match so let's check if one of the generic types could. if (literalSearch === true) { - if (obj.generics && obj.generics.length > 0) { - for (var x = 0; x < obj.generics.length; ++x) { - if (obj.generics[x] === val.name) { + if (obj.g && obj.g.length > 0) { + for (var x = 0; x < obj.g.length; ++x) { + if (obj.g[x] === val.name) { return true; } } } return false; } - var lev_distance = Math.min(levenshtein(obj.name, val.name), lev_distance); + var lev_distance = Math.min(levenshtein(obj.n, val.name), lev_distance); if (lev_distance <= MAX_LEV_DISTANCE) { lev_distance = Math.min(checkGenerics(obj, val), lev_distance); - } else if (obj.generics && obj.generics.length > 0) { + } else if (obj.g && obj.g.length > 0) { // We can check if the type we're looking for is inside the generics! - for (var x = 0; x < obj.generics.length; ++x) { - lev_distance = Math.min(levenshtein(obj.generics[x], val.name), + for (var x = 0; x < obj.g.length; ++x) { + lev_distance = Math.min(levenshtein(obj.g[x], val.name), lev_distance); } } @@ -696,9 +696,9 @@ function findArg(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj && obj.type && obj.type.inputs.length > 0) { - for (var i = 0; i < obj.type.inputs.length; i++) { - var tmp = checkType(obj.type.inputs[i], val, literalSearch); + if (obj && obj.type && obj.type.i && obj.type.i.length > 0) { + for (var i = 0; i < obj.type.i.length; i++) { + var tmp = checkType(obj.type.i[i], val, literalSearch); if (literalSearch === true && tmp === true) { return true; } @@ -714,8 +714,8 @@ function checkReturned(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj && obj.type && obj.type.output) { - var tmp = checkType(obj.type.output, val, literalSearch); + if (obj && obj.type && obj.type.o) { + var tmp = checkType(obj.type.o, val, literalSearch); if (literalSearch === true && tmp === true) { return true; } @@ -860,7 +860,7 @@ var fullId = generateId(ty); // allow searching for void (no output) functions as well - var typeOutput = type.output ? type.output.name : ""; + var typeOutput = type.o ? type.o.name : ""; var returned = checkReturned(ty, output, true); if (output.name === "*" || returned === true) { var in_args = false; @@ -1029,6 +1029,7 @@ for (var i = 0; i < aliases.length; ++i) { aliases[i].is_alias = true; aliases[i].alias = query.raw; + aliases[i].path = aliases[i].p; var res = buildHrefAndPath(aliases[i]); aliases[i].displayPath = pathSplitter(res[0]); aliases[i].fullPath = aliases[i].displayPath + aliases[i].name; From 8fab482a68310da88ae72c1aef6edb19067949f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 May 2018 13:52:25 +0200 Subject: [PATCH 14/26] Fix items counts in search results --- src/librustdoc/html/static/main.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 527c880b34ff..e08f32618717 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1256,6 +1256,7 @@ var output = ''; var duplicates = {}; + var length = 0; if (array.length > 0) { output = ''; var shown = []; @@ -1280,6 +1281,7 @@ } duplicates[fullPath] = true; } + length += 1; output += '
' + '' + @@ -1299,7 +1301,7 @@ encodeURIComponent('rust ' + query.query) + '">DuckDuckGo?'; } - return output; + return [output, length]; } function makeTabHeader(tabNb, text, nbElems) { @@ -1320,21 +1322,22 @@ document.body.appendChild(elem); elem.click(); } - var output, query = getQuery(search_input.value); + var query = getQuery(search_input.value); currentResults = query.id; - output = '

Results for ' + escape(query.query) + + + var ret_others = addTab(results['others'], query); + var ret_in_args = addTab(results['in_args'], query, false); + var ret_returned = addTab(results['returned'], query, false); + + var output = '

Results for ' + escape(query.query) + (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '

' + '
' + - makeTabHeader(0, "In Names", results['others'].length) + - makeTabHeader(1, "In Parameters", results['in_args'].length) + - makeTabHeader(2, "In Return Types", results['returned'].length) + - '
'; - - output += addTab(results['others'], query); - output += addTab(results['in_args'], query, false); - output += addTab(results['returned'], query, false); - output += '
'; + makeTabHeader(0, "In Names", ret_others[1]) + + makeTabHeader(1, "In Parameters", ret_in_args[1]) + + makeTabHeader(2, "In Return Types", ret_returned[1]) + + '
' + + ret_others[0] + ret_in_args[0] + ret_returned[0] + '
'; addClass(document.getElementById('main'), 'hidden'); var search = document.getElementById('search'); From f2bc09e68bfc5d84a7abf49bedb5ced8f99b95a7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 May 2018 14:57:52 +0200 Subject: [PATCH 15/26] Fix invalid deduplication --- src/librustdoc/html/static/main.js | 9 +-------- src/test/rustdoc-js/deduplication.js | 21 +++++++++++++++++++++ src/tools/rustdoc-js/tester.js | 5 +++-- 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 src/test/rustdoc-js/deduplication.js diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index e08f32618717..3ee06a964de9 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -462,7 +462,7 @@ if (isType !== true || obj.type) { var res = buildHrefAndPath(obj); obj.displayPath = pathSplitter(res[0]); - obj.fullPath = obj.displayPath + obj.n; + obj.fullPath = obj.displayPath + obj.name; obj.href = res[1]; out.push(obj); if (out.length >= MAX_RESULTS) { @@ -1259,17 +1259,10 @@ var length = 0; if (array.length > 0) { output = ''; - var shown = []; array.forEach(function(item) { var name, type; - var id_ty = item.ty + item.path + item.name; - if (shown.indexOf(id_ty) !== -1) { - return; - } - - shown.push(id_ty); name = item.name; type = itemTypes[item.ty]; diff --git a/src/test/rustdoc-js/deduplication.js b/src/test/rustdoc-js/deduplication.js new file mode 100644 index 000000000000..0f29607d5c99 --- /dev/null +++ b/src/test/rustdoc-js/deduplication.js @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-order + +const QUERY = 'is_nan'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::f32', 'name': 'is_nan' }, + { 'path': 'std::f64', 'name': 'is_nan' }, + { 'path': 'std::option::Option', 'name': 'is_none' }, + ], +}; diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 25f7a2d1294c..47667d93cb7f 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -160,10 +160,11 @@ function main(argv) { // execQuery first parameter is built in getQuery (which takes in the search input). // execQuery last parameter is built in buildIndex. // buildIndex requires the hashmap from search-index. - var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery", - "execSearch"]; + var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", + "getQuery", "buildIndex", "execQuery", "execSearch"]; finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += 'var rootPath = "../";\n'; finalJS += ALIASES; finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); From f0db2cf14e8b58eb04d40e8aebea0a7a987097eb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 May 2018 23:44:40 +0200 Subject: [PATCH 16/26] Use fullpath instead of recreating it --- src/librustdoc/html/static/main.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 3ee06a964de9..9224bd1c5089 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1267,12 +1267,10 @@ type = itemTypes[item.ty]; if (item.is_alias !== true) { - var fullPath = item.displayPath + name; - - if (duplicates[fullPath]) { + if (duplicates[item.fullPath]) { return; } - duplicates[fullPath] = true; + duplicates[item.fullPath] = true; } length += 1; From e0567158dd3a1421fe55e27bee4ffb885ea3f149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 13 May 2018 07:14:36 +0200 Subject: [PATCH 17/26] update libcompiler_builtins let's OpenBSD to use libcompiler_rt.a from system library. it unbreaks the build from source on OpenBSD. --- src/libcompiler_builtins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 2a2f6d96c8dc..4cfd7101eb54 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 2a2f6d96c8dc578d2474742f14c9bab0b36b0408 +Subproject commit 4cfd7101eb549169cdaeda5313f7c39415b9d736 From b638f11b4230ad2e098a75474c36a10de1653d0d Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 11 May 2018 11:26:51 +0200 Subject: [PATCH 18/26] Introduce OperandValue::volatile_store and use it in the intrinsics Fixes #50371. --- src/librustc_trans/abi.rs | 3 ++- src/librustc_trans/base.rs | 10 ++++++---- src/librustc_trans/builder.rs | 3 ++- src/librustc_trans/intrinsic.rs | 21 +++------------------ src/librustc_trans/mir/block.rs | 2 +- src/librustc_trans/mir/operand.rs | 24 +++++++++++++++++++++--- 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1838dae049ad..c80d989e3cb1 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -220,7 +220,8 @@ impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { bx.pointercast(dst.llval, Type::i8p(cx)), bx.pointercast(llscratch, Type::i8p(cx)), C_usize(cx, self.layout.size.bytes()), - self.layout.align.min(scratch_align)); + self.layout.align.min(scratch_align), + false); bx.lifetime_end(llscratch, scratch_size); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0dd1adbff86e..65dce5f3ffbc 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -320,7 +320,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, if src_f.layout.ty == dst_f.layout.ty { memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, - src_f.align.min(dst_f.align)); + src_f.align.min(dst_f.align), false); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -408,7 +408,8 @@ pub fn call_memcpy(bx: &Builder, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, - align: Align) { + align: Align, + volatile: bool) { let cx = bx.cx; let ptr_width = &cx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); @@ -417,7 +418,7 @@ pub fn call_memcpy(bx: &Builder, let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); let size = bx.intcast(n_bytes, cx.isize_ty, false); let align = C_i32(cx, align.abi() as i32); - let volatile = C_bool(cx, false); + let volatile = C_bool(cx, volatile); bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } @@ -427,13 +428,14 @@ pub fn memcpy_ty<'a, 'tcx>( src: ValueRef, layout: TyLayout<'tcx>, align: Align, + volatile: bool, ) { let size = layout.size.bytes(); if size == 0 { return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align); + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, volatile); } pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index db803ca8209d..49bcf9b88a06 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -590,13 +590,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { + pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); assert!(!self.llbuilder.is_null()); self.count_insn("store.volatile"); let ptr = self.check_store(val, ptr); unsafe { let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); + llvm::LLVMSetAlignment(insn, align.abi() as c_uint); llvm::LLVMSetVolatile(insn, llvm::True); insn } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 49a207a2d8ab..65e211ae740b 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -247,26 +247,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, to_immediate(bx, load, cx.layout_of(tp_ty)) }, "volatile_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - if let OperandValue::Pair(a, b) = args[1].val { - bx.volatile_store(a, dst.project_field(bx, 0).llval); - bx.volatile_store(b, dst.project_field(bx, 1).llval); - } else { - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - if dst.layout.is_zst() { - return; - } - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.volatile_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } + if dst.layout.is_zst() { + return; } + args[1].val.volatile_store(bx, dst); return; }, "prefetch_read_data" | "prefetch_write_data" | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b666c2b21152..df8807c318b1 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -626,7 +626,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, false); (scratch.llval, scratch.align, true) } else { (llval, align, true) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 432ac44e0a56..f69661782915 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -275,6 +275,14 @@ impl<'a, 'tcx> OperandRef<'tcx> { impl<'a, 'tcx> OperandValue { pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_maybe_volatile(bx, dest, false); + } + + pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_maybe_volatile(bx, dest, true); + } + + fn store_maybe_volatile(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, volatile: bool) { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`, and store itself is useless. @@ -284,9 +292,14 @@ impl<'a, 'tcx> OperandValue { match self { OperandValue::Ref(r, source_align) => base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align)), + source_align.min(dest.align), volatile), OperandValue::Immediate(s) => { - bx.store(base::from_immediate(bx, s), dest.llval, dest.align); + let val = base::from_immediate(bx, s); + if !volatile { + bx.store(val, dest.llval, dest.align); + } else { + bx.volatile_store(val, dest.llval, dest.align); + } } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { @@ -295,7 +308,12 @@ impl<'a, 'tcx> OperandValue { if common::val_ty(x) == Type::i1(bx.cx) { llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); } - bx.store(base::from_immediate(bx, x), llptr, dest.align); + let val = base::from_immediate(bx, x); + if !volatile { + bx.store(val, llptr, dest.align); + } else { + bx.volatile_store(val, llptr, dest.align); + } } } } From 3ebe8679d2eed3caf30d8c6164405916de38ef94 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 11 May 2018 12:26:32 +0200 Subject: [PATCH 19/26] Introduce OperandValue::nontemporal_store and use it in the intrinsics We use a new MemFlags bitflags type to merge some store code paths. --- src/Cargo.lock | 1 + src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/abi.rs | 4 +- src/librustc_trans/base.rs | 19 ++++++--- src/librustc_trans/builder.rs | 67 ++++++++++++++----------------- src/librustc_trans/intrinsic.rs | 17 +------- src/librustc_trans/lib.rs | 1 + src/librustc_trans/mir/block.rs | 4 +- src/librustc_trans/mir/operand.rs | 29 ++++++------- 9 files changed, 65 insertions(+), 78 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 4cb82f94251f..70a230cb7f7a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2178,6 +2178,7 @@ dependencies = [ name = "rustc_trans" version = "0.0.0" dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index a4dd02e97b23..64d3a4f4d53b 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] +bitflags = "1.0.1" cc = "1.0.1" flate2 = "1.0" jobserver = "0.1.5" diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c80d989e3cb1..25c598c532c4 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, AttributePlace}; use base; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{ty_fn_sig, C_usize}; use context::CodegenCx; use mir::place::PlaceRef; @@ -221,7 +221,7 @@ impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { bx.pointercast(llscratch, Type::i8p(cx)), C_usize(cx, self.layout.size.bytes()), self.layout.align.min(scratch_align), - false); + MemFlags::empty()); bx.lifetime_end(llscratch, scratch_size); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 65dce5f3ffbc..feca36fa6c24 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -53,7 +53,7 @@ use rustc_incremental; use allocator; use mir::place::PlaceRef; use attributes; -use builder::Builder; +use builder::{Builder, MemFlags}; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; @@ -320,7 +320,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, if src_f.layout.ty == dst_f.layout.ty { memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, - src_f.align.min(dst_f.align), false); + src_f.align.min(dst_f.align), MemFlags::empty()); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -409,7 +409,14 @@ pub fn call_memcpy(bx: &Builder, src: ValueRef, n_bytes: ValueRef, align: Align, - volatile: bool) { + flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let val = bx.load(src, align); + let ptr = bx.pointercast(dst, val_ty(val).ptr_to()); + bx.store_with_flags(val, ptr, align, flags); + return; + } let cx = bx.cx; let ptr_width = &cx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); @@ -418,7 +425,7 @@ pub fn call_memcpy(bx: &Builder, let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); let size = bx.intcast(n_bytes, cx.isize_ty, false); let align = C_i32(cx, align.abi() as i32); - let volatile = C_bool(cx, volatile); + let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } @@ -428,14 +435,14 @@ pub fn memcpy_ty<'a, 'tcx>( src: ValueRef, layout: TyLayout<'tcx>, align: Align, - volatile: bool, + flags: MemFlags, ) { let size = layout.size.bytes(); if size == 0 { return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, volatile); + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); } pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 49bcf9b88a06..4153c61e5269 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -50,6 +50,13 @@ fn noname() -> *const c_char { &CNULL } +bitflags! { + pub struct MemFlags: u8 { + const VOLATILE = 1 << 0; + const NONTEMPORAL = 1 << 1; + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self { let bx = Builder::with_cx(cx); @@ -579,30 +586,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + pub fn store_with_flags( + &self, + val: ValueRef, + ptr: ValueRef, + align: Align, + flags: MemFlags, + ) -> ValueRef { + debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags); assert!(!self.llbuilder.is_null()); self.count_insn("store"); let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); llvm::LLVMSetAlignment(store, align.abi() as c_uint); + if flags.contains(MemFlags::VOLATILE) { + llvm::LLVMSetVolatile(store, llvm::True); + } + if flags.contains(MemFlags::NONTEMPORAL) { + // According to LLVM [1] building a nontemporal store must + // *always* point to a metadata value of the integer 1. + // + // [1]: http://llvm.org/docs/LangRef.html#store-instruction + let one = C_i32(self.cx, 1); + let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); + llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); + } store } } - pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.volatile"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetAlignment(insn, align.abi() as c_uint); - llvm::LLVMSetVolatile(insn, llvm::True); - insn - } - } - pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering, align: Align) { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); @@ -616,29 +632,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.nontemporal"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - - // According to LLVM [1] building a nontemporal store must *always* - // point to a metadata value of the integer 1. Who knew? - // - // [1]: http://llvm.org/docs/LangRef.html#store-instruction - let one = C_i32(self.cx, 1); - let node = llvm::LLVMMDNodeInContext(self.cx.llcx, - &one, - 1); - llvm::LLVMSetMetadata(insn, - llvm::MD_nontemporal as c_uint, - node); - insn - } - } - pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { self.count_insn("gep"); unsafe { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 65e211ae740b..86aa48b6a9e4 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -248,9 +248,6 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, }, "volatile_store" => { let dst = args[0].deref(bx.cx); - if dst.layout.is_zst() { - return; - } args[1].val.volatile_store(bx, dst); return; }, @@ -536,19 +533,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } "nontemporal_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.nontemporal_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } - return + args[1].val.nontemporal_store(bx, dst); + return; } _ => { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 30780b8c9656..6db95657ce05 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -34,6 +34,7 @@ use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; +#[macro_use] extern crate bitflags; extern crate flate2; extern crate libc; #[macro_use] extern crate rustc; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index df8807c318b1..e4989da36c02 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -17,7 +17,7 @@ use rustc::mir::interpret::EvalErrorKind; use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; use consts; use meth; @@ -626,7 +626,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, false); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); (scratch.llval, scratch.align, true) } else { (llval, align, true) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index f69661782915..3e4a73c2e905 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::Idx; use base; use common::{self, CodegenCx, C_null, C_undef, C_usize}; -use builder::Builder; +use builder::{Builder, MemFlags}; use value::Value; use type_of::LayoutLlvmExt; use type_::Type; @@ -275,14 +275,18 @@ impl<'a, 'tcx> OperandRef<'tcx> { impl<'a, 'tcx> OperandValue { pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_maybe_volatile(bx, dest, false); + self.store_with_flags(bx, dest, MemFlags::empty()); } pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_maybe_volatile(bx, dest, true); + self.store_with_flags(bx, dest, MemFlags::VOLATILE); } - fn store_maybe_volatile(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, volatile: bool) { + pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); + } + + fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`, and store itself is useless. @@ -290,16 +294,13 @@ impl<'a, 'tcx> OperandValue { return; } match self { - OperandValue::Ref(r, source_align) => + OperandValue::Ref(r, source_align) => { base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align), volatile), + source_align.min(dest.align), flags) + } OperandValue::Immediate(s) => { let val = base::from_immediate(bx, s); - if !volatile { - bx.store(val, dest.llval, dest.align); - } else { - bx.volatile_store(val, dest.llval, dest.align); - } + bx.store_with_flags(val, dest.llval, dest.align, flags); } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { @@ -309,11 +310,7 @@ impl<'a, 'tcx> OperandValue { llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); } let val = base::from_immediate(bx, x); - if !volatile { - bx.store(val, llptr, dest.align); - } else { - bx.volatile_store(val, llptr, dest.align); - } + bx.store_with_flags(val, llptr, dest.align, flags); } } } From 394945ee36301f0e2be2aa711d9fe6c063960083 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 2 May 2018 03:02:05 +0000 Subject: [PATCH 20/26] stabilize :lifetime --- .../macro-lifetime-matcher.md | 14 -------------- src/librustc/lib.rs | 1 - src/librustc_metadata/lib.rs | 2 -- src/librustc_save_analysis/lib.rs | 1 - src/libsyntax/ext/tt/macro_rules.rs | 14 +------------- src/libsyntax/feature_gate.rs | 8 ++------ .../macro-lifetime-used-with-bound.rs | 2 -- .../macro-lifetime-used-with-labels.rs | 1 - .../macro-lifetime-used-with-static.rs | 2 -- src/test/run-pass/macro-lifetime.rs | 2 -- .../ui/feature-gate-macro-lifetime-matcher.rs | 19 ------------------- src/test/ui/macros/nonterminal-matching.rs | 2 +- 12 files changed, 4 insertions(+), 64 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md delete mode 100644 src/test/ui/feature-gate-macro-lifetime-matcher.rs diff --git a/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md b/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md deleted file mode 100644 index 5b585d7f041d..000000000000 --- a/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md +++ /dev/null @@ -1,14 +0,0 @@ -# `macro_lifetime_matcher` - -The tracking issue for this feature is: [#46895] - -With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: - -* `lifetime`: a lifetime. Examples: 'static, 'a. - -A `lifetime` variable may be followed by anything. - -[#46895]: https://github.com/rust-lang/rust/issues/46895 -[frags]: ../book/first-edition/macros.html#syntactic-requirements - ------------------------- diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 879d38c48944..b9928a08131f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -50,7 +50,6 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![cfg_attr(windows, feature(libc))] -#![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index a99e0a32e664..60016a0d8645 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -15,9 +15,7 @@ #![feature(box_patterns)] #![feature(fs_read_write)] #![feature(libc)] -#![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] -#![feature(macro_lifetime_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index cf12302d9896..bfcb23c1fb89 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(custom_attribute)] -#![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] #[macro_use] diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1fc5aed7e7a2..e96a0e838cfc 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -904,20 +904,8 @@ fn is_legal_fragment_specifier(sess: &ParseSess, frag_name: &str, frag_span: Span) -> bool { match frag_name { - "item" | "block" | "stmt" | "expr" | "pat" | + "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, - "lifetime" => { - if !features.macro_lifetime_matcher && - !attr::contains_name(attrs, "allow_internal_unstable") { - let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; - emit_feature_err(sess, - "macro_lifetime_matcher", - frag_span, - GateIssue::Language, - explain); - } - true - }, "literal" => { if !features.macro_literal_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 562705462e2a..cb5125fe9ef5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -396,9 +396,6 @@ declare_features! ( // Termination trait in tests (RFC 1937) (active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)), - // Allows use of the :lifetime macro fragment specifier - (active, macro_lifetime_matcher, "1.24.0", Some(46895), None), - // `extern` in paths (active, extern_in_paths, "1.23.0", Some(44660), None), @@ -598,6 +595,8 @@ declare_features! ( (accepted, dyn_trait, "1.27.0", Some(44662), None), // allow `#[must_use]` on functions; and, must-use operators (RFC 1940) (accepted, fn_must_use, "1.27.0", Some(43302), None), + // Allows use of the :lifetime macro fragment specifier + (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1331,9 +1330,6 @@ pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = pub const EXPLAIN_VIS_MATCHER: &'static str = ":vis fragment specifier is experimental and subject to change"; -pub const EXPLAIN_LIFETIME_MATCHER: &'static str = - ":lifetime fragment specifier is experimental and subject to change"; - pub const EXPLAIN_LITERAL_MATCHER: &'static str = ":literal fragment specifier is experimental and subject to change"; diff --git a/src/test/run-pass/macro-lifetime-used-with-bound.rs b/src/test/run-pass/macro-lifetime-used-with-bound.rs index b0c9280b6ce4..b9e1fde6b1f3 100644 --- a/src/test/run-pass/macro-lifetime-used-with-bound.rs +++ b/src/test/run-pass/macro-lifetime-used-with-bound.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(macro_lifetime_matcher)] - macro_rules! foo { ($l:lifetime, $l2:lifetime) => { fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str { diff --git a/src/test/run-pass/macro-lifetime-used-with-labels.rs b/src/test/run-pass/macro-lifetime-used-with-labels.rs index 8a2d76e17df6..d003d7dcfb62 100644 --- a/src/test/run-pass/macro-lifetime-used-with-labels.rs +++ b/src/test/run-pass/macro-lifetime-used-with-labels.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(unreachable_code)] -#![feature(macro_lifetime_matcher)] macro_rules! x { ($a:lifetime) => { diff --git a/src/test/run-pass/macro-lifetime-used-with-static.rs b/src/test/run-pass/macro-lifetime-used-with-static.rs index 468ee2e94365..5c1f8683e00f 100644 --- a/src/test/run-pass/macro-lifetime-used-with-static.rs +++ b/src/test/run-pass/macro-lifetime-used-with-static.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(macro_lifetime_matcher)] - macro_rules! foo { ($l:lifetime) => { fn f(arg: &$l str) -> &$l str { diff --git a/src/test/run-pass/macro-lifetime.rs b/src/test/run-pass/macro-lifetime.rs index db521ca7f103..ff5798ff78d6 100644 --- a/src/test/run-pass/macro-lifetime.rs +++ b/src/test/run-pass/macro-lifetime.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(macro_lifetime_matcher)] - macro_rules! foo { ($l:lifetime) => { fn f<$l>(arg: &$l str) -> &$l str { diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.rs b/src/test/ui/feature-gate-macro-lifetime-matcher.rs deleted file mode 100644 index 0d107d283cdf..000000000000 --- a/src/test/ui/feature-gate-macro-lifetime-matcher.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher -// feature gate is not used. - -macro_rules! m { ($lt:lifetime) => {} } -//~^ ERROR :lifetime fragment specifier is experimental and subject to change - -fn main() { - m!('a); -} diff --git a/src/test/ui/macros/nonterminal-matching.rs b/src/test/ui/macros/nonterminal-matching.rs index 4dcb8afa94ea..54d280a63e79 100644 --- a/src/test/ui/macros/nonterminal-matching.rs +++ b/src/test/ui/macros/nonterminal-matching.rs @@ -11,7 +11,7 @@ // Check that we are refusing to match on complex nonterminals for which tokens are // unavailable and we'd have to go through AST comparisons. -#![feature(decl_macro, macro_lifetime_matcher)] +#![feature(decl_macro)] macro simple_nonterminal($nt_ident: ident, $nt_lifetime: lifetime, $nt_tt: tt) { macro n(a $nt_ident b $nt_lifetime c $nt_tt d) { From e6f7cf7e75286ca0e298bcdce7d831e5ebd451df Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 2 May 2018 04:38:08 +0000 Subject: [PATCH 21/26] remove stray ui stderr --- .../ui/feature-gate-macro-lifetime-matcher.stderr | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/test/ui/feature-gate-macro-lifetime-matcher.stderr diff --git a/src/test/ui/feature-gate-macro-lifetime-matcher.stderr b/src/test/ui/feature-gate-macro-lifetime-matcher.stderr deleted file mode 100644 index b7805f6f5fbf..000000000000 --- a/src/test/ui/feature-gate-macro-lifetime-matcher.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: :lifetime fragment specifier is experimental and subject to change (see issue #46895) - --> $DIR/feature-gate-macro-lifetime-matcher.rs:14:19 - | -LL | macro_rules! m { ($lt:lifetime) => {} } - | ^^^^^^^^^^^^ - | - = help: add #![feature(macro_lifetime_matcher)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From e857c1b79028765c62e7f29584c7ce75bfb739b9 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Thu, 10 May 2018 02:01:03 +0000 Subject: [PATCH 22/26] restore feature for stage0 --- src/librustc/lib.rs | 1 + src/librustc_metadata/lib.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b9928a08131f..2a288ae522aa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -50,6 +50,7 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![cfg_attr(windows, feature(libc))] +#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 60016a0d8645..7ecf2eba43dd 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(fs_read_write)] #![feature(libc)] +#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index bfcb23c1fb89..e57a793ff426 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -12,6 +12,7 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(custom_attribute)] +#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![allow(unused_attributes)] #[macro_use] From cdd61396c93f34915d145f0ab5b388138b479a3c Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Sat, 12 May 2018 19:04:44 +0000 Subject: [PATCH 23/26] typeck: Save the index of private fields Save the index of all fields regardless of their visibility. Problems could occur later when attempting to index fields in error recovery if they are not inserted. --- src/librustc_typeck/check/mod.rs | 4 ++- .../proc-macro/auxiliary/issue_50493.rs | 32 +++++++++++++++++++ .../proc-macro/issue-50493.rs | 27 ++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7b859635f60d..e38a00bba162 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3081,12 +3081,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) { let field = &fields[index]; let field_ty = self.field_ty(expr.span, field, substs); + // Save the index of all fields regardless of their visibility in case + // of error recovery. + self.write_field_index(expr.id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { let adjustments = autoderef.adjust_steps(needs); self.apply_adjustments(base, adjustments); autoderef.finalize(); - self.write_field_index(expr.id, index); self.tcx.check_stability(field.did, Some(expr.id), expr.span); return field_ty; } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs new file mode 100644 index 000000000000..7d36517d9704 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(proc_macro, proc_macro_lib)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(Derive)] +pub fn derive(_: TokenStream) -> TokenStream { + let code = " + fn one(r: Restricted) { + r.field; + } + fn two(r: Restricted) { + r.field; + } + "; + + code.parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs new file mode 100644 index 000000000000..51112f202c89 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue_50493.rs +// ignore-stage1 + +#![feature(proc_macro)] + +#[macro_use] +extern crate issue_50493; + +#[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private +struct Restricted { + pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules +} + +mod restricted {} + +fn main() {} + From 29b4c7b9e0a5e32127c42f5aab9baefadc38033c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 14 May 2018 12:23:12 +0300 Subject: [PATCH 24/26] rustc: don't trip an assertion for enums with present but uninhabited variants. --- src/librustc/ty/layout.rs | 5 +++++ src/test/run-pass/issue-50731.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/run-pass/issue-50731.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b22c025e86c0..bbfc6d883e9a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -888,6 +888,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if x < min { min = x; } if x > max { max = x; } } + // We might have no inhabited variants, so pretend there's at least one. + if (min, max) == (i128::max_value(), i128::min_value()) { + min = 0; + max = 0; + } assert!(min <= max, "discriminant range is {}...{}", min, max); let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); diff --git a/src/test/run-pass/issue-50731.rs b/src/test/run-pass/issue-50731.rs new file mode 100644 index 000000000000..06df2b989af2 --- /dev/null +++ b/src/test/run-pass/issue-50731.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Void {} +fn foo(_: Result<(Void, u32), (Void, String)>) {} +fn main() { + let _: fn(_) = foo; +} From 3a5b13ad36d5cb4081c727c78e7d6fd6711108b9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 14 May 2018 16:11:24 +0200 Subject: [PATCH 25/26] Bump clippy --- src/Cargo.lock | 6 +++--- src/tools/clippy | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 70a230cb7f7a..2f52c8895588 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -288,12 +288,12 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.198" +version = "0.0.200" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.198", + "clippy_lints 0.0.200", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.0.198" +version = "0.0.200" dependencies = [ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/clippy b/src/tools/clippy index 7a4c00c669b3..c658fc8cbcd1 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 7a4c00c669b3bf0ffb24c7aa89a776cd48f1e2d0 +Subproject commit c658fc8cbcd1f199edd445a49cb43139ebdc5f02 From 647b1add7fc1cb3204131f82cbbe67eb9b4a27b3 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 14 May 2018 12:32:04 -0400 Subject: [PATCH 26/26] Update stdsimd module to include https://github.com/rust-lang-nursery/stdsimd/commit/a19ca1cd91cf97777af8268a6136bd2e4648e189 --- src/stdsimd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdsimd b/src/stdsimd index 2f86c75a2479..a19ca1cd91cf 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1 +Subproject commit a19ca1cd91cf97777af8268a6136bd2e4648e189