Merge pull request #560 from rust-lang/stable-in-nightly

Check that we don't use any unstable features.
This commit is contained in:
Carol (Nichols || Goulding)
2017-03-23 16:45:21 -04:00
committed by GitHub
7 changed files with 76 additions and 294 deletions

View File

@@ -12,6 +12,14 @@ set -e
export PATH=$PATH:/home/travis/.cargo/bin;
# feature check
cd ci/stable-check
cargo run -- ../../first-edition/src
cargo run -- ../../second-edition/src
cd ../..
# tests for the second edition
cd second-edition

4
ci/stable-check/Cargo.lock generated Normal file
View File

@@ -0,0 +1,4 @@
[root]
name = "stable-check"
version = "0.1.0"

View File

@@ -0,0 +1,6 @@
[package]
name = "stable-check"
version = "0.1.0"
authors = ["steveklabnik <steve@steveklabnik.com>"]
[dependencies]

View File

@@ -0,0 +1,43 @@
use std::error::Error;
use std::env;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
fn main() {
let arg = env::args().nth(1).unwrap_or_else(|| {
println!("Please pass a src directory as the first argument");
std::process::exit(1);
});
match check_directory(&Path::new(&arg)) {
Ok(()) => println!("passed!"),
Err(e) => {
println!("Error: {}", e);
std::process::exit(1);
}
}
}
fn check_directory(dir: &Path) -> Result<(), Box<Error>> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
continue;
}
let mut file = File::open(&path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
if contents.contains("#![feature") {
return Err(From::from(format!("Feature flag found in {:?}", path)));
}
}
Ok(())
}

View File

@@ -222,26 +222,11 @@ operator. From this, everything else clicks into place. In Rust, we use the
trait system to overload operators. Calling functions is no different. We have
three separate traits to overload with:
```rust
# #![feature(unboxed_closures)]
# mod foo {
pub trait Fn<Args> : FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
* `Fn`
* `FnMut`
* `FnOnce`
pub trait FnMut<Args> : FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
# }
```
Youll notice a few differences between these traits, but a big one is `self`:
There are a few differences between these traits, but a big one is `self`:
`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
covers all three kinds of `self` via the usual method call syntax. But weve
split them up into three traits, rather than having a single one. This gives us

View File

@@ -1,253 +0,0 @@
# Compiler Plugins
## Introduction
`rustc` can load compiler plugins, which are user-provided libraries that
extend the compiler's behavior with new syntax extensions, lint checks, etc.
A plugin is a dynamic library crate with a designated *registrar* function that
registers extensions with `rustc`. Other crates can load these extensions using
the crate attribute `#![plugin(...)]`. See the
`rustc_plugin` documentation for more about the
mechanics of defining and loading a plugin.
If present, arguments passed as `#![plugin(foo(... args ...))]` are not
interpreted by rustc itself. They are provided to the plugin through the
`Registry`'s `args` method.
In the vast majority of cases, a plugin should *only* be used through
`#![plugin]` and not through an `extern crate` item. Linking a plugin would
pull in all of libsyntax and librustc as dependencies of your crate. This is
generally unwanted unless you are building another plugin. The
`plugin_as_library` lint checks these guidelines.
The usual practice is to put compiler plugins in their own crate, separate from
any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
of a library.
# Syntax extensions
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
is the procedural macro. These are invoked the same way as [ordinary
macros](macros.html), but the expansion is performed by arbitrary Rust
code that manipulates syntax trees at
compile time.
Let's write a plugin
[`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs)
that implements Roman numeral integer literals.
```rust,ignore
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // A trait for expr_usize.
use syntax::ext::quote::rt::Span;
use rustc_plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<MacResult + 'static> {
static NUMERALS: &'static [(&'static str, usize)] = &[
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)];
if args.len() != 1 {
cx.span_err(
sp,
&format!("argument should be a single identifier, but got {} arguments", args.len()));
return DummyResult::any(sp);
}
let text = match args[0] {
TokenTree::Token(_, token::Ident(s)) => s.to_string(),
_ => {
cx.span_err(sp, "argument should be a single identifier");
return DummyResult::any(sp);
}
};
let mut text = &*text;
let mut total = 0;
while !text.is_empty() {
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
Some(&(rn, val)) => {
total += val;
text = &text[rn.len()..];
}
None => {
cx.span_err(sp, "invalid Roman numeral");
return DummyResult::any(sp);
}
}
}
MacEager::expr(cx.expr_usize(sp, total))
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("rn", expand_rn);
}
```
Then we can use `rn!()` like any other macro:
```rust,ignore
#![feature(plugin)]
#![plugin(roman_numerals)]
fn main() {
assert_eq!(rn!(MMXV), 2015);
}
```
The advantages over a simple `fn(&str) -> u32` are:
* The (arbitrarily complex) conversion is done at compile time.
* Input validation is also performed at compile time.
* It can be extended to allow use in patterns, which effectively gives
a way to define new literal syntax for any data type.
In addition to procedural macros, you can define new
[`derive`](../reference/attributes.html#derive)-like attributes and other kinds of
extensions. See `Registry::register_syntax_extension` and the `SyntaxExtension`
enum. For a more involved macro example, see
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
## Tips and tricks
Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
You can use `syntax::parse` to turn token trees into
higher-level syntax elements like expressions:
```rust,ignore
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<MacResult+'static> {
let mut parser = cx.new_parser_from_tts(args);
let expr: P<Expr> = parser.parse_expr();
```
Looking through [`libsyntax` parser
code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
will give you a feel for how the parsing infrastructure works.
Keep the `Span`s of everything you parse, for better error reporting. You can
wrap `Spanned` around your custom data structures.
Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
can continue and find further errors.
To print syntax fragments for debugging, you can use `span_note` together with
`syntax::print::pprust::*_to_string`.
The example above produced an integer literal using `AstBuilder::expr_usize`.
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
quasiquote macros. They are undocumented and very rough around the edges.
However, the implementation may be a good starting point for an improved
quasiquote as an ordinary plugin library.
# Lint plugins
Plugins can extend [Rust's lint
infrastructure](../reference/attributes.html#lint-check-attributes) with
additional checks for code style, safety, etc. Now let's write a plugin
[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs)
that warns about any item named `lintme`.
```rust,ignore
#![feature(plugin_registrar)]
#![feature(box_syntax, rustc_private)]
extern crate syntax;
// Load rustc as a plugin to get macros
#[macro_use]
extern crate rustc;
extern crate rustc_plugin;
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
EarlyLintPassObject, LintArray};
use rustc_plugin::Registry;
use syntax::ast;
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array!(TEST_LINT)
}
}
impl EarlyLintPass for Pass {
fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
if it.ident.name.as_str() == "lintme" {
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
}
}
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
}
```
Then code like
```rust,ignore
#![plugin(lint_plugin_test)]
fn lintme() { }
```
will produce a compiler warning:
```txt
foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
foo.rs:4 fn lintme() { }
^~~~~~~~~~~~~~~
```
The components of a lint plugin are:
* one or more `declare_lint!` invocations, which define static `Lint` structs;
* a struct holding any state needed by the lint pass (here, none);
* a `LintPass`
implementation defining how to check each syntax element. A single
`LintPass` may call `span_lint` for several different `Lint`s, but should
register them all through the `get_lints` method.
Lint passes are syntax traversals, but they run at a late stage of compilation
where type information is available. `rustc`'s [built-in
lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
mostly use the same infrastructure as lint plugins, and provide examples of how
to access type information.
Lints defined by plugins are controlled by the usual [attributes and compiler
flags](../reference/attributes.html#lint-check-attributes), e.g.
`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
first argument to `declare_lint!`, with appropriate case and punctuation
conversion.
You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
including those provided by plugins loaded by `foo.rs`.

