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 7 pull requests #39663

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ba60af3
Document RFC 1623: static lifetime elision.
chriskrycho Nov 22, 2016
e8cb83a
Add feature flag to reference docs for RFC 1623.
chriskrycho Jan 28, 2017
3f0ca55
Change placement of `[Unstable]` marker in RFC 1623 docs.
chriskrycho Jan 28, 2017
c68e963
Add Rvalue::Discriminant to retrieve discriminant
nagisa Jan 30, 2017
caf9f95
If is now always a SwitchInt in MIR
nagisa Jan 31, 2017
6849985
Move type of discriminant to AdtDef
nagisa Feb 1, 2017
a8075a4
AdtDef now contains discr_ty same as layouted
nagisa Feb 1, 2017
1355a57
SwitchInt over Switch
nagisa Feb 2, 2017
94e587e
Only SwitchInt over integers, not all consts
nagisa Feb 2, 2017
3393584
Fix build on further stages
nagisa Feb 2, 2017
76bc6c3
Reimplement simplify_cfg for SwitchInt
nagisa Feb 2, 2017
cd41479
Fix the IntTypeExt::to_ty() lifetime bounds
nagisa Feb 2, 2017
ff167a6
Fix SwitchInt building in ElaborateDrops pass
nagisa Feb 2, 2017
4e7770e
Prefer switching on false for boolean switches
nagisa Feb 2, 2017
d3f704a
Fix codegen test
nagisa Feb 2, 2017
5e465d5
Inspect now does not force on-stack Lvalue
nagisa Feb 2, 2017
1fee722
Revert use of layout code in typeck::collect
nagisa Feb 3, 2017
832d7e0
Add TerminatorKind::if_ convenience constructor
nagisa Feb 3, 2017
4e29e81
Fix build
nagisa Feb 3, 2017
cdd4aad
Fix tests
nagisa Feb 3, 2017
1e8c855
Rebase fixups
nagisa Feb 4, 2017
1246779
Inline open_drop_for_variant & clean matches::test
nagisa Feb 4, 2017
7c2752a
rustbuild: support setting verbosity in config.toml
Keruspe Feb 6, 2017
05eef36
rustdoc: Improve impl disambiguation
ollie27 Feb 6, 2017
4268872
rustbuild: add verbose to config.toml.example
Keruspe Feb 6, 2017
52a887e
Remove some leftover makefiles.
Ms2ger Feb 8, 2017
4096dd6
Add more examples, get everything passing at last.
chriskrycho Feb 8, 2017
3022614
Add missing urls on join_paths
GuillaumeGomez Feb 8, 2017
51ef003
Fixed #39661
Henning-K Feb 8, 2017
cc455b3
Rollup merge of #37928 - chriskrycho:document-rfc-1623, r=steveklabnik
frewsxcv Feb 9, 2017
f045a41
Rollup merge of #39456 - nagisa:mir-switchint-everywhere, r=nikomatsakis
frewsxcv Feb 9, 2017
26efb21
Rollup merge of #39587 - Keruspe:master, r=alexcrichton
frewsxcv Feb 9, 2017
c744113
Rollup merge of #39589 - ollie27:rustdoc_impl_disambiguation, r=alexc…
frewsxcv Feb 9, 2017
3564084
Rollup merge of #39641 - Ms2ger:purge-mk, r=alexcrichton
frewsxcv Feb 9, 2017
805b2f6
Rollup merge of #39649 - GuillaumeGomez:join_paths-url, r=frewsxcv
frewsxcv Feb 9, 2017
14d894f
Rollup merge of #39662 - Henning-K:patch-1, r=steveklabnik
frewsxcv Feb 9, 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: 0 additions & 1 deletion mk/cfg/aarch64-unknown-freebsd.mk

This file was deleted.

1 change: 0 additions & 1 deletion mk/cfg/i686-unknown-netbsd.mk

This file was deleted.

2 changes: 2 additions & 0 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ struct Build {
python: Option<String>,
full_bootstrap: Option<bool>,
extended: Option<bool>,
verbose: Option<usize>,
}

