Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 9 pull requests #38826

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a99f70b
Clarify zero-value behavior of `ctlz`/`cttz` intrinsics.
frewsxcv Dec 11, 2016
3caf478
Add test for correct span for type
estebank Dec 25, 2016
0ab7812
Clarify behavior of `VecDeque::insert`.
frewsxcv Dec 23, 2016
a52f257
Fix doc for `escape_debug`
bombless Dec 27, 2016
dfb6ae6
Test for appropriate span on second custom derive
estebank Dec 25, 2016
ca9b07b
Replace uses of `#[unsafe_destructor_blind_to_params]` with `#[may_da…
apasel422 Dec 28, 2016
ae23f03
Doc fix
minaguib Jan 3, 2017
c0efdbf
Document custom derive.
steveklabnik Jan 2, 2017
07e844f
Add more docs for CoerceUnsized and Unsize
Manishearth Jan 4, 2017
5dadffc
Rollup merge of #38310 - frewsxcv:ctlz-cttz, r=pnkfelix
GuillaumeGomez Jan 4, 2017
69888bd
Rollup merge of #38581 - frewsxcv:vecdequeue-insert, r=GuillaumeGomez
GuillaumeGomez Jan 4, 2017
74c6fcc
Rollup merge of #38606 - estebank:test-for-27522, r=petrochenkov
GuillaumeGomez Jan 4, 2017
30c405d
Rollup merge of #38607 - estebank:test-for-36935, r=petrochenkov
GuillaumeGomez Jan 4, 2017
8b05a91
Rollup merge of #38629 - bombless:patch-4, r=petrochenkov
GuillaumeGomez Jan 4, 2017
a282e07
Rollup merge of #38664 - apasel422:may-dangle, r=pnkfelix
GuillaumeGomez Jan 4, 2017
e9926c0
Rollup merge of #38770 - steveklabnik:doc-custom-derive, r=nikomatsakis
GuillaumeGomez Jan 4, 2017
3458490
Rollup merge of #38799 - minaguib:patch-1, r=steveklabnik
GuillaumeGomez Jan 4, 2017
05913bd
Rollup merge of #38816 - Manishearth:coercion-doc, r=GuillaumeGomez
GuillaumeGomez Jan 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/book/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
* [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)
* [Procedural Macros (and custom derive)](procedural-macros.md)
* [Nightly Rust](nightly-rust.md)
* [Compiler Plugins](compiler-plugins.md)
* [Inline Assembly](inline-assembly.md)
Expand Down
213 changes: 213 additions & 0 deletions src/doc/book/procedural-macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
% Procedural Macros (and custom Derive)

As you've seen throughout the rest of the book, Rust provides a mechanism
called "derive" that lets you implement traits easily. For example,

```rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
```

is a lot simpler than

```rust
struct Point {
x: i32,
y: i32,
}

use std::fmt;

impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
}
}
```

Rust includes several traits that you can derive, but it also lets you define
your own. We can accomplish this task through a feature of Rust called
"procedural macros." Eventually, procedural macros will allow for all sorts of
advanced metaprogramming in Rust, but today, they're only for custom derive.

Let's build a very simple trait, and derive it with custom derive.

## Hello World

So the first thing we need to do is start a new crate for our project.

```bash
$ cargo new --bin hello-world
```

All we want is to be able to call `hello_world()` on a derived type. Something
like this:

```rust,ignore
#[derive(HelloWorld)]
struct Pancakes;

fn main() {
Pancakes::hello_world();
}
```

With some kind of nice output, like `Hello, World! My name is Pancakes.`.

Let's go ahead and write up what we think our macro will look like from a user
perspective. In `src/main.rs` we write:

```rust,ignore
#[macro_use]
extern crate hello_world_derive;

trait HelloWorld {
fn hello_world();
}

#[derive(HelloWorld)]
struct FrenchToast;

#[derive(HelloWorld)]
struct Waffles;

