From 0d395841fc5141462c88a4167b2f675405d3a8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 Jun 2016 18:29:16 -0700 Subject: [PATCH 001/104] Detect double reference when applying binary op ```rust let vr = v.iter().filter(|x| { x % 2 == 0 }); ``` will now yield the following compiler output: ```bash ERROR binary operation `%` cannot be applied to type `&&_` NOTE this is a reference of a reference to a type that `%` can be applied to, you need to dereference this variable once for this operation to work NOTE an implementation of `std::ops::Rem` might be missing for `&&_` ``` The first NOTE is new. Bug #33877 --- src/librustc_typeck/check/op.rs | 17 +++++++++++++++- .../compile-fail/binary-op-on-double-ref.rs | 20 +++++++++++++++++++ .../compile-fail/str-concat-on-double-ref.rs | 19 ++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/binary-op-on-double-ref.rs create mode 100644 src/test/compile-fail/str-concat-on-double-ref.rs diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1a9b8ef85ae..4202f65c44d4 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -12,7 +12,7 @@ use super::FnCtxt; use hir::def_id::DefId; -use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue}; +use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::infer::type_variable::TypeVariableOrigin; use syntax::ast; use syntax::symbol::Symbol; @@ -204,6 +204,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); + + if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { + if self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + token::intern(name), trait_def_id, + lhs_expr).is_ok() { + err.span_note( + lhs_expr.span, + &format!( + "this is a reference of type that `{}` can be applied to, \ + you need to dereference this variable once for this \ + operation to work", + op.node.as_str())); + } + } + let missing_trait = match op.node { hir::BiAdd => Some("std::ops::Add"), hir::BiSub => Some("std::ops::Sub"), diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs new file mode 100644 index 000000000000..5cc8e0f9988f --- /dev/null +++ b/src/test/compile-fail/binary-op-on-double-ref.rs @@ -0,0 +1,20 @@ +// Copyright 2012-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. + +fn main() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + let vr = v.iter().filter(|x| { + x % 2 == 0 + //~^ ERROR binary operation `%` cannot be applied to type `&&_` + //~| NOTE this is a reference of type that `%` can be applied to + //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_` + }); + println!("{:?}", vr); +} diff --git a/src/test/compile-fail/str-concat-on-double-ref.rs b/src/test/compile-fail/str-concat-on-double-ref.rs new file mode 100644 index 000000000000..d79ab6b805c8 --- /dev/null +++ b/src/test/compile-fail/str-concat-on-double-ref.rs @@ -0,0 +1,19 @@ +// Copyright 2012-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. + +fn main() { + let a: &String = &"1".to_owned(); + let b: &str = &"2"; + let c = a + b; + //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String` + //~| NOTE this is a reference of type that `+` can be applied to + //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String` + println!("{:?}", c); +} From b8669dff556a03ca37b39cbb81be65c94d24defe Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 26 Dec 2016 13:27:51 -0500 Subject: [PATCH 002/104] Ensure type is copyable before emitting note suggesting adding manual deref. drive-by: fix merge conflict; fix test expected error output post rebase. --- src/librustc_typeck/check/op.rs | 5 +++-- src/test/compile-fail/binary-op-on-double-ref.rs | 4 ++-- src/test/compile-fail/str-concat-on-double-ref.rs | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 4202f65c44d4..925d28247b61 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -206,8 +206,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty); if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { - if self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], - token::intern(name), trait_def_id, + if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.span_note( lhs_expr.span, diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs index 5cc8e0f9988f..a49cfaa17606 100644 --- a/src/test/compile-fail/binary-op-on-double-ref.rs +++ b/src/test/compile-fail/binary-op-on-double-ref.rs @@ -12,9 +12,9 @@ fn main() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; let vr = v.iter().filter(|x| { x % 2 == 0 - //~^ ERROR binary operation `%` cannot be applied to type `&&_` + //~^ ERROR binary operation `%` cannot be applied to type `&&{integer}` //~| NOTE this is a reference of type that `%` can be applied to - //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_` + //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&{integer}` }); println!("{:?}", vr); } diff --git a/src/test/compile-fail/str-concat-on-double-ref.rs b/src/test/compile-fail/str-concat-on-double-ref.rs index d79ab6b805c8..f85422f76d40 100644 --- a/src/test/compile-fail/str-concat-on-double-ref.rs +++ b/src/test/compile-fail/str-concat-on-double-ref.rs @@ -13,7 +13,6 @@ fn main() { let b: &str = &"2"; let c = a + b; //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String` - //~| NOTE this is a reference of type that `+` can be applied to //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String` println!("{:?}", c); } From 5f118b954e2aeced356511167319a31fc0503f47 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 Jan 2017 09:02:14 -0500 Subject: [PATCH 003/104] travis: Gate on some minimal support for incremental compilation. This commit adds a travis job that builds a stage2 compiler in incremental mode (but with empty incremental compilation cache). Building incrementally with an empty cache makes sure that the compiler doesn't crash in dependency tracking during bootstrapping. --- .travis.yml | 1 + .../docker/x86_64-gnu-incremental/Dockerfile | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/ci/docker/x86_64-gnu-incremental/Dockerfile diff --git a/.travis.yml b/.travis.yml index abd0a8fe346f..b6656bec6052 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ matrix: - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1 - env: IMAGE=x86_64-musl DEPLOY=1 - env: IMAGE=x86_64-gnu-distcheck + - env: IMAGE=x86_64-gnu-incremental # OSX builders - env: > diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile new file mode 100644 index 000000000000..3e084f4a3c30 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils + +ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 +RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ + tar xJf - -C /usr/local/bin --strip-components=1 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUSTFLAGS -Zincremental=/tmp/rust-incr-cache +ENV RUST_CHECK_TARGET check From 65147b673bcf8cc740d40209321f0716864a0ab3 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Thu, 19 Jan 2017 18:09:23 -0500 Subject: [PATCH 004/104] Update nomicon to describe `#[may_dangle]` --- src/doc/nomicon/dropck.md | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/doc/nomicon/dropck.md b/src/doc/nomicon/dropck.md index f54933827b33..6114006cbb34 100644 --- a/src/doc/nomicon/dropck.md +++ b/src/doc/nomicon/dropck.md @@ -199,24 +199,42 @@ assert (unsafely) that a generic type's destructor is *guaranteed* to not access any expired data, even if its type gives it the capability to do so. -That attribute is called `unsafe_destructor_blind_to_params`. +That attribute is called `may_dangle` and was introduced in [RFC 1327] +(https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md). To deploy it on the Inspector example from above, we would write: ```rust,ignore struct Inspector<'a>(&'a u8, &'static str); -impl<'a> Drop for Inspector<'a> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> { fn drop(&mut self) { println!("Inspector(_, {}) knows when *not* to inspect.", self.1); } } ``` -This attribute has the word `unsafe` in it because the compiler is not -checking the implicit assertion that no potentially expired data +Use of this attribute requires the `Drop` impl to be marked `unsafe` because the +compiler is not checking the implicit assertion that no potentially expired data (e.g. `self.0` above) is accessed. +The attribute can be applied to any number of lifetime and type parameters. In +the following example, we assert that we access no data behind a reference of +lifetime `'b` and that the only uses of `T` will be moves or drops, but omit +the attribute from `'a` and `U`, because we do access data with that lifetime +and that type: + +```rust,ignore +use std::fmt::Display; + +struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U); + +unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> { + fn drop(&mut self) { + println!("Inspector({}, _, _, {})", self.0, self.3); + } +} +``` + It is sometimes obvious that no such access can occur, like the case above. However, when dealing with a generic type parameter, such access can occur indirectly. Examples of such indirect access are: @@ -263,7 +281,7 @@ some other method invoked by the destructor, rather than being written directly within it. In all of the above cases where the `&'a u8` is accessed in the -destructor, adding the `#[unsafe_destructor_blind_to_params]` +destructor, adding the `#[may_dangle]` attribute makes the type vulnerable to misuse that the borrower checker will not catch, inviting havoc. It is better to avoid adding the attribute. From b795abeb1dc0f6d27e49d980a48936b687754b28 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 17 Jan 2017 21:18:29 +0300 Subject: [PATCH 005/104] Refactor parsing of generic arguments/parameters and where clauses --- src/librustc_passes/ast_validation.rs | 26 + src/librustc_typeck/collect.rs | 5 +- src/librustdoc/clean/mod.rs | 7 +- src/libsyntax/parse/parser.rs | 679 +++++++----------- src/libsyntax/parse/token.rs | 23 + .../attrs-with-no-formal-in-generics-2.rs | 9 +- .../generic-non-trailing-defaults.rs | 20 + src/test/compile-fail/issue-20616-1.rs | 2 +- src/test/compile-fail/issue-20616-2.rs | 2 +- src/test/compile-fail/issue-20616-3.rs | 2 +- src/test/compile-fail/issue-20616-4.rs | 2 +- src/test/compile-fail/issue-20616-5.rs | 2 +- src/test/compile-fail/issue-20616-6.rs | 2 +- src/test/compile-fail/issue-20616-7.rs | 2 +- src/test/compile-fail/issue-20616-8.rs | 2 +- src/test/compile-fail/issue-20616-9.rs | 2 +- src/test/parse-fail/issue-14303-path.rs | 1 - ...-trailing-defaults.rs => issue-17904-2.rs} | 6 +- src/test/parse-fail/issue-17904.rs | 3 +- src/test/parse-fail/issue-32214.rs | 5 +- src/test/parse-fail/lifetime-semicolon.rs | 3 +- .../where-clauses-no-bounds-or-predicates.rs | 4 +- 22 files changed, 341 insertions(+), 468 deletions(-) create mode 100644 src/test/compile-fail/generic-non-trailing-defaults.rs rename src/test/parse-fail/{generic-non-trailing-defaults.rs => issue-17904-2.rs} (74%) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index b7b027102b2a..9720bb842647 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -146,6 +146,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { TyKind::TraitObject(ref bounds) => { self.no_questions_in_bounds(bounds, "trait object types", false); } + TyKind::ImplTrait(ref bounds) => { + if !bounds.iter() + .any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { + self.err_handler().span_err(ty.span, "at least one trait must be specified"); + } + } _ => {} } @@ -284,6 +290,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_vis(self, vis) } + + fn visit_generics(&mut self, g: &'a Generics) { + let mut seen_default = None; + for ty_param in &g.ty_params { + if ty_param.default.is_some() { + seen_default = Some(ty_param.span); + } else if let Some(span) = seen_default { + self.err_handler() + .span_err(span, "type parameters with a default must be trailing"); + break + } + } + for predicate in &g.where_clause.predicates { + if let WherePredicate::EqPredicate(ref predicate) = *predicate { + self.err_handler().span_err(predicate.span, "equality constraints are not yet \ + supported in where clauses (#20041)"); + } + } + visit::walk_generics(self, g) + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d403ac434353..b9ee1c2b84cb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1833,11 +1833,8 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - &hir::WherePredicate::EqPredicate(ref eq_pred) => { + &hir::WherePredicate::EqPredicate(..) => { // FIXME(#20041) - span_bug!(eq_pred.span, - "Equality constraints are not yet \ - implemented (#20041)") } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a77485477b15..77f0482e1131 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -842,8 +842,11 @@ impl Clean for hir::WherePredicate { } } - hir::WherePredicate::EqPredicate(_) => { - unimplemented!() // FIXME(#20041) + hir::WherePredicate::EqPredicate(ref wrp) => { + WherePredicate::EqPredicate { + lhs: wrp.lhs_ty.clean(cx), + rhs: wrp.rhs_ty.clean(cx) + } } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2a0a73859987..c589f1a7aaaa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -22,7 +22,7 @@ use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{Ident, ImplItem, Item, ItemKind}; -use ast::{Lit, LitKind, UintTy}; +use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; use ast::Mac_; @@ -638,13 +638,7 @@ impl<'a> Parser<'a> { let lo = span.lo + BytePos(1); Ok(self.bump_with(token::Eq, lo, span.hi)) } - _ => { - let gt_str = Parser::token_to_string(&token::Gt); - let this_token_str = self.this_token_to_string(); - Err(self.fatal(&format!("expected `{}`, found `{}`", - gt_str, - this_token_str))) - } + _ => self.unexpected() } } @@ -971,20 +965,11 @@ impl<'a> Parser<'a> { Parses whatever can come after a `for` keyword in a type. The `for` hasn't been consumed. - Deprecated: - - - for <'lt> |S| -> T - - Eventually: - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) - + - for <'lt> path::foo(a, b) + Trait + 'a */ - // parse <'lt> let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; // examine next token to decide to do @@ -993,9 +978,9 @@ impl<'a> Parser<'a> { } else { let hi = self.span.hi; let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; + let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, + trait_ref: trait_ref, + span: mk_sp(lo, hi)}; let other_bounds = if self.eat(&token::BinOp(token::Plus)) { self.parse_ty_param_bounds()? } else { @@ -1010,18 +995,9 @@ impl<'a> Parser<'a> { } pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `impl` keyword in a type. - The `impl` has already been consumed. - */ - - let bounds = self.parse_ty_param_bounds()?; - - if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { - self.span_err(self.prev_span, "at least one trait must be specified"); - } - - Ok(ast::TyKind::ImplTrait(bounds)) + // Parses whatever can come after a `impl` keyword in a type. + // The `impl` has already been consumed. + Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) } pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { @@ -1029,7 +1005,7 @@ impl<'a> Parser<'a> { } /// parse a TyKind::BareFn type: - pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult<'a, TyKind> { /* @@ -1201,13 +1177,6 @@ impl<'a> Parser<'a> { }) } - /// Parse a possibly mutable type - pub fn parse_mt(&mut self) -> PResult<'a, MutTy> { - let mutbl = self.parse_mutability()?; - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl: mutbl }) - } - /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { @@ -1259,8 +1228,8 @@ impl<'a> Parser<'a> { pprust::ty_to_string(&lhs)); err.span_label(lhs.span, &format!("expected a path")); let hi = bounds.iter().map(|x| match *x { - ast::TraitTyParamBound(ref tr, _) => tr.span.hi, - ast::RegionTyParamBound(ref r) => r.span.hi, + TraitTyParamBound(ref tr, _) => tr.span.hi, + RegionTyParamBound(ref r) => r.span.hi, }).max_by_key(|x| x.to_usize()); let full_span = hi.map(|hi| Span { lo: lhs.span.lo, @@ -1308,9 +1277,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let t = if self.check(&token::OpenDelim(token::Paren)) { - self.bump(); - + let t = if self.eat(&token::OpenDelim(token::Paren)) { // (t) is a parenthesized ty // (t,) is the type of a tuple with only one field, // of type t @@ -1318,9 +1285,8 @@ impl<'a> Parser<'a> { let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { ts.push(self.parse_ty()?); - if self.check(&token::Comma) { + if self.eat(&token::Comma) { last_comma = true; - self.bump(); } else { last_comma = false; break; @@ -1335,13 +1301,11 @@ impl<'a> Parser<'a> { } } else if self.eat(&token::Not) { TyKind::Never - } else if self.check(&token::BinOp(token::Star)) { + } else if self.eat(&token::BinOp(token::Star)) { // STAR POINTER (bare pointer?) - self.bump(); TyKind::Ptr(self.parse_ptr()?) - } else if self.check(&token::OpenDelim(token::Bracket)) { + } else if self.eat(&token::OpenDelim(token::Bracket)) { // VECTOR - self.expect(&token::OpenDelim(token::Bracket))?; let t = self.parse_ty()?; // Parse the `; e` in `[ i32; e ]` @@ -1353,13 +1317,15 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Bracket))?; t } else if self.check(&token::BinOp(token::And)) || - self.token == token::AndAnd { + self.check(&token::AndAnd) { // BORROWED POINTER self.expect_and()?; self.parse_borrowed_pointee()? } else if self.check_keyword(keywords::For) { + // FIXME plus priority self.parse_for_in_type()? } else if self.eat_keyword(keywords::Impl) { + // FIXME plus priority self.parse_impl_trait_type()? } else if self.token_is_bare_fn_keyword() { // BARE FUNCTION @@ -1372,10 +1338,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) } else if self.eat_lt() { - - let (qself, path) = - self.parse_qualified_path(PathStyle::Type)?; - + let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Type)?; @@ -1405,10 +1368,10 @@ impl<'a> Parser<'a> { pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.parse_opt_lifetime()?; - - let mt = self.parse_mt()?; - return Ok(TyKind::Rptr(opt_lifetime, mt)); + let opt_lifetime = self.eat_lifetime(); + let mutbl = self.parse_mutability()?; + let ty = self.parse_ty_no_plus()?; + return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> { @@ -1504,8 +1467,7 @@ impl<'a> Parser<'a> { } pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.check(&token::Semi) { - self.bump(); + if self.eat(&token::Semi) { Ok(Some(self.parse_expr()?)) } else { Ok(None) @@ -1727,7 +1689,8 @@ impl<'a> Parser<'a> { // Parse types, optionally. let parameters = if self.eat_lt() { - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; + let (lifetimes, types, bindings) = self.parse_generic_args()?; + self.expect_gt()?; ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1785,7 +1748,8 @@ impl<'a> Parser<'a> { // Check for a type segment. if self.eat_lt() { // Consumed `a::b::<`, go look for types - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; + let (lifetimes, types, bindings) = self.parse_generic_args()?; + self.expect_gt()?; segments.push(ast::PathSegment { identifier: identifier, parameters: ast::AngleBracketedParameterData { @@ -1827,121 +1791,18 @@ impl<'a> Parser<'a> { } } - /// parses 0 or 1 lifetime - pub fn parse_opt_lifetime(&mut self) -> PResult<'a, Option> { + /// Parse single lifetime 'a or nothing. + pub fn eat_lifetime(&mut self) -> Option { match self.token { - token::Lifetime(..) => { - Ok(Some(self.parse_lifetime()?)) - } - _ => { - Ok(None) - } - } - } - - /// Parses a single lifetime - /// Matches lifetime = LIFETIME - pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> { - match self.token { - token::Lifetime(i) => { - let span = self.span; + token::Lifetime(ident) => { self.bump(); - return Ok(ast::Lifetime { + Some(Lifetime { id: ast::DUMMY_NODE_ID, - span: span, - name: i.name - }); + span: self.prev_span, + name: ident.name + }) } - _ => { - return Err(self.fatal("expected a lifetime name")); - } - } - } - - /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def = - /// lifetime [':' lifetimes]` - /// - /// If `followed_by_ty_params` is None, then we are in a context - /// where only lifetime parameters are allowed, and thus we should - /// error if we encounter attributes after the bound lifetimes. - /// - /// If `followed_by_ty_params` is Some(r), then there may be type - /// parameter bindings after the lifetimes, so we should pass - /// along the parsed attributes to be attached to the first such - /// type parmeter. - pub fn parse_lifetime_defs(&mut self, - followed_by_ty_params: Option<&mut Vec>) - -> PResult<'a, Vec> - { - let mut res = Vec::new(); - loop { - let attrs = self.parse_outer_attributes()?; - match self.token { - token::Lifetime(_) => { - let lifetime = self.parse_lifetime()?; - let bounds = - if self.eat(&token::Colon) { - self.parse_lifetimes(token::BinOp(token::Plus))? - } else { - Vec::new() - }; - res.push(ast::LifetimeDef { attrs: attrs.into(), - lifetime: lifetime, - bounds: bounds }); - } - - _ => { - if let Some(recv) = followed_by_ty_params { - assert!(recv.is_empty()); - *recv = attrs; - debug!("parse_lifetime_defs ret {:?}", res); - return Ok(res); - } else if !attrs.is_empty() { - let msg = "trailing attribute after lifetime parameters"; - return Err(self.fatal(msg)); - } - } - } - - match self.token { - token::Comma => { self.bump();} - token::Gt => { return Ok(res); } - token::BinOp(token::Shr) => { return Ok(res); } - _ => { - let this_token_str = self.this_token_to_string(); - let msg = format!("expected `,` or `>` after lifetime \ - name, found `{}`", - this_token_str); - return Err(self.fatal(&msg[..])); - } - } - } - } - - /// matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) actually, it matches the empty - /// one too, but putting that in there messes up the grammar.... - /// - /// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by - /// either a comma or `>`. Used when parsing type parameter lists, where we expect something - /// like `<'a, 'b, T>`. - pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult<'a, Vec> { - - let mut res = Vec::new(); - loop { - match self.token { - token::Lifetime(_) => { - res.push(self.parse_lifetime()?); - } - _ => { - return Ok(res); - } - } - - if self.token != sep { - return Ok(res); - } - - self.bump(); + _ => None } } @@ -2458,7 +2319,9 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; - self.parse_generic_values_after_lt()? + let args = self.parse_generic_args()?; + self.expect_gt()?; + args } else { (Vec::new(), Vec::new(), Vec::new()) }; @@ -4075,69 +3938,76 @@ impl<'a> Parser<'a> { }).emit(); } - // Parses a sequence of bounds if a `:` is found, - // otherwise returns empty list. - fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { - if !self.eat(&token::Colon) { - Ok(Vec::new()) - } else { - self.parse_ty_param_bounds() - } - } - - // matches bounds = ( boundseq )? - // where boundseq = ( polybound + boundseq ) | polybound - // and polybound = ( 'for' '<' 'region '>' )? bound - // and bound = 'region | trait_ref + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // BOUND = TY_BOUND | LT_BOUND + // LT_BOUND = LIFETIME (e.g. `'a`) + // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { - let mut result = vec![]; + let mut bounds = Vec::new(); loop { - let question_span = self.span; - let ate_question = self.eat(&token::Question); - match self.token { - token::Lifetime(lifetime) => { - if ate_question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - result.push(RegionTyParamBound(ast::Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.span, - name: lifetime.name - })); - self.bump(); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if let Some(lifetime) = self.eat_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); } - _ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => { - let poly_trait_ref = self.parse_poly_trait_ref()?; - let modifier = if ate_question { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - result.push(TraitTyParamBound(poly_trait_ref, modifier)) - } - _ => break, + bounds.push(RegionTyParamBound(lifetime)); + } else if self.token.is_keyword(keywords::For) || self.token.is_path_start() { + let poly_trait_ref = self.parse_poly_trait_ref()?; + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + } else { + break } - if !self.eat(&token::BinOp(token::Plus)) { - break; + // Trailing plus is not allowed for now and we have to detect it. + let is_bound_start = |token: &token::Token| { + token == &token::Question || token.is_lifetime() || + token.is_keyword(keywords::For) || token.is_path_start() + }; + if self.check(&token::BinOp(token::Plus)) && self.look_ahead(1, is_bound_start) { + self.bump(); + } else { + break } } - return Ok(result); + return Ok(bounds); + } + + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // BOUND = LT_BOUND (e.g. `'a`) + fn parse_lt_param_bounds(&mut self) -> Vec { + let mut lifetimes = Vec::new(); + while let Some(lifetime) = self.eat_lifetime() { + lifetimes.push(lifetime); + if self.check(&token::BinOp(token::Plus)) && self.look_ahead(1, |t| t.is_lifetime()) { + self.bump(); + } else { + break + } + } + lifetimes } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? - fn parse_ty_param(&mut self, preceding_attrs: Vec) -> PResult<'a, TyParam> { + fn parse_ty_param(&mut self, preceding_attrs: Vec) -> PResult<'a, TyParam> { let span = self.span; let ident = self.parse_ident()?; - let bounds = self.parse_colon_then_ty_param_bounds()?; + // Parse optional colon and param bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_ty_param_bounds()? + } else { + Vec::new() + }; - let default = if self.check(&token::Eq) { - self.bump(); + let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None @@ -4153,6 +4023,51 @@ impl<'a> Parser<'a> { }) } + /// Parses (possibly empty) list of lifetime and type parameters, possibly including + /// trailing comma and erroneous trailing attributes. + pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec, Vec)> { + let mut lifetime_defs = Vec::new(); + let mut ty_params = Vec::new(); + let mut seen_ty_param = false; + loop { + let attrs = self.parse_outer_attributes()?; + if let Some(lifetime) = self.eat_lifetime() { + // Parse lifetime parameter. + let bounds = if self.eat(&token::Colon) { + self.parse_lt_param_bounds() + } else { + Vec::new() + }; + lifetime_defs.push(LifetimeDef { + attrs: attrs.into(), + lifetime: lifetime, + bounds: bounds, + }); + if seen_ty_param { + self.span_err(self.prev_span, + "lifetime parameters must be declared prior to type parameters"); + } + } else if self.token.is_ident() { + // Parse type parameter. + ty_params.push(self.parse_ty_param(attrs)?); + seen_ty_param = true; + } else { + // Check for trailing attributes and stop parsing. + if !attrs.is_empty() { + let param_kind = if seen_ty_param { "type" } else { "lifetime" }; + self.span_err(attrs[0].span, + &format!("trailing attribute after {} parameters", param_kind)); + } + break + } + + if !self.eat(&token::Comma) { + break + } + } + Ok((lifetime_defs, ty_params)) + } + /// Parse a set of optional generic type parameter declarations. Where /// clauses are not parsed here, and must be added later via /// `parse_where_clause()`. @@ -4162,45 +4077,11 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; - if self.eat(&token::Lt) { - // Upon encountering attribute in generics list, we do not - // know if it is attached to lifetime or to type param. - // - // Solution: 1. eagerly parse attributes in tandem with - // lifetime defs, 2. store last set of parsed (and unused) - // attributes in `attrs`, and 3. pass in those attributes - // when parsing formal type param after lifetime defs. - let mut attrs = vec![]; - let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?; - let mut seen_default = false; - let mut post_lifetime_attrs = Some(attrs); - let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| { - p.forbid_lifetime()?; - // Move out of `post_lifetime_attrs` if present. O/w - // not first type param: parse attributes anew. - let attrs = match post_lifetime_attrs.as_mut() { - None => p.parse_outer_attributes()?, - Some(attrs) => mem::replace(attrs, vec![]), - }; - post_lifetime_attrs = None; - let ty_param = p.parse_ty_param(attrs)?; - if ty_param.default.is_some() { - seen_default = true; - } else if seen_default { - let prev_span = p.prev_span; - p.span_err(prev_span, - "type parameters with a default must be trailing"); - } - Ok(ty_param) - })?; - if let Some(attrs) = post_lifetime_attrs { - if !attrs.is_empty() { - self.span_err(attrs[0].span, - "trailing attribute after lifetime parameters"); - } - } + let span_lo = self.span.lo; + if self.eat_lt() { + let (lifetime_defs, ty_params) = self.parse_generic_params()?; + self.expect_gt()?; Ok(ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params, @@ -4215,85 +4096,53 @@ impl<'a> Parser<'a> { } } - fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec, - Vec>, - Vec)> { - let span_lo = self.span.lo; - let lifetimes = self.parse_lifetimes(token::Comma)?; - - let missing_comma = !lifetimes.is_empty() && - !self.token.is_like_gt() && - self.prev_token_kind != PrevTokenKind::Comma; - - if missing_comma { - - let msg = format!("expected `,` or `>` after lifetime \ - name, found `{}`", - self.this_token_to_string()); - let mut err = self.diagnostic().struct_span_err(self.span, &msg); - - let span_hi = self.span.hi; - let span_hi = match self.parse_ty_no_plus() { - Ok(..) => self.span.hi, - Err(ref mut err) => { - self.cancel(err); - span_hi + /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, + /// possibly including trailing comma. + fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec>, Vec)> { + let mut lifetimes = Vec::new(); + let mut types = Vec::new(); + let mut bindings = Vec::new(); + let mut seen_type = false; + let mut seen_binding = false; + loop { + let eq_is_next = self.look_ahead(1, |t| t == &token::Eq); // borrowck workaround + if let Some(lifetime) = self.eat_lifetime() { + // Parse lifetime argument. + lifetimes.push(lifetime); + if seen_type || seen_binding { + self.span_err(self.prev_span, + "lifetime parameters must be declared prior to type parameters"); } - }; - - let msg = format!("did you mean a single argument type &'a Type, \ - or did you mean the comma-separated arguments \ - 'a, Type?"); - err.span_note(mk_sp(span_lo, span_hi), &msg); - return Err(err); - } - - // First parse types. - let (types, returned) = self.parse_seq_to_gt_or_return( - Some(token::Comma), - |p| { - p.forbid_lifetime()?; - if p.look_ahead(1, |t| t == &token::Eq) { - Ok(None) - } else { - Ok(Some(p.parse_ty()?)) - } - } - )?; - - // If we found the `>`, don't continue. - if !returned { - return Ok((lifetimes, types, Vec::new())); - } - - // Then parse type bindings. - let bindings = self.parse_seq_to_gt( - Some(token::Comma), - |p| { - p.forbid_lifetime()?; - let lo = p.span.lo; - let ident = p.parse_ident()?; - p.expect(&token::Eq)?; - let ty = p.parse_ty_no_plus()?; - let hi = ty.span.hi; - let span = mk_sp(lo, hi); - return Ok(TypeBinding{id: ast::DUMMY_NODE_ID, + } else if self.token.is_ident() && eq_is_next { + // Parse associated type binding. + let lo = self.span.lo; + let ident = self.parse_ident()?; + self.bump(); + let ty = self.parse_ty()?; + bindings.push(TypeBinding { + id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: span, + span: mk_sp(lo, self.prev_span.hi), }); + seen_binding = true; + } else if self.token.can_begin_type() { + // Parse type argument. + types.push(self.parse_ty()?); + if seen_binding { + self.span_err(types[types.len() - 1].span, + "type parameters must be declared prior to associated type bindings"); + } + seen_type = true; + } else { + break } - )?; - Ok((lifetimes, types, bindings)) - } - fn forbid_lifetime(&mut self) -> PResult<'a, ()> { - if self.token.is_lifetime() { - let span = self.span; - return Err(self.diagnostic().struct_span_err(span, "lifetime parameters must be \ - declared prior to type parameters")) + if !self.eat(&token::Comma) { + break + } } - Ok(()) + Ok((lifetimes, types, bindings)) } /// Parses an optional `where` clause and places it in `generics`. @@ -4301,7 +4150,7 @@ impl<'a> Parser<'a> { /// ```ignore /// where T : Trait + 'b, 'a : 'b /// ``` - pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> { + pub fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { maybe_whole!(self, NtWhereClause, |x| x); let mut where_clause = WhereClause { @@ -4313,7 +4162,7 @@ impl<'a> Parser<'a> { return Ok(where_clause); } - // This is a temporary hack. + // This is a temporary future proofing. // // We are considering adding generics to the `where` keyword as an alternative higher-rank // parameter syntax (as in `where<'a>` or `where`. To avoid that being a breaking @@ -4330,106 +4179,64 @@ impl<'a> Parser<'a> { } } - let mut parsed_something = false; loop { let lo = self.span.lo; - match self.token { - token::OpenDelim(token::Brace) => { - break - } + if let Some(lifetime) = self.eat_lifetime() { + // Bounds starting with a colon are mandatory, but possibly empty. + self.expect(&token::Colon)?; + let bounds = self.parse_lt_param_bounds(); + where_clause.predicates.push(ast::WherePredicate::RegionPredicate( + ast::WhereRegionPredicate { + span: mk_sp(lo, self.prev_span.hi), + lifetime: lifetime, + bounds: bounds, + } + )); + } else if self.token.can_begin_type() { + // Parse optional `for<'a, 'b>`. + // This `for` is parsed greedily and applies to the whole predicate, + // the bounded type can have its own `for` applying only to it. + // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/> + // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/> + // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/> + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - token::Lifetime(..) => { - let bounded_lifetime = - self.parse_lifetime()?; - - self.expect(&token::Colon)?; - - let bounds = - self.parse_lifetimes(token::BinOp(token::Plus))?; - - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - - where_clause.predicates.push(ast::WherePredicate::RegionPredicate( - ast::WhereRegionPredicate { - span: span, - lifetime: bounded_lifetime, - bounds: bounds + // Parse type with mandatory colon and (possibly empty) bounds, + // or with mandatory equality sign and the second type. + let ty = self.parse_ty()?; + if self.eat(&token::Colon) { + let bounds = self.parse_ty_param_bounds()?; + where_clause.predicates.push(ast::WherePredicate::BoundPredicate( + ast::WhereBoundPredicate { + span: mk_sp(lo, self.prev_span.hi), + bound_lifetimes: lifetime_defs, + bounded_ty: ty, + bounds: bounds, } )); - - parsed_something = true; - } - - _ => { - let bound_lifetimes = if self.eat_keyword(keywords::For) { - // Higher ranked constraint. - self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs(None)?; - self.expect_gt()?; - lifetime_defs - } else { - vec![] - }; - - let bounded_ty = self.parse_ty_no_plus()?; - - if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds()?; - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - - if bounds.is_empty() { - self.span_err(span, - "each predicate in a `where` clause must have \ - at least one bound in it"); + // FIXME: Decide what should be used here, `=` or `==`. + } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { + let rhs_ty = self.parse_ty()?; + where_clause.predicates.push(ast::WherePredicate::EqPredicate( + ast::WhereEqPredicate { + span: mk_sp(lo, self.prev_span.hi), + lhs_ty: ty, + rhs_ty: rhs_ty, + id: ast::DUMMY_NODE_ID, } - - where_clause.predicates.push(ast::WherePredicate::BoundPredicate( - ast::WhereBoundPredicate { - span: span, - bound_lifetimes: bound_lifetimes, - bounded_ty: bounded_ty, - bounds: bounds, - })); - - parsed_something = true; - } else if self.eat(&token::Eq) { - // let ty = try!(self.parse_ty_no_plus()); - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - // where_clause.predicates.push( - // ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - // id: ast::DUMMY_NODE_ID, - // span: span, - // path: panic!("NYI"), //bounded_ty, - // ty: ty, - // })); - // parsed_something = true; - // // FIXME(#18433) - self.span_err(span, - "equality constraints are not yet supported \ - in where clauses (#20041)"); - } else { - let prev_span = self.prev_span; - self.span_err(prev_span, - "unexpected token in `where` clause"); - } + )); + } else { + return self.unexpected(); } - }; + } else { + break + } if !self.eat(&token::Comma) { break } } - if !parsed_something { - let prev_span = self.prev_span; - self.span_err(prev_span, - "a `where` clause must have at least one predicate \ - in it"); - } - Ok(where_clause) } @@ -4528,13 +4335,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.parse_lifetime()?; + let lt = self.eat_lifetime().expect("not a lifetime"); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.parse_lifetime()?; + let lt = self.eat_lifetime().expect("not a lifetime"); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4836,8 +4643,12 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; - // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds()?; + // Parse optional colon and supertrait bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_ty_param_bounds()? + } else { + Vec::new() + }; tps.where_clause = self.parse_where_clause()?; @@ -4928,17 +4739,21 @@ impl<'a> Parser<'a> { /// Parse a::B fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(ast::TraitRef { + Ok(TraitRef { path: self.parse_path(PathStyle::Type)?, ref_id: ast::DUMMY_NODE_ID, }) } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { + fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(keywords::For) { - self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs(None)?; + self.expect_lt()?; + let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; + if !ty_params.is_empty() { + self.span_err(ty_params[0].span, + "only lifetime parameters can be used in this context"); + } Ok(lifetime_defs) } else { Ok(Vec::new()) @@ -4950,7 +4765,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - Ok(ast::PolyTraitRef { + Ok(PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: self.parse_trait_ref()?, span: mk_sp(lo, self.prev_span.hi), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bf790b96e37f..d9e47a6b56e8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -187,6 +187,29 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of a type. + pub fn can_begin_type(&self) -> bool { + match *self { + OpenDelim(Paren) => true, // tuple + OpenDelim(Bracket) => true, // array + Ident(..) => true, // type name or keyword + Underscore => true, // placeholder + Not => true, // never + BinOp(Star) => true, // raw pointer + BinOp(And) => true, // reference + AndAnd => true, // double reference + Lt | BinOp(Shl) => true, // associated path + ModSep => true, // global path + Interpolated(ref nt) => match **nt { + NtTy(..) => true, + NtIdent(..) => true, + NtPath(..) => true, + _ => false, + }, + _ => false, + } + } + /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs index a38a7bfb9378..5e09473ab77d 100644 --- a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs @@ -17,10 +17,7 @@ struct RefAny<'a, T>(&'a T); -impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> { - //~^ ERROR expected identifier, found `>` -} +impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {} +//~^ ERROR trailing attribute after type parameters -fn main() { - -} +fn main() {} diff --git a/src/test/compile-fail/generic-non-trailing-defaults.rs b/src/test/compile-fail/generic-non-trailing-defaults.rs new file mode 100644 index 000000000000..77e552032637 --- /dev/null +++ b/src/test/compile-fail/generic-non-trailing-defaults.rs @@ -0,0 +1,20 @@ +// Copyright 2014 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. + +struct Heap; + +struct Vec; +//~^ ERROR type parameters with a default must be trailing + +struct Foo, C>; +//~^ ERROR type parameters with a default must be trailing +//~| ERROR type parameters with a default cannot use forward declared identifiers + +fn main() {} diff --git a/src/test/compile-fail/issue-20616-1.rs b/src/test/compile-fail/issue-20616-1.rs index 5b4f9942d28b..a1949df661a3 100644 --- a/src/test/compile-fail/issue-20616-1.rs +++ b/src/test/compile-fail/issue-20616-1.rs @@ -16,7 +16,7 @@ type Type_1_<'a, T> = &'a T; -type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T` +type Type_1<'a T> = &'a T; //~ error: expected one of `,`, `:`, or `>`, found `T` //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(` diff --git a/src/test/compile-fail/issue-20616-2.rs b/src/test/compile-fail/issue-20616-2.rs index 65305ff3ac82..87b836d68727 100644 --- a/src/test/compile-fail/issue-20616-2.rs +++ b/src/test/compile-fail/issue-20616-2.rs @@ -19,7 +19,7 @@ type Type_1_<'a, T> = &'a T; //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T` -type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(` +type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(` //type Type_3 = Box; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs index 101f81019d97..9a5972a7a164 100644 --- a/src/test/compile-fail/issue-20616-3.rs +++ b/src/test/compile-fail/issue-20616-3.rs @@ -22,7 +22,7 @@ type Type_1_<'a, T> = &'a T; //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(` -type Type_3 = Box; //~ error: expected type, found `,` +type Type_3 = Box; //~ error: expected `>`, found `,` //type Type_4 = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs index 6450e9ed68cb..1567698e476b 100644 --- a/src/test/compile-fail/issue-20616-4.rs +++ b/src/test/compile-fail/issue-20616-4.rs @@ -25,7 +25,7 @@ type Type_1_<'a, T> = &'a T; //type Type_3 = Box; // error: expected type, found `,` -type Type_4 = Type_1_<'static,, T>; //~ error: expected type, found `,` +type Type_4 = Type_1_<'static,, T>; //~ error: expected `>`, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs index d1840427ad8b..c5a0624574d0 100644 --- a/src/test/compile-fail/issue-20616-5.rs +++ b/src/test/compile-fail/issue-20616-5.rs @@ -31,7 +31,7 @@ type Type_1_<'a, T> = &'a T; type Type_5_<'a> = Type_1_<'a, ()>; -type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,` +type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected `>`, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs index b0b5bc653f6d..56578409546f 100644 --- a/src/test/compile-fail/issue-20616-6.rs +++ b/src/test/compile-fail/issue-20616-6.rs @@ -34,7 +34,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,` -type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,` +type Type_6 = Type_5_<'a,,>; //~ error: expected `>`, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs index 0958f8b4ed22..ecd0a467cf6b 100644 --- a/src/test/compile-fail/issue-20616-7.rs +++ b/src/test/compile-fail/issue-20616-7.rs @@ -37,7 +37,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` -type Type_7 = Box<(),,>; //~ error: expected type, found `,` +type Type_7 = Box<(),,>; //~ error: expected `>`, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs index d6cf9acae9b0..535672c65e46 100644 --- a/src/test/compile-fail/issue-20616-8.rs +++ b/src/test/compile-fail/issue-20616-8.rs @@ -40,7 +40,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_7 = Box<(),,>; // error: expected type, found `,` -type Type_8<'a,,> = &'a (); //~ error: expected identifier, found `,` +type Type_8<'a,,> = &'a (); //~ error: expected `>`, found `,` //type Type_9 = Box; // error: expected identifier, found `,` diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs index d64cec446ef3..b666a8b67aa3 100644 --- a/src/test/compile-fail/issue-20616-9.rs +++ b/src/test/compile-fail/issue-20616-9.rs @@ -43,4 +43,4 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_8<'a,,> = &'a (); // error: expected identifier, found `,` -type Type_9 = Box; //~ error: expected identifier, found `,` +type Type_9 = Box; //~ error: expected `>`, found `,` diff --git a/src/test/parse-fail/issue-14303-path.rs b/src/test/parse-fail/issue-14303-path.rs index 431a917c2d9f..f0d1feffec80 100644 --- a/src/test/parse-fail/issue-14303-path.rs +++ b/src/test/parse-fail/issue-14303-path.rs @@ -12,4 +12,3 @@ fn bar<'a, T>(x: mymodule::X<'a, T, 'b, 'c>) {} //~^ ERROR lifetime parameters must be declared prior to type parameters -//~^^ ERROR expected pattern, found `'c` diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/issue-17904-2.rs similarity index 74% rename from src/test/parse-fail/generic-non-trailing-defaults.rs rename to src/test/parse-fail/issue-17904-2.rs index 2bb593258ae4..3f41c0edd2e6 100644 --- a/src/test/parse-fail/generic-non-trailing-defaults.rs +++ b/src/test/parse-fail/issue-17904-2.rs @@ -10,10 +10,6 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error -struct Heap; - -struct Vec; //~ ERROR type parameters with a default must be trailing - -struct Foo, C>; //~ ERROR type parameters with a default must be trailing +struct Bar { x: T } where T: Copy //~ ERROR expected item, found `where` fn main() {} diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index de5aeb02ab78..ae28ac76acb9 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -13,7 +13,6 @@ struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. -struct Foo where T: Copy, (T); //~ ERROR unexpected token in `where` clause -struct Bar { x: T } where T: Copy //~ ERROR expected item, found `where` +struct Foo where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;` fn main() {} diff --git a/src/test/parse-fail/issue-32214.rs b/src/test/parse-fail/issue-32214.rs index 3ba59c8ee946..9e2000940936 100644 --- a/src/test/parse-fail/issue-32214.rs +++ b/src/test/parse-fail/issue-32214.rs @@ -10,8 +10,7 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error -pub fn test >() { - //~^ ERROR expected `=`, found `>` -} +pub fn test >() {} +//~^ ERROR type parameters must be declared prior to associated type bindings fn main() { } diff --git a/src/test/parse-fail/lifetime-semicolon.rs b/src/test/parse-fail/lifetime-semicolon.rs index 7010d0e7debf..e1975952fca3 100644 --- a/src/test/parse-fail/lifetime-semicolon.rs +++ b/src/test/parse-fail/lifetime-semicolon.rs @@ -15,5 +15,4 @@ struct Foo<'a, 'b> { } fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} -//~^ ERROR expected `,` or `>` after lifetime name, found `;` -//~^^ NOTE did you mean a single argument type &'a Type, or did you mean the comma-separated +//~^ ERROR expected one of `,` or `>`, found `;` diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs index 78d974540873..cf67b518fff9 100644 --- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs @@ -10,13 +10,13 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error +// Empty predicate list is OK fn equal1(_: &T, _: &T) -> bool where { -//~^ ERROR a `where` clause must have at least one predicate in it true } +// Empty bound list is OK fn equal2(_: &T, _: &T) -> bool where T: { -//~^ ERROR each predicate in a `where` clause must have at least one bound true } From a8f5047430aa78c2d1ff30b5960cdbde24daab84 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Jan 2017 17:41:57 +0300 Subject: [PATCH 006/104] Add tests --- src/test/compile-fail/impl-trait/no-trait.rs | 15 ++++++++++++ .../where-equality-constraints.rs | 16 +++++++++++++ .../compile-fail/where-lifetime-resolution.rs | 23 +++++++++++++++++++ src/test/parse-fail/bounds-lifetime-1.rs | 15 ++++++++++++ src/test/parse-fail/bounds-lifetime-2.rs | 15 ++++++++++++ src/test/parse-fail/bounds-lifetime-3.rs | 15 ++++++++++++ .../parse-fail/bounds-lifetime-where-1.rs | 15 ++++++++++++ .../parse-fail/bounds-lifetime-where-2.rs | 15 ++++++++++++ src/test/parse-fail/bounds-lifetime-where.rs | 21 +++++++++++++++++ src/test/parse-fail/bounds-lifetime.rs | 23 +++++++++++++++++++ src/test/parse-fail/bounds-type-where-1.rs | 16 +++++++++++++ src/test/parse-fail/bounds-type-where.rs | 21 +++++++++++++++++ src/test/parse-fail/bounds-type.rs | 23 +++++++++++++++++++ 13 files changed, 233 insertions(+) create mode 100644 src/test/compile-fail/impl-trait/no-trait.rs create mode 100644 src/test/compile-fail/where-equality-constraints.rs create mode 100644 src/test/compile-fail/where-lifetime-resolution.rs create mode 100644 src/test/parse-fail/bounds-lifetime-1.rs create mode 100644 src/test/parse-fail/bounds-lifetime-2.rs create mode 100644 src/test/parse-fail/bounds-lifetime-3.rs create mode 100644 src/test/parse-fail/bounds-lifetime-where-1.rs create mode 100644 src/test/parse-fail/bounds-lifetime-where-2.rs create mode 100644 src/test/parse-fail/bounds-lifetime-where.rs create mode 100644 src/test/parse-fail/bounds-lifetime.rs create mode 100644 src/test/parse-fail/bounds-type-where-1.rs create mode 100644 src/test/parse-fail/bounds-type-where.rs create mode 100644 src/test/parse-fail/bounds-type.rs diff --git a/src/test/compile-fail/impl-trait/no-trait.rs b/src/test/compile-fail/impl-trait/no-trait.rs new file mode 100644 index 000000000000..ce61c5bf63d8 --- /dev/null +++ b/src/test/compile-fail/impl-trait/no-trait.rs @@ -0,0 +1,15 @@ +// 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. + +#![feature(conservative_impl_trait)] + +fn f() -> impl 'static {} //~ ERROR at least one trait must be specified + +fn main() {} diff --git a/src/test/compile-fail/where-equality-constraints.rs b/src/test/compile-fail/where-equality-constraints.rs new file mode 100644 index 000000000000..5b2fe2901c4c --- /dev/null +++ b/src/test/compile-fail/where-equality-constraints.rs @@ -0,0 +1,16 @@ +// 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. + +fn f() where u8 = u16 {} +//~^ ERROR equality constraints are not yet supported in where clauses +fn g() where for<'a> &(u8,) == u16, {} +//~^ ERROR equality constraints are not yet supported in where clauses + +fn main() {} diff --git a/src/test/compile-fail/where-lifetime-resolution.rs b/src/test/compile-fail/where-lifetime-resolution.rs new file mode 100644 index 000000000000..f4c6842206db --- /dev/null +++ b/src/test/compile-fail/where-lifetime-resolution.rs @@ -0,0 +1,23 @@ +// 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. + +trait Trait1 {} +trait Trait2 {} + +fn f() where + for<'a> Trait1<'a>: Trait1<'a>, // OK + (for<'a> Trait1<'a>): Trait1<'a>, + //~^ ERROR use of undeclared lifetime name `'a` + for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + //~^ ERROR use of undeclared lifetime name `'b` + //~| ERROR nested quantification of lifetimes +{} + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-1.rs b/src/test/parse-fail/bounds-lifetime-1.rs new file mode 100644 index 000000000000..824d243d5f84 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-1.rs @@ -0,0 +1,15 @@ +// 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. + +// compile-flags: -Z parse-only + +type A = for<'a 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `'b` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-2.rs b/src/test/parse-fail/bounds-lifetime-2.rs new file mode 100644 index 000000000000..3c67dda70f56 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-2.rs @@ -0,0 +1,15 @@ +// 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. + +// compile-flags: -Z parse-only + +type A = for<'a + 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `+` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-3.rs b/src/test/parse-fail/bounds-lifetime-3.rs new file mode 100644 index 000000000000..be7c197245e4 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-3.rs @@ -0,0 +1,15 @@ +// 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. + +// compile-flags: -Z parse-only + +type A = for<,> fn(); //~ ERROR expected `>`, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where-1.rs b/src/test/parse-fail/bounds-lifetime-where-1.rs new file mode 100644 index 000000000000..aae9d7299875 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-where-1.rs @@ -0,0 +1,15 @@ +// 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. + +// compile-flags: -Z parse-only + +type A where 'a; //~ ERROR expected `:`, found `;` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where-2.rs b/src/test/parse-fail/bounds-lifetime-where-2.rs new file mode 100644 index 000000000000..97dcd5cc5f8c --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-where-2.rs @@ -0,0 +1,15 @@ +// 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. + +// compile-flags: -Z parse-only + +type A where , = u8; //~ ERROR expected `=`, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where.rs b/src/test/parse-fail/bounds-lifetime-where.rs new file mode 100644 index 000000000000..f7f56446006a --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-where.rs @@ -0,0 +1,21 @@ +// 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. + +// compile-flags: -Z parse-only + +type A where 'a: 'b + 'c = u8; // OK +type A where 'a: 'b, = u8; // OK +type A where 'a: = u8; // OK +type A where 'a:, = u8; // OK +type A where 'a: 'b + 'c = u8; // OK +type A where = u8; // OK +type A where 'a: 'b + = u8; //~ ERROR expected one of `,` or `=`, found `+` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime.rs b/src/test/parse-fail/bounds-lifetime.rs new file mode 100644 index 000000000000..71547b543c35 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime.rs @@ -0,0 +1,23 @@ +// 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. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +type A = for<'a: 'b + 'c> fn(); // OK +type A = for<'a: 'b,> fn(); // OK +type A = for<'a:> fn(); // OK +type A = for<'a:,> fn(); // OK +type A = for<'a> fn(); // OK +type A = for<> fn(); // OK + +type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context +type A = for<'a: 'b +> fn(); //~ ERROR expected one of `,` or `>`, found `+` + +fn main() {} diff --git a/src/test/parse-fail/bounds-type-where-1.rs b/src/test/parse-fail/bounds-type-where-1.rs new file mode 100644 index 000000000000..52b5035abda3 --- /dev/null +++ b/src/test/parse-fail/bounds-type-where-1.rs @@ -0,0 +1,16 @@ +// 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. + +// compile-flags: -Z parse-only + +type A where T, = u8; +//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-type-where.rs b/src/test/parse-fail/bounds-type-where.rs new file mode 100644 index 000000000000..789a0934a83c --- /dev/null +++ b/src/test/parse-fail/bounds-type-where.rs @@ -0,0 +1,21 @@ +// 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. + +// compile-flags: -Z parse-only + +type A where for<'a> for<'b> Trait1 + ?Trait2: 'a + Trait = u8; // OK +type A where T: Trait, = u8; // OK +type A where T: = u8; // OK +type A where T:, = u8; // OK +type A where T: Trait + Trait = u8; // OK +type A where = u8; // OK +type A where T: Trait + = u8; //~ ERROR expected one of `(`, `,`, `::`, `<`, or `=`, found `+` + +fn main() {} diff --git a/src/test/parse-fail/bounds-type.rs b/src/test/parse-fail/bounds-type.rs new file mode 100644 index 000000000000..6e339429eed3 --- /dev/null +++ b/src/test/parse-fail/bounds-type.rs @@ -0,0 +1,23 @@ +// 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. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +struct S< + T: 'a + Tr, // OK + T: Tr + 'a, // OK + T: 'a, // OK + T:, // OK + T: ?for<'a: 'b + 'c> Trait, // OK + T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds + T: Tr +, //~ ERROR expected one of `(`, `,`, `::`, `<`, `=`, or `>`, found `+` +>; + +fn main() {} From 375cb2eec70f239b477c6b88852c8258765b5420 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Jan 2017 19:01:04 +0300 Subject: [PATCH 007/104] Improve some expected/found error messages from parser --- src/libsyntax/parse/parser.rs | 61 +++++++++++++++---- src/test/compile-fail/issue-20616-3.rs | 2 +- src/test/compile-fail/issue-20616-4.rs | 3 +- src/test/compile-fail/issue-20616-5.rs | 3 +- src/test/compile-fail/issue-20616-6.rs | 3 +- src/test/compile-fail/issue-20616-7.rs | 2 +- src/test/compile-fail/issue-20616-8.rs | 2 +- src/test/compile-fail/issue-20616-9.rs | 2 +- src/test/parse-fail/bounds-lifetime-3.rs | 2 +- .../parse-fail/bounds-lifetime-where-2.rs | 2 +- 10 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c589f1a7aaaa..939f126640d9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -192,14 +192,22 @@ pub enum TokenType { Token(token::Token), Keyword(keywords::Keyword), Operator, + Lifetime, + Ident, + Path, + Type, } impl TokenType { fn to_string(&self) -> String { match *self { TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)), - TokenType::Operator => "an operator".to_string(), TokenType::Keyword(kw) => format!("`{}`", kw.name()), + TokenType::Operator => "an operator".to_string(), + TokenType::Lifetime => "lifetime".to_string(), + TokenType::Ident => "identifier".to_string(), + TokenType::Path => "path".to_string(), + TokenType::Type => "type".to_string(), } } } @@ -552,6 +560,33 @@ impl<'a> Parser<'a> { } } + fn check_ident(&mut self) -> bool { + if self.token.is_ident() { + true + } else { + self.expected_tokens.push(TokenType::Ident); + false + } + } + + fn check_path(&mut self) -> bool { + if self.token.is_path_start() { + true + } else { + self.expected_tokens.push(TokenType::Path); + false + } + } + + fn check_type(&mut self) -> bool { + if self.token.can_begin_type() { + true + } else { + self.expected_tokens.push(TokenType::Type); + false + } + } + /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. fn expect_and(&mut self) -> PResult<'a, ()> { @@ -1802,7 +1837,10 @@ impl<'a> Parser<'a> { name: ident.name }) } - _ => None + _ => { + self.expected_tokens.push(TokenType::Lifetime); + None + } } } @@ -3953,7 +3991,7 @@ impl<'a> Parser<'a> { "`?` may only modify trait bounds, not lifetime bounds"); } bounds.push(RegionTyParamBound(lifetime)); - } else if self.token.is_keyword(keywords::For) || self.token.is_path_start() { + } else {if self.check_keyword(keywords::For) || self.check_path() { let poly_trait_ref = self.parse_poly_trait_ref()?; let modifier = if question.is_some() { TraitBoundModifier::Maybe @@ -3963,7 +4001,7 @@ impl<'a> Parser<'a> { bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); } else { break - } + }} // Trailing plus is not allowed for now and we have to detect it. let is_bound_start = |token: &token::Token| { @@ -4047,7 +4085,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else if self.token.is_ident() { + } else {if self.check_ident() { // Parse type parameter. ty_params.push(self.parse_ty_param(attrs)?); seen_ty_param = true; @@ -4059,7 +4097,7 @@ impl<'a> Parser<'a> { &format!("trailing attribute after {} parameters", param_kind)); } break - } + }} if !self.eat(&token::Comma) { break @@ -4105,7 +4143,6 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - let eq_is_next = self.look_ahead(1, |t| t == &token::Eq); // borrowck workaround if let Some(lifetime) = self.eat_lifetime() { // Parse lifetime argument. lifetimes.push(lifetime); @@ -4113,7 +4150,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else if self.token.is_ident() && eq_is_next { + } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. let lo = self.span.lo; let ident = self.parse_ident()?; @@ -4126,7 +4163,7 @@ impl<'a> Parser<'a> { span: mk_sp(lo, self.prev_span.hi), }); seen_binding = true; - } else if self.token.can_begin_type() { + } else if self.check_type() { // Parse type argument. types.push(self.parse_ty()?); if seen_binding { @@ -4136,7 +4173,7 @@ impl<'a> Parser<'a> { seen_type = true; } else { break - } + }} if !self.eat(&token::Comma) { break @@ -4192,7 +4229,7 @@ impl<'a> Parser<'a> { bounds: bounds, } )); - } else if self.token.can_begin_type() { + } else {if self.check_type() { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. @@ -4230,7 +4267,7 @@ impl<'a> Parser<'a> { } } else { break - } + }} if !self.eat(&token::Comma) { break diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs index 9a5972a7a164..e5ed46d2cb3b 100644 --- a/src/test/compile-fail/issue-20616-3.rs +++ b/src/test/compile-fail/issue-20616-3.rs @@ -22,7 +22,7 @@ type Type_1_<'a, T> = &'a T; //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(` -type Type_3 = Box; //~ error: expected `>`, found `,` +type Type_3 = Box; //~ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_4 = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs index 1567698e476b..9b731289e138 100644 --- a/src/test/compile-fail/issue-20616-4.rs +++ b/src/test/compile-fail/issue-20616-4.rs @@ -25,7 +25,8 @@ type Type_1_<'a, T> = &'a T; //type Type_3 = Box; // error: expected type, found `,` -type Type_4 = Type_1_<'static,, T>; //~ error: expected `>`, found `,` +type Type_4 = Type_1_<'static,, T>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs index c5a0624574d0..5e3b024da9a0 100644 --- a/src/test/compile-fail/issue-20616-5.rs +++ b/src/test/compile-fail/issue-20616-5.rs @@ -31,7 +31,8 @@ type Type_1_<'a, T> = &'a T; type Type_5_<'a> = Type_1_<'a, ()>; -type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected `>`, found `,` +type Type_5<'a> = Type_1_<'a, (),,>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs index 56578409546f..b6ee26f9f62b 100644 --- a/src/test/compile-fail/issue-20616-6.rs +++ b/src/test/compile-fail/issue-20616-6.rs @@ -34,7 +34,8 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,` -type Type_6 = Type_5_<'a,,>; //~ error: expected `>`, found `,` +type Type_6 = Type_5_<'a,,>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs index ecd0a467cf6b..fef3dd4e31d5 100644 --- a/src/test/compile-fail/issue-20616-7.rs +++ b/src/test/compile-fail/issue-20616-7.rs @@ -37,7 +37,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` -type Type_7 = Box<(),,>; //~ error: expected `>`, found `,` +type Type_7 = Box<(),,>; //~ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs index 535672c65e46..b7bef47c4f44 100644 --- a/src/test/compile-fail/issue-20616-8.rs +++ b/src/test/compile-fail/issue-20616-8.rs @@ -40,7 +40,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_7 = Box<(),,>; // error: expected type, found `,` -type Type_8<'a,,> = &'a (); //~ error: expected `>`, found `,` +type Type_8<'a,,> = &'a (); //~ error: expected one of `>`, identifier, or lifetime, found `,` //type Type_9 = Box; // error: expected identifier, found `,` diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs index b666a8b67aa3..5c16d24cef85 100644 --- a/src/test/compile-fail/issue-20616-9.rs +++ b/src/test/compile-fail/issue-20616-9.rs @@ -43,4 +43,4 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_8<'a,,> = &'a (); // error: expected identifier, found `,` -type Type_9 = Box; //~ error: expected `>`, found `,` +type Type_9 = Box; //~ error: expected one of `>`, identifier, or lifetime, found `,` diff --git a/src/test/parse-fail/bounds-lifetime-3.rs b/src/test/parse-fail/bounds-lifetime-3.rs index be7c197245e4..e04431598156 100644 --- a/src/test/parse-fail/bounds-lifetime-3.rs +++ b/src/test/parse-fail/bounds-lifetime-3.rs @@ -10,6 +10,6 @@ // compile-flags: -Z parse-only -type A = for<,> fn(); //~ ERROR expected `>`, found `,` +type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,` fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where-2.rs b/src/test/parse-fail/bounds-lifetime-where-2.rs index 97dcd5cc5f8c..ffcacdf357df 100644 --- a/src/test/parse-fail/bounds-lifetime-where-2.rs +++ b/src/test/parse-fail/bounds-lifetime-where-2.rs @@ -10,6 +10,6 @@ // compile-flags: -Z parse-only -type A where , = u8; //~ ERROR expected `=`, found `,` +type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` fn main() {} From 65aeafa24f1542c23643a67172b7b2fec4f290cc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 24 Jan 2017 22:55:45 +0300 Subject: [PATCH 008/104] parser: Permit trailing +'s in bound lists --- src/libsyntax/parse/parser.rs | 14 +++----------- src/test/parse-fail/bounds-lifetime-3.rs | 15 --------------- src/test/parse-fail/bounds-lifetime-where-2.rs | 15 --------------- src/test/parse-fail/bounds-lifetime-where.rs | 3 ++- src/test/parse-fail/bounds-lifetime.rs | 3 ++- src/test/parse-fail/bounds-type-where-1.rs | 16 ---------------- src/test/parse-fail/bounds-type-where.rs | 4 +++- src/test/parse-fail/bounds-type.rs | 2 +- 8 files changed, 11 insertions(+), 61 deletions(-) delete mode 100644 src/test/parse-fail/bounds-lifetime-3.rs delete mode 100644 src/test/parse-fail/bounds-lifetime-where-2.rs delete mode 100644 src/test/parse-fail/bounds-type-where-1.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 939f126640d9..9e3c1dcef8a6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4003,14 +4003,7 @@ impl<'a> Parser<'a> { break }} - // Trailing plus is not allowed for now and we have to detect it. - let is_bound_start = |token: &token::Token| { - token == &token::Question || token.is_lifetime() || - token.is_keyword(keywords::For) || token.is_path_start() - }; - if self.check(&token::BinOp(token::Plus)) && self.look_ahead(1, is_bound_start) { - self.bump(); - } else { + if !self.eat(&token::BinOp(token::Plus)) { break } } @@ -4024,9 +4017,8 @@ impl<'a> Parser<'a> { let mut lifetimes = Vec::new(); while let Some(lifetime) = self.eat_lifetime() { lifetimes.push(lifetime); - if self.check(&token::BinOp(token::Plus)) && self.look_ahead(1, |t| t.is_lifetime()) { - self.bump(); - } else { + + if !self.eat(&token::BinOp(token::Plus)) { break } } diff --git a/src/test/parse-fail/bounds-lifetime-3.rs b/src/test/parse-fail/bounds-lifetime-3.rs deleted file mode 100644 index e04431598156..000000000000 --- a/src/test/parse-fail/bounds-lifetime-3.rs +++ /dev/null @@ -1,15 +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. - -// compile-flags: -Z parse-only - -type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,` - -fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where-2.rs b/src/test/parse-fail/bounds-lifetime-where-2.rs deleted file mode 100644 index ffcacdf357df..000000000000 --- a/src/test/parse-fail/bounds-lifetime-where-2.rs +++ /dev/null @@ -1,15 +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. - -// compile-flags: -Z parse-only - -type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` - -fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where.rs b/src/test/parse-fail/bounds-lifetime-where.rs index f7f56446006a..0a30818bc96a 100644 --- a/src/test/parse-fail/bounds-lifetime-where.rs +++ b/src/test/parse-fail/bounds-lifetime-where.rs @@ -16,6 +16,7 @@ type A where 'a: = u8; // OK type A where 'a:, = u8; // OK type A where 'a: 'b + 'c = u8; // OK type A where = u8; // OK -type A where 'a: 'b + = u8; //~ ERROR expected one of `,` or `=`, found `+` +type A where 'a: 'b + = u8; // OK +type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime.rs b/src/test/parse-fail/bounds-lifetime.rs index 71547b543c35..5113a6b4803f 100644 --- a/src/test/parse-fail/bounds-lifetime.rs +++ b/src/test/parse-fail/bounds-lifetime.rs @@ -16,8 +16,9 @@ type A = for<'a:> fn(); // OK type A = for<'a:,> fn(); // OK type A = for<'a> fn(); // OK type A = for<> fn(); // OK +type A = for<'a: 'b +> fn(); // OK type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context -type A = for<'a: 'b +> fn(); //~ ERROR expected one of `,` or `>`, found `+` +type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,` fn main() {} diff --git a/src/test/parse-fail/bounds-type-where-1.rs b/src/test/parse-fail/bounds-type-where-1.rs deleted file mode 100644 index 52b5035abda3..000000000000 --- a/src/test/parse-fail/bounds-type-where-1.rs +++ /dev/null @@ -1,16 +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. - -// compile-flags: -Z parse-only - -type A where T, = u8; -//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,` - -fn main() {} diff --git a/src/test/parse-fail/bounds-type-where.rs b/src/test/parse-fail/bounds-type-where.rs index 789a0934a83c..9dc5d8277446 100644 --- a/src/test/parse-fail/bounds-type-where.rs +++ b/src/test/parse-fail/bounds-type-where.rs @@ -16,6 +16,8 @@ type A where T: = u8; // OK type A where T:, = u8; // OK type A where T: Trait + Trait = u8; // OK type A where = u8; // OK -type A where T: Trait + = u8; //~ ERROR expected one of `(`, `,`, `::`, `<`, or `=`, found `+` +type A where T: Trait + = u8; // OK +type A where T, = u8; +//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,` fn main() {} diff --git a/src/test/parse-fail/bounds-type.rs b/src/test/parse-fail/bounds-type.rs index 6e339429eed3..c224b44a14bf 100644 --- a/src/test/parse-fail/bounds-type.rs +++ b/src/test/parse-fail/bounds-type.rs @@ -16,8 +16,8 @@ struct S< T: 'a, // OK T:, // OK T: ?for<'a: 'b + 'c> Trait, // OK + T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds - T: Tr +, //~ ERROR expected one of `(`, `,`, `::`, `<`, `=`, or `>`, found `+` >; fn main() {} From b996a7ecec4bb22a28bce3b86f68fe51b4409287 Mon Sep 17 00:00:00 2001 From: Freyskeyd Date: Wed, 4 Jan 2017 16:02:34 +0100 Subject: [PATCH 009/104] Fix doc cfg(test) and tests directory Signed-off-by: Freyskeyd --- src/doc/book/testing.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 96cec7295aa9..6fefa1c9f1e1 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -499,6 +499,10 @@ be imported in every test with `mod common;` That's all there is to the `tests` directory. The `tests` module isn't needed here, since the whole thing is focused on tests. +Note, when building integration tests, cargo will not pass the `test` attribute +to the compiler. It means that all parts in `cfg(test)` won't be included in +the build used in your integration tests. + Let's finally check out that third section: documentation tests. # Documentation tests From 4186037aaa1a6aa3ba15a10130b424e7508bd276 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sun, 22 Jan 2017 00:28:17 +0200 Subject: [PATCH 010/104] Make backtraces work on Windows GNU targets again. This is done by adding a function that can return a filename to pass to backtrace_create_state. The filename is obtained in a safe way by first getting the filename, locking the file so it can't be moved, and then getting the filename again and making sure it's the same. See: https://github.com/rust-lang/rust/pull/37359#issuecomment-260123399 Issue: #33985 --- src/libstd/sys/unix/backtrace/mod.rs | 7 ++++ src/libstd/sys/windows/backtrace.rs | 48 +++++++++++++++++++++++ src/libstd/sys/windows/c.rs | 23 +++++++++++ src/libstd/sys/windows/mod.rs | 46 ++++++++++++++++++++++ src/libstd/sys_common/gnu/libbacktrace.rs | 17 +++++++- src/test/run-pass/backtrace-debuginfo.rs | 2 - src/test/run-pass/backtrace.rs | 4 -- 7 files changed, 140 insertions(+), 7 deletions(-) diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index d7c05e513f68..e3f1b23f7a24 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -83,9 +83,16 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. +use io; +use fs; + pub use self::tracing::write; // tracing impls: mod tracing; // symbol resolvers: mod printing; + +pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { + Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) +} diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 82a44c1c1103..e6182cda58a2 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -30,9 +30,13 @@ use io; use libc::c_void; use mem; use ptr; +use path::PathBuf; +use fs::{OpenOptions, File}; +use sys::ext::fs::OpenOptionsExt; use sys::c; use sys::dynamic_lib::DynamicLibrary; use sys::mutex::Mutex; +use sys::handle::Handle; macro_rules! sym { ($lib:expr, $e:expr, $t:ident) => ( @@ -157,3 +161,47 @@ unsafe fn _write(w: &mut Write) -> io::Result<()> { Ok(()) } + +fn query_full_process_image_name() -> io::Result { + unsafe { + let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, + c::FALSE, + c::GetCurrentProcessId())); + super::fill_utf16_buf(|buf, mut sz| { + if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { + 0 + } else { + sz + } + }, super::os2path) + } +} + +fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { + // We query the current image name, open the file without FILE_SHARE_DELETE so it + // can't be moved and then get the current image name again. If the names are the + // same than we have successfully locked the file + let image_name1 = query_full_process_image_name()?; + let file = OpenOptions::new() + .read(true) + .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) + .open(&image_name1)?; + let image_name2 = query_full_process_image_name()?; + + if image_name1 != image_name2 { + return Err(io::Error::new(io::ErrorKind::Other, + "executable moved while trying to lock it")); + } + + Ok((image_name1, file)) +} + +// Get the executable filename for libbacktrace +// This returns the path in the ANSI code page and a File which should remain open +// for as long as the path should remain valid +pub fn get_executable_filename() -> io::Result<(Vec, File)> { + let (executable, file) = lock_and_get_executable_filename()?; + let u16_executable = super::to_u16s(executable.into_os_string())?; + Ok((super::wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, + &u16_executable, true)?, file)) +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index dc7b2fc9a6ba..c6fac6d1759b 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -69,6 +69,7 @@ pub type LPWCH = *mut WCHAR; pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; pub type LPWSADATA = *mut WSADATA; pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; +pub type LPSTR = *mut CHAR; pub type LPWSTR = *mut WCHAR; pub type LPFILETIME = *mut FILETIME; @@ -157,6 +158,7 @@ pub const WSAECONNREFUSED: c_int = 10061; pub const MAX_PROTOCOL_CHAIN: DWORD = 7; +pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; pub const TOKEN_READ: DWORD = 0x20008; pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; @@ -218,6 +220,10 @@ pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; +pub const CP_ACP: UINT = 0; + +pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; + pub const AF_INET: c_int = 2; pub const AF_INET6: c_int = 23; pub const SD_BOTH: c_int = 2; @@ -888,6 +894,9 @@ extern "system" { pNumArgs: *mut c_int) -> *mut *mut u16; pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD; + pub fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; pub fn OpenProcessToken(ProcessHandle: HANDLE, DesiredAccess: DWORD, TokenHandle: *mut HANDLE) -> BOOL; @@ -973,6 +982,14 @@ extern "system" { pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; + pub fn WideCharToMultiByte(CodePage: UINT, + dwFlags: DWORD, + lpWideCharStr: LPCWSTR, + cchWideChar: c_int, + lpMultiByteStr: LPSTR, + cbMultiByte: c_int, + lpDefaultChar: LPCSTR, + lpUsedDefaultChar: LPBOOL) -> c_int; pub fn closesocket(socket: SOCKET) -> c_int; pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, @@ -1136,6 +1153,12 @@ compat_fn! { _dwFlags: DWORD) -> DWORD { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } + pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, + _dwFlags: DWORD, + _lpExeName: LPWSTR, + _lpdwSize: LPDWORD) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index defc41c5f46a..4468cf574b38 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -10,6 +10,7 @@ #![allow(missing_docs, bad_style)] +use ptr; use ffi::{OsStr, OsString}; use io::{self, ErrorKind}; use os::windows::ffi::{OsStrExt, OsStringExt}; @@ -171,6 +172,51 @@ fn os2path(s: &[u16]) -> PathBuf { PathBuf::from(OsString::from_wide(s)) } +fn wide_char_to_multi_byte(code_page: u32, + flags: u32, + s: &[u16], + no_default_char: bool) + -> io::Result> { + unsafe { + let mut size = c::WideCharToMultiByte(code_page, + flags, + s.as_ptr(), + s.len() as i32, + ptr::null_mut(), + 0, + ptr::null(), + ptr::null_mut()); + if size == 0 { + return Err(io::Error::last_os_error()); + } + + let mut buf = Vec::with_capacity(size as usize); + buf.set_len(size as usize); + + let mut used_default_char = c::FALSE; + size = c::WideCharToMultiByte(code_page, + flags, + s.as_ptr(), + s.len() as i32, + buf.as_mut_ptr(), + buf.len() as i32, + ptr::null(), + if no_default_char { &mut used_default_char } + else { ptr::null_mut() }); + if size == 0 { + return Err(io::Error::last_os_error()); + } + if no_default_char && used_default_char == c::TRUE { + return Err(io::Error::new(io::ErrorKind::InvalidData, + "string cannot be converted to requested code page")); + } + + buf.set_len(size as usize); + + Ok(buf) + } +} + pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { match v.iter().position(|c| *c == 0) { // don't include the 0 diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index b5802afc1094..94d206f3ac3c 100644 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs @@ -16,6 +16,7 @@ use sys_common::backtrace::{output, output_fileline}; pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, symaddr: *mut libc::c_void) -> io::Result<()> { use ffi::CStr; + use mem; use ptr; //////////////////////////////////////////////////////////////////////// @@ -124,7 +125,21 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, unsafe fn init_state() -> *mut backtrace_state { static mut STATE: *mut backtrace_state = ptr::null_mut(); if !STATE.is_null() { return STATE } - STATE = backtrace_create_state(ptr::null(), 0, error_cb, + + let filename = match ::sys::backtrace::get_executable_filename() { + Ok((filename, file)) => { + // filename is purposely leaked here since libbacktrace requires + // it to stay allocated permanently, file is also leaked so that + // the file stays locked + let filename_ptr = filename.as_ptr(); + mem::forget(filename); + mem::forget(file); + filename_ptr + }, + Err(_) => ptr::null(), + }; + + STATE = backtrace_create_state(filename, 0, error_cb, ptr::null_mut()); STATE } diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 72cf109fd597..626eccfc9ec8 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -37,7 +37,6 @@ macro_rules! dump_and_die { target_os = "ios", target_os = "android", all(target_os = "linux", target_arch = "arm"), - target_os = "windows", target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", @@ -173,4 +172,3 @@ fn main() { run_test(&args[0]); } } - diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 75c665b04a12..834ce984e663 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -104,10 +104,6 @@ fn runtest(me: &str) { } fn main() { - if cfg!(windows) && cfg!(target_env = "gnu") { - return - } - let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "fail" { foo(); From 5056a43752a34ec633fb71ff395f518bfc7ce52c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 12 Nov 2016 15:33:16 +0300 Subject: [PATCH 011/104] Stabilize Self and associated types in struct expressions and patterns --- src/librustc_typeck/check/mod.rs | 10 ------ src/libsyntax/feature_gate.rs | 6 ++-- .../struct-path-associated-type.rs | 2 -- .../struct-path-self-feature-gate.rs | 31 ------------------- .../struct-path-self-type-mismatch.rs | 2 -- src/test/compile-fail/struct-path-self.rs | 2 -- .../run-pass/struct-path-associated-type.rs | 2 -- src/test/run-pass/struct-path-self.rs | 2 -- 8 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 src/test/compile-fail/struct-path-self-feature-gate.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e240c70aaa3a..265f76417685 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3328,16 +3328,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { - match def { - Def::AssociatedTy(..) | Def::SelfTy(..) - if !self.tcx.sess.features.borrow().more_struct_aliases => { - emit_feature_err(&self.tcx.sess.parse_sess, - "more_struct_aliases", path_span, GateIssue::Language, - "`Self` and associated types in struct \ - expressions and patterns are unstable"); - } - _ => {} - } match ty.sty { ty::TyAdt(adt, substs) if !adt.is_enum() => { Some((adt.struct_variant(), adt.did, substs)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c25020caf857..b99300f6195a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -295,10 +295,6 @@ declare_features! ( // The #![windows_subsystem] attribute (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows using `Self` and associated types in struct expressions and patterns. - (active, more_struct_aliases, "1.14.0", Some(37544)), - - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -378,6 +374,8 @@ declare_features! ( // Allows `..` in tuple (struct) patterns (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)), (accepted, item_like_imports, "1.14.0", Some(35120)), + // Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.14.0", Some(37544)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs index ecaf269fcb1a..660ac44ce0b5 100644 --- a/src/test/compile-fail/struct-path-associated-type.rs +++ b/src/test/compile-fail/struct-path-associated-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S; trait Tr { diff --git a/src/test/compile-fail/struct-path-self-feature-gate.rs b/src/test/compile-fail/struct-path-self-feature-gate.rs deleted file mode 100644 index c40d05749559..000000000000 --- a/src/test/compile-fail/struct-path-self-feature-gate.rs +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -// gate-test-more_struct_aliases - -struct S; - -trait Tr { - type A; -} - -fn f>() { - let _ = T::A {}; - //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable -} - -impl S { - fn f() { - let _ = Self {}; - //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable - } -} - -fn main() {} diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs index 8352bd6751f5..f694e7d277c7 100644 --- a/src/test/compile-fail/struct-path-self-type-mismatch.rs +++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct Foo { inner: A } trait Bar { fn bar(); } diff --git a/src/test/compile-fail/struct-path-self.rs b/src/test/compile-fail/struct-path-self.rs index aeac199227b7..067d6ac22dc6 100644 --- a/src/test/compile-fail/struct-path-self.rs +++ b/src/test/compile-fail/struct-path-self.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S; trait Tr { diff --git a/src/test/run-pass/struct-path-associated-type.rs b/src/test/run-pass/struct-path-associated-type.rs index 292761dfd005..b033ed5c8021 100644 --- a/src/test/run-pass/struct-path-associated-type.rs +++ b/src/test/run-pass/struct-path-associated-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S { a: T, b: U, diff --git a/src/test/run-pass/struct-path-self.rs b/src/test/run-pass/struct-path-self.rs index b569ab62c1bf..c7a282c2a2fa 100644 --- a/src/test/run-pass/struct-path-self.rs +++ b/src/test/run-pass/struct-path-self.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - use std::ops::Add; struct S { From 197f037652bffe7e62be4c7f861c247946549619 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 24 Jan 2017 11:03:37 -0500 Subject: [PATCH 012/104] incr.comp.: Make cross-crate tracking for incr. comp. opt-in. --- src/librustc/session/config.rs | 2 ++ src/librustc_incremental/persist/preds.rs | 8 ++++-- src/librustc_incremental/persist/save.rs | 26 +++++++++++-------- .../auxiliary/point.rs | 2 ++ .../callee_caller_cross_crate/auxiliary/a.rs | 2 ++ .../change_private_fn_cc/auxiliary/point.rs | 2 ++ .../auxiliary/point.rs | 2 ++ .../auxiliary/a.rs | 2 ++ .../rlib_cross_crate/auxiliary/a.rs | 1 + .../auxiliary/a.rs | 2 ++ .../type_alias_cross_crate/auxiliary/a.rs | 2 ++ 11 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7d8f7fcefe63..7419d74287b9 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -899,6 +899,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "attempt to recover from parse errors (experimental)"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation (experimental)"), + incremental_cc: bool = (false, parse_bool, [UNTRACKED], + "enable cross-crate incremental compilation (even more experimental)"), incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof)"), incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index b2a4a2772ec2..327927b2f774 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -33,8 +33,12 @@ pub struct Predecessors<'query> { impl<'q> Predecessors<'q> { pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { - // Find nodes for which we want to know the full set of preds let tcx = hcx.tcx; + + let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc || + tcx.sess.opts.debugging_opts.query_dep_graph; + + // Find nodes for which we want to know the full set of preds let node_count = query.graph.len_nodes(); // Set up some data structures the cache predecessor search needs: @@ -52,7 +56,7 @@ impl<'q> Predecessors<'q> { .enumerate() .filter(|&(_, node)| match node.data { DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => def_id.is_local(), + DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(), // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 356eb845fed9..f626905f27d4 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -55,17 +55,21 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let preds = Predecessors::new(&query, &mut hcx); let mut current_metadata_hashes = FxHashMap(); - // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, - // since metadata-encoding might add new entries to the - // DefIdDirectory (which is saved in the dep-graph file). - save_in(sess, - metadata_hash_export_path(sess), - |e| encode_metadata_hashes(tcx, - svh, - &preds, - &mut builder, - &mut current_metadata_hashes, - e)); + if sess.opts.debugging_opts.incremental_cc || + sess.opts.debugging_opts.query_dep_graph { + // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, + // since metadata-encoding might add new entries to the + // DefIdDirectory (which is saved in the dep-graph file). + save_in(sess, + metadata_hash_export_path(sess), + |e| encode_metadata_hashes(tcx, + svh, + &preds, + &mut builder, + &mut current_metadata_hashes, + e)); + } + save_in(sess, dep_graph_path(sess), |e| encode_dep_graph(&preds, &mut builder, e)); diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs index adc2b23441ef..1064c97b744a 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs index d802c9a8352e..a02b71a753cc 100644 --- a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] diff --git a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs index dcc1ced635fb..08eef2a73f68 100644 --- a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs index 8df1cf54da2b..e69dc51119e9 100644 --- a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs index 4d84e844dedb..39547fb7359f 100644 --- a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs +++ b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![allow(warnings)] #![crate_name = "a"] #![crate_type = "rlib"] diff --git a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs index ff5fd6347144..3ecd9aff3f8c 100644 --- a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc // no-prefer-dynamic #![crate_type="rlib"] diff --git a/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs b/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs index 2ddcaf157210..d14ebf78d822 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs index e1dba1317703..0393bcda9915 100644 --- a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] From c6cfa3c4899e46addfe6d04d6aaa2d247056748f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 24 Jan 2017 22:44:33 -0500 Subject: [PATCH 013/104] Extend Cell to work with non-Copy types Part of #39264 --- src/libcore/cell.rs | 130 +++++++++++++++++++++++++++++----------- src/libcoretest/cell.rs | 31 ++++++++++ src/libcoretest/lib.rs | 1 + 3 files changed, 126 insertions(+), 36 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c3f862e7c541..cafa19afcb64 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -176,6 +176,7 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; +use mem; use ops::{Deref, DerefMut, CoerceUnsized}; /// A mutable memory location that admits only `Copy` data. @@ -187,23 +188,6 @@ pub struct Cell { } impl Cell { - /// Creates a new `Cell` containing the given value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn new(value: T) -> Cell { - Cell { - value: UnsafeCell::new(value), - } - } - /// Returns a copy of the contained value. /// /// # Examples @@ -221,25 +205,6 @@ impl Cell { unsafe{ *self.value.get() } } - /// Sets the contained value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// c.set(10); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set(&self, value: T) { - unsafe { - *self.value.get() = value; - } - } - /// Returns a reference to the underlying `UnsafeCell`. /// /// # Examples @@ -378,6 +343,99 @@ impl From for Cell { } } +#[unstable(feature = "move_cell", issue = "39264")] +impl Cell { + /// Creates a new `Cell` containing the given value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn new(value: T) -> Cell { + Cell { + value: UnsafeCell::new(value), + } + } + + /// Sets the contained value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// c.set(10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn set(&self, val: T) { + let old = self.replace(val); + drop(old); + } + + /// Replaces the contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let old = c.replace(10); + /// + /// assert_eq!(5, old); + /// ``` + pub fn replace(&self, val: T) -> T { + mem::replace(unsafe { &mut *self.value.get() }, val) + } + + /// Unwraps the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let five = c.into_inner(); + /// + /// assert_eq!(five, 5); + /// ``` + pub fn into_inner(self) -> T { + unsafe { self.value.into_inner() } + } +} + +#[unstable(feature = "move_cell", issue = "39264")] +impl Cell { + /// Takes the value of the cell, leaving `Default::default()` in its place. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let five = c.take(); + /// + /// assert_eq!(five, 5); + /// assert_eq!(c.into_inner(), 0); + /// ``` + pub fn take(&self) -> T { + self.replace(Default::default()) + } +} + #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for Cell {} diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 724a312ea79e..8585f2f08711 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -209,6 +209,37 @@ fn cell_default() { assert_eq!(0, cell.get()); } +#[test] +fn cell_set() { + let cell = Cell::new(10); + cell.set(20); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + cell.set("World".to_owned()); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_replace() { + let cell = Cell::new(10); + assert_eq!(10, cell.replace(20)); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + assert_eq!("Hello".to_owned(), cell.replace("World".to_owned())); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_into_inner() { + let cell = Cell::new(10); + assert_eq!(10, cell.into_inner()); + + let cell = Cell::new("Hello world".to_owned()); + assert_eq!("Hello world".to_owned(), cell.into_inner()); +} + #[test] fn refcell_default() { let cell: RefCell = Default::default(); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index ee47b510ee07..ea88d45630c4 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -34,6 +34,7 @@ #![feature(ordering_chaining)] #![feature(result_unwrap_or_default)] #![feature(ptr_unaligned)] +#![feature(move_cell)] extern crate core; extern crate test; From 2b7a23ed304d4298247b030eea0820018c05cd30 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 25 Jan 2017 14:48:20 +0800 Subject: [PATCH 014/104] Hide uninhabitedness checks behind feature gate --- src/librustc/ty/inhabitedness/mod.rs | 6 +-- src/librustc_const_eval/_match.rs | 17 +++++-- src/librustc_mir/build/matches/simplify.rs | 30 ++++++----- .../uninhabited-matches-feature-gated.rs | 50 +++++++++++++++++++ ...ninhabited-reference-type-feature-gated.rs | 19 ------- 5 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 src/test/compile-fail/uninhabited-matches-feature-gated.rs delete mode 100644 src/test/compile-fail/uninhabited-reference-type-feature-gated.rs diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 92395e3c381a..6c49493a6555 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -191,11 +191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } TyRef(_, ref tm) => { - if tcx.sess.features.borrow().never_type { - tm.ty.uninhabited_from(visited, tcx) - } else { - DefIdForest::empty() - } + tm.ty.uninhabited_from(visited, tcx) } _ => DefIdForest::empty(), diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index bb5dacf71e17..1770a112cdf2 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -379,19 +379,24 @@ impl<'tcx> Witness<'tcx> { fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, pcx: PatternContext<'tcx>) -> Vec { + let check_inhabited = cx.tcx.sess.features.borrow().never_type; debug!("all_constructors({:?})", pcx.ty); match pcx.ty.sty { ty::TyBool => [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(ref sub_ty) => { - if sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![Slice(0)] } else { (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() } } ty::TyArray(ref sub_ty, length) => { - if length == 0 || !sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited) + { vec![Slice(length)] } else { vec![] @@ -403,7 +408,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let forest = v.uninhabited_from(&mut visited, cx.tcx, substs, AdtKind::Enum); - if forest.contains(cx.tcx, cx.module) { + if forest.contains(cx.tcx, cx.module) + && check_inhabited + { None } else { Some(Variant(v.did)) @@ -411,7 +418,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, }).collect() } _ => { - if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) { + if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![] } else { vec![Single] diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b07183412236..e94d35195c21 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -99,20 +99,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { - let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { - i == variant_index || { - let mut visited = FxHashSet::default(); - let node_set = v.uninhabited_from(&mut visited, - self.hir.tcx(), - substs, - adt_def.adt_kind()); - !node_set.is_empty() + if self.hir.tcx().sess.features.borrow().never_type { + let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { + i == variant_index || { + let mut visited = FxHashSet::default(); + let node_set = v.uninhabited_from(&mut visited, + self.hir.tcx(), + substs, + adt_def.adt_kind()); + !node_set.is_empty() + } + }); + if irrefutable { + let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); + candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); + Ok(()) + } else { + Err(match_pair) } - }); - if irrefutable { - let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); - candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); - Ok(()) } else { Err(match_pair) } diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs new file mode 100644 index 000000000000..0f8b0a6c238d --- /dev/null +++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs @@ -0,0 +1,50 @@ +// 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. + +#![feature(slice_patterns)] + +enum Void {} + +fn main() { + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(n) => n, + }; + + let x: &Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: (Void,) = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: [Void; 1] = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: &[Void] = unsafe { std::mem::uninitialized() }; + let _ = match x { //~ ERROR non-exhaustive + &[] => (), + }; + + let x: Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; // okay + + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(x) => x, + }; + + let x: Result = Ok(23); + let Ok(x) = x; + //~^ ERROR refutable +} + diff --git a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs b/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs deleted file mode 100644 index 8f246eddbcde..000000000000 --- a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -enum Void {} - -fn main() { - let x: Result = Ok(23); - let _ = match x { //~ ERROR non-exhaustive - Ok(n) => n, - }; -} - From 9e8785f01757a50e321e85adeb659a9aff6fc00e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Jan 2017 14:37:04 -0800 Subject: [PATCH 015/104] rustbuild: Add manifest generation in-tree This commit adds a new tool, `build-manifest`, which is used to generate a distribution manifest of all produced artifacts. This tool is intended to replace the `build-rust-manifest.py` script that's currently located on the buildmaster. The intention is that we'll have a builder which periodically: * Downloads all artifacts for a commit * Runs `./x.py dist hash-and-sign`. This will generate `sha256` and `asc` files as well as TOML manifests. * Upload all generated hashes and manifests to the directory the artifacts came from. * Upload *all* artifacts (tarballs and hashes and manifests) to an archived location. * If necessary, upload all artifacts to the main location. This script is intended to just be the second step here where orchestrating uploads and such will all happen externally from the build system itself. --- src/Cargo.lock | 8 + src/Cargo.toml | 1 + src/bootstrap/config.rs | 19 ++ src/bootstrap/config.toml.example | 30 ++ src/bootstrap/dist.rs | 33 ++- src/bootstrap/step.rs | 10 + src/tools/build-manifest/Cargo.toml | 8 + src/tools/build-manifest/src/main.rs | 404 +++++++++++++++++++++++++++ 8 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 src/tools/build-manifest/Cargo.toml create mode 100644 src/tools/build-manifest/src/main.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 7db243c5eb9d..93bbf0f227b1 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -50,6 +50,14 @@ dependencies = [ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build-manifest" +version = "0.1.0" +dependencies = [ + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "build_helper" version = "0.1.0" diff --git a/src/Cargo.toml b/src/Cargo.toml index 8fb5c70c41bf..0db26ea5ae02 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -10,6 +10,7 @@ members = [ "tools/linkchecker", "tools/rustbook", "tools/tidy", + "tools/build-manifest", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7d1abcfa6f6e..e035f8157ffd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -78,6 +78,11 @@ pub struct Config { pub cargo: Option, pub local_rebuild: bool, + // dist misc + pub dist_sign_folder: Option, + pub dist_upload_addr: Option, + pub dist_gpg_password_file: Option, + // libstd features pub debug_jemalloc: bool, pub use_jemalloc: bool, @@ -123,6 +128,7 @@ struct TomlConfig { llvm: Option, rust: Option, target: Option>, + dist: Option, } /// TOML representation of various global build decisions. @@ -166,6 +172,13 @@ struct Llvm { targets: Option, } +#[derive(RustcDecodable, Default, Clone)] +struct Dist { + sign_folder: Option, + gpg_password_file: Option, + upload_addr: Option, +} + #[derive(RustcDecodable)] enum StringOrBool { String(String), @@ -352,6 +365,12 @@ impl Config { } } + if let Some(ref t) = toml.dist { + config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); + config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); + config.dist_upload_addr = t.upload_addr.clone(); + } + return config } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 4b859482562d..a53419ad7fd7 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -242,3 +242,33 @@ # that this option only makes sense for MUSL targets that produce statically # linked binaries #musl-root = "..." + +# ============================================================================= +# Distribution options +# +# These options are related to distribution, mostly for the Rust project itself. +# You probably won't need to concern yourself with any of these options +# ============================================================================= +[dist] + +# This is the folder of artifacts that the build system will sign. All files in +# this directory will be signed with the default gpg key using the system `gpg` +# binary. The `asc` and `sha256` files will all be output into the standard dist +# output folder (currently `build/dist`) +# +# This folder should be populated ahead of time before the build system is +# invoked. +#sign-folder = "path/to/folder/to/sign" + +# This is a file which contains the password of the default gpg key. This will +# be passed to `gpg` down the road when signing all files in `sign-folder` +# above. This should be stored in plaintext. +#gpg-password-file = "path/to/gpg/password" + +# The remote address that all artifacts will eventually be uploaded to. The +# build system generates manifests which will point to these urls, and for the +# manifests to be correct they'll have to have the right URLs encoded. +# +# Note that this address should not contain a trailing slash as file names will +# be appended to it. +#upload-addr = "https://example.com/folder" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e5f050595231..71a5f313bbd2 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -22,7 +22,7 @@ use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::{PathBuf, Path}; -use std::process::Command; +use std::process::{Command, Stdio}; use build_helper::output; @@ -876,3 +876,34 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) { cmd.env("CFG_PLATFORM", "x86"); } } + +pub fn hash_and_sign(build: &Build) { + let compiler = Compiler::new(0, &build.config.build); + let mut cmd = build.tool_cmd(&compiler, "build-manifest"); + let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") + }); + let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") + }); + let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n") + }); + let mut pass = String::new(); + t!(t!(File::open(&file)).read_to_string(&mut pass)); + + let today = output(Command::new("date").arg("+%Y-%m-%d")); + + cmd.arg(sign); + cmd.arg(distdir(build)); + cmd.arg(today.trim()); + cmd.arg(package_vers(build)); + cmd.arg(addr); + + t!(fs::create_dir_all(distdir(build))); + + let mut child = t!(cmd.stdin(Stdio::piped()).spawn()); + t!(child.stdin.take().unwrap().write_all(pass.as_bytes())); + let status = t!(child.wait()); + assert!(status.success()); +} diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 697b14c6050c..3932a7cf8c56 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -513,6 +513,9 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("tool-compiletest", "src/tools/compiletest") .dep(|s| s.name("libtest")) .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); + rules.build("tool-build-manifest", "src/tools/build-manifest") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest")); // ======================================================================== // Documentation targets @@ -633,6 +636,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-cargo")) .run(move |s| dist::extended(build, s.stage, s.target)); + rules.dist("dist-sign", "hash-and-sign") + .host(true) + .only_build(true) + .only_host_build(true) + .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0)) + .run(move |_| dist::hash_and_sign(build)); + rules.verify(); return rules; } diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml new file mode 100644 index 000000000000..4b876753b1fe --- /dev/null +++ b/src/tools/build-manifest/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "build-manifest" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +toml = "0.1" +rustc-serialize = "0.3" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs new file mode 100644 index 000000000000..8c15a6630a33 --- /dev/null +++ b/src/tools/build-manifest/src/main.rs @@ -0,0 +1,404 @@ +// 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. + +extern crate toml; +extern crate rustc_serialize; + +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::path::{PathBuf, Path}; +use std::process::{Command, Stdio}; + +static HOSTS: &'static [&'static str] = &[ + "aarch64-unknown-linux-gnu", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "i686-apple-darwin", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "mips-unknown-linux-gnu", + "mips64-unknown-linux-gnuabi64", + "mips64el-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-netbsd", +]; + +static TARGETS: &'static [&'static str] = &[ + "aarch64-apple-ios", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "arm-linux-androideabi", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "armv7-apple-ios", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabihf", + "armv7s-apple-ios", + "asmjs-unknown-emscripten", + "i386-apple-ios", + "i586-pc-windows-msvc", + "i586-unknown-linux-gnu", + "i686-apple-darwin", + "i686-linux-android", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "i686-unknown-linux-musl", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips64-unknown-linux-gnuabi64", + "mips64el-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "wasm32-unknown-emscripten", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-rumprun-netbsd", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", +]; + +static MINGW: &'static [&'static str] = &[ + "i686-pc-windows-gnu", + "x86_64-pc-windows-gnu", +]; + +#[derive(RustcEncodable)] +struct Manifest { + manifest_version: String, + date: String, + pkg: HashMap, +} + +#[derive(RustcEncodable)] +struct Package { + version: String, + target: HashMap, +} + +#[derive(RustcEncodable)] +struct Target { + available: bool, + url: Option, + hash: Option, + components: Option>, + extensions: Option>, +} + +#[derive(RustcEncodable)] +struct Component { + pkg: String, + target: String, +} + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +struct Builder { + channel: String, + input: PathBuf, + output: PathBuf, + gpg_passphrase: String, + digests: HashMap, + s3_address: String, + date: String, + rust_version: String, + cargo_version: String, +} + +fn main() { + let mut args = env::args().skip(1); + let input = PathBuf::from(args.next().unwrap()); + let output = PathBuf::from(args.next().unwrap()); + let date = args.next().unwrap(); + let channel = args.next().unwrap(); + let s3_address = args.next().unwrap(); + let mut passphrase = String::new(); + t!(io::stdin().read_to_string(&mut passphrase)); + + Builder { + channel: channel, + input: input, + output: output, + gpg_passphrase: passphrase, + digests: HashMap::new(), + s3_address: s3_address, + date: date, + rust_version: String::new(), + cargo_version: String::new(), + }.build(); +} + +impl Builder { + fn build(&mut self) { + self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); + self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); + + self.digest_and_sign(); + let manifest = self.build_manifest(); + let manifest = toml::encode(&manifest).to_string(); + + let filename = format!("channel-rust-{}.toml", self.channel); + self.write_manifest(&manifest, &filename); + + if self.channel != "beta" && self.channel != "nightly" { + self.write_manifest(&manifest, "channel-rust-stable.toml"); + } + } + + fn digest_and_sign(&mut self) { + for file in t!(self.input.read_dir()).map(|e| t!(e).path()) { + let filename = file.file_name().unwrap().to_str().unwrap(); + let digest = self.hash(&file); + self.sign(&file); + assert!(self.digests.insert(filename.to_string(), digest).is_none()); + } + } + + fn build_manifest(&mut self) -> Manifest { + let mut manifest = Manifest { + manifest_version: "2".to_string(), + date: self.date.to_string(), + pkg: HashMap::new(), + }; + + self.package("rustc", &mut manifest.pkg, HOSTS); + self.package("cargo", &mut manifest.pkg, HOSTS); + self.package("rust-mingw", &mut manifest.pkg, MINGW); + self.package("rust-std", &mut manifest.pkg, TARGETS); + self.package("rust-docs", &mut manifest.pkg, TARGETS); + self.package("rust-src", &mut manifest.pkg, &["*"]); + + let mut pkg = Package { + version: self.cached_version("rust").to_string(), + target: HashMap::new(), + }; + for host in HOSTS { + let filename = self.filename("rust", host); + let digest = match self.digests.remove(&filename) { + Some(digest) => digest, + None => { + pkg.target.insert(host.to_string(), Target { + available: false, + url: None, + hash: None, + components: None, + extensions: None, + }); + continue + } + }; + let mut components = Vec::new(); + let mut extensions = Vec::new(); + + // rustc/rust-std/cargo are all required, and so is rust-mingw if it's + // available for the target. + components.extend(vec![ + Component { pkg: "rustc".to_string(), target: host.to_string() }, + Component { pkg: "rust-std".to_string(), target: host.to_string() }, + Component { pkg: "cargo".to_string(), target: host.to_string() }, + ]); + if host.contains("pc-windows-gnu") { + components.push(Component { + pkg: "rust-mingw".to_string(), + target: host.to_string(), + }); + } + + // Docs, other standard libraries, and the source package are all + // optional. + extensions.push(Component { + pkg: "rust-docs".to_string(), + target: host.to_string(), + }); + for target in TARGETS { + if target != host { + extensions.push(Component { + pkg: "rust-std".to_string(), + target: target.to_string(), + }); + } + } + extensions.push(Component { + pkg: "rust-src".to_string(), + target: "*".to_string(), + }); + + pkg.target.insert(host.to_string(), Target { + available: true, + url: Some(self.url("rust", host)), + hash: Some(to_hex(digest.as_ref())), + components: Some(components), + extensions: Some(extensions), + }); + } + manifest.pkg.insert("rust".to_string(), pkg); + + return manifest + } + + fn package(&mut self, + pkgname: &str, + dst: &mut HashMap, + targets: &[&str]) { + let targets = targets.iter().map(|name| { + let filename = self.filename(pkgname, name); + let digest = match self.digests.remove(&filename) { + Some(digest) => digest, + None => { + return (name.to_string(), Target { + available: false, + url: None, + hash: None, + components: None, + extensions: None, + }) + } + }; + + (name.to_string(), Target { + available: true, + url: Some(self.url(pkgname, name)), + hash: Some(digest), + components: None, + extensions: None, + }) + }).collect(); + + dst.insert(pkgname.to_string(), Package { + version: self.cached_version(pkgname).to_string(), + target: targets, + }); + } + + fn url(&self, component: &str, target: &str) -> String { + format!("{}/{}/{}", + self.s3_address, + self.date, + self.filename(component, target)) + } + + fn filename(&self, component: &str, target: &str) -> String { + if component == "rust-src" { + format!("rust-src-{}.tar.gz", self.channel) + } else { + format!("{}-{}-{}.tar.gz", component, self.channel, target) + } + } + + fn cached_version(&self, component: &str) -> &str { + if component == "cargo" { + &self.cargo_version + } else { + &self.rust_version + } + } + + fn version(&self, component: &str, target: &str) -> String { + let mut cmd = Command::new("tar"); + let filename = self.filename(component, target); + cmd.arg("xf") + .arg(self.input.join(&filename)) + .arg(format!("{}/version", filename.replace(".tar.gz", ""))) + .arg("-O"); + let version = t!(cmd.output()); + if !version.status.success() { + panic!("failed to learn version:\n\n{:?}\n\n{}\n\n{}", + cmd, + String::from_utf8_lossy(&version.stdout), + String::from_utf8_lossy(&version.stderr)); + } + String::from_utf8_lossy(&version.stdout).trim().to_string() + } + + fn hash(&self, path: &Path) -> String { + let sha = t!(Command::new("shasum") + .arg("-a").arg("256") + .arg(path) + .output()); + assert!(sha.status.success()); + + let filename = path.file_name().unwrap().to_str().unwrap(); + let sha256 = self.output.join(format!("{}.sha256", filename)); + t!(t!(File::create(&sha256)).write_all(&sha.stdout)); + + let stdout = String::from_utf8_lossy(&sha.stdout); + stdout.split_whitespace().next().unwrap().to_string() + } + + fn sign(&self, path: &Path) { + let filename = path.file_name().unwrap().to_str().unwrap(); + let asc = self.output.join(format!("{}.asc", filename)); + println!("signing: {:?}", path); + let mut cmd = Command::new("gpg"); + cmd.arg("--no-tty") + .arg("--yes") + .arg("--passphrase-fd").arg("0") + .arg("--armor") + .arg("--output").arg(&asc) + .arg("--detach-sign").arg(path) + .stdin(Stdio::piped()); + let mut child = t!(cmd.spawn()); + t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes())); + assert!(t!(child.wait()).success()); + } + + fn write_manifest(&self, manifest: &str, name: &str) { + let dst = self.output.join(name); + t!(t!(File::create(&dst)).write_all(manifest.as_bytes())); + self.hash(&dst); + self.sign(&dst); + } +} + +fn to_hex(digest: &[u8]) -> String { + let mut ret = String::new(); + for byte in digest { + ret.push(hex((byte & 0xf0) >> 4)); + ret.push(hex(byte & 0xf)); + } + return ret; + + fn hex(b: u8) -> char { + match b { + 0...9 => (b'0' + b) as char, + _ => (b'a' + b - 10) as char, + } + } +} From 8944582d1d51f64d38a88791a30e1b2d415ef123 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jan 2017 11:55:30 -0800 Subject: [PATCH 016/104] travis: Upload all artifacts in build/dist Previously we only uploaded tarballs, but this modifies Travis/AppVeyor to upload everything. We shouldn't have anything else in there to worry about and otherwise we need to be sure to pick up pkg/msi/exe installers. --- .travis.yml | 4 ++-- appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index bbe0cdfb6f8f..0f73f67224b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -124,9 +124,9 @@ before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT - > if [ "$TRAVIS_OS_NAME" == "osx" ]; then - cp build/dist/*.tar.gz deploy/$TRAVIS_COMMIT; + cp -r build/dist deploy/$TRAVIS_COMMIT; else - cp obj/build/dist/*.tar.gz deploy/$TRAVIS_COMMIT; + cp -r obj/build/dist deploy/$TRAVIS_COMMIT; fi deploy: diff --git a/appveyor.yml b/appveyor.yml index f158d788d16a..418cdcb07af4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,7 +137,7 @@ branches: before_deploy: - ps: | New-Item -Path deploy -ItemType directory - Get-ChildItem -Path build\dist -Filter '*.tar.gz' | Move-Item -Destination deploy + Get-ChildItem -Path build\dist | Move-Item -Destination deploy Get-ChildItem -Path deploy | Foreach-Object { Push-AppveyorArtifact $_.FullName -FileName ${env:APPVEYOR_REPO_COMMIT}/$_ } @@ -151,7 +151,7 @@ deploy: bucket: rust-lang-ci set_public: true region: us-east-1 - artifact: /.*\.tar.gz/ + artifact: /.*/ folder: rustc-builds on: branch: auto From 671b1c1d895c54903a10555196b789ebd5ff2c90 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jan 2017 15:37:20 -0800 Subject: [PATCH 017/104] std: Stabilize APIs for the 1.16.0 release This commit applies the stabilization/deprecations of the 1.16.0 release, as tracked by the rust-lang/rust issue tracker and the final-comment-period tag. The following APIs were stabilized: * `VecDeque::truncate` * `VecDeque::resize` * `String::insert_str` * `Duration::checked_{add,sub,div,mul}` * `str::replacen` * `SocketAddr::is_ipv{4,6}` * `IpAddr::is_ipv{4,6}` * `str::repeat` * `Vec::dedup_by` * `Vec::dedup_by_key` * `Result::unwrap_or_default` * `<*const T>::wrapping_offset` * `<*mut T>::wrapping_offset` * `CommandExt::creation_flags` (on Windows) * `File::set_permissions` * `String::split_off` The following APIs were deprecated * `EnumSet` - replaced with other ecosystem abstractions, long since unstable Closes #27788 Closes #35553 Closes #35774 Closes #36436 Closes #36949 Closes #37079 Closes #37087 Closes #37516 Closes #37827 Closes #37916 Closes #37966 Closes #38080 --- src/libcollections/enum_set.rs | 2 + src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 10 +- src/libcollections/string.rs | 9 +- src/libcollections/vec.rs | 7 +- src/libcollections/vec_deque.rs | 12 +- src/libcollectionstest/enum_set.rs | 268 -------------------------- src/libcollectionstest/lib.rs | 6 - src/libcore/ptr.rs | 6 +- src/libcore/result.rs | 4 +- src/libcoretest/lib.rs | 1 - src/libserialize/collection_impls.rs | 29 --- src/libserialize/lib.rs | 1 - src/libstd/fs.rs | 3 +- src/libstd/net/addr.rs | 8 +- src/libstd/net/ip.rs | 8 +- src/libstd/sys/windows/ext/process.rs | 6 +- src/libstd/time/duration.rs | 16 +- 18 files changed, 26 insertions(+), 371 deletions(-) delete mode 100644 src/libcollectionstest/enum_set.rs diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 87bc5e59ef78..78b610797778 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -17,6 +17,8 @@ reason = "matches collection reform specification, \ waiting for dust to settle", issue = "37966")] +#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")] +#![allow(deprecated)] use core::marker; use core::fmt; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 561d8860dc88..39de87c08407 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -79,6 +79,7 @@ pub use btree_set::BTreeSet; #[doc(no_inline)] pub use linked_list::LinkedList; #[doc(no_inline)] +#[allow(deprecated)] pub use enum_set::EnumSet; #[doc(no_inline)] pub use vec_deque::VecDeque; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 70cedce9a905..458d5114829f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1607,7 +1607,6 @@ impl str { /// Basic usage: /// /// ``` - /// # #![feature(str_replacen)] /// let s = "foo foo 123 foo"; /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); @@ -1617,13 +1616,10 @@ impl str { /// When the pattern doesn't match: /// /// ``` - /// # #![feature(str_replacen)] /// let s = "this is old"; /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); /// ``` - #[unstable(feature = "str_replacen", - issue = "36436", - reason = "only need to replace first N matches")] + #[stable(feature = "str_replacen", since = "1.16.0")] pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation let mut result = String::with_capacity(32); @@ -1795,11 +1791,9 @@ impl str { /// Basic usage: /// /// ``` - /// #![feature(repeat_str)] - /// /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc")); /// ``` - #[unstable(feature = "repeat_str", issue = "37079")] + #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { let mut s = String::with_capacity(self.len() * n); s.extend((0..n).map(|_| self)); diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 5210c25b4e5c..b184a8603e6b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1166,8 +1166,6 @@ impl String { /// Basic usage: /// /// ``` - /// #![feature(insert_str)] - /// /// let mut s = String::from("bar"); /// /// s.insert_str(0, "foo"); @@ -1175,9 +1173,7 @@ impl String { /// assert_eq!("foobar", s); /// ``` #[inline] - #[unstable(feature = "insert_str", - reason = "recent addition", - issue = "35553")] + #[stable(feature = "insert_str", since = "1.16.0")] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -1270,7 +1266,6 @@ impl String { /// # Examples /// /// ``` - /// # #![feature(string_split_off)] /// # fn main() { /// let mut hello = String::from("Hello, World!"); /// let world = hello.split_off(7); @@ -1279,7 +1274,7 @@ impl String { /// # } /// ``` #[inline] - #[unstable(feature = "string_split_off", issue = "38080")] + #[stable(feature = "string_split_off", since = "1.16.0")] pub fn split_off(&mut self, mid: usize) -> String { assert!(self.is_char_boundary(mid)); let other = self.vec.split_off(mid); diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c5b904c8a2f0..1f8fd32da9ab 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -820,15 +820,13 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(dedup_by)] - /// /// let mut vec = vec![10, 20, 21, 30, 20]; /// /// vec.dedup_by_key(|i| *i / 10); /// /// assert_eq!(vec, [10, 20, 30, 20]); /// ``` - #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[stable(feature = "dedup_by", since = "1.16.0")] #[inline] pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq { self.dedup_by(|a, b| key(a) == key(b)) @@ -841,7 +839,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(dedup_by)] /// use std::ascii::AsciiExt; /// /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; @@ -850,7 +847,7 @@ impl Vec { /// /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); /// ``` - #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[stable(feature = "dedup_by", since = "1.16.0")] pub fn dedup_by(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { unsafe { // Although we have a mutable reference to `self`, we cannot make diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index fea2d111f472..5b1bc3a3ae4f 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -643,8 +643,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -655,9 +653,7 @@ impl VecDeque { /// assert_eq!(buf.len(), 1); /// assert_eq!(Some(&5), buf.get(0)); /// ``` - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification; waiting on panic semantics", - issue = "27788")] + #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { for _ in len..self.len() { self.pop_back(); @@ -1779,8 +1775,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1793,9 +1787,7 @@ impl VecDeque { /// assert_eq!(a, b); /// } /// ``` - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification; waiting on panic semantics", - issue = "27788")] + #[stable(feature = "deque_extras", since = "1.16.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); diff --git a/src/libcollectionstest/enum_set.rs b/src/libcollectionstest/enum_set.rs deleted file mode 100644 index 972361326d7b..000000000000 --- a/src/libcollectionstest/enum_set.rs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2012 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. - -use std::mem; - -use collections::enum_set::{CLike, EnumSet}; - -use self::Foo::*; - -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(usize)] -enum Foo { - A, - B, - C, -} - -impl CLike for Foo { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Foo { - unsafe { mem::transmute(v) } - } -} - -#[test] -fn test_new() { - let e: EnumSet = EnumSet::new(); - assert!(e.is_empty()); -} - -#[test] -fn test_show() { - let mut e = EnumSet::new(); - assert!(format!("{:?}", e) == "{}"); - e.insert(A); - assert!(format!("{:?}", e) == "{A}"); - e.insert(C); - assert!(format!("{:?}", e) == "{A, C}"); -} - -#[test] -fn test_len() { - let mut e = EnumSet::new(); - assert_eq!(e.len(), 0); - e.insert(A); - e.insert(B); - e.insert(C); - assert_eq!(e.len(), 3); - e.remove(&A); - assert_eq!(e.len(), 2); - e.clear(); - assert_eq!(e.len(), 0); -} - -/////////////////////////////////////////////////////////////////////////// -// intersect - -#[test] -fn test_two_empties_do_not_intersect() { - let e1: EnumSet = EnumSet::new(); - let e2: EnumSet = EnumSet::new(); - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_empty_does_not_intersect_with_full() { - let e1: EnumSet = EnumSet::new(); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - e2.insert(C); - - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_disjoint_intersects() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(B); - - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_overlapping_intersects() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - - assert!(!e1.is_disjoint(&e2)); -} - -/////////////////////////////////////////////////////////////////////////// -// contains and contains_elem - -#[test] -fn test_superset() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - - let mut e3: EnumSet = EnumSet::new(); - e3.insert(C); - - assert!(e1.is_subset(&e2)); - assert!(e2.is_superset(&e1)); - assert!(!e3.is_superset(&e2)); - assert!(!e2.is_superset(&e3)) -} - -#[test] -fn test_contains() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - assert!(e1.contains(&A)); - assert!(!e1.contains(&B)); - assert!(!e1.contains(&C)); - - e1.insert(A); - e1.insert(B); - assert!(e1.contains(&A)); - assert!(e1.contains(&B)); - assert!(!e1.contains(&C)); -} - -/////////////////////////////////////////////////////////////////////////// -// iter - -#[test] -fn test_iterator() { - let mut e1: EnumSet = EnumSet::new(); - - let elems: Vec = e1.iter().collect(); - assert!(elems.is_empty()); - - e1.insert(A); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A]); - - e1.insert(C); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, C]); - - e1.insert(C); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, C]); - - e1.insert(B); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, B, C]); -} - -/////////////////////////////////////////////////////////////////////////// -// operators - -#[test] -fn test_operators() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - e1.insert(C); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(B); - e2.insert(C); - - let e_union = e1 | e2; - let elems: Vec<_> = e_union.iter().collect(); - assert_eq!(elems, [A, B, C]); - - let e_intersection = e1 & e2; - let elems: Vec<_> = e_intersection.iter().collect(); - assert_eq!(elems, [C]); - - // Another way to express intersection - let e_intersection = e1 - (e1 - e2); - let elems: Vec<_> = e_intersection.iter().collect(); - assert_eq!(elems, [C]); - - let e_subtract = e1 - e2; - let elems: Vec<_> = e_subtract.iter().collect(); - assert_eq!(elems, [A]); - - // Bitwise XOR of two sets, aka symmetric difference - let e_symmetric_diff = e1 ^ e2; - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); - - // Another way to express symmetric difference - let e_symmetric_diff = (e1 - e2) | (e2 - e1); - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); - - // Yet another way to express symmetric difference - let e_symmetric_diff = (e1 | e2) - (e1 & e2); - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); -} - -#[test] -#[should_panic] -fn test_overflow() { - #[allow(dead_code)] - #[derive(Copy, Clone)] - #[repr(usize)] - enum Bar { - V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, - V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, - V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, - V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, - V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, - V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, - V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, - } - - impl CLike for Bar { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Bar { - unsafe { mem::transmute(v) } - } - } - let mut set = EnumSet::new(); - set.insert(Bar::V64); -} - -#[test] -fn test_extend_ref() { - let mut a = EnumSet::new(); - a.insert(A); - - a.extend(&[A, C]); - - assert_eq!(a.len(), 2); - assert!(a.contains(&A)); - assert!(a.contains(&C)); - - let mut b = EnumSet::new(); - b.insert(B); - - a.extend(&b); - - assert_eq!(a.len(), 3); - assert!(a.contains(&A)); - assert!(a.contains(&B)); - assert!(a.contains(&C)); -} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index bec3965a9589..b146672893f8 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -18,17 +18,12 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] -#![feature(dedup_by)] -#![feature(enumset)] #![feature(exact_size_is_empty)] #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(repeat_str)] #![feature(step_by)] #![feature(str_escape)] -#![feature(str_replacen)] -#![feature(string_split_off)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] @@ -47,7 +42,6 @@ mod bench; mod binary_heap; mod btree; mod cow_str; -mod enum_set; mod fmt; mod linked_list; mod slice; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index bf5a59c45e4d..02851c224e2e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -448,7 +448,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(ptr_wrapping_offset)] /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -463,7 +462,7 @@ impl *const T { /// ptr = ptr.wrapping_offset(step); /// } /// ``` - #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[inline] pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { unsafe { @@ -572,7 +571,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(ptr_wrapping_offset)] /// // Iterate using a raw pointer in increments of two elements /// let mut data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *mut u8 = data.as_mut_ptr(); @@ -587,7 +585,7 @@ impl *mut T { /// } /// assert_eq!(&data, &[0, 2, 0, 4, 0]); /// ``` - #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[inline] pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { unsafe { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index f02df88bb2ef..0a2e36396534 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -840,8 +840,6 @@ impl Result { /// `Err` on error. /// /// ``` - /// #![feature(result_unwrap_or_default)] - /// /// let good_year_from_input = "1909"; /// let bad_year_from_input = "190blarg"; /// let good_year = good_year_from_input.parse().unwrap_or_default(); @@ -854,7 +852,7 @@ impl Result { /// [`FromStr`]: ../../std/str/trait.FromStr.html /// ``` #[inline] - #[unstable(feature = "result_unwrap_or_default", issue = "37516")] + #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { match self { Ok(x) => x, diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index ee47b510ee07..8e5893b5ecbe 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -32,7 +32,6 @@ #![feature(unicode)] #![feature(unique)] #![feature(ordering_chaining)] -#![feature(result_unwrap_or_default)] #![feature(ptr_unaligned)] extern crate core; diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index ba9bf2b86a60..05cfb6352fbb 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -11,11 +11,9 @@ //! Implementations of serialization for structures found in libcollections use std::hash::{Hash, BuildHasher}; -use std::mem; use {Decodable, Encodable, Decoder, Encoder}; use std::collections::{LinkedList, VecDeque, BTreeMap, BTreeSet, HashMap, HashSet}; -use collections::enum_set::{EnumSet, CLike}; impl< T: Encodable @@ -128,33 +126,6 @@ impl< } } -impl< - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - let mut bits = 0; - for item in self { - bits |= 1 << item.to_usize(); - } - s.emit_usize(bits) - } -} - -impl< - T: Decodable + CLike -> Decodable for EnumSet { - fn decode(d: &mut D) -> Result, D::Error> { - let bits = d.read_usize()?; - let mut set = EnumSet::new(); - for bit in 0..(mem::size_of::()*8) { - if bits & (1 << bit) != 0 { - set.insert(CLike::from_usize(bit)); - } - } - Ok(set) - } -} - impl Encodable for HashMap where K: Encodable + Hash + Eq, V: Encodable, diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2cfc3924c036..1cb83fa33da0 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -30,7 +30,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] #![feature(core_intrinsics)] -#![feature(enumset)] #![feature(specialization)] #![feature(staged_api)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f1dc36ae7933..249627c430cb 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -404,7 +404,6 @@ impl File { /// # Examples /// /// ``` - /// #![feature(set_permissions_atomic)] /// # fn foo() -> std::io::Result<()> { /// use std::fs::File; /// @@ -415,7 +414,7 @@ impl File { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "set_permissions_atomic", issue="37916")] + #[stable(feature = "set_permissions_atomic", since = "1.16.0")] pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) } diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index d186a53311da..751878c687c0 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -148,8 +148,6 @@ impl SocketAddr { /// # Examples /// /// ``` - /// #![feature(sockaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// fn main() { @@ -158,7 +156,7 @@ impl SocketAddr { /// assert_eq!(socket.is_ipv6(), false); /// } /// ``` - #[unstable(feature = "sockaddr_checker", issue = "36949")] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { match *self { SocketAddr::V4(_) => true, @@ -172,8 +170,6 @@ impl SocketAddr { /// # Examples /// /// ``` - /// #![feature(sockaddr_checker)] - /// /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; /// /// fn main() { @@ -183,7 +179,7 @@ impl SocketAddr { /// assert_eq!(socket.is_ipv6(), true); /// } /// ``` - #[unstable(feature = "sockaddr_checker", issue = "36949")] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { match *self { SocketAddr::V4(_) => false, diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 05e3d38b17eb..7803cf728f2e 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -196,8 +196,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ipaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// fn main() { @@ -206,7 +204,7 @@ impl IpAddr { /// false); /// } /// ``` - #[unstable(feature = "ipaddr_checker", issue = "36949")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { match *self { IpAddr::V4(_) => true, @@ -219,8 +217,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ipaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// fn main() { @@ -229,7 +225,7 @@ impl IpAddr { /// true); /// } /// ``` - #[unstable(feature = "ipaddr_checker", issue = "36949")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { match *self { IpAddr::V4(_) => false, diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 0a3221aeae6f..1419a4af4273 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -99,17 +99,17 @@ impl ExitStatusExt for process::ExitStatus { } /// Windows-specific extensions to the `std::process::Command` builder -#[unstable(feature = "windows_process_extensions", issue = "37827")] +#[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[unstable(feature = "windows_process_extensions", issue = "37827")] + #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; } -#[unstable(feature = "windows_process_extensions", issue = "37827")] +#[stable(feature = "windows_process_extensions", since = "1.16.0")] impl CommandExt for process::Command { fn creation_flags(&mut self, flags: u32) -> &mut process::Command { self.as_inner_mut().creation_flags(flags); diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 2c4e2bbff93a..af7eaeb3106b 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -154,14 +154,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_add(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_add(rhs.secs) { @@ -194,14 +192,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_sub(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { @@ -232,14 +228,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_mul(self, rhs: u32) -> Option { // Multiply nanoseconds as u64, because it cannot overflow that way. @@ -269,15 +263,13 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); /// assert_eq!(Duration::new(2, 0).checked_div(0), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_div(self, rhs: u32) -> Option { if rhs != 0 { From ff11f987c669a62058267c5b71f804b03fe9954d Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 26 Jan 2017 10:37:20 +0100 Subject: [PATCH 018/104] drop_in_place is stable now, don't #![feature] it in the nomicon and a test It was stable since Rust 1.8. --- src/doc/nomicon/destructors.md | 6 +++--- src/test/run-pass/extern_fat_drop.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md index c6fa5b079db0..be4730cf8bce 100644 --- a/src/doc/nomicon/destructors.md +++ b/src/doc/nomicon/destructors.md @@ -26,7 +26,7 @@ this is totally fine. For instance, a custom implementation of `Box` might write `Drop` like this: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -57,7 +57,7 @@ use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -135,7 +135,7 @@ The classic safe solution to overriding recursive drop and allowing moving out of Self during `drop` is to use an Option: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; diff --git a/src/test/run-pass/extern_fat_drop.rs b/src/test/run-pass/extern_fat_drop.rs index deb7e6bd5398..8ce1f744dee1 100644 --- a/src/test/run-pass/extern_fat_drop.rs +++ b/src/test/run-pass/extern_fat_drop.rs @@ -10,8 +10,6 @@ // aux-build:fat_drop.rs -#![feature(drop_in_place)] - extern crate fat_drop; fn main() { From f02c9e37415de1b838ec08f6cbc54524d5c755f7 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 26 Jan 2017 11:09:45 +0100 Subject: [PATCH 019/104] Rewrite the first sentence in slice::sort For every method, the first sentence should consisely explain what it does, not how. This sentence usually starts with a verb. It's really weird for `sort` to be explained in terms of another function, namely `sort_by`. There's no need for that because it's obvious how `sort` sorts elements: there is `T: Ord`. If `sort_by_key` does not have to explicitly state how it's implemented, then `sort` doesn't either. --- src/libcollections/slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index fc49c9f56438..11f513ed798e 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -509,7 +509,7 @@ impl [T] { core_slice::SliceExt::swap(self, a, b) } - /// Reverse the order of elements in a slice, in place. + /// Reverses the order of elements in a slice, in place. /// /// # Example /// @@ -1062,7 +1062,7 @@ impl [T] { core_slice::SliceExt::binary_search_by_key(self, b, f) } - /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. + /// Sorts the slice. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. /// From eaf182e5395e4e0ab0b792020daed1f12b99d688 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 25 Jan 2017 23:28:59 +0100 Subject: [PATCH 020/104] Add note for E0117 --- src/librustc_typeck/coherence/orphan.rs | 1 + src/test/compile-fail/E0117.rs | 1 + src/test/compile-fail/E0206.rs | 1 + src/test/compile-fail/coherence-impls-copy.rs | 5 ++++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 2b5a4515cd0d..c54f467a4c41 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -263,6 +263,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { .span_label(item.span, &format!("impl doesn't use types inside crate")) .note(&format!("the impl does not reference any types defined in \ this crate")) + .note("define and implement a trait or new type instead") .emit(); return; } diff --git a/src/test/compile-fail/E0117.rs b/src/test/compile-fail/E0117.rs index e9375e673253..4ba9c3382f35 100644 --- a/src/test/compile-fail/E0117.rs +++ b/src/test/compile-fail/E0117.rs @@ -11,6 +11,7 @@ impl Drop for u32 {} //~ ERROR E0117 //~^ NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } diff --git a/src/test/compile-fail/E0206.rs b/src/test/compile-fail/E0206.rs index 888e42ed3a18..1131e8e1b01c 100644 --- a/src/test/compile-fail/E0206.rs +++ b/src/test/compile-fail/E0206.rs @@ -16,6 +16,7 @@ impl Copy for Foo { } //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead #[derive(Copy, Clone)] struct Bar; diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index f686a146042c..fe121a3bc48f 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -37,6 +37,7 @@ impl Copy for (MyType, MyType) {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead impl Copy for &'static NotSync {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -46,8 +47,9 @@ impl Copy for [MyType] {} //~^ ERROR the trait `Copy` may not be implemented for this type //~| NOTE type is not a structure or enumeration //~| ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead +//~| NOTE impl doesn't use types inside crate impl Copy for &'static [NotSync] {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -55,6 +57,7 @@ impl Copy for &'static [NotSync] {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } From bd4d5ec758cac866af2ca8fc09b27ce0d0112786 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 26 Jan 2017 17:41:37 +0300 Subject: [PATCH 021/104] Better comments for FIXMEs --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9e3c1dcef8a6..0261bda2252a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1357,10 +1357,10 @@ impl<'a> Parser<'a> { self.expect_and()?; self.parse_borrowed_pointee()? } else if self.check_keyword(keywords::For) { - // FIXME plus priority + // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). self.parse_for_in_type()? } else if self.eat_keyword(keywords::Impl) { - // FIXME plus priority + // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). self.parse_impl_trait_type()? } else if self.token_is_bare_fn_keyword() { // BARE FUNCTION From 7095a48bf6c1257f7674059ec678ce5bbe10d195 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Jan 2017 09:04:07 -0800 Subject: [PATCH 022/104] travis: Turn off core dumps on OSX I've seen these take up quite a bit of log space and I have the sneaking suspicion that they're just making our test suite take longer (sometimes timing out on 32-bit OSX now). In any case the backtraces haven't proven too useful, unfortunately. --- .travis.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index bbe0cdfb6f8f..5e7c89fc100d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,17 +43,9 @@ matrix: SRC=. os: osx osx_image: xcode8.2 - before_script: &osx_before_script > - ulimit -c unlimited install: &osx_install_sccache > curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 | tar xJf - -C /usr/local/bin --strip-components=1 - after_failure: &osx_after_failure > - echo 'bt all' > cmds; - for file in $(ls /cores); do - echo core file $file; - lldb -c /cores/$file `which ld` -b -s cmds; - done - env: > SCRIPT="./x.py test && ./x.py dist" @@ -62,18 +54,14 @@ matrix: DEPLOY=1 os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure - env: > RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin --disable-rustbuild SRC=. os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" @@ -81,9 +69,7 @@ matrix: DEPLOY=1 os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure env: global: From fc490ad679328d657265352a71ed1f0e59a125bb Mon Sep 17 00:00:00 2001 From: king6cong Date: Fri, 27 Jan 2017 02:05:33 +0800 Subject: [PATCH 023/104] doc comment typo fix --- src/librustc/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 697ab6ee491d..d8d2b08de0bb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -514,7 +514,7 @@ pub enum BorrowKind { /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when you the closure + /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: /// /// let x: &mut isize = ...; From 36ad34d343c364f9d9570d5bea4d253882577f4e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 25 Jan 2017 14:40:47 +1300 Subject: [PATCH 024/104] save-analysis: get tables directly, accomodating them being missing Fixes an ICE when running with save-analsysis after an error --- src/librustc_save_analysis/dump_visitor.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 74521fe465bc..f128167bbf62 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -111,11 +111,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn nest_tables(&mut self, item_id: NodeId, f: F) where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>) { - let old_tables = self.save_ctxt.tables; let item_def_id = self.tcx.hir.local_def_id(item_id); - self.save_ctxt.tables = self.tcx.item_tables(item_def_id); - f(self); - self.save_ctxt.tables = old_tables; + match self.tcx.tables.borrow().get(&item_def_id) { + Some(tables) => { + let old_tables = self.save_ctxt.tables; + self.save_ctxt.tables = tables; + f(self); + self.save_ctxt.tables = old_tables; + } + None => f(self), + } } pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { From 8ad06af1311e7112d6f21709ba344d43867b547c Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Wed, 25 Jan 2017 21:16:38 -0800 Subject: [PATCH 025/104] Avoid ICE when pretty-printing non-local MIR item. This comes up when using `-Zunstable-options --unpretty=mir`. Previously, rustc would ICE due to an unwrap later in this function (after `as_local_node_id`). Instead, we should just ignore items from other crates when pretty-printing MIR. --- src/librustc_mir/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index e7188d536980..6602d26f17fc 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -92,7 +92,7 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, where I: Iterator, 'tcx: 'a { let mut first = true; - for def_id in iter { + for def_id in iter.filter(DefId::is_local) { let mir = &tcx.item_mir(def_id); if first { From e1280d81af3101d918fcd1ff9ca040b59e7d907b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 16 Jan 2017 23:42:11 -0800 Subject: [PATCH 026/104] Point to immutable arg/fields when trying to use as &mut Point to immutable borrow arguments and fields when trying to use them as mutable borrows. Add label to primary span on "cannot borrow as mutable" errors. Present the following output when trying to access an immutable borrow's field as mutable: ``` error[E0389]: cannot borrow data mutably in a `&` reference --> $DIR/issue-38147-1.rs:27:9 | 26 | fn f(&self) { | ----- use `&mut self` here to make mutable 27 | f.s.push('x'); | ^^^ assignment into an immutable reference ``` And the following when trying to access an immutable struct field as mutable: ``` error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-3.rs:17:9 | 12 | s: &'a String | ------------- use `&'a mut String` here to make mutable ...| 16 | fn f(&self) { | ----- use `&mut self` here to make mutable 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable ``` --- src/librustc/hir/map/blocks.rs | 2 +- src/librustc/middle/mem_categorization.rs | 57 +++++++ src/librustc/ty/mod.rs | 2 + src/librustc/ty/sty.rs | 2 +- .../borrowck/gather_loans/mod.rs | 6 +- src/librustc_borrowck/borrowck/mod.rs | 140 ++++++++++++------ src/test/ui/did_you_mean/issue-38147-1.rs | 31 ++++ src/test/ui/did_you_mean/issue-38147-1.stderr | 10 ++ src/test/ui/did_you_mean/issue-38147-2.rs | 21 +++ src/test/ui/did_you_mean/issue-38147-2.stderr | 11 ++ src/test/ui/did_you_mean/issue-38147-3.rs | 21 +++ src/test/ui/did_you_mean/issue-38147-3.stderr | 13 ++ src/test/ui/did_you_mean/issue-38147-4.rs | 19 +++ src/test/ui/did_you_mean/issue-38147-4.stderr | 10 ++ ...ck-borrow-overloaded-auto-deref-mut.stderr | 8 +- ...orrowck-borrow-overloaded-deref-mut.stderr | 4 +- ...borrowck-call-is-borrow-issue-12224.stderr | 6 +- ...owck-call-method-from-mut-aliasable.stderr | 2 +- .../ui/span/borrowck-fn-in-const-b.stderr | 2 +- .../ui/span/borrowck-object-mutability.stderr | 4 +- src/test/ui/span/mut-arg-hint.stderr | 6 +- 21 files changed, 310 insertions(+), 67 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-38147-1.rs create mode 100644 src/test/ui/did_you_mean/issue-38147-1.stderr create mode 100644 src/test/ui/did_you_mean/issue-38147-2.rs create mode 100644 src/test/ui/did_you_mean/issue-38147-2.stderr create mode 100644 src/test/ui/did_you_mean/issue-38147-3.rs create mode 100644 src/test/ui/did_you_mean/issue-38147-3.stderr create mode 100644 src/test/ui/did_you_mean/issue-38147-4.rs create mode 100644 src/test/ui/did_you_mean/issue-38147-4.stderr diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 91e88e2c73ff..ff2f1dc1ba28 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -38,7 +38,7 @@ use syntax_pos::Span; /// - The default implementation for a trait method. /// /// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct FnLikeNode<'a> { node: map::Node<'a> } /// MaybeFnLike wraps a method that indicates if an object diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 126d43aa6900..85902af68538 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -193,6 +193,63 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +impl<'tcx> cmt_<'tcx> { + pub fn get_field(&self, name: ast::Name) -> Option { + match self.cat { + Categorization::Deref(ref cmt, ..) | + Categorization::Interior(ref cmt, _) | + Categorization::Downcast(ref cmt, _) => { + if let Categorization::Local(_) = cmt.cat { + if let ty::TyAdt(def, _) = self.ty.sty { + return def.struct_variant().find_field_named(name).map(|x| x.did); + } + None + } else { + cmt.get_field(name) + } + } + _ => None + } + } + + pub fn get_field_name(&self) -> Option { + match self.cat { + Categorization::Interior(_, ref ik) => { + if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { + Some(name) + } else { + None + } + } + Categorization::Deref(ref cmt, ..) | + Categorization::Downcast(ref cmt, _) => { + cmt.get_field_name() + } + _ => None, + } + } + + pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { + match self.cat { + Categorization::Deref(ref cmt, ..) | + Categorization::Interior(ref cmt, _) | + Categorization::Downcast(ref cmt, _) => { + if let Categorization::Local(nid) = cmt.cat { + if let ty::TyAdt(_, _) = self.ty.sty { + if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { + return Some(nid); + } + } + None + } else { + cmt.get_arg_if_immutable(map) + } + } + _ => None + } + } +} + pub trait ast_node { fn id(&self) -> ast::NodeId; fn span(&self) -> Span; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5681e8c77662..36fc5149b40d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1325,6 +1325,7 @@ bitflags! { } } +#[derive(Debug)] pub struct VariantDef { /// The variant's DefId. If this is a tuple-like struct, /// this is the DefId of the struct's ctor. @@ -1335,6 +1336,7 @@ pub struct VariantDef { pub ctor_kind: CtorKind, } +#[derive(Debug)] pub struct FieldDef { pub did: DefId, pub name: Name, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b02bb7c6e4dd..d6164e69ffd3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -134,7 +134,7 @@ pub enum TypeVariants<'tcx> { TyRawPtr(TypeAndMut<'tcx>), /// A reference; a pointer with an associated lifetime. Written as - /// `&a mut T` or `&'a T`. + /// `&'a mut T` or `&'a T`. TyRef(&'tcx Region, TypeAndMut<'tcx>), /// The anonymous type of a function declaration/definition. Each diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 7f7f73d9a967..1783ca74a259 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -195,7 +195,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, bccx.report_aliasability_violation( borrow_span, loan_cause, - mc::AliasableReason::UnaliasableImmutable); + mc::AliasableReason::UnaliasableImmutable, + cmt); Err(()) } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | @@ -203,7 +204,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, bccx.report_aliasability_violation( borrow_span, loan_cause, - alias_cause); + alias_cause, + cmt); Err(()) } (..) => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 3464f1fa89a2..4386a5bd1591 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -540,7 +540,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { // Errors // Errors that can occur -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum bckerr_code<'tcx> { err_mutbl, /// superscope, subscope, loan cause @@ -550,7 +550,7 @@ pub enum bckerr_code<'tcx> { // Combination of an error code and the categorization of the expression // that caused it -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct BckError<'tcx> { span: Span, cause: AliasableViolationKind, @@ -601,12 +601,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => { } } - // General fallback. - let span = err.span.clone(); - let mut db = self.struct_span_err( - err.span, - &self.bckerr_to_string(&err)); - self.note_and_explain_bckerr(&mut db, err, span); + let mut db = self.bckerr_to_diag(&err); + self.note_and_explain_bckerr(&mut db, err); db.emit(); } @@ -771,8 +767,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String { - match err.code { + pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + let span = err.span.clone(); + let mut immutable_field = None; + + let msg = &match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -783,6 +782,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { format!("{} {}", err.cmt.mutbl.to_user_str(), self.cmt_to_string(&err.cmt)) + } Some(lp) => { format!("{} {} `{}`", @@ -807,6 +807,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { + // Check for this field's definition to see if it is an immutable reference + // and suggest making it mutable if that is the case. + immutable_field = err.cmt.get_field_name() + .and_then(|name| err.cmt.get_field(name)) + .and_then(|did| self.tcx.hir.as_local_node_id(did)) + .and_then(|nid| { + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { + return self.suggest_mut_for_immutable(&field.ty) + .map(|msg| (self.tcx.hir.span(nid), msg)); + } + None + }); + format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -830,13 +843,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { its contents can be safely reborrowed", descr) } + }; + + let mut db = self.struct_span_err(span, msg); + if let Some((span, msg)) = immutable_field { + db.span_label(span, &msg); } + db } pub fn report_aliasability_violation(&self, span: Span, kind: AliasableViolationKind, - cause: mc::AliasableReason) { + cause: mc::AliasableReason, + cmt: mc::cmt<'tcx>) { let mut is_closure = false; let prefix = match kind { MutabilityViolation => { @@ -903,6 +923,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); e.span_label(span, &"assignment into an immutable reference"); + if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { + self.immutable_argument_should_be_mut(nid, &mut e); + } e } }; @@ -913,6 +936,55 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { err.emit(); } + /// Given a type, if it is an immutable reference, return a suggestion to make it mutable + fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + // Check wether the argument is an immutable reference + if let hir::TyRptr(opt_lifetime, hir::MutTy { + mutbl: hir::Mutability::MutImmutable, + ref ty + }) = pty.node { + // Account for existing lifetimes when generating the message + if let Some(lifetime) = opt_lifetime { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { + if let Ok(lifetime_snippet) = self.tcx.sess.codemap() + .span_to_snippet(lifetime.span) { + return Some(format!("use `&{} mut {}` here to make mutable", + lifetime_snippet, + snippet)); + } + } + } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { + if snippet.starts_with("&") { + return Some(format!("use `{}` here to make mutable", + snippet.replace("&", "&mut "))); + } + } else { + bug!("couldn't find a snippet for span: {:?}", pty.span); + } + } + None + } + + fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { + let parent = self.tcx.hir.get_parent_node(nid); + let parent_node = self.tcx.hir.get(parent); + + // The parent node is like a fn + if let Some(fn_like) = FnLikeNode::from_node(parent_node) { + // `nid`'s parent's `Body` + let fn_body = self.tcx.hir.body(fn_like.body()); + // Get the position of `nid` in the arguments list + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + if let Some(i) = arg_pos { + // The argument's `Ty` + let arg_ty = &fn_like.decl().inputs[i]; + if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { + db.span_label(arg_ty.span, &msg); + } + } + } + } + fn report_out_of_scope_escaping_closure_capture(&self, err: &BckError<'tcx>, capture_span: Span) @@ -961,8 +1033,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>, - error_span: Span) { + pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + let error_span = err.span.clone(); match err.code { err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), err_out_of_scope(super_scope, sub_scope, cause) => { @@ -1103,41 +1175,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } _ => { - if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - let parent = self.tcx.hir.get_parent_node(local_id); - - if let Some(fn_like) = FnLikeNode::from_node(self.tcx.hir.get(parent)) { - if let Some(i) = self.tcx.hir.body(fn_like.body()).arguments.iter() - .position(|arg| arg.pat.id == local_id) { - let arg_ty = &fn_like.decl().inputs[i]; - if let hir::TyRptr( - opt_lifetime, - hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) = - arg_ty.node { - if let Some(lifetime) = opt_lifetime { - if let Ok(snippet) = self.tcx.sess.codemap() - .span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - db.span_label(arg_ty.span, - &format!("use `&{} mut {}` \ - here to make mutable", - lifetime_snippet, - snippet)); - } - } - } - else if let Ok(snippet) = self.tcx.sess.codemap() - .span_to_snippet(arg_ty.span) { - if snippet.starts_with("&") { - db.span_label(arg_ty.span, - &format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } - } - } - } + if let Categorization::Deref(..) = err.cmt.cat { + db.span_label(*error_span, &"cannot borrow as mutable"); + if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { + self.immutable_argument_should_be_mut(local_id, db); + } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { + if let Categorization::Local(local_id) = inner_cmt.cat { + self.immutable_argument_should_be_mut(local_id, db); } } } else if let Categorization::Local(local_id) = err.cmt.cat { diff --git a/src/test/ui/did_you_mean/issue-38147-1.rs b/src/test/ui/did_you_mean/issue-38147-1.rs new file mode 100644 index 000000000000..136921dd0a56 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-1.rs @@ -0,0 +1,31 @@ +// 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. + +struct Pass<'a> { + s: &'a mut String +} + +impl<'a> Pass<'a> { + fn f(&mut self) { + self.s.push('x'); + } +} + +struct Foo<'a> { + s: &'a mut String +} + +impl<'a> Foo<'a> { + fn f(&self) { + self.s.push('x'); + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-1.stderr b/src/test/ui/did_you_mean/issue-38147-1.stderr new file mode 100644 index 000000000000..e9f2b1dad806 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-1.stderr @@ -0,0 +1,10 @@ +error[E0389]: cannot borrow data mutably in a `&` reference + --> $DIR/issue-38147-1.rs:27:9 + | +26 | fn f(&self) { + | ----- use `&mut self` here to make mutable +27 | self.s.push('x'); + | ^^^^^^ assignment into an immutable reference + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-2.rs b/src/test/ui/did_you_mean/issue-38147-2.rs new file mode 100644 index 000000000000..a5d533edf75e --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-2.rs @@ -0,0 +1,21 @@ +// 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. + +struct Bar<'a> { + s: &'a String +} + +impl<'a> Bar<'a> { + fn f(&mut self) { + self.s.push('x'); + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr new file mode 100644 index 000000000000..fdaf0cd44d9d --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable borrowed content `*self.s` as mutable + --> $DIR/issue-38147-2.rs:17:9 + | +12 | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... +17 | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-3.rs b/src/test/ui/did_you_mean/issue-38147-3.rs new file mode 100644 index 000000000000..5e8f2d3eaefa --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-3.rs @@ -0,0 +1,21 @@ +// 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. + +struct Qux<'a> { + s: &'a String +} + +impl<'a> Qux<'a> { + fn f(&self) { + self.s.push('x'); + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr new file mode 100644 index 000000000000..d2280fa561bd --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -0,0 +1,13 @@ +error: cannot borrow immutable borrowed content `*self.s` as mutable + --> $DIR/issue-38147-3.rs:17:9 + | +12 | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... +16 | fn f(&self) { + | ----- use `&mut self` here to make mutable +17 | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-4.rs b/src/test/ui/did_you_mean/issue-38147-4.rs new file mode 100644 index 000000000000..4eb20ceeed48 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-4.rs @@ -0,0 +1,19 @@ +// 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. + +struct Foo<'a> { + s: &'a mut String +} + +fn f(x: usize, f: &Foo) { + f.s.push('x'); +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-4.stderr b/src/test/ui/did_you_mean/issue-38147-4.stderr new file mode 100644 index 000000000000..9a8853f4fbbd --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-4.stderr @@ -0,0 +1,10 @@ +error[E0389]: cannot borrow data mutably in a `&` reference + --> $DIR/issue-38147-4.rs:16:5 + | +15 | fn f(x: usize, f: &Foo) { + | ---- use `&mut Foo` here to make mutable +16 | f.s.push('x'); + | ^^^ assignment into an immutable reference + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index 1109351bff83..b83a6aaebf32 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 74 | fn deref_extend_mut_field1(x: &Own) -> &mut isize { | ----------- use `&mut Own` here to make mutable 75 | &mut x.y //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19 @@ -38,7 +38,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 101 | fn assign_field2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 102 | x.y = 3; //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5 @@ -64,7 +64,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 130 | fn deref_extend_mut_method1(x: &Own) -> &mut isize { | ----------- use `&mut Own` here to make mutable 131 | x.y_mut() //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 @@ -80,7 +80,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 142 | fn assign_method2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 143 | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to 10 previous errors diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index a5b704591614..af954a4d7924 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 50 | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { | -------------- use `&'a mut Own` here to make mutable 51 | &mut **x //~ ERROR cannot borrow - | ^^ + | ^^ cannot borrow as mutable error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 @@ -28,7 +28,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 62 | fn assign2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 63 | **x = 3; //~ ERROR cannot borrow - | ^^ + | ^^ cannot borrow as mutable error: aborting due to 4 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 16bb60013674..f2f0e027f016 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -17,13 +17,15 @@ error: cannot borrow immutable borrowed content `*f` as mutable 35 | fn test2(f: &F) where F: FnMut() { | -- use `&mut F` here to make mutable 36 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable - | ^^^^ + | ^^^^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*f.f` as mutable --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 | +43 | fn test4(f: &Test) { + | ----- use `&mut Test` here to make mutable 44 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable - | ^^^ + | ^^^ cannot borrow as mutable error[E0504]: cannot move `f` into closure because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr index a1af1ca7408a..2349bfaf75e6 100644 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -5,7 +5,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable | ---- use `&mut Foo` here to make mutable 26 | x.f(); 27 | x.h(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 41f549c708a2..251a9e4aa575 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 16 | fn broken(x: &Vec) { | ------------ use `&mut Vec` here to make mutable 17 | x.push(format!("this is broken")); - | ^ + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index 32e4da18056f..4ef1cb9c239e 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -5,13 +5,13 @@ error: cannot borrow immutable borrowed content `*x` as mutable | ---- use `&mut Foo` here to make mutable 18 | x.borrowed(); 19 | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*x` as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | 29 | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index 58f66c135843..e4ed06221471 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 17 | pub fn foo<'a>(mut a: &'a String) { | ---------- use `&'a mut String` here to make mutable 18 | a.push_str("foo"); - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:13:9 @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 12 | fn foo(mut a: &String) { | ------- use `&mut String` here to make mutable 13 | a.push_str("bar"); - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:25:9 @@ -20,7 +20,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 24 | pub fn foo(mut a: &String) { | ------- use `&mut String` here to make mutable 25 | a.push_str("foo"); - | ^ + | ^ cannot borrow as mutable error: aborting due to 3 previous errors From 1363cdaec9984269fc421cbc910f1f520b669f21 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 Jan 2017 17:51:10 +0200 Subject: [PATCH 027/104] Remove unnecessary LLVMRustPersonalityFn binding LLVM Core C bindings provide this function for all the versions back to what we support (3.7), and helps to avoid this unnecessary builder->function transition every time. Also a negative diff. --- src/librustc_llvm/ffi.rs | 2 +- src/librustc_trans/builder.rs | 2 +- src/librustc_trans/mir/mod.rs | 4 +++- src/rustllvm/RustWrapper.cpp | 8 -------- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index caa27404086b..58b2017ceb66 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -804,7 +804,7 @@ extern "C" { Name: *const c_char) -> ValueRef; pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, Handler: BasicBlockRef); - pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); + pub fn LLVMSetPersonalityFn(Func: ValueRef, Pers: ValueRef); // Add a case to the switch instruction pub fn LLVMAddCase(Switch: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef); diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index cf7f3e9501d1..c113716ca5c7 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -1107,7 +1107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn set_personality_fn(&self, personality: ValueRef) { unsafe { - llvm::LLVMRustSetPersonalityFn(self.llbuilder, personality); + llvm::LLVMSetPersonalityFn(self.llfn(), personality); } } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index eedd7956805b..30c138310da9 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -319,7 +319,9 @@ pub fn trans_mir<'a, 'tcx: 'a>( mircx.cleanup_kinds.iter_enumerated().map(|(bb, cleanup_kind)| { if let CleanupKind::Funclet = *cleanup_kind { let bcx = mircx.get_builder(bb); - bcx.set_personality_fn(mircx.ccx.eh_personality()); + unsafe { + llvm::LLVMSetPersonalityFn(mircx.llfn, mircx.ccx.eh_personality()); + } if base::wants_msvc_seh(ccx.sess()) { return Some(Funclet::new(bcx.cleanup_pad(None, &[]))); } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index bd0ff9e8d83c..34ee7d552f34 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1082,14 +1082,6 @@ extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, #endif } -extern "C" void LLVMRustSetPersonalityFn(LLVMBuilderRef B, - LLVMValueRef Personality) { -#if LLVM_VERSION_GE(3, 8) - unwrap(B)->GetInsertBlock()->getParent()->setPersonalityFn( - cast(unwrap(Personality))); -#endif -} - #if LLVM_VERSION_GE(3, 8) extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, From a2735c02493d816835a19249dd258e0c678530d0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 9 Oct 2016 10:30:11 -0700 Subject: [PATCH 028/104] rustc: Remove all "consider using an explicit lifetime parameter" suggestions These give so many incorrect suggestions that having them is detrimental to the user experience. The compiler should not be suggesting changes to the code that are wrong - it is infuriating: not only is the compiler telling you that _you don't understand_ borrowing, _the compiler itself_ appears to not understand borrowing. It does not inspire confidence. --- src/librustc/infer/error_reporting.rs | 718 +----------------- src/test/compile-fail/issue-13058.rs | 1 - ...me-inference-give-expl-lifetime-param-2.rs | 36 - ...me-inference-give-expl-lifetime-param-3.rs | 32 - ...time-inference-give-expl-lifetime-param.rs | 57 -- .../consider-using-explicit-lifetime.rs | 28 - .../consider-using-explicit-lifetime.stderr | 25 - 7 files changed, 4 insertions(+), 893 deletions(-) delete mode 100644 src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs delete mode 100644 src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs delete mode 100644 src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs delete mode 100644 src/test/ui/lifetimes/consider-using-explicit-lifetime.rs delete mode 100644 src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 23106d2bdc7d..2489a6a6c7a6 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -55,8 +55,6 @@ //! ported to this system, and which relies on string concatenation at the //! time of error detection. -use self::FreshOrKept::*; - use super::InferCtxt; use super::TypeTrace; use super::SubregionOrigin; @@ -71,13 +69,10 @@ use super::region_inference::ProcessedErrors; use super::region_inference::ProcessedErrorOrigin; use super::region_inference::SameRegions; -use std::collections::HashSet; - use hir::map as hir_map; use hir; use lint; -use hir::def::Def; use hir::def_id::DefId; use infer; use middle::region; @@ -86,13 +81,9 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; -use std::cell::{Cell, RefCell}; -use std::char::from_u32; use std::fmt; use syntax::ast; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax_pos::{self, Pos, Span}; +use syntax_pos::{Pos, Span}; use errors::DiagnosticBuilder; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -292,7 +283,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ProcessedErrors(ref origins, ref same_regions) => { if !same_regions.is_empty() { - self.report_processed_errors(origins, same_regions); + self.report_processed_errors(origins); } } } @@ -1050,9 +1041,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn report_processed_errors(&self, - origins: &[ProcessedErrorOrigin<'tcx>], - same_regions: &[SameRegions]) { - for (i, origin) in origins.iter().enumerate() { + origins: &[ProcessedErrorOrigin<'tcx>]) { + for origin in origins.iter() { let mut err = match *origin { ProcessedErrorOrigin::VariableFailure(ref var_origin) => self.report_inference_failure(var_origin.clone()), @@ -1060,78 +1050,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_concrete_failure(sr_origin.clone(), sub, sup), }; - // attach the suggestion to the last such error - if i == origins.len() - 1 { - self.give_suggestion(&mut err, same_regions); - } - err.emit(); } } - fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) { - let scope_id = same_regions[0].scope_id; - let parent = self.tcx.hir.get_parent(scope_id); - let parent_node = self.tcx.hir.find(parent); - let taken = lifetimes_in_scope(self.tcx, scope_id); - let life_giver = LifeGiver::with_taken(&taken[..]); - let node_inner = match parent_node { - Some(ref node) => match *node { - hir_map::NodeItem(ref item) => { - match item.node { - hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => { - Some((fn_decl, gen, unsafety, constness, item.name, item.span, body)) - } - _ => None, - } - } - hir_map::NodeImplItem(item) => { - let id = self.tcx.hir.get_parent(item.id); - if let Some(hir_map::NodeItem(parent_scope)) = self.tcx.hir.find(id) { - if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node { - // this impl scope implements a trait, do not recomend - // using explicit lifetimes (#37363) - return; - } - } - if let hir::ImplItemKind::Method(ref sig, body) = item.node { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span, - body)) - } else { - None - } - }, - hir_map::NodeTraitItem(item) => { - match item.node { - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span, - body)) - } - _ => None, - } - } - _ => None, - }, - None => None, - }; - let (fn_decl, generics, unsafety, constness, name, span, body) - = node_inner.expect("expect item fn"); - let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver); - let (fn_decl, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param( - err, &fn_decl, unsafety, constness, name, &generics, span, body); - } - pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) { for issue32330 in issue32330s { match *issue32330 { @@ -1154,530 +1076,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -struct RebuildPathInfo<'a> { - path: &'a hir::Path, - // indexes to insert lifetime on path.lifetimes - indexes: Vec, - // number of lifetimes we expect to see on the type referred by `path` - // (e.g., expected=1 for struct Foo<'a>) - expected: u32, - anon_nums: &'a HashSet, - region_names: &'a HashSet -} - -struct Rebuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_decl: &'a hir::FnDecl, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver, - cur_anon: Cell, - inserted_anons: RefCell>, -} - -enum FreshOrKept { - Fresh, - Kept -} - -impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_decl: &'a hir::FnDecl, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver) - -> Rebuilder<'a, 'gcx, 'tcx> { - Rebuilder { - tcx: tcx, - fn_decl: fn_decl, - generics: generics, - same_regions: same_regions, - life_giver: life_giver, - cur_anon: Cell::new(0), - inserted_anons: RefCell::new(HashSet::new()), - } - } - - fn rebuild(&self) -> (hir::FnDecl, hir::Generics) { - let mut inputs = self.fn_decl.inputs.clone(); - let mut output = self.fn_decl.output.clone(); - let mut ty_params = self.generics.ty_params.clone(); - let where_clause = self.generics.where_clause.clone(); - let mut kept_lifetimes = HashSet::new(); - for sr in self.same_regions { - self.cur_anon.set(0); - self.offset_cur_anon(); - let (anon_nums, region_names) = - self.extract_anon_nums_and_names(sr); - let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names); - match fresh_or_kept { - Kept => { kept_lifetimes.insert(lifetime.name); } - _ => () - } - inputs = self.rebuild_args_ty(&inputs[..], lifetime, - &anon_nums, ®ion_names); - output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names); - ty_params = self.rebuild_ty_params(ty_params, lifetime, - ®ion_names); - } - let fresh_lifetimes = self.life_giver.get_generated_lifetimes(); - let all_region_names = self.extract_all_region_names(); - let generics = self.rebuild_generics(self.generics, - &fresh_lifetimes, - &kept_lifetimes, - &all_region_names, - ty_params, - where_clause); - let new_fn_decl = hir::FnDecl { - inputs: inputs, - output: output, - variadic: self.fn_decl.variadic - }; - (new_fn_decl, generics) - } - - fn pick_lifetime(&self, - region_names: &HashSet) - -> (hir::Lifetime, FreshOrKept) { - if !region_names.is_empty() { - // It's not necessary to convert the set of region names to a - // vector of string and then sort them. However, it makes the - // choice of lifetime name deterministic and thus easier to test. - let mut names = Vec::new(); - for rn in region_names { - let lt_name = rn.to_string(); - names.push(lt_name); - } - names.sort(); - let name = Symbol::intern(&names[0]); - return (name_to_dummy_lifetime(name), Kept); - } - return (self.life_giver.give_lifetime(), Fresh); - } - - fn extract_anon_nums_and_names(&self, same_regions: &SameRegions) - -> (HashSet, HashSet) { - let mut anon_nums = HashSet::new(); - let mut region_names = HashSet::new(); - for br in &same_regions.regions { - match *br { - ty::BrAnon(i) => { - anon_nums.insert(i); - } - ty::BrNamed(_, name, _) => { - region_names.insert(name); - } - _ => () - } - } - (anon_nums, region_names) - } - - fn extract_all_region_names(&self) -> HashSet { - let mut all_region_names = HashSet::new(); - for sr in self.same_regions { - for br in &sr.regions { - match *br { - ty::BrNamed(_, name, _) => { - all_region_names.insert(name); - } - _ => () - } - } - } - all_region_names - } - - fn inc_cur_anon(&self, n: u32) { - let anon = self.cur_anon.get(); - self.cur_anon.set(anon+n); - } - - fn offset_cur_anon(&self) { - let mut anon = self.cur_anon.get(); - while self.inserted_anons.borrow().contains(&anon) { - anon += 1; - } - self.cur_anon.set(anon); - } - - fn inc_and_offset_cur_anon(&self, n: u32) { - self.inc_cur_anon(n); - self.offset_cur_anon(); - } - - fn track_anon(&self, anon: u32) { - self.inserted_anons.borrow_mut().insert(anon); - } - - fn rebuild_ty_params(&self, - ty_params: hir::HirVec, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::HirVec { - ty_params.into_iter().map(|ty_param| { - let bounds = self.rebuild_ty_param_bounds(ty_param.bounds, - lifetime, - region_names); - hir::TyParam { - name: ty_param.name, - id: ty_param.id, - bounds: bounds, - default: ty_param.default, - span: ty_param.span, - pure_wrt_drop: ty_param.pure_wrt_drop, - } - }).collect() - } - - fn rebuild_ty_param_bounds(&self, - ty_param_bounds: hir::TyParamBounds, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::TyParamBounds { - ty_param_bounds.iter().map(|tpb| { - match tpb { - &hir::RegionTyParamBound(lt) => { - // FIXME -- it's unclear whether I'm supposed to - // substitute lifetime here. I suspect we need to - // be passing down a map. - hir::RegionTyParamBound(lt) - } - &hir::TraitTyParamBound(ref poly_tr, modifier) => { - let tr = &poly_tr.trait_ref; - let last_seg = tr.path.segments.last().unwrap(); - let mut insert = Vec::new(); - let lifetimes = last_seg.parameters.lifetimes(); - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - let rebuild_info = RebuildPathInfo { - path: &tr.path, - indexes: insert, - expected: lifetimes.len() as u32, - anon_nums: &HashSet::new(), - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - hir::TraitTyParamBound(hir::PolyTraitRef { - bound_lifetimes: poly_tr.bound_lifetimes.clone(), - trait_ref: hir::TraitRef { - path: new_path, - ref_id: tr.ref_id, - }, - span: poly_tr.span, - }, modifier) - } - } - }).collect() - } - - fn rebuild_generics(&self, - generics: &hir::Generics, - add: &Vec, - keep: &HashSet, - remove: &HashSet, - ty_params: hir::HirVec, - where_clause: hir::WhereClause) - -> hir::Generics { - let mut lifetimes = Vec::new(); - for lt in add { - lifetimes.push(hir::LifetimeDef { - lifetime: *lt, - bounds: hir::HirVec::new(), - pure_wrt_drop: false, - }); - } - for lt in &generics.lifetimes { - if keep.contains(<.lifetime.name) || - !remove.contains(<.lifetime.name) { - lifetimes.push((*lt).clone()); - } - } - hir::Generics { - lifetimes: lifetimes.into(), - ty_params: ty_params, - where_clause: where_clause, - span: generics.span, - } - } - - fn rebuild_args_ty(&self, - inputs: &[P], - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> hir::HirVec> { - inputs.iter().map(|arg_ty| { - self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names) - }).collect() - } - - fn rebuild_output(&self, ty: &hir::FunctionRetTy, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) -> hir::FunctionRetTy { - match *ty { - hir::Return(ref ret_ty) => hir::Return( - self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names) - ), - hir::DefaultReturn(span) => hir::DefaultReturn(span), - } - } - - fn rebuild_arg_ty_or_output(&self, - ty: &hir::Ty, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> P { - let mut new_ty = P(ty.clone()); - let mut ty_queue = vec![ty]; - while !ty_queue.is_empty() { - let cur_ty = ty_queue.remove(0); - match cur_ty.node { - hir::TyRptr(lt_opt, ref mut_ty) => { - let rebuild = match lt_opt { - Some(lt) => region_names.contains(<.name), - None => { - let anon = self.cur_anon.get(); - let rebuild = anon_nums.contains(&anon); - if rebuild { - self.track_anon(anon); - } - self.inc_and_offset_cur_anon(1); - rebuild - } - }; - if rebuild { - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyRptr(Some(lifetime), mut_ty.clone()), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - ty_queue.push(&mut_ty.ty); - } - hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { - match path.def { - Def::Enum(did) | Def::TyAlias(did) | - Def::Struct(did) | Def::Union(did) => { - let generics = self.tcx.item_generics(did); - - let expected = - generics.regions.len() as u32; - let lifetimes = - path.segments.last().unwrap().parameters.lifetimes(); - let mut insert = Vec::new(); - if lifetimes.is_empty() { - let anon = self.cur_anon.get(); - for (i, a) in (anon..anon+expected).enumerate() { - if anon_nums.contains(&a) { - insert.push(i as u32); - } - self.track_anon(a); - } - self.inc_and_offset_cur_anon(expected); - } else { - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - } - let rebuild_info = RebuildPathInfo { - path: path, - indexes: insert, - expected: expected, - anon_nums: anon_nums, - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - let qself = maybe_qself.as_ref().map(|qself| { - self.rebuild_arg_ty_or_output(qself, lifetime, - anon_nums, region_names) - }); - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - _ => () - } - } - - hir::TyPtr(ref mut_ty) => { - ty_queue.push(&mut_ty.ty); - } - hir::TySlice(ref ty) | - hir::TyArray(ref ty, _) => { - ty_queue.push(&ty); - } - hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), - _ => {} - } - } - new_ty - } - - fn rebuild_ty(&self, - from: P, - to: P) - -> P { - - fn build_to(from: P, - to: &mut Option>) - -> P { - if Some(from.id) == to.as_ref().map(|ty| ty.id) { - return to.take().expect("`to` type found more than once during rebuild"); - } - from.map(|hir::Ty {id, node, span}| { - let new_node = match node { - hir::TyRptr(lifetime, mut_ty) => { - hir::TyRptr(lifetime, hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TyPtr(mut_ty) => { - hir::TyPtr(hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TySlice(ty) => hir::TySlice(build_to(ty, to)), - hir::TyArray(ty, e) => { - hir::TyArray(build_to(ty, to), e) - } - hir::TyTup(tys) => { - hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) - } - other => other - }; - hir::Ty { id: id, node: new_node, span: span } - }) - } - - build_to(from, &mut Some(to)) - } - - fn rebuild_path(&self, - rebuild_info: RebuildPathInfo, - lifetime: hir::Lifetime) - -> hir::Path - { - let RebuildPathInfo { - path, - indexes, - expected, - anon_nums, - region_names, - } = rebuild_info; - - let last_seg = path.segments.last().unwrap(); - let new_parameters = match last_seg.parameters { - hir::ParenthesizedParameters(..) => { - last_seg.parameters.clone() - } - - hir::AngleBracketedParameters(ref data) => { - let mut new_lts = Vec::new(); - if data.lifetimes.is_empty() { - // traverse once to see if there's a need to insert lifetime - let need_insert = (0..expected).any(|i| { - indexes.contains(&i) - }); - if need_insert { - for i in 0..expected { - if indexes.contains(&i) { - new_lts.push(lifetime); - } else { - new_lts.push(self.life_giver.give_lifetime()); - } - } - } - } else { - for (i, lt) in data.lifetimes.iter().enumerate() { - if indexes.contains(&(i as u32)) { - new_lts.push(lifetime); - } else { - new_lts.push(*lt); - } - } - } - let new_types = data.types.iter().map(|t| { - self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names) - }).collect(); - let new_bindings = data.bindings.iter().map(|b| { - hir::TypeBinding { - id: b.id, - name: b.name, - ty: self.rebuild_arg_ty_or_output(&b.ty, - lifetime, - anon_nums, - region_names), - span: b.span - } - }).collect(); - hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: new_lts.into(), - types: new_types, - infer_types: data.infer_types, - bindings: new_bindings, - }) - } - }; - let new_seg = hir::PathSegment { - name: last_seg.name, - parameters: new_parameters - }; - let mut new_segs = Vec::new(); - new_segs.extend_from_slice(path.segments.split_last().unwrap().1); - new_segs.push(new_seg); - hir::Path { - span: path.span, - def: path.def, - segments: new_segs.into() - } - } -} - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn give_expl_lifetime_param(&self, - err: &mut DiagnosticBuilder, - decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - name: ast::Name, - generics: &hir::Generics, - span: Span, - body: hir::BodyId) { - let s = hir::print::to_string(&self.tcx.hir, |s| { - use syntax::abi::Abi; - use syntax::print::pprust::PrintState; - - s.head("")?; - s.print_fn(decl, - unsafety, - constness, - Abi::Rust, - Some(name), - generics, - &hir::Inherited, - &[], - Some(body))?; - s.end()?; // Close the head box - s.end() // Close the outer box - }); - let msg = format!("consider using an explicit lifetime parameter as shown: {}", s); - err.span_help(span, &msg[..]); - } - fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> DiagnosticBuilder<'tcx> { @@ -1890,114 +1289,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - scope_id: ast::NodeId) - -> Vec { - let mut taken = Vec::new(); - let parent = tcx.hir.get_parent(scope_id); - let method_id_opt = match tcx.hir.find(parent) { - Some(node) => match node { - hir_map::NodeItem(item) => match item.node { - hir::ItemFn(.., ref gen, _) => { - taken.extend_from_slice(&gen.lifetimes); - None - }, - _ => None - }, - hir_map::NodeImplItem(ii) => { - match ii.node { - hir::ImplItemKind::Method(ref sig, _) => { - taken.extend_from_slice(&sig.generics.lifetimes); - Some(ii.id) - } - _ => None, - } - } - _ => None - }, - None => None - }; - if let Some(method_id) = method_id_opt { - let parent = tcx.hir.get_parent(method_id); - if let Some(node) = tcx.hir.find(parent) { - match node { - hir_map::NodeItem(item) => match item.node { - hir::ItemImpl(_, _, ref gen, ..) => { - taken.extend_from_slice(&gen.lifetimes); - } - _ => () - }, - _ => () - } - } - } - return taken; -} - -// LifeGiver is responsible for generating fresh lifetime names -struct LifeGiver { - taken: HashSet, - counter: Cell, - generated: RefCell>, -} - -impl LifeGiver { - fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver { - let mut taken_ = HashSet::new(); - for lt in taken { - let lt_name = lt.lifetime.name.to_string(); - taken_.insert(lt_name); - } - LifeGiver { - taken: taken_, - counter: Cell::new(0), - generated: RefCell::new(Vec::new()), - } - } - - fn inc_counter(&self) { - let c = self.counter.get(); - self.counter.set(c+1); - } - - fn give_lifetime(&self) -> hir::Lifetime { - let lifetime; - loop { - let mut s = String::from("'"); - s.push_str(&num_to_string(self.counter.get())); - if !self.taken.contains(&s) { - lifetime = name_to_dummy_lifetime(Symbol::intern(&s)); - self.generated.borrow_mut().push(lifetime); - break; - } - self.inc_counter(); - } - self.inc_counter(); - return lifetime; - - // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on - fn num_to_string(counter: usize) -> String { - let mut s = String::new(); - let (n, r) = (counter/26 + 1, counter % 26); - let letter: char = from_u32((r+97) as u32).unwrap(); - for _ in 0..n { - s.push(letter); - } - s - } - } - - fn get_generated_lifetimes(&self) -> Vec { - self.generated.borrow().clone() - } -} - -fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { - hir::Lifetime { id: ast::DUMMY_NODE_ID, - span: syntax_pos::DUMMY_SP, - name: name } -} - impl<'tcx> ObligationCause<'tcx> { fn as_failure_str(&self) -> &'static str { use traits::ObligationCauseCode::*; @@ -2038,4 +1329,3 @@ impl<'tcx> ObligationCause<'tcx> { } } } - diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index de578257e468..408c6d411de9 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -20,7 +20,6 @@ impl<'r> Itble<'r, usize, Range> for (usize, usize) { } fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool -//~^ HELP as shown: fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) { let cont_iter = cont.iter(); //~^ ERROR cannot infer an appropriate lifetime for autoref due to conflicting requirements diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs deleted file mode 100644 index d2d0dbf3e981..000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 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-tidy-linelength - -use std::ops::Range; - -trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } - -impl<'r> Itble<'r, usize, Range> for (usize, usize) { - fn iter(&'r self) -> Range { - let &(min, max) = self; - min..max - } -} - -fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) - let cont_iter = cont.iter(); //~ ERROR: cannot infer - let result = cont_iter.fold(Some(0), |state, val| { - state.map_or(None, |mask| { - let bit = 1 << val; - if mask & bit == 0 {Some(mask|bit)} else {None} - }) - }); - result.is_some() -} - -fn main() {} diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs deleted file mode 100644 index 6b22d434804f..000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2014 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-tidy-linelength - -use std::marker::PhantomData; - -struct Bar<'x, 'y, 'z> { bar: &'y i32, baz: i32, marker: PhantomData<(&'x(),&'y(),&'z())> } -fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) - (x.bar, &x.baz, &x.baz) - //~^ ERROR E0312 - //~| ERROR cannot infer - //~| ERROR cannot infer -} - -fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) { - //~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) - (x.bar, &x.baz, &x.baz) - //~^ ERROR E0312 - //~| ERROR cannot infer - //~| ERROR cannot infer -} - -fn main() { } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs deleted file mode 100644 index 4323929e2e37..000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2014 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-tidy-linelength - -use std::marker::PhantomData; - -struct Foo<'x> { bar: isize, marker: PhantomData<&'x ()> } -fn foo1<'a>(x: &Foo) -> &'a isize { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo1<'a>(x: &'a Foo) -> &'a isize - &x.bar //~ ERROR: cannot infer -} - -fn foo2<'a, 'b>(x: &'a Foo) -> &'b isize { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo2<'a>(x: &'a Foo) -> &'a isize - &x.bar //~ ERROR: cannot infer -} - -fn foo3<'a>(x: &Foo) -> (&'a isize, &'a isize) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo3<'a>(x: &'a Foo) -> (&'a isize, &'a isize) - (&x.bar, &x.bar) //~ ERROR: cannot infer - //~^ ERROR: cannot infer -} - -fn foo4<'a, 'b>(x: &'a Foo) -> (&'b isize, &'a isize, &'b isize) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo4<'a>(x: &'a Foo) -> (&'a isize, &'a isize, &'a isize) - (&x.bar, &x.bar, &x.bar) //~ ERROR: cannot infer - //~^ ERROR: cannot infer -} - -struct Cat<'x, T> { cat: &'x isize, t: T } -struct Dog<'y> { dog: &'y isize } - -fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x isize { - //~^ HELP consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x isize - x.t.dog //~ ERROR E0312 -} - -struct Baz<'x> { - bar: &'x isize -} - -impl<'a> Baz<'a> { - fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - (self.bar, x) //~ ERROR E0312 - //~^ ERROR E0312 - } -} - -fn main() {} diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs b/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs deleted file mode 100644 index 603f55af465f..000000000000 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -use std::str::FromStr; - -pub struct Foo<'a> { - field: &'a str, -} - -impl<'a> Foo<'a> { - fn bar(path: &str) -> Result { - Ok(Foo { field: path }) - } -} - -impl<'a> FromStr for Foo<'a> { - type Err = (); - fn from_str(path: &str) -> Result { - Ok(Foo { field: path }) - } -} diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr deleted file mode 100644 index 153aaa07833a..000000000000 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: main function not found - -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/consider-using-explicit-lifetime.rs:19:12 - | -19 | Ok(Foo { field: path }) - | ^^^ - -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/consider-using-explicit-lifetime.rs:26:12 - | -26 | Ok(Foo { field: path }) - | ^^^ - | -help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result - --> $DIR/consider-using-explicit-lifetime.rs:25:5 - | -25 | fn from_str(path: &str) -> Result { - | _____^ starting here... -26 | | Ok(Foo { field: path }) -27 | | } - | |_____^ ...ending here - -error: aborting due to 2 previous errors - From afac3ecacc92ccf7a3f693702c9582f930fb91f3 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 26 Jan 2017 21:28:22 -0500 Subject: [PATCH 029/104] Move stability attributes per feedback --- src/libcore/cell.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index cafa19afcb64..f889ff9a6ae2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -343,7 +343,6 @@ impl From for Cell { } } -#[unstable(feature = "move_cell", issue = "39264")] impl Cell { /// Creates a new `Cell` containing the given value. /// @@ -393,6 +392,7 @@ impl Cell { /// /// assert_eq!(5, old); /// ``` + #[unstable(feature = "move_cell", issue = "39264")] pub fn replace(&self, val: T) -> T { mem::replace(unsafe { &mut *self.value.get() }, val) } @@ -410,12 +410,12 @@ impl Cell { /// /// assert_eq!(five, 5); /// ``` + #[unstable(feature = "move_cell", issue = "39264")] pub fn into_inner(self) -> T { unsafe { self.value.into_inner() } } } -#[unstable(feature = "move_cell", issue = "39264")] impl Cell { /// Takes the value of the cell, leaving `Default::default()` in its place. /// @@ -431,6 +431,7 @@ impl Cell { /// assert_eq!(five, 5); /// assert_eq!(c.into_inner(), 0); /// ``` + #[unstable(feature = "move_cell", issue = "39264")] pub fn take(&self) -> T { self.replace(Default::default()) } From b8036b69086c6a43c86a20f0ac5e0bbc2d03fb9d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Jan 2017 04:36:12 +0200 Subject: [PATCH 030/104] Fix another endian-ness issue in i128 trans Apparently LLVMArbitraryPrecisionInteger demands integers to be in low-endian 64-bytes, rather than host-endian 64-bytes. This is weird, and obviously, not documented. Also, fixed now. And rustc now works a teeny bit more on big endians. --- src/librustc_trans/common.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 419267cb269c..0ba94fdfe635 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -234,7 +234,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_big_integral(t: Type, u: u128, sign_extend: bool) -> ValueRef { if ::std::mem::size_of::() == 16 { unsafe { - llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) + let words = [u as u64, u.wrapping_shr(64) as u64]; + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) } } else { // SNAP: remove after snapshot From d83687f68c1eed7d9783d23a7464e93aa5e886c3 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 26 Jan 2017 21:51:20 -0800 Subject: [PATCH 031/104] Fix can_begin_expr keyword behavior --- src/libsyntax/parse/token.rs | 24 ++++++++++++++- src/test/compile-fail/can-begin-expr-check.rs | 30 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/can-begin-expr-check.rs diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bf790b96e37f..43ad1eacf33b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -80,6 +80,28 @@ impl Lit { } } +fn ident_can_begin_expr(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::Box.name(), + keywords::Break.name(), + keywords::Continue.name(), + keywords::False.name(), + keywords::For.name(), + keywords::If.name(), + keywords::Loop.name(), + keywords::Match.name(), + keywords::Move.name(), + keywords::Return.name(), + keywords::True.name(), + keywords::Unsafe.name(), + keywords::While.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -163,7 +185,7 @@ impl Token { pub fn can_begin_expr(&self) -> bool { match *self { OpenDelim(..) => true, - Ident(..) => true, + Ident(ident) => ident_can_begin_expr(ident), Literal(..) => true, Not => true, BinOp(Minus) => true, diff --git a/src/test/compile-fail/can-begin-expr-check.rs b/src/test/compile-fail/can-begin-expr-check.rs new file mode 100644 index 000000000000..68f219c6ed99 --- /dev/null +++ b/src/test/compile-fail/can-begin-expr-check.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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. + +pub fn main() { + + return; + return (); + return as (); + return return as (); + return return return; + + return if true { + () + } else { + () + }; + + loop { + return break as (); + } + + return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` +} From a5561ce2b94c33add47d288e1826183c511ec9fa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 22 Jan 2017 12:53:35 -0800 Subject: [PATCH 032/104] rustc: Don't export builtins/panic/alloc syms This hides symbols from various unstable and implementation-detail crates of the standard library. Although typically transitive exported `pub extern` functions are exported from cdylibs, these crates aren't necessary as they're all implementation details. Closes #34493 --- src/liballoc_jemalloc/build.rs | 11 +++++++ src/liballoc_jemalloc/lib.rs | 2 +- src/liballoc_jemalloc/pthread_atfork_dummy.c | 6 ++++ src/librustc_trans/back/symbol_export.rs | 33 +++++++++++++++++++- 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/liballoc_jemalloc/pthread_atfork_dummy.c diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 1edcb0b1f24d..1143df0c6302 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -181,4 +181,15 @@ fn main() { } else if !target.contains("windows") && !target.contains("musl") { println!("cargo:rustc-link-lib=pthread"); } + + // The pthread_atfork symbols is used by jemalloc on android but the really + // old android we're building on doesn't have them defined, so just make + // sure the symbols are available. + if target.contains("androideabi") { + println!("cargo:rerun-if-changed=pthread_atfork_dummy.c"); + gcc::Config::new() + .flag("-fvisibility=hidden") + .file("pthread_atfork_dummy.c") + .compile("libpthread_atfork_dummy.a"); + } } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 241f8149d24d..fc8a5455d1d0 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -143,7 +143,7 @@ mod imp { // we're building on doesn't have them defined, so just make sure the symbols // are available. #[no_mangle] - #[cfg(target_os = "android")] + #[cfg(all(target_os = "android", not(cargobuild)))] pub extern "C" fn pthread_atfork(_prefork: *mut u8, _postfork_parent: *mut u8, _postfork_child: *mut u8) diff --git a/src/liballoc_jemalloc/pthread_atfork_dummy.c b/src/liballoc_jemalloc/pthread_atfork_dummy.c new file mode 100644 index 000000000000..f798afe741f6 --- /dev/null +++ b/src/liballoc_jemalloc/pthread_atfork_dummy.c @@ -0,0 +1,6 @@ +// See comments in build.rs for why this exists +int pthread_atfork(void* prefork, + void* postfork_parent, + void* postfork_child) { + return 0; +} diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 81be2d02f125..bea3ca8df70e 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -81,11 +81,25 @@ impl ExportedSymbols { for cnum in scx.sess().cstore.crates() { debug_assert!(cnum != LOCAL_CRATE); + // If this crate is a plugin and/or a custom derive crate, then + // we're not even going to link those in so we skip those crates. if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() || scx.sess().cstore.derive_registrar_fn(cnum).is_some() { continue; } + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = + scx.sess().cstore.is_allocator(cnum) || + scx.sess().cstore.is_panic_runtime(cnum) || + scx.sess().cstore.is_compiler_builtins(cnum); + let crate_exports = scx .sess() .cstore @@ -93,7 +107,24 @@ impl ExportedSymbols { .iter() .map(|&def_id| { let name = Instance::mono(scx, def_id).symbol_name(scx); - let export_level = export_level(scx, def_id); + let export_level = if special_runtime_crate { + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if name == "rust_eh_personality" || + name == "rust_eh_register_frames" || + name == "rust_eh_unregister_frames" { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } else { + export_level(scx, def_id) + }; debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); (name, export_level) }) From 3d6f263b2a162974725cdcb914ba9ad9c2dbef84 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 22 Jan 2017 12:58:56 -0800 Subject: [PATCH 033/104] std: Compile libbacktrace with -fvisibility=hidden We don't want these symbols exported from the standard library, this is just an internal implementation detail of the standard library currently. Closes #34984 --- src/liballoc_jemalloc/pthread_atfork_dummy.c | 10 ++++++++++ src/libstd/build.rs | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/liballoc_jemalloc/pthread_atfork_dummy.c b/src/liballoc_jemalloc/pthread_atfork_dummy.c index f798afe741f6..4e3df0ab26c3 100644 --- a/src/liballoc_jemalloc/pthread_atfork_dummy.c +++ b/src/liballoc_jemalloc/pthread_atfork_dummy.c @@ -1,3 +1,13 @@ +// 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. + // See comments in build.rs for why this exists int pthread_atfork(void* prefork, void* postfork_parent, diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 5e1c3a285156..9504194393f9 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -87,8 +87,9 @@ fn build_libbacktrace(host: &str, target: &str) { let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); - let cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) - .collect::>().join(" "); + let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) + .collect::>().join(" "); + cflags.push_str(" -fvisibility=hidden"); run(Command::new("sh") .current_dir(&build_dir) .arg(src_dir.join("configure").to_str().unwrap() From 450554ebf139d0b6ecde80f17c2ef89ff7de78bb Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Fri, 27 Jan 2017 11:33:24 +0200 Subject: [PATCH 034/104] Attempt at fixing dead code lints --- src/libstd/sys/unix/backtrace/mod.rs | 13 +++-- src/libstd/sys/windows/backtrace.rs | 52 ++----------------- src/libstd/sys/windows/backtrace_gnu.rs | 61 +++++++++++++++++++++++ src/libstd/sys/windows/c.rs | 45 +++++++++++------ src/libstd/sys/windows/mod.rs | 1 + src/libstd/sys_common/gnu/libbacktrace.rs | 2 +- 6 files changed, 106 insertions(+), 68 deletions(-) create mode 100644 src/libstd/sys/windows/backtrace_gnu.rs diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index e3f1b23f7a24..62e9c24ac304 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -83,9 +83,6 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. -use io; -use fs; - pub use self::tracing::write; // tracing impls: @@ -93,6 +90,12 @@ mod tracing; // symbol resolvers: mod printing; -pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] +pub mod gnu { + use io; + use fs; + + pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { + Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) + } } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index e6182cda58a2..94aaf439f3d5 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -30,13 +30,9 @@ use io; use libc::c_void; use mem; use ptr; -use path::PathBuf; -use fs::{OpenOptions, File}; -use sys::ext::fs::OpenOptionsExt; use sys::c; use sys::dynamic_lib::DynamicLibrary; use sys::mutex::Mutex; -use sys::handle::Handle; macro_rules! sym { ($lib:expr, $e:expr, $t:ident) => ( @@ -55,6 +51,10 @@ mod printing; #[path = "printing/gnu.rs"] mod printing; +#[cfg(target_env = "gnu")] +#[path = "backtrace_gnu.rs"] +pub mod gnu; + type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; @@ -161,47 +161,3 @@ unsafe fn _write(w: &mut Write) -> io::Result<()> { Ok(()) } - -fn query_full_process_image_name() -> io::Result { - unsafe { - let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, - c::FALSE, - c::GetCurrentProcessId())); - super::fill_utf16_buf(|buf, mut sz| { - if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { - 0 - } else { - sz - } - }, super::os2path) - } -} - -fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { - // We query the current image name, open the file without FILE_SHARE_DELETE so it - // can't be moved and then get the current image name again. If the names are the - // same than we have successfully locked the file - let image_name1 = query_full_process_image_name()?; - let file = OpenOptions::new() - .read(true) - .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) - .open(&image_name1)?; - let image_name2 = query_full_process_image_name()?; - - if image_name1 != image_name2 { - return Err(io::Error::new(io::ErrorKind::Other, - "executable moved while trying to lock it")); - } - - Ok((image_name1, file)) -} - -// Get the executable filename for libbacktrace -// This returns the path in the ANSI code page and a File which should remain open -// for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec, File)> { - let (executable, file) = lock_and_get_executable_filename()?; - let u16_executable = super::to_u16s(executable.into_os_string())?; - Ok((super::wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, - &u16_executable, true)?, file)) -} diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs new file mode 100644 index 000000000000..8282174a59ef --- /dev/null +++ b/src/libstd/sys/windows/backtrace_gnu.rs @@ -0,0 +1,61 @@ +// Copyright 2014 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. + +use io; +use sys::c; +use path::PathBuf; +use fs::{OpenOptions, File}; +use sys::ext::fs::OpenOptionsExt; +use sys::handle::Handle; +use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; + +fn query_full_process_image_name() -> io::Result { + unsafe { + let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, + c::FALSE, + c::GetCurrentProcessId())); + fill_utf16_buf(|buf, mut sz| { + if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { + 0 + } else { + sz + } + }, os2path) + } +} + +fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { + // We query the current image name, open the file without FILE_SHARE_DELETE so it + // can't be moved and then get the current image name again. If the names are the + // same than we have successfully locked the file + let image_name1 = query_full_process_image_name()?; + let file = OpenOptions::new() + .read(true) + .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) + .open(&image_name1)?; + let image_name2 = query_full_process_image_name()?; + + if image_name1 != image_name2 { + return Err(io::Error::new(io::ErrorKind::Other, + "executable moved while trying to lock it")); + } + + Ok((image_name1, file)) +} + +// Get the executable filename for libbacktrace +// This returns the path in the ANSI code page and a File which should remain open +// for as long as the path should remain valid +pub fn get_executable_filename() -> io::Result<(Vec, File)> { + let (executable, file) = lock_and_get_executable_filename()?; + let u16_executable = to_u16s(executable.into_os_string())?; + Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, + &u16_executable, true)?, file)) +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index c6fac6d1759b..1b29bf73c7ae 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -158,7 +158,6 @@ pub const WSAECONNREFUSED: c_int = 10061; pub const MAX_PROTOCOL_CHAIN: DWORD = 7; -pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; pub const TOKEN_READ: DWORD = 0x20008; pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; @@ -220,10 +219,6 @@ pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; -pub const CP_ACP: UINT = 0; - -pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; - pub const AF_INET: c_int = 2; pub const AF_INET6: c_int = 23; pub const SD_BOTH: c_int = 2; @@ -894,9 +889,6 @@ extern "system" { pNumArgs: *mut c_int) -> *mut *mut u16; pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD; - pub fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; pub fn OpenProcessToken(ProcessHandle: HANDLE, DesiredAccess: DWORD, TokenHandle: *mut HANDLE) -> BOOL; @@ -1153,12 +1145,6 @@ compat_fn! { _dwFlags: DWORD) -> DWORD { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, - _dwFlags: DWORD, - _lpExeName: LPWSTR, - _lpdwSize: LPDWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } @@ -1201,3 +1187,34 @@ compat_fn! { panic!("rwlocks not available") } } + +#[cfg(target_env = "gnu")] +mod gnu { + use super::*; + + pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; + + pub const CP_ACP: UINT = 0; + + pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; + + extern "system" { + pub fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + } + + compat_fn! { + kernel32: + + pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, + _dwFlags: DWORD, + _lpExeName: LPWSTR, + _lpdwSize: LPDWORD) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + } +} + +#[cfg(target_env = "gnu")] +pub use self::gnu::*; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 4468cf574b38..4424c6c6136c 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -172,6 +172,7 @@ fn os2path(s: &[u16]) -> PathBuf { PathBuf::from(OsString::from_wide(s)) } +#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename() fn wide_char_to_multi_byte(code_page: u32, flags: u32, s: &[u16], diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index 94d206f3ac3c..d464a13ad1d3 100644 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs @@ -126,7 +126,7 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, static mut STATE: *mut backtrace_state = ptr::null_mut(); if !STATE.is_null() { return STATE } - let filename = match ::sys::backtrace::get_executable_filename() { + let filename = match ::sys::backtrace::gnu::get_executable_filename() { Ok((filename, file)) => { // filename is purposely leaked here since libbacktrace requires // it to stay allocated permanently, file is also leaked so that From 09b3903aecf2c8cafa62cb67eccbe10a3ca09b5d Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Fri, 27 Jan 2017 18:08:51 +0000 Subject: [PATCH 035/104] Fix a few links in the docs --- src/doc/book/ffi.md | 2 +- src/liballoc/arc.rs | 2 +- src/libcore/hash/mod.rs | 1 + src/libcore/iter/iterator.rs | 6 +++--- src/libcore/sync/atomic.rs | 4 ++-- src/libstd/env.rs | 2 +- src/libstd/thread/mod.rs | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 50d4d0170fc7..8ab580e6aa9f 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -710,7 +710,7 @@ Please note that [`catch_unwind()`] will only catch unwinding panics, not those who abort the process. See the documentation of [`catch_unwind()`] for more information. -[`catch_unwind()`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html +[`catch_unwind()`]: ../std/panic/fn.catch_unwind.html # Representing opaque structs diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 459dc94f3368..38d843263ffd 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -59,7 +59,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// as long as `T` implements [`Send`] and [`Sync`][sync]. The disadvantage is /// that atomic operations are more expensive than ordinary memory accesses. /// If you are not sharing reference-counted values between threads, consider -/// using [`rc::Rc`] for lower overhead. [`Rc`] is a safe default, because +/// using [`rc::Rc`][`Rc`] for lower overhead. [`Rc`] is a safe default, because /// the compiler will catch any attempt to send an [`Rc`] between threads. /// However, a library might choose `Arc` in order to give library consumers /// more flexibility. diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 92657a6d0b1c..dd6edc7d39af 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -307,6 +307,7 @@ pub trait BuildHasher { /// [`BuildHasher`]: trait.BuildHasher.html /// [`Default`]: ../default/trait.Default.html /// [`Hasher`]: trait.Hasher.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub struct BuildHasherDefault(marker::PhantomData); diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 91c09c553056..3b406873d4b1 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1108,9 +1108,9 @@ pub trait Iterator { /// /// One of the keys to `collect()`'s power is that many things you might /// not think of as 'collections' actually are. For example, a [`String`] - /// is a collection of [`char`]s. And a collection of [`Result`] can - /// be thought of as single [`Result`]`, E>`. See the examples - /// below for more. + /// is a collection of [`char`]s. And a collection of + /// [`Result`][`Result`] can be thought of as single + /// [`Result`]`, E>`. See the examples below for more. /// /// Because `collect()` is so general, it can cause problems with type /// inference. As such, `collect()` is one of the few times you'll see diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a3cb12844777..743e3c41170a 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -24,7 +24,7 @@ //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2]. //! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations -//! [2]: https://doc.rust-lang.org/nomicon/atomics.html +//! [2]: ../../../nomicon/atomics.html //! //! Atomic variables are safe to share between threads (they implement `Sync`) //! but they do not themselves provide the mechanism for sharing and follow the @@ -144,7 +144,7 @@ unsafe impl Sync for AtomicPtr {} /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// /// For more information see the [nomicon][1]. -/// [1]: https://doc.rust-lang.org/nomicon/atomics.html +/// [1]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 80c64ae860f8..c3a6b2433ed8 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -222,7 +222,7 @@ fn _var_os(key: &OsStr) -> Option { /// Possible errors from the [`env::var`] function. /// -/// [env::var]: fn.var.html +/// [`env::var`]: fn.var.html #[derive(Debug, PartialEq, Eq, Clone)] #[stable(feature = "env", since = "1.0.0")] pub enum VarError { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 07a9b4bed992..8789006436c0 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -391,7 +391,7 @@ impl Builder { /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join /// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`panic!`]: ../../std/macro.panic.html +/// [`panic`]: ../../std/macro.panic.html /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn /// /// # Examples @@ -974,7 +974,7 @@ impl JoinHandle { /// to [`panic`]. /// /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`panic!`]: ../../std/macro.panic.html + /// [`panic`]: ../../std/macro.panic.html /// /// # Examples /// From c31d5b504144c4c542c3042b850cfc3b1066aa38 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 27 Jan 2017 19:45:18 +0100 Subject: [PATCH 036/104] Use less syscalls in `anon_pipe()` Save a `ENOSYS` failure from `pipe2` and don't try again. Use `cvt` instead of `cvt_r` for `pipe2` - `EINTR` is not an error `pipe2` can return. --- src/libstd/sys/unix/pipe.rs | 38 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index a8ed415b7f47..a5d60c257ed6 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -13,7 +13,8 @@ use io; use libc::{self, c_int}; use mem; use ptr; -use sys::cvt_r; +use sync::atomic::{AtomicBool, Ordering}; +use sys::{cvt, cvt_r}; use sys::fd::FileDesc; //////////////////////////////////////////////////////////////////////////////// @@ -29,34 +30,33 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in // 2.6.27, however, and because we support 2.6.18 we must detect this // support dynamically. - if cfg!(target_os = "linux") { + static TRY_PIPE2: AtomicBool = AtomicBool::new(cfg!(target_os = "linux")); + if TRY_PIPE2.load(Ordering::Relaxed) { weak! { fn pipe2(*mut c_int, c_int) -> c_int } if let Some(pipe) = pipe2.get() { - match cvt_r(|| unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { + match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { + TRY_PIPE2.store(false, Ordering::Relaxed); + // Fall through + }, + res => { + res?; return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))) + AnonPipe(FileDesc::new(fds[1])))); } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), } } } - if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } { - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?)) - } else { - Err(io::Error::last_os_error()) - } + cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; + + let fd0 = FileDesc::new(fds[0]); + let fd1 = FileDesc::new(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((AnonPipe(fd0), AnonPipe(fd1))) } impl AnonPipe { - pub fn from_fd(fd: FileDesc) -> io::Result { - fd.set_cloexec()?; - Ok(AnonPipe(fd)) - } - pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } From 0f2a5f686f3fbc3d66dce301e965b43d5c3acd63 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 27 Jan 2017 14:29:11 -0500 Subject: [PATCH 037/104] Fix up @carols10cents' mailmap entry The previous ways didn't work; this does. cc rust-lang-nursery/thanks#45 --- .mailmap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index be18190e12b3..90a5e0f5f321 100644 --- a/.mailmap +++ b/.mailmap @@ -43,8 +43,8 @@ Brian Anderson Brian Dawn Brian Leibig Brian Leibig Carl-Anton Ingmarsson -Carol (Nichols || Goulding) Carol Nichols -Carol (Nichols || Goulding) Carol Nichols +Carol (Nichols || Goulding) +Carol (Nichols || Goulding) Carol Willing Chris C Cerami Chris C Cerami Chris Pressey From 945177de8c78a8c727b6b591e6f3a3a840824bd2 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 27 Jan 2017 15:19:30 -0500 Subject: [PATCH 038/104] Fix @jethrogb's mailmap entry cc rust-lang-nursery/thanks#51 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index be18190e12b3..12b9b30edad9 100644 --- a/.mailmap +++ b/.mailmap @@ -102,6 +102,7 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jethro Beekman Jihyun Yu Jihyun Yu jihyun Jihyun Yu Jihyun Yu From 810b22bdb117cdffff06216c68e2875404e098eb Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 27 Jan 2017 15:27:26 -0500 Subject: [PATCH 039/104] Fix cyryl's mailmap entry --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index be18190e12b3..f4103941db3c 100644 --- a/.mailmap +++ b/.mailmap @@ -53,6 +53,7 @@ Clark Gaebel Clinton Ryan Corey Farwell Corey Farwell Corey Richardson Elaine "See More" Nemo +Cyryl PÅ‚otnicki Damien Schoof Daniel Ramos David Klein From f4010d7e618b38aea7ad073ffaf9bb90b12c6ca5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 27 Jan 2017 16:16:43 -0500 Subject: [PATCH 040/104] move `cast_kinds` into `TypeckTables` where it belongs --- src/librustc/ty/context.rs | 14 +++++++------- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_typeck/check/cast.rs | 4 ++-- src/librustc_typeck/check/writeback.rs | 10 ++++++++++ 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c78ba3b8a9bb..931d83f5e188 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -231,7 +231,11 @@ pub struct TypeckTables<'tcx> { /// of the struct - this is needed because it is non-trivial to /// normalize while preserving regions. This table is used only in /// MIR construction and hence is not serialized to metadata. - pub fru_field_types: NodeMap>> + pub fru_field_types: NodeMap>>, + + /// Maps a cast expression to its kind. This is keyed on the + /// *from* expression of the cast, not the cast itself. + pub cast_kinds: NodeMap, } impl<'tcx> TypeckTables<'tcx> { @@ -246,7 +250,8 @@ impl<'tcx> TypeckTables<'tcx> { closure_tys: NodeMap(), closure_kinds: NodeMap(), liberated_fn_sigs: NodeMap(), - fru_field_types: NodeMap() + fru_field_types: NodeMap(), + cast_kinds: NodeMap(), } } @@ -533,10 +538,6 @@ pub struct GlobalCtxt<'tcx> { /// expression defining the closure. pub closure_kinds: RefCell>>, - /// Maps a cast expression to its kind. This is keyed on the - /// *from* expression of the cast, not the cast itself. - pub cast_kinds: RefCell>, - /// Maps Fn items to a collection of fragment infos. /// /// The main goal is to identify data (each of which may be moved @@ -792,7 +793,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())), closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - cast_kinds: RefCell::new(NodeMap()), fragment_infos: RefCell::new(DefIdMap()), crate_name: Symbol::intern(crate_name), data_layout: data_layout, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 477a1086e815..7eaf1fe13986 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -663,7 +663,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprCast(ref source, _) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) { + if let Some(&TyCastKind::CoercionCast) = cx.tables().cast_kinds.get(&source.id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b6241c618df2..0b55513f8318 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -314,7 +314,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprCast(ref from, _) => { debug!("Checking const cast(id={})", from.id); - match v.tcx.cast_kinds.borrow().get(&from.id) { + match v.tables.cast_kinds.get(&from.id) { None => span_bug!(e.span, "no kind for cast"), Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { v.promotable = false; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 265dcada1f81..0218f1c70ba8 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -348,12 +348,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, CastKind::CoercionCast); + fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, CastKind::CoercionCast); } else { match self.do_check(fcx) { Ok(k) => { debug!(" -> {:?}", k); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k); + fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, k); } Err(e) => self.report_cast_error(fcx, e), }; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b95126af56aa..7f82d7829ce5 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -51,6 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_anon_types(); wbcx.visit_deferred_obligations(item_id); wbcx.visit_type_nodes(); + wbcx.visit_cast_types(); let tables = self.tcx.alloc_tables(wbcx.tables); self.tcx.tables.borrow_mut().insert(item_def_id, tables); @@ -291,6 +292,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + fn visit_cast_types(&mut self) { + if self.fcx.writeback_errors.get() { + return + } + + self.tables.cast_kinds.extend( + self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value))); + } + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return From 98bc300d697d0c9f68abb6bb6eef978bce8e25c5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 27 Jan 2017 23:23:26 +0200 Subject: [PATCH 041/104] Use __SIZEOF_INT128__ to test __int128 presence Previously we tested whether a handful of preprocessor variables indicating certain 64 bit platforms, but this does not work for other 64 bit targets which have support for __int128 in C compiler. Use the __SIZEOF__INT128__ preprocessor variable instead. This variable gets set to 16 by gcc and clang for every target where __int128 is supported. --- src/rt/rust_test_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index 5900b21b6126..2a14b3da7b7d 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -269,7 +269,7 @@ LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) { return li; } -#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && defined(__amd64__) +#if __SIZEOF_INT128__ == 16 unsigned __int128 identity(unsigned __int128 a) { return a; From 460a3b20aac43cf4a1deaee566125d60e250496d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Jan 2017 16:59:35 +0100 Subject: [PATCH 042/104] Don't generate doc if doc comments only filled with 'white' characters --- src/librustdoc/html/markdown.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index f2427008a7d4..8cc3b60a1840 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -237,8 +237,9 @@ pub fn render(w: &mut fmt::Formatter, let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); let text = (*orig_text).as_bytes(); let origtext = str::from_utf8(text).unwrap(); + let origtext = origtext.trim_left(); debug!("docblock: ==============\n{:?}\n=======", text); - let rendered = if lang.is_null() { + let rendered = if lang.is_null() || origtext.is_empty() { false } else { let rlang = (*lang).as_bytes(); From e2ef630a21ae7439477642c7b629cd9beaa1811e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 27 Jan 2017 14:51:47 -0800 Subject: [PATCH 043/104] rustdoc: Suppress warnings/errors with --test Threads spawned by the test framework have their output captured by default, so for `rustdoc --test` threads this propagates that capturing to the spawned thread that we now have. Closes #39327 --- src/librustdoc/test.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1f224cac9e91..ab0ac02fd88f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -429,8 +429,12 @@ impl Collector { should_panic: testing::ShouldPanic::No, }, testfn: testing::DynTestFn(box move |()| { + let panic = io::set_panic(None); + let print = io::set_print(None); match { rustc_driver::in_rustc_thread(move || { + io::set_panic(panic); + io::set_print(print); runtest(&test, &cratename, cfgs, From 1b4a6c86fa2acc4385c3c420773484d61ecc22b8 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 28 Jan 2017 01:01:16 +0200 Subject: [PATCH 044/104] Use libc::c_char instead of i8 due to platforms with unsigned char --- src/libstd/sys/unix/backtrace/mod.rs | 3 ++- src/libstd/sys/windows/backtrace_gnu.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index 62e9c24ac304..1eef89bf66f7 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -94,8 +94,9 @@ mod printing; pub mod gnu { use io; use fs; + use libc::c_char; - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { + pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) } } diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs index 8282174a59ef..f0d29dd4178d 100644 --- a/src/libstd/sys/windows/backtrace_gnu.rs +++ b/src/libstd/sys/windows/backtrace_gnu.rs @@ -10,6 +10,7 @@ use io; use sys::c; +use libc::c_char; use path::PathBuf; use fs::{OpenOptions, File}; use sys::ext::fs::OpenOptionsExt; @@ -53,7 +54,7 @@ fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { // Get the executable filename for libbacktrace // This returns the path in the ANSI code page and a File which should remain open // for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec, File)> { +pub fn get_executable_filename() -> io::Result<(Vec, File)> { let (executable, file) = lock_and_get_executable_filename()?; let u16_executable = to_u16s(executable.into_os_string())?; Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, From 4f559f8c33634670a8113091fe71080b21562031 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 4 Jan 2017 14:32:44 +0200 Subject: [PATCH 045/104] rustc_typeck: force users of RegionScope to get anon_region's one by one. --- src/librustc_typeck/astconv.rs | 14 ++--- src/librustc_typeck/check/mod.rs | 8 ++- src/librustc_typeck/rscope.rs | 91 ++++++++++---------------------- 3 files changed, 39 insertions(+), 74 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1af8b59cdfa7..166178d6c29c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -306,9 +306,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ast_region_to_region(self.tcx(), lifetime) } - None => self.tcx().mk_region(match rscope.anon_regions(default_span, 1) { - Ok(rs) => rs[0], - Err(params) => { + None => { + self.tcx().mk_region(rscope.anon_region(default_span).unwrap_or_else(|params| { let ampersand_span = Span { hi: default_span.lo, ..default_span}; let mut err = struct_span_err!(self.tcx().sess, ampersand_span, E0106, @@ -320,8 +319,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } err.emit(); ty::ReStatic - } - }) + })) + } }; debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", @@ -412,8 +411,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let regions = if expected_num_region_params == supplied_num_region_params { lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect() } else { - let anon_regions = - rscope.anon_regions(span, expected_num_region_params); + let anon_regions = (0..expected_num_region_params).map(|_| { + rscope.anon_region(span) + }).collect::, _>>(); if supplied_num_region_params != 0 || anon_regions.is_err() { report_lifetime_number_error(tcx, span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 20c4f8f95224..1e76267f32c3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1466,11 +1466,9 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { *self.next_region_var(infer::MiscVariable(span)) } - fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> { - Ok((0..count).map(|_| { - *self.next_region_var(infer::MiscVariable(span)) - }).collect()) + fn anon_region(&self, span: Span) + -> Result>> { + Ok(*self.next_region_var(infer::MiscVariable(span))) } } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 3f5e443a20a6..839eb8be9ace 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -33,18 +33,16 @@ pub type ElidedLifetime = Result>>; /// Defines strategies for handling regions that are omitted. For /// example, if one writes the type `&Foo`, then the lifetime of /// this reference has been omitted. When converting this -/// type, the generic functions in astconv will invoke `anon_regions` +/// type, the generic functions in astconv will invoke `anon_region` /// on the provided region-scope to decide how to translate this /// omitted region. /// -/// It is not always legal to omit regions, therefore `anon_regions` +/// It is not always legal to omit regions, therefore `anon_region` /// can return `Err(())` to indicate that this is not a scope in which /// regions can legally be omitted. pub trait RegionScope { - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>>; + fn anon_region(&self, span: Span) + -> Result>>; /// If an object omits any explicit lifetime bound, and none can /// be derived from the object traits, what should we use? If @@ -117,11 +115,9 @@ impl RegionScope for MaybeWithAnonTypes { self.base_scope.object_lifetime_default(span) } - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> { - self.base_scope.anon_regions(span, count) + fn anon_region(&self, span: Span) + -> Result>> { + self.base_scope.anon_region(span) } fn base_object_lifetime_default(&self, span: Span) -> ty::Region { @@ -139,10 +135,8 @@ impl RegionScope for MaybeWithAnonTypes { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn anon_regions(&self, - _span: Span, - _count: usize) - -> Result, Option>> { + fn anon_region(&self, _span: Span) + -> Result>> { Err(None) } @@ -165,12 +159,9 @@ impl UnelidableRscope { } impl RegionScope for UnelidableRscope { - fn anon_regions(&self, - _span: Span, - _count: usize) - -> Result, Option>> { - let UnelidableRscope(ref v) = *self; - Err(v.clone()) + fn anon_region(&self, _span: Span) + -> Result>> { + Err(self.0.clone()) } fn object_lifetime_default(&self, span: Span) -> Option { @@ -208,12 +199,10 @@ impl RegionScope for ElidableRscope { ty::ReStatic } - fn anon_regions(&self, - _span: Span, - count: usize) - -> Result, Option>> + fn anon_region(&self, _span: Span) + -> Result>> { - Ok(vec![self.default; count]) + Ok(self.default) } } @@ -232,10 +221,8 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { } impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> { + fn anon_region(&self, span: Span) + -> Result>> { if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess @@ -244,7 +231,7 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> `static_in_const` feature, see #35897") .emit(); } - Ok(vec![ty::ReStatic; count]) + Ok(ty::ReStatic) } fn object_lifetime_default(&self, span: Span) -> Option { @@ -268,12 +255,6 @@ impl BindingRscope { anon_bindings: Cell::new(0), } } - - fn next_region(&self) -> ty::Region { - let idx = self.anon_bindings.get(); - self.anon_bindings.set(idx + 1); - ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx)) - } } impl RegionScope for BindingRscope { @@ -288,12 +269,12 @@ impl RegionScope for BindingRscope { ty::ReStatic } - fn anon_regions(&self, - _: Span, - count: usize) - -> Result, Option>> + fn anon_region(&self, _: Span) + -> Result>> { - Ok((0..count).map(|_| self.next_region()).collect()) + let idx = self.anon_bindings.get(); + self.anon_bindings.set(idx + 1); + Ok(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx))) } } @@ -334,12 +315,10 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { self.base_scope.base_object_lifetime_default(span) } - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> + fn anon_region(&self, span: Span) + -> Result>> { - self.base_scope.anon_regions(span, count) + self.base_scope.anon_region(span) } fn anon_type_scope(&self) -> Option { @@ -369,22 +348,10 @@ impl<'r> RegionScope for ShiftedRscope<'r> { ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> + fn anon_region(&self, span: Span) + -> Result>> { - match self.base_scope.anon_regions(span, count) { - Ok(mut v) => { - for r in &mut v { - *r = ty::fold::shift_region(*r, 1); - } - Ok(v) - } - Err(errs) => { - Err(errs) - } - } + self.base_scope.anon_region(span).map(|r| ty::fold::shift_region(r, 1)) } fn anon_type_scope(&self) -> Option { From f79feba2053c78425b6490c8587359846fa6648f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 4 Jan 2017 23:23:11 +0200 Subject: [PATCH 046/104] rustc_typeck: pass all lifetimes through AstConv::opt_ast_region_to_region. --- src/librustc_typeck/astconv.rs | 204 +++++++++++++++---------------- src/librustc_typeck/check/mod.rs | 16 +-- src/librustc_typeck/collect.rs | 19 ++- src/librustc_typeck/rscope.rs | 24 ++-- 4 files changed, 131 insertions(+), 132 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 166178d6c29c..0a836a8ba222 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -64,7 +64,7 @@ use require_c_abi_if_variadic; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, ElisionFailureInfo, ElidedLifetime}; -use rscope::{AnonTypeScope, MaybeWithAnonTypes}; +use rscope::{AnonTypeScope, MaybeWithAnonTypes, ExplicitRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -161,70 +161,6 @@ struct ConvertedBinding<'tcx> { /// This type must not appear anywhere in other converted types. const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0)); -pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - lifetime: &hir::Lifetime) - -> &'tcx ty::Region { - let r = match tcx.named_region_map.defs.get(&lifetime.id) { - None => { - // should have been recorded by the `resolve_lifetime` pass - span_bug!(lifetime.span, "unresolved lifetime"); - } - - Some(&rl::DefStaticRegion) => { - ty::ReStatic - } - - Some(&rl::DefLateBoundRegion(debruijn, id)) => { - // If this region is declared on a function, it will have - // an entry in `late_bound`, but if it comes from - // `for<'a>` in some type or something, it won't - // necessarily have one. In that case though, we won't be - // changed from late to early bound, so we can just - // substitute false. - let issue_32330 = tcx.named_region_map - .late_bound - .get(&id) - .cloned() - .unwrap_or(ty::Issue32330::WontChange); - ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id), - lifetime.name, - issue_32330)) - } - - Some(&rl::DefEarlyBoundRegion(index, _)) => { - ty::ReEarlyBound(ty::EarlyBoundRegion { - index: index, - name: lifetime.name - }) - } - - Some(&rl::DefFreeRegion(scope, id)) => { - // As in DefLateBoundRegion above, could be missing for some late-bound - // regions, but also for early-bound regions. - let issue_32330 = tcx.named_region_map - .late_bound - .get(&id) - .cloned() - .unwrap_or(ty::Issue32330::WontChange); - ty::ReFree(ty::FreeRegion { - scope: scope.to_code_extent(&tcx.region_maps), - bound_region: ty::BrNamed(tcx.hir.local_def_id(id), - lifetime.name, - issue_32330) - }) - - // (*) -- not late-bound, won't change - } - }; - - debug!("ast_region_to_region(lifetime={:?} id={}) yields {:?}", - lifetime, - lifetime.id, - r); - - tcx.mk_region(r) -} - fn report_elision_failure( tcx: TyCtxt, db: &mut DiagnosticBuilder, @@ -296,38 +232,98 @@ fn report_elision_failure( } impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { - pub fn opt_ast_region_to_region(&self, + pub fn ast_region_to_region(&self, lifetime: &hir::Lifetime) -> &'tcx ty::Region { + self.opt_ast_region_to_region(&ExplicitRscope, lifetime.span, Some(lifetime), None) + } + + fn try_opt_ast_region_to_region(&self, rscope: &RegionScope, default_span: Span, - opt_lifetime: &Option) -> &'tcx ty::Region + opt_lifetime: Option<&hir::Lifetime>, + def: Option<&ty::RegionParameterDef>) + -> Result<&'tcx ty::Region, Option>> { - let r = match *opt_lifetime { - Some(ref lifetime) => { - ast_region_to_region(self.tcx(), lifetime) + let tcx = self.tcx(); + let name = opt_lifetime.map(|l| l.name); + let resolved = opt_lifetime.and_then(|l| tcx.named_region_map.defs.get(&l.id)); + let r = tcx.mk_region(match resolved { + Some(&rl::DefStaticRegion) => { + ty::ReStatic } - None => { - self.tcx().mk_region(rscope.anon_region(default_span).unwrap_or_else(|params| { - let ampersand_span = Span { hi: default_span.lo, ..default_span}; - - let mut err = struct_span_err!(self.tcx().sess, ampersand_span, E0106, - "missing lifetime specifier"); - err.span_label(ampersand_span, &format!("expected lifetime parameter")); - - if let Some(params) = params { - report_elision_failure(self.tcx(), &mut err, params); - } - err.emit(); - ty::ReStatic - })) + Some(&rl::DefLateBoundRegion(debruijn, id)) => { + // If this region is declared on a function, it will have + // an entry in `late_bound`, but if it comes from + // `for<'a>` in some type or something, it won't + // necessarily have one. In that case though, we won't be + // changed from late to early bound, so we can just + // substitute false. + let issue_32330 = tcx.named_region_map + .late_bound + .get(&id) + .cloned() + .unwrap_or(ty::Issue32330::WontChange); + ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id), + name.unwrap(), + issue_32330)) } - }; + + Some(&rl::DefEarlyBoundRegion(index, _)) => { + ty::ReEarlyBound(ty::EarlyBoundRegion { + index: index, + name: name.unwrap() + }) + } + + Some(&rl::DefFreeRegion(scope, id)) => { + // As in DefLateBoundRegion above, could be missing for some late-bound + // regions, but also for early-bound regions. + let issue_32330 = tcx.named_region_map + .late_bound + .get(&id) + .cloned() + .unwrap_or(ty::Issue32330::WontChange); + ty::ReFree(ty::FreeRegion { + scope: scope.to_code_extent(&tcx.region_maps), + bound_region: ty::BrNamed(tcx.hir.local_def_id(id), + name.unwrap(), + issue_32330) + }) + + // (*) -- not late-bound, won't change + } + + None => rscope.anon_region(default_span, def)? + }); debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", opt_lifetime, r); - r + Ok(r) + } + + pub fn opt_ast_region_to_region(&self, + rscope: &RegionScope, + default_span: Span, + opt_lifetime: Option<&hir::Lifetime>, + def: Option<&ty::RegionParameterDef>) -> &'tcx ty::Region + { + let tcx = self.tcx(); + self.try_opt_ast_region_to_region(rscope, default_span, opt_lifetime, def) + .unwrap_or_else(|params| { + let ampersand_span = Span { hi: default_span.lo, ..default_span}; + + let mut err = struct_span_err!(tcx.sess, ampersand_span, E0106, + "missing lifetime specifier"); + err.span_label(ampersand_span, &format!("expected lifetime parameter")); + + if let Some(params) = params { + report_elision_failure(tcx, &mut err, params); + } + err.emit(); + tcx.mk_region(ty::ReStatic) + }) } /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, @@ -408,25 +404,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); - let regions = if expected_num_region_params == supplied_num_region_params { - lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect() - } else { - let anon_regions = (0..expected_num_region_params).map(|_| { - rscope.anon_region(span) - }).collect::, _>>(); - - if supplied_num_region_params != 0 || anon_regions.is_err() { + let has_exact_lifetimes = expected_num_region_params == supplied_num_region_params; + let mut can_report_lifetime_count_mismatch = !has_exact_lifetimes; + let mut maybe_report_lifetime_count_mismatch = || { + if can_report_lifetime_count_mismatch { + can_report_lifetime_count_mismatch = false; report_lifetime_number_error(tcx, span, supplied_num_region_params, expected_num_region_params); } - - match anon_regions { - Ok(anon_regions) => anon_regions, - Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect() - } }; + if supplied_num_region_params != 0 { + maybe_report_lifetime_count_mismatch(); + } + // If a self-type was declared, one should be provided. assert_eq!(decl_generics.has_self, self_ty.is_some()); @@ -452,7 +444,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - tcx.mk_region(regions[i]) + let l = if has_exact_lifetimes { + Some(&lifetimes[i]) + } else { + None + }; + self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| { + maybe_report_lifetime_count_mismatch(); + tcx.mk_region(ty::ReStatic) + }) }, |def, substs| { let i = def.index as usize; @@ -1472,7 +1472,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }) } hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region); + let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region.as_ref(), None); debug!("TyRef r={:?}", r); let rscope1 = &ObjectLifetimeDefaultRscope::new( @@ -1823,7 +1823,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Some(&r) = explicit_region_bounds.get(0) { // Explicitly specified region bound. Use that. - return Some(ast_region_to_region(tcx, r)); + return Some(self.ast_region_to_region(r)); } if let Some(principal) = existential_predicates.principal() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e76267f32c3..e7544c10be3e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -80,7 +80,7 @@ pub use self::Expectation::*; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; -use astconv::{AstConv, ast_region_to_region}; +use astconv::AstConv; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; @@ -1466,9 +1466,13 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { *self.next_region_var(infer::MiscVariable(span)) } - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>> { - Ok(*self.next_region_var(infer::MiscVariable(span))) + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span) + }; + Ok(*self.next_region_var(v)) } } @@ -4404,11 +4408,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => &[] }; - if let Some(ast_lifetime) = lifetimes.get(i) { - ast_region_to_region(self.tcx, ast_lifetime) - } else { - self.region_var_for_def(span, def) - } + AstConv::opt_ast_region_to_region(self, self, span, lifetimes.get(i), Some(def)) }, |def, substs| { let mut i = def.index as usize; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1fd03b33a761..f954d2a5d616 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -57,7 +57,7 @@ There are some shortcomings in this design: */ -use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds}; +use astconv::{AstConv, Bounds, PartitionedBounds, partition_bounds}; use lint; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; @@ -1472,7 +1472,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { - ast_region_to_region(tcx, l) + AstConv::ast_region_to_region(&ccx.icx(&()), l) }).collect(), pure_wrt_drop: l.pure_wrt_drop, } @@ -1765,7 +1765,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, name: param.lifetime.name })); for bound in ¶m.bounds { - let bound_region = ast_region_to_region(ccx.tcx, bound); + let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); predicates.push(outlives.to_predicate()); } @@ -1816,7 +1816,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(tcx, lifetime); + let region = AstConv::ast_region_to_region(&ccx.icx(&()), lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); predicates.push(ty::Predicate::TypeOutlives(pred)) } @@ -1825,9 +1825,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = ast_region_to_region(tcx, ®ion_pred.lifetime); + let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime); for bound in ®ion_pred.bounds { - let r2 = ast_region_to_region(tcx, bound); + let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); predicates.push(ty::Predicate::RegionOutlives(pred)) } @@ -1935,7 +1935,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hir::TraitTyParamBound(..) => None, hir::RegionTyParamBound(ref lifetime) => - Some(ast_region_to_region(ccx.tcx, lifetime)), + Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime)), } }) .collect() @@ -1981,7 +1981,6 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, span: Span) -> Bounds<'tcx> { - let tcx = astconv.tcx(); let PartitionedBounds { trait_bounds, region_bounds @@ -1998,7 +1997,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, }).collect(); let region_bounds = region_bounds.into_iter().map(|r| { - ast_region_to_region(tcx, r) + astconv.ast_region_to_region(r) }).collect(); trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); @@ -2040,7 +2039,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, .collect() } hir::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(astconv.tcx(), lifetime); + let region = astconv.ast_region_to_region(lifetime); let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); vec![ty::Predicate::TypeOutlives(pred)] } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 839eb8be9ace..2ad1a7c3d685 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -41,7 +41,7 @@ pub type ElidedLifetime = Result>>; /// can return `Err(())` to indicate that this is not a scope in which /// regions can legally be omitted. pub trait RegionScope { - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>>; /// If an object omits any explicit lifetime bound, and none can @@ -115,9 +115,9 @@ impl RegionScope for MaybeWithAnonTypes { self.base_scope.object_lifetime_default(span) } - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>> { - self.base_scope.anon_region(span) + self.base_scope.anon_region(span, def) } fn base_object_lifetime_default(&self, span: Span) -> ty::Region { @@ -135,7 +135,7 @@ impl RegionScope for MaybeWithAnonTypes { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn anon_region(&self, _span: Span) + fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { Err(None) } @@ -159,7 +159,7 @@ impl UnelidableRscope { } impl RegionScope for UnelidableRscope { - fn anon_region(&self, _span: Span) + fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { Err(self.0.clone()) } @@ -199,7 +199,7 @@ impl RegionScope for ElidableRscope { ty::ReStatic } - fn anon_region(&self, _span: Span) + fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { Ok(self.default) @@ -221,7 +221,7 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { } impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { if !self.tcx.sess.features.borrow().static_in_const { self.tcx @@ -269,7 +269,7 @@ impl RegionScope for BindingRscope { ty::ReStatic } - fn anon_region(&self, _: Span) + fn anon_region(&self, _: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { let idx = self.anon_bindings.get(); @@ -315,10 +315,10 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { self.base_scope.base_object_lifetime_default(span) } - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>> { - self.base_scope.anon_region(span) + self.base_scope.anon_region(span, def) } fn anon_type_scope(&self) -> Option { @@ -348,10 +348,10 @@ impl<'r> RegionScope for ShiftedRscope<'r> { ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>> { - self.base_scope.anon_region(span).map(|r| ty::fold::shift_region(r, 1)) + self.base_scope.anon_region(span, def).map(|r| ty::fold::shift_region(r, 1)) } fn anon_type_scope(&self) -> Option { From 7a2a669bb70633a8c9ac4be708813b311c52ff93 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 9 Jan 2017 17:46:11 +0200 Subject: [PATCH 047/104] rustc: always include elidable lifetimes in HIR types. --- src/librustc/hir/intravisit.rs | 4 +- src/librustc/hir/lowering.rs | 152 ++++++++++++++---- src/librustc/hir/mod.rs | 45 ++---- src/librustc/hir/print.rs | 65 +++----- src/librustc/middle/cstore.rs | 3 + src/librustc/middle/resolve_lifetime.rs | 3 + src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_lint/bad_style.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 5 + src/librustc_metadata/decoder.rs | 15 +- src/librustc_metadata/encoder.rs | 14 +- src/librustc_metadata/schema.rs | 15 +- src/librustc_typeck/astconv.rs | 27 ++-- src/librustdoc/clean/mod.rs | 22 ++- .../unboxed-closure-sugar-region.rs | 4 +- 15 files changed, 248 insertions(+), 134 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d4095c6875c1..d71263bea004 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyPtr(ref mutable_type) => { visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref opt_lifetime, ref mutable_type) => { - walk_list!(visitor, visit_lifetime, opt_lifetime); + TyRptr(ref lifetime, ref mutable_type) => { + visitor.visit_lifetime(lifetime); visitor.visit_ty(&mutable_type.ty) } TyNever => {}, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 88d461cab9f4..4160ec5b74a9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -41,12 +41,12 @@ // in the HIR, especially for multiple identifiers. use hir; -use hir::map::Definitions; +use hir::map::{Definitions, DefKey}; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; use std::collections::BTreeMap; use std::iter; @@ -78,6 +78,8 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: FxHashMap, + + type_def_lifetime_params: DefIdMap, } pub trait Resolver { @@ -110,6 +112,7 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -123,24 +126,33 @@ enum ParamMode { impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { - self.lower_items(c); - let module = self.lower_mod(&c.module); - let attrs = self.lower_attrs(&c.attrs); - let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); - - hir::Crate { - module: module, - attrs: attrs, - span: c.span, - exported_macros: exported_macros, - items: self.items, - trait_items: self.trait_items, - impl_items: self.impl_items, - bodies: self.bodies, + /// Full-crate AST visitor that inserts into a fresh + /// `LoweringContext` any information that may be + /// needed from arbitrary locations in the crate. + /// E.g. The number of lifetime generic parameters + /// declared for every type and trait definition. + struct MiscCollector<'lcx, 'interner: 'lcx> { + lctx: &'lcx mut LoweringContext<'interner>, + } + + impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + match item.node { + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | + ItemKind::Enum(_, ref generics) | + ItemKind::Ty(_, ref generics) | + ItemKind::Trait(_, ref generics, ..) => { + let def_id = self.lctx.resolver.definitions().local_def_id(item.id); + let count = generics.lifetimes.len(); + self.lctx.type_def_lifetime_params.insert(def_id, count); + } + _ => {} + } + visit::walk_item(self, item); + } } - } - fn lower_items(&mut self, c: &Crate) { struct ItemLowerer<'lcx, 'interner: 'lcx> { lctx: &'lcx mut LoweringContext<'interner>, } @@ -167,8 +179,23 @@ impl<'a> LoweringContext<'a> { } } - let mut item_lowerer = ItemLowerer { lctx: self }; - visit::walk_crate(&mut item_lowerer, c); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); + visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); + + let module = self.lower_mod(&c.module); + let attrs = self.lower_attrs(&c.attrs); + let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + + hir::Crate { + module: module, + attrs: attrs, + span: c.span, + exported_macros: exported_macros, + items: self.items, + trait_items: self.trait_items, + impl_items: self.impl_items, + bodies: self.bodies, + } } fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) @@ -232,6 +259,14 @@ impl<'a> LoweringContext<'a> { result } + fn def_key(&mut self, id: DefId) -> DefKey { + if id.is_local() { + self.resolver.definitions().def_key(id.index) + } else { + self.sess.cstore.def_key(id) + } + } + fn lower_opt_sp_ident(&mut self, o_id: Option>) -> Option> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } @@ -279,7 +314,11 @@ impl<'a> LoweringContext<'a> { TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { - hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt)) + let lifetime = match *region { + Some(ref lt) => self.lower_lifetime(lt), + None => self.elided_lifetime(t.span) + }; + hir::TyRptr(lifetime, self.lower_mt(mt)) } TyKind::BareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { @@ -377,7 +416,40 @@ impl<'a> LoweringContext<'a> { } _ => param_mode }; - self.lower_path_segment(segment, param_mode) + + // Figure out if this is a type/trait segment, + // which may need lifetime elision performed. + let parent_def_id = |this: &mut Self, def_id: DefId| { + DefId { + krate: def_id.krate, + index: this.def_key(def_id).parent.expect("missing parent") + } + }; + let type_def_id = match resolution.base_def { + Def::AssociatedTy(def_id) if i + 2 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Def::Variant(def_id) if i + 1 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Def::Struct(def_id) | + Def::Union(def_id) | + Def::Enum(def_id) | + Def::TyAlias(def_id) | + Def::Trait(def_id) if i + 1 == proj_start => Some(def_id), + _ => None + }; + + let num_lifetimes = type_def_id.map_or(0, |def_id| { + if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { + return n; + } + assert!(!def_id.is_local()); + let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id); + self.type_def_lifetime_params.insert(def_id, n); + n + }); + self.lower_path_segment(p.span, segment, param_mode, num_lifetimes) }).collect(), span: p.span, }); @@ -411,7 +483,7 @@ impl<'a> LoweringContext<'a> { // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { - let segment = P(self.lower_path_segment(segment, param_mode)); + let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0)); let qpath = hir::QPath::TypeRelative(ty, segment); // It's finished, return the extension of the right node type. @@ -443,7 +515,7 @@ impl<'a> LoweringContext<'a> { hir::Path { def: self.expect_full_def(id), segments: segments.map(|segment| { - self.lower_path_segment(segment, param_mode) + self.lower_path_segment(p.span, segment, param_mode, 0) }).chain(name.map(|name| { hir::PathSegment { name: name, @@ -464,10 +536,12 @@ impl<'a> LoweringContext<'a> { } fn lower_path_segment(&mut self, + path_span: Span, segment: &PathSegment, - param_mode: ParamMode) + param_mode: ParamMode, + expected_lifetimes: usize) -> hir::PathSegment { - let parameters = if let Some(ref parameters) = segment.parameters { + let mut parameters = if let Some(ref parameters) = segment.parameters { match **parameters { PathParameters::AngleBracketed(ref data) => { let data = self.lower_angle_bracketed_parameter_data(data, param_mode); @@ -482,6 +556,14 @@ impl<'a> LoweringContext<'a> { hir::AngleBracketedParameters(data) }; + if let hir::AngleBracketedParameters(ref mut data) = parameters { + if data.lifetimes.is_empty() { + data.lifetimes = (0..expected_lifetimes).map(|_| { + self.elided_lifetime(path_span) + }).collect(); + } + } + hir::PathSegment { name: segment.identifier.name, parameters: parameters, @@ -628,10 +710,6 @@ impl<'a> LoweringContext<'a> { lts.iter().map(|l| self.lower_lifetime_def(l)).collect() } - fn lower_opt_lifetime(&mut self, o_lt: &Option) -> Option { - o_lt.as_ref().map(|lt| self.lower_lifetime(lt)) - } - fn lower_generics(&mut self, g: &Generics) -> hir::Generics { // Collect `?Trait` bounds in where clause and move them to parameter definitions. let mut add_bounds = NodeMap(); @@ -751,8 +829,12 @@ impl<'a> LoweringContext<'a> { } fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { + let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) { + hir::QPath::Resolved(None, path) => path.and_then(|path| path), + qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath) + }; hir::TraitRef { - path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false), + path: path, ref_id: p.ref_id, } } @@ -2276,4 +2358,12 @@ impl<'a> LoweringContext<'a> { span: span, }) } + + fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { + hir::Lifetime { + id: self.next_id(), + span: span, + name: keywords::Invalid.name() + } + } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fe086347884b..94cb33b138c5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -77,6 +77,13 @@ pub mod svh; pub struct Lifetime { pub id: NodeId, pub span: Span, + + /// Either "'a", referring to a named lifetime definition, + /// or "" (aka keywords::Invalid), for elision placeholders. + /// + /// HIR lowering inserts these placeholders in type paths that + /// refer to type definitions needing lifetime parameters, + /// `&T` and `&mut T`, and trait objects without `... + 'a`. pub name: Name, } @@ -89,6 +96,12 @@ impl fmt::Debug for Lifetime { } } +impl Lifetime { + pub fn is_elided(&self) -> bool { + self.name == keywords::Invalid.name() + } +} + /// A lifetime definition, eg `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { @@ -165,30 +178,6 @@ impl PathParameters { }) } - pub fn is_empty(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => data.is_empty(), - - // Even if the user supplied no types, something like - // `X()` is equivalent to `X<(),()>`. - ParenthesizedParameters(..) => false, - } - } - - pub fn has_lifetimes(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(), - ParenthesizedParameters(_) => false, - } - } - - pub fn has_types(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.types.is_empty(), - ParenthesizedParameters(..) => true, - } - } - /// Returns the types that the user wrote. Note that these do not necessarily map to the type /// parameters in the parenthesized case. pub fn types(&self) -> HirVec<&P> { @@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData { pub bindings: HirVec, } -impl AngleBracketedParameterData { - fn is_empty(&self) -> bool { - self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() - } -} - /// A path like `Foo(A,B) -> C` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ParenthesizedParameterData { @@ -1208,7 +1191,7 @@ pub enum Ty_ { /// A raw pointer (`*const T` or `*mut T`) TyPtr(MutTy), /// A reference (`&'a T` or `&'a mut T`) - TyRptr(Option, MutTy), + TyRptr(Lifetime, MutTy), /// A bare function (e.g. `fn(usize) -> bool`) TyBareFn(P), /// The never type (`!`) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d4bb2d37091b..8e866f571749 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -26,6 +26,7 @@ use syntax_pos::{self, BytePos}; use hir; use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd}; +use std::cell::Cell; use std::io::{self, Write, Read}; pub enum AnnNode<'a> { @@ -359,9 +360,9 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_opt_lifetime(&mut self, lifetime: &Option) -> io::Result<()> { - if let Some(l) = *lifetime { - self.print_lifetime(&l)?; + pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { + if !lifetime.is_elided() { + self.print_lifetime(lifetime)?; self.nbsp()?; } Ok(()) @@ -1553,65 +1554,49 @@ impl<'a> State<'a> { parameters: &hir::PathParameters, colons_before_params: bool) -> io::Result<()> { - if parameters.is_empty() { - let infer_types = match *parameters { - hir::AngleBracketedParameters(ref data) => data.infer_types, - hir::ParenthesizedParameters(_) => false - }; - - // FIXME(eddyb) See the comment below about infer_types. - if !(infer_types && false) { - return Ok(()); - } - } - - if colons_before_params { - word(&mut self.s, "::")? - } - match *parameters { hir::AngleBracketedParameters(ref data) => { - word(&mut self.s, "<")?; - - let mut comma = false; - for lifetime in &data.lifetimes { - if comma { - self.word_space(",")? + let start = if colons_before_params { "::<" } else { "<" }; + let empty = Cell::new(true); + let start_or_comma = |this: &mut Self| { + if empty.get() { + empty.set(false); + word(&mut this.s, start) + } else { + this.word_space(",") + } + }; + + if !data.lifetimes.iter().all(|lt| lt.is_elided()) { + for lifetime in &data.lifetimes { + start_or_comma(self)?; + self.print_lifetime(lifetime)?; } - self.print_lifetime(lifetime)?; - comma = true; } if !data.types.is_empty() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?; - comma = true; } // FIXME(eddyb) This would leak into error messages, e.g.: // "non-exhaustive patterns: `Some::<..>(_)` not covered". if data.infer_types && false { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; word(&mut self.s, "..")?; - comma = true; } for binding in data.bindings.iter() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.print_name(binding.name)?; space(&mut self.s)?; self.word_space("=")?; self.print_type(&binding.ty)?; - comma = true; } - word(&mut self.s, ">")? + if !empty.get() { + word(&mut self.s, ">")? + } } hir::ParenthesizedParameters(ref data) => { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 496a3d4a4984..8cf13cddc8c7 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -182,6 +182,7 @@ pub trait CrateStore<'tcx> { -> ty::GenericPredicates<'tcx>; fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx>; + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize); fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef; @@ -331,6 +332,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx> { bug!("item_generics") } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) + { bug!("item_generics_own_param_counts") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef { bug!("trait_def") } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index dd99aea909fa..a09f0ed7552b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -279,6 +279,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + if lifetime_ref.is_elided() { + return; + } if lifetime_ref.name == keywords::StaticLifetime.name() { self.insert_lifetime(lifetime_ref, DefStaticRegion); return; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4ce6c9527571..46179b31d5cb 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -939,12 +939,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { /// Given a type, if it is an immutable reference, return a suggestion to make it mutable fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { // Check wether the argument is an immutable reference - if let hir::TyRptr(opt_lifetime, hir::MutTy { + if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if let Some(lifetime) = opt_lifetime { + if !lifetime.is_elided() { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { if let Ok(lifetime_snippet) = self.tcx.sess.codemap() .span_to_snippet(lifetime.span) { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index d4ab31da8a31..05ba262ef90c 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -377,8 +377,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if path.segments.len() == 1 && path.segments[0].parameters.is_empty() { - if let Def::Const(..) = path.def { + if let Def::Const(..) = path.def { + if path.segments.len() == 1 { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", path.segments[0].name, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d100cb53a8b0..03b2b0114f19 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -110,6 +110,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).get_generics(def.index, tcx) } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).generics_own_param_counts(def.index) + } + fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 101531b52afb..bfc4257bda01 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -598,7 +598,20 @@ impl<'a, 'tcx> CrateMetadata { item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx> { - self.entry(item_id).generics.unwrap().decode((self, tcx)) + let g = self.entry(item_id).generics.unwrap().decode(self); + ty::Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: g.regions.decode((self, tcx)).collect(), + types: g.types.decode((self, tcx)).collect(), + has_self: g.has_self, + } + } + + pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) { + let g = self.entry(item_id).generics.unwrap().decode(self); + (g.regions.len, g.types.len) } pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2f71776ecf75..c407c27b096e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -417,9 +417,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_generics(&mut self, def_id: DefId) -> Lazy> { + fn encode_generics(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(tcx.item_generics(def_id)) + let g = tcx.item_generics(def_id); + let regions = self.lazy_seq_ref(&g.regions); + let types = self.lazy_seq_ref(&g.types); + self.lazy(&Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: regions, + types: types, + has_self: g.has_self, + }) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 74825a5c6e3f..4f9f2d23f5d3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -213,7 +213,7 @@ pub struct Entry<'tcx> { pub ty: Option>>, pub inherent_impls: LazySeq, pub variances: LazySeq, - pub generics: Option>>, + pub generics: Option>>, pub predicates: Option>>, pub ast: Option>>, @@ -247,6 +247,19 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer), } +/// A copy of `ty::Generics` which allows lazy decoding of +/// `regions` and `types` (e.g. knowing the number of type +/// and lifetime parameters before `TyCtxt` is created). +#[derive(RustcEncodable, RustcDecodable)] +pub struct Generics<'tcx> { + pub parent: Option, + pub parent_regions: u32, + pub parent_types: u32, + pub regions: LazySeq>, + pub types: LazySeq>, + pub has_self: bool, +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0a836a8ba222..bc8e56e811ed 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -404,19 +404,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); - let has_exact_lifetimes = expected_num_region_params == supplied_num_region_params; - let mut can_report_lifetime_count_mismatch = !has_exact_lifetimes; - let mut maybe_report_lifetime_count_mismatch = || { - if can_report_lifetime_count_mismatch { - can_report_lifetime_count_mismatch = false; + let mut reported_lifetime_count_mismatch = false; + let mut report_lifetime_count_mismatch = || { + if !reported_lifetime_count_mismatch { + reported_lifetime_count_mismatch = true; + let all_infer = lifetimes.iter().all(|lt| lt.is_elided()); + let supplied = if all_infer { 0 } else { supplied_num_region_params }; report_lifetime_number_error(tcx, span, - supplied_num_region_params, + supplied, expected_num_region_params); } }; - if supplied_num_region_params != 0 { - maybe_report_lifetime_count_mismatch(); + if expected_num_region_params != supplied_num_region_params { + report_lifetime_count_mismatch(); } // If a self-type was declared, one should be provided. @@ -444,13 +445,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - let l = if has_exact_lifetimes { - Some(&lifetimes[i]) - } else { - None - }; + let l = lifetimes.get(i); self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| { - maybe_report_lifetime_count_mismatch(); + report_lifetime_count_mismatch(); tcx.mk_region(ty::ReStatic) }) }, |def, substs| { @@ -1472,7 +1469,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }) } hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region.as_ref(), None); + let r = self.opt_ast_region_to_region(rscope, ast_ty.span, Some(region), None); debug!("TyRef r={:?}", r); let rscope1 = &ObjectLifetimeDefaultRscope::new( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 080bc5072d69..54a5b9f43c0d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1688,9 +1688,15 @@ impl Clean for hir::Ty { match self.node { TyNever => Never, TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), - TyRptr(ref l, ref m) => - BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), - type_: box m.ty.clean(cx)}, + TyRptr(ref l, ref m) => { + let lifetime = if l.is_elided() { + None + } else { + Some(l.clean(cx)) + }; + BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx), + type_: box m.ty.clean(cx)} + } TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, length) => { use rustc_const_eval::eval_length; @@ -1729,7 +1735,9 @@ impl Clean for hir::Ty { for (i, lt_param) in generics.lifetimes.iter().enumerate() { if let Some(lt) = provided_params.lifetimes().get(i).cloned() .cloned() { - lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + if !lt.is_elided() { + lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + } } } return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx)); @@ -2242,7 +2250,11 @@ impl Clean for hir::PathParameters { match *self { hir::AngleBracketedParameters(ref data) => { PathParameters::AngleBracketed { - lifetimes: data.lifetimes.clean(cx), + lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) { + vec![] + } else { + data.lifetimes.clean(cx) + }, types: data.types.clean(cx), bindings: data.bindings.clean(cx) } diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs index 057b496bd43e..18a1185d695f 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-region.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -38,9 +38,9 @@ fn test<'a,'b>() { } fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { +//~^ ERROR wrong number of lifetime parameters: expected 1, found 0 // Here, the omitted lifetimes are expanded to distinct things. - same_type(x, y) //~ ERROR cannot infer - //~^ ERROR cannot infer + same_type(x, y) } fn main() { } From 0682a75f44c7fee5e7c60d72030deea8e4841732 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 8 Jan 2017 22:40:04 +0200 Subject: [PATCH 048/104] rustc: clean up the style of middle::resolve_lifetime. --- src/librustc/middle/resolve_lifetime.rs | 166 ++++++++++++-------- src/librustc_typeck/astconv.rs | 10 +- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustdoc/clean/mod.rs | 8 +- 4 files changed, 108 insertions(+), 78 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a09f0ed7552b..c92722c40d57 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -15,9 +15,6 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore we break lifetime name resolution into a separate pass. -pub use self::DefRegion::*; -use self::ScopeChain::*; - use dep_graph::DepNode; use hir::map::Map; use session::Session; @@ -36,22 +33,19 @@ use hir; use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] -pub enum DefRegion { - DefStaticRegion, - DefEarlyBoundRegion(/* index */ u32, - /* lifetime decl */ ast::NodeId), - DefLateBoundRegion(ty::DebruijnIndex, - /* lifetime decl */ ast::NodeId), - DefFreeRegion(region::CallSiteScopeData, - /* lifetime decl */ ast::NodeId), +pub enum Region { + Static, + EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId), + LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), + Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId), } // Maps the id of each lifetime reference to the lifetime decl // that it corresponds to. pub struct NamedRegionMap { // maps from every use of a named (not anonymous) lifetime to a - // `DefRegion` describing how that region is bound - pub defs: NodeMap, + // `Region` describing how that region is bound + pub defs: NodeMap, // the set of lifetime def ids that are late-bound; late-bound ids // are named regions appearing in fn arguments that do not appear @@ -63,7 +57,7 @@ struct LifetimeContext<'a, 'tcx: 'a> { sess: &'a Session, hir_map: &'a Map<'tcx>, map: &'a mut NamedRegionMap, - scope: Scope<'a>, + scope: ScopeRef<'a>, // Deep breath. Our representation for poly trait refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` @@ -86,25 +80,36 @@ struct LifetimeContext<'a, 'tcx: 'a> { } #[derive(PartialEq, Debug)] -enum ScopeChain<'a> { - /// EarlyScope(['a, 'b, ...], start, s) extends s with early-bound - /// lifetimes, with consecutive parameter indices from `start`. - /// That is, 'a has index `start`, 'b has index `start + 1`, etc. +enum Scope<'a> { + /// Extends `s` with early-bound `lifetimes`, having consecutive parameter + /// indices from `start`, i.e. `lifetimes[i]` has index `start + i`. /// Indices before `start` correspond to other generic parameters /// of a parent item (trait/impl of a method), or `Self` in traits. - EarlyScope(&'a [hir::LifetimeDef], u32, Scope<'a>), - /// LateScope(['a, 'b, ...], s) extends s with late-bound - /// lifetimes introduced by the declaration binder_id. - LateScope(&'a [hir::LifetimeDef], Scope<'a>), + Early { + lifetimes: &'a [hir::LifetimeDef], + start: u32, + s: ScopeRef<'a> + }, - /// lifetimes introduced by a fn are scoped to the call-site for that fn. - FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> }, - RootScope + /// Extends `s` with late-bound `lifetimes`. + Late { + lifetimes: &'a [hir::LifetimeDef], + s: ScopeRef<'a> + }, + + /// Lifetimes introduced by a fn are scoped to the call-site for that fn. + Fn { + fn_id: ast::NodeId, + body_id: ast::NodeId, + s: ScopeRef<'a> + }, + + Root } -type Scope<'a> = &'a ScopeChain<'a>; +type ScopeRef<'a> = &'a Scope<'a>; -static ROOT_SCOPE: ScopeChain<'static> = RootScope; +const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn krate(sess: &Session, hir_map: &Map) @@ -120,7 +125,7 @@ pub fn krate(sess: &Session, sess: sess, hir_map: hir_map, map: &mut map, - scope: &ROOT_SCOPE, + scope: ROOT_SCOPE, trait_ref_hack: false, labels_in_fn: vec![], }, krate); @@ -140,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); // Items always introduce a new root scope - self.with(RootScope, |_, this| { + self.with(Scope::Root, |_, this| { match item.node { hir::ItemFn(..) => { // Fn lifetimes get added in visit_fn below: @@ -169,7 +174,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } else { 0 }; - this.with(EarlyScope(lifetimes, start, &ROOT_SCOPE), |old_scope, this| { + let early = Scope::Early { + lifetimes: lifetimes, + start: start, + s: ROOT_SCOPE + }; + this.with(early, |old_scope, this| { this.check_lifetime_defs(old_scope, lifetimes); intravisit::walk_item(this, item); }); @@ -187,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let saved = replace(&mut self.labels_in_fn, vec![]); // Items always introduce a new root scope - self.with(RootScope, |_, this| { + self.with(Scope::Root, |_, this| { match item.node { hir::ForeignItemFn(ref decl, _, ref generics) => { this.visit_early_late(item.id, decl, generics, |this| { @@ -233,7 +243,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { - self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { + let late = Scope::Late { + lifetimes: &c.lifetimes, + s: self.scope + }; + self.with(late, |old_scope, this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. this.check_lifetime_defs(old_scope, &c.lifetimes); @@ -245,7 +259,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // a trait ref, which introduces a binding scope. match path.def { Def::Trait(..) => { - self.with(LateScope(&[], self.scope), |_, this| { + self.with(Scope::Late { lifetimes: &[], s: self.scope }, |_, this| { this.visit_path(path, ty.id); }); } @@ -283,7 +297,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { return; } if lifetime_ref.name == keywords::StaticLifetime.name() { - self.insert_lifetime(lifetime_ref, DefStaticRegion); + self.insert_lifetime(lifetime_ref, Region::Static); return; } self.resolve_lifetime_ref(lifetime_ref); @@ -304,8 +318,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .. }) => { if !bound_lifetimes.is_empty() { self.trait_ref_hack = true; - let result = self.with(LateScope(bound_lifetimes, self.scope), - |old_scope, this| { + let late = Scope::Late { + lifetimes: bound_lifetimes, + s: self.scope + }; + let result = self.with(late, |old_scope, this| { this.check_lifetime_defs(old_scope, bound_lifetimes); this.visit_ty(&bounded_ty); walk_list!(this, visit_ty_param_bound, bounds); @@ -346,7 +363,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { span_err!(self.sess, trait_ref.span, E0316, "nested quantification of lifetimes"); } - self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| { + let late = Scope::Late { + lifetimes: &trait_ref.bound_lifetimes, + s: self.scope + }; + self.with(late, |old_scope, this| { this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes); for lifetime in &trait_ref.bound_lifetimes { this.visit_lifetime_def(lifetime); @@ -412,7 +433,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { struct GatherLabels<'a> { sess: &'a Session, - scope: Scope<'a>, + scope: ScopeRef<'a>, labels_in_fn: &'a mut Vec<(ast::Name, Span)>, } @@ -471,16 +492,16 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } fn check_if_label_shadows_lifetime<'a>(sess: &'a Session, - mut scope: Scope<'a>, + mut scope: ScopeRef<'a>, label: ast::Name, label_span: Span) { loop { match *scope { - FnScope { s, .. } => { scope = s; } - RootScope => { return; } + Scope::Fn { s, .. } => { scope = s; } + Scope::Root => { return; } - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { + Scope::Early { lifetimes, s, .. } | + Scope::Late { lifetimes, s } => { for lifetime_def in lifetimes { // FIXME (#24278): non-hygienic comparison if label == lifetime_def.lifetime.name { @@ -524,7 +545,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // `self.labels_in_fn`. extract_labels(self, fb); - self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope }, + self.with(Scope::Fn { fn_id: fn_id, body_id: fb.node_id, s: self.scope }, |_old_scope, this| this.visit_nested_body(fb)) } @@ -535,8 +556,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { f(self) } - fn with(&mut self, wrap_scope: ScopeChain, f: F) where - F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>), + fn with(&mut self, wrap_scope: Scope, f: F) where + F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; let mut this = LifetimeContext { @@ -591,7 +612,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Find the start of nested early scopes, e.g. in methods. let mut start = 0; - if let EarlyScope(..) = *self.scope { + if let Scope::Early {..} = *self.scope { let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id)); if let hir::ItemTrait(..) = parent.node { start += 1; // Self comes first. @@ -605,8 +626,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| { - this.with(LateScope(&late, this.scope), move |_, this| { + let early = Scope::Early { + lifetimes: &early, + start: start as u32, + s: self.scope + }; + self.with(early, move |old_scope, this| { + let late = Scope::Late { + lifetimes: &late, + s: this.scope + }; + this.with(late, move |_, this| { this.check_lifetime_defs(old_scope, &generics.lifetimes); this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` }); @@ -624,22 +654,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut scope = self.scope; loop { match *scope { - FnScope {fn_id, body_id, s } => { + Scope::Fn { fn_id, body_id, s } => { return self.resolve_free_lifetime_ref( region::CallSiteScopeData { fn_id: fn_id, body_id: body_id }, lifetime_ref, s); } - RootScope => { + Scope::Root => { break; } - EarlyScope(lifetimes, start, s) => { + Scope::Early { lifetimes, start, s } => { match search_lifetimes(lifetimes, lifetime_ref) { Some((index, lifetime_def)) => { let decl_id = lifetime_def.id; - let def = DefEarlyBoundRegion(start + index, decl_id); + let def = Region::EarlyBound(start + index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -649,12 +679,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - LateScope(lifetimes, s) => { + Scope::Late { lifetimes, s } => { match search_lifetimes(lifetimes, lifetime_ref) { Some((_index, lifetime_def)) => { let decl_id = lifetime_def.id; let debruijn = ty::DebruijnIndex::new(late_depth + 1); - let def = DefLateBoundRegion(debruijn, decl_id); + let def = Region::LateBound(debruijn, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -674,7 +704,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn resolve_free_lifetime_ref(&mut self, scope_data: region::CallSiteScopeData, lifetime_ref: &hir::Lifetime, - scope: Scope) { + scope: ScopeRef) { debug!("resolve_free_lifetime_ref \ scope_data: {:?} lifetime_ref: {:?} scope: {:?}", scope_data, lifetime_ref, scope); @@ -690,19 +720,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope_data: {:?} scope: {:?} search_result: {:?}", scope_data, scope, search_result); match *scope { - FnScope { fn_id, body_id, s } => { + Scope::Fn { fn_id, body_id, s } => { scope_data = region::CallSiteScopeData { fn_id: fn_id, body_id: body_id }; scope = s; } - RootScope => { + Scope::Root => { break; } - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { + Scope::Early { lifetimes, s, .. } | + Scope::Late { lifetimes, s } => { search_result = search_lifetimes(lifetimes, lifetime_ref); if search_result.is_some() { break; @@ -714,7 +744,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { match search_result { Some((_depth, lifetime)) => { - let def = DefFreeRegion(scope_data, lifetime.id); + let def = Region::Free(scope_data, lifetime.id); self.insert_lifetime(lifetime_ref, def); } @@ -732,7 +762,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .emit(); } - fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &[hir::LifetimeDef]) { + fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) { for i in 0..lifetimes.len() { let lifetime_i = &lifetimes[i]; @@ -773,7 +803,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn check_lifetime_def_for_shadowing(&self, - mut old_scope: Scope, + mut old_scope: ScopeRef, lifetime: &hir::Lifetime) { for &(label, label_span) in &self.labels_in_fn { @@ -789,16 +819,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *old_scope { - FnScope { s, .. } => { + Scope::Fn { s, .. } => { old_scope = s; } - RootScope => { + Scope::Root => { return; } - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { + Scope::Early { lifetimes, s, .. } | + Scope::Late { lifetimes, s } => { if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { signal_shadowing_problem( self.sess, @@ -816,7 +846,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn insert_lifetime(&mut self, lifetime_ref: &hir::Lifetime, - def: DefRegion) { + def: Region) { if lifetime_ref.id == ast::DUMMY_NODE_ID { span_bug!(lifetime_ref.span, "lifetime reference not renumbered, \ diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bc8e56e811ed..3338daeb7744 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -247,11 +247,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let name = opt_lifetime.map(|l| l.name); let resolved = opt_lifetime.and_then(|l| tcx.named_region_map.defs.get(&l.id)); let r = tcx.mk_region(match resolved { - Some(&rl::DefStaticRegion) => { + Some(&rl::Region::Static) => { ty::ReStatic } - Some(&rl::DefLateBoundRegion(debruijn, id)) => { + Some(&rl::Region::LateBound(debruijn, id)) => { // If this region is declared on a function, it will have // an entry in `late_bound`, but if it comes from // `for<'a>` in some type or something, it won't @@ -268,15 +268,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { issue_32330)) } - Some(&rl::DefEarlyBoundRegion(index, _)) => { + Some(&rl::Region::EarlyBound(index, _)) => { ty::ReEarlyBound(ty::EarlyBoundRegion { index: index, name: name.unwrap() }) } - Some(&rl::DefFreeRegion(scope, id)) => { - // As in DefLateBoundRegion above, could be missing for some late-bound + Some(&rl::Region::Free(scope, id)) => { + // As in Region::LateBound above, could be missing for some late-bound // regions, but also for early-bound regions. let issue_32330 = tcx.named_region_map .late_bound diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 55033330a449..ba00f237684e 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -154,7 +154,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let tcx = self.terms_cx.tcx; assert!(is_lifetime(&tcx.hir, param_id)); match tcx.named_region_map.defs.get(¶m_id) { - Some(&rl::DefEarlyBoundRegion(_, lifetime_decl_id)) => lifetime_decl_id, + Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id, Some(_) => bug!("should not encounter non early-bound cases"), // The lookup should only fail when `param_id` is diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 54a5b9f43c0d..4182dca71531 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -28,7 +28,7 @@ use syntax::symbol::keywords; use syntax_pos::{self, DUMMY_SP, Pos}; use rustc::middle::privacy::AccessLevels; -use rustc::middle::resolve_lifetime::DefRegion::*; +use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -765,9 +765,9 @@ impl Clean for hir::Lifetime { fn clean(&self, cx: &DocContext) -> Lifetime { let def = cx.tcx.named_region_map.defs.get(&self.id).cloned(); match def { - Some(DefEarlyBoundRegion(_, node_id)) | - Some(DefLateBoundRegion(_, node_id)) | - Some(DefFreeRegion(_, node_id)) => { + Some(rl::Region::EarlyBound(_, node_id)) | + Some(rl::Region::LateBound(_, node_id)) | + Some(rl::Region::Free(_, node_id)) => { if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { return lt; } From bbc341424cd19f1d0a66fb2df78b22a3ad0e6856 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 11 Jan 2017 17:35:54 +0200 Subject: [PATCH 049/104] rustc: simplify scope-tracking in resolve_lifetime. --- src/librustc/lib.rs | 1 + src/librustc/middle/resolve_lifetime.rs | 546 ++++++++++-------------- 2 files changed, 223 insertions(+), 324 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 619a3e995c3a..11fdf6919ccb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -30,6 +30,7 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(libc)] +#![feature(loop_break_value)] #![feature(nonzero)] #![feature(pub_restricted)] #![feature(quote)] diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c92722c40d57..c76ce9dac6fb 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -26,11 +26,10 @@ use std::mem::replace; use syntax::ast; use syntax::symbol::keywords; use syntax_pos::Span; -use util::nodemap::NodeMap; +use util::nodemap::{NodeMap, FxHashSet, FxHashMap}; -use rustc_data_structures::fx::FxHashSet; use hir; -use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use hir::intravisit::{self, Visitor, NestedVisitorMap}; #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum Region { @@ -40,6 +39,37 @@ pub enum Region { Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId), } +impl Region { + fn early(index: &mut u32, def: &hir::LifetimeDef) -> (ast::Name, Region) { + let i = *index; + *index += 1; + (def.lifetime.name, Region::EarlyBound(i, def.lifetime.id)) + } + + fn late(def: &hir::LifetimeDef) -> (ast::Name, Region) { + let depth = ty::DebruijnIndex::new(1); + (def.lifetime.name, Region::LateBound(depth, def.lifetime.id)) + } + + fn id(&self) -> Option { + match *self { + Region::Static => None, + Region::EarlyBound(_, id) | + Region::LateBound(_, id) | + Region::Free(_, id) => Some(id) + } + } + + fn shifted(self, amount: u32) -> Region { + match self { + Region::LateBound(depth, id) => { + Region::LateBound(depth.shifted(amount), id) + } + _ => self + } + } +} + // Maps the id of each lifetime reference to the lifetime decl // that it corresponds to. pub struct NamedRegionMap { @@ -79,28 +109,21 @@ struct LifetimeContext<'a, 'tcx: 'a> { labels_in_fn: Vec<(ast::Name, Span)>, } -#[derive(PartialEq, Debug)] +#[derive(Debug)] enum Scope<'a> { - /// Extends `s` with early-bound `lifetimes`, having consecutive parameter - /// indices from `start`, i.e. `lifetimes[i]` has index `start + i`. - /// Indices before `start` correspond to other generic parameters - /// of a parent item (trait/impl of a method), or `Self` in traits. - Early { - lifetimes: &'a [hir::LifetimeDef], - start: u32, + /// Declares lifetimes, and each can be early-bound or late-bound. + /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// it should be shifted by the number of `Binder`s in between the + /// declaration `Binder` and the location it's referenced from. + Binder { + lifetimes: FxHashMap, s: ScopeRef<'a> }, - /// Extends `s` with late-bound `lifetimes`. - Late { - lifetimes: &'a [hir::LifetimeDef], - s: ScopeRef<'a> - }, - - /// Lifetimes introduced by a fn are scoped to the call-site for that fn. - Fn { - fn_id: ast::NodeId, - body_id: ast::NodeId, + /// Lifetimes introduced by a fn are scoped to the call-site for that fn, + /// if this is a fn body, otherwise the original definitions are used. + Body { + id: hir::BodyId, s: ScopeRef<'a> }, @@ -121,121 +144,93 @@ pub fn krate(sess: &Session, late_bound: NodeMap(), }; sess.track_errors(|| { - intravisit::walk_crate(&mut LifetimeContext { + let mut visitor = LifetimeContext { sess: sess, hir_map: hir_map, map: &mut map, scope: ROOT_SCOPE, trait_ref_hack: false, labels_in_fn: vec![], - }, krate); + }; + for (_, item) in &krate.items { + visitor.visit_item(item); + } })?; Ok(map) } impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { - // Override the nested functions -- lifetimes follow lexical scope, - // so it's convenient to walk the tree in lexical order. fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.hir_map) + NestedVisitorMap::All(self.hir_map) } - fn visit_item(&mut self, item: &'tcx hir::Item) { - // Save labels for nested items. - let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); + // We want to nest trait/impl items in their parent, but nothing else. + fn visit_nested_item(&mut self, _: hir::ItemId) {} - // Items always introduce a new root scope - self.with(Scope::Root, |_, this| { - match item.node { - hir::ItemFn(..) => { - // Fn lifetimes get added in visit_fn below: - intravisit::walk_item(this, item); - } - hir::ItemExternCrate(_) | - hir::ItemUse(..) | - hir::ItemMod(..) | - hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) | - hir::ItemStatic(..) | - hir::ItemConst(..) => { - // These sorts of items have no lifetime parameters at all. - intravisit::walk_item(this, item); - } - hir::ItemTy(_, ref generics) | - hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) | - hir::ItemUnion(_, ref generics) | - hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { - // These kinds of items have only early bound lifetime parameters. - let lifetimes = &generics.lifetimes; - let start = if let hir::ItemTrait(..) = item.node { - 1 // Self comes before lifetimes - } else { - 0 - }; - let early = Scope::Early { - lifetimes: lifetimes, - start: start, - s: ROOT_SCOPE - }; - this.with(early, |old_scope, this| { - this.check_lifetime_defs(old_scope, lifetimes); - intravisit::walk_item(this, item); - }); - } - } - }); - - // Done traversing the item; remove any labels it created - self.labels_in_fn = saved_labels_in_fn; - } - - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { - // Items save/restore the set of labels. This way inner items - // can freely reuse names, be they loop labels or lifetimes. + fn visit_nested_body(&mut self, body: hir::BodyId) { + // Each body has their own set of labels, save labels. let saved = replace(&mut self.labels_in_fn, vec![]); - - // Items always introduce a new root scope - self.with(Scope::Root, |_, this| { - match item.node { - hir::ForeignItemFn(ref decl, _, ref generics) => { - this.visit_early_late(item.id, decl, generics, |this| { - intravisit::walk_foreign_item(this, item); - }) - } - hir::ForeignItemStatic(..) => { - intravisit::walk_foreign_item(this, item); - } - } + let body = self.hir_map.body(body); + extract_labels(self, body); + self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { + this.visit_body(body); }); - - // Done traversing the item; restore saved set of labels. replace(&mut self.labels_in_fn, saved); } - fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, - b: hir::BodyId, s: Span, fn_id: ast::NodeId) { - match fk { - FnKind::ItemFn(_, generics, ..) => { - self.visit_early_late(fn_id,decl, generics, |this| { - this.add_scope_and_walk_fn(fk, decl, b, s, fn_id) + fn visit_item(&mut self, item: &'tcx hir::Item) { + match item.node { + hir::ItemFn(ref decl, _, _, _, ref generics, _) => { + self.visit_early_late(item.id, None, decl, generics, |this| { + intravisit::walk_item(this, item); + }); + } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(..) | + hir::ItemDefaultImpl(..) | + hir::ItemForeignMod(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) => { + // These sorts of items have no lifetime parameters at all. + intravisit::walk_item(self, item); + } + hir::ItemTy(_, ref generics) | + hir::ItemEnum(_, ref generics) | + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | + hir::ItemTrait(_, ref generics, ..) | + hir::ItemImpl(_, _, ref generics, ..) => { + // These kinds of items have only early bound lifetime parameters. + let mut index = if let hir::ItemTrait(..) = item.node { + 1 // Self comes before lifetimes + } else { + 0 + }; + let lifetimes = generics.lifetimes.iter().map(|def| { + Region::early(&mut index, def) + }).collect(); + let scope = Scope::Binder { + lifetimes: lifetimes, + s: ROOT_SCOPE + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_defs(old_scope, &generics.lifetimes); + intravisit::walk_item(this, item); + }); + } + } + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { + match item.node { + hir::ForeignItemFn(ref decl, _, ref generics) => { + self.visit_early_late(item.id, None, decl, generics, |this| { + intravisit::walk_foreign_item(this, item); }) } - FnKind::Method(_, sig, ..) => { - self.visit_early_late( - fn_id, - decl, - &sig.generics, - |this| this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)); - } - FnKind::Closure(_) => { - // Closures have their own set of labels, save labels just - // like for foreign items above. - let saved = replace(&mut self.labels_in_fn, vec![]); - let result = self.add_scope_and_walk_fn(fk, decl, b, s, fn_id); - replace(&mut self.labels_in_fn, saved); - result + hir::ForeignItemStatic(..) => { + intravisit::walk_foreign_item(self, item); } } } @@ -243,11 +238,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { - let late = Scope::Late { - lifetimes: &c.lifetimes, + let scope = Scope::Binder { + lifetimes: c.lifetimes.iter().map(Region::late).collect(), s: self.scope }; - self.with(late, |old_scope, this| { + self.with(scope, |old_scope, this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. this.check_lifetime_defs(old_scope, &c.lifetimes); @@ -259,7 +254,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // a trait ref, which introduces a binding scope. match path.def { Def::Trait(..) => { - self.with(Scope::Late { lifetimes: &[], s: self.scope }, |_, this| { + let scope = Scope::Binder { + lifetimes: FxHashMap(), + s: self.scope + }; + self.with(scope, |_, this| { this.visit_path(path, ty.id); }); } @@ -275,21 +274,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - // We reset the labels on every trait item, so that different - // methods in an impl can reuse label names. - let saved = replace(&mut self.labels_in_fn, vec![]); - - if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = - trait_item.node { + if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node { self.visit_early_late( trait_item.id, + Some(self.hir_map.get_parent(trait_item.id)), &sig.decl, &sig.generics, |this| intravisit::walk_trait_item(this, trait_item)) } else { intravisit::walk_trait_item(self, trait_item); } + } - replace(&mut self.labels_in_fn, saved); + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + self.visit_early_late( + impl_item.id, + Some(self.hir_map.get_parent(impl_item.id)), + &sig.decl, &sig.generics, + |this| intravisit::walk_impl_item(this, impl_item)) + } else { + intravisit::walk_impl_item(self, impl_item); + } } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { @@ -318,11 +323,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .. }) => { if !bound_lifetimes.is_empty() { self.trait_ref_hack = true; - let late = Scope::Late { - lifetimes: bound_lifetimes, + let scope = Scope::Binder { + lifetimes: bound_lifetimes.iter().map(Region::late).collect(), s: self.scope }; - let result = self.with(late, |old_scope, this| { + let result = self.with(scope, |old_scope, this| { this.check_lifetime_defs(old_scope, bound_lifetimes); this.visit_ty(&bounded_ty); walk_list!(this, visit_ty_param_bound, bounds); @@ -363,11 +368,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { span_err!(self.sess, trait_ref.span, E0316, "nested quantification of lifetimes"); } - let late = Scope::Late { - lifetimes: &trait_ref.bound_lifetimes, + let scope = Scope::Binder { + lifetimes: trait_ref.bound_lifetimes.iter().map(Region::late).collect(), s: self.scope }; - self.with(late, |old_scope, this| { + self.with(scope, |old_scope, this| { this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes); for lifetime in &trait_ref.bound_lifetimes { this.visit_lifetime_def(lifetime); @@ -391,8 +396,8 @@ fn original_label(span: Span) -> Original { fn shadower_label(span: Span) -> Shadower { Shadower { kind: ShadowKind::Label, span: span } } -fn original_lifetime(l: &hir::Lifetime) -> Original { - Original { kind: ShadowKind::Lifetime, span: l.span } +fn original_lifetime(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span: span } } fn shadower_lifetime(l: &hir::Lifetime) -> Shadower { Shadower { kind: ShadowKind::Lifetime, span: l.span } @@ -430,33 +435,28 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning // if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { - struct GatherLabels<'a> { +fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { + struct GatherLabels<'a, 'tcx: 'a> { sess: &'a Session, + hir_map: &'a Map<'tcx>, scope: ScopeRef<'a>, labels_in_fn: &'a mut Vec<(ast::Name, Span)>, } let mut gather = GatherLabels { sess: ctxt.sess, + hir_map: ctxt.hir_map, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn, }; - gather.visit_body(ctxt.hir_map.body(b)); - return; + gather.visit_body(body); - impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { + impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { NestedVisitorMap::None } - fn visit_expr(&mut self, ex: &'v hir::Expr) { - // do not recurse into closures defined in the block - // since they are treated as separate fns from the POV of - // labels_in_fn - if let hir::ExprClosure(..) = ex.node { - return - } + fn visit_expr(&mut self, ex: &hir::Expr) { if let Some((label, label_span)) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison @@ -469,6 +469,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } check_if_label_shadows_lifetime(self.sess, + self.hir_map, self.scope, label, label_span); @@ -492,26 +493,24 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } fn check_if_label_shadows_lifetime<'a>(sess: &'a Session, + hir_map: &Map, mut scope: ScopeRef<'a>, label: ast::Name, label_span: Span) { loop { match *scope { - Scope::Fn { s, .. } => { scope = s; } + Scope::Body { s, .. } => { scope = s; } Scope::Root => { return; } - Scope::Early { lifetimes, s, .. } | - Scope::Late { lifetimes, s } => { - for lifetime_def in lifetimes { - // FIXME (#24278): non-hygienic comparison - if label == lifetime_def.lifetime.name { - signal_shadowing_problem( - sess, - label, - original_lifetime(&lifetime_def.lifetime), - shadower_label(label_span)); - return; - } + Scope::Binder { ref lifetimes, s } => { + // FIXME (#24278): non-hygienic comparison + if let Some(def) = lifetimes.get(&label) { + signal_shadowing_problem( + sess, + label, + original_lifetime(hir_map.span(def.id().unwrap())), + shadower_label(label_span)); + return; } scope = s; } @@ -521,34 +520,6 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - fn add_scope_and_walk_fn(&mut self, - fk: FnKind<'tcx>, - fd: &'tcx hir::FnDecl, - fb: hir::BodyId, - _span: Span, - fn_id: ast::NodeId) { - match fk { - FnKind::ItemFn(_, generics, ..) => { - intravisit::walk_fn_decl(self, fd); - self.visit_generics(generics); - } - FnKind::Method(_, sig, ..) => { - intravisit::walk_fn_decl(self, fd); - self.visit_generics(&sig.generics); - } - FnKind::Closure(_) => { - intravisit::walk_fn_decl(self, fd); - } - } - - // After inpsecting the decl, add all labels from the body to - // `self.labels_in_fn`. - extract_labels(self, fb); - - self.with(Scope::Fn { fn_id: fn_id, body_id: fb.node_id, s: self.scope }, - |_old_scope, this| this.visit_nested_body(fb)) - } - // FIXME(#37666) this works around a limitation in the region inferencer fn hack(&mut self, f: F) where F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), @@ -560,17 +531,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; + let labels_in_fn = replace(&mut self.labels_in_fn, vec![]); let mut this = LifetimeContext { sess: sess, hir_map: hir_map, map: *map, scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, - labels_in_fn: self.labels_in_fn.clone(), + labels_in_fn: labels_in_fn, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); debug!("exiting scope {:?}", this.scope); + self.labels_in_fn = this.labels_in_fn; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -593,6 +566,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late(&mut self, fn_id: ast::NodeId, + parent_id: Option, decl: &'tcx hir::FnDecl, generics: &'tcx hir::Generics, walk: F) where @@ -604,162 +578,98 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { decl, generics); - let (late, early): (Vec<_>, _) = - generics.lifetimes - .iter() - .cloned() - .partition(|l| self.map.late_bound.contains_key(&l.lifetime.id)); - // Find the start of nested early scopes, e.g. in methods. - let mut start = 0; - if let Scope::Early {..} = *self.scope { - let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id)); + let mut index = 0; + if let Some(parent_id) = parent_id { + let parent = self.hir_map.expect_item(parent_id); if let hir::ItemTrait(..) = parent.node { - start += 1; // Self comes first. + index += 1; // Self comes first. } match parent.node { hir::ItemTrait(_, ref generics, ..) | hir::ItemImpl(_, _, ref generics, ..) => { - start += generics.lifetimes.len() + generics.ty_params.len(); + index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} } } - let early = Scope::Early { - lifetimes: &early, - start: start as u32, + let lifetimes = generics.lifetimes.iter().map(|def| { + if self.map.late_bound.contains_key(&def.lifetime.id) { + Region::late(def) + } else { + Region::early(&mut index, def) + } + }).collect(); + + let scope = Scope::Binder { + lifetimes: lifetimes, s: self.scope }; - self.with(early, move |old_scope, this| { - let late = Scope::Late { - lifetimes: &late, - s: this.scope - }; - this.with(late, move |_, this| { - this.check_lifetime_defs(old_scope, &generics.lifetimes); - this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` - }); + self.with(scope, move |old_scope, this| { + this.check_lifetime_defs(old_scope, &generics.lifetimes); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` }); } fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the - // given name or we run out of scopes. If we encounter a code - // block, then the lifetime is not bound but free, so switch - // over to `resolve_free_lifetime_ref()` to complete the + // given name or we run out of scopes. // search. let mut late_depth = 0; let mut scope = self.scope; - loop { + let mut outermost_body = None; + let result = loop { match *scope { - Scope::Fn { fn_id, body_id, s } => { - return self.resolve_free_lifetime_ref( - region::CallSiteScopeData { fn_id: fn_id, body_id: body_id }, - lifetime_ref, - s); - } - - Scope::Root => { - break; - } - - Scope::Early { lifetimes, start, s } => { - match search_lifetimes(lifetimes, lifetime_ref) { - Some((index, lifetime_def)) => { - let decl_id = lifetime_def.id; - let def = Region::EarlyBound(start + index, decl_id); - self.insert_lifetime(lifetime_ref, def); - return; - } - None => { - scope = s; - } - } - } - - Scope::Late { lifetimes, s } => { - match search_lifetimes(lifetimes, lifetime_ref) { - Some((_index, lifetime_def)) => { - let decl_id = lifetime_def.id; - let debruijn = ty::DebruijnIndex::new(late_depth + 1); - let def = Region::LateBound(debruijn, decl_id); - self.insert_lifetime(lifetime_ref, def); - return; - } - - None => { - late_depth += 1; - scope = s; - } - } - } - } - } - - self.unresolved_lifetime_ref(lifetime_ref); - } - - fn resolve_free_lifetime_ref(&mut self, - scope_data: region::CallSiteScopeData, - lifetime_ref: &hir::Lifetime, - scope: ScopeRef) { - debug!("resolve_free_lifetime_ref \ - scope_data: {:?} lifetime_ref: {:?} scope: {:?}", - scope_data, lifetime_ref, scope); - - // Walk up the scope chain, tracking the outermost free scope, - // until we encounter a scope that contains the named lifetime - // or we run out of scopes. - let mut scope_data = scope_data; - let mut scope = scope; - let mut search_result = None; - loop { - debug!("resolve_free_lifetime_ref \ - scope_data: {:?} scope: {:?} search_result: {:?}", - scope_data, scope, search_result); - match *scope { - Scope::Fn { fn_id, body_id, s } => { - scope_data = region::CallSiteScopeData { - fn_id: fn_id, body_id: body_id - }; + Scope::Body { id, s } => { + outermost_body = Some(id); scope = s; } Scope::Root => { - break; + break None; } - Scope::Early { lifetimes, s, .. } | - Scope::Late { lifetimes, s } => { - search_result = search_lifetimes(lifetimes, lifetime_ref); - if search_result.is_some() { - break; + Scope::Binder { ref lifetimes, s } => { + if let Some(&def) = lifetimes.get(&lifetime_ref.name) { + break Some(def.shifted(late_depth)); + } else { + late_depth += 1; + scope = s; } - scope = s; } } - } + }; - match search_result { - Some((_depth, lifetime)) => { - let def = Region::Free(scope_data, lifetime.id); - self.insert_lifetime(lifetime_ref, def); - } - - None => { - self.unresolved_lifetime_ref(lifetime_ref); + if let Some(mut def) = result { + if let Some(body_id) = outermost_body { + let fn_id = self.hir_map.body_owner(body_id); + let scope_data = region::CallSiteScopeData { + fn_id: fn_id, body_id: body_id.node_id + }; + match self.hir_map.get(fn_id) { + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. + }) | + hir::map::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(..), .. + }) | + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. + }) => { + def = Region::Free(scope_data, def.id().unwrap()); + } + _ => {} + } } + self.insert_lifetime(lifetime_ref, def); + } else { + struct_span_err!(self.sess, lifetime_ref.span, E0261, + "use of undeclared lifetime name `{}`", lifetime_ref.name) + .span_label(lifetime_ref.span, &format!("undeclared lifetime")) + .emit(); } - - } - - fn unresolved_lifetime_ref(&self, lifetime_ref: &hir::Lifetime) { - struct_span_err!(self.sess, lifetime_ref.span, E0261, - "use of undeclared lifetime name `{}`", lifetime_ref.name) - .span_label(lifetime_ref.span, &format!("undeclared lifetime")) - .emit(); } fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) { @@ -819,7 +729,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *old_scope { - Scope::Fn { s, .. } => { + Scope::Body { s, .. } => { old_scope = s; } @@ -827,13 +737,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - Scope::Early { lifetimes, s, .. } | - Scope::Late { lifetimes, s } => { - if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { + Scope::Binder { ref lifetimes, s } => { + if let Some(&def) = lifetimes.get(&lifetime.name) { signal_shadowing_problem( self.sess, lifetime.name, - original_lifetime(&lifetime_def), + original_lifetime(self.hir_map.span(def.id().unwrap())), shadower_lifetime(&lifetime)); return; } @@ -861,17 +770,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } -fn search_lifetimes<'a>(lifetimes: &'a [hir::LifetimeDef], - lifetime_ref: &hir::Lifetime) - -> Option<(u32, &'a hir::Lifetime)> { - for (i, lifetime_decl) in lifetimes.iter().enumerate() { - if lifetime_decl.lifetime.name == lifetime_ref.name { - return Some((i as u32, &lifetime_decl.lifetime)); - } - } - return None; -} - /////////////////////////////////////////////////////////////////////////// /// Detects late-bound lifetimes and inserts them into From ba1849daecf0ae8fee54cc32f378809a9531e5ed Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 13 Jan 2017 15:09:56 +0200 Subject: [PATCH 050/104] rustc: move most of lifetime elision to resolve_lifetimes. --- src/librustc/diagnostics.rs | 63 +++ src/librustc/hir/lowering.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 502 +++++++++++++++++- src/librustc_typeck/astconv.rs | 337 ++---------- src/librustc_typeck/check/mod.rs | 26 +- src/librustc_typeck/collect.rs | 82 +-- src/librustc_typeck/diagnostics.rs | 72 +-- src/librustc_typeck/rscope.rs | 168 ------ src/test/compile-fail/E0106.rs | 12 + src/test/compile-fail/E0107.rs | 3 - ...iated-types-project-from-hrtb-in-struct.rs | 9 +- ...-return-type-requires-explicit-lifetime.rs | 24 + src/test/compile-fail/rfc1623.rs | 4 +- 13 files changed, 703 insertions(+), 602 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2878ff5e2846..b51a7d4104ab 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -327,6 +327,69 @@ struct ListNode { This works because `Box` is a pointer, so its size is well-known. "##, +E0106: r##" +This error indicates that a lifetime is missing from a type. If it is an error +inside a function signature, the problem may be with failing to adhere to the +lifetime elision rules (see below). + +Here are some simple examples of where you'll run into this error: + +```compile_fail,E0106 +struct Foo { x: &bool } // error +struct Foo<'a> { x: &'a bool } // correct + +enum Bar { A(u8), B(&bool), } // error +enum Bar<'a> { A(u8), B(&'a bool), } // correct + +type MyStr = &str; // error +type MyStr<'a> = &'a str; // correct +``` + +Lifetime elision is a special, limited kind of inference for lifetimes in +function signatures which allows you to leave out lifetimes in certain cases. +For more background on lifetime elision see [the book][book-le]. + +The lifetime elision rules require that any function signature with an elided +output lifetime must either have + + - exactly one input lifetime + - or, multiple input lifetimes, but the function must also be a method with a + `&self` or `&mut self` receiver + +In the first case, the output lifetime is inferred to be the same as the unique +input lifetime. In the second case, the lifetime is instead inferred to be the +same as the lifetime on `&self` or `&mut self`. + +Here are some examples of elision errors: + +```compile_fail,E0106 +// error, no input lifetimes +fn foo() -> &str { } + +// error, `x` and `y` have distinct lifetimes inferred +fn bar(x: &str, y: &str) -> &str { } + +// error, `y`'s lifetime is inferred to be distinct from `x`'s +fn baz<'a>(x: &'a str, y: &str) -> &str { } +``` + +Here's an example that is currently an error, but may work in a future version +of Rust: + +```compile_fail,E0106 +struct Foo<'a>(&'a str); + +trait Quux { } +impl Quux for Foo { } +``` + +Lifetime elision in implementation headers was part of the lifetime elision +RFC. It is, however, [currently unimplemented][iss15872]. + +[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision +[iss15872]: https://github.com/rust-lang/rust/issues/15872 +"##, + E0109: r##" You tried to give a type parameter to a type which doesn't need it. Erroneous code example: diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4160ec5b74a9..7ca251f3ff91 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -314,9 +314,10 @@ impl<'a> LoweringContext<'a> { TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { + let span = Span { hi: t.span.lo, ..t.span }; let lifetime = match *region { Some(ref lt) => self.lower_lifetime(lt), - None => self.elided_lifetime(t.span) + None => self.elided_lifetime(span) }; hir::TyRptr(lifetime, self.lower_mt(mt)) } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c76ce9dac6fb..4e02485a40b7 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -22,11 +22,16 @@ use hir::def::Def; use hir::def_id::DefId; use middle::region; use ty; + +use std::cell::Cell; use std::mem::replace; use syntax::ast; +use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::Span; +use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, FxHashSet, FxHashMap}; +use rustc_back::slice; use hir; use hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -36,6 +41,7 @@ pub enum Region { Static, EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId), LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), + LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId), } @@ -51,9 +57,18 @@ impl Region { (def.lifetime.name, Region::LateBound(depth, def.lifetime.id)) } + fn late_anon(index: &Cell) -> Region { + let i = index.get(); + index.set(i + 1); + let depth = ty::DebruijnIndex::new(1); + Region::LateBoundAnon(depth, i) + } + fn id(&self) -> Option { match *self { - Region::Static => None, + Region::Static | + Region::LateBoundAnon(..) => None, + Region::EarlyBound(_, id) | Region::LateBound(_, id) | Region::Free(_, id) => Some(id) @@ -65,6 +80,25 @@ impl Region { Region::LateBound(depth, id) => { Region::LateBound(depth.shifted(amount), id) } + Region::LateBoundAnon(depth, index) => { + Region::LateBoundAnon(depth.shifted(amount), index) + } + _ => self + } + } + + fn from_depth(self, depth: u32) -> Region { + match self { + Region::LateBound(debruijn, id) => { + Region::LateBound(ty::DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, id) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(ty::DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, index) + } _ => self } } @@ -122,14 +156,46 @@ enum Scope<'a> { /// Lifetimes introduced by a fn are scoped to the call-site for that fn, /// if this is a fn body, otherwise the original definitions are used. + /// Unspecified lifetimes are inferred, unless an elision scope is nested, + /// e.g. `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. Body { id: hir::BodyId, s: ScopeRef<'a> }, + /// A scope which either determines unspecified lifetimes or errors + /// on them (e.g. due to ambiguity). For more details, see `Elide`. + Elision { + elide: Elide, + s: ScopeRef<'a> + }, + Root } +#[derive(Clone, Debug)] +enum Elide { + /// Use a fresh anonymous late-bound lifetime each time, by + /// incrementing the counter to generate sequential indices. + FreshLateAnon(Cell), + /// Always use this one lifetime. + Exact(Region), + /// Like `Exact(Static)` but requires `#![feature(static_in_const)]`. + Static, + /// Less or more than one lifetime were found, error on unspecified. + Error(Vec) +} + +#[derive(Clone, Debug)] +struct ElisionFailureInfo { + /// Where we can find the argument pattern. + parent: Option, + /// The index of the argument in the original definition. + index: usize, + lifetime_count: usize, + have_bound_regions: bool +} + type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; @@ -189,12 +255,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) | - hir::ItemStatic(..) | - hir::ItemConst(..) => { + hir::ItemForeignMod(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } + hir::ItemStatic(..) | + hir::ItemConst(..) => { + // No lifetime parameters, but implied 'static. + let scope = Scope::Elision { + elide: Elide::Static, + s: ROOT_SCOPE + }; + self.with(scope, |_, this| intravisit::walk_item(this, item)); + } hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) | @@ -299,6 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.is_elided() { + self.resolve_elided_lifetimes(slice::ref_slice(lifetime_ref)); return; } if lifetime_ref.name == keywords::StaticLifetime.name() { @@ -308,6 +382,31 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(lifetime_ref); } + fn visit_path_parameters(&mut self, _: Span, params: &'tcx hir::PathParameters) { + match *params { + hir::AngleBracketedParameters(ref data) => { + if data.lifetimes.iter().all(|l| l.is_elided()) { + self.resolve_elided_lifetimes(&data.lifetimes); + } else { + for l in &data.lifetimes { self.visit_lifetime(l); } + } + for ty in &data.types { self.visit_ty(ty); } + for b in &data.bindings { self.visit_assoc_type_binding(b); } + } + hir::ParenthesizedParameters(ref data) => { + self.visit_fn_like_elision(&data.inputs, data.output.as_ref()); + } + } + } + + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) { + let output = match fd.output { + hir::DefaultReturn(_) => None, + hir::Return(ref ty) => Some(ty) + }; + self.visit_fn_like_elision(&fd.inputs, output); + } + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { walk_list!(self, visit_ty_param_bound, &ty_param.bounds); @@ -478,10 +577,6 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { } intravisit::walk_expr(self, ex) } - - fn visit_item(&mut self, _: &hir::Item) { - // do not recurse into items defined in the block - } } fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { @@ -499,7 +594,9 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { label_span: Span) { loop { match *scope { - Scope::Body { s, .. } => { scope = s; } + Scope::Body { s, .. } | + Scope::Elision { s, .. } => { scope = s; } + Scope::Root => { return; } Scope::Binder { ref lifetimes, s } => { @@ -639,6 +736,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope = s; } } + + Scope::Elision { s, .. } => { + scope = s; + } } }; @@ -672,6 +773,386 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + fn visit_fn_like_elision(&mut self, inputs: &'tcx [P], + output: Option<&'tcx P>) { + let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); + let arg_scope = Scope::Elision { + elide: arg_elide.clone(), + s: self.scope + }; + self.with(arg_scope, |_, this| { + for input in inputs { + this.visit_ty(input); + } + match *this.scope { + Scope::Elision { ref elide, .. } => { + arg_elide = elide.clone(); + } + _ => bug!() + } + }); + + let output = match output { + Some(ty) => ty, + None => return + }; + + // Figure out if there's a body we can get argument names from, + // and whether there's a `self` argument (treated specially). + let mut assoc_item_kind = None; + let mut impl_self = None; + let parent = self.hir_map.get_parent_node(output.id); + let body = match self.hir_map.get(parent) { + // `fn` definitions and methods. + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(.., body), .. + }) => Some(body), + + hir::map::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(_, ref m), .. + }) => { + match self.hir_map.expect_item(self.hir_map.get_parent(parent)).node { + hir::ItemTrait(.., ref trait_items) => { + assoc_item_kind = trait_items.iter().find(|ti| ti.id.node_id == parent) + .map(|ti| ti.kind); + } + _ => {} + } + match *m { + hir::TraitMethod::Required(_) => None, + hir::TraitMethod::Provided(body) => Some(body), + } + } + + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(_, body), .. + }) => { + match self.hir_map.expect_item(self.hir_map.get_parent(parent)).node { + hir::ItemImpl(.., ref self_ty, ref impl_items) => { + impl_self = Some(self_ty); + assoc_item_kind = impl_items.iter().find(|ii| ii.id.node_id == parent) + .map(|ii| ii.kind); + } + _ => {} + } + Some(body) + } + + // `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). + hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None, + + // Foreign `fn` decls are terrible because we messed up, + // and their return types get argument type elision. + // And now too much code out there is abusing this rule. + hir::map::NodeForeignItem(_) => { + let arg_scope = Scope::Elision { + elide: arg_elide, + s: self.scope + }; + self.with(arg_scope, |_, this| this.visit_ty(output)); + return; + } + + // Everything else (only closures?) doesn't + // actually enjoy elision in return types. + _ => { + self.visit_ty(output); + return; + } + }; + + let has_self = match assoc_item_kind { + Some(hir::AssociatedItemKind::Method { has_self }) => has_self, + _ => false + }; + + // In accordance with the rules for lifetime elision, we can determine + // what region to use for elision in the output type in two ways. + // First (determined here), if `self` is by-reference, then the + // implied output region is the region of the self parameter. + if has_self { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + let is_self_ty = |def: Def| { + if let Def::SelfTy(..) = def { + return true; + } + + // Can't always rely on literal (or implied) `Self` due + // to the way elision rules were originally specified. + let impl_self = impl_self.map(|ty| &ty.node); + if let Some(&hir::TyPath(hir::QPath::Resolved(None, ref path))) = impl_self { + match path.def { + // Whitelist the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + Def::Struct(_) | + Def::Union(_) | + Def::Enum(_) | + Def::Trait(_) | + Def::PrimTy(_) => return def == path.def, + _ => {} + } + } + + false + }; + + if let hir::TyRptr(lifetime_ref, ref mt) = inputs[0].node { + if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = mt.ty.node { + if is_self_ty(path.def) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { + let scope = Scope::Elision { + elide: Elide::Exact(lifetime), + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(output)); + return; + } + } + } + } + } + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let mut possible_implied_output_region = None; + let mut lifetime_count = 0; + let arg_lifetimes = inputs.iter().enumerate().skip(has_self as usize).map(|(i, input)| { + let mut gather = GatherLifetimes { + map: self.map, + binder_depth: 1, + have_bound_regions: false, + lifetimes: FxHashSet() + }; + gather.visit_ty(input); + + lifetime_count += gather.lifetimes.len(); + + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + + ElisionFailureInfo { + parent: body, + index: i, + lifetime_count: gather.lifetimes.len(), + have_bound_regions: gather.have_bound_regions + } + }).collect(); + + let elide = if lifetime_count == 1 { + Elide::Exact(possible_implied_output_region.unwrap()) + } else { + Elide::Error(arg_lifetimes) + }; + + let scope = Scope::Elision { + elide: elide, + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(output)); + + struct GatherLifetimes<'a> { + map: &'a NamedRegionMap, + binder_depth: u32, + have_bound_regions: bool, + lifetimes: FxHashSet, + } + + impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty) { + let delta = match ty.node { + hir::TyBareFn(_) => 1, + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { + // if this path references a trait, then this will resolve to + // a trait ref, which introduces a binding scope. + match path.def { + Def::Trait(..) => 1, + _ => 0 + } + } + _ => 0 + }; + self.binder_depth += delta; + intravisit::walk_ty(self, ty); + self.binder_depth -= delta; + } + + fn visit_poly_trait_ref(&mut self, + trait_ref: &hir::PolyTraitRef, + modifier: &hir::TraitBoundModifier) { + self.binder_depth += 1; + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.binder_depth -= 1; + } + + fn visit_lifetime_def(&mut self, lifetime_def: &hir::LifetimeDef) { + for l in &lifetime_def.bounds { self.visit_lifetime(l); } + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { + match lifetime { + Region::LateBound(debruijn, _) | + Region::LateBoundAnon(debruijn, _) + if debruijn.depth < self.binder_depth => { + self.have_bound_regions = true; + } + _ => { + self.lifetimes.insert(lifetime.from_depth(self.binder_depth)); + } + } + } + } + } + + } + + fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[hir::Lifetime]) { + if lifetime_refs.is_empty() { + return; + } + + let span = lifetime_refs[0].span; + let mut late_depth = 0; + let mut scope = self.scope; + let error = loop { + match *scope { + // Do not assign any resolution, it will be inferred. + Scope::Body { .. } => return, + + Scope::Root => break None, + + Scope::Binder { s, .. } => { + late_depth += 1; + scope = s; + } + + Scope::Elision { ref elide, .. } => { + let lifetime = match *elide { + Elide::FreshLateAnon(ref counter) => { + for lifetime_ref in lifetime_refs { + let lifetime = Region::late_anon(counter).shifted(late_depth); + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + Elide::Exact(l) => l.shifted(late_depth), + Elide::Static => { + if !self.sess.features.borrow().static_in_const { + self.sess + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") + .emit(); + } + Region::Static + } + Elide::Error(ref e) => break Some(e) + }; + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + } + }; + + let mut err = struct_span_err!(self.sess, span, E0106, + "missing lifetime specifier{}", + if lifetime_refs.len() > 1 { "s" } else { "" }); + let msg = if lifetime_refs.len() > 1 { + format!("expected {} lifetime parameters", lifetime_refs.len()) + } else { + format!("expected lifetime parameter") + }; + err.span_label(span, &msg); + + if let Some(params) = error { + if lifetime_refs.len() == 1 { + self.report_elision_failure(&mut err, params); + } + } + err.emit(); + } + + fn report_elision_failure(&mut self, + db: &mut DiagnosticBuilder, + params: &[ElisionFailureInfo]) { + let mut m = String::new(); + let len = params.len(); + + let elided_params: Vec<_> = params.iter().cloned() + .filter(|info| info.lifetime_count > 0) + .collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { + parent, index, lifetime_count: n, have_bound_regions + } = info; + + let help_name = if let Some(body) = parent { + let arg = &self.hir_map.body(body).arguments[index]; + format!("`{}`", self.hir_map.node_to_pretty_string(arg.pat.id)) + } else { + format!("argument {}", index + 1) + }; + + m.push_str(&(if n == 1 { + help_name + } else { + format!("one of {}'s {} elided {}lifetimes", help_name, n, + if have_bound_regions { "free " } else { "" } ) + })[..]); + + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); + } + + } + + if len == 0 { + help!(db, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from"); + help!(db, + "consider giving it a 'static lifetime"); + } else if elided_len == 0 { + help!(db, + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments"); + help!(db, + "consider giving it an explicit bounded or 'static \ + lifetime"); + } else if elided_len == 1 { + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m); + } else { + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m); + } + } + fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) { for i in 0..lifetimes.len() { let lifetime_i = &lifetimes[i]; @@ -729,7 +1210,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *old_scope { - Scope::Body { s, .. } => { + Scope::Body { s, .. } | + Scope::Elision { s, .. } => { old_scope = s; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3338daeb7744..42a220e1b9b4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -61,9 +61,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; use rustc_back::slice; use require_c_abi_if_variadic; -use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, - ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, - ElisionFailureInfo, ElidedLifetime}; +use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope}; use rscope::{AnonTypeScope, MaybeWithAnonTypes, ExplicitRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -74,7 +72,6 @@ use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; -use errors::DiagnosticBuilder; pub trait AstConv<'gcx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; @@ -111,6 +108,10 @@ pub trait AstConv<'gcx, 'tcx> { /// See ParameterEnvironment::free_substs for more information. fn get_free_substs(&self) -> Option<&Substs<'tcx>>; + /// What lifetime should we use when a lifetime is omitted (and not elided)? + fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) + -> &'tcx ty::Region; + /// What type should we use when a type is omitted? fn ty_infer(&self, span: Span) -> Ty<'tcx>; @@ -161,94 +162,16 @@ struct ConvertedBinding<'tcx> { /// This type must not appear anywhere in other converted types. const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0)); -fn report_elision_failure( - tcx: TyCtxt, - db: &mut DiagnosticBuilder, - params: Vec) -{ - let mut m = String::new(); - let len = params.len(); - - let elided_params: Vec<_> = params.into_iter() - .filter(|info| info.lifetime_count > 0) - .collect(); - - let elided_len = elided_params.len(); - - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { - parent, index, lifetime_count: n, have_bound_regions - } = info; - - let help_name = if let Some(body) = parent { - let arg = &tcx.hir.body(body).arguments[index]; - format!("`{}`", tcx.hir.node_to_pretty_string(arg.pat.id)) - } else { - format!("argument {}", index + 1) - }; - - m.push_str(&(if n == 1 { - help_name - } else { - format!("one of {}'s {} elided {}lifetimes", help_name, n, - if have_bound_regions { "free " } else { "" } ) - })[..]); - - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); - } - - } - - if len == 0 { - help!(db, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from"); - help!(db, - "consider giving it a 'static lifetime"); - } else if elided_len == 0 { - help!(db, - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments"); - help!(db, - "consider giving it an explicit bounded or 'static \ - lifetime"); - } else if elided_len == 1 { - help!(db, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m); - } else { - help!(db, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m); - } -} - impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { - pub fn ast_region_to_region(&self, lifetime: &hir::Lifetime) -> &'tcx ty::Region { - self.opt_ast_region_to_region(&ExplicitRscope, lifetime.span, Some(lifetime), None) - } - - fn try_opt_ast_region_to_region(&self, - rscope: &RegionScope, - default_span: Span, - opt_lifetime: Option<&hir::Lifetime>, + pub fn ast_region_to_region(&self, + lifetime: &hir::Lifetime, def: Option<&ty::RegionParameterDef>) - -> Result<&'tcx ty::Region, Option>> + -> &'tcx ty::Region { let tcx = self.tcx(); - let name = opt_lifetime.map(|l| l.name); - let resolved = opt_lifetime.and_then(|l| tcx.named_region_map.defs.get(&l.id)); - let r = tcx.mk_region(match resolved { + let r = match tcx.named_region_map.defs.get(&lifetime.id) { Some(&rl::Region::Static) => { - ty::ReStatic + tcx.mk_region(ty::ReStatic) } Some(&rl::Region::LateBound(debruijn, id)) => { @@ -263,16 +186,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .get(&id) .cloned() .unwrap_or(ty::Issue32330::WontChange); - ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id), - name.unwrap(), - issue_32330)) + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReLateBound(debruijn, + ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330))) } - Some(&rl::Region::EarlyBound(index, _)) => { - ty::ReEarlyBound(ty::EarlyBoundRegion { + Some(&rl::Region::LateBoundAnon(debruijn, index)) => { + tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) + } + + Some(&rl::Region::EarlyBound(index, id)) => { + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { index: index, - name: name.unwrap() - }) + name: name + })) } Some(&rl::Region::Free(scope, id)) => { @@ -283,47 +211,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .get(&id) .cloned() .unwrap_or(ty::Issue32330::WontChange); - ty::ReFree(ty::FreeRegion { - scope: scope.to_code_extent(&tcx.region_maps), - bound_region: ty::BrNamed(tcx.hir.local_def_id(id), - name.unwrap(), - issue_32330) - }) + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReFree(ty::FreeRegion { + scope: scope.to_code_extent(&tcx.region_maps), + bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330) + })) // (*) -- not late-bound, won't change } - None => rscope.anon_region(default_span, def)? - }); + None => self.re_infer(lifetime.span, def) + }; - debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", - opt_lifetime, + debug!("ast_region_to_region(lifetime={:?}) yields {:?}", + lifetime, r); - Ok(r) - } - - pub fn opt_ast_region_to_region(&self, - rscope: &RegionScope, - default_span: Span, - opt_lifetime: Option<&hir::Lifetime>, - def: Option<&ty::RegionParameterDef>) -> &'tcx ty::Region - { - let tcx = self.tcx(); - self.try_opt_ast_region_to_region(rscope, default_span, opt_lifetime, def) - .unwrap_or_else(|params| { - let ampersand_span = Span { hi: default_span.lo, ..default_span}; - - let mut err = struct_span_err!(tcx.sess, ampersand_span, E0106, - "missing lifetime specifier"); - err.span_label(ampersand_span, &format!("expected lifetime parameter")); - - if let Some(params) = params { - report_elision_failure(tcx, &mut err, params); - } - err.emit(); - tcx.mk_region(ty::ReStatic) - }) + r } /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, @@ -404,20 +308,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); - let mut reported_lifetime_count_mismatch = false; - let mut report_lifetime_count_mismatch = || { - if !reported_lifetime_count_mismatch { - reported_lifetime_count_mismatch = true; - let all_infer = lifetimes.iter().all(|lt| lt.is_elided()); - let supplied = if all_infer { 0 } else { supplied_num_region_params }; - report_lifetime_number_error(tcx, span, - supplied, - expected_num_region_params); - } - }; - if expected_num_region_params != supplied_num_region_params { - report_lifetime_count_mismatch(); + report_lifetime_number_error(tcx, span, + supplied_num_region_params, + expected_num_region_params); } // If a self-type was declared, one should be provided. @@ -445,11 +339,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - let l = lifetimes.get(i); - self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| { - report_lifetime_count_mismatch(); + if let Some(lifetime) = lifetimes.get(i) { + self.ast_region_to_region(lifetime, Some(def)) + } else { tcx.mk_region(ty::ReStatic) - }) + } }, |def, substs| { let i = def.index as usize; @@ -533,72 +427,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (substs, assoc_bindings) } - /// Returns the appropriate lifetime to use for any output lifetimes - /// (if one exists) and a vector of the (pattern, number of lifetimes) - /// corresponding to each input type/pattern. - fn find_implied_output_region(&self, - input_tys: &[Ty<'tcx>], - parent: Option, - input_indices: I) -> ElidedLifetime - where I: Iterator - { - let tcx = self.tcx(); - let mut lifetimes_for_params = Vec::with_capacity(input_tys.len()); - let mut possible_implied_output_region = None; - let mut lifetimes = 0; - - for (input_type, index) in input_tys.iter().zip(input_indices) { - let mut regions = FxHashSet(); - let have_bound_regions = tcx.collect_regions(input_type, &mut regions); - - debug!("find_implied_output_regions: collected {:?} from {:?} \ - have_bound_regions={:?}", ®ions, input_type, have_bound_regions); - - lifetimes += regions.len(); - - if lifetimes == 1 && regions.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = regions.iter().cloned().next(); - } - - lifetimes_for_params.push(ElisionFailureInfo { - parent: parent, - index: index, - lifetime_count: regions.len(), - have_bound_regions: have_bound_regions - }); - } - - if lifetimes == 1 { - Ok(*possible_implied_output_region.unwrap()) - } else { - Err(Some(lifetimes_for_params)) - } - } - - fn convert_ty_with_lifetime_elision(&self, - elided_lifetime: ElidedLifetime, - ty: &hir::Ty, - anon_scope: Option) - -> Ty<'tcx> - { - match elided_lifetime { - Ok(implied_output_region) => { - let rb = ElidableRscope::new(implied_output_region); - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) - } - Err(param_lifetimes) => { - // All regions must be explicitly specified in the output - // if the lifetime elision rules do not apply. This saves - // the user from potentially-confusing errors. - let rb = UnelidableRscope::new(param_lifetimes); - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) - } - } - } - fn convert_parenthesized_parameters(&self, rscope: &RegionScope, region_substs: &[Kind<'tcx>], @@ -606,19 +434,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> (Ty<'tcx>, ConvertedBinding<'tcx>) { let anon_scope = rscope.anon_type_scope(); - let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope); + let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t) + self.ast_ty_arg_to_ty(&rscope, None, region_substs, a_t) })); - let input_params = 0..inputs.len(); - let implied_output_region = self.find_implied_output_region(&inputs, None, input_params); let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.convert_ty_with_lifetime_elision(implied_output_region, - &output_ty, - anon_scope), - output_ty.span) + (self.ast_ty_to_ty(&rscope, output_ty), output_ty.span) } None => { (self.tcx().mk_nil(), data.span) @@ -1469,7 +1292,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }) } hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, Some(region), None); + let r = self.ast_region_to_region(region, None); debug!("TyRef r={:?}", r); let rscope1 = &ObjectLifetimeDefaultRscope::new( @@ -1489,9 +1312,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let anon_scope = rscope.anon_type_scope(); let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, bf.abi, - None, &bf.decl, - None, anon_scope, anon_scope); @@ -1626,37 +1447,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - pub fn ty_of_method(&self, - sig: &hir::MethodSig, - opt_self_value_ty: Option>, - body: Option, - anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(sig.unsafety, - sig.abi, - opt_self_value_ty, - &sig.decl, - body, - None, - anon_scope) - } - - pub fn ty_of_bare_fn(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl, - body: hir::BodyId, - anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope) + pub fn ty_of_fn(&self, + unsafety: hir::Unsafety, + abi: abi::Abi, + decl: &hir::FnDecl, + anon_scope: Option) + -> &'tcx ty::BareFnTy<'tcx> { + self.ty_of_method_or_bare_fn(unsafety, abi, decl, None, anon_scope) } fn ty_of_method_or_bare_fn(&self, unsafety: hir::Unsafety, abi: abi::Abi, - opt_self_value_ty: Option>, decl: &hir::FnDecl, - body: Option, arg_anon_scope: Option, ret_anon_scope: Option) -> &'tcx ty::BareFnTy<'tcx> @@ -1665,40 +1468,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // New region names that appear inside of the arguments of the function // declaration are bound to that function type. - let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope); + let rb = MaybeWithAnonTypes::new(ExplicitRscope, arg_anon_scope); let input_tys: Vec = decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); - let has_self = opt_self_value_ty.is_some(); - let explicit_self = opt_self_value_ty.map(|self_value_ty| { - ExplicitSelf::determine(self_value_ty, input_tys[0]) - }); - - let implied_output_region = match explicit_self { - // `implied_output_region` is the region that will be assumed for any - // region parameters in the return type. In accordance with the rules for - // lifetime elision, we can determine it in two ways. First (determined - // here), if self is by-reference, then the implied output region is the - // region of the self parameter. - Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), - - // Second, if there was exactly one lifetime (either a substitution or a - // reference) in the arguments, then any anonymous regions in the output - // have that lifetime. - _ => { - let arg_tys = &input_tys[has_self as usize..]; - let arg_params = has_self as usize..input_tys.len(); - self.find_implied_output_region(arg_tys, body, arg_params) - - } - }; - let output_ty = match decl.output { hir::Return(ref output) => - self.convert_ty_with_lifetime_elision(implied_output_region, - &output, - ret_anon_scope), + self.ast_ty_to_ty(&MaybeWithAnonTypes::new(ExplicitRscope, ret_anon_scope), output), hir::DefaultReturn(..) => self.tcx().mk_nil(), }; @@ -1725,10 +1502,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_closure(expected_sig={:?})", expected_sig); - // new region names that appear inside of the fn decl are bound to - // that function type - let rb = rscope::BindingRscope::new(); - let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| { let expected_arg_ty = expected_sig.as_ref().and_then(|e| { // no guarantee that the correct number of expected args @@ -1739,7 +1512,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { None } }); - self.ty_of_arg(&rb, a, expected_arg_ty) + self.ty_of_arg(&ExplicitRscope, a, expected_arg_ty) }); let expected_ret_ty = expected_sig.as_ref().map(|e| e.output()); @@ -1755,7 +1528,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { expected_ret_ty.unwrap(), _ if is_infer => self.ty_infer(decl.output.span()), hir::Return(ref output) => - self.ast_ty_to_ty(&rb, &output), + self.ast_ty_to_ty(&ExplicitRscope, &output), hir::DefaultReturn(..) => bug!(), }; @@ -1820,7 +1593,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Some(&r) = explicit_region_bounds.get(0) { // Explicitly specified region bound. Use that. - return Some(self.ast_region_to_region(r)); + return Some(self.ast_region_to_region(r, None)); } if let Some(principal) = existential_predicates.principal() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e7544c10be3e..a8b5d718f81d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,7 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; -use rscope::{ElisionFailureInfo, RegionScope}; +use rscope::RegionScope; use session::{Session, CompileResult}; use CrateCtxt; use TypeAndSubsts; @@ -1410,6 +1410,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } + fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) + -> &'tcx ty::Region { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span) + }; + self.next_region_var(v) + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { self.next_ty_var(TypeVariableOrigin::TypeInference(span)) } @@ -1465,15 +1474,6 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { // be some expression). *self.next_region_var(infer::MiscVariable(span)) } - - fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> Result>> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span) - }; - Ok(*self.next_region_var(v)) - } } /// Controls whether the arguments are tupled. This is used for the call @@ -4408,7 +4408,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => &[] }; - AstConv::opt_ast_region_to_region(self, self, span, lifetimes.get(i), Some(def)) + if let Some(lifetime) = lifetimes.get(i) { + AstConv::ast_region_to_region(self, lifetime, Some(def)) + } else { + self.re_infer(span, Some(def)) + } }, |def, substs| { let mut i = def.index as usize; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f954d2a5d616..70bd43751ebd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -437,6 +437,11 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { None } + fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) + -> &'tcx ty::Region { + span_bug!(span, "unelided lifetime in signature"); + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { struct_span_err!( self.tcx().sess, @@ -639,8 +644,6 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: AssociatedItemContainer, id: ast::NodeId, sig: &hir::MethodSig, - untransformed_rcvr_ty: Ty<'tcx>, - body: Option, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) { let def_id = ccx.tcx.hir.local_def_id(id); let ty_generics = generics_of_def_id(ccx, def_id); @@ -652,14 +655,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ImplContainer(_) => Some(AnonTypeScope::new(def_id)), TraitContainer(_) => None }; - let assoc_item = ccx.tcx.associated_item(def_id); - let self_value_ty = if assoc_item.method_has_self_argument { - Some(untransformed_rcvr_ty) - } else { - None - }; - let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, self_value_ty, body, anon_scope); + let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + sig.unsafety, sig.abi, &sig.decl, anon_scope); let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.hir.span(id), def_id); @@ -876,14 +873,9 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ); } - hir::TraitItemKind::Method(ref sig, ref method) => { - let body = match *method { - hir::TraitMethod::Required(_) => None, - hir::TraitMethod::Provided(body) => Some(body) - }; + hir::TraitItemKind::Method(ref sig, _) => { convert_method(ccx, TraitContainer(trait_def_id), - trait_item.id, sig, tcx.mk_self_type(), - body, &trait_predicates); + trait_item.id, sig, &trait_predicates); } } } @@ -896,7 +888,6 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { let impl_def_id = tcx.hir.get_parent_did(impl_item.id); let impl_predicates = tcx.item_predicates(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let impl_self_ty = tcx.item_type(impl_def_id); match impl_item.node { hir::ImplItemKind::Const(ref ty, _) => { @@ -923,10 +914,8 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ)); } - hir::ImplItemKind::Method(ref sig, body) => { - convert_method(ccx, ImplContainer(impl_def_id), - impl_item.id, sig, impl_self_ty, - Some(body), &impl_predicates); + hir::ImplItemKind::Method(ref sig, _) => { + convert_method(ccx, ImplContainer(impl_def_id), impl_item.id, sig, &impl_predicates); } } } @@ -1472,7 +1461,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { - AstConv::ast_region_to_region(&ccx.icx(&()), l) + AstConv::ast_region_to_region(&ccx.icx(&()), l, None) }).collect(), pure_wrt_drop: l.pure_wrt_drop, } @@ -1545,11 +1534,11 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t) + ccx.icx(&()).to_ty(&ExplicitRscope, &t) } - ItemFn(ref decl, unsafety, _, abi, ref generics, body) => { - let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, - body, Some(AnonTypeScope::new(def_id))); + ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { + let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl, + Some(AnonTypeScope::new(def_id))); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); ccx.tcx.mk_fn_def(def_id, substs, tofd) } @@ -1765,7 +1754,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, name: param.lifetime.name })); for bound in ¶m.bounds { - let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound); + let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); predicates.push(outlives.to_predicate()); } @@ -1816,7 +1805,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = AstConv::ast_region_to_region(&ccx.icx(&()), lifetime); + let region = AstConv::ast_region_to_region(&ccx.icx(&()), + lifetime, + None); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); predicates.push(ty::Predicate::TypeOutlives(pred)) } @@ -1825,9 +1816,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime); + let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime, None); for bound in ®ion_pred.bounds { - let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound); + let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); predicates.push(ty::Predicate::RegionOutlives(pred)) } @@ -1935,7 +1926,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hir::TraitTyParamBound(..) => None, hir::RegionTyParamBound(ref lifetime) => - Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime)), + Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime, None)), } }) .collect() @@ -1997,7 +1988,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, }).collect(); let region_bounds = region_bounds.into_iter().map(|r| { - astconv.ast_region_to_region(r) + astconv.ast_region_to_region(r, None) }).collect(); trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); @@ -2039,7 +2030,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, .collect() } hir::RegionTyParamBound(ref lifetime) => { - let region = astconv.ast_region_to_region(lifetime); + let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); vec![ty::Predicate::TypeOutlives(pred)] } @@ -2057,18 +2048,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> Ty<'tcx> { - let rb = BindingRscope::new(); - let input_tys = decl.inputs - .iter() - .map(|a| AstConv::ty_of_arg(&ccx.icx(ast_generics), &rb, a, None)) - .collect::>(); - - let output = match decl.output { - hir::Return(ref ty) => - AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty), - hir::DefaultReturn(..) => - ccx.tcx.mk_nil(), - }; + let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl, None); // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. @@ -2084,21 +2064,17 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( .emit(); } }; - for (input, ty) in decl.inputs.iter().zip(&input_tys) { + for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) { check(&input, ty) } if let hir::Return(ref ty) = decl.output { - check(&ty, output) + check(&ty, *fty.sig.output().skip_binder()) } } let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap(); let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id); - ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { - abi: abi, - unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ccx.tcx.mk_fn_sig(input_tys.into_iter(), output, decl.variadic)), - })) + ccx.tcx.mk_fn_def(def_id, substs, fty) } pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6d943f3ca2ef..7f8c508bf222 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1412,85 +1412,19 @@ fn main() { ``` "##, -E0106: r##" -This error indicates that a lifetime is missing from a type. If it is an error -inside a function signature, the problem may be with failing to adhere to the -lifetime elision rules (see below). - -Here are some simple examples of where you'll run into this error: - -```compile_fail,E0106 -struct Foo { x: &bool } // error -struct Foo<'a> { x: &'a bool } // correct - -enum Bar { A(u8), B(&bool), } // error -enum Bar<'a> { A(u8), B(&'a bool), } // correct - -type MyStr = &str; // error -type MyStr<'a> = &'a str; // correct -``` - -Lifetime elision is a special, limited kind of inference for lifetimes in -function signatures which allows you to leave out lifetimes in certain cases. -For more background on lifetime elision see [the book][book-le]. - -The lifetime elision rules require that any function signature with an elided -output lifetime must either have - - - exactly one input lifetime - - or, multiple input lifetimes, but the function must also be a method with a - `&self` or `&mut self` receiver - -In the first case, the output lifetime is inferred to be the same as the unique -input lifetime. In the second case, the lifetime is instead inferred to be the -same as the lifetime on `&self` or `&mut self`. - -Here are some examples of elision errors: - -```compile_fail,E0106 -// error, no input lifetimes -fn foo() -> &str { } - -// error, `x` and `y` have distinct lifetimes inferred -fn bar(x: &str, y: &str) -> &str { } - -// error, `y`'s lifetime is inferred to be distinct from `x`'s -fn baz<'a>(x: &'a str, y: &str) -> &str { } -``` - -[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision -"##, - E0107: r##" This error means that an incorrect number of lifetime parameters were provided -for a type (like a struct or enum) or trait. - -Some basic examples include: +for a type (like a struct or enum) or trait: ```compile_fail,E0107 -struct Foo<'a>(&'a str); +struct Foo<'a, 'b>(&'a str, &'b str); enum Bar { A, B, C } struct Baz<'a> { - foo: Foo, // error: expected 1, found 0 + foo: Foo<'a>, // error: expected 2, found 1 bar: Bar<'a>, // error: expected 0, found 1 } ``` - -Here's an example that is currently an error, but may work in a future version -of Rust: - -```compile_fail,E0107 -struct Foo<'a>(&'a str); - -trait Quux { } -impl Quux for Foo { } // error: expected 1, found 0 -``` - -Lifetime elision in implementation headers was part of the lifetime elision -RFC. It is, however, [currently unimplemented][iss15872]. - -[iss15872]: https://github.com/rust-lang/rust/issues/15872 "##, E0116: r##" diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 2ad1a7c3d685..3ac917c396cf 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -8,28 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty; use rustc::ty::subst::Substs; use astconv::AstConv; -use std::cell::Cell; use syntax_pos::Span; -#[derive(Clone)] -pub struct ElisionFailureInfo { - /// Where we can find the argument pattern. - pub parent: Option, - /// The index of the argument in the original definition. - pub index: usize, - pub lifetime_count: usize, - pub have_bound_regions: bool -} - -pub type ElidedLifetime = Result>>; - /// Defines strategies for handling regions that are omitted. For /// example, if one writes the type `&Foo`, then the lifetime of /// this reference has been omitted. When converting this @@ -41,9 +27,6 @@ pub type ElidedLifetime = Result>>; /// can return `Err(())` to indicate that this is not a scope in which /// regions can legally be omitted. pub trait RegionScope { - fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> Result>>; - /// If an object omits any explicit lifetime bound, and none can /// be derived from the object traits, what should we use? If /// `None` is returned, an explicit annotation is required. @@ -115,11 +98,6 @@ impl RegionScope for MaybeWithAnonTypes { self.base_scope.object_lifetime_default(span) } - fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> Result>> { - self.base_scope.anon_region(span, def) - } - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { self.base_scope.base_object_lifetime_default(span) } @@ -135,11 +113,6 @@ impl RegionScope for MaybeWithAnonTypes { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) - -> Result>> { - Err(None) - } - fn object_lifetime_default(&self, span: Span) -> Option { Some(self.base_object_lifetime_default(span)) } @@ -149,135 +122,6 @@ impl RegionScope for ExplicitRscope { } } -// Same as `ExplicitRscope`, but provides some extra information for diagnostics -pub struct UnelidableRscope(Option>); - -impl UnelidableRscope { - pub fn new(v: Option>) -> UnelidableRscope { - UnelidableRscope(v) - } -} - -impl RegionScope for UnelidableRscope { - fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) - -> Result>> { - Err(self.0.clone()) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -// A scope in which omitted anonymous region defaults to -// `default`. This is used after the `->` in function signatures. The -// latter use may go away. Note that object-lifetime defaults work a -// bit differently, as specified in RFC #599. -pub struct ElidableRscope { - default: ty::Region, -} - -impl ElidableRscope { - pub fn new(r: ty::Region) -> ElidableRscope { - ElidableRscope { default: r } - } -} - -impl RegionScope for ElidableRscope { - fn object_lifetime_default(&self, span: Span) -> Option { - // Per RFC #599, object-lifetimes default to 'static unless - // overridden by context, and this takes precedence over - // lifetime elision. - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } - - fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) - -> Result>> - { - Ok(self.default) - } -} - -/// A scope that behaves as an ElidabeRscope with a `'static` default region -/// that should also warn if the `static_in_const` feature is unset. -#[derive(Copy, Clone)] -pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, -} - -impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { - /// create a new StaticRscope from a reference to the `TyCtxt` - pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { - StaticRscope { tcx: tcx } - } -} - -impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { - fn anon_region(&self, span: Span, _: Option<&ty::RegionParameterDef>) - -> Result>> { - if !self.tcx.sess.features.borrow().static_in_const { - self.tcx - .sess - .struct_span_err(span, - "this needs a `'static` lifetime or the \ - `static_in_const` feature, see #35897") - .emit(); - } - Ok(ty::ReStatic) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -/// A scope in which we generate anonymous, late-bound regions for -/// omitted regions. This occurs in function signatures. -pub struct BindingRscope { - anon_bindings: Cell, -} - -impl BindingRscope { - pub fn new() -> BindingRscope { - BindingRscope { - anon_bindings: Cell::new(0), - } - } -} - -impl RegionScope for BindingRscope { - fn object_lifetime_default(&self, span: Span) -> Option { - // Per RFC #599, object-lifetimes default to 'static unless - // overridden by context, and this takes precedence over the - // binding defaults in a fn signature. - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } - - fn anon_region(&self, _: Span, _: Option<&ty::RegionParameterDef>) - -> Result>> - { - let idx = self.anon_bindings.get(); - self.anon_bindings.set(idx + 1); - Ok(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx))) - } -} - /// A scope which overrides the default object lifetime but has no other effect. pub struct ObjectLifetimeDefaultRscope<'r> { base_scope: &'r (RegionScope+'r), @@ -315,12 +159,6 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { self.base_scope.base_object_lifetime_default(span) } - fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> Result>> - { - self.base_scope.anon_region(span, def) - } - fn anon_type_scope(&self) -> Option { self.base_scope.anon_type_scope() } @@ -348,12 +186,6 @@ impl<'r> RegionScope for ShiftedRscope<'r> { ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } - fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> Result>> - { - self.base_scope.anon_region(span, def).map(|r| ty::fold::shift_region(r, 1)) - } - fn anon_type_scope(&self) -> Option { self.base_scope.anon_type_scope() } diff --git a/src/test/compile-fail/E0106.rs b/src/test/compile-fail/E0106.rs index dab03f0bccfd..d5644ab06088 100644 --- a/src/test/compile-fail/E0106.rs +++ b/src/test/compile-fail/E0106.rs @@ -23,5 +23,17 @@ type MyStr = &str; //~^ ERROR E0106 //~| NOTE expected lifetime parameter +struct Baz<'a>(&'a str); +struct Buzz<'a, 'b>(&'a str, &'b str); + +struct Quux { + baz: Baz, + //~^ ERROR E0106 + //~| expected lifetime parameter + buzz: Buzz, + //~^ ERROR E0106 + //~| expected 2 lifetime parameters +} + fn main() { } diff --git a/src/test/compile-fail/E0107.rs b/src/test/compile-fail/E0107.rs index 5f333e17c478..16ebd3e9ca5f 100644 --- a/src/test/compile-fail/E0107.rs +++ b/src/test/compile-fail/E0107.rs @@ -18,9 +18,6 @@ enum Bar { } struct Baz<'a, 'b, 'c> { - foo: Foo, - //~^ ERROR E0107 - //~| expected 1 lifetime parameter buzz: Buzz<'a>, //~^ ERROR E0107 //~| expected 2 lifetime parameters diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs index 44ad0bb01138..e6251a0d318a 100644 --- a/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs @@ -22,10 +22,11 @@ struct SomeStruct Foo<&'x isize>> { //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } -struct AnotherStruct Foo<&'x isize>> { - field: >::A - //~^ ERROR missing lifetime specifier -} +// FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. + +// struct AnotherStruct Foo<&'x isize>> { +// field: Foo<&'y isize>>::A +// } struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> { field: >::A diff --git a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs index 7355c70ff95e..43371eb6340f 100644 --- a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -38,4 +38,28 @@ fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier panic!() } +// Cases which used to work but now don't. + +type StaticStr = &'static str; // hides 'static +trait WithLifetime<'a> { + type Output; // can hide 'a +} + +// This worked because the type of the first argument contains +// 'static, although StaticStr doesn't even have parameters. +fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier +//~^ HELP this function's return type contains a borrowed value +//~| HELP consider giving it an explicit bounded or 'static lifetime + panic!() +} + +// This worked because the compiler resolved the argument type +// to >::Output which has the hidden 'a. +fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize { +//~^ ERROR missing lifetime specifier +//~| HELP this function's return type contains a borrowed value +//~| HELP consider giving it an explicit bounded or 'static lifetime + panic!() +} + fn main() {} diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 083cc218eecf..93635e7fddea 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -15,8 +15,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { } // the boundaries of elision -static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = //~^ ERROR missing lifetime specifier [E0106] + &(non_elidable as fn(&u8, &u8) -> &u8); + //~^ ERROR missing lifetime specifier [E0106] struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, From 9783947c2adfcadba3c0e036548cf6fd3e12553a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 13 Jan 2017 15:10:37 +0200 Subject: [PATCH 051/104] rustc_typeck: move impl Trait checks out of RegionScope. --- src/librustc_typeck/astconv.rs | 94 +++++++++++-------- src/librustc_typeck/collect.rs | 32 ++----- src/librustc_typeck/lib.rs | 1 + src/librustc_typeck/rscope.rs | 79 ---------------- .../compile-fail/impl-trait/disallowed.rs | 2 +- 5 files changed, 65 insertions(+), 143 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 42a220e1b9b4..90efe7cad399 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -62,7 +62,7 @@ use rustc::ty::wf::object_region_bounds; use rustc_back::slice; use require_c_abi_if_variadic; use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope}; -use rscope::{AnonTypeScope, MaybeWithAnonTypes, ExplicitRscope}; +use rscope::ExplicitRscope; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -361,8 +361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::ParenthesizedParameters(ref data) => { assert_eq!(i, 0); - let (ty, assoc) = - self.convert_parenthesized_parameters(rscope, substs, data); + let (ty, assoc) = self.convert_parenthesized_parameters(substs, data); output_assoc_binding = Some(assoc); ty } @@ -416,7 +415,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { vec![output_assoc_binding.unwrap_or_else(|| { // This is an error condition, but we should // get the associated type binding anyway. - self.convert_parenthesized_parameters(rscope, substs, data).1 + self.convert_parenthesized_parameters(substs, data).1 })] } }; @@ -428,20 +427,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn convert_parenthesized_parameters(&self, - rscope: &RegionScope, region_substs: &[Kind<'tcx>], data: &hir::ParenthesizedParameterData) -> (Ty<'tcx>, ConvertedBinding<'tcx>) { - let anon_scope = rscope.anon_type_scope(); - let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_arg_to_ty(&rscope, None, region_substs, a_t) + self.ast_ty_arg_to_ty(&ExplicitRscope, None, region_substs, a_t) })); let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.ast_ty_to_ty(&rscope, output_ty), output_ty.span) + (self.ast_ty_to_ty(&ExplicitRscope, output_ty), output_ty.span) } None => { (self.tcx().mk_nil(), data.span) @@ -1309,12 +1305,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - let anon_scope = rscope.anon_type_scope(); - let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, - bf.abi, - &bf.decl, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1361,16 +1352,54 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; + // Figure out if we can allow an `impl Trait` here, by walking up + // to a `fn` or inherent `impl` method, going only through `Ty` + // or `TraitRef` nodes (as nothing else should be in types) and + // ensuring that we reach the `fn`/method signature's return type. + let mut node_id = ast_ty.id; + let fn_decl = loop { + let parent = tcx.hir.get_parent_node(node_id); + match tcx.hir.get(parent) { + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(ref fn_decl, ..), .. + }) => break Some(fn_decl), + + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(ref sig, _), .. + }) => { + match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node { + hir::ItemImpl(.., None, _, _) => { + break Some(&sig.decl) + } + _ => break None + } + } + + hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {} + + _ => break None + } + node_id = parent; + }; + let allow = fn_decl.map_or(false, |fd| { + match fd.output { + hir::DefaultReturn(_) => false, + hir::Return(ref ty) => ty.id == node_id + } + }); + // Create the anonymized type. - let def_id = tcx.hir.local_def_id(ast_ty.id); - if let Some(anon_scope) = rscope.anon_type_scope() { - let substs = anon_scope.fresh_substs(self, ast_ty.span); + if allow { + let def_id = tcx.hir.local_def_id(ast_ty.id); + if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) { + return tcx.types.err; + } + let substs = Substs::identity_for_item(tcx, def_id); let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs); // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, - Some(anon_scope), ast_ty.span); let predicates = bounds.predicates(tcx, ty); let predicates = tcx.lift_to_global(&predicates).unwrap(); @@ -1450,36 +1479,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn ty_of_fn(&self, unsafety: hir::Unsafety, abi: abi::Abi, - decl: &hir::FnDecl, - anon_scope: Option) + decl: &hir::FnDecl) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, decl, None, anon_scope) - } - - fn ty_of_method_or_bare_fn(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl, - arg_anon_scope: Option, - ret_anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> - { - debug!("ty_of_method_or_bare_fn"); - - // New region names that appear inside of the arguments of the function - // declaration are bound to that function type. - let rb = MaybeWithAnonTypes::new(ExplicitRscope, arg_anon_scope); + debug!("ty_of_fn"); let input_tys: Vec = - decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); + decl.inputs.iter().map(|a| self.ty_of_arg(&ExplicitRscope, a, None)).collect(); let output_ty = match decl.output { - hir::Return(ref output) => - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(ExplicitRscope, ret_anon_scope), output), + hir::Return(ref output) => self.ast_ty_to_ty(&ExplicitRscope, output), hir::DefaultReturn(..) => self.tcx().mk_nil(), }; - debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); + debug!("ty_of_fn: output_ty={:?}", output_ty); self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 70bd43751ebd..1bfa4fc7b682 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -641,7 +641,6 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: AssociatedItemContainer, id: ast::NodeId, sig: &hir::MethodSig, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) { @@ -651,12 +650,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generic_predicates = ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig.unsafety, sig.abi, &sig.decl, anon_scope); + sig.unsafety, sig.abi, &sig.decl); let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.hir.span(id), def_id); @@ -874,8 +869,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { } hir::TraitItemKind::Method(ref sig, _) => { - convert_method(ccx, TraitContainer(trait_def_id), - trait_item.id, sig, &trait_predicates); + convert_method(ccx, trait_item.id, sig, &trait_predicates); } } } @@ -915,7 +909,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { } hir::ImplItemKind::Method(ref sig, _) => { - convert_method(ccx, ImplContainer(impl_def_id), impl_item.id, sig, &impl_predicates); + convert_method(ccx, impl_item.id, sig, &impl_predicates); } } } @@ -1186,7 +1180,6 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, self_param_ty, bounds, SizedByDefault::No, - None, item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1323,7 +1316,6 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) assoc_ty, bounds, SizedByDefault::Yes, - None, trait_item.span); bounds.predicates(ccx.tcx, assoc_ty).into_iter() @@ -1537,8 +1529,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.icx(&()).to_ty(&ExplicitRscope, &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { - let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl, - Some(AnonTypeScope::new(def_id))); + let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); ccx.tcx.mk_fn_def(def_id, substs, tofd) } @@ -1770,7 +1761,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_ty, ¶m.bounds, SizedByDefault::Yes, - None, param.span); predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } @@ -1968,7 +1958,6 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[hir::TyParamBound], sized_by_default: SizedByDefault, - anon_scope: Option, span: Span) -> Bounds<'tcx> { @@ -1979,9 +1968,8 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, let mut projection_bounds = vec![]; - let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { - astconv.instantiate_poly_trait_ref(&rscope, + astconv.instantiate_poly_trait_ref(&ExplicitRscope, bound, param_ty, &mut projection_bounds) @@ -2048,7 +2036,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> Ty<'tcx> { - let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl, None); + let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl); // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. @@ -2077,10 +2065,10 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( ccx.tcx.mk_fn_def(def_id, substs, fty) } -pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - span: Span, - def_id: DefId) - -> &'tcx Substs<'tcx> { +fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>, + span: Span, + def_id: DefId) + -> &'tcx Substs<'tcx> { let tcx = astconv.tcx(); // FIXME(eddyb) Do this request from Substs::for_item in librustc. if let Err(ErrorReported) = astconv.get_generics(span, def_id) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0e7daa03404c..90ce77cc5f4b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,6 +77,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] +#![feature(loop_break_value)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 3ac917c396cf..d982c91e388d 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -8,11 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::def_id::DefId; use rustc::ty; -use rustc::ty::subst::Substs; - -use astconv::AstConv; use syntax_pos::Span; @@ -38,73 +34,6 @@ pub trait RegionScope { /// computing `object_lifetime_default` (in particular, in legacy /// modes, it may not be relevant). fn base_object_lifetime_default(&self, span: Span) -> ty::Region; - - /// If this scope allows anonymized types, return the generics in - /// scope, that anonymized types will close over. For example, - /// if you have a function like: - /// - /// fn foo<'a, T>() -> impl Trait { ... } - /// - /// then, for the rscope that is used when handling the return type, - /// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`, - /// on which `.fresh_substs(...)` can be used to obtain identity - /// Substs for `'a` and `T`, to track them in `TyAnon`. This property - /// is controlled by the region scope because it's fine-grained enough - /// to allow restriction of anonymized types to the syntactical extent - /// of a function's return type. - fn anon_type_scope(&self) -> Option { - None - } -} - -#[derive(Copy, Clone)] -pub struct AnonTypeScope { - enclosing_item: DefId -} - -impl<'gcx: 'tcx, 'tcx> AnonTypeScope { - pub fn new(enclosing_item: DefId) -> AnonTypeScope { - AnonTypeScope { - enclosing_item: enclosing_item - } - } - - pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span) - -> &'tcx Substs<'tcx> { - use collect::mk_item_substs; - - mk_item_substs(astconv, span, self.enclosing_item) - } -} - -/// A scope wrapper which optionally allows anonymized types. -#[derive(Copy, Clone)] -pub struct MaybeWithAnonTypes { - base_scope: R, - anon_scope: Option -} - -impl MaybeWithAnonTypes { - pub fn new(base_scope: R, anon_scope: Option) -> Self { - MaybeWithAnonTypes { - base_scope: base_scope, - anon_scope: anon_scope - } - } -} - -impl RegionScope for MaybeWithAnonTypes { - fn object_lifetime_default(&self, span: Span) -> Option { - self.base_scope.object_lifetime_default(span) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - self.base_scope.base_object_lifetime_default(span) - } - - fn anon_type_scope(&self) -> Option { - self.anon_scope - } } // A scope in which all regions must be explicitly named. This is used @@ -158,10 +87,6 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { fn base_object_lifetime_default(&self, span: Span) -> ty::Region { self.base_scope.base_object_lifetime_default(span) } - - fn anon_type_scope(&self) -> Option { - self.base_scope.anon_type_scope() - } } /// A scope which simply shifts the Debruijn index of other scopes @@ -185,8 +110,4 @@ impl<'r> RegionScope for ShiftedRscope<'r> { fn base_object_lifetime_default(&self, span: Span) -> ty::Region { ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } - - fn anon_type_scope(&self) -> Option { - self.base_scope.anon_type_scope() - } } diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs index 09aba5d8c916..0467c49b0311 100644 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ b/src/test/compile-fail/impl-trait/disallowed.rs @@ -26,9 +26,9 @@ trait LazyToString { //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types } -// Note that the following impl doesn't error, because the trait is invalid. impl LazyToString for String { fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types || self.clone() } } From 41553d6fbc36ee05364dcdccf43e8b8141a5cfe3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 17 Jan 2017 16:46:23 +0200 Subject: [PATCH 052/104] rustc: lower trait type paths as TyTraitObject. --- src/librustc/hir/lowering.rs | 42 +++++++++++++++++++------ src/librustc/lib.rs | 1 + src/librustc/middle/resolve_lifetime.rs | 39 ++++------------------- src/librustc_typeck/astconv.rs | 18 +---------- src/librustc_typeck/check/mod.rs | 2 +- 5 files changed, 42 insertions(+), 60 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7ca251f3ff91..f7d40350dc93 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -337,7 +337,8 @@ impl<'a> LoweringContext<'a> { return self.lower_ty(ty); } TyKind::Path(ref qself, ref path) => { - hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit)) + let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); + return self.ty_path(t.id, t.span, qpath); } TyKind::ImplicitSelf => { hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { @@ -470,7 +471,8 @@ impl<'a> LoweringContext<'a> { // Otherwise, the base path is an implicit `Self` type path, // e.g. `Vec` in `Vec::new` or `::Item` in // `::Item::default`. - self.ty(p.span, hir::TyPath(hir::QPath::Resolved(qself, path))) + let new_id = self.next_id(); + self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)) }; // Anything after the base path are associated "extensions", @@ -493,7 +495,8 @@ impl<'a> LoweringContext<'a> { } // Wrap the associated extension in another type node. - ty = self.ty(p.span, hir::TyPath(qpath)); + let new_id = self.next_id(); + ty = self.ty_path(new_id, p.span, qpath); } // Should've returned in the for loop above. @@ -2352,12 +2355,33 @@ impl<'a> LoweringContext<'a> { self.expr_block(block, attrs) } - fn ty(&mut self, span: Span, node: hir::Ty_) -> P { - P(hir::Ty { - id: self.next_id(), - node: node, - span: span, - }) + fn ty_path(&mut self, id: NodeId, span: Span, qpath: hir::QPath) -> P { + let mut id = id; + let node = match qpath { + hir::QPath::Resolved(None, path) => { + // Turn trait object paths into `TyTraitObject` instead. + if let Def::Trait(_) = path.def { + let principal = hir::TraitTyParamBound(hir::PolyTraitRef { + bound_lifetimes: hir_vec![], + trait_ref: hir::TraitRef { + path: path.and_then(|path| path), + ref_id: id, + }, + span, + }, hir::TraitBoundModifier::None); + + // The original ID is taken by the `PolyTraitRef`, + // so the `Ty` itself needs a different one. + id = self.next_id(); + + hir::TyTraitObject(hir_vec![principal]) + } else { + hir::TyPath(hir::QPath::Resolved(None, path)) + } + } + _ => hir::TyPath(qpath) + }; + P(hir::Ty { id, node, span }) } fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 11fdf6919ccb..0ff9626ae11a 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![feature(field_init_shorthand)] #![feature(libc)] #![feature(loop_break_value)] #![feature(nonzero)] diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 4e02485a40b7..aa118891d982 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -322,24 +322,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } - hir::TyPath(hir::QPath::Resolved(None, ref path)) => { - // if this path references a trait, then this will resolve to - // a trait ref, which introduces a binding scope. - match path.def { - Def::Trait(..) => { - let scope = Scope::Binder { - lifetimes: FxHashMap(), - s: self.scope - }; - self.with(scope, |_, this| { - this.visit_path(path, ty.id); - }); - } - _ => { - intravisit::walk_ty(self, ty); - } - } - } _ => { intravisit::walk_ty(self, ty) } @@ -889,7 +871,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Def::Struct(_) | Def::Union(_) | Def::Enum(_) | - Def::Trait(_) | Def::PrimTy(_) => return def == path.def, _ => {} } @@ -970,21 +951,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn visit_ty(&mut self, ty: &hir::Ty) { - let delta = match ty.node { - hir::TyBareFn(_) => 1, - hir::TyPath(hir::QPath::Resolved(None, ref path)) => { - // if this path references a trait, then this will resolve to - // a trait ref, which introduces a binding scope. - match path.def { - Def::Trait(..) => 1, - _ => 0 - } - } - _ => 0 - }; - self.binder_depth += delta; + if let hir::TyBareFn(_) = ty.node { + self.binder_depth += 1; + } intravisit::walk_ty(self, ty); - self.binder_depth -= delta; + if let hir::TyBareFn(_) = ty.node { + self.binder_depth -= 1; + } } fn visit_poly_trait_ref(&mut self, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 90efe7cad399..324d569cb8dc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1151,7 +1151,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, opt_self_ty: Option>, path: &hir::Path, - path_id: ast::NodeId, permit_variants: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1161,21 +1160,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { - Def::Trait(trait_def_id) => { - // N.B. this case overlaps somewhat with - // TyTraitObject, see that fn for details - - assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - - self.trait_path_to_object_type(rscope, - span, - trait_def_id, - path_id, - path.segments.last().unwrap(), - span, - partition_bounds(&[])) - } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(path.segments.split_last().unwrap().1); @@ -1421,7 +1405,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| { self.ast_ty_to_ty(rscope, qself) }); - self.def_to_ty(rscope, opt_self_ty, path, ast_ty.id, false) + self.def_to_ty(rscope, opt_self_ty, path, false) } hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => { debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8b5d718f81d..4d1b2cec32e5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3976,7 +3976,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match *qpath { hir::QPath::Resolved(ref maybe_qself, ref path) => { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, node_id, true); + let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, true); (path.def, ty) } hir::QPath::TypeRelative(ref qself, ref segment) => { From c5befdc6308f8624b4b5fa8808ba0af70d2fbcf1 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 24 Jan 2017 17:17:06 +0200 Subject: [PATCH 053/104] rustc: always keep an explicit lifetime in trait objects. --- src/librustc/hir/intravisit.rs | 13 +- src/librustc/hir/lowering.rs | 24 ++- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 17 +- src/librustc/middle/resolve_lifetime.rs | 12 +- .../calculate_svh/svh_visitor.rs | 2 +- src/librustc_passes/ast_validation.rs | 11 ++ src/librustc_passes/diagnostics.rs | 1 + src/librustc_typeck/astconv.rs | 167 ++++-------------- src/librustc_typeck/collect.rs | 19 +- src/librustc_typeck/diagnostics.rs | 1 - src/librustdoc/clean/mod.rs | 28 +-- ...n-bounds-on-objects-and-type-parameters.rs | 6 +- 13 files changed, 137 insertions(+), 166 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d71263bea004..4b3e0d29101e 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -301,7 +301,7 @@ pub trait Visitor<'v> : Sized { fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } fn visit_variant_data(&mut self, @@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v PolyTraitRef, - _modifier: &'v TraitBoundModifier) + _modifier: TraitBoundModifier) where V: Visitor<'v> { walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); @@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(ty); visitor.visit_nested_body(length) } - TyTraitObject(ref bounds) => { - walk_list!(visitor, visit_ty_param_bound, bounds); + TyTraitObject(ref bounds, ref lifetime) => { + for bound in bounds { + visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None); + } + visitor.visit_lifetime(lifetime); } TyImplTrait(ref bounds) => { walk_list!(visitor, visit_ty_param_bound, bounds); @@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { match *bound { - TraitTyParamBound(ref typ, ref modifier) => { + TraitTyParamBound(ref typ, modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } RegionTyParamBound(ref lifetime) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f7d40350dc93..8a4acb3d0388 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -360,7 +360,23 @@ impl<'a> LoweringContext<'a> { hir::TyTypeof(self.record_body(expr, None)) } TyKind::TraitObject(ref bounds) => { - hir::TyTraitObject(self.lower_bounds(bounds)) + let mut lifetime_bound = None; + let bounds = bounds.iter().filter_map(|bound| { + match *bound { + TraitTyParamBound(ref ty, TraitBoundModifier::None) => { + Some(self.lower_poly_trait_ref(ty)) + } + TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, + RegionTyParamBound(ref lifetime) => { + lifetime_bound = Some(self.lower_lifetime(lifetime)); + None + } + } + }).collect(); + let lifetime_bound = lifetime_bound.unwrap_or_else(|| { + self.elided_lifetime(t.span) + }); + hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { hir::TyImplTrait(self.lower_bounds(bounds)) @@ -2361,20 +2377,20 @@ impl<'a> LoweringContext<'a> { hir::QPath::Resolved(None, path) => { // Turn trait object paths into `TyTraitObject` instead. if let Def::Trait(_) = path.def { - let principal = hir::TraitTyParamBound(hir::PolyTraitRef { + let principal = hir::PolyTraitRef { bound_lifetimes: hir_vec![], trait_ref: hir::TraitRef { path: path.and_then(|path| path), ref_id: id, }, span, - }, hir::TraitBoundModifier::None); + }; // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. id = self.next_id(); - hir::TyTraitObject(hir_vec![principal]) + hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span)) } else { hir::TyPath(hir::QPath::Resolved(None, path)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 94cb33b138c5..4ebe416e1bfe 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1205,7 +1205,7 @@ pub enum Ty_ { TyPath(QPath), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TyTraitObject(TyParamBounds), + TyTraitObject(HirVec, Lifetime), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. TyImplTrait(TyParamBounds), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 8e866f571749..e058c48c5914 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -416,8 +416,21 @@ impl<'a> State<'a> { hir::TyPath(ref qpath) => { self.print_qpath(qpath, false)? } - hir::TyTraitObject(ref bounds) => { - self.print_bounds("", &bounds[..])?; + hir::TyTraitObject(ref bounds, ref lifetime) => { + let mut first = true; + for bound in bounds { + self.nbsp()?; + if first { + first = false; + } else { + self.word_space("+")?; + } + self.print_poly_trait_ref(bound)?; + } + if !lifetime.is_elided() { + self.word_space("+")?; + self.print_lifetime(lifetime)?; + } } hir::TyImplTrait(ref bounds) => { self.print_bounds("impl ", &bounds[..])?; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index aa118891d982..88da47c2f0c4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -322,6 +322,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } + hir::TyTraitObject(ref bounds, ref lifetime) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } _ => { intravisit::walk_ty(self, ty) } @@ -441,7 +449,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef, - _modifier: &'tcx hir::TraitBoundModifier) { + _modifier: hir::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { @@ -962,7 +970,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, trait_ref: &hir::PolyTraitRef, - modifier: &hir::TraitBoundModifier) { + modifier: hir::TraitBoundModifier) { self.binder_depth += 1; intravisit::walk_poly_trait_ref(self, trait_ref, modifier); self.binder_depth -= 1; diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 69237f406760..c7512f2971b3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -828,7 +828,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { debug!("visit_poly_trait_ref: st={:?}", self.st); SawPolyTraitRef.hash(self.st); m.hash(self.st); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 9720bb842647..0933fdfd357c 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -144,6 +144,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } TyKind::TraitObject(ref bounds) => { + let mut any_lifetime_bounds = false; + for bound in bounds { + if let RegionTyParamBound(ref lifetime) = *bound { + if any_lifetime_bounds { + span_err!(self.session, lifetime.span, E0226, + "only a single explicit lifetime bound is permitted"); + break; + } + any_lifetime_bounds = true; + } + } self.no_questions_in_bounds(bounds, "trait object types", false); } TyKind::ImplTrait(ref bounds) => { diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index c414d7183681..ef871959176a 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -244,6 +244,7 @@ match 5u32 { } register_diagnostics! { + E0226, // only a single explicit lifetime bound is permitted E0472, // asm! is unsupported on this target E0561, // patterns aren't allowed in function pointer types E0571, // `break` with a value in a non-`loop`-loop diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 324d569cb8dc..5c71947c2077 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -453,24 +453,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding) } - pub fn instantiate_poly_trait_ref(&self, - rscope: &RegionScope, - ast_trait_ref: &hir::PolyTraitRef, - self_ty: Ty<'tcx>, - poly_projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> - { - let trait_ref = &ast_trait_ref.trait_ref; - let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_poly_trait_ref(rscope, - trait_ref.path.span, - trait_def_id, - self_ty, - trait_ref.ref_id, - trait_ref.path.segments.last().unwrap(), - poly_projections) - } - /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. /// Fails if the type is a type other than a trait type. @@ -505,17 +487,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - fn ast_path_to_poly_trait_ref(&self, + pub fn instantiate_poly_trait_ref(&self, rscope: &RegionScope, - span: Span, - trait_def_id: DefId, + ast_trait_ref: &hir::PolyTraitRef, self_ty: Ty<'tcx>, - path_id: ast::NodeId, - trait_segment: &hir::PathSegment, poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); + let trait_ref = &ast_trait_ref.trait_ref; + let trait_def_id = self.trait_def_id(trait_ref); + + debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); // The trait reference introduces a binding level here, so // we need to shift the `rscope`. It'd be nice if we could // do away with this rscope stuff and work this knowledge @@ -525,23 +507,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let (substs, assoc_bindings) = self.create_substs_for_ast_trait_ref(shifted_rscope, - span, + trait_ref.path.span, trait_def_id, self_ty, - trait_segment); + trait_ref.path.segments.last().unwrap()); let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { // specify type to assert that error was already reported in Err case: let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(path_id, + self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref, binding); predicate.ok() // ok to ignore Err() because ErrorReported (see above) })); - debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", - trait_segment, poly_projections, poly_trait_ref); + debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}", + trait_ref, poly_projections, poly_trait_ref); poly_trait_ref } @@ -754,32 +736,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) } - fn trait_path_to_object_type(&self, - rscope: &RegionScope, - path_span: Span, - trait_def_id: DefId, - trait_path_ref_id: ast::NodeId, - trait_segment: &hir::PathSegment, - span: Span, - partitioned_bounds: PartitionedBounds) - -> Ty<'tcx> { + fn conv_object_ty_poly_trait_ref(&self, + rscope: &RegionScope, + span: Span, + trait_bounds: &[hir::PolyTraitRef], + lifetime: &hir::Lifetime) + -> Ty<'tcx> + { let tcx = self.tcx(); + if trait_bounds.is_empty() { + span_err!(tcx.sess, span, E0224, + "at least one non-builtin trait is required for an object type"); + return tcx.types.err; + } + let mut projection_bounds = vec![]; let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); - let principal = self.ast_path_to_poly_trait_ref(rscope, - path_span, - trait_def_id, + let principal = self.instantiate_poly_trait_ref(rscope, + &trait_bounds[0], dummy_self, - trait_path_ref_id, - trait_segment, &mut projection_bounds); - let PartitionedBounds { trait_bounds, - region_bounds } = - partitioned_bounds; - - let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds); + let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]); if !trait_bounds.is_empty() { let b = &trait_bounds[0]; @@ -854,13 +833,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { v.sort_by(|a, b| a.cmp(tcx, b)); let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter())); - let region_bound = self.compute_object_lifetime_bound(span, - ®ion_bounds, - existential_predicates); - let region_bound = match region_bound { - Some(r) => r, - None => { + // Explicitly specified region bound. Use that. + let region_bound = if !lifetime.is_elided() { + self.ast_region_to_region(lifetime, None) + } else { + self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { tcx.mk_region(match rscope.object_lifetime_default(span) { Some(r) => r, None => { @@ -870,7 +848,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty::ReStatic } }) - } + }) }; debug!("region_bound: {:?}", region_bound); @@ -1330,8 +1308,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } tcx.mk_fn_ptr(bare_fn_ty) } - hir::TyTraitObject(ref bounds) => { - self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds) + hir::TyTraitObject(ref bounds, ref lifetime) => { + self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime) } hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; @@ -1537,33 +1515,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - fn conv_object_ty_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - ast_bounds: &[hir::TyParamBound]) - -> Ty<'tcx> - { - let mut partitioned_bounds = partition_bounds(ast_bounds); - - let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { - partitioned_bounds.trait_bounds.remove(0) - } else { - span_err!(self.tcx().sess, span, E0224, - "at least one non-builtin trait is required for an object type"); - return self.tcx().types.err; - }; - - let trait_ref = &trait_bound.trait_ref; - let trait_def_id = self.trait_def_id(trait_ref); - self.trait_path_to_object_type(rscope, - trait_ref.path.span, - trait_def_id, - trait_ref.ref_id, - trait_ref.path.segments.last().unwrap(), - span, - partitioned_bounds) - } - /// Given the bounds on an object, determines what single region bound (if any) we can /// use to summarize this type. The basic idea is that we will use the bound the user /// provided, if they provided one, and otherwise search the supertypes of trait bounds @@ -1571,27 +1522,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// we return `None`. fn compute_object_lifetime_bound(&self, span: Span, - explicit_region_bounds: &[&hir::Lifetime], existential_predicates: ty::Binder<&'tcx ty::Slice>>) -> Option<&'tcx ty::Region> // if None, use the default { let tcx = self.tcx(); - debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ - existential_predicates={:?})", - explicit_region_bounds, + debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); - if explicit_region_bounds.len() > 1 { - span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, - "only a single explicit lifetime bound is permitted"); - } - - if let Some(&r) = explicit_region_bounds.get(0) { - // Explicitly specified region bound. Use that. - return Some(self.ast_region_to_region(r, None)); - } - if let Some(principal) = existential_predicates.principal() { if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) { return Some(tcx.mk_region(ty::ReStatic)); @@ -1627,18 +1565,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } -pub struct PartitionedBounds<'a> { - pub trait_bounds: Vec<&'a hir::PolyTraitRef>, - pub region_bounds: Vec<&'a hir::Lifetime>, -} - /// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the /// remaining general trait bounds. fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_bounds: Vec<&'b hir::PolyTraitRef>) + trait_bounds: &'b [hir::PolyTraitRef]) -> (Vec, Vec<&'b hir::PolyTraitRef>) { - let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| { + let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| { match bound.trait_ref.path.def { Def::Trait(trait_did) => { // Checks whether `trait_did` refers to one of the builtin @@ -1675,30 +1608,6 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, (auto_traits, trait_bounds) } -/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds -pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound]) - -> PartitionedBounds<'b> -{ - let mut region_bounds = Vec::new(); - let mut trait_bounds = Vec::new(); - for ast_bound in ast_bounds { - match *ast_bound { - hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push(b); - } - hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {} - hir::RegionTyParamBound(ref l) => { - region_bounds.push(l); - } - } - } - - PartitionedBounds { - trait_bounds: trait_bounds, - region_bounds: region_bounds, - } -} - fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, ty_param_defs: &[ty::TypeParameterDef]) { let accepted = ty_param_defs.len(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1bfa4fc7b682..90e2f821b10b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -57,7 +57,7 @@ There are some shortcomings in this design: */ -use astconv::{AstConv, Bounds, PartitionedBounds, partition_bounds}; +use astconv::{AstConv, Bounds}; use lint; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; @@ -1961,10 +1961,19 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, span: Span) -> Bounds<'tcx> { - let PartitionedBounds { - trait_bounds, - region_bounds - } = partition_bounds(&ast_bounds); + let mut region_bounds = vec![]; + let mut trait_bounds = vec![]; + for ast_bound in ast_bounds { + match *ast_bound { + hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { + trait_bounds.push(b); + } + hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {} + hir::RegionTyParamBound(ref l) => { + region_bounds.push(l); + } + } + } let mut projection_bounds = vec![]; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7f8c508bf222..c41d40b41e42 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4096,7 +4096,6 @@ register_diagnostics! { // E0222, // Error code E0045 (variadic function must have C calling // convention) duplicate E0224, // at least one non-builtin train is required for an object type - E0226, // only a single explicit lifetime bound is permitted E0227, // ambiguous lifetime bound, explicit lifetime bound required E0228, // explicit lifetime bound required E0231, // only named substitution parameters are allowed diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4182dca71531..f1ced233dde7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1776,20 +1776,20 @@ impl Clean for hir::Ty { trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } } - TyTraitObject(ref bounds) => { - let lhs_ty = bounds[0].clean(cx); - match lhs_ty { - TraitBound(poly_trait, ..) => { - match poly_trait.trait_ { - ResolvedPath { path, typarams: None, did, is_generic } => { - ResolvedPath { - path: path, - typarams: Some(bounds[1..].clean(cx)), - did: did, - is_generic: is_generic, - } - } - _ => Infer // shouldn't happen + TyTraitObject(ref bounds, ref lifetime) => { + match bounds[0].clean(cx).trait_ { + ResolvedPath { path, typarams: None, did, is_generic } => { + let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| { + TraitBound(bound.clean(cx), hir::TraitBoundModifier::None) + }).collect(); + if !lifetime.is_elided() { + bounds.push(RegionBound(lifetime.clean(cx))); + } + ResolvedPath { + path: path, + typarams: Some(bounds), + did: did, + is_generic: is_generic, } } _ => Infer // shouldn't happen diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs index b8cbbdbe9ec3..503b577b1f1b 100644 --- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -18,7 +18,7 @@ trait SomeTrait { } // Bounds on object types: -struct Foo<'a,'b,'c> { +struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used // All of these are ok, because we can derive exactly one bound: a: Box, b: Box>, @@ -28,7 +28,9 @@ struct Foo<'a,'b,'c> { f: Box, // OK, defaults to 'static due to RFC 599. g: Box, - z: Box+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted + z: Box+'b+'c>, + //~^ ERROR only a single explicit lifetime bound is permitted + //~| ERROR lifetime bound not satisfied } fn test< From 4eac052a33f38688d582d3bb5242728f543a3c8f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 25 Jan 2017 17:32:44 +0200 Subject: [PATCH 054/104] rustc: move object default lifetimes to resolve_lifetimes. --- src/librustc/middle/cstore.rs | 6 + src/librustc/middle/resolve_lifetime.rs | 343 ++++++++++++++++-- src/librustc/ty/mod.rs | 19 - src/librustc/ty/structural_impls.rs | 26 +- src/librustc/util/ppaux.rs | 10 - src/librustc_metadata/cstore_impl.rs | 7 + src/librustc_metadata/decoder.rs | 7 + src/librustc_metadata/encoder.rs | 7 + src/librustc_metadata/schema.rs | 2 + src/librustc_typeck/astconv.rs | 175 +++------ src/librustc_typeck/check/mod.rs | 28 +- src/librustc_typeck/collect.rs | 136 +------ src/librustc_typeck/lib.rs | 1 - src/librustc_typeck/rscope.rs | 113 ------ ...object-lifetime-default-from-ref-struct.rs | 18 + .../object-lifetime-default-from-rptr.rs | 6 + 16 files changed, 445 insertions(+), 459 deletions(-) delete mode 100644 src/librustc_typeck/rscope.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8cf13cddc8c7..d11e6e3fc72b 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -28,6 +28,7 @@ use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; use middle::lang_items; +use middle::resolve_lifetime::ObjectLifetimeDefault; use ty::{self, Ty, TyCtxt}; use mir::Mir; use session::Session; @@ -183,6 +184,8 @@ pub trait CrateStore<'tcx> { fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx>; fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize); + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec; fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef; @@ -334,6 +337,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> ty::Generics<'tcx> { bug!("item_generics") } fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) { bug!("item_generics_own_param_counts") } + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec + { bug!("item_generics_object_lifetime_defaults") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef { bug!("trait_def") } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 88da47c2f0c4..88ef2c69a04d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -26,11 +26,12 @@ use ty; use std::cell::Cell; use std::mem::replace; use syntax::ast; +use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::Span; use errors::DiagnosticBuilder; -use util::nodemap::{NodeMap, FxHashSet, FxHashMap}; +use util::nodemap::{NodeMap, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; use hir; @@ -102,8 +103,46 @@ impl Region { _ => self } } + + fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap) + -> Option { + if let Region::EarlyBound(index, _) = self { + params.get(index as usize).and_then(|lifetime| { + map.defs.get(&lifetime.id).cloned() + }) + } else { + Some(self) + } + } } +/// A set containing, at most, one known element. +/// If two distinct values are inserted into a set, then it +/// becomes `Many`, which can be used to detect ambiguities. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +pub enum Set1 { + Empty, + One(T), + Many +} + +impl Set1 { + pub fn insert(&mut self, value: T) { + if let Set1::Empty = *self { + *self = Set1::One(value); + return; + } + if let Set1::One(ref old) = *self { + if *old == value { + return; + } + } + *self = Set1::Many; + } +} + +pub type ObjectLifetimeDefault = Set1; + // Maps the id of each lifetime reference to the lifetime decl // that it corresponds to. pub struct NamedRegionMap { @@ -115,6 +154,10 @@ pub struct NamedRegionMap { // are named regions appearing in fn arguments that do not appear // in where-clauses pub late_bound: NodeMap, + + // For each type and trait definition, maps type parameters + // to the trait object lifetime defaults computed from them. + pub object_lifetime_defaults: NodeMap>, } struct LifetimeContext<'a, 'tcx: 'a> { @@ -141,6 +184,9 @@ struct LifetimeContext<'a, 'tcx: 'a> { // List of labels in the function/method currently under analysis. labels_in_fn: Vec<(ast::Name, Span)>, + + // Cache for cross-crate per-definition object lifetime defaults. + xcrate_object_lifetime_defaults: DefIdMap>, } #[derive(Debug)] @@ -170,6 +216,14 @@ enum Scope<'a> { s: ScopeRef<'a> }, + /// Use a specific lifetime (if `Some`) or leave it unset (to be + /// inferred in a function body or potentially error outside one), + /// for the default choice of lifetime in a trait object type. + ObjectLifetimeDefault { + lifetime: Option, + s: ScopeRef<'a> + }, + Root } @@ -208,6 +262,7 @@ pub fn krate(sess: &Session, let mut map = NamedRegionMap { defs: NodeMap(), late_bound: NodeMap(), + object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map), }; sess.track_errors(|| { let mut visitor = LifetimeContext { @@ -217,6 +272,7 @@ pub fn krate(sess: &Session, scope: ROOT_SCOPE, trait_ref_hack: false, labels_in_fn: vec![], + xcrate_object_lifetime_defaults: DefIdMap(), }; for (_, item) in &krate.items { visitor.visit_item(item); @@ -326,10 +382,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } - if !lifetime.is_elided() { + if lifetime.is_elided() { + self.resolve_object_lifetime_default(lifetime) + } else { self.visit_lifetime(lifetime); } } + hir::TyRptr(ref lifetime_ref, ref mt) => { + self.visit_lifetime(lifetime_ref); + let scope = Scope::ObjectLifetimeDefault { + lifetime: self.map.defs.get(&lifetime_ref.id).cloned(), + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(&mt.ty)); + } _ => { intravisit::walk_ty(self, ty) } @@ -372,20 +438,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(lifetime_ref); } - fn visit_path_parameters(&mut self, _: Span, params: &'tcx hir::PathParameters) { - match *params { - hir::AngleBracketedParameters(ref data) => { - if data.lifetimes.iter().all(|l| l.is_elided()) { - self.resolve_elided_lifetimes(&data.lifetimes); - } else { - for l in &data.lifetimes { self.visit_lifetime(l); } - } - for ty in &data.types { self.visit_ty(ty); } - for b in &data.bindings { self.visit_assoc_type_binding(b); } - } - hir::ParenthesizedParameters(ref data) => { - self.visit_fn_like_elision(&data.inputs, data.output.as_ref()); - } + fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) { + for (i, segment) in path.segments.iter().enumerate() { + let depth = path.segments.len() - i - 1; + self.visit_segment_parameters(path.def, depth, &segment.parameters); } } @@ -466,7 +522,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { for lifetime in &trait_ref.bound_lifetimes { this.visit_lifetime_def(lifetime); } - intravisit::walk_path(this, &trait_ref.trait_ref.path) + this.visit_trait_ref(&trait_ref.trait_ref) }) } else { self.visit_trait_ref(&trait_ref.trait_ref) @@ -585,7 +641,8 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { loop { match *scope { Scope::Body { s, .. } | - Scope::Elision { s, .. } => { scope = s; } + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { scope = s; } Scope::Root => { return; } @@ -606,6 +663,103 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { } } +fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map) + -> NodeMap> { + let mut map = NodeMap(); + for item in hir_map.krate().items.values() { + match item.node { + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | + hir::ItemEnum(_, ref generics) | + hir::ItemTy(_, ref generics) | + hir::ItemTrait(_, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(hir_map, generics); + + // Debugging aid. + if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") { + let object_lifetime_default_reprs: String = + result.iter().map(|set| { + match *set { + Set1::Empty => "BaseDefault".to_string(), + Set1::One(Region::Static) => "'static".to_string(), + Set1::One(Region::EarlyBound(i, _)) => { + generics.lifetimes[i as usize].lifetime.name.to_string() + } + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".to_string(), + } + }).collect::>().join(","); + sess.span_err(item.span, &object_lifetime_default_reprs); + } + + map.insert(item.id, result); + } + _ => {} + } + } + map +} + +/// Scan the bounds and where-clauses on parameters to extract bounds +/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` +/// for each type parameter. +fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics) + -> Vec { + fn add_bounds(set: &mut Set1, bounds: &[hir::TyParamBound]) { + for bound in bounds { + if let hir::RegionTyParamBound(ref lifetime) = *bound { + set.insert(lifetime.name); + } + } + } + + generics.ty_params.iter().map(|param| { + let mut set = Set1::Empty; + + add_bounds(&mut set, ¶m.bounds); + + let param_def_id = hir_map.local_def_id(param.id); + for predicate in &generics.where_clause.predicates { + // Look for `type: ...` where clauses. + let data = match *predicate { + hir::WherePredicate::BoundPredicate(ref data) => data, + _ => continue + }; + + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_lifetimes.is_empty() { + continue; + } + + let def = match data.bounded_ty.node { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def, + _ => continue + }; + + if def == Def::TyParam(param_def_id) { + add_bounds(&mut set, &data.bounds); + } + } + + match set { + Set1::Empty => Set1::Empty, + Set1::One(name) => { + if name == keywords::StaticLifetime.name() { + Set1::One(Region::Static) + } else { + generics.lifetimes.iter().enumerate().find(|&(_, def)| { + def.lifetime.name == name + }).map_or(Set1::Many, |(i, def)| { + Set1::One(Region::EarlyBound(i as u32, def.lifetime.id)) + }) + } + } + Set1::Many => Set1::Many + } + }).collect() +} + impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // FIXME(#37666) this works around a limitation in the region inferencer fn hack(&mut self, f: F) where @@ -619,6 +773,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; let labels_in_fn = replace(&mut self.labels_in_fn, vec![]); + let xcrate_object_lifetime_defaults = + replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap()); let mut this = LifetimeContext { sess: sess, hir_map: hir_map, @@ -626,11 +782,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, labels_in_fn: labels_in_fn, + xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); debug!("exiting scope {:?}", this.scope); self.labels_in_fn = this.labels_in_fn; + self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -727,7 +885,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - Scope::Elision { s, .. } => { + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { scope = s; } } @@ -763,6 +922,109 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + fn visit_segment_parameters(&mut self, + def: Def, + depth: usize, + params: &'tcx hir::PathParameters) { + let data = match *params { + hir::ParenthesizedParameters(ref data) => { + self.visit_fn_like_elision(&data.inputs, data.output.as_ref()); + return; + } + hir::AngleBracketedParameters(ref data) => data + }; + + if data.lifetimes.iter().all(|l| l.is_elided()) { + self.resolve_elided_lifetimes(&data.lifetimes); + } else { + for l in &data.lifetimes { self.visit_lifetime(l); } + } + + // Figure out if this is a type/trait segment, + // which requires object lifetime defaults. + let parent_def_id = |this: &mut Self, def_id: DefId| { + let def_key = if def_id.is_local() { + this.hir_map.def_key(def_id) + } else { + this.sess.cstore.def_key(def_id) + }; + DefId { + krate: def_id.krate, + index: def_key.parent.expect("missing parent") + } + }; + let type_def_id = match def { + Def::AssociatedTy(def_id) if depth == 1 => { + Some(parent_def_id(self, def_id)) + } + Def::Variant(def_id) if depth == 0 => { + Some(parent_def_id(self, def_id)) + } + Def::Struct(def_id) | + Def::Union(def_id) | + Def::Enum(def_id) | + Def::TyAlias(def_id) | + Def::Trait(def_id) if depth == 0 => Some(def_id), + _ => None + }; + + let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { + let in_body = { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + Scope::Body { .. } => break true, + + Scope::Binder { s, .. } | + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + } + }; + + let map = &self.map; + let unsubst = if let Some(id) = self.hir_map.as_local_node_id(def_id) { + &map.object_lifetime_defaults[&id] + } else { + let cstore = &self.sess.cstore; + self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { + cstore.item_generics_object_lifetime_defaults(def_id) + }) + }; + unsubst.iter().map(|set| { + match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(r) => r.subst(&data.lifetimes, map), + Set1::Many => None + } + }).collect() + }); + + for (i, ty) in data.types.iter().enumerate() { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { + lifetime: lt, + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + } + + for b in &data.bindings { self.visit_assoc_type_binding(b); } + } + fn visit_fn_like_elision(&mut self, inputs: &'tcx [P], output: Option<&'tcx P>) { let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); @@ -962,7 +1224,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if let hir::TyBareFn(_) = ty.node { self.binder_depth += 1; } - intravisit::walk_ty(self, ty); + if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } else { + intravisit::walk_ty(self, ty); + } if let hir::TyBareFn(_) = ty.node { self.binder_depth -= 1; } @@ -1045,6 +1319,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } return; } + + Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } } }; @@ -1134,6 +1412,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &hir::Lifetime) { + let mut late_depth = 0; + let mut scope = self.scope; + let lifetime = loop { + match *scope { + Scope::Binder { s, .. } => { + late_depth += 1; + scope = s; + } + + Scope::Root | + Scope::Elision { .. } => break Region::Static, + + Scope::Body { .. } | + Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, + + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l + } + }; + self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + } + fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) { for i in 0..lifetimes.len() { let lifetime_i = &lifetimes[i]; @@ -1192,7 +1492,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *old_scope { Scope::Body { s, .. } | - Scope::Elision { s, .. } => { + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { old_scope = s; } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36fc5149b40d..6ea083b314fe 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -592,24 +592,6 @@ pub enum IntVarValue { UintType(ast::UintTy), } -/// Default region to use for the bound of objects that are -/// supplied as the value for this type parameter. This is derived -/// from `T:'a` annotations appearing in the type definition. If -/// this is `None`, then the default is inherited from the -/// surrounding context. See RFC #599 for details. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum ObjectLifetimeDefault<'tcx> { - /// Require an explicit annotation. Occurs when multiple - /// `T:'a` constraints are found. - Ambiguous, - - /// Use the base default, typically 'static, but in a fn body it is a fresh variable - BaseDefault, - - /// Use the given region as the default. - Specific(&'tcx Region), -} - #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef<'tcx> { pub name: Name, @@ -617,7 +599,6 @@ pub struct TypeParameterDef<'tcx> { pub index: u32, pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, - pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute /// on generic parameter `T`, asserts data behind the parameter diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0f0478bc8cdb..56f5dbc735de 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -726,36 +726,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { index: self.index, default: self.default.fold_with(folder), default_def_id: self.default_def_id, - object_lifetime_default: self.object_lifetime_default.fold_with(folder), pure_wrt_drop: self.pure_wrt_drop, } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.default.visit_with(visitor) || - self.object_lifetime_default.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::ObjectLifetimeDefault::Ambiguous => - ty::ObjectLifetimeDefault::Ambiguous, - - ty::ObjectLifetimeDefault::BaseDefault => - ty::ObjectLifetimeDefault::BaseDefault, - - ty::ObjectLifetimeDefault::Specific(r) => - ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor), - _ => false, - } + self.default.visit_with(visitor) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e90e1a94be95..0522ea90522c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -523,16 +523,6 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"), - ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"), - ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r), - } - } -} - impl fmt::Display for ty::Region { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if verbose() { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 03b2b0114f19..39581a469608 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -17,6 +17,7 @@ use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternC use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -115,6 +116,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).generics_own_param_counts(def.index) } + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index) + } + fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index bfc4257bda01..dd44ef202dc2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -614,6 +615,12 @@ impl<'a, 'tcx> CrateMetadata { (g.regions.len, g.types.len) } + pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex) + -> Vec { + self.entry(item_id).generics.unwrap().decode(self) + .object_lifetime_defaults.decode(self).collect() + } + pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { self.entry(id).ty.unwrap().decode((self, tcx)) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index c407c27b096e..028555d1df84 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -422,6 +422,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let g = tcx.item_generics(def_id); let regions = self.lazy_seq_ref(&g.regions); let types = self.lazy_seq_ref(&g.types); + let mut object_lifetime_defaults = LazySeq::empty(); + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) { + object_lifetime_defaults = self.lazy_seq_ref(o); + } + } self.lazy(&Generics { parent: g.parent, parent_regions: g.parent_regions, @@ -429,6 +435,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { regions: regions, types: types, has_self: g.has_self, + object_lifetime_defaults: object_lifetime_defaults, }) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 4f9f2d23f5d3..91375d42823f 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::mir; use rustc::ty::{self, Ty}; use rustc_back::PanicStrategy; @@ -258,6 +259,7 @@ pub struct Generics<'tcx> { pub regions: LazySeq>, pub types: LazySeq>, pub has_self: bool, + pub object_lifetime_defaults: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5c71947c2077..56de539cbfe9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -10,7 +10,7 @@ //! Conversion from AST representation of types to the ty.rs //! representation. The main routine here is `ast_ty_to_ty()`: each use -//! is parameterized by an instance of `AstConv` and a `RegionScope`. +//! is parameterized by an instance of `AstConv`. //! //! The parameterization of `ast_ty_to_ty()` is because it behaves //! somewhat differently during the collect and check phases, @@ -22,31 +22,6 @@ //! an error). In the check phase, when the FnCtxt is used as the //! `AstConv`, `get_item_type()` just looks up the item type in //! `tcx.types` (using `TyCtxt::item_type`). -//! -//! The `RegionScope` trait controls what happens when the user does -//! not specify a region in some location where a region is required -//! (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`). -//! See the `rscope` module for more details. -//! -//! Unlike the `AstConv` trait, the region scope can change as we descend -//! the type. This is to accommodate the fact that (a) fn types are binding -//! scopes and (b) the default region may change. To understand case (a), -//! consider something like: -//! -//! type foo = { x: &a.int, y: |&a.int| } -//! -//! The type of `x` is an error because there is no region `a` in scope. -//! In the type of `y`, however, region `a` is considered a bound region -//! as it does not already appear in scope. -//! -//! Case (b) says that if you have a type: -//! type foo<'a> = ...; -//! type bar = fn(&foo, &a.foo) -//! The fully expanded version of type bar is: -//! type bar = fn(&'foo &, &a.foo<'a>) -//! Note that the self region for the `foo` defaulted to `&` in the first -//! case but `&a` in the second. Basically, defaults that appear inside -//! an rptr (`&r.T`) use the region `r` that appears in the rptr. use rustc_const_eval::eval_length; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -61,8 +36,6 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; use rustc_back::slice; use require_c_abi_if_variadic; -use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope}; -use rscope::ExplicitRscope; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -110,7 +83,7 @@ pub trait AstConv<'gcx, 'tcx> { /// What lifetime should we use when a lifetime is omitted (and not elided)? fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) - -> &'tcx ty::Region; + -> Option<&'tcx ty::Region>; /// What type should we use when a type is omitted? fn ty_infer(&self, span: Span) -> Ty<'tcx>; @@ -220,7 +193,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // (*) -- not late-bound, won't change } - None => self.re_infer(lifetime.span, def) + None => { + self.re_infer(lifetime.span, def).expect("unelided lifetime in signature") + } }; debug!("ast_region_to_region(lifetime={:?}) yields {:?}", @@ -233,7 +208,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, /// returns an appropriate set of substitutions for this particular reference to `I`. pub fn ast_path_substs_for_ty(&self, - rscope: &RegionScope, span: Span, def_id: DefId, item_segment: &hir::PathSegment) @@ -258,8 +232,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } let (substs, assoc_bindings) = - self.create_substs_for_ast_path(rscope, - span, + self.create_substs_for_ast_path(span, def_id, &item_segment.parameters, None); @@ -275,7 +248,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// /// Note that the type listing given here is *exactly* what the user provided. fn create_substs_for_ast_path(&self, - rscope: &RegionScope, span: Span, def_id: DefId, parameters: &hir::PathParameters, @@ -357,11 +329,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // A provided type parameter. match *parameters { hir::AngleBracketedParameters(ref data) => { - self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i]) + self.ast_ty_to_ty(&data.types[i]) } hir::ParenthesizedParameters(ref data) => { assert_eq!(i, 0); - let (ty, assoc) = self.convert_parenthesized_parameters(substs, data); + let (ty, assoc) = self.convert_parenthesized_parameters(data); output_assoc_binding = Some(assoc); ty } @@ -406,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { data.bindings.iter().map(|b| { ConvertedBinding { item_name: b.name, - ty: self.ast_ty_to_ty(rscope, &b.ty), + ty: self.ast_ty_to_ty(&b.ty), span: b.span } }).collect() @@ -415,7 +387,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { vec![output_assoc_binding.unwrap_or_else(|| { // This is an error condition, but we should // get the associated type binding anyway. - self.convert_parenthesized_parameters(substs, data).1 + self.convert_parenthesized_parameters(data).1 })] } }; @@ -427,17 +399,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn convert_parenthesized_parameters(&self, - region_substs: &[Kind<'tcx>], data: &hir::ParenthesizedParameterData) -> (Ty<'tcx>, ConvertedBinding<'tcx>) { let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_arg_to_ty(&ExplicitRscope, None, region_substs, a_t) + self.ast_ty_to_ty(a_t) })); let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.ast_ty_to_ty(&ExplicitRscope, output_ty), output_ty.span) + (self.ast_ty_to_ty(output_ty), output_ty.span) } None => { (self.tcx().mk_nil(), data.span) @@ -460,14 +431,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. pub fn instantiate_mono_trait_ref(&self, - rscope: &RegionScope, trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_mono_trait_ref(rscope, - trait_ref.path.span, + self.ast_path_to_mono_trait_ref(trait_ref.path.span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap()) @@ -488,7 +457,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } pub fn instantiate_poly_trait_ref(&self, - rscope: &RegionScope, ast_trait_ref: &hir::PolyTraitRef, self_ty: Ty<'tcx>, poly_projections: &mut Vec>) @@ -498,16 +466,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def_id = self.trait_def_id(trait_ref); debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); - // The trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = &ShiftedRscope::new(rscope); let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(shifted_rscope, - trait_ref.path.span, + self.create_substs_for_ast_trait_ref(trait_ref.path.span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap()); @@ -528,7 +489,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn ast_path_to_mono_trait_ref(&self, - rscope: &RegionScope, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, @@ -536,8 +496,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> ty::TraitRef<'tcx> { let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(rscope, - span, + self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); @@ -546,7 +505,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn create_substs_for_ast_trait_ref(&self, - rscope: &RegionScope, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, @@ -590,8 +548,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - self.create_substs_for_ast_path(rscope, - span, + self.create_substs_for_ast_path(span, trait_def_id, &trait_segment.parameters, Some(self_ty)) @@ -700,7 +657,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn ast_path_to_ty(&self, - rscope: &RegionScope, span: Span, did: DefId, item_segment: &hir::PathSegment) @@ -714,8 +670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }; - let substs = self.ast_path_substs_for_ty(rscope, - span, + let substs = self.ast_path_substs_for_ty(span, did, item_segment); @@ -737,7 +692,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn conv_object_ty_poly_trait_ref(&self, - rscope: &RegionScope, span: Span, trait_bounds: &[hir::PolyTraitRef], lifetime: &hir::Lifetime) @@ -753,8 +707,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut projection_bounds = vec![]; let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); - let principal = self.instantiate_poly_trait_ref(rscope, - &trait_bounds[0], + let principal = self.instantiate_poly_trait_ref(&trait_bounds[0], dummy_self, &mut projection_bounds); @@ -839,15 +792,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.ast_region_to_region(lifetime, None) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - tcx.mk_region(match rscope.object_lifetime_default(span) { - Some(r) => r, - None => { - span_err!(self.tcx().sess, span, E0228, + if tcx.named_region_map.defs.contains_key(&lifetime.id) { + self.ast_region_to_region(lifetime, None) + } else { + self.re_infer(span, None).unwrap_or_else(|| { + span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); - ty::ReStatic - } - }) + tcx.mk_region(ty::ReStatic) + }) + } }) }; @@ -1059,7 +1013,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn qpath_to_ty(&self, - rscope: &RegionScope, span: Span, opt_self_ty: Option>, trait_def_id: DefId, @@ -1084,8 +1037,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("qpath_to_ty: self_type={:?}", self_ty); - let trait_ref = self.ast_path_to_mono_trait_ref(rscope, - span, + let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment); @@ -1095,38 +1047,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.projected_ty(span, trait_ref, item_segment.name) } - /// Convert a type supplied as value for a type argument from AST into our - /// our internal representation. This is the same as `ast_ty_to_ty` but that - /// it applies the object lifetime default. - /// - /// # Parameters - /// - /// * `this`, `rscope`: the surrounding context - /// * `def`: the type parameter being instantiated (if available) - /// * `region_substs`: a partial substitution consisting of - /// only the region type parameters being supplied to this type. - /// * `ast_ty`: the ast representation of the type being supplied - fn ast_ty_arg_to_ty(&self, - rscope: &RegionScope, - def: Option<&ty::TypeParameterDef<'tcx>>, - region_substs: &[Kind<'tcx>], - ast_ty: &hir::Ty) - -> Ty<'tcx> - { - let tcx = self.tcx(); - - if let Some(def) = def { - let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); - let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); - self.ast_ty_to_ty(rscope1, ast_ty) - } else { - self.ast_ty_to_ty(rscope, ast_ty) - } - } - // Check a type Path and convert it to a Ty. pub fn def_to_ty(&self, - rscope: &RegionScope, opt_self_ty: Option>, path: &hir::Path, permit_variants: bool) @@ -1141,15 +1063,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, span, did, path.segments.last().unwrap()) + self.ast_path_to_ty(span, did, path.segments.last().unwrap()) } Def::Variant(did) if permit_variants => { // Convert "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, - span, + self.ast_path_to_ty(span, tcx.parent_def_id(did).unwrap(), path.segments.last().unwrap()) } @@ -1207,8 +1128,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::AssociatedTy(def_id) => { tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]); let trait_did = tcx.parent_def_id(def_id).unwrap(); - self.qpath_to_ty(rscope, - span, + self.qpath_to_ty(span, opt_self_ty, trait_did, &path.segments[path.segments.len()-2], @@ -1228,7 +1148,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Parses the programmer's textual representation of a type into our /// internal notion of a type. - pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { + pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", ast_ty.id, ast_ty); @@ -1241,29 +1161,25 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let result_ty = match ast_ty.node { hir::TySlice(ref ty) => { - tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) + tcx.mk_slice(self.ast_ty_to_ty(&ty)) } hir::TyPtr(ref mt) => { tcx.mk_ptr(ty::TypeAndMut { - ty: self.ast_ty_to_ty(rscope, &mt.ty), + ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) } hir::TyRptr(ref region, ref mt) => { let r = self.ast_region_to_region(region, None); debug!("TyRef r={:?}", r); - let rscope1 = - &ObjectLifetimeDefaultRscope::new( - rscope, - ty::ObjectLifetimeDefault::Specific(r)); - let t = self.ast_ty_to_ty(rscope1, &mt.ty); + let t = self.ast_ty_to_ty(&mt.ty); tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) } hir::TyNever => { tcx.types.never }, hir::TyTup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t))) + tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); @@ -1309,7 +1225,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.mk_fn_ptr(bare_fn_ty) } hir::TyTraitObject(ref bounds, ref lifetime) => { - self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime) + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; @@ -1381,13 +1297,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.ast_ty_to_ty(rscope, qself) + self.ast_ty_to_ty(qself) }); - self.def_to_ty(rscope, opt_self_ty, path, false) + self.def_to_ty(opt_self_ty, path, false) } hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => { debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); - let ty = self.ast_ty_to_ty(rscope, qself); + let ty = self.ast_ty_to_ty(qself); let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node { path.def @@ -1398,7 +1314,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::TyArray(ref ty, length) => { if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") { - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) + tcx.mk_array(self.ast_ty_to_ty(&ty), length) } else { self.tcx().types.err } @@ -1426,7 +1342,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } pub fn ty_of_arg(&self, - rscope: &RegionScope, ty: &hir::Ty, expected_ty: Option>) -> Ty<'tcx> @@ -1434,7 +1349,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { match ty.node { hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), hir::TyInfer => self.ty_infer(ty.span), - _ => self.ast_ty_to_ty(rscope, ty), + _ => self.ast_ty_to_ty(ty), } } @@ -1446,10 +1361,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_fn"); let input_tys: Vec = - decl.inputs.iter().map(|a| self.ty_of_arg(&ExplicitRscope, a, None)).collect(); + decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect(); let output_ty = match decl.output { - hir::Return(ref output) => self.ast_ty_to_ty(&ExplicitRscope, output), + hir::Return(ref output) => self.ast_ty_to_ty(output), hir::DefaultReturn(..) => self.tcx().mk_nil(), }; @@ -1486,7 +1401,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { None } }); - self.ty_of_arg(&ExplicitRscope, a, expected_arg_ty) + self.ty_of_arg(a, expected_arg_ty) }); let expected_ret_ty = expected_sig.as_ref().map(|e| e.output()); @@ -1502,7 +1417,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { expected_ret_ty.unwrap(), _ if is_infer => self.ty_infer(decl.output.span()), hir::Return(ref output) => - self.ast_ty_to_ty(&ExplicitRscope, &output), + self.ast_ty_to_ty(&output), hir::DefaultReturn(..) => bug!(), }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4d1b2cec32e5..c2f32c2b52bb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,6 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; -use rscope::RegionScope; use session::{Session, CompileResult}; use CrateCtxt; use TypeAndSubsts; @@ -1411,12 +1410,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { } fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) - -> &'tcx ty::Region { + -> Option<&'tcx ty::Region> { let v = match def { Some(def) => infer::EarlyBoundRegion(span, def.name), None => infer::MiscVariable(span) }; - self.next_region_var(v) + Some(self.next_region_var(v)) } fn ty_infer(&self, span: Span) -> Ty<'tcx> { @@ -1459,23 +1458,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - // RFC #599 specifies that object lifetime defaults take - // precedence over other defaults. But within a fn body we - // don't have a *default* region, rather we use inference to - // find the *correct* region, which is strictly more general - // (and anyway, within a fn body the right region may not even - // be something the user can write explicitly, since it might - // be some expression). - *self.next_region_var(infer::MiscVariable(span)) - } -} - /// Controls whether the arguments are tupled. This is used for the call /// operator. /// @@ -1832,7 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, self, ast_t); + let t = AstConv::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); t } @@ -3976,7 +3958,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match *qpath { hir::QPath::Resolved(ref maybe_qself, ref path) => { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, true); + let ty = AstConv::def_to_ty(self, opt_self_ty, path, true); (path.def, ty) } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -4411,7 +4393,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(lifetime) = lifetimes.get(i) { AstConv::ast_region_to_region(self, lifetime, Some(def)) } else { - self.re_infer(span, Some(def)) + self.re_infer(span, Some(def)).unwrap() } }, |def, substs| { let mut i = def.index as usize; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 90e2f821b10b..6f0825a25f94 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -68,10 +68,9 @@ use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; -use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; -use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeMap, FxHashMap}; use CrateCtxt; use rustc_const_math::ConstInt; @@ -373,8 +372,8 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } impl<'a,'tcx> ItemCtxt<'a,'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> { - AstConv::ast_ty_to_ty(self, rs, ast_ty) + fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { + AstConv::ast_ty_to_ty(self, ast_ty) } } @@ -437,9 +436,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { None } - fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) - -> &'tcx ty::Region { - span_bug!(span, "unelided lifetime in signature"); + fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>) + -> Option<&'tcx ty::Region> { + None } fn ty_infer(&self, span: Span) -> Ty<'tcx> { @@ -631,7 +630,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, field: &hir::StructField, ty_f: &'tcx ty::FieldDef) { - let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty); + let tt = ccx.icx(struct_predicates).to_ty(&field.ty); ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt); let def_id = ccx.tcx.hir.local_def_id(field.id); @@ -757,7 +756,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = AstConv::instantiate_mono_trait_ref(&ccx.icx(&()), - &ExplicitRscope, ast_trait_ref, tcx.mk_self_type()); @@ -779,12 +777,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { debug!("convert: impl_bounds={:?}", ty_predicates); - let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty); + let selfty = ccx.icx(&ty_predicates).to_ty(&selfty); tcx.item_types.borrow_mut().insert(def_id, selfty); let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, ast_trait_ref, selfty) }); @@ -850,8 +847,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { hir::TraitItemKind::Const(ref ty, _) => { let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id); generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&trait_predicates) - .to_ty(&ExplicitRscope, &ty); + let ty = ccx.icx(&trait_predicates).to_ty(&ty); tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, TraitContainer(trait_def_id), trait_item.id, ty); @@ -862,7 +858,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { generics_of_def_id(ccx, type_def_id); let typ = opt_ty.as_ref().map({ - |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) + |ty| ccx.icx(&trait_predicates).to_ty(&ty) }); convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ); @@ -887,8 +883,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { hir::ImplItemKind::Const(ref ty, _) => { let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id); generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&impl_predicates) - .to_ty(&ExplicitRscope, &ty); + let ty = ccx.icx(&impl_predicates).to_ty(&ty); tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, ImplContainer(impl_def_id), impl_item.id, ty); @@ -903,7 +898,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { "associated types are not allowed in inherent impls"); } - let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty); + let typ = ccx.icx(&impl_predicates).to_ty(ty); convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ)); } @@ -1410,7 +1405,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: tcx.hir.local_def_id(param_id), default_def_id: tcx.hir.local_def_id(parent), default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, pure_wrt_drop: false, }; tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); @@ -1463,7 +1457,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let type_start = own_start + regions.len() as u32; let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { let i = type_start + i as u32; - get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults) + get_or_create_type_parameter_def(ccx, i, p, allow_defaults) }); let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1478,24 +1472,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: def_id, default_def_id: parent_def_id.unwrap(), default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, pure_wrt_drop: false, })); }); } - // Debugging aid. - if tcx.has_attr(def_id, "rustc_object_lifetime_default") { - let object_lifetime_default_reprs: String = - types.iter().map(|t| { - match t.object_lifetime_default { - ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), - d => format!("{:?}", d), - } - }).collect::>().join(","); - tcx.sess.span_err(tcx.hir.span(node_id), &object_lifetime_default_reprs); - } - tcx.alloc_generics(ty::Generics { parent: parent_def_id, parent_regions: parent_regions, @@ -1526,7 +1507,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ExplicitRscope, &t) + ccx.icx(&()).to_ty(&t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl); @@ -1534,7 +1515,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.mk_fn_def(def_id, substs, tofd) } ItemTy(ref t, ref generics) => { - ccx.icx(generics).to_ty(&ExplicitRscope, &t) + ccx.icx(generics).to_ty(&t) } ItemEnum(ref ei, ref generics) => { let def = convert_enum_def(ccx, item, ei); @@ -1575,7 +1556,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn_decl, generics, abi) } ForeignItemStatic(ref t, _) => { - ccx.icx(&()).to_ty(&ExplicitRscope, t) + ccx.icx(&()).to_ty(t) } } } @@ -1771,7 +1752,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, match predicate { &hir::WherePredicate::BoundPredicate(ref bound_pred) => { let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)), - &ExplicitRscope, &bound_pred.bounded_ty); for bound in bound_pred.bounds.iter() { @@ -1782,7 +1762,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let trait_ref = AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), - &ExplicitRscope, poly_trait_ref, ty, &mut projections); @@ -1827,7 +1806,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - ast_generics: &hir::Generics, index: u32, param: &hir::TyParam, allow_defaults: bool) @@ -1840,11 +1818,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } let default = - param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def)); - - let object_lifetime_default = - compute_object_lifetime_default(ccx, param.id, - ¶m.bounds, &ast_generics.where_clause); + param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def)); let parent = tcx.hir.get_parent(param.id); @@ -1865,7 +1839,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, def_id: ccx.tcx.hir.local_def_id(param.id), default_def_id: ccx.tcx.hir.local_def_id(parent), default: default, - object_lifetime_default: object_lifetime_default, pure_wrt_drop: param.pure_wrt_drop, }; @@ -1880,75 +1853,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, def } -/// Scan the bounds and where-clauses on a parameter to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`. -/// This runs as part of computing the minimal type scheme, so we -/// intentionally avoid just asking astconv to convert all the where -/// clauses into a `ty::Predicate`. This is because that could induce -/// artificial cycles. -fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - param_id: ast::NodeId, - param_bounds: &[hir::TyParamBound], - where_clause: &hir::WhereClause) - -> ty::ObjectLifetimeDefault<'tcx> -{ - let inline_bounds = from_bounds(ccx, param_bounds); - let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); - let all_bounds: FxHashSet<_> = inline_bounds.into_iter() - .chain(where_bounds) - .collect(); - return if all_bounds.len() > 1 { - ty::ObjectLifetimeDefault::Ambiguous - } else if all_bounds.len() == 0 { - ty::ObjectLifetimeDefault::BaseDefault - } else { - ty::ObjectLifetimeDefault::Specific( - all_bounds.into_iter().next().unwrap()) - }; - - fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - bounds: &[hir::TyParamBound]) - -> Vec<&'tcx ty::Region> - { - bounds.iter() - .filter_map(|bound| { - match *bound { - hir::TraitTyParamBound(..) => - None, - hir::RegionTyParamBound(ref lifetime) => - Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime, None)), - } - }) - .collect() - } - - fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - param_id: ast::NodeId, - predicates: &[hir::WherePredicate]) - -> Vec<&'tcx ty::Region> - { - predicates.iter() - .flat_map(|predicate| { - match *predicate { - hir::WherePredicate::BoundPredicate(ref data) => { - if data.bound_lifetimes.is_empty() && - is_param(ccx.tcx, &data.bounded_ty, param_id) - { - from_bounds(ccx, &data.bounds).into_iter() - } else { - Vec::new().into_iter() - } - } - hir::WherePredicate::RegionPredicate(..) | - hir::WherePredicate::EqPredicate(..) => { - Vec::new().into_iter() - } - } - }) - .collect() - } -} - pub enum SizedByDefault { Yes, No, } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or @@ -1978,8 +1882,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, let mut projection_bounds = vec![]; let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { - astconv.instantiate_poly_trait_ref(&ExplicitRscope, - bound, + astconv.instantiate_poly_trait_ref(bound, param_ty, &mut projection_bounds) }).collect(); @@ -2017,8 +1920,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, match *bound { hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => { let mut projections = Vec::new(); - let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope, - tr, + let pred = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections); projections.into_iter() diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 90ce77cc5f4b..4ed116b88f6d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -127,7 +127,6 @@ pub mod diagnostics; pub mod check; pub mod check_unused; -mod rscope; mod astconv; pub mod collect; mod constrained_type_params; diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs deleted file mode 100644 index d982c91e388d..000000000000 --- a/src/librustc_typeck/rscope.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2012 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. - -use rustc::ty; - -use syntax_pos::Span; - -/// Defines strategies for handling regions that are omitted. For -/// example, if one writes the type `&Foo`, then the lifetime of -/// this reference has been omitted. When converting this -/// type, the generic functions in astconv will invoke `anon_region` -/// on the provided region-scope to decide how to translate this -/// omitted region. -/// -/// It is not always legal to omit regions, therefore `anon_region` -/// can return `Err(())` to indicate that this is not a scope in which -/// regions can legally be omitted. -pub trait RegionScope { - /// If an object omits any explicit lifetime bound, and none can - /// be derived from the object traits, what should we use? If - /// `None` is returned, an explicit annotation is required. - fn object_lifetime_default(&self, span: Span) -> Option; - - /// The "base" default is the initial default for a scope. This is - /// 'static except for in fn bodies, where it is a fresh inference - /// variable. You shouldn't call this except for as part of - /// computing `object_lifetime_default` (in particular, in legacy - /// modes, it may not be relevant). - fn base_object_lifetime_default(&self, span: Span) -> ty::Region; -} - -// A scope in which all regions must be explicitly named. This is used -// for types that appear in structs and so on. -#[derive(Copy, Clone)] -pub struct ExplicitRscope; - -impl RegionScope for ExplicitRscope { - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -/// A scope which overrides the default object lifetime but has no other effect. -pub struct ObjectLifetimeDefaultRscope<'r> { - base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault<'r>, -} - -impl<'r> ObjectLifetimeDefaultRscope<'r> { - pub fn new(base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault<'r>) - -> ObjectLifetimeDefaultRscope<'r> - { - ObjectLifetimeDefaultRscope { - base_scope: base_scope, - default: default, - } - } -} - -impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { - fn object_lifetime_default(&self, span: Span) -> Option { - match self.default { - ty::ObjectLifetimeDefault::Ambiguous => - None, - - ty::ObjectLifetimeDefault::BaseDefault => - // NB: This behavior changed in Rust 1.3. - Some(self.base_object_lifetime_default(span)), - - ty::ObjectLifetimeDefault::Specific(r) => - Some(*r), - } - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - self.base_scope.base_object_lifetime_default(span) - } -} - -/// A scope which simply shifts the Debruijn index of other scopes -/// to account for binding levels. -pub struct ShiftedRscope<'r> { - base_scope: &'r (RegionScope+'r) -} - -impl<'r> ShiftedRscope<'r> { - pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> { - ShiftedRscope { base_scope: base_scope } - } -} - -impl<'r> RegionScope for ShiftedRscope<'r> { - fn object_lifetime_default(&self, span: Span) -> Option { - self.base_scope.object_lifetime_default(span) - .map(|r| ty::fold::shift_region(r, 1)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) - } -} diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs index 910d933d46f0..6aaf89209713 100644 --- a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs +++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs @@ -15,6 +15,8 @@ #![allow(dead_code)] +use std::fmt::Display; + trait Test { fn foo(&self) { } } @@ -23,6 +25,11 @@ struct Ref<'a,T:'a+?Sized> { r: &'a T } +struct Ref2<'a,'b,T:'a+'b+?Sized> { + a: &'a T, + b: &'b T +} + struct SomeStruct<'a> { t: Ref<'a,Test>, u: Ref<'a,Test+'a>, @@ -44,6 +51,17 @@ fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) { ss.u = t; } +fn e<'a>(_: Ref<'a, Display+'static>) {} +fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {} + fn main() { + // Inside a function body, we can just infer all + // lifetimes, to allow Ref<'tmp, Display+'static> + // and Ref2<'tmp, 'tmp, Display+'static>. + let x = &0 as &(Display+'static); + let r: Ref = Ref { r: x }; + let r2: Ref2 = Ref2 { a: x, b: x }; + e(r); + g(r2); } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs index d9e0b22fbfa4..cbff0d4dbaa3 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs @@ -15,6 +15,8 @@ #![allow(dead_code)] +use std::fmt::Display; + trait Test { fn foo(&self) { } } @@ -40,6 +42,10 @@ fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) { ss.u = t; } +fn e<'a>(_: &'a (Display+'static)) {} fn main() { + // Inside a function body, we can just infer both + // lifetimes, to allow &'tmp (Display+'static). + e(&0 as &Display); } From 9a0af1638a2e91f6979c10e4d4b37159ed5bf951 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 25 Jan 2017 18:39:21 +0200 Subject: [PATCH 055/104] rustc: remove unused `bounds` field from `RegionParameterDef`. --- src/librustc/ty/mod.rs | 11 +++++------ src/librustc/ty/structural_impls.rs | 18 +----------------- src/librustc/util/ppaux.rs | 7 +++---- src/librustc_metadata/schema.rs | 2 +- src/librustc_typeck/collect.rs | 3 --- src/librustdoc/clean/mod.rs | 9 ++------- 6 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6ea083b314fe..cc813d0bf831 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -606,12 +606,11 @@ pub struct TypeParameterDef<'tcx> { pub pure_wrt_drop: bool, } -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct RegionParameterDef<'tcx> { +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub struct RegionParameterDef { pub name: Name, pub def_id: DefId, pub index: u32, - pub bounds: Vec<&'tcx ty::Region>, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute /// on generic parameter `'a`, asserts data of lifetime `'a` @@ -619,7 +618,7 @@ pub struct RegionParameterDef<'tcx> { pub pure_wrt_drop: bool, } -impl<'tcx> RegionParameterDef<'tcx> { +impl RegionParameterDef { pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { ty::EarlyBoundRegion { index: self.index, @@ -640,7 +639,7 @@ pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, pub parent_types: u32, - pub regions: Vec>, + pub regions: Vec, pub types: Vec>, pub has_self: bool, } @@ -658,7 +657,7 @@ impl<'tcx> Generics<'tcx> { self.parent_count() + self.own_count() } - pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> { + pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef { &self.regions[param.index as usize - self.has_self as usize] } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 56f5dbc735de..06ba1b2a1faf 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -353,7 +353,7 @@ macro_rules! CopyImpls { } } -CopyImpls! { (), hir::Unsafety, abi::Abi } +CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef } impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) { @@ -735,22 +735,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::RegionParameterDef { - name: self.name, - def_id: self.def_id, - index: self.index, - bounds: self.bounds.fold_with(folder), - pure_wrt_drop: self.pure_wrt_drop, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.bounds.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::Generics { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0522ea90522c..74e27f84fddc 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -336,13 +336,12 @@ impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { } } -impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> { +impl fmt::Debug for ty::RegionParameterDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionParameterDef({}, {:?}, {}, {:?})", + write!(f, "RegionParameterDef({}, {:?}, {})", self.name, self.def_id, - self.index, - self.bounds) + self.index) } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 91375d42823f..d9c639f2bc57 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -256,7 +256,7 @@ pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, pub parent_types: u32, - pub regions: LazySeq>, + pub regions: LazySeq, pub types: LazySeq>, pub has_self: bool, pub object_lifetime_defaults: LazySeq, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6f0825a25f94..bbd0c8058151 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1446,9 +1446,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, name: l.lifetime.name, index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), - bounds: l.bounds.iter().map(|l| { - AstConv::ast_region_to_region(&ccx.icx(&()), l, None) - }).collect(), pure_wrt_drop: l.pure_wrt_drop, } }).collect::>(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f1ced233dde7..7591475c5d3f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -794,7 +794,7 @@ impl Clean for hir::LifetimeDef { } } -impl<'tcx> Clean for ty::RegionParameterDef<'tcx> { +impl Clean for ty::RegionParameterDef { fn clean(&self, _: &DocContext) -> Lifetime { Lifetime(self.name.to_string()) } @@ -970,11 +970,6 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, Some(tp.clean(cx)) } }).collect::>(); - let stripped_lifetimes = gens.regions.iter().map(|rp| { - let mut srp = rp.clone(); - srp.bounds = Vec::new(); - srp.clean(cx) - }).collect::>(); let mut where_predicates = preds.predicates.to_vec().clean(cx); @@ -1017,7 +1012,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, Generics { type_params: simplify::ty_params(stripped_typarams), - lifetimes: stripped_lifetimes, + lifetimes: gens.regions.clean(cx), where_predicates: simplify::where_clauses(cx, where_predicates), } } From c0e474d9a6d11518e602b7e20ccf2bf36725f0ad Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 27 Jan 2017 19:03:59 +0200 Subject: [PATCH 056/104] test: add missing lifetime in recently added test. --- src/test/compile-fail/where-equality-constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/where-equality-constraints.rs b/src/test/compile-fail/where-equality-constraints.rs index 5b2fe2901c4c..e449a736c753 100644 --- a/src/test/compile-fail/where-equality-constraints.rs +++ b/src/test/compile-fail/where-equality-constraints.rs @@ -10,7 +10,7 @@ fn f() where u8 = u16 {} //~^ ERROR equality constraints are not yet supported in where clauses -fn g() where for<'a> &(u8,) == u16, {} +fn g() where for<'a> &'static (u8,) == u16, {} //~^ ERROR equality constraints are not yet supported in where clauses fn main() {} From 15411fb0fafc65719ea8ce0f1a479a5df19a090a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sat, 28 Jan 2017 17:00:43 +0300 Subject: [PATCH 057/104] Fix typos in libsyntax/tokenstream.rs --- src/libsyntax/tokenstream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index ab5dc8181e05..0ca0538c03a3 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -17,7 +17,7 @@ //! expansion). //! //! ## Ownership -//! TokenStreams are persistant data structures construced as ropes with reference +//! TokenStreams are persistent data structures constructed as ropes with reference //! counted-children. In general, this means that calling an operation on a TokenStream //! (such as `slice`) produces an entirely new TokenStream from the borrowed reference to //! the original. This essentially coerces TokenStreams into 'views' of their subparts, From b081872d5bf19a063fbf7f2f315560a59592308d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 28 Dec 2016 12:16:19 -0800 Subject: [PATCH 058/104] Implement `PartialEq<&[A]>` for `VecDeque`. Fixes https://github.com/rust-lang/rust/issues/38625. --- src/libcollections/vec_deque.rs | 110 +++++++++++++++++++--------- src/libcollectionstest/vec_deque.rs | 19 +++++ 2 files changed, 93 insertions(+), 36 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 5b1bc3a3ae4f..5e1adb3d808c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -469,9 +469,9 @@ impl VecDeque { /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); + /// assert_eq!(buf, [3, 4, 5]); /// buf.swap(0, 2); - /// assert_eq!(buf[0], 5); - /// assert_eq!(buf[2], 3); + /// assert_eq!(buf, [5, 4, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(&mut self, i: usize, j: usize) { @@ -649,9 +649,9 @@ impl VecDeque { /// buf.push_back(5); /// buf.push_back(10); /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); /// buf.truncate(1); - /// assert_eq!(buf.len(), 1); - /// assert_eq!(Some(&5), buf.get(0)); + /// assert_eq!(buf, [5]); /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { @@ -826,8 +826,9 @@ impl VecDeque { /// use std::collections::VecDeque; /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// assert_eq!(vec![3].into_iter().collect::>(), v.drain(2..).collect()); - /// assert_eq!(vec![1, 2].into_iter().collect::>(), v); + /// let drained = v.drain(2..).collect::>(); + /// assert_eq!(drained, [3]); + /// assert_eq!(v, [1, 2]); /// /// // A full range clears all contents /// v.drain(..); @@ -1179,11 +1180,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.swap_remove_back(0), Some(1)); - /// assert_eq!(buf.len(), 2); - /// assert_eq!(buf[0], 3); - /// assert_eq!(buf[1], 2); + /// assert_eq!(buf, [3, 2]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn swap_remove_back(&mut self, index: usize) -> Option { @@ -1215,11 +1215,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.swap_remove_front(2), Some(3)); - /// assert_eq!(buf.len(), 2); - /// assert_eq!(buf[0], 2); - /// assert_eq!(buf[1], 1); + /// assert_eq!(buf, [2, 1]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn swap_remove_front(&mut self, index: usize) -> Option { @@ -1250,11 +1249,10 @@ impl VecDeque { /// vec_deque.push_back('a'); /// vec_deque.push_back('b'); /// vec_deque.push_back('c'); + /// assert_eq!(vec_deque, &['a', 'b', 'c']); /// /// vec_deque.insert(1, 'd'); - /// - /// let vec = vec_deque.into_iter().collect::>(); - /// assert_eq!(vec, ['a', 'd', 'b', 'c']); + /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { @@ -1478,9 +1476,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.remove(1), Some(2)); - /// assert_eq!(buf.get(1), Some(&3)); + /// assert_eq!(buf, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, index: usize) -> Option { @@ -1659,9 +1658,8 @@ impl VecDeque { /// /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); /// let buf2 = buf.split_off(1); - /// // buf = [1], buf2 = [2, 3] - /// assert_eq!(buf.len(), 1); - /// assert_eq!(buf2.len(), 2); + /// assert_eq!(buf, [1]); + /// assert_eq!(buf2, [2, 3]); /// ``` #[inline] #[stable(feature = "split_off", since = "1.4.0")] @@ -1718,11 +1716,11 @@ impl VecDeque { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// let mut buf2: VecDeque<_> = vec![4, 5, 6].into_iter().collect(); + /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect(); + /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect(); /// buf.append(&mut buf2); - /// assert_eq!(buf.len(), 6); - /// assert_eq!(buf2.len(), 0); + /// assert_eq!(buf, [1, 2, 3, 4]); + /// assert_eq!(buf2, []); /// ``` #[inline] #[stable(feature = "append", since = "1.4.0")] @@ -1745,9 +1743,7 @@ impl VecDeque { /// let mut buf = VecDeque::new(); /// buf.extend(1..5); /// buf.retain(|&x| x%2 == 0); - /// - /// let v: Vec<_> = buf.into_iter().collect(); - /// assert_eq!(&v[..], &[2, 4]); + /// assert_eq!(buf, [2, 4]); /// ``` #[stable(feature = "vec_deque_retain", since = "1.4.0")] pub fn retain(&mut self, mut f: F) @@ -1781,11 +1777,13 @@ impl VecDeque { /// buf.push_back(5); /// buf.push_back(10); /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); + /// /// buf.resize(2, 0); - /// buf.resize(6, 20); - /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(&buf) { - /// assert_eq!(a, b); - /// } + /// assert_eq!(buf, [5, 10]); + /// + /// buf.resize(5, 20); + /// assert_eq!(buf, [5, 10, 20, 20, 20]); /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] pub fn resize(&mut self, new_len: usize, value: T) { @@ -2162,6 +2160,46 @@ impl PartialEq for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for VecDeque {} +macro_rules! __impl_slice_eq1 { + ($Lhs: ty, $Rhs: ty) => { + __impl_slice_eq1! { $Lhs, $Rhs, Sized } + }; + ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.16.0")] + impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + fn eq(&self, other: &$Rhs) -> bool { + if self.len() != other.len() { + return false; + } + let (sa, sb) = self.as_slices(); + let (oa, ob) = other[..].split_at(sa.len()); + sa == oa && sb == ob + } + } + } +} + +__impl_slice_eq1! { VecDeque, Vec } +__impl_slice_eq1! { VecDeque, &'b [B] } +__impl_slice_eq1! { VecDeque, &'b mut [B] } + +macro_rules! array_impls { + ($($N: expr)+) => { + $( + __impl_slice_eq1! { VecDeque, [B; $N] } + __impl_slice_eq1! { VecDeque, &'b [B; $N] } + __impl_slice_eq1! { VecDeque, &'b mut [B; $N] } + )+ + } +} + +array_impls! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for VecDeque { fn partial_cmp(&self, other: &VecDeque) -> Option { @@ -2434,7 +2472,7 @@ mod tests { let final_len = usable_cap / 2; for len in 0..final_len { - let expected = if back { + let expected: VecDeque<_> = if back { (0..len).collect() } else { (0..len).rev().collect() @@ -2483,7 +2521,7 @@ mod tests { // len is the length *after* insertion for len in 1..cap { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..cap { for to_insert in 0..len { tester.tail = tail_pos; @@ -2516,7 +2554,7 @@ mod tests { // len is the length *after* removal for len in 0..cap - 1 { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..cap { for to_remove in 0..len + 1 { tester.tail = tail_pos; @@ -2591,7 +2629,7 @@ mod tests { for len in 0..cap + 1 { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..max_cap + 1 { tester.tail = tail_pos; tester.head = tail_pos; @@ -2624,9 +2662,9 @@ mod tests { // index to split at for at in 0..len + 1 { // 0, 1, 2, .., at - 1 (may be empty) - let expected_self = (0..).take(at).collect(); + let expected_self = (0..).take(at).collect::>(); // at, at + 1, .., len - 1 (may be empty) - let expected_other = (at..).take(len - at).collect(); + let expected_other = (at..).take(len - at).collect::>(); for tail_pos in 0..cap { tester.tail = tail_pos; diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index cdf022e4f02f..bb60f888f8be 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -603,6 +603,25 @@ fn test_eq() { assert!(e == VecDeque::new()); } +#[test] +fn test_partial_eq_array() { + let d = VecDeque::::new(); + assert!(d == []); + + let mut d = VecDeque::new(); + d.push_front('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + d.push_back('b'); + assert!(d == ['a', 'b']); +} + #[test] fn test_hash() { let mut x = VecDeque::new(); From ab21314c3fbf093c92123abee62101d15846c1e2 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 28 Jan 2017 21:52:31 +0200 Subject: [PATCH 059/104] Disable backtrace tests on i686-pc-windows-gnu since it's broken by FPO --- src/test/run-pass/backtrace-debuginfo.rs | 1 + src/test/run-pass/backtrace.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 626eccfc9ec8..015ba75d432a 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -37,6 +37,7 @@ macro_rules! dump_and_die { target_os = "ios", target_os = "android", all(target_os = "linux", target_arch = "arm"), + all(target_os = "windows", target_pointer_width = "32"), target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 834ce984e663..e892f5e7728b 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -104,6 +104,10 @@ fn runtest(me: &str) { } fn main() { + if cfg!(windows) && cfg!(target_env = "gnu") && cfg!(target_pointer_width = "32") { + return + } + let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "fail" { foo(); From 95227a4dc16b90994e6b39271a75363ff0f05bb3 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 28 Jan 2017 14:37:50 -0700 Subject: [PATCH 060/104] Remove ToPrimitive trait. It is no longer used. --- src/librustc/lib.rs | 1 - src/librustc/util/num.rs | 98 ---------------------------------------- 2 files changed, 99 deletions(-) delete mode 100644 src/librustc/util/num.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 0ff9626ae11a..855f4a8197e3 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -109,7 +109,6 @@ pub mod util { pub mod common; pub mod ppaux; pub mod nodemap; - pub mod num; pub mod fs; } diff --git a/src/librustc/util/num.rs b/src/librustc/util/num.rs deleted file mode 100644 index da04976a96a3..000000000000 --- a/src/librustc/util/num.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2015 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. - -pub trait ToPrimitive { - fn to_i8(&self) -> Option; - fn to_i16(&self) -> Option; - fn to_i32(&self) -> Option; - fn to_i64(&self) -> Option; - fn to_u8(&self) -> Option; - fn to_u16(&self) -> Option; - fn to_u32(&self) -> Option; - fn to_u64(&self) -> Option; -} - -impl ToPrimitive for i64 { - fn to_i8(&self) -> Option { - if *self < i8::min_value() as i64 || *self > i8::max_value() as i64 { - None - } else { - Some(*self as i8) - } - } - fn to_i16(&self) -> Option { - if *self < i16::min_value() as i64 || *self > i16::max_value() as i64 { - None - } else { - Some(*self as i16) - } - } - fn to_i32(&self) -> Option { - if *self < i32::min_value() as i64 || *self > i32::max_value() as i64 { - None - } else { - Some(*self as i32) - } - } - fn to_i64(&self) -> Option { - Some(*self) - } - fn to_u8(&self) -> Option { - if *self < 0 || *self > u8::max_value() as i64 { - None - } else { - Some(*self as u8) - } - } - fn to_u16(&self) -> Option { - if *self < 0 || *self > u16::max_value() as i64 { - None - } else { - Some(*self as u16) - } - } - fn to_u32(&self) -> Option { - if *self < 0 || *self > u32::max_value() as i64 { - None - } else { - Some(*self as u32) - } - } - fn to_u64(&self) -> Option { - if *self < 0 {None} else {Some(*self as u64)} - } -} - -impl ToPrimitive for u64 { - fn to_i8(&self) -> Option { - if *self > i8::max_value() as u64 {None} else {Some(*self as i8)} - } - fn to_i16(&self) -> Option { - if *self > i16::max_value() as u64 {None} else {Some(*self as i16)} - } - fn to_i32(&self) -> Option { - if *self > i32::max_value() as u64 {None} else {Some(*self as i32)} - } - fn to_i64(&self) -> Option { - if *self > i64::max_value() as u64 {None} else {Some(*self as i64)} - } - fn to_u8(&self) -> Option { - if *self > u8::max_value() as u64 {None} else {Some(*self as u8)} - } - fn to_u16(&self) -> Option { - if *self > u16::max_value() as u64 {None} else {Some(*self as u16)} - } - fn to_u32(&self) -> Option { - if *self > u32::max_value() as u64 {None} else {Some(*self as u32)} - } - fn to_u64(&self) -> Option { - Some(*self) - } -} From 339bdc158f37e3c9073c29d59de06899c93a1c90 Mon Sep 17 00:00:00 2001 From: Denis Andrejew Date: Sat, 28 Jan 2017 22:16:16 +0000 Subject: [PATCH 061/104] Fix typo in liballoc/lib.rs --- src/liballoc/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c67106cf57aa..0c01eabd593f 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -47,7 +47,7 @@ //! that the contained type `T` is shareable. Additionally, `Arc` is itself //! sendable while `Rc` is not. //! -//! This types allows for shared access to the contained data, and is often +//! This type allows for shared access to the contained data, and is often //! paired with synchronization primitives such as mutexes to allow mutation of //! shared resources. //! From b54f593cffc40e9d07650b36629e60c48da6b11d Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Sat, 14 Jan 2017 15:25:33 -0500 Subject: [PATCH 062/104] Add clearer error message using `&str + &str` This is the first part of #39018. One of the common things for new users coming from more dynamic languages like JavaScript, Python or Ruby is to use `+` to concatenate strings. However, this doesn't work that way in Rust unless the first type is a `String`. This commit adds a check for this use case and outputs a new error as well as a suggestion to guide the user towards the desired behavior. It also adds a new test case to test the output of the error. --- src/librustc_typeck/check/op.rs | 57 ++++++++++++++++++++++++-- src/test/parse-fail/issue-39018.stderr | 28 +++++++++++++ src/test/ui/span/issue-39018.rs | 23 +++++++++++ src/test/ui/span/issue-39018.stderr | 28 +++++++++++++ 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/test/parse-fail/issue-39018.stderr create mode 100644 src/test/ui/span/issue-39018.rs create mode 100644 src/test/ui/span/issue-39018.stderr diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 925d28247b61..0dcdab07e6fc 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -13,7 +13,9 @@ use super::FnCtxt; use hir::def_id::DefId; use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; +use rustc::ty::TypeVariants::{TyStr, TyRef}; use rustc::infer::type_variable::TypeVariableOrigin; +use errors; use syntax::ast; use syntax::symbol::Symbol; use rustc::hir; @@ -237,9 +239,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { - span_note!(&mut err, lhs_expr.span, - "an implementation of `{}` might be missing for `{}`", - missing_trait, lhs_ty); + if missing_trait == "std::ops::Add" && + self.check_str_addition(expr, lhs_expr, lhs_ty, + rhs_expr, rhs_ty_var, &mut err) { + // This has nothing here because it means we did string + // concatenation (e.g. "Hello " + "World!"). This means + // we don't want the span in the else clause to be emmitted + } else { + span_note!(&mut err, lhs_expr.span, + "an implementation of `{}` might be missing for `{}`", + missing_trait, lhs_ty); + } } err.emit(); } @@ -254,6 +264,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (rhs_ty_var, return_ty) } + fn check_str_addition(&self, + expr: &'gcx hir::Expr, + lhs_expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'gcx hir::Expr, + rhs_ty_var: Ty<'tcx>, + mut err: &mut errors::DiagnosticBuilder) -> bool { + // If this function returns false it means we use it to make sure we print + // out the an "implementation of span_note!" above where this function is + // called and if true we don't. + let mut is_string_addition = false; + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + if let TyRef(_, l_ty) = lhs_ty.sty { + if let TyRef(_, r_ty) = rhs_ty.sty { + if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { + span_note!(&mut err, lhs_expr.span, + "`+` can't be used to concatenate two `&str` strings"); + let codemap = self.tcx.sess.codemap(); + let suggestion = + match (codemap.span_to_snippet(lhs_expr.span), + codemap.span_to_snippet(rhs_expr.span)) { + (Ok(lstring), Ok(rstring)) => + format!("{}.to_owned() + {}", lstring, rstring), + _ => format!("") + }; + err.span_suggestion(expr.span, + &format!("to_owned() can be used to create an owned `String` \ + from a string reference. String concatenation \ + appends the string on the right to the string \ + on the left and may require reallocation. This \ + requires ownership of the string on the left."), suggestion); + is_string_addition = true; + } + + } + + } + + is_string_addition + } + pub fn check_user_unop(&self, op_str: &str, mname: &str, diff --git a/src/test/parse-fail/issue-39018.stderr b/src/test/parse-fail/issue-39018.stderr new file mode 100644 index 000000000000..ee1a32c4c16c --- /dev/null +++ b/src/test/parse-fail/issue-39018.stderr @@ -0,0 +1,28 @@ +error[E0369]: binary operation `+` cannot be applied to type `&'static str` + --> src/test/ui/span/issue-39018.rs:2:13 + | +2 | let x = "Hello " + "World!"; + | ^^^^^^^^ + | +note: `+` can't be used to concatenate two `&str` strings + --> src/test/ui/span/issue-39018.rs:2:13 + | +2 | let x = "Hello " + "World!"; + | ^^^^^^^^ +help: to_owned() can be used to create an owned `String` from a string reference. This allows concatenation since the `String` is owned. + | let x = "Hello ".to_owned() + "World!"; + +error[E0369]: binary operation `+` cannot be applied to type `World` + --> src/test/ui/span/issue-39018.rs:7:13 + | +7 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + | +note: an implementation of `std::ops::Add` might be missing for `World` + --> src/test/ui/span/issue-39018.rs:7:13 + | +7 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs new file mode 100644 index 000000000000..1cbc5ff1d2ab --- /dev/null +++ b/src/test/ui/span/issue-39018.rs @@ -0,0 +1,23 @@ +// 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. + +pub fn main() { + let x = "Hello " + "World!"; + + // Make sure that the span outputs a warning + // for not having an implementation for std::ops::Add + // that won't output for the above string concatenation + let y = World::Hello + World::Goodbye; +} + +enum World { + Hello, + Goodbye, +} diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr new file mode 100644 index 000000000000..a8cc74056ca2 --- /dev/null +++ b/src/test/ui/span/issue-39018.stderr @@ -0,0 +1,28 @@ +error[E0369]: binary operation `+` cannot be applied to type `&'static str` + --> $DIR/issue-39018.rs:12:13 + | +12 | let x = "Hello " + "World!"; + | ^^^^^^^^ + | +note: `+` can't be used to concatenate two `&str` strings + --> $DIR/issue-39018.rs:12:13 + | +12 | let x = "Hello " + "World!"; + | ^^^^^^^^ +help: to_owned() can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. + | let x = "Hello ".to_owned() + "World!"; + +error[E0369]: binary operation `+` cannot be applied to type `World` + --> $DIR/issue-39018.rs:17:13 + | +17 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + | +note: an implementation of `std::ops::Add` might be missing for `World` + --> $DIR/issue-39018.rs:17:13 + | +17 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 18b96cf286e99ba61ff52fb916463466b2a63a67 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 9 Jan 2017 00:21:35 +0300 Subject: [PATCH 063/104] Privatize constructors of tuple structs with private fields --- src/librustc_metadata/encoder.rs | 8 +++- src/librustc_resolve/build_reduced_graph.rs | 22 ++++++---- .../auxiliary/privacy-struct-ctor.rs | 21 ++++++++++ src/test/compile-fail/privacy-struct-ctor.rs | 42 +++++++++++++++++++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/privacy-struct-ctor.rs create mode 100644 src/test/compile-fail/privacy-struct-ctor.rs diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 028555d1df84..b9c2f0622b69 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -396,10 +396,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let struct_id = tcx.hir.as_local_node_id(adt_def_id).unwrap(); let struct_vis = &tcx.hir.expect_item(struct_id).vis; + let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx); + for field in &variant.fields { + if ctor_vis.is_at_least(field.vis, tcx) { + ctor_vis = field.vis; + } + } Entry { kind: EntryKind::Struct(self.lazy(&data)), - visibility: self.lazy(&ty::Visibility::from_hir(struct_vis, struct_id, tcx)), + visibility: self.lazy(&ctor_vis), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), children: LazySeq::empty(), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f74af416cde0..f144be7996ae 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -327,21 +327,25 @@ impl<'a> Resolver<'a> { let def = Def::Struct(self.definitions.local_def_id(item.id)); self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + // Record field names for error reporting. + let mut ctor_vis = vis; + let field_names = struct_def.fields().iter().filter_map(|field| { + let field_vis = self.resolve_visibility(&field.vis); + if ctor_vis.is_at_least(field_vis, &*self) { + ctor_vis = field_vis; + } + field.ident.map(|ident| ident.name) + }).collect(); + let item_def_id = self.definitions.local_def_id(item.id); + self.insert_field_names(item_def_id, field_names); + // If this is a tuple or unit struct, define a name // in the value namespace as well. if !struct_def.is_struct() { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); - self.define(parent, ident, ValueNS, (ctor_def, vis, sp, expansion)); + self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); } - - // Record field names for error reporting. - let field_names = struct_def.fields().iter().filter_map(|field| { - self.resolve_visibility(&field.vis); - field.ident.map(|ident| ident.name) - }).collect(); - let item_def_id = self.definitions.local_def_id(item.id); - self.insert_field_names(item_def_id, field_names); } ItemKind::Union(ref vdata, _) => { diff --git a/src/test/compile-fail/auxiliary/privacy-struct-ctor.rs b/src/test/compile-fail/auxiliary/privacy-struct-ctor.rs new file mode 100644 index 000000000000..f190f5dd0534 --- /dev/null +++ b/src/test/compile-fail/auxiliary/privacy-struct-ctor.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(pub_restricted)] + +pub mod m { + pub struct S(u8); + + pub mod n { + pub(m) struct Z(pub(m::n) u8); + } +} + +pub use m::S; diff --git a/src/test/compile-fail/privacy-struct-ctor.rs b/src/test/compile-fail/privacy-struct-ctor.rs new file mode 100644 index 000000000000..13a04f490141 --- /dev/null +++ b/src/test/compile-fail/privacy-struct-ctor.rs @@ -0,0 +1,42 @@ +// 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:privacy-struct-ctor.rs + +#![feature(pub_restricted)] + +extern crate privacy_struct_ctor as xcrate; + +mod m { + pub struct S(u8); + + pub mod n { + pub(m) struct Z(pub(m::n) u8); + } + + use m::n::Z; // OK, only the type is imported + + fn f() { + n::Z; //~ ERROR tuple struct `Z` is private + Z; //~ ERROR expected value, found struct `Z` + } +} + +use m::S; // OK, only the type is imported + +fn main() { + m::S; //~ ERROR tuple struct `S` is private + S; //~ ERROR expected value, found struct `S` + m::n::Z; //~ ERROR tuple struct `Z` is private + + xcrate::m::S; //~ ERROR tuple struct `S` is private + xcrate::S; //~ ERROR expected value, found struct `xcrate::S` + xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private +} From 962d88b5eeeb602b2a6c9a2f96f9476152279a42 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 9 Jan 2017 00:34:52 +0300 Subject: [PATCH 064/104] Fix the fallout --- src/librustc_privacy/diagnostics.rs | 2 +- src/libsyntax/symbol.rs | 19 ++-- .../explore-issue-38412.rs | 7 -- src/test/compile-fail/E0450.rs | 21 ---- src/test/compile-fail/E0451.rs | 5 - src/test/compile-fail/issue-38412.rs | 2 +- src/test/compile-fail/privacy5.rs | 99 +++++++++---------- 7 files changed, 59 insertions(+), 96 deletions(-) delete mode 100644 src/test/compile-fail/E0450.rs diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs index 66afe5835bf6..8506b1d75c5b 100644 --- a/src/librustc_privacy/diagnostics.rs +++ b/src/librustc_privacy/diagnostics.rs @@ -119,7 +119,7 @@ E0450: r##" A tuple constructor was invoked while some of its fields are private. Erroneous code example: -```compile_fail,E0450 +```compile_fail mod Bar { pub struct Foo(isize); } diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c2123ea5a079..c278171aa109 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -140,7 +140,7 @@ macro_rules! declare_keywords {( $( #[allow(non_upper_case_globals)] pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(ast::Name($index)) + ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) }; )* } @@ -282,25 +282,24 @@ impl Encodable for InternedString { #[cfg(test)] mod tests { use super::*; - use ast::Name; #[test] fn interner_tests() { let mut i: Interner = Interner::new(); // first one is zero: - assert_eq!(i.intern("dog"), Name(0)); + assert_eq!(i.intern("dog"), Symbol(0)); // re-use gets the same entry: - assert_eq!(i.intern ("dog"), Name(0)); + assert_eq!(i.intern ("dog"), Symbol(0)); // different string gets a different #: - assert_eq!(i.intern("cat"), Name(1)); - assert_eq!(i.intern("cat"), Name(1)); + assert_eq!(i.intern("cat"), Symbol(1)); + assert_eq!(i.intern("cat"), Symbol(1)); // dog is still at zero - assert_eq!(i.intern("dog"), Name(0)); + assert_eq!(i.intern("dog"), Symbol(0)); // gensym gets 3 - assert_eq!(i.gensym("zebra"), Name(2)); + assert_eq!(i.gensym("zebra"), Symbol(2)); // gensym of same string gets new number : - assert_eq!(i.gensym("zebra"), Name(3)); + assert_eq!(i.gensym("zebra"), Symbol(3)); // gensym of *existing* string gets new number: - assert_eq!(i.gensym("dog"), Name(4)); + assert_eq!(i.gensym("dog"), Symbol(4)); } } diff --git a/src/test/compile-fail-fulldeps/explore-issue-38412.rs b/src/test/compile-fail-fulldeps/explore-issue-38412.rs index aab92575321e..b9839edea2dc 100644 --- a/src/test/compile-fail-fulldeps/explore-issue-38412.rs +++ b/src/test/compile-fail-fulldeps/explore-issue-38412.rs @@ -25,21 +25,14 @@ use pub_and_stability::{Record, Trait, Tuple}; fn main() { // Okay let Record { .. } = Record::new(); - // Okay (for now; see RFC Issue #902) - let Tuple(..) = Tuple::new(); // Okay let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new(); - // Okay (for now; see RFC Issue #902) - let Tuple(_, _, ..) = Tuple::new(); // analogous to above let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = Record::new(); //~^^ ERROR use of unstable library feature 'unstable_undeclared' - let Tuple(_, _, _, ..) = Tuple::new(); // analogous to previous - //~^ ERROR use of unstable library feature 'unstable_undeclared' - let r = Record::new(); let t = Tuple::new(); diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/E0450.rs deleted file mode 100644 index 200b58a32934..000000000000 --- a/src/test/compile-fail/E0450.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -mod Bar { - pub struct Foo( bool, pub i32, f32, bool); - //~^ NOTE private field declared here - //~| NOTE private field declared here - //~| NOTE private field declared here -} - -fn main() { - let f = Bar::Foo(false,1,0.1, true); //~ ERROR E0450 - //~^ NOTE cannot construct with a private field -} diff --git a/src/test/compile-fail/E0451.rs b/src/test/compile-fail/E0451.rs index f7b106d160da..ace96c9983e6 100644 --- a/src/test/compile-fail/E0451.rs +++ b/src/test/compile-fail/E0451.rs @@ -25,11 +25,6 @@ fn pat_match(foo: Bar::Foo) { //~^ NOTE field `b` is private } -fn pat_match_tuple(foo: Bar::FooTuple) { - let Bar::FooTuple(a,b) = foo; //~ ERROR E0451 - //~^ NOTE field `1` is private -} - fn main() { let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451 //~^ NOTE field `b` is private diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 00305eb2bc04..b4feadbacf74 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -10,7 +10,7 @@ fn main() { let Box(a) = loop { }; - //~^ ERROR field `0` of struct `std::boxed::Box` is private + //~^ ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/privacy5.rs b/src/test/compile-fail/privacy5.rs index 9d6ae187cd38..599c1f871604 100644 --- a/src/test/compile-fail/privacy5.rs +++ b/src/test/compile-fail/privacy5.rs @@ -58,30 +58,31 @@ mod a { } fn this_crate() { - let a = a::A(()); //~ ERROR: cannot invoke tuple struct constructor - let b = a::B(2); //~ ERROR: cannot invoke tuple struct constructor - let c = a::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor + let a = a::A(()); //~ ERROR tuple struct `A` is private + let b = a::B(2); //~ ERROR tuple struct `B` is private + let c = a::C(2, 3); //~ ERROR tuple struct `C` is private let d = a::D(4); - let a::A(()) = a; //~ ERROR: field `0` of struct `a::A` is private - let a::A(_) = a; - match a { a::A(()) => {} } //~ ERROR: field `0` of struct `a::A` is private - match a { a::A(_) => {} } + let a::A(()) = a; //~ ERROR tuple struct `A` is private + let a::A(_) = a; //~ ERROR tuple struct `A` is private + match a { a::A(()) => {} } //~ ERROR tuple struct `A` is private + match a { a::A(_) => {} } //~ ERROR tuple struct `A` is private - let a::B(_) = b; - let a::B(_b) = b; //~ ERROR: field `0` of struct `a::B` is private - match b { a::B(_) => {} } - match b { a::B(_b) => {} } //~ ERROR: field `0` of struct `a::B` is private - match b { a::B(1) => {} a::B(_) => {} } //~ ERROR: field `0` of struct `a::B` is private + let a::B(_) = b; //~ ERROR tuple struct `B` is private + let a::B(_b) = b; //~ ERROR tuple struct `B` is private + match b { a::B(_) => {} } //~ ERROR tuple struct `B` is private + match b { a::B(_b) => {} } //~ ERROR tuple struct `B` is private + match b { a::B(1) => {} a::B(_) => {} } //~ ERROR tuple struct `B` is private + //~^ ERROR tuple struct `B` is private - let a::C(_, _) = c; - let a::C(_a, _) = c; - let a::C(_, _b) = c; //~ ERROR: field `1` of struct `a::C` is private - let a::C(_a, _b) = c; //~ ERROR: field `1` of struct `a::C` is private - match c { a::C(_, _) => {} } - match c { a::C(_a, _) => {} } - match c { a::C(_, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private - match c { a::C(_a, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private + let a::C(_, _) = c; //~ ERROR tuple struct `C` is private + let a::C(_a, _) = c; //~ ERROR tuple struct `C` is private + let a::C(_, _b) = c; //~ ERROR tuple struct `C` is private + let a::C(_a, _b) = c; //~ ERROR tuple struct `C` is private + match c { a::C(_, _) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_a, _) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_, _b) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private let a::D(_) = d; let a::D(_d) = d; @@ -89,42 +90,38 @@ fn this_crate() { match d { a::D(_d) => {} } match d { a::D(1) => {} a::D(_) => {} } - let a2 = a::A; //~ ERROR: cannot invoke tuple struct constructor - let b2 = a::B; //~ ERROR: cannot invoke tuple struct constructor - let c2 = a::C; //~ ERROR: cannot invoke tuple struct constructor + let a2 = a::A; //~ ERROR tuple struct `A` is private + let b2 = a::B; //~ ERROR tuple struct `B` is private + let c2 = a::C; //~ ERROR tuple struct `C` is private let d2 = a::D; } fn xcrate() { - let a = other::A(()); //~ ERROR: cannot invoke tuple struct constructor - let b = other::B(2); //~ ERROR: cannot invoke tuple struct constructor - let c = other::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor + let a = other::A(()); //~ ERROR tuple struct `A` is private + let b = other::B(2); //~ ERROR tuple struct `B` is private + let c = other::C(2, 3); //~ ERROR tuple struct `C` is private let d = other::D(4); - let other::A(()) = a; //~ ERROR: field `0` of struct `other::A` is private - let other::A(_) = a; - match a { other::A(()) => {} } - //~^ ERROR: field `0` of struct `other::A` is private - match a { other::A(_) => {} } + let other::A(()) = a; //~ ERROR tuple struct `A` is private + let other::A(_) = a; //~ ERROR tuple struct `A` is private + match a { other::A(()) => {} } //~ ERROR tuple struct `A` is private + match a { other::A(_) => {} } //~ ERROR tuple struct `A` is private - let other::B(_) = b; - let other::B(_b) = b; //~ ERROR: field `0` of struct `other::B` is private - match b { other::B(_) => {} } - match b { other::B(_b) => {} } - //~^ ERROR: field `0` of struct `other::B` is private - match b { other::B(1) => {} other::B(_) => {} } - //~^ ERROR: field `0` of struct `other::B` is private + let other::B(_) = b; //~ ERROR tuple struct `B` is private + let other::B(_b) = b; //~ ERROR tuple struct `B` is private + match b { other::B(_) => {} } //~ ERROR tuple struct `B` is private + match b { other::B(_b) => {} } //~ ERROR tuple struct `B` is private + match b { other::B(1) => {} other::B(_) => {} } //~ ERROR tuple struct `B` is private + //~^ ERROR tuple struct `B` is private - let other::C(_, _) = c; - let other::C(_a, _) = c; - let other::C(_, _b) = c; //~ ERROR: field `1` of struct `other::C` is private - let other::C(_a, _b) = c; //~ ERROR: field `1` of struct `other::C` is private - match c { other::C(_, _) => {} } - match c { other::C(_a, _) => {} } - match c { other::C(_, _b) => {} } - //~^ ERROR: field `1` of struct `other::C` is private - match c { other::C(_a, _b) => {} } - //~^ ERROR: field `1` of struct `other::C` is private + let other::C(_, _) = c; //~ ERROR tuple struct `C` is private + let other::C(_a, _) = c; //~ ERROR tuple struct `C` is private + let other::C(_, _b) = c; //~ ERROR tuple struct `C` is private + let other::C(_a, _b) = c; //~ ERROR tuple struct `C` is private + match c { other::C(_, _) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_a, _) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_, _b) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private let other::D(_) = d; let other::D(_d) = d; @@ -132,9 +129,9 @@ fn xcrate() { match d { other::D(_d) => {} } match d { other::D(1) => {} other::D(_) => {} } - let a2 = other::A; //~ ERROR: cannot invoke tuple struct constructor - let b2 = other::B; //~ ERROR: cannot invoke tuple struct constructor - let c2 = other::C; //~ ERROR: cannot invoke tuple struct constructor + let a2 = other::A; //~ ERROR tuple struct `A` is private + let b2 = other::B; //~ ERROR tuple struct `B` is private + let c2 = other::C; //~ ERROR tuple struct `C` is private let d2 = other::D; } From 8b060e25ba80eb2866839335302b31359c18421a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 20 Jan 2017 18:53:49 +0300 Subject: [PATCH 065/104] Implement compatibility lint for legacy constructor visibilities --- src/librustc/lint/builtin.rs | 7 +++++ src/librustc_lint/lib.rs | 4 +++ src/librustc_resolve/build_reduced_graph.rs | 3 ++ src/librustc_resolve/lib.rs | 24 ++++++++++++++-- .../privacy/legacy-ctor-visibility.rs | 28 +++++++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/privacy/legacy-ctor-visibility.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b0db3b75029f..e1605959922c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -223,6 +223,12 @@ declare_lint! { "detects names that resolve to ambiguous glob imports with RFC 1560" } +declare_lint! { + pub LEGACY_CONSTRUCTOR_VISIBILITY, + Deny, + "detects use of struct constructors that would be invisible with new visibility rules" +} + declare_lint! { pub DEPRECATED, Warn, @@ -271,6 +277,7 @@ impl LintPass for HardwiredLints { EXTRA_REQUIREMENT_IN_IMPL, LEGACY_DIRECTORY_OWNERSHIP, LEGACY_IMPORTS, + LEGACY_CONSTRUCTOR_VISIBILITY, DEPRECATED ) } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 34bc57884ecb..18067cb86739 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -240,6 +240,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LEGACY_IMPORTS), reference: "issue #38260 ", }, + FutureIncompatibleInfo { + id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY), + reference: "issue #39207 ", + }, ]); // Register renamed and removed lints diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f144be7996ae..144ec8c680ee 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -345,6 +345,9 @@ impl<'a> Resolver<'a> { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); + if !ctor_vis.is_at_least(vis, &*self) { + self.legacy_ctor_visibilities.insert(def.def_id(), (ctor_def, ctor_vis)); + } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b5e2715ab4f0..4ade64ee1985 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,7 +45,7 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet}; +use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy}; @@ -1131,6 +1131,9 @@ pub struct Resolver<'a> { warned_proc_macros: FxHashSet, potentially_unused_imports: Vec<&'a ImportDirective<'a>>, + + // Auxiliary map used only for reporting `legacy_constructor_visibility` lint. + legacy_ctor_visibilities: DefIdMap<(Def, ty::Visibility)>, } pub struct ResolverArenas<'a> { @@ -1310,6 +1313,7 @@ impl<'a> Resolver<'a> { proc_macro_enabled: features.proc_macro, warned_proc_macros: FxHashSet(), potentially_unused_imports: Vec::new(), + legacy_ctor_visibilities: DefIdMap(), } } @@ -2235,7 +2239,23 @@ impl<'a> Resolver<'a> { if is_expected(resolution.base_def) || resolution.base_def == Def::Err { resolution } else { - report_errors(self, Some(resolution.base_def)) + // Add a temporary hack to smooth the transition to new struct ctor + // visibility rules. See #38932 for more details. + let mut res = None; + if let Def::Struct(def_id) = resolution.base_def { + if let Some((ctor_def, ctor_vis)) + = self.legacy_ctor_visibilities.get(&def_id).cloned() { + if is_expected(ctor_def) && self.is_accessible(ctor_vis) { + let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; + self.session.add_lint(lint, id, span, + "private struct constructors are not usable through \ + reexports in outer modules".to_string()); + res = Some(PathResolution::new(ctor_def)); + } + } + } + + res.unwrap_or_else(|| report_errors(self, Some(resolution.base_def))) } } Some(resolution) if source.defer_to_typeck() => { diff --git a/src/test/compile-fail/privacy/legacy-ctor-visibility.rs b/src/test/compile-fail/privacy/legacy-ctor-visibility.rs new file mode 100644 index 000000000000..fb65af230ace --- /dev/null +++ b/src/test/compile-fail/privacy/legacy-ctor-visibility.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(unused)] + +use m::S; + +mod m { + pub struct S(u8); + + mod n { + use S; + fn f() { + S(10); + //~^ ERROR private struct constructors are not usable through reexports in outer modules + //~| WARN this was previously accepted + } + } +} + +fn main() {} From c9788fdd5b8d136b1c32e0130f8e2fdbc8f8073b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 20 Jan 2017 20:11:42 +0300 Subject: [PATCH 066/104] Remove no longer necessary ctor checks in rustc_privacy --- src/librustc_privacy/diagnostics.rs | 43 +++-------------------------- src/librustc_privacy/lib.rs | 29 +------------------ src/librustdoc/html/markdown.rs | 2 -- 3 files changed, 5 insertions(+), 69 deletions(-) diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs index 8506b1d75c5b..49f2ccb7c57f 100644 --- a/src/librustc_privacy/diagnostics.rs +++ b/src/librustc_privacy/diagnostics.rs @@ -115,45 +115,6 @@ pub enum Foo { ``` "##, -E0450: r##" -A tuple constructor was invoked while some of its fields are private. Erroneous -code example: - -```compile_fail -mod Bar { - pub struct Foo(isize); -} - -let f = Bar::Foo(0); // error: cannot invoke tuple struct constructor with - // private fields -``` - -To solve this issue, please ensure that all of the fields of the tuple struct -are public. Alternatively, provide a `new()` method to the tuple struct to -construct it from a given inner value. Example: - -``` -mod Bar { - pub struct Foo(pub isize); // we set its field to public -} - -let f = Bar::Foo(0); // ok! - -// or: -mod bar { - pub struct Foo(isize); - - impl Foo { - pub fn new(x: isize) -> Foo { - Foo(x) - } - } -} - -let f = bar::Foo::new(1); -``` -"##, - E0451: r##" A struct constructor with private fields was invoked. Erroneous code example: @@ -204,3 +165,7 @@ let f = Bar::Foo::new(); // ok! "##, } + +register_diagnostics! { +// E0450, moved into resolve +} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 7357d6f38b65..9dc94745cff7 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -27,7 +27,7 @@ extern crate syntax_pos; use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; -use rustc::hir::def::{self, Def, CtorKind}; +use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; @@ -478,33 +478,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { } } } - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { - if let Def::StructCtor(_, CtorKind::Fn) = path.def { - let adt_def = self.tcx.expect_variant_def(path.def); - let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| { - !field.vis.is_accessible_from(self.curitem, self.tcx) - }).map(|(i, _)| i).collect::>(); - - if !private_indexes.is_empty() { - let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450, - "cannot invoke tuple struct constructor \ - with private fields"); - error.span_label(expr.span, - &format!("cannot construct with a private field")); - - if let Some(node_id) = self.tcx.hir.as_local_node_id(adt_def.did) { - let node = self.tcx.hir.find(node_id); - if let Some(hir::map::NodeStructCtor(vdata)) = node { - for i in private_indexes { - error.span_label(vdata.fields()[i].span, - &format!("private field declared here")); - } - } - } - error.emit(); - } - } - } _ => {} } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8cc3b60a1840..442a2f407421 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -660,8 +660,6 @@ mod tests { t("no_run", false, true, false, true, false, false, Vec::new()); t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); - t("E0450", false, false, false, true, false, false, - vec!["E0450".to_owned()]); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); From d38a8ad488047b8acdeed44bb7c67dc776324624 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 29 Jan 2017 02:56:52 +0300 Subject: [PATCH 067/104] Improve diagnostics for inaccessible constructors --- src/librustc_resolve/build_reduced_graph.rs | 16 +++-- src/librustc_resolve/lib.rs | 18 +++-- src/test/compile-fail/issue-38412.rs | 1 + .../resolve}/auxiliary/privacy-struct-ctor.rs | 0 .../resolve}/privacy-struct-ctor.rs | 12 +++- .../ui/resolve/privacy-struct-ctor.stderr | 68 +++++++++++++++++++ 6 files changed, 103 insertions(+), 12 deletions(-) rename src/test/{compile-fail => ui/resolve}/auxiliary/privacy-struct-ctor.rs (100%) rename src/test/{compile-fail => ui/resolve}/privacy-struct-ctor.rs (71%) create mode 100644 src/test/ui/resolve/privacy-struct-ctor.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 144ec8c680ee..eb6c7f4bed5d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -345,9 +345,7 @@ impl<'a> Resolver<'a> { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); - if !ctor_vis.is_at_least(vis, &*self) { - self.legacy_ctor_visibilities.insert(def.def_id(), (ctor_def, ctor_vis)); - } + self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis)); } } @@ -441,10 +439,18 @@ impl<'a> Resolver<'a> { Def::Variant(..) | Def::TyAlias(..) => { self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } - Def::Fn(..) | Def::Static(..) | Def::Const(..) | - Def::VariantCtor(..) | Def::StructCtor(..) => { + Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } + Def::StructCtor(..) => { + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + + if let Some(struct_def_id) = + self.session.cstore.def_key(def_id).parent + .map(|index| DefId { krate: def_id.krate, index: index }) { + self.struct_constructors.insert(struct_def_id, (def, vis)); + } + } Def::Trait(..) => { let module_kind = ModuleKind::Def(def, ident.name); let module = self.new_module(parent, module_kind, parent.normal_ancestor_id); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4ade64ee1985..676ff98e602d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1132,8 +1132,9 @@ pub struct Resolver<'a> { potentially_unused_imports: Vec<&'a ImportDirective<'a>>, - // Auxiliary map used only for reporting `legacy_constructor_visibility` lint. - legacy_ctor_visibilities: DefIdMap<(Def, ty::Visibility)>, + // This table maps struct IDs into struct constructor IDs, + // it's not used during normal resolution, only for better error reporting. + struct_constructors: DefIdMap<(Def, ty::Visibility)>, } pub struct ResolverArenas<'a> { @@ -1313,7 +1314,7 @@ impl<'a> Resolver<'a> { proc_macro_enabled: features.proc_macro, warned_proc_macros: FxHashSet(), potentially_unused_imports: Vec::new(), - legacy_ctor_visibilities: DefIdMap(), + struct_constructors: DefIdMap(), } } @@ -2209,6 +2210,15 @@ impl<'a> Resolver<'a> { _ => {} }, _ if ns == ValueNS && is_struct_like(def) => { + if let Def::Struct(def_id) = def { + if let Some((ctor_def, ctor_vis)) + = this.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_def) && !this.is_accessible(ctor_vis) { + err.span_label(span, &format!("constructor is not visible \ + here due to private fields")); + } + } + } err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?", path_str)); return err; @@ -2244,7 +2254,7 @@ impl<'a> Resolver<'a> { let mut res = None; if let Def::Struct(def_id) = resolution.base_def { if let Some((ctor_def, ctor_vis)) - = self.legacy_ctor_visibilities.get(&def_id).cloned() { + = self.struct_constructors.get(&def_id).cloned() { if is_expected(ctor_def) && self.is_accessible(ctor_vis) { let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; self.session.add_lint(lint, id, span, diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index b4feadbacf74..3b62aaf2ab8e 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -11,6 +11,7 @@ fn main() { let Box(a) = loop { }; //~^ ERROR expected tuple struct/variant, found struct `Box` + //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs similarity index 100% rename from src/test/compile-fail/auxiliary/privacy-struct-ctor.rs rename to src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs diff --git a/src/test/compile-fail/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs similarity index 71% rename from src/test/compile-fail/privacy-struct-ctor.rs rename to src/test/ui/resolve/privacy-struct-ctor.rs index 13a04f490141..3d0c76c740ad 100644 --- a/src/test/compile-fail/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -25,7 +25,9 @@ mod m { fn f() { n::Z; //~ ERROR tuple struct `Z` is private - Z; //~ ERROR expected value, found struct `Z` + Z; + //~^ ERROR expected value, found struct `Z` + //~| NOTE tuple struct constructors with private fields are invisible outside of their mod } } @@ -33,10 +35,14 @@ use m::S; // OK, only the type is imported fn main() { m::S; //~ ERROR tuple struct `S` is private - S; //~ ERROR expected value, found struct `S` + S; + //~^ ERROR expected value, found struct `S` + //~| NOTE constructor is not visible here due to private fields m::n::Z; //~ ERROR tuple struct `Z` is private xcrate::m::S; //~ ERROR tuple struct `S` is private - xcrate::S; //~ ERROR expected value, found struct `xcrate::S` + xcrate::S; + //~^ ERROR expected value, found struct `xcrate::S` + //~| NOTE constructor is not visible here due to private fields xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private } diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr new file mode 100644 index 000000000000..30fdbb02cc71 --- /dev/null +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -0,0 +1,68 @@ +error[E0423]: expected value, found struct `Z` + --> $DIR/privacy-struct-ctor.rs:28:9 + | +28 | Z; + | ^ + | | + | did you mean `Z { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::n::Z;` + +error[E0423]: expected value, found struct `S` + --> $DIR/privacy-struct-ctor.rs:38:5 + | +38 | S; + | ^ + | | + | did you mean `S { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::S;` + +error[E0423]: expected value, found struct `xcrate::S` + --> $DIR/privacy-struct-ctor.rs:44:5 + | +44 | xcrate::S; + | ^^^^^^^^^ + | | + | did you mean `xcrate::S { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::S;` + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:27:9 + | +27 | n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^ + +error: tuple struct `S` is private + --> $DIR/privacy-struct-ctor.rs:37:5 + | +37 | m::S; //~ ERROR tuple struct `S` is private + | ^^^^ + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:41:5 + | +41 | m::n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^^^^ + +error: tuple struct `S` is private + --> $DIR/privacy-struct-ctor.rs:43:5 + | +43 | xcrate::m::S; //~ ERROR tuple struct `S` is private + | ^^^^^^^^^^^^ + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:47:5 + | +47 | xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + From 7e73884941b64625417faa20135d84c68b07c18a Mon Sep 17 00:00:00 2001 From: Caleb Reach Date: Sat, 28 Jan 2017 23:01:22 -0500 Subject: [PATCH 068/104] Fix typo in librustc_trans/collector.rs --- src/librustc_trans/collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d30766dc5392..fa8bad5807aa 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -52,7 +52,7 @@ //! the LLVM artifact produced for A references the LLVM artifact produced //! for B. //! -//! - Translation items and the references between them for a directed graph, +//! - Translation items and the references between them form a directed graph, //! where the translation items are the nodes and references form the edges. //! Let's call this graph the "translation item graph". //! From 3f1d3948d6d434b34dd47f132c126a6cb6b8a4ab Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 28 Jan 2017 21:54:59 +0200 Subject: [PATCH 069/104] Fix backtraces on i686-pc-windows-gnu by disabling FPO This might have performance implications. But do note that MSVC disables FPO by default nowadays and it's use is limited in exception heavy languages like C++. Closes: #28218 --- src/librustc_back/target/i686_pc_windows_gnu.rs | 1 + src/test/run-pass/backtrace-debuginfo.rs | 1 - src/test/run-pass/backtrace.rs | 4 ---- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 0c2c5433e6c4..294772613920 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -14,6 +14,7 @@ pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); + base.eliminate_frame_pointer = false; // Required for backtraces // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 015ba75d432a..626eccfc9ec8 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -37,7 +37,6 @@ macro_rules! dump_and_die { target_os = "ios", target_os = "android", all(target_os = "linux", target_arch = "arm"), - all(target_os = "windows", target_pointer_width = "32"), target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index e892f5e7728b..834ce984e663 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -104,10 +104,6 @@ fn runtest(me: &str) { } fn main() { - if cfg!(windows) && cfg!(target_env = "gnu") && cfg!(target_pointer_width = "32") { - return - } - let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "fail" { foo(); From 7ed78fcbdf3648403ff9811e36c10b96bf49b93f Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 29 Jan 2017 06:07:45 +0100 Subject: [PATCH 070/104] Remove dead recursive partial eq impl Its nowhere used (if it had been used used, the rust stack would have overflown due to the recursion). Its presence was confusing for mrustc. --- src/librustc_data_structures/accumulate_vec.rs | 2 +- src/librustc_data_structures/array_vec.rs | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 78af655852d1..d4bd9e707fdc 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -25,7 +25,7 @@ use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use array_vec::{self, Array, ArrayVec}; -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(Hash, Debug)] pub enum AccumulateVec { Array(ArrayVec), Heap(Vec) diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index c0b5b7f51733..51e6e09ab500 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -52,14 +52,6 @@ impl Hash for ArrayVec } } -impl PartialEq for ArrayVec { - fn eq(&self, other: &Self) -> bool { - self == other - } -} - -impl Eq for ArrayVec {} - impl Clone for ArrayVec where A: Array, A::Element: Clone { From 23e8f70b460f03aa90b810394d3c6c84056a9f07 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 28 Jan 2017 21:25:11 -0800 Subject: [PATCH 071/104] travis: move IBM backwards in time Using Ubuntu's cross-toolchains for powerpc* and s390x meant they were depending on glibc symbols from Ubuntu 16.04. And if that host is ever updated to a new release, the toolchains would raise the bar too. This switches powerpc, powerpc64, and s390x to use crosstool-ng toolchains, configured approximately like RHEL6 with kernel 2.6.32 and glibc 2.12. This ABI level should also be compatible with Debian 7 (wheezy) and Ubuntu 12.04 (precise). For powerpc64le, the challenge was that only glibc-2.19 officially added support, but RHEL7 backported those changes to glibc-2.17. The backport patches are complex and numerous, so instead of trying to push those into crosstool-ng, this just uses glibc binaries directly from CentOS 7 and builds the toolchain manually. This is ported from rust-lang/rust-buildbot#149. r? @alexcrichton --- src/ci/docker/README.md | 55 ++ src/ci/docker/dist-powerpc-linux/Dockerfile | 66 ++- .../build-powerpc-toolchain.sh | 36 ++ ...PC-Remove-unnecessary-mnew-mnemonics.patch | 24 + .../powerpc-linux-gnu.config | 528 ++++++++++++++++++ src/ci/docker/dist-powerpc64-linux/Dockerfile | 75 ++- .../build-powerpc64-toolchain.sh | 36 ++ .../build-powerpc64le-toolchain.sh | 70 +++ ...PC-Remove-unnecessary-mnew-mnemonics.patch | 24 + ...Prevent-inlining-in-PPC64-initfini.s.patch | 26 + .../powerpc64-linux-gnu.config | 528 ++++++++++++++++++ .../docker/dist-s390x-linux-netbsd/Dockerfile | 80 ++- ...toolchain.sh => build-netbsd-toolchain.sh} | 0 .../build-s390x-toolchain.sh | 36 ++ ...prevent-AS-from-complaining-about-z9.patch | 63 +++ .../s390x-linux-gnu.config | 508 +++++++++++++++++ 16 files changed, 2115 insertions(+), 40 deletions(-) create mode 100755 src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh create mode 100644 src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch create mode 100644 src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config create mode 100755 src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh create mode 100755 src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh create mode 100644 src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch create mode 100644 src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch create mode 100644 src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config rename src/ci/docker/dist-s390x-linux-netbsd/{build-toolchain.sh => build-netbsd-toolchain.sh} (100%) mode change 100644 => 100755 create mode 100755 src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh create mode 100644 src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch create mode 100644 src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 9a0a4c8cb530..52f74ba90de6 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -143,3 +143,58 @@ For targets: `aarch64-unknown-linux-gnu` - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version - C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM + +## `powerpc-linux-gnu.config` + +For targets: `powerpc-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches +- Target options > Target Architecture = powerpc +- Target options > Emit assembly for CPU = power4 -- (+) +- Target options > Tune for CPU = power6 -- (+) +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) +- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) +- C compiler > C++ = ENABLE -- to cross compile LLVM + +(+) These CPU options match the configuration of the toolchains in RHEL6. + +## `powerpc64-linux-gnu.config` + +For targets: `powerpc64-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches +- Target options > Target Architecture = powerpc +- Target options > Bitness = 64-bit +- Target options > Emit assembly for CPU = power4 -- (+) +- Target options > Tune for CPU = power6 -- (+) +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > C++ = ENABLE -- to cross compile LLVM + +(+) These CPU options match the configuration of the toolchains in RHEL6. + +## `s390x-linux-gnu.config` + +For targets: `s390x-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /build/patches +- Target options > Target Architecture = s390 +- Target options > Bitness = 64-bit +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support +- C compiler > C++ = ENABLE -- to cross compile LLVM diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index ed4e9a35960f..640bacc54eb3 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -1,18 +1,29 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ + automake \ + bison \ + bzip2 \ ca-certificates \ - python2.7 \ - git \ cmake \ - sudo \ + curl \ + file \ + flex \ + g++ \ + gawk \ gdb \ - xz-utils \ - g++-powerpc-linux-gnu + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ @@ -23,6 +34,43 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY powerpc-linux-gnu.config build-powerpc-toolchain.sh /tmp/ +RUN ./build-powerpc-toolchain.sh + +USER root + +ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin + +ENV \ + CC_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-gcc \ + AR_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-ar \ + CXX_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-g++ + ENV HOSTS=powerpc-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended diff --git a/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh b/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh new file mode 100755 index 000000000000..90a4df0c1958 --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../powerpc-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch new file mode 100644 index 000000000000..744eb180cd1f --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch @@ -0,0 +1,24 @@ +From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Thu, 1 Nov 2012 18:00:06 -0500 +Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics. + +--- + sysdeps/powerpc/Makefile | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile +index 79dd6fa976d5..7442b6709ad1 100644 +--- a/sysdeps/powerpc/Makefile ++++ b/sysdeps/powerpc/Makefile +@@ -1,7 +1,3 @@ +-# We always want to use the new mnemonic syntax even if we are on a RS6000 +-# machine. +-+cflags += -mnew-mnemonics +- + ifeq ($(subdir),gmon) + sysdep_routines += ppc-mcount + endif +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config new file mode 100644 index 000000000000..26e2de863a0f --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -0,0 +1,528 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="powerpc" +CT_ARCH_SUPPORTS_BOTH_ENDIAN=y +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_ABI=y +CT_ARCH_SUPPORTS_WITH_CPU=y +CT_ARCH_SUPPORTS_WITH_TUNE=y +CT_ARCH_SUPPORTS_WITH_FLOAT=y +CT_ARCH_DEFAULT_BE=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_ABI="" +CT_ARCH_CPU="power4" +CT_ARCH_TUNE="power6" +CT_ARCH_BE=y +# CT_ARCH_LE is not set +CT_ARCH_32=y +# CT_ARCH_64 is not set +CT_ARCH_BITNESS=32 +# CT_ARCH_FLOAT_HW is not set +# CT_ARCH_FLOAT_SW is not set +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +CT_ARCH_powerpc=y +# CT_ARCH_s390 is not set +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ENDIAN="big" + +# +# Target optimisations +# +CT_ARCH_FLOAT_AUTO=y +CT_ARCH_FLOAT="auto" + +# +# powerpc other options +# +CT_ARCH_powerpc_ABI="" +CT_ARCH_powerpc_ABI_DEFAULT=y +# CT_ARCH_powerpc_ABI_SPE is not set + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 6c04048f4ddf..42842d2368ac 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -1,19 +1,29 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ + automake \ + bison \ + bzip2 \ ca-certificates \ - python2.7 \ - git \ cmake \ - sudo \ + curl \ + file \ + flex \ + g++ \ + gawk \ gdb \ - xz-utils \ - g++-powerpc64-linux-gnu \ - g++-powerpc64le-linux-gnu + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ @@ -24,10 +34,49 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY powerpc64-linux-gnu.config build-powerpc64-toolchain.sh /tmp/ +RUN ./build-powerpc64-toolchain.sh + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnueabihf/bin + ENV \ - AR_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-ar \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-g++ + AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ + CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh new file mode 100755 index 000000000000..d70947d2dd9d --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../powerpc64-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh new file mode 100755 index 000000000000..98fbe5045452 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -ex + +BINUTILS=2.25.1 +GCC=5.3.0 +TARGET=powerpc64le-linux-gnu +SYSROOT=/usr/local/$TARGET/sysroot + +# First, download the CentOS7 glibc.ppc64le and relevant header files. +# (upstream ppc64le support wasn't added until 2.19, which el7 backported.) +mkdir -p $SYSROOT +pushd $SYSROOT + +centos_base=http://mirror.centos.org/altarch/7.3.1611/os/ppc64le/Packages +glibc_v=2.17-157.el7 +kernel_v=3.10.0-514.el7 +for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do + curl $centos_base/$package.ppc64le.rpm | \ + rpm2cpio - | cpio -idm +done + +ln -sT lib64 lib +ln -sT lib64 usr/lib + +popd + +# Next, download and build binutils. +mkdir binutils-$TARGET +pushd binutils-$TARGET +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT +make -j10 +make install +popd +rm -rf binutils-$TARGET + +# Finally, download and build gcc. +mkdir gcc-$TARGET +pushd gcc-$TARGET +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$TARGET \ + --with-cpu=power8 \ + --with-sysroot=$SYSROOT \ + --disable-libcilkrts \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrt \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +make -j10 +make install + +popd +rm -rf gcc-$TARGET diff --git a/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch new file mode 100644 index 000000000000..744eb180cd1f --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch @@ -0,0 +1,24 @@ +From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Thu, 1 Nov 2012 18:00:06 -0500 +Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics. + +--- + sysdeps/powerpc/Makefile | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile +index 79dd6fa976d5..7442b6709ad1 100644 +--- a/sysdeps/powerpc/Makefile ++++ b/sysdeps/powerpc/Makefile +@@ -1,7 +1,3 @@ +-# We always want to use the new mnemonic syntax even if we are on a RS6000 +-# machine. +-+cflags += -mnew-mnemonics +- + ifeq ($(subdir),gmon) + sysdep_routines += ppc-mcount + endif +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch new file mode 100644 index 000000000000..47cc8b28d225 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch @@ -0,0 +1,26 @@ +From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001 +From: Josh Stone +Date: Fri, 20 Jan 2017 15:41:56 -0800 +Subject: [PATCH] Prevent inlining in PPC64 initfini.s + +Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html +--- + sysdeps/powerpc/powerpc64/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile +index 78d4f07e575f..fe96aae4d43e 100644 +--- a/sysdeps/powerpc/powerpc64/Makefile ++++ b/sysdeps/powerpc/powerpc64/Makefile +@@ -28,7 +28,7 @@ elide-routines.os += hp-timing + ifneq ($(elf),no) + # The initfini generation code doesn't work in the presence of -fPIC, so + # we use -fpic instead which is much better. +-CFLAGS-initfini.s += -fpic -O1 ++CFLAGS-initfini.s += -fpic -O1 -fno-inline + endif + endif + +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config new file mode 100644 index 000000000000..c2d02ee85cf2 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config @@ -0,0 +1,528 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="powerpc" +CT_ARCH_SUPPORTS_BOTH_ENDIAN=y +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_ABI=y +CT_ARCH_SUPPORTS_WITH_CPU=y +CT_ARCH_SUPPORTS_WITH_TUNE=y +CT_ARCH_SUPPORTS_WITH_FLOAT=y +CT_ARCH_DEFAULT_BE=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_ABI="" +CT_ARCH_CPU="power4" +CT_ARCH_TUNE="power6" +CT_ARCH_BE=y +# CT_ARCH_LE is not set +# CT_ARCH_32 is not set +CT_ARCH_64=y +CT_ARCH_BITNESS=64 +# CT_ARCH_FLOAT_HW is not set +# CT_ARCH_FLOAT_SW is not set +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +CT_ARCH_powerpc=y +# CT_ARCH_s390 is not set +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ENDIAN="big" + +# +# Target optimisations +# +CT_ARCH_FLOAT_AUTO=y +CT_ARCH_FLOAT="auto" + +# +# powerpc other options +# +CT_ARCH_powerpc_ABI="" +CT_ARCH_powerpc_ABI_DEFAULT=y +# CT_ARCH_powerpc_ABI_SPE is not set + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index ec38855fe3a0..589b5fd530fc 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -1,37 +1,81 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ - ca-certificates \ - python2.7 \ - git \ - cmake \ - sudo \ + automake \ + bison \ bzip2 \ - xz-utils \ - wget \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ patch \ - g++-s390x-linux-gnu + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils -COPY build-toolchain.sh /tmp/ -RUN sh /tmp/build-toolchain.sh +ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 +RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ + tar xJf - -C /usr/local/bin --strip-components=1 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] -ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 -RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ - tar xJf - -C /usr/local/bin --strip-components=1 +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ +RUN ./build-s390x-toolchain.sh + +USER root + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ AR_x86_64_unknown_netbsd=x86_64-unknown-netbsd-ar \ CC_x86_64_unknown_netbsd=x86_64-unknown-netbsd-gcc \ - CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ + CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ \ + CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ + AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ + CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ ENV HOSTS=x86_64-unknown-netbsd ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh old mode 100644 new mode 100755 similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-toolchain.sh rename to src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh new file mode 100755 index 000000000000..b4995e20dc69 --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../s390x-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch new file mode 100644 index 000000000000..cba416ed2f70 --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch @@ -0,0 +1,63 @@ +From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001 +From: Andreas Krebbel +Date: Sun, 17 Apr 2011 20:43:59 -0400 +Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109 + instructions in iconv modules + +--- + sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++- + sysdeps/s390/s390-64/utf8-utf16-z9.c | 5 ++++- + sysdeps/s390/s390-64/utf8-utf32-z9.c | 5 ++++- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c +index 14daf2118fe5..5bcaaaedec9c 100644 +--- a/sysdeps/s390/s390-64/utf16-utf32-z9.c ++++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c +@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c +index 5f73f3c59e21..812a42fae44c 100644 +--- a/sysdeps/s390/s390-64/utf8-utf16-z9.c ++++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c +@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c +index 17ef8bc890c3..0ffd848c8124 100644 +--- a/sysdeps/s390/s390-64/utf8-utf32-z9.c ++++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c +@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +-- +2.9.3 + diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config new file mode 100644 index 000000000000..fa5e4510987f --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config @@ -0,0 +1,508 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="s390" +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_FPU=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_FPU="" +# CT_ARCH_32 is not set +CT_ARCH_64=y +CT_ARCH_BITNESS=64 +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +# CT_ARCH_powerpc is not set +CT_ARCH_s390=y +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y + +# +# Target optimisations +# +CT_ARCH_FLOAT="" + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-arch=z10" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set From c051d2c8ad4b893580e891cb790aae6705ddb470 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 28 Jan 2017 21:41:35 -0800 Subject: [PATCH 072/104] Add a license to build-powerpc64le-toolchain.sh --- .../dist-powerpc64-linux/build-powerpc64le-toolchain.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh index 98fbe5045452..8b924ca34c47 100755 --- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh @@ -1,4 +1,13 @@ #!/bin/bash +# 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. set -ex From cb47d9ffc3a4fcd66e38b9065bcb9a9487dea3fc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 28 Jan 2017 22:02:49 -0800 Subject: [PATCH 073/104] Fix the powerpc64 PATH --- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 42842d2368ac..624763ef5de6 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -68,7 +68,7 @@ RUN apt-get install -y --no-install-recommends rpm2cpio cpio COPY build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh -ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnueabihf/bin +ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ From d880bbb35ff19a6e7c257eae6ef7c48df5eda9e6 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 29 Jan 2017 08:17:34 +0200 Subject: [PATCH 074/104] Remove the workaround for gh32959 This workaround is no longer necessary as Rust, and by extension MIR, now support uninhabited type properly. This removes the workaround for the gh32959 that was introduced in gh33267. Fixes #32959 --- src/librustc_mir/build/block.rs | 5 +---- src/librustc_mir/build/expr/into.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 73d3875ba238..121d592da031 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -16,8 +16,6 @@ use rustc::hir; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn ast_block(&mut self, destination: &Lvalue<'tcx>, - // FIXME(#32959): temporary measure for the issue - dest_is_unit: bool, mut block: BasicBlock, ast_block: &'tcx hir::Block) -> BlockAnd<()> { @@ -83,8 +81,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // of the block. if let Some(expr) = expr { unpack!(block = this.into(destination, block, expr)); - } else if dest_is_unit { - // FIXME(#31472) + } else { let source_info = this.source_info(span); this.cfg.push_assign_unit(block, source_info, destination); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 24b9c955658f..3d4af259ec9f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, expr.ty.is_nil(), block, ast_block) + this.ast_block(destination, block, ast_block) } ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) From 87bbb3c738e7d351d21fb19b51b2094b5afa0482 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Sun, 29 Jan 2017 10:51:26 +0000 Subject: [PATCH 075/104] Minor grammar fix 'can not' -> 'cannot' The previous version suggested that the compiler chooses not to check, rather than being unable to check. --- src/doc/book/ffi.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 8ab580e6aa9f..8d29f11aa051 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -56,9 +56,9 @@ almost any function that takes a pointer argument isn't valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of Rust's safe memory model. -When declaring the argument types to a foreign function, the Rust compiler can -not check if the declaration is correct, so specifying it correctly is part of -keeping the binding correct at runtime. +When declaring the argument types to a foreign function, the Rust compiler +cannot check if the declaration is correct, so specifying it correctly is part +of keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: From 149242e5190664bef3ae36e7780f33571f19c8d4 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 29 Jan 2017 20:35:11 +0900 Subject: [PATCH 076/104] Bootstrap: append libjemalloc_pic.a Fix #35349 --- src/bootstrap/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e035f8157ffd..6e077691b3a0 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -516,7 +516,7 @@ impl Config { "CFG_JEMALLOC_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - target.jemalloc = Some(parse_configure_path(value)); + target.jemalloc = Some(parse_configure_path(value).join("libjemalloc_pic.a")); } "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "arm-linux-androideabi".to_string(); From 19c9f18b2c89558300d5b71d47928878edb8bf97 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Jan 2017 23:33:12 +0100 Subject: [PATCH 077/104] Add missing url in convert module --- src/libcore/convert.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 830bbc079ad1..abd686b15e22 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -18,25 +18,33 @@ //! support arguments of multiple types. //! //! - Impl the `As*` traits for reference-to-reference conversions -//! - Impl the `Into` trait when you want to consume the value in the conversion -//! - The `From` trait is the most flexible, useful for value _and_ reference conversions -//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the +//! - Impl the [`Into`] trait when you want to consume the value in the conversion +//! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions +//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the //! conversion to fail //! -//! As a library author, you should prefer implementing `From` or `TryFrom` rather than -//! `Into` or `TryInto`, as `From` and `TryFrom` provide greater flexibility and offer -//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation +//! As a library author, you should prefer implementing [`From`][`From`] or +//! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], +//! as [`From`] and [`TryFrom`] provide greater flexibility and offer +//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation //! in the standard library. //! //! # Generic impl //! -//! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference -//! - `From for T` implies `Into for U` -//! - `TryFrom for T` implies `TryInto for U` -//! - `From` and `Into` are reflexive, which means that all types can `into()` +//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference +//! - [`From`]` for T` implies [`Into`]` for U` +//! - [`TryFrom`]` for T` implies [`TryInto`]` for U` +//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()` //! themselves and `from()` themselves //! //! See each trait for usage examples. +//! +//! [`Into`]: trait.Into.html +//! [`From`]: trait.From.html +//! [`TryFrom`]: trait.TryFrom.html +//! [`TryInto`]: trait.TryInto.html +//! [`AsRef`]: trait.AsRef.html +//! [`AsMut`]: trait.AsMut.html #![stable(feature = "rust1", since = "1.0.0")] From 986dd077eabd5b4bb313ed2e3b864106f8076fc0 Mon Sep 17 00:00:00 2001 From: king6cong Date: Mon, 30 Jan 2017 10:12:10 +0800 Subject: [PATCH 078/104] doc comment reword --- src/librustc_driver/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a7188f6da1ff..5603ecb1c041 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -780,7 +780,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, hir_map::Forest::new(hir_crate, &sess.dep_graph) }); - // Discard hygiene data, which isn't required past lowering to HIR. + // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { syntax::ext::hygiene::reset_hygiene_data(); } From 701c32ed4ab5014671f7237ab115817b9130d3bb Mon Sep 17 00:00:00 2001 From: king6cong Date: Mon, 30 Jan 2017 10:22:26 +0800 Subject: [PATCH 079/104] unify time_passes argument passing --- src/librustc_driver/driver.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5603ecb1c041..a04a5b106b8f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -741,15 +741,15 @@ pub fn phase_2_configure_and_expand(sess: &Session, "checking for inline asm in case the target doesn't support it", || no_asm::check_crate(sess, &krate)); - time(sess.time_passes(), + time(time_passes, "early lint checks", || lint::check_ast_crate(sess, &krate)); - time(sess.time_passes(), + time(time_passes, "AST validation", || ast_validation::check_crate(sess, &krate)); - time(sess.time_passes(), "name resolution", || -> CompileResult { + time(time_passes, "name resolution", || -> CompileResult { // Since import resolution will eventually happen in expansion, // don't perform `after_expand` until after import resolution. after_expand(&krate)?; @@ -770,7 +770,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, })?; // Lower ast -> hir. - let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { + let hir_forest = time(time_passes, "lowering ast -> hir", || { let hir_crate = lower_crate(sess, &krate, &mut resolver); if sess.opts.debugging_opts.hir_stats { From 4814fa488e44e641ff788dda9a07bbcc33a59560 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Mon, 30 Jan 2017 08:39:03 +0200 Subject: [PATCH 080/104] doc: minor Option improvements --- src/libcore/option.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 8871e1fa840e..c4d7b2dcf96f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -60,7 +60,7 @@ //! the optional owned box, [`Option`]`<`[`Box`]`>`. //! //! The following example uses [`Option`] to create an optional box of -//! [`i32`]. Notice that in order to use the inner [`i32`] value first the +//! [`i32`]. Notice that in order to use the inner [`i32`] value first, the //! `check_optional` function needs to use pattern matching to //! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or //! not ([`None`]). @@ -74,8 +74,8 @@ //! //! fn check_optional(optional: &Option>) { //! match *optional { -//! Some(ref p) => println!("have value {}", p), -//! None => println!("have no value"), +//! Some(ref p) => println!("has value {}", p), +//! None => println!("has no value"), //! } //! } //! ``` From 4b46d2a3a222f090b07b019df0e9346b08c40ae1 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 30 Jan 2017 17:37:49 +0100 Subject: [PATCH 081/104] Don't handle ENOSYS in `anon_pipe()` We're not calling the raw syscall but a libc function, the libc will have a compatibility layer. --- src/libstd/sys/unix/pipe.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index a5d60c257ed6..51e00fc1ab96 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -13,7 +13,6 @@ use io; use libc::{self, c_int}; use mem; use ptr; -use sync::atomic::{AtomicBool, Ordering}; use sys::{cvt, cvt_r}; use sys::fd::FileDesc; @@ -30,21 +29,17 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in // 2.6.27, however, and because we support 2.6.18 we must detect this // support dynamically. - static TRY_PIPE2: AtomicBool = AtomicBool::new(cfg!(target_os = "linux")); - if TRY_PIPE2.load(Ordering::Relaxed) { + if cfg!(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd")) + { weak! { fn pipe2(*mut c_int, c_int) -> c_int } if let Some(pipe) = pipe2.get() { - match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { - TRY_PIPE2.store(false, Ordering::Relaxed); - // Fall through - }, - res => { - res?; - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); - } - } + cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; + return Ok((AnonPipe(FileDesc::new(fds[0])), + AnonPipe(FileDesc::new(fds[1])))); } } cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; From 45d203df302d1a4b684ffec07edc4ec7fd1fa36d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 28 Jan 2017 10:24:42 -0800 Subject: [PATCH 082/104] travis: Tweak artifact uploads * Don't upload `*.wixpdb` files by accident * Don't upload `doc` dir by accident * Fix level of indirection on Travis --- .travis.yml | 5 +++-- appveyor.yml | 1 + src/bootstrap/dist.rs | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a7dc96b34b2..5abbdbc599bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -108,11 +108,12 @@ cache: before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT + - rm -rf build/dist/doc - > if [ "$TRAVIS_OS_NAME" == "osx" ]; then - cp -r build/dist deploy/$TRAVIS_COMMIT; + cp -r build/dist/* deploy/$TRAVIS_COMMIT; else - cp -r obj/build/dist deploy/$TRAVIS_COMMIT; + cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT; fi deploy: diff --git a/appveyor.yml b/appveyor.yml index 418cdcb07af4..c617ac8a4e34 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,6 +137,7 @@ branches: before_deploy: - ps: | New-Item -Path deploy -ItemType directory + Remove-Item -Recurse -Force build\dist\doc Get-ChildItem -Path build\dist | Move-Item -Destination deploy Get-ChildItem -Path deploy | Foreach-Object { Push-AppveyorArtifact $_.FullName -FileName ${env:APPVEYOR_REPO_COMMIT}/$_ diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 71a5f313bbd2..5fac142f777f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -827,7 +827,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cmd.arg("-nologo") .arg("-ext").arg("WixUIExtension") .arg("-ext").arg("WixUtilExtension") - .arg("-out").arg(distdir(build).join(filename)) + .arg("-out").arg(exe.join(&filename)) .arg("rust.wixobj") .arg("ui.wixobj") .arg("rustwelcomedlg.wixobj") @@ -844,6 +844,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cmd.arg("-sice:ICE57"); build.run(&mut cmd); + + t!(fs::rename(exe.join(&filename), distdir(build).join(&filename))); } } From bcca5e64544d55ae090b05048496c478bac22d59 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 10 Nov 2015 12:42:37 -0500 Subject: [PATCH 083/104] trans::debuginfo: simplify --- src/librustc_trans/debuginfo/utils.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 3ee2497009f6..8d634c0e292a 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -60,8 +60,7 @@ pub fn bytes_to_bits(bytes: u64) -> u64 { #[inline] pub fn debug_context<'a, 'tcx>(cx: &'a CrateContext<'a, 'tcx>) -> &'a CrateDebugContext<'tcx> { - let debug_context: &'a CrateDebugContext<'tcx> = cx.dbg_cx().as_ref().unwrap(); - debug_context + cx.dbg_cx().as_ref().unwrap() } #[inline] From 83fe5325d23fc77ff326db168c854cbc28e19258 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 8 Nov 2015 13:39:27 -0500 Subject: [PATCH 084/104] statics in match arm: compile with -g Closes #24956. --- src/test/run-pass/match-arm-statics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index 9700ed247959..78a37f518378 100644 --- a/src/test/run-pass/match-arm-statics.rs +++ b/src/test/run-pass/match-arm-statics.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -g #[derive(PartialEq, Eq)] struct NewBool(bool); From ffba0cea621c2609582b4e201b76b3b19860ec4f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Jan 2017 17:40:31 +0300 Subject: [PATCH 085/104] Merge ty::TyBox into ty::TyAdt --- src/liballoc/boxed.rs | 1 + src/librustc/infer/freshen.rs | 1 - src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/traits/coherence.rs | 13 +--- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/select.rs | 8 +- src/librustc/ty/contents.rs | 8 +- src/librustc/ty/context.rs | 8 +- src/librustc/ty/error.rs | 1 - src/librustc/ty/fast_reject.rs | 5 -- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 3 +- src/librustc/ty/layout.rs | 77 +++++++++++-------- src/librustc/ty/mod.rs | 12 ++- src/librustc/ty/outlives.rs | 1 - src/librustc/ty/relate.rs | 6 -- src/librustc/ty/structural_impls.rs | 2 - src/librustc/ty/sty.rs | 25 +++--- src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 2 +- src/librustc/ty/wf.rs | 1 - src/librustc/util/ppaux.rs | 3 +- .../borrowck/mir/elaborate_drops.rs | 10 +-- src/librustc_const_eval/_match.rs | 2 - src/librustc_const_eval/pattern.rs | 2 +- src/librustc_driver/test.rs | 11 +-- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/types.rs | 5 -- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/type_check.rs | 5 +- src/librustc_trans/abi.rs | 14 ++-- src/librustc_trans/base.rs | 46 ++++++----- src/librustc_trans/collector.rs | 35 +++++---- src/librustc_trans/debuginfo/metadata.rs | 64 ++++++++------- src/librustc_trans/debuginfo/type_names.rs | 5 -- src/librustc_trans/glue.rs | 32 ++++---- src/librustc_trans/mir/analyze.rs | 2 +- src/librustc_trans/trans_item.rs | 5 -- src/librustc_trans/type_of.rs | 57 ++++++++------ src/librustc_typeck/astconv.rs | 15 +--- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 5 -- src/librustc_typeck/check/mod.rs | 3 +- src/librustc_typeck/check/regionck.rs | 6 +- src/librustc_typeck/coherence/builtin.rs | 2 - src/librustc_typeck/coherence/mod.rs | 4 +- src/librustc_typeck/coherence/orphan.rs | 7 -- src/librustc_typeck/variance/constraints.rs | 1 - src/librustdoc/clean/mod.rs | 31 -------- src/test/compile-fail/autoderef-full-lval.rs | 5 +- .../borrowck/borrowck-box-insensitivity.rs | 12 +-- src/test/compile-fail/cross-borrow-trait.rs | 3 +- .../compile-fail/destructure-trait-ref.rs | 3 +- src/test/compile-fail/fn-trait-formatting.rs | 9 +-- src/test/compile-fail/issue-14915.rs | 3 +- src/test/compile-fail/issue-17441.rs | 4 +- src/test/compile-fail/issue-5100.rs | 3 +- src/test/compile-fail/issue-7061.rs | 3 +- .../compile-fail/kindck-impl-type-params-2.rs | 2 +- src/test/compile-fail/lint-ctypes.rs | 4 +- src/test/compile-fail/map-types.rs | 2 +- .../object-does-not-impl-trait.rs | 2 +- src/test/compile-fail/occurs-check-2.rs | 2 +- src/test/compile-fail/occurs-check.rs | 2 +- .../regions-infer-paramd-indirect.rs | 4 +- src/test/compile-fail/terr-sorts.rs | 3 +- src/test/compile-fail/trivial_casts.rs | 5 +- .../type-mismatch-same-crate-name.rs | 4 +- src/test/debuginfo/type-names.rs | 12 +-- src/test/run-pass/auxiliary/issue13507.rs | 2 +- .../trait-bounds-cant-coerce.stderr | 4 +- src/test/ui/span/coerce-suggestions.stderr | 2 +- 73 files changed, 315 insertions(+), 345 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5409ade29236..d98bc1892922 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -103,6 +103,7 @@ pub struct ExchangeHeapSingleton { /// /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] +#[fundamental] #[stable(feature = "rust1", since = "1.0.0")] pub struct Box(Unique); diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 19183892e4b0..697a1ecadc45 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -156,7 +156,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyUint(..) | ty::TyFloat(..) | ty::TyAdt(..) | - ty::TyBox(..) | ty::TyStr | ty::TyError | ty::TyArray(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index dca85d7727a7..0e8e1921de70 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -961,7 +961,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> cmt<'tcx> { let ptr = match base_cmt.ty.sty { - ty::TyBox(..) => Unique, + ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), ty::TyRef(r, mt) => { let bk = ty::BorrowKind::from_mutbl(mt.mutbl); diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 58cb52e89778..383fab3fcd76 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -199,7 +199,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt, fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> Vec> { - if ty_is_local_constructor(tcx, ty, infer_is_local) { + if ty_is_local_constructor(ty, infer_is_local) { vec![] } else if fundamental_ty(tcx, ty) { ty.walk_shallow() @@ -219,13 +219,13 @@ fn is_type_parameter(ty: Ty) -> bool { } fn ty_is_local(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal) -> bool { - ty_is_local_constructor(tcx, ty, infer_is_local) || + ty_is_local_constructor(ty, infer_is_local) || fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local)) } fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { - ty::TyBox(..) | ty::TyRef(..) => true, + ty::TyRef(..) => true, ty::TyAdt(def, _) => def.is_fundamental(), ty::TyDynamic(ref data, ..) => { data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental")) @@ -234,7 +234,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { } } -fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> bool { +fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool { debug!("ty_is_local_constructor({:?})", ty); match ty.sty { @@ -265,11 +265,6 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> def.did.is_local() } - ty::TyBox(_) => { // Box - let krate = tcx.lang_items.owned_box().map(|d| d.krate); - krate == Some(LOCAL_CRATE) - } - ty::TyDynamic(ref tt, ..) => { tt.principal().map_or(false, |p| p.def_id().is_local()) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1658efb03235..661d47199df1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -154,7 +154,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyStr => Some(2), ty::TyInt(..) | ty::TyUint(..) | ty::TyInfer(ty::IntVar(..)) => Some(3), ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), - ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), + ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), ty::TyArray(..) | ty::TySlice(..) => Some(6), ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7), ty::TyDynamic(..) => Some(8), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4990bb9f521d..d51332f833d7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1735,7 +1735,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | - ty::TyChar | ty::TyBox(_) | ty::TyRef(..) | + ty::TyChar | ty::TyRef(..) | ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything @@ -1788,7 +1788,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(Vec::new())) } - ty::TyBox(_) | ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | + ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyClosure(..) | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { Never @@ -1865,10 +1865,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { t); } - ty::TyBox(referent_ty) => { // Box - vec![referent_ty] - } - ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) | ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => { vec![element_ty] diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index ed5b470849c4..53e8a1d0e37e 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -191,10 +191,6 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TC::None } - ty::TyBox(typ) => { - tc_ty(tcx, typ, cache).owned_pointer() - } - ty::TyDynamic(..) => { TC::All - TC::InteriorParam } @@ -227,6 +223,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } + ty::TyAdt(def, _) if def.is_box() => { + tc_ty(tcx, ty.boxed_ty(), cache).owned_pointer() + } + ty::TyAdt(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 931d83f5e188..ce4a6a318263 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -19,6 +19,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DisambiguatedDefPathData; use middle::free_region::FreeRegionMap; +use middle::lang_items; use middle::region::RegionMaps; use middle::resolve_lifetime; use middle::stability; @@ -1088,7 +1089,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); @@ -1336,7 +1337,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyBox(ty)) + let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); + let adt_def = self.lookup_adt_def(def_id); + let substs = self.mk_substs(iter::once(Kind::from(ty))); + self.mk_ty(TyAdt(adt_def, substs)) } pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 91087a3dcecd..29d855a7fcb7 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -181,7 +181,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), - ty::TyBox(_) => "box".to_string(), ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 7b4d76ad4973..94b9abc72025 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -11,7 +11,6 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use syntax::ast; -use middle::lang_items::OwnedBoxLangItem; use self::SimplifiedType::*; @@ -69,10 +68,6 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // view of possibly unifying simplify_type(tcx, mt.ty, can_simplify_params) } - ty::TyBox(_) => { - // treat like we would treat `Box` - Some(AdtSimplifiedType(tcx.require_lang_item(OwnedBoxLangItem))) - } ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index a06d3ed6cf4f..0de77526b5a4 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -138,7 +138,7 @@ impl FlagComputation { self.add_region(r); } - &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { + &ty::TyArray(tt, _) | &ty::TySlice(tt) => { self.add_ty(tt) } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index d488cd1c4271..b719911d18cf 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -314,8 +314,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()), ty::TyArray(subty, _) | - ty::TySlice(subty) | - ty::TyBox(subty) => characteristic_def_id_of_type(subty), + ty::TySlice(subty) => characteristic_def_id_of_type(subty), ty::TyRawPtr(mt) | ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ff95554dbbfc..78364abdaecb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1053,6 +1053,23 @@ impl<'a, 'gcx, 'tcx> Layout { let dl = &tcx.data_layout; assert!(!ty.has_infer_types()); + let ptr_layout = |pointee: Ty<'gcx>| { + let non_zero = !ty.is_unsafe_ptr(); + let pointee = normalize_associated_type(infcx, pointee); + if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { + Ok(Scalar { value: Pointer, non_zero: non_zero }) + } else { + let unsized_part = tcx.struct_tail(pointee); + let meta = match unsized_part.sty { + ty::TySlice(_) | ty::TyStr => { + Int(dl.ptr_sized_integer()) + } + ty::TyDynamic(..) => Pointer, + _ => return Err(LayoutError::Unknown(unsized_part)) + }; + Ok(FatPointer { metadata: meta, non_zero: non_zero }) + } + }; let layout = match ty.sty { // Basic scalars. @@ -1082,24 +1099,12 @@ impl<'a, 'gcx, 'tcx> Layout { }, // Potentially-fat pointers. - ty::TyBox(pointee) | ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); - if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { - Scalar { value: Pointer, non_zero: non_zero } - } else { - let unsized_part = tcx.struct_tail(pointee); - let meta = match unsized_part.sty { - ty::TySlice(_) | ty::TyStr => { - Int(dl.ptr_sized_integer()) - } - ty::TyDynamic(..) => Pointer, - _ => return Err(LayoutError::Unknown(unsized_part)) - }; - FatPointer { metadata: meta, non_zero: non_zero } - } + ptr_layout(pointee)? + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_layout(ty.boxed_ty())? } // Arrays and slices. @@ -1560,26 +1565,32 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { Err(err) => err }; + let ptr_skeleton = |pointee: Ty<'gcx>| { + let non_zero = !ty.is_unsafe_ptr(); + let tail = tcx.struct_tail(pointee); + match tail.sty { + ty::TyParam(_) | ty::TyProjection(_) => { + assert!(tail.has_param_types() || tail.has_self_ty()); + Ok(SizeSkeleton::Pointer { + non_zero: non_zero, + tail: tcx.erase_regions(&tail) + }) + } + _ => { + bug!("SizeSkeleton::compute({}): layout errored ({}), yet \ + tail `{}` is not a type parameter or a projection", + ty, err, tail) + } + } + }; + match ty.sty { - ty::TyBox(pointee) | ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let non_zero = !ty.is_unsafe_ptr(); - let tail = tcx.struct_tail(pointee); - match tail.sty { - ty::TyParam(_) | ty::TyProjection(_) => { - assert!(tail.has_param_types() || tail.has_self_ty()); - Ok(SizeSkeleton::Pointer { - non_zero: non_zero, - tail: tcx.erase_regions(&tail) - }) - } - _ => { - bug!("SizeSkeleton::compute({}): layout errored ({}), yet \ - tail `{}` is not a type parameter or a projection", - ty, err, tail) - } - } + ptr_skeleton(pointee) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_skeleton(ty.boxed_ty()) } ty::TyAdt(def, substs) => { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 702f3681a020..db21d35f990d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1302,6 +1302,7 @@ bitflags! { const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, const IS_UNION = 1 << 6, + const IS_BOX = 1 << 7, } } @@ -1376,6 +1377,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { if Some(did) == tcx.lang_items.phantom_data() { flags = flags | AdtFlags::IS_PHANTOM_DATA; } + if Some(did) == tcx.lang_items.owned_box() { + flags = flags | AdtFlags::IS_BOX; + } match kind { AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, AdtKind::Union => flags = flags | AdtFlags::IS_UNION, @@ -1468,6 +1472,12 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) } + /// Returns true if this is Box. + #[inline] + pub fn is_box(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_BOX) + } + /// Returns whether this type has a destructor. pub fn has_dtor(&self) -> bool { self.dtor_kind().is_present() @@ -1641,7 +1651,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { -> Vec> { let result = match ty.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyClosure(..) | TyNever => { vec![] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index eb384eec6a6f..bc30f1fb7172 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -167,7 +167,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::TyFloat(..) | // OutlivesScalar ty::TyNever | // ... ty::TyAdt(..) | // OutlivesNominalType - ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) ty::TyArray(..) | // ... diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 76c26d01ac8e..89514085e1c7 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -418,12 +418,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) } - (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => - { - let typ = relation.relate(&a_inner, &b_inner)?; - Ok(tcx.mk_box(typ)) - } - (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => { let mt = relation.relate(a_mt, b_mt)?; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 06ba1b2a1faf..05f4abad4692 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -468,7 +468,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { - ty::TyBox(typ) => ty::TyBox(typ.fold_with(folder)), ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), @@ -506,7 +505,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match self.sty { - ty::TyBox(typ) => typ.visit_with(visitor), ty::TyRawPtr(ref tm) => tm.visit_with(visitor), ty::TyArray(typ, _sz) => typ.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d6164e69ffd3..d7686b60ae31 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -115,12 +115,6 @@ pub enum TypeVariants<'tcx> { /// definition and not a concrete use of it. TyAdt(&'tcx AdtDef, &'tcx Substs<'tcx>), - /// `Box`; this is nominally a struct in the documentation, but is - /// special-cased internally. For example, it is possible to implicitly - /// move the contents of a box out of that box, and methods of any type - /// can have type `Box`. - TyBox(Ty<'tcx>), - /// The pointee of a string slice. Written as `str`. TyStr, @@ -1139,10 +1133,18 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_unique(&self) -> bool { + pub fn is_box(&self) -> bool { match self.sty { - TyBox(_) => true, - _ => false + TyAdt(def, _) => def.is_box(), + _ => false, + } + } + + pub fn boxed_ty(&self) -> Ty<'tcx> { + match self.sty { + TyAdt(def, substs) if def.is_box() => + substs.types().next().expect("Box doesn't have type parameters"), + _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } } @@ -1247,9 +1249,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { -> Option> { match self.sty { - TyBox(ty) => { + TyAdt(def, _) if def.is_box() => { Some(TypeAndMut { - ty: ty, + ty: self.boxed_ty(), mutbl: if pref == ty::PreferMutLvalue { hir::MutMutable } else { @@ -1349,7 +1351,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyInt(_) | TyUint(_) | TyFloat(_) | - TyBox(_) | TyStr | TyArray(..) | TySlice(_) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c05375c47b03..ba49aa1ef486 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -481,7 +481,6 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyBool | TyChar | TyStr | - TyBox(_) | TySlice(_) => {} TyError | @@ -563,7 +562,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { mutbl: hir::MutImmutable, .. }) => Some(false), - TyStr | TyBox(..) | TyRef(_, TypeAndMut { + TyStr | TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) => Some(true), @@ -606,7 +605,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true), TyStr | TyDynamic(..) | TySlice(_) => Some(false), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 3fa7a803141d..0d1dc2e4d7c2 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -83,7 +83,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { } - ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty::TyArray(ty, _) | ty::TySlice(ty) => { stack.push(ty); } ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index bab9964651dc..33b70b09dcb7 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -323,7 +323,6 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - ty::TyBox(_) | ty::TyRawPtr(_) => { // simple cases that are WF if their type args are WF } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 74e27f84fddc..aa2eb2955deb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -16,7 +16,7 @@ use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyProjection, TyAnon}; -use ty::{TyBox, TyDynamic, TyInt, TyUint, TyInfer}; +use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use std::cell::Cell; @@ -708,7 +708,6 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInt(t) => write!(f, "{}", t.ty_to_string()), TyUint(t) => write!(f, "{}", t.ty_to_string()), TyFloat(t) => write!(f, "{}", t.ty_to_string()), - TyBox(typ) => write!(f, "Box<{}>", typ), TyRawPtr(ref tm) => { write!(f, "*{} {}", match tm.mutbl { hir::MutMutable => "mut", diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 8e0d9c147824..d555502c3ff8 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,9 +709,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyAdt(def, substs) => { - self.open_drop_for_adt(c, def, substs) - } ty::TyClosure(def_id, substs) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); self.open_drop_for_tuple(c, &tys) @@ -719,8 +716,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyTuple(tys) => { self.open_drop_for_tuple(c, tys) } - ty::TyBox(ty) => { - self.open_drop_for_box(c, ty) + ty::TyAdt(def, _) if def.is_box() => { + self.open_drop_for_box(c, ty.boxed_ty()) + } + ty::TyAdt(def, substs) => { + self.open_drop_for_adt(c, def, substs) } _ => bug!("open drop from non-ADT `{:?}`", ty) } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 1770a112cdf2..94b2ba58c9aa 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -722,7 +722,6 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize debug!("constructor_arity({:?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs) => fs.len(), - ty::TyBox(_) => 1, ty::TySlice(..) | ty::TyArray(..) => match *ctor { Slice(length) => length, ConstantValue(_) => 0, @@ -747,7 +746,6 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(), - ty::TyBox(ty) => vec![ty], ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => repeat(ty).take(length).collect(), ConstantValue(_) => vec![], diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a3b80ebddcf0..c6272613f4d0 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -215,7 +215,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } PatternKind::Deref { ref subpattern } => { match self.ty.sty { - ty::TyBox(_) => write!(f, "box ")?, + ty::TyAdt(def, _) if def.is_box() => write!(f, "box ")?, ty::TyRef(_, mt) => { write!(f, "&")?; if mt.mutbl == hir::MutMutable { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 59f6889ba4d9..1086d75f02cb 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -805,10 +805,9 @@ fn walk_ty() { let uint_ty = tcx.types.usize; let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); - let uniq_ty = tcx.mk_box(tup2_ty); - let walked: Vec<_> = uniq_ty.walk().collect(); + let walked: Vec<_> = tup2_ty.walk().collect(); assert_eq!(walked, - [uniq_ty, tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, + [tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, uint_ty]); }) } @@ -821,12 +820,10 @@ fn walk_ty_skip_subtree() { let uint_ty = tcx.types.usize; let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); - let uniq_ty = tcx.mk_box(tup2_ty); // types we expect to see (in order), plus a boolean saying // whether to skip the subtree. - let mut expected = vec![(uniq_ty, false), - (tup2_ty, false), + let mut expected = vec![(tup2_ty, false), (tup1_ty, false), (int_ty, false), (uint_ty, false), @@ -836,7 +833,7 @@ fn walk_ty_skip_subtree() { (uint_ty, false)]; expected.reverse(); - let mut walker = uniq_ty.walk(); + let mut walker = tup2_ty.walk(); while let Some(t) = walker.next() { debug!("walked to {:?}", t); let (expected_ty, skip) = expected.pop().unwrap(); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2892d61b8bd6..1592d1781764 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -95,7 +95,7 @@ pub struct BoxPointers; impl BoxPointers { fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext, span: Span, ty: Ty) { for leaf_ty in ty.walk() { - if let ty::TyBox(_) = leaf_ty.sty { + if leaf_ty.is_box() { let m = format!("type uses owned (Box type) pointers: {}", ty); cx.span_lint(BOX_POINTERS, span, &m); } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 532e60222645..9669efa2d86b 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -519,11 +519,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Primitive types with a stable representation. ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe, - ty::TyBox(..) => { - FfiUnsafe("found Rust type Box<_> in foreign module, \ - consider using a raw pointer instead") - } - ty::TySlice(_) => { FfiUnsafe("found Rust slice type in foreign module, \ consider using a raw pointer instead") diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index af9f7fb57813..9c1107344f24 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { base: Lvalue::Local(index), elem: ProjectionElem::Deref }) if self.mir.local_kind(index) == LocalKind::Temp - && self.mir.local_decls[index].ty.is_unique() + && self.mir.local_decls[index].ty.is_box() && self.temp_qualif[index].map_or(false, |qualif| { qualif.intersects(Qualif::NOT_CONST) }) => { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 0fabbe6678ad..c9195f29f178 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -580,9 +580,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { return; } - let arg_ty = match args[0].ty(mir, self.tcx()).sty { + let ty = args[0].ty(mir, self.tcx()); + let arg_ty = match ty.sty { ty::TyRawPtr(mt) => mt.ty, - ty::TyBox(ty) => ty, + ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), _ => { span_mirbug!(self, term, "box_free called with bad arg ty"); return; diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 577744653f09..d392ebaa33d4 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -429,7 +429,7 @@ impl FnType { if !type_is_fat_ptr(ccx, ret_ty) { // The `noalias` attribute on the return value is useful to a // function ptr caller. - if let ty::TyBox(_) = ret_ty.sty { + if ret_ty.is_box() { // `Box` pointer return values never alias because ownership // is transferred ret.attrs.set(ArgAttribute::NoAlias); @@ -438,12 +438,16 @@ impl FnType { // We can also mark the return value as `dereferenceable` in certain cases match ret_ty.sty { // These are not really pointers but pairs, (pointer, len) - ty::TyRef(_, ty::TypeAndMut { ty, .. }) | - ty::TyBox(ty) => { + ty::TyRef(_, ty::TypeAndMut { ty, .. }) => { let llty = type_of::sizing_type_of(ccx, ty); let llsz = llsize_of_alloc(ccx, llty); ret.attrs.set_dereferenceable(llsz); } + ty::TyAdt(def, _) if def.is_box() => { + let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty()); + let llsz = llsize_of_alloc(ccx, llty); + ret.attrs.set_dereferenceable(llsz); + } _ => {} } } @@ -453,9 +457,9 @@ impl FnType { // Handle safe Rust thin and fat pointers. let rust_ptr_attrs = |ty: Ty<'tcx>, arg: &mut ArgType| match ty.sty { // `Box` pointer parameters never alias because ownership is transferred - ty::TyBox(inner) => { + ty::TyAdt(def, _) if def.is_box() => { arg.attrs.set(ArgAttribute::NoAlias); - Some(inner) + Some(ty.boxed_ty()) } ty::TyRef(b, mt) => { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 32fe3effcc9f..9bd19d5bbb3e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -227,7 +227,6 @@ pub fn unsize_thin_ptr<'a, 'tcx>( ) -> (ValueRef, ValueRef) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), @@ -238,6 +237,12 @@ pub fn unsize_thin_ptr<'a, 'tcx>( let ptr_ty = type_of::in_memory_type_of(bcx.ccx, b).ptr_to(); (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); + assert!(bcx.ccx.shared().type_is_sized(a)); + let ptr_ty = type_of::in_memory_type_of(bcx.ccx, b).ptr_to(); + (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) + } _ => bug!("unsize_thin_ptr: called on bad types"), } } @@ -249,25 +254,30 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, src_ty: Ty<'tcx>, dst: ValueRef, dst_ty: Ty<'tcx>) { + let coerce_ptr = || { + let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) { + // fat-ptr to fat-ptr unsize preserves the vtable + // i.e. &'a fmt::Debug+Send => &'a fmt::Debug + // So we need to pointercast the base to ensure + // the types match up. + let (base, info) = load_fat_ptr(bcx, src, src_ty); + let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty); + let base = bcx.pointercast(base, llcast_ty); + (base, info) + } else { + let base = load_ty(bcx, src, src_ty); + unsize_thin_ptr(bcx, base, src_ty, dst_ty) + }; + store_fat_ptr(bcx, base, info, dst, dst_ty); + }; match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyBox(..), &ty::TyBox(..)) | (&ty::TyRef(..), &ty::TyRef(..)) | (&ty::TyRef(..), &ty::TyRawPtr(..)) | (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { - let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e. &'a fmt::Debug+Send => &'a fmt::Debug - // So we need to pointercast the base to ensure - // the types match up. - let (base, info) = load_fat_ptr(bcx, src, src_ty); - let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty); - let base = bcx.pointercast(base, llcast_ty); - (base, info) - } else { - let base = load_ty(bcx, src, src_ty); - unsize_thin_ptr(bcx, base, src_ty, dst_ty) - }; - store_fat_ptr(bcx, base, info, dst, dst_ty); + coerce_ptr() + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + coerce_ptr() } (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => { @@ -414,7 +424,7 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> V // a char is a Unicode codepoint, and so takes values from 0 // to 0x10FFFF inclusive only. b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False) - } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(ccx, t) { + } else if (t.is_region_ptr() || t.is_box()) && !common::type_is_fat_ptr(ccx, t) { b.load_nonnull(ptr) } else { b.load(ptr) @@ -449,7 +459,7 @@ pub fn load_fat_ptr<'a, 'tcx>( b: &Builder<'a, 'tcx>, src: ValueRef, t: Ty<'tcx> ) -> (ValueRef, ValueRef) { let ptr = get_dataptr(b, src); - let ptr = if t.is_region_ptr() || t.is_unique() { + let ptr = if t.is_region_ptr() || t.is_box() { b.load_nonnull(ptr) } else { b.load(ptr) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index fa8bad5807aa..9766b816d9b3 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -721,14 +721,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty)); // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value. - if let ty::TyBox(content_type) = ty.sty { + if ty.is_box() { let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem); - if should_trans_locally(scx.tcx(), def_id) { let box_free_fn_trans_item = create_fn_trans_item(scx, def_id, - scx.tcx().mk_substs(iter::once(Kind::from(content_type))), + scx.tcx().mk_substs(iter::once(Kind::from(ty.boxed_ty()))), scx.tcx().intern_substs(&[])); output.push(box_free_fn_trans_item); } @@ -790,8 +789,14 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyDynamic(..) => { /* nothing to do */ } - ty::TyAdt(adt_def, substs) => { - for field in adt_def.all_fields() { + ty::TyAdt(def, _) if def.is_box() => { + let inner_type = glue::get_drop_glue_type(scx, ty.boxed_ty()); + if scx.type_needs_drop(inner_type) { + output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); + } + } + ty::TyAdt(def, substs) => { + for field in def.all_fields() { let field_type = scx.tcx().item_type(field.did); let field_type = monomorphize::apply_param_substs(scx, substs, @@ -811,7 +816,6 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } } - ty::TyBox(inner_type) | ty::TySlice(inner_type) | ty::TyArray(inner_type, _) => { let inner_type = glue::get_drop_glue_type(scx, inner_type); @@ -1008,21 +1012,24 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, source_ty: ty::Ty<'tcx>, target_ty: ty::Ty<'tcx>) -> (ty::Ty<'tcx>, ty::Ty<'tcx>) { + let ptr_vtable = |inner_source: ty::Ty<'tcx>, inner_target: ty::Ty<'tcx>| { + if !scx.type_is_sized(inner_source) { + (inner_source, inner_target) + } else { + scx.tcx().struct_lockstep_tails(inner_source, inner_target) + } + }; match (&source_ty.sty, &target_ty.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { - let (inner_source, inner_target) = (a, b); - - if !scx.type_is_sized(inner_source) { - (inner_source, inner_target) - } else { - scx.tcx().struct_lockstep_tails(inner_source, inner_target) - } + ptr_vtable(a, b) + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } (&ty::TyAdt(source_adt_def, source_substs), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 0de3c13dc21a..b7e319f2de43 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -490,6 +490,35 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, debug!("type_metadata: {:?}", t); let sty = &t.sty; + let ptr_metadata = |ty: Ty<'tcx>| { + match ty.sty { + ty::TySlice(typ) => { + Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)) + } + ty::TyStr => { + Ok(vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)) + } + ty::TyDynamic(..) => { + Ok(MetadataCreationResult::new( + trait_pointer_metadata(cx, ty, Some(t), unique_type_id), + false)) + } + _ => { + let pointee_metadata = type_metadata(cx, ty, usage_site_span); + + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return Err(metadata), + None => { /* proceed normally */ } + }; + + Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false)) + } + } + }; + let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty { ty::TyNever | ty::TyBool | @@ -516,34 +545,17 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, trait_pointer_metadata(cx, t, None, unique_type_id), false) } - ty::TyBox(ty) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { - match ty.sty { - ty::TySlice(typ) => { - vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span) - } - ty::TyStr => { - vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span) - } - ty::TyDynamic(..) => { - MetadataCreationResult::new( - trait_pointer_metadata(cx, ty, Some(t), unique_type_id), - false) - } - _ => { - let pointee_metadata = type_metadata(cx, ty, usage_site_span); - - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return metadata, - None => { /* proceed normally */ } - }; - - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), - false) - } + match ptr_metadata(ty) { + Ok(res) => res, + Err(metadata) => return metadata, + } + } + ty::TyAdt(def, _) if def.is_box() => { + match ptr_metadata(t.boxed_ty()) { + Ok(res) => res, + Err(metadata) => return metadata, } } ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => { diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 788ce32937d8..8e11bf6b8976 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -60,11 +60,6 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } output.push(')'); }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - push_debuginfo_type_name(cx, inner_type, true, output); - output.push('>'); - }, ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { output.push('*'); match mutbl { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index b24f00ee6976..65f3c7add4db 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -79,16 +79,21 @@ pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'t return scx.tcx().types.i8; } match t.sty { - ty::TyBox(typ) if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) => { - scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - let layout = t.layout(&infcx).unwrap(); - if layout.size(&scx.tcx().data_layout).bytes() == 0 { - // `Box` does not allocate. - scx.tcx().types.i8 - } else { - t - } - }) + ty::TyAdt(def, _) if def.is_box() => { + let typ = t.boxed_ty(); + if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { + scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + let layout = t.layout(&infcx).unwrap(); + if layout.size(&scx.tcx().data_layout).bytes() == 0 { + // `Box` does not allocate. + scx.tcx().types.i8 + } else { + t + } + }) + } else { + t + } } _ => t } @@ -205,11 +210,12 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi }; let bcx = match t.sty { - ty::TyBox(content_ty) => { - // Support for TyBox is built-in and its drop glue is + ty::TyAdt(def, _) if def.is_box() => { + // Support for Box is built-in and its drop glue is // special. It may move to library and have Drop impl. As - // a safe-guard, assert TyBox not used with TyContents. + // a safe-guard, assert Box not used with TyContents. assert!(!skip_dtor); + let content_ty = t.boxed_ty(); let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) { let llbox = bcx.load(get_dataptr(&bcx, ptr.llval)); let info = bcx.load(get_meta(&bcx, ptr.llval)); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 8df24da71358..2a1ab10d74e1 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -30,7 +30,7 @@ pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let ty = mircx.monomorphize(&ty); debug!("local {} has type {:?}", index, ty); if ty.is_scalar() || - ty.is_unique() || + ty.is_box() || ty.is_region_ptr() || ty.is_simd() || common::type_is_zero_size(mircx.ccx, ty) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 43ea1e56a5a4..d58a93e3cb71 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -421,11 +421,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } output.push(')'); }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - self.push_type_name(inner_type, output); - output.push('>'); - }, ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { output.push('*'); match mutbl { diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 469214b466e1..4df0e989ada9 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -38,6 +38,13 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ debug!("sizing_type_of {:?}", t); let _recursion_lock = cx.enter_type_of(t); + let ptr_sizing_ty = |ty: Ty<'tcx>| { + if cx.shared().type_is_sized(ty) { + Type::i8p(cx) + } else { + Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) + } + }; let llsizingty = match t.sty { _ if !cx.shared().type_is_sized(t) => { Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false) @@ -50,14 +57,12 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::TyFloat(t) => Type::float_from_ty(cx, t), ty::TyNever => Type::nil(cx), - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - if cx.shared().type_is_sized(ty) { - Type::i8p(cx) - } else { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) - } + ptr_sizing_ty(ty) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_sizing_ty(t.boxed_ty()) } ty::TyFnDef(..) => Type::nil(cx), @@ -131,11 +136,13 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { match ty.sty { - ty::TyBox(t) | ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => { in_memory_type_of(ccx, t).ptr_to() } + ty::TyAdt(def, _) if def.is_box() => { + in_memory_type_of(ccx, ty.boxed_ty()).ptr_to() + } _ => bug!("expected fat ptr ty but got {:?}", ty) } } @@ -214,6 +221,22 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> return llty; } + let ptr_ty = |ty: Ty<'tcx>| { + if !cx.shared().type_is_sized(ty) { + if let ty::TyStr = ty.sty { + // This means we get a nicer name in the output (str is always + // unsized). + cx.str_slice_type() + } else { + let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); + let info_ty = unsized_info_ty(cx, ty); + Type::struct_(cx, &[ptr_ty, info_ty], false) + } + } else { + in_memory_type_of(cx, ty).ptr_to() + } + }; + let mut llty = match t.sty { ty::TyBool => Type::bool(cx), ty::TyChar => Type::char(cx), @@ -227,22 +250,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> adt::incomplete_type_of(cx, t, "closure") } - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - if !cx.shared().type_is_sized(ty) { - if let ty::TyStr = ty.sty { - // This means we get a nicer name in the output (str is always - // unsized). - cx.str_slice_type() - } else { - let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); - let info_ty = unsized_info_ty(cx, ty); - Type::struct_(cx, &[ptr_ty, info_ty], false) - } - } else { - in_memory_type_of(cx, ty).ptr_to() - } + ptr_ty(ty) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_ty(t.boxed_ty()) } ty::TyArray(ty, size) => { @@ -300,7 +313,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() => { + ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() && !t.is_box() => { adt::finish_type_of(cx, t, &mut llty); } _ => () diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 56de539cbfe9..bb9a487802e7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -670,16 +670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }; - let substs = self.ast_path_substs_for_ty(span, - did, - item_segment); - - // FIXME(#12938): This is a hack until we have full support for DST. - if Some(did) == self.tcx().lang_items.owned_box() { - assert_eq!(substs.types().count(), 1); - return self.tcx().mk_box(substs.type_at(0)); - } - + let substs = self.ast_path_substs_for_ty(span, did, item_segment); decl_ty.subst(self.tcx(), substs) } @@ -1674,7 +1665,7 @@ impl<'tcx> ExplicitSelf<'tcx> { fn count_modifiers(ty: Ty) -> usize { match ty.sty { ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, + ty::TyAdt(def, _) if def.is_box() => count_modifiers(ty.boxed_ty()) + 1, _ => 0, } } @@ -1687,7 +1678,7 @@ impl<'tcx> ExplicitSelf<'tcx> { } else { match self_arg_ty.sty { ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl), - ty::TyBox(_) => ExplicitSelf::ByBox, + ty::TyAdt(def, _) if def.is_box() => ExplicitSelf::ByBox, _ => ExplicitSelf::ByValue, } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 0218f1c70ba8..6215b4498dc6 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { tstr); } } - ty::TyBox(..) => { + ty::TyAdt(def, ..) if def.is_box() => { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { Ok(s) => { err.span_suggestion(self.cast_span, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 91b772a748c7..34aa4eda772a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -448,7 +448,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( Ok(()) } - ty::TyBox(ity) | ty::TyArray(ity, _) | ty::TySlice(ity) => { + ty::TyArray(ity, _) | ty::TySlice(ity) => { // single-element containers, behave like their element iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e2d7d31a8a89..300caca30fec 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -391,11 +391,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } - ty::TyBox(_) => { - if let Some(box_did) = self.tcx.lang_items.owned_box() { - self.assemble_inherent_impl_candidates_for_type(box_did); - } - } ty::TyParam(p) => { self.assemble_inherent_candidates_from_param(self_ty, p); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c2f32c2b52bb..c435f9341253 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3438,7 +3438,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprBox(ref subexpr) => { let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { match ty.sty { - ty::TyBox(ty) => Expectation::rvalue_hint(self, ty), + ty::TyAdt(def, _) if def.is_box() + => Expectation::rvalue_hint(self, ty.boxed_ty()), _ => NoExpectation } }); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 7d515a36cfdf..d84e9d3fd373 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -815,9 +815,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r); } - /*From:*/ (&ty::TyBox(from_referent_ty), - /*To: */ &ty::TyBox(to_referent_ty)) => { - self.walk_cast(cast_expr, from_referent_ty, to_referent_ty); + /*From:*/ (&ty::TyAdt(from_def, _), + /*To: */ &ty::TyAdt(to_def, _)) if from_def.is_box() && to_def.is_box() => { + self.walk_cast(cast_expr, from_ty.boxed_ty(), to_ty.boxed_ty()); } _ => { } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 086484c643ad..96875fce468d 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -220,8 +220,6 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (mt_a.ty, mt_b.ty, unsize_trait, None) }; let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None), - (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 5af9ea29fafa..e9c710d2fec4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -21,7 +21,7 @@ use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; +use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; use CrateCtxt; use syntax_pos::Span; @@ -61,8 +61,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()), - TyBox(_) => self.tcx.lang_items.owned_box(), - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError | TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None, diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index a0d25abd14ce..9ef231499df5 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -91,12 +91,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { ty::TyDynamic(ref data, ..) if data.principal().is_some() => { self.check_def_id(item, data.principal().unwrap().def_id()); } - ty::TyBox(..) => { - match self.tcx.lang_items.require_owned_box() { - Ok(trait_id) => self.check_def_id(item, trait_id), - Err(msg) => self.tcx.sess.span_fatal(item.span, &msg), - } - } ty::TyChar => { self.check_primitive_impl(def_id, self.tcx.lang_items.char_impl(), @@ -321,7 +315,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { ty::TyAdt(self_def, _) => Some(self_def.did), - ty::TyBox(..) => self.tcx.lang_items.owned_box(), _ => None, }; diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index ba00f237684e..40e82959336d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -329,7 +329,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_mt(generics, mt, variance); } - ty::TyBox(typ) | ty::TyArray(typ, _) | ty::TySlice(typ) => { self.add_constraints_from_ty(generics, typ, variance); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7591475c5d3f..cdb24a56367f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1808,10 +1808,6 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyUint(uint_ty) => Primitive(uint_ty.into()), ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), - ty::TyBox(t) => { - let box_did = cx.tcx.lang_items.owned_box(); - lang_struct(cx, box_did, t, "Box", Unique) - } ty::TySlice(ty) => Vector(box ty.clean(cx)), ty::TyArray(ty, i) => FixedVector(box ty.clean(cx), format!("{}", i)), @@ -2888,33 +2884,6 @@ impl Clean for attr::Deprecation { } } -fn lang_struct(cx: &DocContext, did: Option, - t: ty::Ty, name: &str, - fallback: fn(Box) -> Type) -> Type { - let did = match did { - Some(did) => did, - None => return fallback(box t.clean(cx)), - }; - inline::record_extern_fqn(cx, did, TypeKind::Struct); - ResolvedPath { - typarams: None, - did: did, - path: Path { - global: false, - def: Def::Err, - segments: vec![PathSegment { - name: name.to_string(), - params: PathParameters::AngleBracketed { - lifetimes: vec![], - types: vec![t.clean(cx)], - bindings: vec![] - } - }], - }, - is_generic: false, - } -} - /// An equality constraint on an associated type, e.g. `A=Bar` in `Foo` #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)] pub struct TypeBinding { diff --git a/src/test/compile-fail/autoderef-full-lval.rs b/src/test/compile-fail/autoderef-full-lval.rs index 0d666a492003..c152fdd92968 100644 --- a/src/test/compile-fail/autoderef-full-lval.rs +++ b/src/test/compile-fail/autoderef-full-lval.rs @@ -22,13 +22,14 @@ struct fish { fn main() { let a: clam = clam{x: box 1, y: box 2}; let b: clam = clam{x: box 10, y: box 20}; - let z: isize = a.x + b.y; //~ ERROR binary operation `+` cannot be applied to type `Box` + let z: isize = a.x + b.y; + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` println!("{}", z); assert_eq!(z, 21); let forty: fish = fish{a: box 40}; let two: fish = fish{a: box 2}; let answer: isize = forty.a + two.a; - //~^ ERROR binary operation `+` cannot be applied to type `Box` + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` println!("{}", answer); assert_eq!(answer, 42); } diff --git a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs index 530822f6c5ba..d09cb73d6702 100644 --- a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs @@ -35,7 +35,7 @@ fn copy_after_move() { let _x = a.x; //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -44,7 +44,7 @@ fn move_after_move() { let _x = a.x; //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -53,7 +53,7 @@ fn borrow_after_move() { let _x = a.x; //~^ value moved here let _y = &a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -106,7 +106,7 @@ fn copy_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } @@ -115,7 +115,7 @@ fn move_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } @@ -124,7 +124,7 @@ fn borrow_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = &a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index 672ff464718f..f389380584b8 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -20,6 +20,5 @@ pub fn main() { let x: Box = Box::new(Foo); let _y: &Trait = x; //~ ERROR mismatched types //~| expected type `&Trait` - //~| found type `Box` - //~| expected &Trait, found box + //~| found type `std::boxed::Box` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 89fb1e105900..835ec8e4a5e7 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -51,6 +51,5 @@ fn main() { let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected type `T` - //~| found type `Box<_>` - //~| expected trait T, found box + //~| found type `std::boxed::Box<_>` } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index e01a0412cef4..6377550d3d22 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -16,18 +16,15 @@ fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box` - //~| expected (), found box + //~| found type `std::boxed::Box` let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box` - //~| expected (), found box + //~| found type `std::boxed::Box` let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box isize>` - //~| expected (), found box + //~| found type `std::boxed::Box isize>` needs_fn(1); //~^ ERROR : std::ops::Fn<(isize,)>` diff --git a/src/test/compile-fail/issue-14915.rs b/src/test/compile-fail/issue-14915.rs index 18e4ccc33119..810d6656a8f6 100644 --- a/src/test/compile-fail/issue-14915.rs +++ b/src/test/compile-fail/issue-14915.rs @@ -13,5 +13,6 @@ fn main() { let x: Box = box 0; - println!("{}", x + 1); //~ ERROR binary operation `+` cannot be applied to type `Box` + println!("{}", x + 1); + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` } diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index 7d300bfb1483..45ab9903532e 100644 --- a/src/test/compile-fail/issue-17441.rs +++ b/src/test/compile-fail/issue-17441.rs @@ -13,9 +13,9 @@ fn main() { //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` //~^^ HELP consider using an implicit coercion to `&[usize]` instead - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + // FIXME (#22405): Replace `std::boxed::Box::new` with `box` here when/if possible. let _bar = Box::new(1_usize) as std::fmt::Debug; - //~^ ERROR cast to unsized type: `Box` as `std::fmt::Debug` + //~^ ERROR cast to unsized type: `std::boxed::Box` as `std::fmt::Debug` //~^^ HELP try casting to a `Box` instead let _baz = 1_usize as std::fmt::Debug; diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index a1f5d74b30e3..9ef780aac8e2 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -43,8 +43,7 @@ fn main() { box (true, false) => () //~^ ERROR mismatched types //~| expected type `(bool, bool)` -//~| found type `Box<_>` -//~| expected tuple, found box +//~| found type `std::boxed::Box<_>` } match (true, false) { diff --git a/src/test/compile-fail/issue-7061.rs b/src/test/compile-fail/issue-7061.rs index da6f49f3efe9..b99f5b707ee2 100644 --- a/src/test/compile-fail/issue-7061.rs +++ b/src/test/compile-fail/issue-7061.rs @@ -13,9 +13,8 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected type `Box` + //~| expected type `std::boxed::Box` //~| found type `&'a mut BarStruct` - //~| expected box, found mutable reference } fn main() {} diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index a455a7b2d5d0..21aefc4f9c1b 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -21,5 +21,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR `Box<{integer}>: std::marker::Copy` is not satisfied + //~^ ERROR `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/compile-fail/lint-ctypes.rs index 731c1edbfc00..ccc25b58228b 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/compile-fail/lint-ctypes.rs @@ -34,7 +34,7 @@ extern { pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type pub fn str_type(p: &str); //~ ERROR: found Rust type - pub fn box_type(p: Box); //~ ERROR found Rust type + pub fn box_type(p: Box); //~ ERROR found struct without pub fn char_type(p: char); //~ ERROR found Rust type pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type @@ -42,7 +42,7 @@ extern { pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust - pub fn fn_contained(p: RustBadRet); //~ ERROR: found Rust type + pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without pub fn good1(size: *const libc::c_int); pub fn good2(size: *const libc::c_uint); diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index e24441c5497d..eaafc312379c 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -26,5 +26,5 @@ fn main() { let x: Box> = x; // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let y: Box> = Box::new(x); - //~^ ERROR `Box>: Map` is not satisfied + //~^ ERROR `std::boxed::Box>: Map` is not satisfied } diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs index 6fa261dea71c..8babc734c84c 100644 --- a/src/test/compile-fail/object-does-not-impl-trait.rs +++ b/src/test/compile-fail/object-does-not-impl-trait.rs @@ -14,5 +14,5 @@ trait Foo {} fn take_foo(f: F) {} fn take_object(f: Box) { take_foo(f); } -//~^ ERROR `Box: Foo` is not satisfied +//~^ ERROR `std::boxed::Box: Foo` is not satisfied fn main() {} diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index 5cb60079fa4b..a276af83dee2 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -17,6 +17,6 @@ fn main() { f = box g; //~^ ERROR mismatched types //~| expected type `_` - //~| found type `Box<_>` + //~| found type `std::boxed::Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 499124cb0573..5b6a11e58c27 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -15,6 +15,6 @@ fn main() { f = box f; //~^ ERROR mismatched types //~| expected type `_` - //~| found type `Box<_>` + //~| found type `std::boxed::Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index fad115c2aedf..c559992c8653 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -32,8 +32,8 @@ impl<'a> set_f<'a> for c<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected type `Box>` - //~| found type `Box>` + //~| expected type `std::boxed::Box>` + //~| found type `std::boxed::Box>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/terr-sorts.rs b/src/test/compile-fail/terr-sorts.rs index 592d7b3929bf..fd92a26d0fce 100644 --- a/src/test/compile-fail/terr-sorts.rs +++ b/src/test/compile-fail/terr-sorts.rs @@ -20,8 +20,7 @@ fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types //~| expected type `foo` - //~| found type `Box` - //~| expected struct `foo`, found box + //~| found type `std::boxed::Box` } fn main() {} diff --git a/src/test/compile-fail/trivial_casts.rs b/src/test/compile-fail/trivial_casts.rs index 7693d98a2f7b..aabf0d26d5ba 100644 --- a/src/test/compile-fail/trivial_casts.rs +++ b/src/test/compile-fail/trivial_casts.rs @@ -52,7 +52,8 @@ pub fn main() { let _: *mut [u32] = x; let x: Box<[u32; 3]> = Box::new([42, 43, 44]); - let _ = x as Box<[u32]>; //~ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` + let _ = x as Box<[u32]>; + //~^ ERROR trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _: Box<[u32]> = x; @@ -70,7 +71,7 @@ pub fn main() { let _: *mut Foo = x; let x: Box = Box::new(Bar); - let _ = x as Box; //~ERROR trivial cast: `Box` as `Box` + let _ = x as Box; //~ERROR trivial cast: `std::boxed::Box` as `std::boxed::Box` let x: Box = Box::new(Bar); let _: Box = x; diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs index e74acaa71b0f..4295d08a4709 100644 --- a/src/test/compile-fail/type-mismatch-same-crate-name.rs +++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs @@ -33,7 +33,7 @@ fn main() { //~^ ERROR mismatched types //~| Perhaps two different versions of crate `crate_a1` //~| expected trait `main::a::Bar` - //~| expected type `Box` - //~| found type `Box` + //~| expected type `std::boxed::Box` + //~| found type `std::boxed::Box` } } diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 438a78743bb1..57d40cccf2d8 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -70,12 +70,12 @@ // BOX // gdb-command:whatis box1 -// gdbg-check:type = struct (Box, i32) -// gdbr-check:type = (Box, i32) +// gdbg-check:type = struct (alloc::boxed::Box, i32) +// gdbr-check:type = (alloc::boxed::Box, i32) // gdb-command:whatis box2 -// gdbg-check:type = struct (Box>, i32) -// gdbr-check:type = (Box>, i32) +// gdbg-check:type = struct (alloc::boxed::Box>, i32) +// gdbr-check:type = (alloc::boxed::Box>, i32) // REFERENCES @@ -196,8 +196,8 @@ // gdbr-check:type = (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) // gdb-command:whatis extern_stdcall_fn_with_return_value -// gdbg-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) -// gdbr-check:type = (extern "stdcall" fn(Box) -> usize, usize) +// gdbg-check:type = struct (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) +// gdbr-check:type = (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) // gdb-command:whatis generic_function_int // gdbg-check:type = struct (fn(isize) -> isize, usize) diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index ba50aed42c36..ee7d45b77bf4 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -58,7 +58,7 @@ pub mod testtypes { // Tests TySlice pub type FooSlice = [u8]; - // Tests TyBox (of u8) + // Tests Box (of u8) pub type FooBox = Box; // Tests TyRawPtr diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr index c47975b01355..ccc9fb56772f 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 24 | a(x); //~ ERROR mismatched types [E0308] | ^ expected trait `Foo + std::marker::Send`, found trait `Foo` | - = note: expected type `Box` - found type `Box` + = note: expected type `std::boxed::Box` + found type `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index c32fefcd0d6a..6a70b8ff851d 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -49,7 +49,7 @@ error[E0308]: mismatched types | ^^^^^ cyclic type of infinite size | = note: expected type `_` - found type `Box<_>` + found type `std::boxed::Box<_>` error: aborting due to 5 previous errors From 4a4f8ff0a3eeb0855f03ad88c2f11f12761041f0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Jan 2017 22:44:44 +0300 Subject: [PATCH 086/104] Implement Drop for Box --- src/liballoc/boxed.rs | 8 ++++++ src/librustc/ty/contents.rs | 27 +++---------------- src/librustc/ty/sty.rs | 3 +-- .../borrowck/mir/elaborate_drops.rs | 2 +- .../borrowck/mir/gather_moves.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/glue.rs | 5 ++-- 8 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d98bc1892922..b6f490e09cdd 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -293,6 +293,14 @@ impl Box { } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized> Drop for Box { + fn drop(&mut self) { + // FIXME: Do nothing, drop is currently performed by compiler. + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { /// Creates a `Box`, with the `Default` value for T. diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 53e8a1d0e37e..00c6dca21b1e 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -56,12 +56,8 @@ def_type_content_sets! { // InteriorAll = 0b00000000__00000000__1111, // Things that are owned by the value (second and third nibbles): - OwnsOwned = 0b0000_0000__0000_0001__0000, OwnsDtor = 0b0000_0000__0000_0010__0000, - OwnsAll = 0b0000_0000__1111_1111__0000, - - // Things that mean drop glue is necessary - NeedsDrop = 0b0000_0000__0000_0111__0000, + // OwnsAll = 0b0000_0000__1111_1111__0000, // All bits All = 0b1111_1111__1111_1111__1111 @@ -77,10 +73,6 @@ impl TypeContents { (self.bits & tc.bits) != 0 } - pub fn owns_owned(&self) -> bool { - self.intersects(TC::OwnsOwned) - } - pub fn interior_param(&self) -> bool { self.intersects(TC::InteriorParam) } @@ -90,12 +82,7 @@ impl TypeContents { } pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TC::NeedsDrop) - } - - /// Includes only those bits that still apply when indirected through a `Box` pointer - pub fn owned_pointer(&self) -> TypeContents { - TC::OwnsOwned | (*self & TC::OwnsAll) + self.intersects(TC::OwnsDtor) } pub fn union(v: I, mut f: F) -> TypeContents where @@ -104,10 +91,6 @@ impl TypeContents { { v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) } - - pub fn has_dtor(&self) -> bool { - self.intersects(TC::OwnsDtor) - } } impl ops::BitOr for TypeContents { @@ -223,10 +206,6 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyAdt(def, _) if def.is_box() => { - tc_ty(tcx, ty.boxed_ty(), cache).owned_pointer() - } - ty::TyAdt(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { @@ -237,7 +216,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { if def.is_union() { // unions don't have destructors regardless of the child types - res = res - TC::NeedsDrop; + res = res - TC::OwnsDtor; } if def.has_dtor() { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d7686b60ae31..113534e4529c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1142,8 +1142,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn boxed_ty(&self) -> Ty<'tcx> { match self.sty { - TyAdt(def, substs) if def.is_box() => - substs.types().next().expect("Box doesn't have type parameters"), + TyAdt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index d555502c3ff8..9e89a3689c7a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -895,7 +895,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match ty.sty { ty::TyAdt(def, _) => { - if def.has_dtor() { + if def.has_dtor() && !def.is_box() { self.tcx.sess.span_warn( c.source_info.span, &format!("dataflow bug??? moving out of type with dtor {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 2a9acaf58b8f..7cf6ab2999c0 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { // error: can't move out of borrowed content ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyAdt(adt, _) if adt.has_dtor() => + ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() => return Err(MovePathError::IllegalMove), // move out of union - always move the entire union ty::TyAdt(adt, _) if adt.is_union() => diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 372eb1d5d64f..a0c36139ddcd 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => { + ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 9766b816d9b3..392c270c130a 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -740,7 +740,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, _ => None }; - if let Some(destructor_did) = destructor_did { + if let (Some(destructor_did), false) = (destructor_did, ty.is_box()) { use rustc::ty::ToPolyTraitRef; let drop_trait_def_id = scx.tcx() diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 65f3c7add4db..350c8f950ddf 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -211,9 +211,8 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi let bcx = match t.sty { ty::TyAdt(def, _) if def.is_box() => { - // Support for Box is built-in and its drop glue is - // special. It may move to library and have Drop impl. As - // a safe-guard, assert Box not used with TyContents. + // Support for Box is built-in as yet and its drop glue is special + // despite having a dummy Drop impl in the library. assert!(!skip_dtor); let content_ty = t.boxed_ty(); let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) { From a5d725cc82f0b3ca99d3d6fc157b0a28da4ddf9b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 30 Jan 2017 23:18:22 +0300 Subject: [PATCH 087/104] cleanup: Refactor away `DtorKind` --- src/librustc/ty/mod.rs | 25 +------------------------ src/librustc_trans/glue.rs | 2 +- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index db21d35f990d..5ab45e746e7f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use self::Variance::*; -pub use self::DtorKind::*; pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; @@ -120,21 +119,6 @@ pub struct Resolutions { pub maybe_unused_trait_imports: NodeSet, } -#[derive(Copy, Clone)] -pub enum DtorKind { - NoDtor, - TraitDtor -} - -impl DtorKind { - pub fn is_present(&self) -> bool { - match *self { - TraitDtor => true, - _ => false - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum AssociatedItemContainer { TraitContainer(DefId), @@ -1480,7 +1464,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Returns whether this type has a destructor. pub fn has_dtor(&self) -> bool { - self.dtor_kind().is_present() + self.destructor.get().is_some() } /// Asserts this is a struct and returns the struct's unique @@ -1543,13 +1527,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.destructor.set(Some(dtor)); } - pub fn dtor_kind(&self) -> DtorKind { - match self.destructor.get() { - Some(_) => TraitDtor, - None => NoDtor, - } - } - /// Returns a simpler type such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 350c8f950ddf..1415ca6029f5 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -235,7 +235,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi bcx.call(dtor, &[ptr.llval], None); bcx } - ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => { + ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => { let shallow_drop = def.is_union(); let tcx = bcx.tcx(); From 93e3f634b096129227c3863b76a1f303716122f4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 30 Jan 2017 23:18:29 +0300 Subject: [PATCH 088/104] Fix debuginfo scope issue with `Box` --- src/librustc_trans/debuginfo/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index f05d48566daa..e9468e56637d 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -400,7 +400,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyAdt(..) => { + ty::TyAdt(def, ..) if !def.is_box() => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None From d292e1229f1e7cc882e550d3ecc0e152720a0ab5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 30 Jan 2017 12:28:31 -0500 Subject: [PATCH 089/104] compiletest: Clear RUSTFLAGS env-var for run-make tests. --- src/tools/compiletest/src/runtest.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 05d6e21e9aae..86fa5e70c9c2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2175,6 +2175,10 @@ actual:\n\ .env("LLVM_COMPONENTS", &self.config.llvm_components) .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags); + // We don't want RUSTFLAGS set from the outside to interfere with + // compiler flags set in the test cases: + cmd.env_remove("RUSTFLAGS"); + if self.config.target.contains("msvc") { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. From 775b32305f8ec9ed18d6cc8ff13bd8af8f4be14a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Jan 2017 15:21:32 -0800 Subject: [PATCH 090/104] travis: Really delete the `doc` folder Got two location to look at, be sure to delete them both. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5abbdbc599bd..7afa97260f5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -108,11 +108,12 @@ cache: before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT - - rm -rf build/dist/doc - > if [ "$TRAVIS_OS_NAME" == "osx" ]; then + rm -rf build/dist/doc && cp -r build/dist/* deploy/$TRAVIS_COMMIT; else + rm -rf obj/build/dist/doc && cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT; fi From fe324cea6490fc6e7ce16fb5209fde57cfa1b94f Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Tue, 31 Jan 2017 00:57:52 +0100 Subject: [PATCH 091/104] rustdoc: mark ffi functions with unsafety icon --- src/librustdoc/html/render.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 52257653405e..40eb7e5ab78c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1806,12 +1806,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, String::new() }; - let mut unsafety_flag = ""; - if let clean::FunctionItem(ref func) = myitem.inner { - if func.unsafety == hir::Unsafety::Unsafe { - unsafety_flag = "âš "; + let unsafety_flag = match myitem.inner { + clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) + if func.unsafety == hir::Unsafety::Unsafe => { + "âš " } - } + _ => "", + }; let doc_value = myitem.doc_value().unwrap_or(""); write!(w, " From 94e9086685bf0195875037deb3a4dc634bffef60 Mon Sep 17 00:00:00 2001 From: Colm Seale Date: Sun, 22 Jan 2017 23:35:08 +0000 Subject: [PATCH 092/104] [Gate Tests] - marking feature tests Removal of the lang feature gate tests whitelist #39059 r? @est31 --- src/test/compile-fail-fulldeps/gated-macro-reexports.rs | 1 + src/test/compile-fail-fulldeps/gated-quote.rs | 2 ++ src/tools/tidy/src/features.rs | 3 +-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs index b3dbcb743a13..22c92623e1c1 100644 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs @@ -11,6 +11,7 @@ // Test that macro reexports item are gated by `macro_reexport` feature gate. // aux-build:macro_reexport_1.rs +// gate-test-macro_reexport #![crate_type = "dylib"] diff --git a/src/test/compile-fail-fulldeps/gated-quote.rs b/src/test/compile-fail-fulldeps/gated-quote.rs index dade0e946c5b..51a9a87744a2 100644 --- a/src/test/compile-fail-fulldeps/gated-quote.rs +++ b/src/test/compile-fail-fulldeps/gated-quote.rs @@ -15,6 +15,8 @@ // FIXME the error message that is current emitted seems pretty bad. +// gate-test-quote + #![feature(rustc_private)] #![allow(dead_code, unused_imports, unused_variables)] diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 154ebd3649bc..2c3e57c83326 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -166,8 +166,7 @@ pub fn check(path: &Path, bad: &mut bool) { // FIXME get this whitelist empty. let whitelist = vec![ - "abi_ptx", "simd", "macro_reexport", - "static_recursion", "quote", + "abi_ptx", "simd", "static_recursion", "cfg_target_has_atomic", "staged_api", "const_indexing", "unboxed_closures", "stmt_expr_attributes", "cfg_target_thread_local", "unwind_attributes", From b13d9ce2220a9769b526fb65e7d411ada8db34c9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 30 Jan 2017 20:19:00 -0700 Subject: [PATCH 093/104] Add dev and ino to MetadataExt --- src/libstd/sys/redox/ext/fs.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 7ad8d27b4833..fc81cc737d9f 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -160,6 +160,10 @@ impl OpenOptionsExt for OpenOptions { // casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn dev(&self) -> u64; + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn ino(&self) -> u64; #[stable(feature = "metadata_ext", since = "1.1.0")] fn mode(&self) -> u32; #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -184,6 +188,12 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for fs::Metadata { + fn dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } fn mode(&self) -> u32 { self.as_inner().as_inner().st_mode as u32 } From d73e84d2e7a7733d507ed7a3a44af4ab7941ce88 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 31 Jan 2017 14:45:08 +0100 Subject: [PATCH 094/104] use suggestions instead of helps with code in them --- src/librustc_const_eval/eval.rs | 2 -- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++--- src/test/compile-fail/missing-block-hint.rs | 3 ++- src/test/parse-fail/tuple-float-index.rs | 3 ++- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a9dcb1ed8961..47a98155fc4b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//#![allow(non_camel_case_types)] - use rustc::middle::const_val::ConstVal::*; use rustc::middle::const_val::ConstVal; use self::ErrKind::*; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3480db8ec3b7..2532a1def7dd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2456,9 +2456,21 @@ impl<'a> Parser<'a> { Some(f) => f, None => continue, }; - err.help(&format!("try parenthesizing the first index; e.g., `(foo.{}){}`", - float.trunc() as usize, - format!(".{}", fstr.splitn(2, ".").last().unwrap()))); + let sugg = pprust::to_string(|s| { + use print::pprust::PrintState; + use print::pp::word; + s.popen()?; + s.print_expr(&e)?; + word(&mut s.s, ".")?; + s.print_usize(float.trunc() as usize)?; + s.pclose()?; + word(&mut s.s, ".")?; + word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) + }); + err.span_suggestion( + prev_span, + "try parenthesizing the first index", + sugg); } return Err(err); @@ -3900,7 +3912,14 @@ impl<'a> Parser<'a> { if self.eat(&token::Semi) { stmt_span.hi = self.prev_span.hi; } - e.span_help(stmt_span, "try placing this code inside a block"); + let sugg = pprust::to_string(|s| { + use print::pprust::{PrintState, INDENT_UNIT}; + s.ibox(INDENT_UNIT)?; + s.bopen()?; + s.print_stmt(&stmt)?; + s.bclose_maybe_open(stmt.span, INDENT_UNIT, false) + }); + e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); } Err(mut e) => { self.recover_stmt_(SemiColonMode::Break); diff --git a/src/test/compile-fail/missing-block-hint.rs b/src/test/compile-fail/missing-block-hint.rs index 1f29ff4e05c0..6a140e6f21c1 100644 --- a/src/test/compile-fail/missing-block-hint.rs +++ b/src/test/compile-fail/missing-block-hint.rs @@ -15,6 +15,7 @@ fn main() { { if (foo) bar; //~ ERROR expected `{`, found `bar` - //^ HELP try placing this code inside a block + //~^ HELP try placing this code inside a block + //~| SUGGESTION { bar; } } } diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/parse-fail/tuple-float-index.rs index f3f5e3563468..57ad89ad3740 100644 --- a/src/test/parse-fail/tuple-float-index.rs +++ b/src/test/parse-fail/tuple-float-index.rs @@ -12,5 +12,6 @@ fn main () { (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index; e.g., `(foo.1).1` + //~^ HELP try parenthesizing the first index + //~| SUGGESTION ((1, (2, 3)).1).1 } From 4b52600b152a2220dca847046962a6f37a773378 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 31 Jan 2017 13:19:03 -0500 Subject: [PATCH 095/104] update mailmap for @pliniker --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index c44c486831ac..1ae0aae2d01b 100644 --- a/.mailmap +++ b/.mailmap @@ -167,6 +167,7 @@ Ožbolt Menegatti gareins Paul Faria Peer Aramillo Irizar parir Peter Elmers +Peter Liniker Peter Zotov Phil Dawes Phil Dawes Philipp Brüschweiler From 4a07e722c01962aa814f2ae0915dfa84cd4d732a Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 25 Jan 2017 13:11:15 -0600 Subject: [PATCH 096/104] In std:rc, clarify the lack of mutability inside an Rc Also, point to the example in Cell's docs for how to do it. --- src/liballoc/rc.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 010e378ef2f4..6108a06634bb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -17,9 +17,11 @@ //! pointer to the same value in the heap. When the last [`Rc`] pointer to a //! given value is destroyed, the pointed-to value is also destroyed. //! -//! Shared references in Rust disallow mutation by default, and `Rc` is no -//! exception. If you need to mutate through an [`Rc`], use [`Cell`] or -//! [`RefCell`]. +//! Shared references in Rust disallow mutation by default, and [`Rc`] +//! is no exception: you cannot obtain a mutable reference to +//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] +//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability +//! inside an Rc][mutability]. //! //! [`Rc`] uses non-atomic reference counting. This means that overhead is very //! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] @@ -214,6 +216,7 @@ //! [upgrade]: struct.Weak.html#method.upgrade //! [`None`]: ../../std/option/enum.Option.html#variant.None //! [assoc]: ../../book/method-syntax.html#associated-functions +//! [mutability]: ../../std/cell/index.html#introducing-mutability-inside-of-something-immutable #![stable(feature = "rust1", since = "1.0.0")] From 94687aaf58c9a935ed3efb84d0f3b60e00342dcc Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 30 Jan 2017 21:38:13 -0500 Subject: [PATCH 097/104] Removes FIXMEs related to #22405 --- src/libcoretest/hash/mod.rs | 1 - src/libcoretest/iter.rs | 2 -- .../auxiliary/macro_crate_test.rs | 2 -- .../borrowck/borrowck-borrowed-uniq-rvalue.rs | 1 - src/test/compile-fail/cross-borrow-trait.rs | 1 - src/test/compile-fail/dst-bad-assign-2.rs | 1 - src/test/compile-fail/dst-bad-assign.rs | 1 - src/test/compile-fail/issue-10291.rs | 1 - src/test/compile-fail/issue-11515.rs | 1 - src/test/compile-fail/issue-17441.rs | 1 - src/test/compile-fail/issue-17651.rs | 1 - src/test/compile-fail/issue-18783.rs | 2 -- src/test/compile-fail/issue-3763.rs | 2 -- src/test/compile-fail/issue-4335.rs | 1 - src/test/compile-fail/map-types.rs | 1 - ...ased-on-type-no-recursive-stack-closure.rs | 1 - .../region-object-lifetime-in-coercion.rs | 2 -- ...gions-close-associated-type-into-object.rs | 2 -- .../regions-close-param-into-object.rs | 2 -- src/test/compile-fail/regions-nested-fns.rs | 2 -- .../regions-proc-bound-capture.rs | 2 -- .../compile-fail/regions-steal-closure.rs | 1 - .../trait-coercion-generic-bad.rs | 1 - .../trait-coercion-generic-regions.rs | 1 - .../unboxed-closure-illegal-move.rs | 2 -- src/test/compile-fail/unique-pinned-nocopy.rs | 1 - .../auxiliary/macro_crate_test.rs | 3 -- .../auxiliary/plugin_args.rs | 1 - .../deriving-encodable-decodable-box.rs | 1 - src/test/run-pass-valgrind/dst-dtor-1.rs | 1 - src/test/run-pass-valgrind/dst-dtor-2.rs | 1 - ...ciated-types-doubleendediterator-object.rs | 1 - src/test/run-pass/coerce-expect-unsized.rs | 9 ------ src/test/run-pass/deriving-default-box.rs | 1 - .../run-pass/deriving-eq-ord-boxed-slice.rs | 1 - src/test/run-pass/dst-deref-mut.rs | 1 - src/test/run-pass/dst-deref.rs | 1 - src/test/run-pass/dst-struct.rs | 1 - src/test/run-pass/dst-trait.rs | 1 - .../run-pass/empty-allocation-non-null.rs | 3 -- src/test/run-pass/hashmap-memory.rs | 1 - src/test/run-pass/hrtb-precedence-of-plus.rs | 1 - src/test/run-pass/issue-11205.rs | 2 -- src/test/run-pass/issue-11677.rs | 1 - src/test/run-pass/issue-12744.rs | 1 - src/test/run-pass/issue-13808.rs | 1 - src/test/run-pass/issue-14589.rs | 2 -- src/test/run-pass/issue-14919.rs | 1 - src/test/run-pass/issue-16668.rs | 1 - src/test/run-pass/issue-17734.rs | 2 -- src/test/run-pass/issue-20575.rs | 1 - src/test/run-pass/issue-3052.rs | 1 - src/test/run-pass/issue-3609.rs | 1 - src/test/run-pass/newlambdas-ret-infer.rs | 1 - src/test/run-pass/newlambdas-ret-infer2.rs | 1 - src/test/run-pass/regions-fn-subtyping.rs | 2 -- ...ions-on-closures-to-inference-variables.rs | 1 - src/test/run-pass/show-boxed-slice.rs | 1 - src/test/run-pass/trait-bounds-in-arc.rs | 1 - src/test/run-pass/trait-coercion-generic.rs | 1 - src/test/run-pass/trait-coercion.rs | 2 -- ...ed-closures-call-sugar-object-autoderef.rs | 1 - .../unboxed-closures-call-sugar-object.rs | 1 - .../borrowck-call-is-borrow-issue-12224.rs | 2 -- ...borrowck-call-is-borrow-issue-12224.stderr | 32 +++++++++---------- 65 files changed, 16 insertions(+), 108 deletions(-) diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 0d1243381334..53ac17c052f6 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -66,7 +66,6 @@ fn test_writer_hasher() { assert_eq!(hash(& s), 97 + 0xFF); let cs: &[u8] = &[1, 2, 3]; assert_eq!(hash(& cs), 9); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let cs: Box<[u8]> = Box::new([1, 2, 3]); assert_eq!(hash(& cs), 9); diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 99d312930533..6d02f76c33d1 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -700,7 +700,6 @@ fn test_collect() { #[test] fn test_all() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); assert!(v.iter().all(|&x| x < 10)); assert!(!v.iter().all(|&x| x % 2 == 0)); @@ -710,7 +709,6 @@ fn test_all() { #[test] fn test_any() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); assert!(v.iter().any(|&x| x < 10)); assert!(v.iter().any(|&x| x % 2 == 0)); diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index dc88bfc40595..61b1a0a0b4d2 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -36,11 +36,9 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("identity", expand_identity); reg.register_syntax_extension( Symbol::intern("into_multi_foo"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiModifier(Box::new(expand_into_foo_multi))); reg.register_syntax_extension( Symbol::intern("duplicate"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); } diff --git a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs index e4eca7e7eceb..f58eca7c8ae3 100644 --- a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -17,7 +17,6 @@ use std::collections::HashMap; fn main() { let tmp: Box<_>; let mut buggy_map: HashMap = HashMap::new(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough // but it is ok if we use a temporary diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index f389380584b8..e5afccb9cf39 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -16,7 +16,6 @@ trait Trait { fn foo(&self) {} } impl Trait for Foo {} pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let x: Box = Box::new(Foo); let _y: &Trait = x; //~ ERROR mismatched types //~| expected type `&Trait` diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 241fabf053c0..10c8f1eed00b 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -41,7 +41,6 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; //~^ ERROR `ToBar: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 9e71ad241779..4f7d07600ad1 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -41,7 +41,6 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = Bar1 {f: 36}; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 43255db2ff3a..d4e7dc7e9a35 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -9,7 +9,6 @@ // except according to those terms. fn test<'x>(x: &'x isize) { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { x //~ ERROR E0312 })); diff --git a/src/test/compile-fail/issue-11515.rs b/src/test/compile-fail/issue-11515.rs index f682d618ab64..7afb8314ea68 100644 --- a/src/test/compile-fail/issue-11515.rs +++ b/src/test/compile-fail/issue-11515.rs @@ -15,7 +15,6 @@ struct Test { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let closure: Box = Box::new(|| ()); let test = box Test { func: closure }; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index 45ab9903532e..bddc9c13815e 100644 --- a/src/test/compile-fail/issue-17441.rs +++ b/src/test/compile-fail/issue-17441.rs @@ -13,7 +13,6 @@ fn main() { //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` //~^^ HELP consider using an implicit coercion to `&[usize]` instead - // FIXME (#22405): Replace `std::boxed::Box::new` with `box` here when/if possible. let _bar = Box::new(1_usize) as std::fmt::Debug; //~^ ERROR cast to unsized type: `std::boxed::Box` as `std::fmt::Debug` //~^^ HELP try casting to a `Box` instead diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 3ea136aca4be..4996da057dd8 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -12,7 +12,6 @@ // and rejected. fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (|| Box::new(*(&[0][..])))(); //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-18783.rs b/src/test/compile-fail/issue-18783.rs index 5eb3c439df2f..9a7b3781f1e2 100644 --- a/src/test/compile-fail/issue-18783.rs +++ b/src/test/compile-fail/issue-18783.rs @@ -10,8 +10,6 @@ use std::cell::RefCell; -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn main() { let mut y = 1; let c = RefCell::new(vec![]); diff --git a/src/test/compile-fail/issue-3763.rs b/src/test/compile-fail/issue-3763.rs index 085b4e76afbf..851f5dfeabe8 100644 --- a/src/test/compile-fail/issue-3763.rs +++ b/src/test/compile-fail/issue-3763.rs @@ -25,13 +25,11 @@ fn main() { let _woohoo = (&my_struct).priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _woohoo = (Box::new(my_struct)).priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private (&my_struct).happyfun(); //~ ERROR method `happyfun` is private - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (Box::new(my_struct)).happyfun(); //~ ERROR method `happyfun` is private let nope = my_struct.priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 51f5fc5ee98e..c5aae894c3ec 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -13,7 +13,6 @@ fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. id(Box::new(|| *v)) //~^ ERROR E0373 //~| NOTE `v` is borrowed here diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index eaafc312379c..9dcf902a69f9 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -24,7 +24,6 @@ impl Map for HashMap {} fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let y: Box> = Box::new(x); //~^ ERROR `std::boxed::Box>: Map` is not satisfied } diff --git a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs index df9a3519d5d6..d52960659999 100644 --- a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs @@ -38,7 +38,6 @@ fn innocent_looking_victim() { } fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mut r = R {c: Box::new(f)}; f(&mut r, false) //~ ERROR use of moved value } diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index f95ee405895a..687b2c344a3b 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -14,8 +14,6 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn a(v: &[u8]) -> Box { let x: Box = Box::new(v); //~^ ERROR cannot infer an appropriate lifetime due to conflicting diff --git a/src/test/compile-fail/regions-close-associated-type-into-object.rs b/src/test/compile-fail/regions-close-associated-type-into-object.rs index 61897aac1876..6b88abfca6c9 100644 --- a/src/test/compile-fail/regions-close-associated-type-into-object.rs +++ b/src/test/compile-fail/regions-close-associated-type-into-object.rs @@ -10,8 +10,6 @@ #![feature(box_syntax)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait X {} trait Iter { diff --git a/src/test/compile-fail/regions-close-param-into-object.rs b/src/test/compile-fail/regions-close-param-into-object.rs index 7324d4a4a0ed..c9063405bd7e 100644 --- a/src/test/compile-fail/regions-close-param-into-object.rs +++ b/src/test/compile-fail/regions-close-param-into-object.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait X { fn foo(&self) {} } fn p1(v: T) -> Box diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 5ef2a701a600..010b7d176881 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn ignore(t: T) {} fn nested<'x>(x: &'x isize) { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index 48b6e8b773f3..fb726e31af58 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { // This is legal, because the region bound on `proc` // states that it captures `x`. diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index 59fe1ce3af1a..7ca63b9896fe 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -21,7 +21,6 @@ fn box_it<'r>(x: Box) -> closure_box<'r> { fn main() { let mut cl_box = { let mut i = 3; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. box_it(Box::new(|| i += 1)) //~ ERROR `i` does not live long enough }; cl_box.cl.call_mut(()); diff --git a/src/test/compile-fail/trait-coercion-generic-bad.rs b/src/test/compile-fail/trait-coercion-generic-bad.rs index dd64085f6f66..3839e90ed9fe 100644 --- a/src/test/compile-fail/trait-coercion-generic-bad.rs +++ b/src/test/compile-fail/trait-coercion-generic-bad.rs @@ -23,7 +23,6 @@ impl Trait<&'static str> for Struct { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let s: Box> = Box::new(Struct { person: "Fred" }); //~^ ERROR `Struct: Trait` is not satisfied s.f(1); diff --git a/src/test/compile-fail/trait-coercion-generic-regions.rs b/src/test/compile-fail/trait-coercion-generic-regions.rs index 9ba017e150e6..18d3ded77f8f 100644 --- a/src/test/compile-fail/trait-coercion-generic-regions.rs +++ b/src/test/compile-fail/trait-coercion-generic-regions.rs @@ -25,6 +25,5 @@ impl Trait<&'static str> for Struct { fn main() { let person = "Fred".to_string(); let person: &str = &person; //~ ERROR `person` does not live long enough - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let s: Box> = Box::new(Struct { person: person }); } diff --git a/src/test/compile-fail/unboxed-closure-illegal-move.rs b/src/test/compile-fail/unboxed-closure-illegal-move.rs index 564b1b4669f7..427be5607600 100644 --- a/src/test/compile-fail/unboxed-closure-illegal-move.rs +++ b/src/test/compile-fail/unboxed-closure-illegal-move.rs @@ -18,8 +18,6 @@ fn to_fn>(f: F) -> F { f } fn to_fn_mut>(f: F) -> F { f } fn to_fn_once>(f: F) -> F { f } -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn main() { // By-ref cases { diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index d971940db38f..c09feec1d4af 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -18,7 +18,6 @@ impl Drop for r { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let i = Box::new(r { b: true }); let _j = i.clone(); //~ ERROR no method named `clone` found println!("{:?}", i); diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 29cc6b7db947..aa2f1626a6a8 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -38,15 +38,12 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("identity", expand_identity); reg.register_syntax_extension( Symbol::intern("into_multi_foo"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiModifier(Box::new(expand_into_foo_multi))); reg.register_syntax_extension( Symbol::intern("duplicate"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); reg.register_syntax_extension( Symbol::intern("caller"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_caller))); } diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index ba2af77cdb29..3c8868f1664e 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -48,6 +48,5 @@ impl TTMacroExpander for Expander { pub fn plugin_registrar(reg: &mut Registry) { let args = reg.args().to_owned(); reg.register_syntax_extension(Symbol::intern("plugin_args"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. NormalTT(Box::new(Expander { args: args, }), None, false)); } diff --git a/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs index 328cc134f3b1..1573b0807173 100644 --- a/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs @@ -24,7 +24,6 @@ struct A { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let obj = A { foo: Box::new([true, false]) }; let s = json::encode(&obj).unwrap(); let obj2: A = json::decode(&s).unwrap(); diff --git a/src/test/run-pass-valgrind/dst-dtor-1.rs b/src/test/run-pass-valgrind/dst-dtor-1.rs index 995da8c73fab..4af642a106c1 100644 --- a/src/test/run-pass-valgrind/dst-dtor-1.rs +++ b/src/test/run-pass-valgrind/dst-dtor-1.rs @@ -28,7 +28,6 @@ struct Fat { pub fn main() { { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _x: Box> = Box::>::new(Fat { f: Foo }); } unsafe { diff --git a/src/test/run-pass-valgrind/dst-dtor-2.rs b/src/test/run-pass-valgrind/dst-dtor-2.rs index 471169340d79..283b8202b35d 100644 --- a/src/test/run-pass-valgrind/dst-dtor-2.rs +++ b/src/test/run-pass-valgrind/dst-dtor-2.rs @@ -25,7 +25,6 @@ struct Fat { pub fn main() { { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _x: Box> = Box::>::new(Fat { f: [Foo, Foo, Foo] }); } unsafe { diff --git a/src/test/run-pass/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types-doubleendediterator-object.rs index dd194447740b..0a6135080bb6 100644 --- a/src/test/run-pass/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types-doubleendediterator-object.rs @@ -26,7 +26,6 @@ fn pairwise_sub(mut t: Box>) -> isize { fn main() { let v = vec![1, 2, 3, 4, 5, 6]; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let r = pairwise_sub(Box::new(v.into_iter())); assert_eq!(r, 9); } diff --git a/src/test/run-pass/coerce-expect-unsized.rs b/src/test/run-pass/coerce-expect-unsized.rs index e4792e7936bc..a074aea9caa5 100644 --- a/src/test/run-pass/coerce-expect-unsized.rs +++ b/src/test/run-pass/coerce-expect-unsized.rs @@ -19,15 +19,6 @@ use std::rc::Rc; // rvalue expressions to be unsized. See #20169 for more information. pub fn main() { - // FIXME #22405: We cannot infer the type `Box<[isize; k]>` for - // the r-value expression from the context `Box<[isize]>`, and - // therefore the `box EXPR` desugaring breaks down. - // - // One could reasonably claim that the `box EXPR` desugaring is - // effectively regressing half of Issue #20169. Hopefully we will - // eventually fix that, at which point the `Box::new` calls below - // should be replaced wth uses of `box`. - let _: Box<[isize]> = Box::new({ [1, 2, 3] }); let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] }); let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] }); diff --git a/src/test/run-pass/deriving-default-box.rs b/src/test/run-pass/deriving-default-box.rs index dc31e71aad87..c9e5b014da37 100644 --- a/src/test/run-pass/deriving-default-box.rs +++ b/src/test/run-pass/deriving-default-box.rs @@ -21,7 +21,6 @@ struct A { pub fn main() { let a: A = Default::default(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let b: Box<[_]> = Box::<[bool; 0]>::new([]); assert_eq!(a.foo, b); } diff --git a/src/test/run-pass/deriving-eq-ord-boxed-slice.rs b/src/test/run-pass/deriving-eq-ord-boxed-slice.rs index f490cca6a699..16c49065008a 100644 --- a/src/test/run-pass/deriving-eq-ord-boxed-slice.rs +++ b/src/test/run-pass/deriving-eq-ord-boxed-slice.rs @@ -12,7 +12,6 @@ struct Foo(Box<[u8]>); pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let a = Foo(Box::new([0, 1, 2])); let b = Foo(Box::new([0, 1, 2])); assert_eq!(a, b); diff --git a/src/test/run-pass/dst-deref-mut.rs b/src/test/run-pass/dst-deref-mut.rs index 0666e41738e3..9fb4635765ca 100644 --- a/src/test/run-pass/dst-deref-mut.rs +++ b/src/test/run-pass/dst-deref-mut.rs @@ -39,7 +39,6 @@ pub fn foo(arr: &mut Arr) { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mut a = Arr { ptr: Box::new([1, 2, 3]) }; foo(&mut a); } diff --git a/src/test/run-pass/dst-deref.rs b/src/test/run-pass/dst-deref.rs index 957ed13a3d81..4a143873e6e1 100644 --- a/src/test/run-pass/dst-deref.rs +++ b/src/test/run-pass/dst-deref.rs @@ -34,7 +34,6 @@ pub fn foo(arr: &Arr) { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let a = Arr { ptr: Box::new([1, 2, 3]) }; foo(&a); } diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 94efa7a256b4..56199c1aa61f 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -127,7 +127,6 @@ pub fn main() { let f2 : Box> = f1; foo(&*f2); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f3 : Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 9d12a4a34b7d..d8d7d9a28bfb 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -97,7 +97,6 @@ pub fn main() { // &* // - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f7: Box = Box::new(Bar1 {f :42}); bar(&*f7); diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs index af6e321e40aa..3dbe7da6ac70 100644 --- a/src/test/run-pass/empty-allocation-non-null.rs +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - - pub fn main() { assert!(Some(Box::new(())).is_some()); diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 2306fa9afa2e..bd90ce683c45 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -62,7 +62,6 @@ mod map_reduce { } let ctrl_clone = ctrl.clone(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. ::map(input, Box::new(|a,b| emit(&mut intermediates, ctrl.clone(), a, b))); ctrl_clone.send(ctrl_proto::mapper_done).unwrap(); } diff --git a/src/test/run-pass/hrtb-precedence-of-plus.rs b/src/test/run-pass/hrtb-precedence-of-plus.rs index d93e52a8f5fb..516278df178e 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus.rs @@ -17,7 +17,6 @@ // cause a compilation error. Issue #18772. fn adder(y: isize) -> Box isize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |x| y + x) } diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs index 679d494a4730..25c66bf8d485 100644 --- a/src/test/run-pass/issue-11205.rs +++ b/src/test/run-pass/issue-11205.rs @@ -12,8 +12,6 @@ #![allow(dead_code)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait Foo { fn dummy(&self) { } } impl Foo for isize {} fn foo(_: [&Foo; 2]) {} diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs index d4244d44439b..62da3b146755 100644 --- a/src/test/run-pass/issue-11677.rs +++ b/src/test/run-pass/issue-11677.rs @@ -27,6 +27,5 @@ impl X for F { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. S {f: Box::new(F), g: Box::new(F) }; } diff --git a/src/test/run-pass/issue-12744.rs b/src/test/run-pass/issue-12744.rs index 56d1d3599c7f..aec45216b1b7 100644 --- a/src/test/run-pass/issue-12744.rs +++ b/src/test/run-pass/issue-12744.rs @@ -9,7 +9,6 @@ // except according to those terms. fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. fn test() -> Box { Box::new(1) } println!("{:?}", test()) } diff --git a/src/test/run-pass/issue-13808.rs b/src/test/run-pass/issue-13808.rs index c85c0117581a..ccdfa0646c6a 100644 --- a/src/test/run-pass/issue-13808.rs +++ b/src/test/run-pass/issue-13808.rs @@ -16,7 +16,6 @@ struct Foo<'a> { impl<'a> Foo<'a> { fn new(listener: F) -> Foo<'a> where F: FnMut() + 'a { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Foo { listener: Box::new(listener) } } } diff --git a/src/test/run-pass/issue-14589.rs b/src/test/run-pass/issue-14589.rs index b0893e21af7e..8aaa24e991ea 100644 --- a/src/test/run-pass/issue-14589.rs +++ b/src/test/run-pass/issue-14589.rs @@ -11,8 +11,6 @@ // All 3 expressions should work in that the argument gets // coerced to a trait object -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - // pretty-expanded FIXME #23616 fn main() { diff --git a/src/test/run-pass/issue-14919.rs b/src/test/run-pass/issue-14919.rs index d3c9fe9161cc..df5d62e7699b 100644 --- a/src/test/run-pass/issue-14919.rs +++ b/src/test/run-pass/issue-14919.rs @@ -31,7 +31,6 @@ trait IntoMatcher<'a, T> { impl<'a, 'b, F> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for F where F: FnMut(char) -> bool + 'b { fn into_matcher(self, s: &'a str) -> CharPredMatcher<'a, 'b> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. CharPredMatcher { str: s, pred: Box::new(self), diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 18861feb1997..5613211b31df 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -16,7 +16,6 @@ struct Parser<'a, I, O> { impl<'a, I: 'a, O: 'a> Parser<'a, I, O> { fn compose(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Parser { parse: Box::new(move |x: I| { match (self.parse)(x) { diff --git a/src/test/run-pass/issue-17734.rs b/src/test/run-pass/issue-17734.rs index 0fc8eea778da..8178c1fd7c88 100644 --- a/src/test/run-pass/issue-17734.rs +++ b/src/test/run-pass/issue-17734.rs @@ -17,8 +17,6 @@ fn f(s: Box) -> Box { fn main() { // There is currently no safe way to construct a `Box`, so improvise - // - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let box_arr: Box<[u8]> = Box::new(['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8]); let box_str: Box = unsafe { std::mem::transmute(box_arr) }; assert_eq!(&*box_str, "hello"); diff --git a/src/test/run-pass/issue-20575.rs b/src/test/run-pass/issue-20575.rs index e73492e7a7ee..7db7e3b28e8e 100644 --- a/src/test/run-pass/issue-20575.rs +++ b/src/test/run-pass/issue-20575.rs @@ -13,7 +13,6 @@ // pretty-expanded FIXME #23616 fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; let _: Option> = functions.iter().map(|f| (*f)()).collect(); diff --git a/src/test/run-pass/issue-3052.rs b/src/test/run-pass/issue-3052.rs index 8f013ee4f3a0..3b56b2e28ff2 100644 --- a/src/test/run-pass/issue-3052.rs +++ b/src/test/run-pass/issue-3052.rs @@ -13,7 +13,6 @@ type Connection = Box) + 'static>; fn f() -> Option { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mock_connection: Connection = Box::new(|_| {}); Some(mock_connection) } diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index 61de3c6385e7..d1bf7e066cb5 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -26,7 +26,6 @@ fn foo(name: String, samples_chan: Sender) { thread::spawn(move|| { let mut samples_chan = samples_chan; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let callback: SamplesFn = Box::new(move |buffer| { for i in 0..buffer.len() { println!("{}: {}", i, buffer[i]) diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs index 543dbb36b285..428eed0787a8 100644 --- a/src/test/run-pass/newlambdas-ret-infer.rs +++ b/src/test/run-pass/newlambdas-ret-infer.rs @@ -11,7 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. // pretty-expanded FIXME #23616 fn unique() -> Box { return Box::new(|| ()); } diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index e8297173a583..439ea3f2b579 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -11,7 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. // pretty-expanded FIXME #23616 fn unique() -> Box { Box::new(|| ()) } diff --git a/src/test/run-pass/regions-fn-subtyping.rs b/src/test/run-pass/regions-fn-subtyping.rs index fc42fbc714c0..c7a4accff85e 100644 --- a/src/test/run-pass/regions-fn-subtyping.rs +++ b/src/test/run-pass/regions-fn-subtyping.rs @@ -16,8 +16,6 @@ #![allow(unused_variables)] #![allow(unknown_features)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - // Should pass region checking. fn ok(f: Box) { // Here, g is a function that can accept a usize pointer with diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs index 8eee54b3fec6..ae4adbfb1f49 100644 --- a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -31,7 +31,6 @@ struct Foo<'a,'tcx:'a> { impl<'a,'tcx> Foo<'a,'tcx> { fn bother(&mut self) -> isize { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. self.elaborate_bounds(Box::new(|this| { // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, // where `'f0` and `'f1` are fresh, free regions that diff --git a/src/test/run-pass/show-boxed-slice.rs b/src/test/run-pass/show-boxed-slice.rs index 03971668182a..47d0737dfc45 100644 --- a/src/test/run-pass/show-boxed-slice.rs +++ b/src/test/run-pass/show-boxed-slice.rs @@ -12,6 +12,5 @@ struct Foo(Box<[u8]>); pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. println!("{:?}", Foo(Box::new([0, 1, 2]))); } diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 9877dffe9df0..c58442aa58f3 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -105,7 +105,6 @@ fn check_legs(arc: Arc>>) { } fn check_names(arc: Arc>>) { for pet in arc.iter() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. pet.name(Box::new(|name| { assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8); })) diff --git a/src/test/run-pass/trait-coercion-generic.rs b/src/test/run-pass/trait-coercion-generic.rs index f9a22d5ccec6..40453262ddf3 100644 --- a/src/test/run-pass/trait-coercion-generic.rs +++ b/src/test/run-pass/trait-coercion-generic.rs @@ -26,7 +26,6 @@ impl Trait<&'static str> for Struct { pub fn main() { let a = Struct { x: 1, y: 2 }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let b: Box> = Box::new(a); b.f("Mary"); let c: &Trait<&'static str> = &a; diff --git a/src/test/run-pass/trait-coercion.rs b/src/test/run-pass/trait-coercion.rs index d40d9c89f89d..130c6ee7521b 100644 --- a/src/test/run-pass/trait-coercion.rs +++ b/src/test/run-pass/trait-coercion.rs @@ -30,8 +30,6 @@ impl Trait for Struct { fn foo(mut a: Box) {} -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - pub fn main() { let a = Struct { x: 1, y: 2 }; let b: Box = Box::new(a); diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs index a92fb05306f4..789d2237c543 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -15,7 +15,6 @@ use std::ops::FnMut; fn make_adder(x: isize) -> Boxisize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |y| { x + y }) } diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object.rs b/src/test/run-pass/unboxed-closures-call-sugar-object.rs index 5dd2343cfd1d..e73077154717 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object.rs @@ -13,7 +13,6 @@ use std::ops::FnMut; fn make_adder(x: isize) -> Boxisize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |y| { x + y }) } diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index ba1ae64ec330..6264d1118645 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -18,7 +18,6 @@ struct Test<'a> { f: Box } -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. fn call(mut f: F) where F: FnMut(Fn) { f(Box::new(|| { //~^ ERROR: cannot borrow `f` as mutable more than once @@ -58,7 +57,6 @@ fn test6() { fn test7() { fn foo(_: F) where F: FnMut(Box, isize) {} let mut f = |g: Box, b: isize| {}; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. f(Box::new(|a| { foo(f); //~^ ERROR cannot move `f` into closure because it is borrowed diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index f2f0e027f016..58b3f205fe35 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -1,44 +1,44 @@ error[E0499]: cannot borrow `f` as mutable more than once at a time - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:22:16 | -23 | f(Box::new(|| { +22 | f(Box::new(|| { | - ^^ second mutable borrow occurs here | | | first mutable borrow occurs here -24 | //~^ ERROR: cannot borrow `f` as mutable more than once -25 | f((Box::new(|| {}))) +23 | //~^ ERROR: cannot borrow `f` as mutable more than once +24 | f((Box::new(|| {}))) | - borrow occurs due to use of `f` in closure -26 | })); +25 | })); | - first borrow ends here error: cannot borrow immutable borrowed content `*f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5 | -35 | fn test2(f: &F) where F: FnMut() { +34 | fn test2(f: &F) where F: FnMut() { | -- use `&mut F` here to make mutable -36 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable +35 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable | ^^^^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*f.f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:43:5 | -43 | fn test4(f: &Test) { +42 | fn test4(f: &Test) { | ----- use `&mut Test` here to make mutable -44 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable +43 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable | ^^^ cannot borrow as mutable error[E0504]: cannot move `f` into closure because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 | -62 | f(Box::new(|a| { +60 | f(Box::new(|a| { | - borrow of `f` occurs here -63 | foo(f); +61 | foo(f); | ^ move into closure occurs here error[E0507]: cannot move out of captured outer variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 | -63 | foo(f); +61 | foo(f); | ^ cannot move out of captured outer variable in an `FnMut` closure error: aborting due to 5 previous errors From daa509109fb140cdbb6bb391ed361ab9ee502e68 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 26 Jan 2017 22:23:32 -0500 Subject: [PATCH 098/104] Update cell docs --- src/libcore/cell.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index f889ff9a6ae2..ab44342ebf02 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -15,10 +15,18 @@ //! references. We say that `Cell` and `RefCell` provide 'interior mutability', in contrast //! with typical Rust types that exhibit 'inherited mutability'. //! -//! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` provides `get` and `set` -//! methods that change the interior value with a single method call. `Cell` though is only -//! compatible with types that implement `Copy`. For other types, one must use the `RefCell` -//! type, acquiring a write lock before mutating. +//! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` implements interior +//! mutability by moving values in and out of the `Cell`. To use references instead of values, +//! one must use the `RefCell` type, acquiring a write lock before mutating. `Cell` provides +//! methods to retrieve and change the current interior value: +//! +//! - For types that implement `Copy`, the `get` method retrieves the current interior value. +//! - For types that implement `Default`, the `take` method replaces the current interior value +//! with `Default::default()` and returns the replaced value. +//! - For all types, the `replace` method replaces the current interior value and returns the +//! replaced value and the `into_inner` method consumes the `Cell` and returns the interior +//! value. Additionally, the `set` method replaces the interior value, dropping the replaced +//! value. //! //! `RefCell` uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can //! claim temporary, exclusive, mutable access to the inner value. Borrows for `RefCell`s are @@ -179,7 +187,7 @@ use marker::Unsize; use mem; use ops::{Deref, DerefMut, CoerceUnsized}; -/// A mutable memory location that admits only `Copy` data. +/// A mutable memory location. /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] From 8b947a37c8bf396cf80c3790f68253c97d435250 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 Feb 2017 22:53:39 -0500 Subject: [PATCH 099/104] Update Cell references in the book --- src/doc/book/choosing-your-guarantees.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/doc/book/choosing-your-guarantees.md b/src/doc/book/choosing-your-guarantees.md index 9dca3479d35e..17741cac10b7 100644 --- a/src/doc/book/choosing-your-guarantees.md +++ b/src/doc/book/choosing-your-guarantees.md @@ -118,7 +118,8 @@ These types are _generally_ found in struct fields, but they may be found elsewh ## `Cell` -[`Cell`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types. +[`Cell`][cell] is a type that provides zero-cost interior mutability by moving data in and +out of the cell. Since the compiler knows that all the data owned by the contained value is on the stack, there's no worry of leaking any data behind references (or worse!) by simply replacing the data. @@ -160,7 +161,7 @@ This relaxes the “no aliasing with mutability” restriction in places unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your invariants depend on data stored within `Cell`, you should be careful. -This is useful for mutating primitives and other `Copy` types when there is no easy way of +This is useful for mutating primitives and other types when there is no easy way of doing it in line with the static rules of `&` and `&mut`. `Cell` does not let you obtain interior references to the data, which makes it safe to freely @@ -168,16 +169,17 @@ mutate. #### Cost -There is no runtime cost to using `Cell`, however if you are using it to wrap larger (`Copy`) +There is no runtime cost to using `Cell`, however if you are using it to wrap larger structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is otherwise a full copy of the struct. ## `RefCell` -[`RefCell`][refcell] also provides interior mutability, but isn't restricted to `Copy` types. +[`RefCell`][refcell] also provides interior mutability, but doesn't move data in and out of the +cell. -Instead, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's +However, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the `borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when From 80f7db63b6e658468f181d602767c8da412459d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Feb 2017 11:26:44 -0800 Subject: [PATCH 100/104] std: Fix IntoIter::as_mut_slice's signature This was intended to require `&mut self`, not `&self`, otherwise it's unsound! Closes #39465 --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 1f8fd32da9ab..c45518438bd8 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1958,7 +1958,7 @@ impl IntoIter { /// assert_eq!(into_iter.next().unwrap(), 'z'); /// ``` #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] - pub fn as_mut_slice(&self) -> &mut [T] { + pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.ptr as *mut T, self.len()) } From 6c2ef5201abb1f9c4848088cadc89c467dbc0a46 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 27 Jan 2017 01:57:30 +0300 Subject: [PATCH 101/104] rustbuild: Build jemalloc and libbacktrace only once (take 2) --- src/bootstrap/lib.rs | 10 ++++-- src/build_helper/lib.rs | 15 ++++++++ src/liballoc_jemalloc/build.rs | 62 +++++++++++++++------------------- src/libstd/build.rs | 26 ++++++-------- 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index db2fe2db813a..52944f36996f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -482,7 +482,8 @@ impl Build { // // These variables are primarily all read by // src/bootstrap/bin/{rustc.rs,rustdoc.rs} - cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")) + cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) + .env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) @@ -746,10 +747,15 @@ impl Build { } } + /// Directory for libraries built from C/C++ code and shared between stages. + fn native_dir(&self, target: &str) -> PathBuf { + self.out.join(target).join("native") + } + /// Root output directory for rust_test_helpers library compiled for /// `target` fn test_helpers_out(&self, target: &str) -> PathBuf { - self.out.join(target).join("rust-test-helpers") + self.native_dir(target).join("rust-test-helpers") } /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index d0d588f46a75..7784584baf49 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -88,6 +88,21 @@ pub fn output(cmd: &mut Command) -> String { String::from_utf8(output.stdout).unwrap() } +pub fn rerun_if_changed_anything_in_dir(dir: &Path) { + let mut stack = dir.read_dir().unwrap() + .map(|e| e.unwrap()) + .filter(|e| &*e.file_name() != ".git") + .collect::>(); + while let Some(entry) = stack.pop() { + let path = entry.path(); + if entry.file_type().unwrap().is_dir() { + stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } + } +} + fn fail(s: &str) -> ! { println!("\n\n{}\n\n", s); std::process::exit(1); diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 1143df0c6302..e08fc75e9ef6 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -13,20 +13,15 @@ extern crate build_helper; extern crate gcc; -use std::env; +use std::{env, fs}; use std::path::PathBuf; use std::process::Command; -use build_helper::run; +use build_helper::{run, rerun_if_changed_anything_in_dir}; fn main() { println!("cargo:rustc-cfg=cargobuild"); println!("cargo:rerun-if-changed=build.rs"); - let target = env::var("TARGET").expect("TARGET was not set"); - let host = env::var("HOST").expect("HOST was not set"); - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let src_dir = env::current_dir().unwrap(); - // FIXME: This is a hack to support building targets that don't // support jemalloc alongside hosts that do. The jemalloc build is // controlled by a feature of the std crate, and if that feature @@ -35,6 +30,7 @@ fn main() { // that the feature set used by std is the same across all // targets, which means we have to build the alloc_jemalloc crate // for targets like emscripten, even if we don't use it. + let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") || target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") || target.contains("redox") { @@ -57,6 +53,28 @@ fn main() { return; } + let build_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); + let build_dir = PathBuf::from(build_dir).join("jemalloc"); + let _ = fs::create_dir_all(&build_dir); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=static=jemalloc"); + } else { + println!("cargo:rustc-link-lib=static=jemalloc_pic"); + } + println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); + if target.contains("android") { + println!("cargo:rustc-link-lib=gcc"); + } else if !target.contains("windows") && !target.contains("musl") { + println!("cargo:rustc-link-lib=pthread"); + } + if !cfg!(stage0) { + return + } + + let host = env::var("HOST").expect("HOST was not set"); + let src_dir = env::current_dir().unwrap().join("../jemalloc"); + rerun_if_changed_anything_in_dir(&src_dir); let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); @@ -66,23 +84,8 @@ fn main() { .collect::>() .join(" "); - let mut stack = src_dir.join("../jemalloc") - .read_dir() - .unwrap() - .map(|e| e.unwrap()) - .filter(|e| &*e.file_name() != ".git") - .collect::>(); - while let Some(entry) = stack.pop() { - let path = entry.path(); - if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } - } - let mut cmd = Command::new("sh"); - cmd.arg(src_dir.join("../jemalloc/configure") + cmd.arg(src_dir.join("configure") .to_str() .unwrap() .replace("C:\\", "/c/") @@ -158,6 +161,7 @@ fn main() { } run(&mut cmd); + let mut make = Command::new(build_helper::make(&host)); make.current_dir(&build_dir) .arg("build_lib_static"); @@ -170,18 +174,6 @@ fn main() { run(&mut make); - if target.contains("windows") { - println!("cargo:rustc-link-lib=static=jemalloc"); - } else { - println!("cargo:rustc-link-lib=static=jemalloc_pic"); - } - println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); - if target.contains("android") { - println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("windows") && !target.contains("musl") { - println!("cargo:rustc-link-lib=pthread"); - } - // The pthread_atfork symbols is used by jemalloc on android but the really // old android we're building on doesn't have them defined, so just make // sure the symbols are available. diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9504194393f9..faff0d1cb47b 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -13,11 +13,10 @@ extern crate gcc; extern crate build_helper; -use std::env; +use std::{env, fs}; use std::path::PathBuf; use std::process::Command; - -use build_helper::run; +use build_helper::{run, rerun_if_changed_anything_in_dir}; fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -66,24 +65,18 @@ fn main() { } fn build_libbacktrace(host: &str, target: &str) { - let src_dir = env::current_dir().unwrap().join("../libbacktrace"); - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let build_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); + let build_dir = PathBuf::from(build_dir).join("libbacktrace"); + let _ = fs::create_dir_all(&build_dir); println!("cargo:rustc-link-lib=static=backtrace"); println!("cargo:rustc-link-search=native={}/.libs", build_dir.display()); - - let mut stack = src_dir.read_dir().unwrap() - .map(|e| e.unwrap()) - .collect::>(); - while let Some(entry) = stack.pop() { - let path = entry.path(); - if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } + if !cfg!(stage0) { + return } + let src_dir = env::current_dir().unwrap().join("../libbacktrace"); + rerun_if_changed_anything_in_dir(&src_dir); let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); @@ -105,6 +98,7 @@ fn build_libbacktrace(host: &str, target: &str) { .env("AR", &ar) .env("RANLIB", format!("{} s", ar.display())) .env("CFLAGS", cflags)); + run(Command::new(build_helper::make(host)) .current_dir(&build_dir) .arg(format!("INCDIR={}", src_dir.display())) From c0253304ea9d40103dc7d1055b7fa090b48781f8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 28 Jan 2017 16:05:13 +0300 Subject: [PATCH 102/104] Fix build in cross-compilation scenarios --- src/liballoc_jemalloc/build.rs | 4 ++-- src/libstd/build.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index e08fc75e9ef6..c982f98e63de 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -31,6 +31,7 @@ fn main() { // targets, which means we have to build the alloc_jemalloc crate // for targets like emscripten, even if we don't use it. let target = env::var("TARGET").expect("TARGET was not set"); + let host = env::var("HOST").expect("HOST was not set"); if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") || target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") || target.contains("redox") { @@ -68,11 +69,10 @@ fn main() { } else if !target.contains("windows") && !target.contains("musl") { println!("cargo:rustc-link-lib=pthread"); } - if !cfg!(stage0) { + if !cfg!(stage0) && target == host { return } - let host = env::var("HOST").expect("HOST was not set"); let src_dir = env::current_dir().unwrap().join("../jemalloc"); rerun_if_changed_anything_in_dir(&src_dir); let compiler = gcc::Config::new().get_compiler(); diff --git a/src/libstd/build.rs b/src/libstd/build.rs index faff0d1cb47b..112e48921cb7 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -71,7 +71,7 @@ fn build_libbacktrace(host: &str, target: &str) { println!("cargo:rustc-link-lib=static=backtrace"); println!("cargo:rustc-link-search=native={}/.libs", build_dir.display()); - if !cfg!(stage0) { + if !cfg!(stage0) && target == host { return } From a5b603b1bf1e9d74227a8a3b2f73acd558b952ef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 1 Feb 2017 00:27:51 +0300 Subject: [PATCH 103/104] Build libbacktrace/jemalloc only when their timestamps are older than sources --- src/Cargo.lock | 3 ++ src/bootstrap/compile.rs | 4 +-- src/bootstrap/doc.rs | 3 +- src/bootstrap/lib.rs | 20 ++---------- src/bootstrap/native.rs | 3 +- src/bootstrap/util.rs | 37 ---------------------- src/build_helper/Cargo.toml | 3 ++ src/build_helper/lib.rs | 56 ++++++++++++++++++++++++++++++++++ src/liballoc_jemalloc/build.rs | 17 +++++++---- src/libstd/build.rs | 19 +++++++----- 10 files changed, 94 insertions(+), 71 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 93bbf0f227b1..ec45f45ccb60 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -61,6 +61,9 @@ dependencies = [ [[package]] name = "build_helper" version = "0.1.0" +dependencies = [ + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cargotest" diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7c35151a6d27..776b91028a1a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -21,10 +21,10 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::output; +use build_helper::{output, mtime}; use filetime::FileTime; -use util::{exe, libdir, mtime, is_dylib, copy}; +use util::{exe, libdir, is_dylib, copy}; use {Build, Compiler, Mode}; /// Build the standard library. diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d1c9918a7337..3dc9b8375550 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -22,7 +22,8 @@ use std::io::prelude::*; use std::process::Command; use {Build, Compiler, Mode}; -use util::{up_to_date, cp_r}; +use util::cp_r; +use build_helper::up_to_date; /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book /// `name` into the `out` path. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 52944f36996f..df1218752d1c 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -66,6 +66,7 @@ #![deny(warnings)] +#[macro_use] extern crate build_helper; extern crate cmake; extern crate filetime; @@ -83,24 +84,9 @@ use std::fs::{self, File}; use std::path::{Component, PathBuf, Path}; use std::process::Command; -use build_helper::{run_silent, output}; +use build_helper::{run_silent, output, mtime}; -use util::{exe, mtime, libdir, add_lib_path}; - -/// A helper macro to `unwrap` a result except also print out details like: -/// -/// * The file/line of the panic -/// * The expression that failed -/// * The error itself -/// -/// This is currently used judiciously throughout the build system rather than -/// using a `Result` with `try!`, but this may change one day... -macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), - }) -} +use util::{exe, libdir, add_lib_path}; mod cc; mod channel; diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 4b6fef8edc17..21fc61cc8148 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -28,7 +28,8 @@ use cmake; use gcc; use Build; -use util::{self, up_to_date}; +use util; +use build_helper::up_to_date; /// Compile LLVM for `target`. pub fn llvm(build: &Build, target: &str) { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2ab3776ada09..520514f5fc95 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -20,8 +20,6 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; -use filetime::FileTime; - /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { if target.contains("windows") { @@ -31,13 +29,6 @@ pub fn staticlib(name: &str, target: &str) -> String { } } -/// Returns the last-modified time for `path`, or zero if it doesn't exist. -pub fn mtime(path: &Path) -> FileTime { - fs::metadata(path).map(|f| { - FileTime::from_last_modification_time(&f) - }).unwrap_or(FileTime::zero()) -} - /// Copies a file from `src` to `dst`, attempting to use hard links and then /// falling back to an actually filesystem copy if necessary. pub fn copy(src: &Path, dst: &Path) { @@ -132,34 +123,6 @@ pub fn add_lib_path(path: Vec, cmd: &mut Command) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -/// Returns whether `dst` is up to date given that the file or files in `src` -/// are used to generate it. -/// -/// Uses last-modified time checks to verify this. -pub fn up_to_date(src: &Path, dst: &Path) -> bool { - let threshold = mtime(dst); - let meta = match fs::metadata(src) { - Ok(meta) => meta, - Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), - }; - if meta.is_dir() { - dir_up_to_date(src, &threshold) - } else { - FileTime::from_last_modification_time(&meta) <= threshold - } -} - -fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { - t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { - let meta = t!(e.metadata()); - if meta.is_dir() { - dir_up_to_date(&e.path(), threshold) - } else { - FileTime::from_last_modification_time(&meta) < *threshold - } - }) -} - /// Returns the environment variable which the dynamic library lookup path /// resides in for this platform. pub fn dylib_path_var() -> &'static str { diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 01d704f816bb..f8ade0616a57 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -6,3 +6,6 @@ authors = ["The Rust Project Developers"] [lib] name = "build_helper" path = "lib.rs" + +[dependencies] +filetime = "0.1" diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 7784584baf49..3dfd29380828 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -10,9 +10,30 @@ #![deny(warnings)] +extern crate filetime; + +use std::fs; use std::process::{Command, Stdio}; use std::path::{Path, PathBuf}; +use filetime::FileTime; + +/// A helper macro to `unwrap` a result except also print out details like: +/// +/// * The file/line of the panic +/// * The expression that failed +/// * The error itself +/// +/// This is currently used judiciously throughout the build system rather than +/// using a `Result` with `try!`, but this may change one day... +#[macro_export] +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + pub fn run(cmd: &mut Command) { println!("running: {:?}", cmd); run_silent(cmd); @@ -103,6 +124,41 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path) { } } +/// Returns the last-modified time for `path`, or zero if it doesn't exist. +pub fn mtime(path: &Path) -> FileTime { + fs::metadata(path).map(|f| { + FileTime::from_last_modification_time(&f) + }).unwrap_or(FileTime::zero()) +} + +/// Returns whether `dst` is up to date given that the file or files in `src` +/// are used to generate it. +/// +/// Uses last-modified time checks to verify this. +pub fn up_to_date(src: &Path, dst: &Path) -> bool { + let threshold = mtime(dst); + let meta = match fs::metadata(src) { + Ok(meta) => meta, + Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), + }; + if meta.is_dir() { + dir_up_to_date(src, &threshold) + } else { + FileTime::from_last_modification_time(&meta) <= threshold + } +} + +fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { + t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { + let meta = t!(e.metadata()); + if meta.is_dir() { + dir_up_to_date(&e.path(), threshold) + } else { + FileTime::from_last_modification_time(&meta) < *threshold + } + }) +} + fn fail(s: &str) -> ! { println!("\n\n{}\n\n", s); std::process::exit(1); diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index c982f98e63de..7e616c0ff27c 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -10,13 +10,15 @@ #![deny(warnings)] +#[macro_use] extern crate build_helper; extern crate gcc; -use std::{env, fs}; -use std::path::PathBuf; +use std::env; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{run, rerun_if_changed_anything_in_dir}; +use build_helper::{run, rerun_if_changed_anything_in_dir, up_to_date}; fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -69,12 +71,13 @@ fn main() { } else if !target.contains("windows") && !target.contains("musl") { println!("cargo:rustc-link-lib=pthread"); } - if !cfg!(stage0) && target == host { + let src_dir = env::current_dir().unwrap().join("../jemalloc"); + rerun_if_changed_anything_in_dir(&src_dir); + let timestamp = build_dir.join("rustbuild.timestamp"); + if up_to_date(&Path::new("build.rs"), ×tamp) && up_to_date(&src_dir, ×tamp) { return } - let src_dir = env::current_dir().unwrap().join("../jemalloc"); - rerun_if_changed_anything_in_dir(&src_dir); let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); @@ -184,4 +187,6 @@ fn main() { .file("pthread_atfork_dummy.c") .compile("libpthread_atfork_dummy.a"); } + + t!(File::create(×tamp)); } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 112e48921cb7..a08448217093 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -10,13 +10,15 @@ #![deny(warnings)] -extern crate gcc; +#[macro_use] extern crate build_helper; +extern crate gcc; -use std::{env, fs}; -use std::path::PathBuf; +use std::env; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{run, rerun_if_changed_anything_in_dir}; +use build_helper::{run, rerun_if_changed_anything_in_dir, up_to_date}; fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -71,12 +73,13 @@ fn build_libbacktrace(host: &str, target: &str) { println!("cargo:rustc-link-lib=static=backtrace"); println!("cargo:rustc-link-search=native={}/.libs", build_dir.display()); - if !cfg!(stage0) && target == host { + let src_dir = env::current_dir().unwrap().join("../libbacktrace"); + rerun_if_changed_anything_in_dir(&src_dir); + let timestamp = build_dir.join("rustbuild.timestamp"); + if up_to_date(&Path::new("build.rs"), ×tamp) && up_to_date(&src_dir, ×tamp) { return } - let src_dir = env::current_dir().unwrap().join("../libbacktrace"); - rerun_if_changed_anything_in_dir(&src_dir); let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); @@ -103,4 +106,6 @@ fn build_libbacktrace(host: &str, target: &str) { .current_dir(&build_dir) .arg(format!("INCDIR={}", src_dir.display())) .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + + t!(File::create(×tamp)); } From b4abb72ef0bda4092ca81610d310081d78f51d2a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 2 Feb 2017 23:55:42 +0300 Subject: [PATCH 104/104] Fixup crate versions --- src/Cargo.lock | 4 ++-- src/bootstrap/check.rs | 2 +- src/rustc/std_shim/Cargo.toml | 2 +- src/rustc/test_shim/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index ec45f45ccb60..c058586410da 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -597,7 +597,7 @@ dependencies = [ [[package]] name = "std_shim" -version = "0.1.0" +version = "0.0.0" dependencies = [ "core 0.0.0", "std 0.0.0", @@ -656,7 +656,7 @@ dependencies = [ [[package]] name = "test_shim" -version = "0.1.0" +version = "0.0.0" dependencies = [ "test 0.0.0", ] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 4aca843558fd..19aac0f36bb2 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -383,7 +383,7 @@ pub fn krate(build: &Build, // helper crate, not tested. If it leaks through then it ends up // messing with various mtime calculations and such. if !name.contains("jemalloc") && name != "build_helper" { - cargo.arg("-p").arg(name); + cargo.arg("-p").arg(&format!("{}:0.0.0", name)); } for dep in build.crates[name].deps.iter() { if visited.insert(dep) { diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 7260a8440734..14c9c5544b18 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -21,7 +21,7 @@ [package] name = "std_shim" -version = "0.1.0" +version = "0.0.0" authors = ["The Rust Project Developers"] [lib] diff --git a/src/rustc/test_shim/Cargo.toml b/src/rustc/test_shim/Cargo.toml index ac7842770f5b..6ef613eee062 100644 --- a/src/rustc/test_shim/Cargo.toml +++ b/src/rustc/test_shim/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "test_shim" -version = "0.1.0" +version = "0.0.0" authors = ["The Rust Project Developers"] [lib]