/// TOML representation of various global install decisions.
Expand Down Expand Up @@ -294,6 +295,7 @@ impl Config {
set(&mut config.vendor, build.vendor);
set(&mut config.full_bootstrap, build.full_bootstrap);
set(&mut config.extended, build.extended);
set(&mut config.verbose, build.verbose);

if let Some(ref install) = toml.install {
config.prefix = install.prefix.clone().map(PathBuf::from);
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
# disabled by default.
#extended = false

# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
#verbose = 0

# =============================================================================
# General install configuration options
# =============================================================================
Expand Down
69 changes: 60 additions & 9 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1291,15 +1291,18 @@ guaranteed to refer to the same memory address.

Constant values must not have destructors, and otherwise permit most forms of
data. Constants may refer to the address of other constants, in which case the
address will have the `static` lifetime. The compiler is, however, still at
liberty to translate the constant many times, so the address referred to may not
be stable.
address will have elided lifetimes where applicable, otherwise – in most cases –
defaulting to the `static` lifetime. (See below on [static lifetime elision].)
The compiler is, however, still at liberty to translate the constant many times,
so the address referred to may not be stable.

[static lifetime elision]: #static-lifetime-elision

Constants must be explicitly typed. The type may be `bool`, `char`, a number, or
a type derived from those primitive types. The derived types are references with
the `static` lifetime, fixed-size arrays, tuples, enum variants, and structs.

```
```rust
const BIT1: u32 = 1 << 0;
const BIT2: u32 = 1 << 1;

Expand All @@ -1317,6 +1320,8 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
};
```



### Static items

A *static item* is similar to a *constant*, except that it represents a precise
Expand Down Expand Up @@ -1351,7 +1356,7 @@ running in the same process.
Mutable statics are still very useful, however. They can be used with C
libraries and can also be bound from C libraries (in an `extern` block).

```
```rust
# fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 }

static mut LEVELS: u32 = 0;
Expand All @@ -1375,6 +1380,53 @@ unsafe fn bump_levels_unsafe2() -> u32 {
Mutable statics have the same restrictions as normal statics, except that the
type of the value is not required to ascribe to `Sync`.

#### `'static` lifetime elision

[Unstable] Both constant and static declarations of reference types have
*implicit* `'static` lifetimes unless an explicit lifetime is specified. As
such, the constant declarations involving `'static` above may be written
without the lifetimes. Returning to our previous example:

```rust
# #![feature(static_in_const)]
const BIT1: u32 = 1 << 0;
const BIT2: u32 = 1 << 1;

const BITS: [u32; 2] = [BIT1, BIT2];
const STRING: &str = "bitstring";

struct BitsNStrings<'a> {
mybits: [u32; 2],
mystring: &'a str,
}

const BITS_N_STRINGS: BitsNStrings = BitsNStrings {
mybits: BITS,
mystring: STRING,
};
```

Note that if the `static` or `const` items include function or closure
references, which themselves include references, the compiler will first try the
standard elision rules ([see discussion in the nomicon][elision-nomicon]). If it
is unable to resolve the lifetimes by its usual rules, it will default to using
the `'static` lifetime. By way of example:

[elision-nomicon]: https://doc.rust-lang.org/nomicon/lifetime-elision.html

```rust,ignore
// Resolved as `fn<'a>(&'a str) -> &'a str`.
const RESOLVED_SINGLE: fn(&str) -> &str = ..

// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`.
const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..

// There is insufficient information to bound the return reference lifetime
// relative to the argument lifetimes, so the signature is resolved as
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
```

### Traits

A _trait_ describes an abstract interface that types can
Expand Down Expand Up @@ -2072,7 +2124,9 @@ macro scope.

### Miscellaneous attributes

- `deprecated` - mark the item as deprecated; the full attribute is `#[deprecated(since = "crate version", note = "...")`, where both arguments are optional.
- `deprecated` - mark the item as deprecated; the full attribute is
`#[deprecated(since = "crate version", note = "...")`, where both arguments
are optional.
- `export_name` - on statics and functions, this determines the name of the
exported symbol.
- `link_section` - on statics and functions, this specifies the section of the
Expand Down Expand Up @@ -2489,9 +2543,6 @@ The currently implemented features of the reference compiler are:
into a Rust program. This capability, especially the signature for the
annotated function, is subject to change.

