From 84bd1ce9841dbefc30c2ade67964ac652856e8a3 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 28 Apr 2016 20:18:39 +0200 Subject: [PATCH 01/14] Fix std::fmt format spec: named args are allowed with "$" syntax --- src/libcollections/fmt.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 710a30ff2364e..d58c26a72136b 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -333,7 +333,7 @@ //! precision := count | '*' //! type := identifier | '' //! count := parameter | integer -//! parameter := integer '$' +//! parameter := argument '$' //! ``` //! //! # Formatting Parameters @@ -403,11 +403,12 @@ //! println!("Hello {:5}!", "x"); //! println!("Hello {:1$}!", "x", 5); //! println!("Hello {1:0$}!", 5, "x"); +//! println!("Hello {:width$}!", "x", width = 5); //! ``` //! //! Referring to an argument with the dollar syntax does not affect the "next -//! argument" counter, so it's usually a good idea to refer to all arguments by -//! their position explicitly. +//! argument" counter, so it's usually a good idea to refer to arguments by +//! position, or use named arguments. //! //! ## Precision //! @@ -426,7 +427,7 @@ //! //! the integer `N` itself is the precision. //! -//! 2. An integer followed by dollar sign `.N$`: +//! 2. An integer or name followed by dollar sign `.N$`: //! //! use format *argument* `N` (which must be a `usize`) as the precision. //! @@ -456,6 +457,10 @@ //! // Hello {next arg (x)} is {arg 2 (0.01) with precision //! // specified in its predecessor (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); +//! +//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified +//! // in arg "prec" (5)} +//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); //! ``` //! //! All print the same thing: From 538098c7a4bdab205a7057b1925c1dad68382bce Mon Sep 17 00:00:00 2001 From: Stephen Mather Date: Sun, 1 May 2016 19:15:33 +0100 Subject: [PATCH 02/14] doc/book/getting-started.md: Corrected spelling of 'Internet'. --- src/doc/book/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index fc2a762088331..b8435438be796 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -8,7 +8,7 @@ we’ll talk about Cargo, Rust’s build system and package manager. The first step to using Rust is to install it. Generally speaking, you’ll need an Internet connection to run the commands in this section, as we’ll be -downloading Rust from the internet. +downloading Rust from the Internet. We’ll be showing off a number of commands using a terminal, and those lines all start with `$`. We don't need to type in the `$`s, they are there to indicate From 3f49920495c1db358e5964acf8182b96405ce435 Mon Sep 17 00:00:00 2001 From: Timothy McRoy Date: Sun, 1 May 2016 13:41:11 -0500 Subject: [PATCH 03/14] Add error explanation for E0501 --- src/librustc_borrowck/diagnostics.rs | 77 +++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 7f6fd9de3d294..6eccc7082aad4 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -314,6 +314,82 @@ let c = &i; // still ok! ``` "##, +E0501: r##" +This error indicates that a mutable variable is being used while it is still +captured by a closure. Because the closure has borrowed the variable, it is not +available for use until the closure goes out of scope. + +Note that a capture will either move or borrow a variable, but in this +situation, the closure is borrowing the variable. Take a look at +http://rustbyexample.com/fn/closures/capture.html for more information about +capturing. + +Example of erroneous code: + +```compile_fail +fn inside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn outside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn foo(a: &mut i32) { + let bar = || { + inside_closure(a) + }; + outside_closure(a); // error: cannot borrow `*a` as mutable because previous + // closure requires unique access. +} +``` + +To fix this error, you can place the closure in its own scope: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + { + let bar = || { + inside_closure(a) + }; + } // borrow on `a` ends. + outside_closure(a); // ok! +} +``` + +Or you can pass the variable as a parameter to the closure: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let bar = |s: &mut i32| { + inside_closure(s) + }; + outside_closure(a); + bar(a); +} +``` + +It may be possible to define the closure later: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + outside_closure(a); + let bar = || { + inside_closure(a) + }; +} +``` +"##, + E0507: r##" You tried to move out of a value which was borrowed. Erroneous code example: @@ -436,7 +512,6 @@ register_diagnostics! { E0388, // {} in a static location E0389, // {} in a `&` reference E0500, // closure requires unique access to `..` but .. is already borrowed - E0501, // cannot borrow `..`.. as .. because previous closure requires unique access E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ... E0503, // cannot use `..` because it was mutably borrowed E0504, // cannot move `..` into closure because it is borrowed From 018c595574ef78d6f00dcf529914a7a54bac6423 Mon Sep 17 00:00:00 2001 From: Stephen Mather Date: Sun, 1 May 2016 19:45:38 +0100 Subject: [PATCH 04/14] doc/book/getting-started.md: Removed references to creating a new executable from 'Converting to Cargo'. --- src/doc/book/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index b8435438be796..e61a76a2c37a9 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -399,13 +399,13 @@ Let’s convert the Hello World program to Cargo. To Cargo-fy a project, you nee to do three things: 1. Put your source file in the right directory. -2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere else) - and make a new one. +2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere + else). 3. Make a Cargo configuration file. Let's get started! -### Creating a new Executable and Source Directory +### Creating a Source Directory and Removing the Old Executable First, go back to your terminal, move to your *hello_world* directory, and enter the following commands: From 12c4a1951e85925dbccc40efb163f4f179c30046 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 11:02:44 +0200 Subject: [PATCH 05/14] remove unused constant error variants --- src/librustc_const_eval/eval.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c2ac3d838c8d0..4fd4daf09980b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -377,13 +377,6 @@ pub enum ErrKind { NotOn(ConstVal), CallOn(ConstVal), - NegateWithOverflow(i64), - AddiWithOverflow(i64, i64), - SubiWithOverflow(i64, i64), - MuliWithOverflow(i64, i64), - AdduWithOverflow(u64, u64), - SubuWithOverflow(u64, u64), - MuluWithOverflow(u64, u64), DivideByZero, DivideWithOverflow, ModuloByZero, @@ -439,13 +432,6 @@ impl ConstEvalErr { NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(), - NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(), - AddiWithOverflow(..) => "attempted to add with overflow".into_cow(), - SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(), - MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(), - AdduWithOverflow(..) => "attempted to add with overflow".into_cow(), - SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(), - MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(), DivideByZero => "attempted to divide by zero".into_cow(), DivideWithOverflow => "attempted to divide with overflow".into_cow(), ModuloByZero => "attempted remainder with a divisor of zero".into_cow(), From bf51eafbef4d949673a17ae1f2cc478bcc8c0b58 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 11:26:29 +0200 Subject: [PATCH 06/14] check for wrong const_err warnings --- src/librustc_const_eval/eval.rs | 26 ++++++++++++-------------- src/test/run-pass/const-err.rs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/const-err.rs diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4fd4daf09980b..1bd9b37b644b3 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -408,6 +408,7 @@ pub enum ErrKind { TypeMismatch(String, ConstInt), BadType(ConstVal), ErroneousReferencedConstant(Box), + BadCharValue, } impl From for ErrKind { @@ -468,6 +469,7 @@ impl ConstEvalErr { }, BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), + BadCharValue => "invalid numeric value for char".into_cow(), } } } @@ -1075,23 +1077,19 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))), } }, - ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => { - // FIXME: this could probably be prettier - // there's no easy way to turn an `Infer` into a f64 - let val = (-val).map_err(Math)?; - let val = val.to_u64().unwrap() as f64; - let val = -val; - Ok(Float(val)) + ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { + Infer(u) => Ok(Float(u as f64)), + InferSigned(i) => Ok(Float(i as f64)), + _ => unreachable!(), }, - ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)), - ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => { - let val = (-val).map_err(Math)?; - let val = val.to_u64().unwrap() as f32; - let val = -val; - Ok(Float(val as f64)) + ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { + Infer(u) => Ok(Float(u as f32 as f64)), + InferSigned(i) => Ok(Float(i as f32 as f64)), + _ => unreachable!(), }, - ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)), ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), + ty::TyChar if v as u32 as u64 == v => ::std::char::from_u32(v as u32).map(Char) + .ok_or(BadCharValue), _ => Err(CannotCast), } } diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs new file mode 100644 index 0000000000000..8d7ac4f54c131 --- /dev/null +++ b/src/test/run-pass/const-err.rs @@ -0,0 +1,19 @@ +// 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. + +// check for const_err regressions + +#![deny(const_err)] + + +fn main() { + let _ = ((-1 as i8) << 8 - 1) as f32; + let _ = 0u8 as char; +} From 98d991fac531d9a437a697dc7ad29967c978a3d3 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 15:09:36 +0200 Subject: [PATCH 07/14] parser: change warning into an error on `T` Fixes: #32214 --- src/libsyntax/parse/parser.rs | 6 +----- src/test/parse-fail/issue-32214.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 src/test/parse-fail/issue-32214.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 671a11b57dec1..e5780c706081e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4420,11 +4420,7 @@ impl<'a> Parser<'a> { p.forbid_lifetime()?; let lo = p.span.lo; let ident = p.parse_ident()?; - let found_eq = p.eat(&token::Eq); - if !found_eq { - let span = p.span; - p.span_warn(span, "whoops, no =?"); - } + p.expect(&token::Eq)?; let ty = p.parse_ty()?; let hi = ty.span.hi; let span = mk_sp(lo, hi); diff --git a/src/test/parse-fail/issue-32214.rs b/src/test/parse-fail/issue-32214.rs new file mode 100644 index 0000000000000..3ba59c8ee946b --- /dev/null +++ b/src/test/parse-fail/issue-32214.rs @@ -0,0 +1,17 @@ +// 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. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +pub fn test >() { + //~^ ERROR expected `=`, found `>` +} + +fn main() { } From 10737a5a45ed9a1d9ae73b996fae893da1d62512 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:38:33 +0200 Subject: [PATCH 08/14] `* as char` assumes `*` to be of type `u8` --- src/librustc_const_eval/eval.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 1bd9b37b644b3..21eb06dfb97d1 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -408,7 +408,7 @@ pub enum ErrKind { TypeMismatch(String, ConstInt), BadType(ConstVal), ErroneousReferencedConstant(Box), - BadCharValue, + CharCast(ConstInt), } impl From for ErrKind { @@ -469,7 +469,9 @@ impl ConstEvalErr { }, BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), - BadCharValue => "invalid numeric value for char".into_cow(), + CharCast(ref got) => { + format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow() + }, } } } @@ -1080,16 +1082,19 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { Infer(u) => Ok(Float(u as f64)), InferSigned(i) => Ok(Float(i as f64)), - _ => unreachable!(), + _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), }, ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { Infer(u) => Ok(Float(u as f32 as f64)), InferSigned(i) => Ok(Float(i as f32 as f64)), - _ => unreachable!(), + _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), }, ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), - ty::TyChar if v as u32 as u64 == v => ::std::char::from_u32(v as u32).map(Char) - .ok_or(BadCharValue), + ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) { + Ok(U8(u)) => Ok(Char(u as char)), + // can only occur before typeck, typeck blocks `T as char` for `T` != `u8` + _ => Err(CharCast(val)), + }, _ => Err(CannotCast), } } From f080b13c6beaa409c2bb643dd997a73ce0e75b89 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:38:49 +0200 Subject: [PATCH 09/14] tests --- .../compile-fail/const-eval-overflow-4b.rs | 18 +++++++++++------- src/test/run-pass/const-err.rs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 5aa93cf6383fe..31e1a72967f4d 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -15,7 +15,6 @@ #![allow(unused_imports)] -use std::fmt; use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; @@ -26,10 +25,15 @@ const A_I8_T //~| found `u8` [E0250] = [0; (i8::MAX as usize) + 1]; -fn main() { - foo(&A_I8_T[..]); -} -fn foo(x: T) { - println!("{:?}", x); -} +const A_CHAR_USIZE + : [u32; 5u8 as char as usize] + = [0; 5]; + + +const A_BAD_CHAR_USIZE + : [u32; 5i8 as char as usize] + //~^ ERROR only `u8` can be cast as `char`, not `i8` + = [0; 5]; + +fn main() {} diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index 8d7ac4f54c131..30641c1cb87b1 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // From ce6ea47d43e9c646849aad34876a0054da58a1e9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:40:40 +0200 Subject: [PATCH 10/14] refactor infer function There was no span available in the cast function, but we need to infer the `x` in `x as char` to `u8`. The spans are now removed from all functions using `infer` and instead added in `eval_const_expr_partial` --- src/librustc_const_eval/eval.rs | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 21eb06dfb97d1..fc933d567fbd3 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -814,7 +814,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, debug!("const call({:?})", call_args); eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))? }, - hir::ExprLit(ref lit) => lit_to_const(&lit.node, tcx, ety, lit.span)?, + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) { + Ok(val) => val, + Err(err) => signal!(e, err), + }, hir::ExprBlock(ref block) => { match block.expr { Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?, @@ -920,7 +923,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, }; match (ety.map(|t| &t.sty), result) { - (Some(ref ty_hint), Integral(i)) => Ok(Integral(infer(i, tcx, ty_hint, e.span)?)), + (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) { + Ok(inferred) => Ok(Integral(inferred)), + Err(err) => signal!(e, err), + }, (_, result) => Ok(result), } } @@ -929,15 +935,9 @@ fn infer<'tcx>( i: ConstInt, tcx: &TyCtxt<'tcx>, ty_hint: &ty::TypeVariants<'tcx>, - span: Span -) -> Result { +) -> Result { use syntax::ast::*; - let err = |e| ConstEvalErr { - span: span, - kind: e, - }; - match (ty_hint, i) { (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result), (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), @@ -983,17 +983,17 @@ fn infer<'tcx>( Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))), } }, - (&ty::TyUint(_), InferSigned(_)) => Err(err(IntermediateUnsignedNegative)), + (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative), - (&ty::TyInt(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))), - (&ty::TyUint(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))), + (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), + (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyEnum(ref adt, _), i) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(i, tcx, &int_ty.to_ty(tcx).sty, span) + infer(i, tcx, &int_ty.to_ty(tcx).sty) }, - (_, i) => Err(err(BadType(ConstVal::Integral(i)))), + (_, i) => Err(BadType(ConstVal::Integral(i))), } } @@ -1125,7 +1125,7 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind, tcx: &TyCtxt<'tcx>, ty_hint: Option>, span: Span, - ) -> Result { + ) -> Result { use syntax::ast::*; use syntax::ast::LitIntType::*; match *lit { @@ -1133,28 +1133,28 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind, LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), LitKind::Byte(n) => Ok(Integral(U8(n))), LitKind::Int(n, Signed(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral) + infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) }, LitKind::Int(n, Unsuffixed) => { match ty_hint.map(|t| &t.sty) { Some(&ty::TyInt(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral) + infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) }, Some(&ty::TyUint(uty)) => { - infer(Infer(n), tcx, &ty::TyUint(uty), span).map(Integral) + infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) }, None => Ok(Integral(Infer(n))), Some(&ty::TyEnum(ref adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty, span).map(Integral) + infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) }, Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), } }, LitKind::Int(n, Unsigned(ity)) => { - infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral) + infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral) }, LitKind::Float(ref n, _) | From 4ba6bf44bd010c1837fdcb87bbebf67e8abd67d4 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 11:26:34 +0200 Subject: [PATCH 11/14] resolve: print location of static for "static in pattern" error The implementation mirrors the one for "constant defined here" annotation used for constant patterns in the irrefutable-pattern case. Fixes: #23716 --- src/librustc_resolve/lib.rs | 36 +++++++++++++++++++--------- src/test/compile-fail/issue-23716.rs | 29 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/issue-23716.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1674a96c8badc..c36fc771b5e6b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -158,7 +158,7 @@ enum ResolutionError<'a> { /// error E0416: identifier is bound more than once in the same pattern IdentifierBoundMoreThanOnceInSamePattern(&'a str), /// error E0417: static variables cannot be referenced in a pattern - StaticVariableReference, + StaticVariableReference(DefId, Option), /// error E0418: is not an enum variant, struct or const NotAnEnumVariantStructOrConst(&'a str), /// error E0419: unresolved enum variant, struct or const @@ -367,12 +367,24 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, "identifier `{}` is bound more than once in the same pattern", identifier) } - ResolutionError::StaticVariableReference => { - struct_span_err!(resolver.session, - span, - E0417, - "static variables cannot be referenced in a pattern, use a \ - `const` instead") + ResolutionError::StaticVariableReference(did, name) => { + let mut err = struct_span_err!(resolver.session, + span, + E0417, + "static variables cannot be referenced in a \ + pattern, use a `const` instead"); + if let Some(sp) = resolver.ast_map.span_if_local(did) { + err.span_note(sp, "static variable defined here"); + } + if let Some(name) = name { + if let Some(binding) = resolver.current_module + .resolve_name_in_lexical_scope(name, ValueNS) { + if binding.is_import() { + err.span_note(binding.span, "static variable imported here"); + } + } + } + err } ResolutionError::NotAnEnumVariantStructOrConst(name) => { struct_span_err!(resolver.session, @@ -2374,10 +2386,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Def::Variant(..) | Def::Const(..) => { self.record_def(pattern.id, path_res); } - Def::Static(..) => { + Def::Static(did, _) => { resolve_error(&self, path.span, - ResolutionError::StaticVariableReference); + ResolutionError::StaticVariableReference( + did, None)); self.record_def(pattern.id, err_path_resolution()); } _ => { @@ -2517,8 +2530,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(def @ Def::Const(..)) | Some(def @ Def::AssociatedConst(..)) => { FoundConst(def, ident.unhygienic_name) } - Some(Def::Static(..)) => { - resolve_error(self, span, ResolutionError::StaticVariableReference); + Some(Def::Static(did, _)) => { + resolve_error(self, span, ResolutionError::StaticVariableReference( + did, Some(ident.unhygienic_name))); BareIdentifierPatternUnresolved } _ => BareIdentifierPatternUnresolved, diff --git a/src/test/compile-fail/issue-23716.rs b/src/test/compile-fail/issue-23716.rs new file mode 100644 index 0000000000000..c54f901199b46 --- /dev/null +++ b/src/test/compile-fail/issue-23716.rs @@ -0,0 +1,29 @@ +// 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. + +static foo: i32 = 0; +//~^ NOTE static variable defined here + +fn bar(foo: i32) {} +//~^ ERROR static variables cannot be referenced in a pattern, use a `const` instead + +mod submod { + pub static answer: i32 = 42; + //~^ NOTE static variable defined here +} + +use self::submod::answer; +//~^ NOTE static variable imported here + +fn question(answer: i32) {} +//~^ ERROR static variables cannot be referenced in a pattern, use a `const` instead + +fn main() { +} From 237eb7285e5c2d47e4cfdb75116d9ad8e296a6f8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 2 May 2016 13:57:53 -0700 Subject: [PATCH 12/14] libcore: Inline `mem::forget()`. Was causing severe performance problems in WebRender. --- src/libcore/mem.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 2c648d1516bff..5da97127623d0 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -110,6 +110,7 @@ pub use intrinsics::transmute; /// } /// } /// ``` +#[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { unsafe { intrinsics::forget(t) } From 24117f3c589dca680bdfe7e193e52e210770dc79 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 3 May 2016 13:09:42 +0200 Subject: [PATCH 13/14] rustdoc: fix inserting source code spans for constant values This will go wrong when the constants partially result from macro expansion. Instead, use the expressions and pretty-print them as Rust code. Fixes: #33302 --- src/librustdoc/clean/inline.rs | 9 +++---- src/librustdoc/clean/mod.rs | 14 +++++----- src/test/rustdoc/issue-33302.rs | 46 +++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 src/test/rustdoc/issue-33302.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e13b268878890..36eb1a1301c9d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,6 +20,7 @@ use rustc::hir; use rustc::middle::cstore::{self, CrateStore}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; +use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt}; use rustc::ty::subst; use rustc::middle::stability; @@ -30,7 +31,7 @@ use core::{DocContext, DocAccessLevels}; use doctree; use clean::{self, GetDefId}; -use super::{Clean, ToSource}; +use super::Clean; /// Attempt to inline the definition of a local node id into this AST. /// @@ -333,8 +334,8 @@ pub fn build_impl(cx: &DocContext, let did = assoc_const.def_id; let type_scheme = tcx.lookup_item_type(did); let default = if assoc_const.has_value { - Some(lookup_const_by_id(tcx, did, None) - .unwrap().0.span.to_src(cx)) + Some(pprust::expr_to_string( + lookup_const_by_id(tcx, did, None).unwrap().0)) } else { None }; @@ -479,8 +480,6 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt, fn build_const(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Constant { - use rustc::hir::print as pprust; - let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { panic!("expected lookup_const_by_id to succeed for {:?}", did); }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 35922c477ccee..0a606e1425c45 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,6 +39,7 @@ use rustc::middle::cstore::{self, CrateStore}; use rustc::middle::privacy::AccessLevels; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::print as pprust; use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace}; use rustc::ty; use rustc::middle::stability; @@ -1285,8 +1286,7 @@ impl Clean for hir::TraitItem { let inner = match self.node { hir::ConstTraitItem(ref ty, ref default) => { AssociatedConstItem(ty.clean(cx), - default.as_ref().map(|expr| - expr.span.to_src(cx))) + default.as_ref().map(|e| pprust::expr_to_string(&e))) } hir::MethodTraitItem(ref sig, Some(_)) => { MethodItem(sig.clean(cx)) @@ -1316,7 +1316,7 @@ impl Clean for hir::ImplItem { let inner = match self.node { hir::ImplItemKind::Const(ref ty, ref expr) => { AssociatedConstItem(ty.clean(cx), - Some(expr.span.to_src(cx))) + Some(pprust::expr_to_string(expr))) } hir::ImplItemKind::Method(ref sig, _) => { MethodItem(sig.clean(cx)) @@ -1635,8 +1635,8 @@ impl Clean for hir::Ty { BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), type_: box m.ty.clean(cx)}, TyVec(ref ty) => Vector(box ty.clean(cx)), - TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx), - e.span.to_src(cx)), + TyFixedLengthVec(ref ty, ref e) => + FixedVector(box ty.clean(cx), pprust::expr_to_string(e)), TyTup(ref tys) => Tuple(tys.clean(cx)), TyPath(None, ref p) => { resolve_type(cx, p.clean(cx), self.id) @@ -2185,7 +2185,7 @@ impl Clean for doctree::Static { inner: StaticItem(Static { type_: self.type_.clean(cx), mutability: self.mutability.clean(cx), - expr: self.expr.span.to_src(cx), + expr: pprust::expr_to_string(&self.expr), }), } } @@ -2209,7 +2209,7 @@ impl Clean for doctree::Constant { deprecation: self.depr.clean(cx), inner: ConstantItem(Constant { type_: self.type_.clean(cx), - expr: self.expr.span.to_src(cx), + expr: pprust::expr_to_string(&self.expr), }), } } diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs new file mode 100644 index 0000000000000..b9188e8a4e9ba --- /dev/null +++ b/src/test/rustdoc/issue-33302.rs @@ -0,0 +1,46 @@ +// 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. + +// Ensure constant and array length values are not taken from source +// code, which wreaks havoc with macros. + +#![feature(associated_consts)] + +macro_rules! make { + ($n:expr) => { + pub struct S; + + // @has issue_33302/constant.CST.html \ + // '//pre[@class="rust const"]' 'pub const CST: i32 = 4 * 4' + pub const CST: i32 = ($n * $n); + // @has issue_33302/static.ST.html \ + // '//pre[@class="rust static"]' 'pub static ST: i32 = 4 * 4' + pub static ST: i32 = ($n * $n); + + pub trait T { + fn ignore(_: &X) {} + const C: X; + // @has issue_33302/trait.T.html \ + // '//*[@class="rust trait"]' 'const D: i32 = 4 * 4;' + // @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4' + const D: i32 = ($n * $n); + } + + // @has issue_33302/struct.S.html \ + // '//h3[@class="impl"]' 'impl T<[i32; 4 * 4]> for S' + // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 4 * 4] = [0; 4 * 4]' + // @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4' + impl T<[i32; ($n * $n)]> for S { + const C: [i32; ($n * $n)] = [0; ($n * $n)]; + } + } +} + +make!(4); From 1bcf41e53f1361a7b09503b6c3a081a3b6907cb6 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 3 May 2016 13:31:12 +0200 Subject: [PATCH 14/14] rustdoc: HTML-escape Rust code (from constants) Especially in cases like the one in the test file, this can blow up the docs big time if string constants in the code contain HTML. But also other constants can contain special chars (e.g. `&` as an operator in constant expressions). --- src/librustdoc/html/format.rs | 3 ++- src/librustdoc/html/render.rs | 4 ++-- src/test/rustdoc/escape-rust-expr.rs | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/escape-rust-expr.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d7763197f8a3b..7af5322e7bdf1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -26,6 +26,7 @@ use rustc::hir; use clean; use core::DocAccessLevels; use html::item_type::ItemType; +use html::escape::Escape; use html::render; use html::render::{cache, CURRENT_LOCATION_KEY}; @@ -496,7 +497,7 @@ impl fmt::Display for clean::Type { primitive_link(f, clean::PrimitiveType::Array, "[")?; write!(f, "{}", t)?; primitive_link(f, clean::PrimitiveType::Array, - &format!("; {}]", *s)) + &format!("; {}]", Escape(s))) } clean::Bottom => f.write_str("!"), clean::RawPointer(m, ref t) => { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5cdddc76582b3..36da95279fb24 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1866,7 +1866,7 @@ impl<'a> fmt::Display for Initializer<'a> { let Initializer(s) = *self; if s.is_empty() { return Ok(()); } write!(f, " = ")?; - write!(f, "{}", s) + write!(f, "{}", Escape(s)) } } @@ -2106,7 +2106,7 @@ fn assoc_const(w: &mut fmt::Formatter, write!(w, ": {}", ty)?; if let Some(default) = default { - write!(w, " = {}", default)?; + write!(w, " = {}", Escape(default))?; } Ok(()) } diff --git a/src/test/rustdoc/escape-rust-expr.rs b/src/test/rustdoc/escape-rust-expr.rs new file mode 100644 index 0000000000000..7f9a2bf175a5f --- /dev/null +++ b/src/test/rustdoc/escape-rust-expr.rs @@ -0,0 +1,15 @@ +// 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. + +// Test that we HTML-escape Rust expressions, where HTML special chars +// can occur, and we know it's definitely not markup. + +// @has escape_rust_expr/constant.CONST_S.html '//pre[@class="rust const"]' '"