View File

@@ -28,8 +28,7 @@ and add `extern crate libc;` to your crate root.
The following is a minimal example of calling a foreign function which will
compile if snappy is installed:
```rust,no_run
# #![feature(libc)]
```rust,ignore
extern crate libc;
use libc::size_t;
@@ -62,8 +61,7 @@ of keeping the binding correct at runtime.
The `extern` block can be extended to cover the entire snappy API:
```rust,no_run
# #![feature(libc)]
```rust,ignore
extern crate libc;
use libc::{c_int, size_t};
@@ -98,8 +96,7 @@ vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous
length is the number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
```rust
# #![feature(libc)]
```rust,ignore
# extern crate libc;
# use libc::{c_int, size_t};
# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 }
@@ -123,8 +120,7 @@ required capacity to hold the compressed output. The vector can then be passed t
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
the true length after compression for setting the length.
```rust
# #![feature(libc)]
```rust,ignore
# extern crate libc;
# use libc::{size_t, c_int};
# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8,
@@ -150,8 +146,7 @@ pub fn compress(src: &[u8]) -> Vec<u8> {
Decompression is similar, because snappy stores the uncompressed size as part of the compression
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
```rust
# #![feature(libc)]
```rust,ignore
# extern crate libc;
# use libc::{size_t, c_int};
# unsafe fn snappy_uncompress(compressed: *const u8,
@@ -185,8 +180,7 @@ pub fn uncompress(src: &[u8]) -> Option<Vec<u8>> {
Then, we can add some tests to show how to use them.
```rust
# #![feature(libc)]
```rust,ignore
# extern crate libc;
# use libc::{c_int, size_t};
# unsafe fn snappy_compress(input: *const u8,
@@ -460,8 +454,7 @@ Foreign APIs often export a global variable which could do something like track
global state. In order to access these variables, you declare them in `extern`
blocks with the `static` keyword:
```rust,no_run
# #![feature(libc)]
```rust,ignore
extern crate libc;
#[link(name = "readline")]
@@ -479,8 +472,7 @@ Alternatively, you may need to alter global state provided by a foreign
interface. To do this, statics can be declared with `mut` so we can mutate
them.
```rust,no_run
# #![feature(libc)]
```rust,ignore
extern crate libc;
use std::ffi::CString;
@@ -512,8 +504,7 @@ Most foreign code exposes a C ABI, and Rust uses the platform's C calling conven
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
conventions. Rust provides a way to tell the compiler which convention to use:
```rust
# #![feature(libc)]
```rust,ignore
extern crate libc;
#[cfg(all(target_os = "win32", target_arch = "x86"))]
@@ -624,8 +615,7 @@ callback, which gets called in certain situations. The callback is passed a func
and an integer and it is supposed to run the function with the integer as a parameter. So
we have function pointers flying across the FFI boundary in both directions.
```rust
# #![feature(libc)]
```rust,ignore
extern crate libc;
use libc::c_int;
@@ -725,8 +715,7 @@ void bar(void *arg);
We can represent this in Rust with the `c_void` type:
```rust
# #![feature(libc)]
```rust,ignore
extern crate libc;
extern "C" {