* `static_in_const` - Enables lifetime elision with a `'static` default for
`const` and `static` item declarations.

* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
and should be seen as unstable. This attribute is used to
declare a `static` as being unique per-thread leveraging
Expand Down
11 changes: 11 additions & 0 deletions src/librustc/middle/const_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::rc::Rc;
use hir::def_id::DefId;
use rustc_const_math::*;
use self::ConstVal::*;
pub use rustc_const_math::ConstInt;

use std::collections::BTreeMap;

Expand Down Expand Up @@ -48,4 +49,14 @@ impl ConstVal {
Char(..) => "char",
}
}

pub fn to_const_int(&self) -> Option<ConstInt> {
match *self {
ConstVal::Integral(i) => Some(i),
ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
_ => None
}
}
}
67 changes: 33 additions & 34 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,36 +453,30 @@ pub enum TerminatorKind<'tcx> {
target: BasicBlock,
},

/// jump to branch 0 if this lvalue evaluates to true
If {
cond: Operand<'tcx>,
targets: (BasicBlock, BasicBlock),
},

/// lvalue evaluates to some enum; jump depending on the branch
Switch {
discr: Lvalue<'tcx>,
adt_def: &'tcx AdtDef,
targets: Vec<BasicBlock>,
},

/// operand evaluates to an integer; jump depending on its value
/// to one of the targets, and otherwise fallback to `otherwise`
SwitchInt {
/// discriminant value being tested
discr: Lvalue<'tcx>,
discr: Operand<'tcx>,

/// type of value being tested
switch_ty: Ty<'tcx>,

/// Possible values. The locations to branch to in each case
/// are found in the corresponding indices from the `targets` vector.
values: Vec<ConstVal>,

/// Possible branch sites. The length of this vector should be
/// equal to the length of the `values` vector plus 1 -- the
/// extra item is the block to branch to if none of the values
/// fit.
values: Cow<'tcx, [ConstInt]>,

/// Possible branch sites. The last element of this vector is used
/// for the otherwise branch, so values.len() == targets.len() + 1
/// should hold.
// This invariant is quite non-obvious and also could be improved.
// One way to make this invariant is to have something like this instead:
//
// branches: Vec<(ConstInt, BasicBlock)>,
// otherwise: Option<BasicBlock> // exhaustive if None
//
// However we’ve decided to keep this as-is until we figure a case
// where some other approach seems to be strictly better than other.
targets: Vec<BasicBlock>,
},

Expand Down Expand Up @@ -546,12 +540,21 @@ impl<'tcx> Terminator<'tcx> {
}

impl<'tcx> TerminatorKind<'tcx> {
pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
TerminatorKind::SwitchInt {
discr: cond,
switch_ty: tcx.types.bool,
values: From::from(BOOL_SWITCH_FALSE),
targets: vec![f, t],
}
}