fn main() {
FrenchToast::hello_world();
Waffles::hello_world();
}
```

Great. So now we just need to actually write the procedural macro. At the
moment, procedural macros need to be in their own crate. Eventually, this
restriction may be lifted, but for now, it's required. As such, there's a
convention; for a crate named `foo`, a custom derive procedural macro is called
`foo-derive`. Let's start a new crate called `hello-world-derive` inside our
`hello-world` project.

```bash
$ cargo new hello-world-derive
```

To make sure that our `hello-world` crate is able to find this new crate we've
created, we'll add it to our toml:

```toml
[dependencies]
hello-world-derive = { path = "hello-world-derive" }
```

As for our the source of our `hello-world-derive` crate, here's an example:

```rust,ignore
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(HelloWorld)]
pub fn hello_world(input: TokenStream) -> TokenStream {
// Construct a string representation of the type definition
let s = input.to_string();

// Parse the string representation
let ast = syn::parse_macro_input(&s).unwrap();

// Build the impl
let gen = impl_hello_world(&ast);

// Return the generated impl
gen.parse().unwrap()
}
```

So there is a lot going on here. We have introduced two new crates: [`syn`] and
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
to a `String`. This `String` is a string representation of the Rust code for which
we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
`TokenStream` is convert it to a string. A richer API will exist in the future.

So what we really need is to be able to _parse_ Rust code into something
usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust
code. The other crate we've introduced is `quote`. It's essentially the dual of
`syn` as it will make generating Rust code really easy. We could write this
stuff on our own, but it's much simpler to use these libraries. Writing a full
parser for Rust code is no simple task.

[`syn`]: https://crates.io/crates/syn
[`quote`]: https://crates.io/crates/quote

The comments seem to give us a pretty good idea of our overall strategy. We
are going to take a `String` of the Rust code for the type we are deriving, parse
it using `syn`, construct the implementation of `hello_world` (using `quote`),
then pass it back to Rust compiler.

One last note: you'll see some `unwrap()`s there. If you want to provide an
error for a procedural macro, then you should `panic!` with the error message.
In this case, we're keeping it as simple as possible.

Great, so let's write `impl_hello_world(&ast)`.

```rust,ignore
fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl HelloWorld for #name {
fn hello_world() {
println!("Hello, World! My name is {}", stringify!(#name));
}
}
}
}
```

So this is where quotes comes in. The `ast` argument is a struct that gives us
a representation of our type (which can be either a `struct` or an `enum`).
Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
there is some useful information there. We are able to get the name of the
type using `ast.ident`. The `quote!` macro let's us write up the Rust code
that we wish to return and convert it into `Tokens`. `quote!` let's us use some
really cool templating mechanics; we simply write `#name` and `quote!` will
replace it with the variable named `name`. You can even do some repetition
similar to regular macros work. You should check out the
[docs](https://docs.rs/quote) for a good introduction.

So I think that's it. Oh, well, we do need to add dependencies for `syn` and
`quote` in the `cargo.toml` for `hello-world-derive`.

```toml
[dependencies]
syn = "0.10.5"
quote = "0.3.10"
```

That should be it. Let's try to compile `hello-world`.

```bash
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
--> hello-world-derive/src/lib.rs:8:3
|
8 | #[proc_macro_derive(HelloWorld)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

Oh, so it appears that we need to declare that our `hello-world-derive` crate is
a `proc-macro` crate type. How do we do this? Like this:

```toml
[lib]
proc-macro = true
```

Ok so now, let's compile `hello-world`. Executing `cargo run` now yields:

```bash
Hello, World! My name is FrenchToast
Hello, World! My name is Waffles
```

We've done it!
4 changes: 3 additions & 1 deletion src/doc/nomicon/coercions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Coercion is allowed between the following types:
* `&T` to `*const T`
* `&mut T` to `*mut T`
* Unsizing: `T` to `U` if `T` implements `CoerceUnsized<U>`
* Deref coercion: Expression `&x` of type `&T` to `&*x` of type `&U` if `T` derefs to `U` (i.e. `T: Deref<Target=U>`)

`CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>` is implemented
for all pointer types (including smart pointers like Box and Rc). Unsize is
Expand All @@ -27,8 +28,9 @@ only implemented automatically, and enables the following transformations:
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
* `T: Unsize<U>`
* `Foo` is a struct
* Only the last field of `Foo` has type `T`
* Only the last field of `Foo` has type involving `T`
* `T` is not part of the type of any other fields
* `Bar<T>: Unsize<Bar<U>>`, if the last field of `Foo` has type `Bar<T>`

Coercions occur at a *coercion site*. Any location that is explicitly typed
will cause a coercion to its type. If inference is necessary, the coercion will
Expand Down
50 changes: 42 additions & 8 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,26 +555,24 @@ mod a {
# fn main() {}
```

# Syntax extensions
# Macros

A number of minor features of Rust are not central enough to have their own
syntax, and yet are not implementable as functions. Instead, they are given
names, and invoked through a consistent syntax: `some_extension!(...)`.

Users of `rustc` can define new syntax extensions in two ways:

* [Compiler plugins][plugin] can include arbitrary Rust code that
manipulates syntax trees at compile time. Note that the interface
for compiler plugins is considered highly unstable.
Users of `rustc` can define new macros in two ways:

* [Macros](book/macros.html) define new syntax in a higher-level,
declarative way.
* [Procedural Macros][procedural macros] can be used to implement custom derive.

And one unstable way: [compiler plugins][plugin].

## Macros

`macro_rules` allows users to define syntax extension in a declarative way. We
call such extensions "macros by example" or simply "macros" — to be distinguished
from the "procedural macros" defined in [compiler plugins][plugin].
call such extensions "macros by example" or simply "macros".

Currently, macros can expand to expressions, statements, items, or patterns.

Expand Down Expand Up @@ -652,6 +650,28 @@ Rust syntax is restricted in two ways:

[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md

## Procedrual Macros

"Procedrual macros" are the second way to implement a macro. For now, the only
thing they can be used for is to implement derive on your own types. See
[the book][procedural macros] for a tutorial.

Procedural macros involve a few different parts of the language and its
standard libraries. First is the `proc_macro` crate, included with Rust,
that defines an interface for building a procedrual macro. The
`#[proc_macro_derive(Foo)]` attribute is used to mark the the deriving
function. This function must have the type signature:

```rust,ignore
use proc_macro::TokenStream;

#[proc_macro_derive(Hello)]
pub fn hello_world(input: TokenStream) -> TokenStream
```

Finally, procedural macros must be in their own crate, with the `proc-macro`
crate type.

# Crates and source files

Although Rust, like any other language, can be implemented by an interpreter as
Expand Down Expand Up @@ -2319,6 +2339,9 @@ impl<T: PartialEq> PartialEq for Foo<T> {
}
```

You can implement `derive` for your own type through [procedural
macros](#procedural-macros).

### Compiler Features

Certain aspects of Rust may be implemented in the compiler, but they're not
Expand Down Expand Up @@ -4122,6 +4145,16 @@ be ignored in favor of only building the artifacts specified by command line.
in dynamic libraries. This form of output is used to produce statically linked
executables as well as `staticlib` outputs.

* `--crate-type=proc-macro`, `#[crate_type = "proc-macro"]` - The output
produced is not specified, but if a `-L` path is provided to it then the
compiler will recognize the output artifacts as a macro and it can be loaded
for a program. If a crate is compiled with the `proc-macro` crate type it
will forbid exporting any items in the crate other than those functions
tagged `#[proc_macro_derive]` and those functions must also be placed at the
crate root. Finally, the compiler will automatically set the
`cfg(proc_macro)` annotation whenever any crate type of a compilation is the
`proc-macro` crate type.

Note that these outputs are stackable in the sense that if multiple are
specified, then the compiler will produce each form of output at once without
having to recompile. However, this only applies for outputs specified by the
Expand Down Expand Up @@ -4299,3 +4332,4 @@ that have since been removed):

[ffi]: book/ffi.html
[plugin]: book/compiler-plugins.html
[procedural macros]: book/procedural-macros.html
3 changes: 1 addition & 2 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ impl<T: ?Sized> Arc<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Arc<T> {
unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> {
/// Drops the `Arc`.
///
/// This will decrement the strong reference count. If the strong reference
Expand Down Expand Up @@ -736,7 +736,6 @@ impl<T: ?Sized> Drop for Arc<T> {
/// drop(foo); // Doesn't print anything
/// drop(foo2); // Prints "dropped!"
/// ```
#[unsafe_destructor_blind_to_params]
#[inline]
fn drop(&mut self) {
// Because `fetch_sub` is already atomic, we do not need to synchronize
Expand Down
3 changes: 2 additions & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_parametricity)]
#![feature(dropck_eyepatch)]
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![feature(fundamental)]
#![feature(generic_param_attrs)]
#![feature(lang_items)]
#![feature(needs_allocator)]
#![feature(optin_builtin_traits)]
Expand Down
3 changes: 1 addition & 2 deletions src/liballoc/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,7 @@ impl<T> RawVec<T> {
}
}

impl<T> Drop for RawVec<T> {
#[unsafe_destructor_blind_to_params]
unsafe impl<#[may_dangle] T> Drop for RawVec<T> {
/// Frees the memory owned by the RawVec *without* trying to Drop its contents.
fn drop(&mut self) {
let elem_size = mem::size_of::<T>();
Expand Down
3 changes: 1 addition & 2 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ impl<T: ?Sized> Deref for Rc<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Rc<T> {
unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
/// Drops the `Rc`.
///
/// This will decrement the strong reference count. If the strong reference
Expand Down Expand Up @@ -672,7 +672,6 @@ impl<T: ?Sized> Drop for Rc<T> {
/// drop(foo); // Doesn't print anything
/// drop(foo2); // Prints "dropped!"
/// ```
#[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
unsafe {
let ptr = *self.ptr;
Expand Down
Loading