diff --git a/src/doc/reference.md b/src/doc/reference.md index 781b40be768c8..87130c08991c0 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -302,7 +302,7 @@ nonzero_dec: '1' | '2' | '3' | '4' A _character literal_ is a single Unicode character enclosed within two `U+0027` (single-quote) characters, with the exception of `U+0027` itself, -which must be _escaped_ by a preceding U+005C character (`\`). +which must be _escaped_ by a preceding `U+005C` character (`\`). ##### String literals @@ -311,6 +311,19 @@ A _string literal_ is a sequence of any Unicode characters enclosed within two which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw string literal_. +A multi-line string literal may be defined by terminating each line with a +`U+005C` character (`\`) immediately before the newline. This causes the +`U+005C` character, the newline, and all whitespace at the beginning of the +next line to be ignored. + +```rust +let a = "foobar"; +let b = "foo\ + bar"; + +assert_eq!(a,b); +``` + ##### Character escapes Some additional _escapes_ are available in either character or non-raw string diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index 5eb6cd7c5cd3a..587da69d4a6f7 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -18,13 +18,15 @@ the Cargo README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) for specific instructions about installing it. +## Converting to Cargo + Let's convert Hello World to Cargo. To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` configuration file, and put our source file in the right place. Let's do that part first: -```{bash} +```bash $ mkdir src $ mv main.rs src/main.rs ``` @@ -36,7 +38,7 @@ place for everything, and everything in its place. Next, our configuration file: -```{bash} +```bash $ editor Cargo.toml ``` @@ -73,7 +75,7 @@ well as what it is named. Once you have this file in place, we should be ready to build! Try this: -```{bash} +```bash $ cargo build Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) $ ./target/hello_world @@ -103,6 +105,62 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our program is simple, it's using much of the real tooling that you'll use for the rest of your Rust career. +## A New Project + +You don't have to go through this whole process every time you want to start a new +project! Cargo has the ability to make a bare-bones project directory in which you +can start developing right away. + +To start a new project with Cargo, use `cargo new`: + +```bash +$ cargo new hello_world --bin +``` + +We're passing `--bin` because we're making a binary program: if we +were making a library, we'd leave it off. + +Let's check out what Cargo has generated for us: + +```bash +$ cd hello_world +$ tree . +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +If you don't have the `tree` command, you can probably get it from your distro's package +manager. It's not necessary, but it's certainly useful. + +This is all we need to get started. First, let's check out `Cargo.toml`: + +```toml +[package] + +name = "hello_world" +version = "0.0.1" +authors = ["Your Name "] +``` + +Cargo has populated this file with reasonable defaults based off the arguments you gave +it and your `git` global configuration. You may notice that Cargo has also initialized +the `hello_world` directory as a `git` repository. + +Here's what's in `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for us, and you're ready to start coding! A +much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). + Now that you've got the tools down, let's actually learn more about the Rust language itself. These are the basics that will serve you well through the rest -of your time with Rust. +of your time with Rust. \ No newline at end of file diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index b4ccf93043729..c49c25b8081a4 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -637,8 +637,8 @@ pub trait IteratorExt: Iterator + Sized { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn all(self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { - for x in self { if !f(x) { return false; } } + fn all(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { + for x in self.by_ref() { if !f(x) { return false; } } true } @@ -1637,8 +1637,6 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool for x in self.iter.by_ref() { if (self.predicate)(&x) { return Some(x); - } else { - continue } } None diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 6c934a998de2d..868a671b9560e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -275,7 +275,13 @@ macro_rules! impls{ /// any methods, but instead is used to gate access to data. /// /// FIXME. Better documentation needed here! -pub trait MarkerTrait : PhantomFn { } +pub trait MarkerTrait : PhantomFn { } +// ~~~~~ <-- FIXME(#22806)? +// +// Marker trait has been made invariant so as to avoid inf recursion, +// but we should ideally solve the underlying problem. That's a bit +// complicated. + impl MarkerTrait for T { } /// `PhantomFn` is a marker trait for use with traits that contain diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bca73782491bf..b8271562d2e67 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -641,9 +641,9 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, res: Result) -> Result { + pub fn or(self, res: Result) -> Result { match self { - Ok(_) => self, + Ok(v) => Ok(v), Err(_) => res, } } diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index ab7b5101e726a..10cc3ad642427 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -36,10 +36,10 @@ pub fn test_and_then() { #[test] pub fn test_or() { - assert_eq!(op1().or(Ok(667)).unwrap(), 666); + assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666); assert_eq!(op1().or(Err("bad")).unwrap(), 666); - assert_eq!(op2().or(Ok(667)).unwrap(), 667); + assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667); assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad"); } diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index f4d3e975b75b9..0682891147146 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -134,11 +134,7 @@ pub trait Reseeder { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. #[derive(Copy)] -pub struct ReseedWithDefault { __hack: [u8; 0] } -// FIXME(#21721) used to be an unit struct but that can cause -// certain LLVM versions to abort during optimizations. -#[allow(non_upper_case_globals)] -pub const ReseedWithDefault: ReseedWithDefault = ReseedWithDefault { __hack: [] }; +pub struct ReseedWithDefault; impl Reseeder for ReseedWithDefault { fn reseed(&mut self, rng: &mut R) { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a4f69e651df60..eed26ccdd9c20 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1885,7 +1885,8 @@ impl LintPass for UnconditionalRecursion { for call in &self_call_spans { sess.span_note(*call, "recursive call site") } - sess.span_help(sp, "a `loop` may express intention better if this is on purpose") + sess.fileline_help(sp, "a `loop` may express intention \ + better if this is on purpose") } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 07082d818769c..4f947b79a7579 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -353,7 +353,7 @@ impl<'a> Context<'a> { } } if self.rejected_via_kind.len() > 0 { - self.sess.span_help(self.span, "please recompile this crate using \ + self.sess.fileline_help(self.span, "please recompile this crate using \ --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { diff --git a/src/librustc/metadata/macro_import.rs b/src/librustc/metadata/macro_import.rs index d25dc4f58a5df..19a29b8eb1b33 100644 --- a/src/librustc/metadata/macro_import.rs +++ b/src/librustc/metadata/macro_import.rs @@ -84,7 +84,7 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { } "plugin" => { self.sess.span_err(attr.span, "#[plugin] on `extern crate` is deprecated"); - self.sess.span_help(attr.span, &format!("use a crate attribute instead, \ + self.sess.fileline_help(attr.span, &format!("use a crate attribute instead, \ i.e. #![plugin({})]", item.ident.as_str())); } diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 17fd80ceaea42..09da93477aba9 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -68,7 +68,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) Some(d) => d.full_def() }; if let def::DefPrimTy(nty) = def { - Some(prim_ty_to_ty(tcx, &path.segments[], nty)) + Some(prim_ty_to_ty(tcx, &path.segments[..], nty)) } else { None } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c409c8fb13f14..6667b550dd722 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -252,7 +252,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", &token::get_ident(ident.node), ty_to_string(cx.tcx, pat_ty)); - span_help!(cx.tcx.sess, p.span, + fileline_help!(cx.tcx.sess, p.span, "if you meant to match on a variant, \ consider making the path in the pattern qualified: `{}::{}`", ty_to_string(cx.tcx, pat_ty), &token::get_ident(ident.node)); diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index da4df813030c3..a7f5c2c843711 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -444,7 +444,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { // Does the required lifetime have a nice name we can print? span_err!(self.tcx.sess, origin.span(), E0309, "{} may not live long enough", labeled_user_string); - self.tcx.sess.span_help( + self.tcx.sess.fileline_help( origin.span(), &format!( "consider adding an explicit lifetime bound `{}: {}`...", @@ -456,7 +456,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { // Does the required lifetime have a nice name we can print? span_err!(self.tcx.sess, origin.span(), E0310, "{} may not live long enough", labeled_user_string); - self.tcx.sess.span_help( + self.tcx.sess.fileline_help( origin.span(), &format!( "consider adding an explicit lifetime bound `{}: 'static`...", @@ -468,7 +468,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span_err!(self.tcx.sess, origin.span(), E0311, "{} may not live long enough", labeled_user_string); - self.tcx.sess.span_help( + self.tcx.sess.fileline_help( origin.span(), &format!( "consider adding an explicit lifetime bound for `{}`", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 78b8d4f7b1e28..4419dd88f80c0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3896,7 +3896,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) let types_a = substs_a.types.get_slice(subst::TypeSpace); let types_b = substs_b.types.get_slice(subst::TypeSpace); - let pairs = types_a.iter().zip(types_b.iter()); + let mut pairs = types_a.iter().zip(types_b.iter()); pairs.all(|(&a, &b)| same_type(a, b)) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 53761eb14713d..84636ebaae42b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -165,7 +165,7 @@ fn note_move_destination(bccx: &BorrowckCtxt, bccx.span_note( move_to_span, "attempting to move value to here"); - bccx.span_help( + bccx.fileline_help( move_to_span, &format!("to prevent the move, \ use `ref {0}` or `ref mut {0}` to capture value by \ diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 67462ab01003e..ff5bde3282f5d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -643,7 +643,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ol, moved_lp_msg, pat_ty.user_string(self.tcx))); - self.tcx.sess.span_help(span, + self.tcx.sess.fileline_help(span, "use `ref` to override"); } @@ -675,7 +675,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { moved_lp_msg, expr_ty.user_string(self.tcx), suggestion)); - self.tcx.sess.span_help(expr_span, help); + self.tcx.sess.fileline_help(expr_span, help); } } @@ -741,6 +741,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_help(s, m); } + pub fn fileline_help(&self, s: Span, m: &str) { + self.tcx.sess.fileline_help(s, m); + } + pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String { match err.code { err_mutbl => { @@ -870,7 +874,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } if is_closure { - self.tcx.sess.span_help( + self.tcx.sess.fileline_help( span, "closures behind references must be called via `&mut`"); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 95523be68c3bf..84020d83db54c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2985,7 +2985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { let msg = format!("use of undeclared trait name `{}`", self.path_names_to_string(trait_path, path_depth)); - self.resolve_error(trait_path.span, &msg[]); + self.resolve_error(trait_path.span, &msg[..]); Err(()) } } @@ -4115,10 +4115,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { uses it like a function name", path_name)); - self.session.span_help(expr.span, - &format!("Did you mean to write: \ - `{} {{ /* fields */ }}`?", - path_name)); + let msg = format!("Did you mean to write: \ + `{} {{ /* fields */ }}`?", + path_name); + if self.emit_errors { + self.session.fileline_help(expr.span, &msg); + } else { + self.session.span_help(expr.span, &msg); + } } else { // Write the result into the def map. debug!("(resolving expr) resolved `{}`", @@ -4146,18 +4150,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match type_res.map(|r| r.base_def) { Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => { - self.resolve_error(expr.span, + self.resolve_error(expr.span, &format!("`{}` is a structure name, but \ this expression \ uses it like a function name", path_name)); - self.session.span_help(expr.span, - &format!("Did you mean to write: \ - `{} {{ /* fields */ }}`?", - path_name)); - - } + let msg = format!("Did you mean to write: \ + `{} {{ /* fields */ }}`?", + path_name); + if self.emit_errors { + self.session.fileline_help(expr.span, &msg); + } else { + self.session.span_help(expr.span, &msg); + } + } _ => { // Keep reporting some errors even if they're ignored above. self.resolve_path(expr.id, path, 0, ValueNS, true); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index efae76c5ef41c..b0383e355e489 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -440,7 +440,7 @@ fn gate_simd_ffi(tcx: &ty::ctxt, decl: &ast::FnDecl, ty: &ty::BareFnTy) { &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", pprust::ty_to_string(ast_ty))); - tcx.sess.span_help(ast_ty.span, + tcx.sess.fileline_help(ast_ty.span, "add #![feature(simd_ffi)] to the crate attributes to enable"); } }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 844635117b5e9..dec18bd62677e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -212,18 +212,18 @@ pub fn opt_ast_region_to_region<'tcx>( } } if len == 1 { - span_help!(this.tcx().sess, default_span, + fileline_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ the signature does not say which {} it is borrowed from", m); } else if len == 0 { - span_help!(this.tcx().sess, default_span, + fileline_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ there is no value for it to be borrowed from"); - span_help!(this.tcx().sess, default_span, + fileline_help!(this.tcx().sess, default_span, "consider giving it a 'static lifetime"); } else { - span_help!(this.tcx().sess, default_span, + fileline_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ the signature does not say whether it is borrowed from {}", m); @@ -705,7 +705,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( span_err!(this.tcx().sess, span, E0215, "angle-bracket notation is not stable when \ used with the `Fn` family of traits, use parentheses"); - span_help!(this.tcx().sess, span, + fileline_help!(this.tcx().sess, span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to enable"); } @@ -719,7 +719,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( span_err!(this.tcx().sess, span, E0216, "parenthetical notation is only stable when \ used with the `Fn` family of traits"); - span_help!(this.tcx().sess, span, + fileline_help!(this.tcx().sess, span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to enable"); } @@ -944,14 +944,14 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, pprust::ty_to_string(ty)); match ty.node { ast::TyRptr(None, ref mut_ty) => { - span_help!(this.tcx().sess, ty.span, + fileline_help!(this.tcx().sess, ty.span, "perhaps you meant `&{}({} +{})`? (per RFC 438)", ppaux::mutability_to_string(mut_ty.mutbl), pprust::ty_to_string(&*mut_ty.ty), pprust::bounds_to_string(bounds)); } ast::TyRptr(Some(ref lt), ref mut_ty) => { - span_help!(this.tcx().sess, ty.span, + fileline_help!(this.tcx().sess, ty.span, "perhaps you meant `&{} {}({} +{})`? (per RFC 438)", pprust::lifetime_to_string(lt), ppaux::mutability_to_string(mut_ty.mutbl), @@ -960,7 +960,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, } _ => { - span_help!(this.tcx().sess, ty.span, + fileline_help!(this.tcx().sess, ty.span, "perhaps you forgot parentheses? (per RFC 438)"); } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0ad15456df98f..e88da5100c0ef 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -63,7 +63,7 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: span_err!(tcx.sess, span, E0174, "explicit use of unboxed closure method `{}` is experimental", method); - span_help!(tcx.sess, span, + fileline_help!(tcx.sess, span, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index ce67369ca9dda..1454c7afcb7c9 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -14,8 +14,9 @@ use middle::infer; use middle::region; use middle::subst; use middle::ty::{self, Ty}; -use util::ppaux::{Repr}; +use util::ppaux::{Repr, UserString}; +use syntax::ast; use syntax::codemap::Span; pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, @@ -28,23 +29,85 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> // types that have been traversed so far by `traverse_type_if_unseen` let mut breadcrumbs: Vec> = Vec::new(); - iterate_over_potentially_unsafe_regions_in_type( + let result = iterate_over_potentially_unsafe_regions_in_type( rcx, &mut breadcrumbs, + TypeContext::Root, typ, span, scope, 0); + match result { + Ok(()) => {} + Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { + let tcx = rcx.tcx(); + span_err!(tcx.sess, span, E0320, + "overflow while adding drop-check rules for {}", + typ.user_string(rcx.tcx())); + match *ctxt { + TypeContext::Root => { + // no need for an additional note if the overflow + // was somehow on the root. + } + TypeContext::EnumVariant { def_id, variant, arg_index } => { + // FIXME (pnkfelix): eventually lookup arg_name + // for the given index on struct variants. + span_note!( + rcx.tcx().sess, + span, + "overflowed on enum {} variant {} argument {} type: {}", + ty::item_path_str(tcx, def_id), + variant, + arg_index, + detected_on_typ.user_string(rcx.tcx())); + } + TypeContext::Struct { def_id, field } => { + span_note!( + rcx.tcx().sess, + span, + "overflowed on struct {} field {} type: {}", + ty::item_path_str(tcx, def_id), + field, + detected_on_typ.user_string(rcx.tcx())); + } + } + } + } +} + +enum Error<'tcx> { + Overflow(TypeContext, ty::Ty<'tcx>), +} + +enum TypeContext { + Root, + EnumVariant { + def_id: ast::DefId, + variant: ast::Name, + arg_index: usize, + }, + Struct { + def_id: ast::DefId, + field: ast::Name, + } } fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( rcx: &mut Rcx<'a, 'tcx>, breadcrumbs: &mut Vec>, + context: TypeContext, ty_root: ty::Ty<'tcx>, span: Span, scope: region::CodeExtent, - depth: uint) + depth: uint) -> Result<(), Error<'tcx>> { + // Issue #22443: Watch out for overflow. While we are careful to + // handle regular types properly, non-regular ones cause problems. + let recursion_limit = rcx.tcx().sess.recursion_limit.get(); + if depth >= recursion_limit { + return Err(Error::Overflow(context, ty_root)) + } + let origin = |&:| infer::SubregionOrigin::SafeDestructor(span); let mut walker = ty_root.walk(); let opt_phantom_data_def_id = rcx.tcx().lang_items.phantom_data(); @@ -240,13 +303,17 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( struct_did, field.id, substs); - iterate_over_potentially_unsafe_regions_in_type( + try!(iterate_over_potentially_unsafe_regions_in_type( rcx, breadcrumbs, + TypeContext::Struct { + def_id: struct_did, + field: field.name, + }, field_type, span, scope, - depth+1) + depth+1)) } } @@ -260,14 +327,19 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( enum_did, substs); for variant_info in all_variant_info.iter() { - for argument_type in variant_info.args.iter() { - iterate_over_potentially_unsafe_regions_in_type( + for (i, arg_type) in variant_info.args.iter().enumerate() { + try!(iterate_over_potentially_unsafe_regions_in_type( rcx, breadcrumbs, - *argument_type, + TypeContext::EnumVariant { + def_id: enum_did, + variant: variant_info.name, + arg_index: i, + }, + *arg_type, span, scope, - depth+1) + depth+1)); } } } @@ -290,4 +362,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( // is done. } } + + return Ok(()); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd6ba79ec21bb..2af132d8b5ee0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3098,7 +3098,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, expr_t, None); - tcx.sess.span_help(field.span, + tcx.sess.fileline_help(field.span, "maybe a `()` to call it is missing? \ If not, try an anonymous function"); } else { @@ -4480,7 +4480,7 @@ pub fn check_instantiable(tcx: &ty::ctxt, span_err!(tcx.sess, sp, E0073, "this type cannot be instantiated without an \ instance of itself"); - span_help!(tcx.sess, sp, "consider using `Option<{}>`", + fileline_help!(tcx.sess, sp, "consider using `Option<{}>`", ppaux::ty_to_string(tcx, item_ty)); false } else { diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e024526d0016f..ee56757510623 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -400,7 +400,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { match suggested_marker_id { Some(def_id) => { - self.tcx().sess.span_help( + self.tcx().sess.fileline_help( span, format!("consider removing `{}` or using a marker such as `{}`", param_name.user_string(self.tcx()), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1913b55f1d8e6..100b4689f6b76 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -524,7 +524,7 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: return // everything OK }; span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name); - span_help!(tcx.sess, sp, + fileline_help!(tcx.sess, sp, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 74fed6cbf3937..9e63382acb1bd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1217,7 +1217,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ which traits can use parenthetical notation"); - span_help!(ccx.tcx.sess, it.span, + fileline_help!(ccx.tcx.sess, it.span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to use it"); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7b43a9fef06dc..3bd15fbc7dbea 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -174,7 +174,8 @@ register_diagnostics! { E0249, // expected constant expr for array length E0250, // expected constant expr for array length E0318, // can't create default impls for traits outside their crates - E0319 // trait impls for defaulted traits allowed just for structs/enums + E0319, // trait impls for defaulted traits allowed just for structs/enums + E0320 // recursive overflow during dropck } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 20ceff0aa6931..209460df10b7c 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -12,6 +12,8 @@ use ops::Sub; use time::Duration; use sync::{Once, ONCE_INIT}; +const NANOS_PER_SEC: i64 = 1_000_000_000; + pub struct SteadyTime { t: libc::LARGE_INTEGER, } @@ -24,7 +26,7 @@ impl SteadyTime { } pub fn ns(&self) -> u64 { - self.t as u64 * 1_000_000_000 / frequency() as u64 + mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64 } } @@ -45,6 +47,27 @@ impl<'a> Sub for &'a SteadyTime { fn sub(self, other: &SteadyTime) -> Duration { let diff = self.t as i64 - other.t as i64; - Duration::microseconds(diff * 1_000_000 / frequency() as i64) + Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64)) } } + +// Computes (value*numer)/denom without overflow, as long as both +// (numer*denom) and the overall result fit into i64 (which is the case +// for our time conversions). +fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numer)/denom and simplify. + // r < denom, so (denom*numer) is the upper bound of (r*numer) + q * numer + r * numer / denom +} + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000); +} diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 54689a1f77ad2..055ade46a3f01 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -52,6 +52,13 @@ macro_rules! span_help { }) } +#[macro_export] +macro_rules! fileline_help { + ($session:expr, $span:expr, $($message:tt)*) => ({ + ($session).fileline_help($span, &format!($($message)*)) + }) +} + #[macro_export] macro_rules! register_diagnostics { ($($code:tt),*) => ( diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2ef90f04f7527..85e6a64e29b0a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -725,6 +725,10 @@ impl<'a> ExtCtxt<'a> { self.print_backtrace(); self.parse_sess.span_diagnostic.span_help(sp, msg); } + pub fn fileline_help(&self, sp: Span, msg: &str) { + self.print_backtrace(); + self.parse_sess.span_diagnostic.fileline_help(sp, msg); + } pub fn bug(&self, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.handler().bug(msg); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bea57ae14e4af..8896a8e0c4fd9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -571,7 +571,7 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use"); is_use = true; if let ast::AttrInner = attr.node.style { - fld.cx.span_help(attr.span, "consider an outer attribute, \ + fld.cx.fileline_help(attr.span, "consider an outer attribute, \ #[macro_use] mod ..."); } }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ffc136d5a1d1a..342593908bf23 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -357,7 +357,7 @@ impl<'a> Context<'a> { pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) { diag.span_err(span, explain); - diag.span_help(span, &format!("add #![feature({})] to the \ + diag.fileline_help(span, &format!("add #![feature({})] to the \ crate attributes to enable", feature)); } @@ -365,7 +365,7 @@ pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) { diag.span_warn(span, explain); if diag.handler.can_emit_warnings { - diag.span_help(span, &format!("add #![feature({})] to the \ + diag.fileline_help(span, &format!("add #![feature({})] to the \ crate attributes to silence this warning", feature)); } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a0e2b4dbf5a70..db5583cf13ac1 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -77,7 +77,7 @@ impl<'a> ParserAttr for Parser<'a> { self.span_err(span, "an inner attribute is not permitted in \ this context"); - self.span_help(span, + self.fileline_help(span, "place inner attribute at the top of the module or block"); } ast::AttrInner diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 83d2bb0cc70a9..31716ef243a49 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -772,7 +772,7 @@ impl<'a> StringReader<'a> { self.span_diagnostic .span_warn(sp, "\\U00ABCD12 and \\uABCD escapes are deprecated"); self.span_diagnostic - .span_help(sp, "use \\u{ABCD12} escapes instead"); + .fileline_help(sp, "use \\u{ABCD12} escapes instead"); } /// Scan for a single (possibly escaped) byte or char diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 4d099529cb49a..95ed4880a5b6f 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -722,7 +722,7 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> &suf[1..])); } else { sd.span_err(sp, &*format!("illegal suffix `{}` for numeric literal", suf)); - sd.span_help(sp, "the suffix must be one of the integral types \ + sd.fileline_help(sp, "the suffix must be one of the integral types \ (`u32`, `isize`, etc)"); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f171e8279f49c..7e280d477b1ab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -973,7 +973,7 @@ impl<'a> Parser<'a> { } pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> ! { self.span_err(sp, m); - self.span_help(sp, help); + self.fileline_help(sp, help); panic!(diagnostic::FatalError); } pub fn span_note(&self, sp: Span, m: &str) { @@ -982,6 +982,9 @@ impl<'a> Parser<'a> { pub fn span_help(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_help(sp, m) } + pub fn fileline_help(&self, sp: Span, m: &str) { + self.sess.span_diagnostic.fileline_help(sp, m) + } pub fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(self.span, m) } @@ -2532,7 +2535,7 @@ impl<'a> Parser<'a> { Some(f) => f, None => continue, }; - self.span_help(last_span, + self.fileline_help(last_span, &format!("try parenthesizing the first index; e.g., `(foo.{}){}`", float.trunc() as usize, &float.fract().to_string()[1..])); @@ -2943,7 +2946,7 @@ impl<'a> Parser<'a> { self.span_err(op_span, "chained comparison operators require parentheses"); if op.node == BiLt && outer_op == BiGt { - self.span_help(op_span, + self.fileline_help(op_span, "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } } @@ -4686,7 +4689,7 @@ impl<'a> Parser<'a> { match visa { Public => { self.span_err(span, "can't qualify macro invocation with `pub`"); - self.span_help(span, "try adjusting the macro to put `pub` inside \ + self.fileline_help(span, "try adjusting the macro to put `pub` inside \ the invocation"); } Inherited => (), @@ -5423,7 +5426,7 @@ impl<'a> Parser<'a> { if self.token.is_ident() { self.bump(); } self.span_err(span, "expected `;`, found `as`"); - self.span_help(span, + self.fileline_help(span, &format!("perhaps you meant to enclose the crate name `{}` in \ a string?", the_ident.as_str())); @@ -5734,7 +5737,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Mut) { let last_span = self.last_span; self.span_err(last_span, "const globals cannot be mutable"); - self.span_help(last_span, "did you mean to declare a static?"); + self.fileline_help(last_span, "did you mean to declare a static?"); } let (ident, item_, extra_attrs) = self.parse_item_const(None); let last_span = self.last_span; diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index 6b412c47cd7f8..896b0ee57a04c 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -40,9 +40,7 @@ fn run(repeat: int, depth: int) { } } -// FIXME(#21721) used to be `List<()>` but that can cause -// certain LLVM versions to abort during optimizations. -type nillist = List<[u8; 0]>; +type nillist = List<()>; // Filled with things that have to be unwound @@ -83,11 +81,11 @@ fn recurse_or_panic(depth: int, st: Option) { } Some(st) => { let mut v = st.vec.clone(); - v.push_all(&[box List::Cons([], st.vec.last().unwrap().clone())]); + v.push_all(&[box List::Cons((), st.vec.last().unwrap().clone())]); State { - unique: box List::Cons([], box *st.unique), + unique: box List::Cons((), box *st.unique), vec: v, - res: r(box List::Cons([], st.res._l.clone())), + res: r(box List::Cons((), st.res._l.clone())), } } }; diff --git a/src/test/compile-fail/dropck_no_diverge_on_nonregular_1.rs b/src/test/compile-fail/dropck_no_diverge_on_nonregular_1.rs new file mode 100644 index 0000000000000..f096885381989 --- /dev/null +++ b/src/test/compile-fail/dropck_no_diverge_on_nonregular_1.rs @@ -0,0 +1,37 @@ +// 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. + +// Issue 22443: Reject code using non-regular types that would +// otherwise cause dropck to loop infinitely. + +use std::marker::PhantomData; + +struct Digit { + elem: T +} + +struct Node { m: PhantomData<&'static T> } + + +enum FingerTree { + Single(T), + // Bug report said Digit after Box would stack overflow (versus + // Digit before Box; see dropck_no_diverge_on_nonregular_2). + Deep( + Box>>, + Digit, + ) +} + +fn main() { + let ft = //~ ERROR overflow while adding drop-check rules for FingerTree + FingerTree::Single(1); + //~^ ERROR overflow while adding drop-check rules for FingerTree +} diff --git a/src/test/compile-fail/dropck_no_diverge_on_nonregular_2.rs b/src/test/compile-fail/dropck_no_diverge_on_nonregular_2.rs new file mode 100644 index 0000000000000..886bd6bea20d7 --- /dev/null +++ b/src/test/compile-fail/dropck_no_diverge_on_nonregular_2.rs @@ -0,0 +1,36 @@ +// 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. + +// Issue 22443: Reject code using non-regular types that would +// otherwise cause dropck to loop infinitely. + +use std::marker::PhantomData; + +struct Digit { + elem: T +} + +struct Node { m: PhantomData<&'static T> } + +enum FingerTree { + Single(T), + // Bug report said Digit before Box would infinite loop (versus + // Digit after Box; see dropck_no_diverge_on_nonregular_1). + Deep( + Digit, + Box>>, + ) +} + +fn main() { + let ft = //~ ERROR overflow while adding drop-check rules for FingerTree + FingerTree::Single(1); + //~^ ERROR overflow while adding drop-check rules for FingerTree +} diff --git a/src/test/compile-fail/dropck_no_diverge_on_nonregular_3.rs b/src/test/compile-fail/dropck_no_diverge_on_nonregular_3.rs new file mode 100644 index 0000000000000..f7eb6e10ca788 --- /dev/null +++ b/src/test/compile-fail/dropck_no_diverge_on_nonregular_3.rs @@ -0,0 +1,46 @@ +// 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. + +// Issue 22443: Reject code using non-regular types that would +// otherwise cause dropck to loop infinitely. +// +// This version is just checking that we still sanely handle a trivial +// wrapper around the non-regular type. (It also demonstrates how the +// error messages will report different types depending on which type +// dropck is analyzing.) + +use std::marker::PhantomData; + +struct Digit { + elem: T +} + +struct Node { m: PhantomData<&'static T> } + +enum FingerTree { + Single(T), + // According to the bug report, Digit before Box would infinite loop. + Deep( + Digit, + Box>>, + ) +} + +enum Wrapper { + Simple, + Other(FingerTree), +} + +fn main() { + let w = //~ ERROR overflow while adding drop-check rules for core::option + Some(Wrapper::Simple::); + //~^ ERROR overflow while adding drop-check rules for core::option::Option + //~| ERROR overflow while adding drop-check rules for Wrapper +} diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs index ce5a0aa96e3d3..aa53a7658e129 100644 --- a/src/test/run-pass/issue-17216.rs +++ b/src/test/run-pass/issue-17216.rs @@ -25,9 +25,7 @@ fn main() { let mut dropped = false; { let leak = Leak { dropped: &mut dropped }; - // FIXME(#21721) "hack" used to be () but that can cause - // certain LLVM versions to abort during optimizations. - for (_, leaked) in Some(("hack", leak)).into_iter() {} + for ((), leaked) in Some(((), leak)).into_iter() {} } assert!(dropped); diff --git a/src/test/run-pass/issue-21721.rs b/src/test/run-pass/issue-21721.rs new file mode 100644 index 0000000000000..fee14061c566a --- /dev/null +++ b/src/test/run-pass/issue-21721.rs @@ -0,0 +1,17 @@ +// 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. + +fn main() { + static NONE: Option<((), &'static u8)> = None; + let ptr = unsafe { + *(&NONE as *const _ as *const *const u8) + }; + assert!(ptr.is_null()); +} diff --git a/src/test/run-pass/traits-issue-22655.rs b/src/test/run-pass/traits-issue-22655.rs new file mode 100644 index 0000000000000..18c7cfb0850ce --- /dev/null +++ b/src/test/run-pass/traits-issue-22655.rs @@ -0,0 +1,29 @@ +// 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. + +// Regression test for issue #22655: This test should not lead to +// infinite recursion. + +unsafe impl Send for Unique { } + +pub struct Unique { + pointer: *const T, +} + +pub struct Node { + vals: V, + edges: Unique>, +} + +fn is_send() {} + +fn main() { + is_send::>(); +}