Skip to content

Commit

Permalink
Revise lang_item demo to something unrelated to Box impl
Browse files Browse the repository at this point in the history
Precursor for landing overloaded-box, since that will decouple the box
syntax from the exchange heap (and should eliminate the use of the
`malloc` and `free` lang items).

(This is a simplified approach to PR rust-lang#22499; note that I have once
again changes which lang item to use for the illustration.)
  • Loading branch information
pnkfelix committed Jul 16, 2015
1 parent ef6d5e3 commit afd9b94
Showing 1 changed file with 77 additions and 35 deletions.
112 changes: 77 additions & 35 deletions src/doc/trpl/lang-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,111 @@ it exists. The marker is the attribute `#[lang = "..."]` and there are
various different values of `...`, i.e. various different 'lang
items'.

For example, `Box` pointers require two lang items, one for allocation
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
For example, some traits in the standard library have special
treatment. One is `Copy`: there is a `copy` lang-item attached to the
`Copy` trait, and the Rust compiler treats this specially in two ways:

```rust
#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]
1. If `x` has type that implements `Copy`, then `x` can be freely
copied by the assignment operator:
```rust,ignore
let y = x;
let z = x;
```

extern crate libc;
2. If a type tries to implement `Copy`, the Rust compiler will
ensure that duplicating a value of that type will not cause any
noncopyable type to be duplicated.

extern {
fn abort() -> !;
}
For example, this code will be rejected:

#[lang = "owned_box"]
pub struct Box<T>(*mut T);
```rust,ignore
#[derive(Clone)]
struct ThisTypeIsNotCopy(Box<i32>);
#[lang = "exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
let p = libc::malloc(size as libc::size_t) as *mut u8;
#[derive(Clone)]
struct TryToMakeThisCopy { okay: i32, not_okay: ThisTypeIsNotCopy }
// malloc failed
if p as usize == 0 {
abort();
}
// This attempt to implement `Copy` will fail.
impl Copy for TryToMakeThisCopy { }
```

p
}
#[lang = "exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
The above two properties are both special qualities of the `Copy`
trait that other traits do not share, and thus they are associated
with whatever trait is given the `copy` lang item.

Here is a freestanding program that provides its own definition of the
`copy` lang item, that is slightly different than the definition in
the Rust standard library:

```
#![feature(lang_items, intrinsics, start, no_std)]
#![no_std]
#[lang = "copy"]
pub trait MyCopy {
// Empty.
}
#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
let x = box 1;
struct C(i32, i32);
impl MyCopy for C { }
0
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
let mut x = C(3, 4);
let mut y = x;
let mut z = x;
x.0 = 5;
y.0 = 6;
z.0 = 7;
#[link(name="c")]
extern { fn printf(f: *const u8, ...); }
let template = b"x: C(%d, %d) y: C(%d, %d), z: C(%d, %d)\n\0";
unsafe { printf(template as *const u8, x.0, x.1, y.0, y.1, z.0, z.1); }
return 0;
}
// Again, these functions and traits are used by the compiler, and are
// normally provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[lang="sized"] pub trait Sized: PhantomFn {}
#[lang="phantom_fn"] pub trait PhantomFn {}
```

This compiles successfully. When we run the above code, it prints:
```text
x: C(5, 4) y: C(6, 4), z: C(7, 4)
```
So we can freely copy instances of `C`, since it implements `MyCopy`.

Note the use of `abort`: the `exchange_malloc` lang item is assumed to
return a valid pointer, and so needs to do the check internally.
A potentially interesting detail about the above program is that it
differs from the Rust standard library in more than just the name
`MyCopy`. The `std::marker::Copy` extends `std::clone::Clone`,
ensuring that every type that implements `Copy` has a `clone` method.
The `MyCopy` trait does *not* extend `Clone`; these values have no
`clone` methods.

Other features provided by lang items include:

- overloadable operators via traits: the traits corresponding to the
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
marked with lang items; those specific four are `eq`, `ord`,
`deref`, and `add` respectively.
- stack unwinding and general failure; the `eh_personality`, `fail`
and `fail_bounds_checks` lang items.
- stack unwinding and general failure; the `eh_personality`, `panic`
`panic_fmt`, and `panic_bounds_check` lang items.
- the traits in `std::marker` used to indicate types of
various kinds; lang items `send`, `sync` and `copy`.
- the marker types and variance indicators found in
`std::marker`; lang items `covariant_type`,
`contravariant_lifetime`, etc.
- matching with string literal patterns; the `str_eq` lang item.

Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc`
and `exchange_free`. `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on.
array indexing (`a[i]`) then there is no need to define a function for
`panic_bounds_check`. `rustc` will emit an error when an item is
needed but not found in the current crate or any that it depends on.

0 comments on commit afd9b94

Please sign in to comment.