diff --git a/mk/main.mk b/mk/main.mk index 38b9328897508..268d26817b0a1 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.6.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release # versions (section 9) -CFG_PRERELEASE_VERSION=.2 +CFG_PRERELEASE_VERSION=.3 # Append a version-dependent hash to each library, so we can install different # versions in the same place diff --git a/src/doc/book/SUMMARY.md b/src/doc/book/SUMMARY.md index 876a7399be9e5..05723779b340e 100644 --- a/src/doc/book/SUMMARY.md +++ b/src/doc/book/SUMMARY.md @@ -54,6 +54,7 @@ * [FFI](ffi.md) * [Borrow and AsRef](borrow-and-asref.md) * [Release Channels](release-channels.md) + * [Using Rust without the standard library](using-rust-without-the-standard-library.md) * [Nightly Rust](nightly-rust.md) * [Compiler Plugins](compiler-plugins.md) * [Inline Assembly](inline-assembly.md) diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 3a4d4c306dc72..65beaed2fc7e9 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -1,8 +1,15 @@ % No stdlib -By default, `std` is linked to every Rust crate. In some contexts, -this is undesirable, and can be avoided with the `#![no_std]` -attribute attached to the crate. +Rust’s standard library provides a lot of useful functionality, but assumes +support for various features of its host system: threads, networking, heap +allocation, and others. There are systems that do not have these features, +however, and Rust can work with those too! To do so, we tell Rust that we +don’t want to use the standard library via an attribute: `#![no_std]`. + +> Note: This feature is technically stable, but there are some caveats. For +> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. +> For details on libraries without the standard library, see [the chapter on +> `#![no_std]`](using-rust-without-the-standard-library.html) Obviously there's more to life than just libraries: one can use `#[no_std]` with an executable, controlling the entry point is @@ -77,89 +84,3 @@ personality function (see the information), but crates which do not trigger a panic can be assured that this function is never called. The second function, `panic_fmt`, is also used by the failure mechanisms of the compiler. - -## Using libcore - -> **Note**: the core library's structure is unstable, and it is recommended to -> use the standard library instead wherever possible. - -With the above techniques, we've got a bare-metal executable running some Rust -code. There is a good deal of functionality provided by the standard library, -however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/index.html) is designed to be used -instead. - -The core library has very few dependencies and is much more portable than the -standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. When -using `#![no_std]`, Rust will automatically inject the `core` crate, just like -we do for `std` when we’re using it. - -As an example, here is a program that will calculate the dot product of two -vectors provided from C, using idiomatic Rust practices. - -```rust -# #![feature(libc)] -#![feature(lang_items)] -#![feature(start)] -#![feature(raw)] -#![no_std] - -extern crate libc; - -use core::mem; - -#[no_mangle] -pub extern fn dot_product(a: *const u32, a_len: u32, - b: *const u32, b_len: u32) -> u32 { - use core::raw::Slice; - - // Convert the provided arrays into Rust slices. - // The core::raw module guarantees that the Slice - // structure has the same memory layout as a &[T] - // slice. - // - // This is an unsafe operation because the compiler - // cannot tell the pointers are valid. - let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { - mem::transmute(( - Slice { data: a, len: a_len as usize }, - Slice { data: b, len: b_len as usize }, - )) - }; - - // Iterate over the slices, collecting the result - let mut ret = 0; - for (i, j) in a_slice.iter().zip(b_slice.iter()) { - ret += (*i) * (*j); - } - return ret; -} - -#[lang = "panic_fmt"] -extern fn panic_fmt(args: &core::fmt::Arguments, - file: &str, - line: u32) -> ! { - loop {} -} - -#[lang = "eh_personality"] extern fn eh_personality() {} -# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} -# fn main() {} -``` - -Note that there is one extra lang item here which differs from the examples -above, `panic_fmt`. This must be defined by consumers of libcore because the -core library declares panics, but it does not define it. The `panic_fmt` -lang item is this crate's definition of panic, and it must be guaranteed to -never return. - -As can be seen in this example, the core library is intended to provide the -power of Rust in all circumstances, regardless of platform requirements. Further -libraries, such as liballoc, add functionality to libcore which make other -platform-specific assumptions, but continue to be more portable than the -standard library itself. - diff --git a/src/doc/book/using-rust-without-the-standard-library.md b/src/doc/book/using-rust-without-the-standard-library.md new file mode 100644 index 0000000000000..59182e1a4efce --- /dev/null +++ b/src/doc/book/using-rust-without-the-standard-library.md @@ -0,0 +1,41 @@ +% Using Rust Without the Standard Library + +Rust’s standard library provides a lot of useful functionality, but assumes +support for various features of its host system: threads, networking, heap +allocation, and others. There are systems that do not have these features, +however, and Rust can work with those too! To do so, we tell Rust that we +don’t want to use the standard library via an attribute: `#![no_std]`. + +> Note: This feature is technically stable, but there are some caveats. For +> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. +> For details on binaries without the standard library, see [the nightly +> chapter on `#![no_std]`](no-stdlib.html) + +To use `#![no_std]`, add a it to your crate root: + +```rust +#![no_std] + +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Much of the functionality that’s exposed in the standard library is also +available via the [`core` crate](../core/). When we’re using the standard +library, Rust automatically brings `std` into scope, allowing you to use +its features without an explicit import. By the same token, when using +`!#[no_std]`, Rust will bring `core` into scope for you, as well as [its +prelude](../core/prelude/v1/). This means that a lot of code will Just Work: + +```rust +#![no_std] + +fn may_fail(failure: bool) -> Result<(), &'static str> { + if failure { + Err("this didn’t work!") + } else { + Ok(()) + } +} +``` diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 0f176cf9f006a..d63f0deaa61b6 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -127,6 +127,12 @@ declare_lint! { "unit struct or enum variant erroneously allowed to match via path::ident(..)" } +declare_lint! { + pub RAW_POINTER_DERIVE, + Warn, + "uses of #[derive] with raw pointers are rarely correct" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -152,7 +158,8 @@ impl LintPass for HardwiredLints { TRIVIAL_CASTS, TRIVIAL_NUMERIC_CASTS, MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, - CONST_ERR + CONST_ERR, + RAW_POINTER_DERIVE ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 4a5a44f19f34b..343963e7c809d 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -218,21 +218,10 @@ impl LintStore { { match self.by_name.get(lint_name) { Some(&Id(lint_id)) => Ok(lint_id), - Some(&Renamed(ref new_name, lint_id)) => { - let warning = format!("lint {} has been renamed to {}", - lint_name, new_name); - match span { - Some(span) => sess.span_warn(span, &warning[..]), - None => sess.warn(&warning[..]), - }; + Some(&Renamed(_, lint_id)) => { Ok(lint_id) }, Some(&Removed(ref reason)) => { - let warning = format!("lint {} has been removed: {}", lint_name, reason); - match span { - Some(span) => sess.span_warn(span, &warning[..]), - None => sess.warn(&warning[..]) - } Err(FindLintError::Removed) }, None => Err(FindLintError::NotFound) @@ -241,8 +230,12 @@ impl LintStore { pub fn process_command_line(&mut self, sess: &Session) { for &(ref lint_name, level) in &sess.opts.lint_opts { + check_lint_name_cmdline(sess, self, + &lint_name[..], level); + match self.find_lint(&lint_name[..], sess, None) { Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)), + Err(FindLintError::Removed) => { } Err(_) => { match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) .collect::>(); } - None => sess.err(&format!("unknown {} flag: {}", - level.as_str(), lint_name)), + None => { + // The lint or lint group doesn't exist. + // This is an error, but it was handled + // by check_lint_name_cmdline. + } } } } @@ -330,29 +326,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec> { let mut out = vec!(); for attr in attrs { - let level = match Level::from_str(&attr.name()) { - None => continue, - Some(lvl) => lvl, - }; + let r = gather_attr(attr); + out.extend(r.into_iter()); + } + out +} - attr::mark_used(attr); +pub fn gather_attr(attr: &ast::Attribute) + -> Vec> { + let mut out = vec!(); - let meta = &attr.node.value; - let metas = match meta.node { - ast::MetaList(_, ref metas) => metas, - _ => { - out.push(Err(meta.span)); - continue; - } - }; + let level = match Level::from_str(&attr.name()) { + None => return out, + Some(lvl) => lvl, + }; - for meta in metas { - out.push(match meta.node { - ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), - _ => Err(meta.span), - }); + attr::mark_used(attr); + + let meta = &attr.node.value; + let metas = match meta.node { + ast::MetaList(_, ref metas) => metas, + _ => { + out.push(Err(meta.span)); + return out; } + }; + + for meta in metas { + out.push(match meta.node { + ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), + _ => Err(meta.span), + }); } + out } @@ -510,9 +516,9 @@ pub trait LintContext: Sized { (*lint_id, level, span)) .collect(), None => { - self.span_lint(builtin::UNKNOWN_LINTS, span, - &format!("unknown `{}` attribute: `{}`", - level.as_str(), lint_name)); + // The lint or lint group doesn't exist. + // This is an error, but it was handled + // by check_lint_name_attribute. continue; } } @@ -824,6 +830,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_attribute(&mut self, attr: &ast::Attribute) { + check_lint_name_attribute(self, attr); run_lints!(self, check_attribute, late_passes, attr); } } @@ -1037,6 +1044,110 @@ impl LateLintPass for GatherNodeLevels { } } +enum CheckLintNameResult { + Ok, + // Lint doesn't exist + NoLint, + // The lint is either renamed or removed and a warning was generated + Mentioned +} + +/// Checks the name of a lint for its existence, and whether it was +/// renamed or removed. Generates a DiagnosticBuilder containing a +/// warning for renamed and removed lints. This is over both lint +/// names from attributes and those passed on the command line. Since +/// it emits non-fatal warnings and there are *two* lint passes that +/// inspect attributes, this is only run from the late pass to avoid +/// printing duplicate warnings. +fn check_lint_name(sess: &Session, + lint_cx: &LintStore, + lint_name: &str, + span: Option) -> CheckLintNameResult { + match lint_cx.by_name.get(lint_name) { + Some(&Renamed(ref new_name, _)) => { + let warning = format!("lint {} has been renamed to {}", + lint_name, new_name); + match span { + Some(span) => sess.span_warn(span, &warning[..]), + None => sess.warn(&warning[..]), + }; + CheckLintNameResult::Mentioned + }, + Some(&Removed(ref reason)) => { + let warning = format!("lint {} has been removed: {}", lint_name, reason); + match span { + Some(span) => sess.span_warn(span, &warning[..]), + None => sess.warn(&warning[..]) + }; + CheckLintNameResult::Mentioned + }, + None => { + match lint_cx.lint_groups.get(lint_name) { + None => { + CheckLintNameResult::NoLint + } + Some(_) => { + /* lint group exists */ + CheckLintNameResult::Ok + } + } + } + Some(_) => { + /* lint exists */ + CheckLintNameResult::Ok + } + } +} + +// Checks the validity of lint names derived from attributes +fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) { + for result in gather_attr(attr) { + match result { + Err(_) => { + // Malformed lint attr. Reported by with_lint_attrs + continue; + } + Ok((lint_name, _, span)) => { + match check_lint_name(&cx.tcx.sess, &cx.lints, &lint_name[..], Some(span)) { + CheckLintNameResult::Ok => (), + CheckLintNameResult::Mentioned => (), + CheckLintNameResult::NoLint => { + cx.span_lint(builtin::UNKNOWN_LINTS, span, + &format!("unknown lint: `{}`", + lint_name)); + } + } + } + } + } +} + +// Checks the validity of lint names derived from the command line +fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, + lint_name: &str, level: Level) { + let explain = match check_lint_name(sess, lint_cx, lint_name, None) { + CheckLintNameResult::Ok => false, + CheckLintNameResult::Mentioned => true, + CheckLintNameResult::NoLint => { + sess.err(&format!("unknown lint: `{}`", lint_name)); + true + } + }; + + if explain { + let msg = format!("requested on the command line with `{} {}`", + match level { + Level::Allow => "-A", + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + }, + lint_name); + sess.note(&msg); + } +} + + /// Perform lint checking on a crate. /// /// Consumes the `lint_store` field of the `Session`. diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 5dd7768cb5c6c..226084361530a 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -152,8 +152,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // We have one lint pass defined specially store.register_late_pass(sess, false, box lint::GatherNodeLevels); - // Insert temporary renamings for a one-time deprecation + // Register renamed and removed lints store.register_renamed("unknown_features", "unused_features"); - store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); + store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok"); + // This was renamed to raw_pointer_derive, which was then removed, + // so it is also considered removed + store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok"); } diff --git a/src/test/compile-fail/lint-malformed.rs b/src/test/compile-fail/lint-malformed.rs new file mode 100644 index 0000000000000..592e2b11905b3 --- /dev/null +++ b/src/test/compile-fail/lint-malformed.rs @@ -0,0 +1,14 @@ +// 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. + +#![deny = "foo"] //~ ERR malformed lint attribute +#![allow(bar = "baz")] //~ ERR malformed lint attribute + +fn main() { } diff --git a/src/test/compile-fail/lint-removed-cmdline.rs b/src/test/compile-fail/lint-removed-cmdline.rs new file mode 100644 index 0000000000000..d6bfd1eec39a6 --- /dev/null +++ b/src/test/compile-fail/lint-removed-cmdline.rs @@ -0,0 +1,20 @@ +// 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. + +// The raw_pointer_derived lint warns about its removal +// cc #30346 + +// compile-flags:-D raw_pointer_derive + +// error-pattern:lint raw_pointer_derive has been removed +// error-pattern:requested on the command line with `-D raw_pointer_derive` + +#[deny(warnings)] +fn main() { let unused = (); } diff --git a/src/test/compile-fail/lint-removed.rs b/src/test/compile-fail/lint-removed.rs new file mode 100644 index 0000000000000..e196e128b1712 --- /dev/null +++ b/src/test/compile-fail/lint-removed.rs @@ -0,0 +1,16 @@ +// 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. + +// The raw_pointer_derived lint only warns about its own removal +// cc #30346 + +#[deny(raw_pointer_derive)] //~ WARN raw_pointer_derive has been removed +#[deny(warnings)] +fn main() { let unused = (); } //~ ERR unused diff --git a/src/test/compile-fail/lint-renamed-cmdline.rs b/src/test/compile-fail/lint-renamed-cmdline.rs new file mode 100644 index 0000000000000..3b352b384ff99 --- /dev/null +++ b/src/test/compile-fail/lint-renamed-cmdline.rs @@ -0,0 +1,18 @@ +// 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:-D unknown_features + +// error-pattern:lint unknown_features has been renamed to unused_features +// error-pattern:requested on the command line with `-D unknown_features` +// error-pattern:unused + +#[deny(unused)] +fn main() { let unused = (); } diff --git a/src/test/compile-fail/lint-renamed.rs b/src/test/compile-fail/lint-renamed.rs new file mode 100644 index 0000000000000..2e85a323a1c41 --- /dev/null +++ b/src/test/compile-fail/lint-renamed.rs @@ -0,0 +1,13 @@ +// 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. + +#[deny(unknown_features)] //~ WARN lint unknown_features has been renamed to unused_features +#[deny(unused)] +fn main() { let unused = (); } //~ ERR unused diff --git a/src/test/compile-fail/lint-unknown-lint-cmdline.rs b/src/test/compile-fail/lint-unknown-lint-cmdline.rs new file mode 100644 index 0000000000000..0c41959f8a710 --- /dev/null +++ b/src/test/compile-fail/lint-unknown-lint-cmdline.rs @@ -0,0 +1,16 @@ +// 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:-D bogus + +// error-pattern:unknown lint +// error-pattern:requested on the command line with `-D bogus` + +fn main() { } diff --git a/src/test/compile-fail/lint-unknown-lint.rs b/src/test/compile-fail/lint-unknown-lint.rs new file mode 100644 index 0000000000000..8f20a2c8ab758 --- /dev/null +++ b/src/test/compile-fail/lint-unknown-lint.rs @@ -0,0 +1,13 @@ +// 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. + +#![allow(not_a_real_lint)] //~ WARN unknown lint +#![deny(unused)] +fn main() { let unused = (); } //~ ERR unused variable