pub fn successors(&self) -> Cow<[BasicBlock]> {
use self::TerminatorKind::*;
match *self {
Goto { target: ref b } => slice::ref_slice(b).into_cow(),
If { targets: (b1, b2), .. } => vec![b1, b2].into_cow(),
Switch { targets: ref b, .. } => b[..].into_cow(),
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
Resume => (&[]).into_cow(),
Return => (&[]).into_cow(),
Expand Down Expand Up @@ -580,8 +583,6 @@ impl<'tcx> TerminatorKind<'tcx> {
use self::TerminatorKind::*;
match *self {
Goto { target: ref mut b } => vec![b],
If { targets: (ref mut b1, ref mut b2), .. } => vec![b1, b2],
Switch { targets: ref mut b, .. } => b.iter_mut().collect(),
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
Resume => Vec::new(),
Return => Vec::new(),
Expand Down Expand Up @@ -659,8 +660,6 @@ impl<'tcx> TerminatorKind<'tcx> {
use self::TerminatorKind::*;
match *self {
Goto { .. } => write!(fmt, "goto"),
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
Return => write!(fmt, "return"),
Resume => write!(fmt, "resume"),
Expand Down Expand Up @@ -710,18 +709,11 @@ impl<'tcx> TerminatorKind<'tcx> {
match *self {
Return | Resume | Unreachable => vec![],
Goto { .. } => vec!["".into()],
If { .. } => vec!["true".into(), "false".into()],
Switch { ref adt_def, .. } => {
adt_def.variants
.iter()
.map(|variant| variant.name.to_string().into())
.collect()
}
SwitchInt { ref values, .. } => {
values.iter()
.map(|const_val| {
let mut buf = String::new();
fmt_const_val(&mut buf, const_val).unwrap();
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
buf.into()
})
.chain(iter::once(String::from("otherwise").into()))
Expand Down Expand Up @@ -997,6 +989,12 @@ pub enum Rvalue<'tcx> {

UnaryOp(UnOp, Operand<'tcx>),

/// Read the discriminant of an ADT.
///
/// Undefined (i.e. no effort is made to make it defined, but there’s no reason why it cannot
/// be defined to return, say, a 0) if ADT is not an enum.
Discriminant(Lvalue<'tcx>),

/// Creates an *uninitialized* Box
Box(Ty<'tcx>),

Expand Down Expand Up @@ -1111,6 +1109,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b)
}
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval),
Box(ref t) => write!(fmt, "Box({:?})", t),
InlineAsm { ref asm, ref outputs, ref inputs } => {
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
Expand Down
35 changes: 23 additions & 12 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use hir;
use ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub enum LvalueTy<'tcx> {
Expand Down Expand Up @@ -135,15 +136,15 @@ impl<'tcx> Lvalue<'tcx> {
impl<'tcx> Rvalue<'tcx> {
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
{
match self {
&Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
&Rvalue::Repeat(ref operand, ref count) => {
match *self {
Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
Rvalue::Repeat(ref operand, ref count) => {
let op_ty = operand.ty(mir, tcx);
let count = count.value.as_u64(tcx.sess.target.uint_type);
assert_eq!(count as usize as u64, count);
Some(tcx.mk_array(op_ty, count as usize))
}
&Rvalue::Ref(reg, bk, ref lv) => {
Rvalue::Ref(reg, bk, ref lv) => {
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
Some(tcx.mk_ref(reg,
ty::TypeAndMut {
Expand All @@ -152,27 +153,37 @@ impl<'tcx> Rvalue<'tcx> {
}
))
}
&Rvalue::Len(..) => Some(tcx.types.usize),
&Rvalue::Cast(.., ty) => Some(ty),
&Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
Rvalue::Len(..) => Some(tcx.types.usize),
Rvalue::Cast(.., ty) => Some(ty),
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
let lhs_ty = lhs.ty(mir, tcx);
let rhs_ty = rhs.ty(mir, tcx);
Some(op.ty(tcx, lhs_ty, rhs_ty))
}
&Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
let lhs_ty = lhs.ty(mir, tcx);
let rhs_ty = rhs.ty(mir, tcx);
let ty = op.ty(tcx, lhs_ty, rhs_ty);
let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
Some(ty)
}
&Rvalue::UnaryOp(_, ref operand) => {
Rvalue::UnaryOp(_, ref operand) => {
Some(operand.ty(mir, tcx))
}
&Rvalue::Box(t) => {
Rvalue::Discriminant(ref lval) => {
let ty = lval.ty(mir, tcx).to_ty(tcx);
if let ty::TyAdt(adt_def, _) = ty.sty {
Some(adt_def.discr_ty.to_ty(tcx))
} else {
// Undefined behaviour, bug for now; may want to return something for
// the `discriminant` intrinsic later.
bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty);
}
}
Rvalue::Box(t) => {
Some(tcx.mk_box(t))
}
&Rvalue::Aggregate(ref ak, ref ops) => {
Rvalue::Aggregate(ref ak, ref ops) => {
match *ak {
AggregateKind::Array => {
if let Some(operand) = ops.get(0) {
Expand All @@ -196,7 +207,7 @@ impl<'tcx> Rvalue<'tcx> {
}
}
}
&Rvalue::InlineAsm { .. } => None
Rvalue::InlineAsm { .. } => None
}
}
}
Expand Down
Loading