//! rustbuild, the Rust build system
//!
//! This is the entry point for the build system used to compile the `rustc`
-//! compiler. Lots of documentation can be found in the `README.md` file next to
-//! this file, and otherwise documentation can be found throughout the `build`
+//! compiler. Lots of documentation can be found in the `README.md` file in the
+//! parent directory, and otherwise documentation can be found throughout the `build`
//! directory in each respective module.
#![deny(warnings)]
rb.use_vendored_sources = '\nvendor = true' in rb.config_toml or \
'CFG_ENABLE_VENDOR' in rb.config_mk
- if 'SUDO_USER' in os.environ:
- if os.environ['USER'] != os.environ['SUDO_USER']:
+ if 'SUDO_USER' in os.environ and not rb.use_vendored_sources:
+ if os.environ.get('USER') != os.environ['SUDO_USER']:
rb.use_vendored_sources = True
print('info: looks like you are running this command under `sudo`')
print(' and so in order to preserve your $HOME this will now')
print(' use vendored sources by default. Note that if this')
print(' does not work you should run a normal build first')
- print(' before running a command like `sudo make intall`')
+ print(' before running a command like `sudo make install`')
if rb.use_vendored_sources:
if not os.path.exists('.cargo'):
"README.md",
"RELEASES.md",
"configure",
- "Makefile.in"
+ "Makefile.in",
+ "x.py",
];
let src_dirs = [
"man",
to generate warnings or errors, when an item is missing documentation.
To generate warnings you use `warn`:
-```rust
+```rust,ignore
#![warn(missing_docs)]
```
You can control a few aspects of the HTML that `rustdoc` generates through the
`#![doc]` version of the attribute:
-```rust
+```rust,ignore
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/")]
To use `#![no_std]`, add it to your crate root:
-```rust
+```rust,ignore
#![no_std]
fn plus_one(x: i32) -> i32 {
prelude](../core/prelude/v1/index.html). This means that a lot of code will Just
Work:
-```rust
+```rust,ignore
#![no_std]
fn may_fail(failure: bool) -> Result<(), &'static str> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
fn from(vec: Vec<T>) -> BinaryHeap<T> {
let mut heap = BinaryHeap { data: vec };
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
fn from(heap: BinaryHeap<T>) -> Vec<T> {
heap.data
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeUnicode {}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
+#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeUnicode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.clone() {
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDefault {}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
+#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.clone() {
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDebug {}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
+#[unstable(feature = "char_escape_debug", issue = "35068")]
impl fmt::Display for EscapeDebug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
type Err;
/// Performs the conversion.
- fn try_from(T) -> Result<Self, Self::Err>;
+ fn try_from(value: T) -> Result<Self, Self::Err>;
}
////////////////////////////////////////////////////////////////////////////////
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
(impl $imp:ident, $method:ident for $t:ty) => {
- #[stable(feature = "rust1", since = "1.0.0")]
+ forward_ref_unop!(impl $imp, $method for $t,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
+ #[$attr]
impl<'a> $imp for &'a $t {
type Output = <$t as $imp>::Output;
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
- #[stable(feature = "rust1", since = "1.0.0")]
+ forward_ref_binop!(impl $imp, $method for $t, $u,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+ #[$attr]
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;
}
}
- #[stable(feature = "rust1", since = "1.0.0")]
+ #[$attr]
impl<'a> $imp<&'a $u> for $t {
type Output = <$t as $imp<$u>>::Output;
}
}
- #[stable(feature = "rust1", since = "1.0.0")]
+ #[$attr]
impl<'a, 'b> $imp<&'a $u> for &'b $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn next(&mut self) -> Option<I::Item> {
- for x in self.iter.by_ref() {
+ for x in &mut self.iter {
if (self.predicate)(&x) {
return Some(x);
}
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}
+
+ // this special case allows the compiler to make `.filter(_).count()`
+ // branchless. Barring perfect branch prediction (which is unattainable in
+ // the general case), this will be much faster in >90% of cases (containing
+ // virtually all real workloads) and only a tiny bit slower in the rest.
+ //
+ // Having this specialization thus allows us to write `.filter(p).count()`
+ // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is
+ // less readable and also less backwards-compatible to Rust before 1.10.
+ //
+ // Using the branchless version will also simplify the LLVM byte code, thus
+ // leaving more budget for LLVM optimizations.
+ #[inline]
+ fn count(mut self) -> usize {
+ let mut count = 0;
+ for x in &mut self.iter {
+ count += (self.predicate)(&x) as usize;
+ }
+ count
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
// NB: explicitly use Add and Mul here to inherit overflow checks
macro_rules! integer_sum_product {
- (@impls $zero:expr, $one:expr, $($a:ty)*) => ($(
- #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+ (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
+ #[$attr]
impl Sum for $a {
fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
iter.fold($zero, Add::add)
}
}
- #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+ #[$attr]
impl Product for $a {
fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
iter.fold($one, Mul::mul)
}
}
- #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+ #[$attr]
impl<'a> Sum<&'a $a> for $a {
fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
iter.fold($zero, Add::add)
}
}
- #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+ #[$attr]
impl<'a> Product<&'a $a> for $a {
fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
iter.fold($one, Mul::mul)
}
)*);
($($a:ty)*) => (
- integer_sum_product!(@impls 0, 1, $($a)+);
- integer_sum_product!(@impls Wrapping(0), Wrapping(1), $(Wrapping<$a>)+);
+ integer_sum_product!(@impls 0, 1,
+ #[stable(feature = "iter_arith_traits", since = "1.12.0")],
+ $($a)+);
+ integer_sum_product!(@impls Wrapping(0), Wrapping(1),
+ #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
+ $(Wrapping<$a>)+);
);
}
macro_rules! int_module {
($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
- ($T:ident, $($attr: tt)*) => (
+ ($T:ident, #[$attr:meta]) => (
/// The smallest value that can be represented by this integer type.
- $($attr)*
+ #[$attr]
pub const MIN: $T = $T::min_value();
/// The largest value that can be represented by this integer type.
- $($attr)*
+ #[$attr]
pub const MAX: $T = $T::max_value();
)
}
macro_rules! uint_module {
($T:ident) => (uint_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
- ($T:ident, $($attr: tt)*) => (
+ ($T:ident, #[$attr:meta]) => (
/// The smallest value that can be represented by this integer type.
- $($attr)*
+ #[$attr]
pub const MIN: $T = $T::min_value();
/// The largest value that can be represented by this integer type.
- $($attr)*
+ #[$attr]
pub const MAX: $T = $T::max_value();
)
}
Wrapping(self.0.wrapping_add(other.0))
}
}
- forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl AddAssign for Wrapping<$t> {
Wrapping(self.0.wrapping_sub(other.0))
}
}
- forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl SubAssign for Wrapping<$t> {
Wrapping(self.0.wrapping_mul(other.0))
}
}
- forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl MulAssign for Wrapping<$t> {
Wrapping(self.0.wrapping_div(other.0))
}
}
- forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl DivAssign for Wrapping<$t> {
Wrapping(self.0.wrapping_rem(other.0))
}
}
- forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl RemAssign for Wrapping<$t> {
Wrapping(!self.0)
}
}
- forward_ref_unop! { impl Not, not for Wrapping<$t> }
+ forward_ref_unop! { impl Not, not for Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "rust1", since = "1.0.0")]
impl BitXor for Wrapping<$t> {
Wrapping(self.0 ^ other.0)
}
}
- forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl BitXorAssign for Wrapping<$t> {
Wrapping(self.0 | other.0)
}
}
- forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl BitOrAssign for Wrapping<$t> {
Wrapping(self.0 & other.0)
}
}
- forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
impl BitAndAssign for Wrapping<$t> {
Wrapping(0) - self
}
}
- forward_ref_unop! { impl Neg, neg for Wrapping<$t> }
+ forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
+ #[stable(feature = "wrapping_ref", since = "1.14.0")] }
)*)
}
}
}
+ /////////////////////////////////////////////////////////////////////////
+ // Entry-like operations to insert if None and return a reference
+ /////////////////////////////////////////////////////////////////////////
+
+ /// Inserts `v` into the option if it is `None`, then
+ /// returns a mutable reference to the contained value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_entry)]
+ ///
+ /// let mut x = None;
+ ///
+ /// {
+ /// let y: &mut u32 = x.get_or_insert(5);
+ /// assert_eq!(y, &5);
+ ///
+ /// *y = 7;
+ /// }
+ ///
+ /// assert_eq!(x, Some(7));
+ /// ```
+ #[inline]
+ #[unstable(feature = "option_entry", issue = "39288")]
+ pub fn get_or_insert(&mut self, v: T) -> &mut T {
+ match *self {
+ None => *self = Some(v),
+ _ => (),
+ }
+
+ match *self {
+ Some(ref mut v) => v,
+ _ => unreachable!(),
+ }
+ }
+
+ /// Inserts a value computed from `f` into the option if it is `None`, then
+ /// returns a mutable reference to the contained value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_entry)]
+ ///
+ /// let mut x = None;
+ ///
+ /// {
+ /// let y: &mut u32 = x.get_or_insert_with(|| 5);
+ /// assert_eq!(y, &5);
+ ///
+ /// *y = 7;
+ /// }
+ ///
+ /// assert_eq!(x, Some(7));
+ /// ```
+ #[inline]
+ #[unstable(feature = "option_entry", issue = "39288")]
+ pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
+ match *self {
+ None => *self = Some(f()),
+ _ => (),
+ }
+
+ match *self {
+ Some(ref mut v) => v,
+ _ => unreachable!(),
+ }
+ }
+
/////////////////////////////////////////////////////////////////////////
// Misc
/////////////////////////////////////////////////////////////////////////
fn index_mut(self, slice: &mut [T]) -> &mut Self::Output;
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for usize {
type Output = T;
}
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::Range<usize> {
type Output = [T];
}
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeTo<usize> {
type Output = [T];
}
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeFrom<usize> {
type Output = [T];
}
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeFull {
type Output = [T];
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> SliceIndex<T> for ops::RangeInclusive<usize> {
type Output = [T];
}
}
-#[stable(feature = "slice-get-slice-impls", since = "1.13.0")]
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> SliceIndex<T> for ops::RangeToInclusive<usize> {
type Output = [T];
unstable(feature = "integer_atomics", issue = "32976"),
u64 AtomicU64 ATOMIC_U64_INIT
}
+#[cfg(not(stage0))]
+#[cfg(target_has_atomic = "128")]
+atomic_int! {
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ i128 AtomicI128 ATOMIC_I128_INIT
+}
+#[cfg(not(stage0))]
+#[cfg(target_has_atomic = "128")]
+atomic_int! {
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ unstable(feature = "i128", issue = "35118"),
+ u128 AtomicU128 ATOMIC_U128_INIT
+}
#[cfg(target_has_atomic = "ptr")]
atomic_int!{
stable(feature = "rust1", since = "1.0.0"),
assert_eq!(xs.iter().count(), 6);
}
+#[test]
+fn test_iterator_filter_count() {
+ let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
+}
+
#[test]
fn test_iterator_peekable() {
let xs = vec![0, 1, 2, 3, 4, 5];
-Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc
+Subproject commit cb7f66732175e6171587ed69656b7aae7dd2e6ec
You can build a free-standing crate by adding `#![no_std]` to the crate
attributes:
-```
+```ignore
#![no_std]
```
"lifetimes or labels named `'_` were erroneously allowed"
}
+declare_lint! {
+ pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
+ Warn,
+ "attempt to resolve a trait on an expression whose type cannot be inferred but which \
+ currently defaults to ()"
+}
+
declare_lint! {
pub SAFE_EXTERN_STATICS,
Warn,
SUPER_OR_SELF_IN_GLOBAL_PATH,
HR_LIFETIME_IN_ASSOC_TYPE,
LIFETIME_UNDERSCORE,
+ RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
SAFE_EXTERN_STATICS,
PATTERNS_IN_FNS_WITHOUT_BODY,
EXTRA_REQUIREMENT_IN_IMPL,
PatKind::Tuple(ref subpats, ddpos) => {
// (p1, ..., pN)
let expected_len = match self.pat_ty(&pat)?.sty {
- ty::TyTuple(ref tys) => tys.len(),
+ ty::TyTuple(ref tys, _) => tys.len(),
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
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]);
+ let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
Some(ty)
}
&Rvalue::UnaryOp(_, ref operand) => {
}
AggregateKind::Tuple => {
Some(tcx.mk_tup(
- ops.iter().map(|op| op.ty(mir, tcx))
+ ops.iter().map(|op| op.ty(mir, tcx)),
+ false
))
}
AggregateKind::Adt(def, _, substs, _) => {
use std::rc::Rc;
use syntax::abi::Abi;
use hir;
+use lint;
use util::nodemap::FxHashMap;
struct InferredObligationsSnapshotVecDelegate<'tcx> {
debug!("select({:?})", obligation);
assert!(!obligation.predicate.has_escaping_regions());
+ let tcx = self.tcx();
let dep_node = obligation.predicate.dep_node();
- let _task = self.tcx().dep_graph.in_task(dep_node);
+ let _task = tcx.dep_graph.in_task(dep_node);
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
- match self.candidate_from_obligation(&stack)? {
- None => Ok(None),
+ let ret = match self.candidate_from_obligation(&stack)? {
+ None => None,
Some(candidate) => {
let mut candidate = self.confirm_candidate(obligation, candidate)?;
let inferred_obligations = (*self.inferred_obligations).into_iter().cloned();
candidate.nested_obligations_mut().extend(inferred_obligations);
- Ok(Some(candidate))
+ Some(candidate)
},
+ };
+
+ // Test whether this is a `()` which was produced by defaulting a
+ // diverging type variable with `!` disabled. If so, we may need
+ // to raise a warning.
+ if obligation.predicate.skip_binder().self_ty().is_defaulted_unit() {
+ let mut raise_warning = true;
+ // Don't raise a warning if the trait is implemented for ! and only
+ // permits a trivial implementation for !. This stops us warning
+ // about (for example) `(): Clone` becoming `!: Clone` because such
+ // a switch can't cause code to stop compiling or execute
+ // differently.
+ let mut never_obligation = obligation.clone();
+ let def_id = never_obligation.predicate.skip_binder().trait_ref.def_id;
+ never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| {
+ // Swap out () with ! so we can check if the trait is impld for !
+ {
+ let mut trait_ref = &mut trait_pred.trait_ref;
+ let unit_substs = trait_ref.substs;
+ let mut never_substs = Vec::with_capacity(unit_substs.len());
+ never_substs.push(From::from(tcx.types.never));
+ never_substs.extend(&unit_substs[1..]);
+ trait_ref.substs = tcx.intern_substs(&never_substs);
+ }
+ trait_pred
+ });
+ if let Ok(Some(..)) = self.select(&never_obligation) {
+ if !tcx.trait_relevant_for_never(def_id) {
+ // The trait is also implemented for ! and the resulting
+ // implementation cannot actually be invoked in any way.
+ raise_warning = false;
+ }
+ }
+
+ if raise_warning {
+ tcx.sess.add_lint(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
+ obligation.cause.body_id,
+ obligation.cause.span,
+ format!("code relies on type inference rules which are likely \
+ to change"));
+ }
}
+ Ok(ret)
}
///////////////////////////////////////////////////////////////////////////
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
}
let sized_crit = def.sized_constraint(self.tcx());
// (*) binder moved here
Where(ty::Binder(match sized_crit.sty {
- ty::TyTuple(tys) => tys.to_vec().subst(self.tcx(), substs),
+ ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
ty::TyBool => vec![],
_ => vec![sized_crit.subst(self.tcx(), substs)]
}))
Where(ty::Binder(vec![element_ty]))
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
// (*) binder moved here
Where(ty::Binder(tys.to_vec()))
}
vec![element_ty]
}
- ty::TyTuple(ref tys) => {
+ ty::TyTuple(ref tys, _) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
tys.to_vec()
}
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes =>
- self.intern_tup(sig.skip_binder().inputs()),
+ self.intern_tup(sig.skip_binder().inputs(), false),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
|ty| tc_ty(tcx, &ty, cache))
}
- ty::TyTuple(ref tys) => {
+ ty::TyTuple(ref tys, _) => {
TypeContents::union(&tys[..],
|ty| tc_ty(tcx, *ty, cache))
}
self.mk_ty(TySlice(ty))
}
- pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
- self.mk_ty(TyTuple(self.intern_type_list(ts)))
+ pub fn intern_tup(self, ts: &[Ty<'tcx>], defaulted: bool) -> Ty<'tcx> {
+ self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted))
}
- pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
- iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts))))
+ pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I,
+ defaulted: bool) -> I::Output {
+ iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted)))
}
pub fn mk_nil(self) -> Ty<'tcx> {
- self.intern_tup(&[])
+ self.intern_tup(&[], false)
}
pub fn mk_diverging_default(self) -> Ty<'tcx> {
if self.sess.features.borrow().never_type {
self.types.never
} else {
- self.mk_nil()
+ self.intern_tup(&[], true)
}
}
match self.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
- ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
+ ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyArray(_, n) => format!("array of {} elements", n),
|p| format!("trait {}", tcx.item_path_str(p.def_id())))
}
ty::TyClosure(..) => "closure".to_string(),
- ty::TyTuple(_) => "tuple".to_string(),
+ ty::TyTuple(..) => "tuple".to_string(),
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
Some(ClosureSimplifiedType(def_id))
}
ty::TyNever => Some(NeverSimplifiedType),
- ty::TyTuple(ref tys) => {
+ ty::TyTuple(ref tys, _) => {
Some(TupleSimplifiedType(tys.len()))
}
ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
self.add_ty(m.ty);
}
- &ty::TyTuple(ref ts) => {
+ &ty::TyTuple(ref ts, _) => {
self.add_tys(&ts[..]);
}
},
TyNever => DefIdForest::full(tcx),
- TyTuple(ref tys) => {
+ TyTuple(ref tys, _) => {
DefIdForest::union(tcx, tys.iter().map(|ty| {
ty.uninhabited_from(visited, tcx)
}))
ty::TyRawPtr(mt) |
ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
- ty::TyTuple(ref tys) => tys.iter()
- .filter_map(|ty| characteristic_def_id_of_type(ty))
- .next(),
+ ty::TyTuple(ref tys, _) => tys.iter()
+ .filter_map(|ty| characteristic_def_id_of_type(ty))
+ .next(),
ty::TyFnDef(def_id, ..) |
ty::TyClosure(def_id, _) => Some(def_id),
Some(&variant.memory_index[..]))
}
// Can we use one of the fields in this tuple?
- (&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
+ (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
Some(&variant.memory_index[..]))
}
Univariant { variant: st, non_zero: false }
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
// See the univariant case below to learn how.
let st = Struct::new(dl,
AssociatedKind::Type => Def::AssociatedTy(self.def_id),
}
}
+
+ /// Tests whether the associated item admits a non-trivial implementation
+ /// for !
+ pub fn relevant_for_never<'tcx>(&self) -> bool {
+ match self.kind {
+ AssociatedKind::Const => true,
+ AssociatedKind::Type => true,
+ // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
+ AssociatedKind::Method => !self.method_has_self_argument,
+ }
+ }
}
#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
_ if tys.references_error() => tcx.types.err,
0 => tcx.types.bool,
1 => tys[0],
- _ => tcx.intern_tup(&tys[..])
+ _ => tcx.intern_tup(&tys[..], false)
};
let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
vec![ty]
}
- TyTuple(ref tys) => {
+ TyTuple(ref tys, _) => {
match tys.last() {
None => vec![],
Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty)
.subst(tcx, substs);
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
ty, adt_ty);
- if let ty::TyTuple(ref tys) = adt_ty.sty {
+ if let ty::TyTuple(ref tys, _) = adt_ty.sty {
tys.iter().flat_map(|ty| {
self.sized_constraint_for_ty(tcx, stack, ty)
}).collect()
}
}
+ pub fn trait_relevant_for_never(self, did: DefId) -> bool {
+ self.associated_items(did).any(|item| {
+ item.relevant_for_never()
+ })
+ }
+
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
self.custom_coerce_unsized_kinds.memoize(did, || {
let (kind, src) = if did.krate != LOCAL_CRATE {
Ok(tcx.mk_slice(t))
}
- (&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
+ (&ty::TyTuple(as_, a_defaulted), &ty::TyTuple(bs, b_defaulted)) =>
{
if as_.len() == bs.len() {
- Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?)
+ let defaulted = a_defaulted || b_defaulted;
+ Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)), defaulted)?)
} else if !(as_.is_empty() || bs.is_empty()) {
Err(TypeError::TupleSize(
expected_found(relation, &as_.len(), &bs.len())))
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
ty::TyDynamic(ref trait_ty, ref region) =>
ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
- ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
+ ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted),
ty::TyFnDef(def_id, substs, f) => {
ty::TyFnDef(def_id,
substs.fold_with(folder),
ty::TyAdt(_, substs) => substs.visit_with(visitor),
ty::TyDynamic(ref trait_ty, ref reg) =>
trait_ty.visit_with(visitor) || reg.visit_with(visitor),
- ty::TyTuple(ts) => ts.visit_with(visitor),
+ ty::TyTuple(ts, _) => ts.visit_with(visitor),
ty::TyFnDef(_, substs, ref f) => {
substs.visit_with(visitor) || f.visit_with(visitor)
}
TyNever,
/// A tuple type. For example, `(i32, bool)`.
- TyTuple(&'tcx Slice<Ty<'tcx>>),
+ /// The bool indicates whether this is a unit tuple and was created by
+ /// defaulting a diverging type variable with feature(never_type) disabled.
+ /// It's only purpose is for raising future-compatibility warnings for when
+ /// diverging type variables start defaulting to ! instead of ().
+ TyTuple(&'tcx Slice<Ty<'tcx>>, bool),
/// The projection of an associated type. For example,
/// `<T as Trait<..>>::N`.
pub fn is_nil(&self) -> bool {
match self.sty {
- TyTuple(ref tys) => tys.is_empty(),
+ TyTuple(ref tys, _) => tys.is_empty(),
_ => false
}
}
}
}
+ // Test whether this is a `()` which was produced by defaulting a
+ // diverging type variable with feature(never_type) disabled.
+ pub fn is_defaulted_unit(&self) -> bool {
+ match self.sty {
+ TyTuple(_, true) => true,
+ _ => false,
+ }
+ }
+
/// Checks whether a type is visibly uninhabited from a particular module.
/// # Example
/// ```rust
TySlice(_) |
TyRawPtr(_) |
TyNever |
- TyTuple(_) |
+ TyTuple(..) |
TyParam(_) |
TyInfer(_) |
TyError => {
// Don't use `struct_variant`, this may be a univariant enum.
adt.variants[0].fields.get(i).map(|f| f.ty(self, substs))
}
- (&TyTuple(ref v), None) => v.get(i).cloned(),
+ (&TyTuple(ref v, _), None) => v.get(i).cloned(),
_ => None
}
}
self.def_id(d);
}
}
- TyTuple(tys) => {
+ TyTuple(tys, defaulted) => {
self.hash(tys.len());
+ self.hash(defaulted);
}
TyParam(p) => {
self.hash(p.idx);
seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
-> Representability {
match ty.sty {
- TyTuple(ref ts) => {
+ TyTuple(ref ts, _) => {
find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
}
// Fixed-length vectors.
ty::TyClosure(_, ref substs) => {
stack.extend(substs.substs.types().rev());
}
- ty::TyTuple(ts) => {
+ ty::TyTuple(ts, _) => {
stack.extend(ts.iter().cloned().rev());
}
ty::TyFnDef(_, substs, ref ft) => {
self.require_sized(subty, traits::SliceOrArrayElem);
}
- ty::TyTuple(ref tys) => {
+ ty::TyTuple(ref tys, _) => {
if let Some((_last, rest)) = tys.split_last() {
for elem in rest {
self.require_sized(elem, traits::TupleElem);
if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
let projection_ty = projections[0].ty;
- if let TyTuple(ref args) = substs.type_at(1).sty {
+ if let TyTuple(ref args, _) = substs.type_at(1).sty {
return fn_sig(f, args, false, projection_ty);
}
}
write!(f, "{}", tm)
}
TyNever => write!(f, "!"),
- TyTuple(ref tys) => {
+ TyTuple(ref tys, _) => {
write!(f, "(")?;
let mut tys = tys.iter();
if let Some(&ty) = tys.next() {
linker_is_gnu: true,
allow_asm: false,
obj_is_bitcode: true,
+ is_like_emscripten: true,
max_atomic_width: Some(32),
post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
target_family: Some("unix".to_string()),
/// Whether the target toolchain is like Android's. Only useful for compiling against Android.
/// Defaults to false.
pub is_like_android: bool,
+ /// Whether the target toolchain is like Emscripten's. Only useful for compiling with
+ /// Emscripten toolchain.
+ /// Defaults to false.
+ pub is_like_emscripten: bool,
/// Whether the linker support GNU-like arguments such as -O. Defaults to false.
pub linker_is_gnu: bool,
/// The MinGW toolchain has a known issue that prevents it from correctly
is_like_solaris: false,
is_like_windows: false,
is_like_android: false,
+ is_like_emscripten: false,
is_like_msvc: false,
linker_is_gnu: false,
allows_weak_linkage: true,
key!(is_like_solaris, bool);
key!(is_like_windows, bool);
key!(is_like_msvc, bool);
+ key!(is_like_emscripten, bool);
key!(is_like_android, bool);
key!(linker_is_gnu, bool);
key!(allows_weak_linkage, bool);
target_option_val!(is_like_solaris);
target_option_val!(is_like_windows);
target_option_val!(is_like_msvc);
+ target_option_val!(is_like_emscripten);
target_option_val!(is_like_android);
target_option_val!(linker_is_gnu);
target_option_val!(allows_weak_linkage);
linker_is_gnu: true,
allow_asm: false,
obj_is_bitcode: true,
+ is_like_emscripten: true,
max_atomic_width: Some(32),
post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
"-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
};
match parent_ty.sty {
- ty::TyTuple(ref v) => {
+ ty::TyTuple(ref v, _) => {
let tuple_idx = match *origin_field_name {
mc::PositionalField(tuple_idx) => tuple_idx,
mc::NamedField(_) =>
let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect();
self.open_drop_for_tuple(c, &tys)
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
self.open_drop_for_tuple(c, tys)
}
ty::TyAdt(def, _) if def.is_box() => {
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
debug!("constructor_arity({:?}, {:?})", ctor, ty);
match ty.sty {
- ty::TyTuple(ref fs) => fs.len(),
+ ty::TyTuple(ref fs, _) => fs.len(),
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
Slice(length) => length,
ConstantValue(_) => 0,
{
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
match ty.sty {
- ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(),
+ ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
Slice(length) => repeat(ty).take(length).collect(),
ConstantValue(_) => vec![],
PatKind::Tuple(ref subpatterns, ddpos) => {
let ty = self.tables.node_id_to_type(pat.id);
match ty.sty {
- ty::TyTuple(ref tys) => {
+ ty::TyTuple(ref tys, _) => {
let subpatterns =
subpatterns.iter()
.enumerate_and_adjust(tys.len(), ddpos)
}
pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
- self.infcx.tcx.intern_tup(&[ty1, ty2])
+ self.infcx.tcx.intern_tup(&[ty1, ty2], false)
}
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
let tcx = env.infcx.tcx;
let int_ty = tcx.types.isize;
let uint_ty = tcx.types.usize;
- let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
- let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
+ let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
+ let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
let walked: Vec<_> = tup2_ty.walk().collect();
assert_eq!(walked,
[tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty,
let tcx = env.infcx.tcx;
let int_ty = tcx.types.isize;
let uint_ty = tcx.types.usize;
- let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
- let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
+ let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
+ let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
// types we expect to see (in order), plus a boolean saying
// whether to skip the subtree.
id: LintId::of(LIFETIME_UNDERSCORE),
reference: "issue #36892 <https://github.com/rust-lang/rust/issues/36892>",
},
+ FutureIncompatibleInfo {
+ id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
+ reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
+ },
FutureIncompatibleInfo {
id: LintId::of(SAFE_EXTERN_STATICS),
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/35112>",
consider using a `*const libc::c_char`")
}
- ty::TyTuple(_) => {
+ ty::TyTuple(..) => {
FfiUnsafe("found Rust tuple type in foreign module; \
consider using a struct instead")
}
let t = cx.tables.expr_ty(&expr);
let warned = match t.sty {
- ty::TyTuple(ref tys) if tys.is_empty() => return,
+ ty::TyTuple(ref tys, _) if tys.is_empty() => return,
ty::TyNever => return,
ty::TyBool => return,
ty::TyAdt(def, _) => {
use proc_macro::TokenStream;
use proc_macro::__internal::Registry;
use rustc_back::dynamic_lib::DynamicLibrary;
- use syntax_ext::deriving::custom::CustomDerive;
+ use syntax_ext::deriving::custom::ProcMacroDerive;
use syntax_ext::proc_macro_impl::AttrProcMacro;
let path = match dylib {
expand: fn(TokenStream) -> TokenStream,
attributes: &[&'static str]) {
let attrs = attributes.iter().cloned().map(Symbol::intern).collect();
- let derive = SyntaxExtension::CustomDerive(
- Box::new(CustomDerive::new(expand, attrs))
+ let derive = SyntaxExtension::ProcMacroDerive(
+ Box::new(ProcMacroDerive::new(expand, attrs))
);
self.0.push((Symbol::intern(trait_name), Rc::new(derive)));
}
let source_info = self.source_info(span);
let bool_ty = self.hir.bool_ty();
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
- let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
+ let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false);
let result_value = self.temp(result_tup);
self.cfg.push_assign(block, source_info,
})
}
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
return match tys.get(field.index()) {
Some(&ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
"an `extern crate` loading macros must be at the crate root");
} else if !self.use_extern_macros && !used &&
self.session.cstore.dep_kind(module.def_id().unwrap().krate).macros_only() {
- let msg = "custom derive crates and `#[no_link]` crates have no effect without \
+ let msg = "proc macro crates and `#[no_link]` crates have no effect without \
`#[macro_use]`";
self.session.span_warn(item.span, msg);
used = true; // Avoid the normal unused extern crate warning
}
result
}
+
+ fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
+ match self.builtin_macros.get(&tname).cloned() {
+ Some(binding) => Ok(binding.get_macro(self)),
+ None => Err(Determinacy::Undetermined),
+ }
+ }
+
+ fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy> {
+ let ast::Path { span, .. } = *path;
+ match self.resolve_macro(scope, path, false) {
+ Ok(ext) => match *ext {
+ SyntaxExtension::BuiltinDerive(..) |
+ SyntaxExtension::ProcMacroDerive(..) => Ok(ext),
+ _ => Err(Determinacy::Determined),
+ },
+ Err(Determinacy::Undetermined) if force => {
+ let msg = format!("cannot find derive macro `{}` in this scope", path);
+ let mut err = self.session.struct_span_err(span, &msg);
+ err.emit();
+ Err(Determinacy::Determined)
+ },
+ Err(err) => Err(err),
+ }
+ }
}
impl<'a> Resolver<'a> {
let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| {
if *i == ident { return None; } // Never suggest the same name
match *resolution.borrow() {
- NameResolution { binding: Some(_), .. } => Some(&i.name),
+ NameResolution { binding: Some(name_binding), .. } => {
+ match name_binding.kind {
+ NameBindingKind::Import { binding, .. } => {
+ match binding.kind {
+ // Never suggest the name that has binding error
+ // i.e. the name that cannot be previously resolved
+ NameBindingKind::Def(Def::Err) => return None,
+ _ => Some(&i.name),
+ }
+ },
+ _ => Some(&i.name),
+ }
+ },
NameResolution { single_imports: SingleImports::None, .. } => None,
_ => Some(&i.name),
}
}.lower(self.tcx));
}
}
- ty::TyTuple(_) => {}
+ ty::TyTuple(..) => {}
_ => span_bug!(ex.span,
"Expected struct or tuple type, found {:?}",
ty),
-> Option<TypeRefData> {
self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
let span = trait_ref.path.span;
+ if generated_code(span) {
+ return None;
+ }
let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
filter!(self.span_utils, sub_span, span, None);
Some(TypeRefData {
assert!(!sig.variadic && extra_args.is_empty());
match sig.inputs().last().unwrap().sty {
- ty::TyTuple(ref tupled_arguments) => {
+ ty::TyTuple(ref tupled_arguments, _) => {
inputs = &sig.inputs()[0..sig.inputs().len() - 1];
&tupled_arguments[..]
}
monomorphize::field_ty(cx.tcx(), substs, f)
}).collect::<Vec<_>>()
},
- ty::TyTuple(fields) => fields.to_vec(),
+ ty::TyTuple(fields, _) => fields.to_vec(),
ty::TyClosure(def_id, substs) => {
if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);}
substs.upvar_tys(def_id, cx.tcx()).collect()
use rustc::hir::def_id::CrateNum;
use rustc::hir::svh::Svh;
use rustc_back::tempdir::TempDir;
+use rustc_back::PanicStrategy;
use rustc_incremental::IncrementalHashesMap;
use std::ascii;
cmd.arg(root.join(obj));
}
+ if sess.target.target.options.is_like_emscripten &&
+ sess.panic_strategy() == PanicStrategy::Abort {
+ cmd.args(&["-s", "DISABLE_EXCEPTION_CATCHING=1"]);
+ }
+
{
let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
link_args(&mut *linker, sess, crate_type, tmpdir,
}
};
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
- let tuple_input_ty = tcx.intern_tup(sig.inputs());
+ let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
let sig = tcx.mk_fn_sig(
[bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
sig.output(),
output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
}
}
- ty::TyTuple(args) => {
+ ty::TyTuple(args, _) => {
for arg in args {
let arg = glue::get_drop_glue_type(scx, arg);
if scx.type_needs_drop(arg) {
}
}))
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
if tys.len() != 2 {
return None;
}
// return type
signature_metadata.push(match signature.output().sty {
- ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+ ty::TyTuple(ref tys, _) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, signature.output(), span)
});
ty::TyFloat(_) => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
}
- ty::TyTuple(ref elements) if elements.is_empty() => {
+ ty::TyTuple(ref elements, _) if elements.is_empty() => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
}
ty::TyArray(typ, len) => {
usage_site_span).finalize(cx)
}
},
- ty::TyTuple(ref elements) => {
+ ty::TyTuple(ref elements, _) => {
prepare_tuple_metadata(cx,
t,
&elements[..],
let (name, encoding) = match t.sty {
ty::TyNever => ("!", DW_ATE_unsigned),
- ty::TyTuple(ref elements) if elements.is_empty() =>
+ ty::TyTuple(ref elements, _) if elements.is_empty() =>
("()", DW_ATE_unsigned),
ty::TyBool => ("bool", DW_ATE_boolean),
ty::TyChar => ("char", DW_ATE_unsigned_char),
// Return type -- llvm::DIBuilder wants this at index 0
signature.push(match sig.output().sty {
- ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+ ty::TyTuple(ref tys, _) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
});
}
if abi == Abi::RustCall && !sig.inputs().is_empty() {
- if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
+ if let ty::TyTuple(args, _) = sig.inputs()[sig.inputs().len() - 1].sty {
for &argument_type in args {
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
push_item_name(cx, def.did, qualified, output);
push_type_params(cx, substs, output);
},
- ty::TyTuple(component_types) => {
+ ty::TyTuple(component_types, _) => {
output.push('(');
for &component_type in component_types {
push_debuginfo_type_name(cx, component_type, true, output);
cx = tvec::slice_for_each(&cx, ptr.llval, unit_ty, ptr.llextra,
|bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
}
- ty::TyTuple(ref args) => {
+ ty::TyTuple(ref args, _) => {
for (i, arg) in args.iter().enumerate() {
let llfld_a = ptr.trans_field_ptr(&cx, i);
drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg));
let tuple = self.trans_operand(bcx, operand);
let arg_types = match tuple.ty.sty {
- ty::TyTuple(ref tys) => tys,
+ ty::TyTuple(ref tys, _) => tys,
_ => span_bug!(self.mir.span,
"bad final argument to \"rust-call\" fn {:?}", tuple.ty)
};
let rhs = self.const_operand(rhs, span)?;
let ty = lhs.ty;
let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
- let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool]);
+ let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
let (lhs, rhs) = (lhs.llval, rhs.llval);
assert!(!ty.is_fp());
// individual LLVM function arguments.
let tupled_arg_tys = match arg_ty.sty {
- ty::TyTuple(ref tys) => tys,
+ ty::TyTuple(ref tys, _) => tys,
_ => bug!("spread argument isn't a tuple?!")
};
lhs.immediate(), rhs.immediate(),
lhs.ty);
let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty);
- let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool]);
+ let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool], false);
let operand = OperandRef {
val: result,
ty: operand_ty
self.push_def_path(adt_def.did, output);
self.push_type_params(substs, iter::empty(), output);
},
- ty::TyTuple(component_types) => {
+ ty::TyTuple(component_types, _) => {
output.push('(');
for &component_type in component_types {
self.push_type_name(component_type, output);
Type::array(&llty, size)
}
- ty::TyTuple(ref tys) if tys.is_empty() => {
+ ty::TyTuple(ref tys, _) if tys.is_empty() => {
Type::nil(cx)
}
let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
}
- ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
+ ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
ty::TyTuple(..) => {
adt::type_of(cx, t)
}
span: output_span
};
- (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding)
+ (self.tcx().mk_ty(ty::TyTuple(inputs, false)), output_binding)
}
/// Instantiates the path for the given trait reference, assuming that it's
tcx.types.never
},
hir::TyTup(ref fields) => {
- tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
+ tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)), false)
}
hir::TyBareFn(ref bf) => {
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
let mut expected_len = elements.len();
if ddpos.is_some() {
// Require known type only when `..` is present
- if let ty::TyTuple(ref tys) =
+ if let ty::TyTuple(ref tys, _) =
self.structurally_resolved_type(pat.span, expected).sty {
expected_len = tys.len();
}
// from all tuple elements isn't trivial.
TypeVariableOrigin::TypeInference(pat.span)));
let element_tys = tcx.mk_type_list(element_tys_iter);
- let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys));
+ let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
self.demand_eqtype(pat.span, expected, pat_ty);
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat(elem, &element_tys[i]);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
fn_ty.sig.0 = self.tcx.mk_fn_sig(
- iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())),
+ iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs(), false)),
fn_ty.sig.skip_binder().output(),
fn_ty.sig.variadic()
);
arg_param_ty);
let input_tys = match arg_param_ty.sty {
- ty::TyTuple(tys) => tys.into_iter(),
+ ty::TyTuple(tys, _) => tys.into_iter(),
_ => {
return None;
}
Ok(())
}
- ty::TyTuple(tys) => {
+ ty::TyTuple(tys, _) => {
for ty in tys {
iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
}
"cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)),
param(ccx, 0),
param(ccx, 0)],
- tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
+ tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
"load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))],
param(ccx, 0)),
"store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>
(1, vec![param(ccx, 0), param(ccx, 0)],
- tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
+ tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
"unchecked_div" | "unchecked_rem" =>
(1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
match *expected {
Void => match t.sty {
- ty::TyTuple(ref v) if v.is_empty() => {},
+ ty::TyTuple(ref v, _) if v.is_empty() => {},
_ => simple_error(&format!("`{}`", t), "()"),
},
// (The width we pass to LLVM doesn't concern the type checker.)
}
Aggregate(_flatten, ref expected_contents) => {
match t.sty {
- ty::TyTuple(contents) => {
+ ty::TyTuple(contents, _) => {
if contents.len() != expected_contents.len() {
simple_error(&format!("tuple with length {}", contents.len()),
&format!("tuple with length {}", expected_contents.len()));
}
/// Apply "fallbacks" to some types
- /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
+ /// unconstrained types get replaced with ! or () (depending on whether
+ /// feature(never_type) is enabled), unconstrained ints with i32, and
+ /// unconstrained floats with f64.
fn default_type_parameters(&self) {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
let err_inputs = match tuple_arguments {
DontTupleArguments => err_inputs,
- TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
+ TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)],
};
self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
let formal_tys = if tuple_arguments == TupleArguments {
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
match tuple_type.sty {
- ty::TyTuple(arg_types) if arg_types.len() != args.len() => {
+ ty::TyTuple(arg_types, _) if arg_types.len() != args.len() => {
parameter_count_error(tcx.sess, sp_args, arg_types.len(), args.len(),
"E0057", false, def_span);
expected_arg_tys = &[];
self.err_args(args.len())
}
- ty::TyTuple(arg_types) => {
+ ty::TyTuple(arg_types, _) => {
expected_arg_tys = match expected_arg_tys.get(0) {
Some(&ty) => match ty.sty {
- ty::TyTuple(ref tys) => &tys,
+ ty::TyTuple(ref tys, _) => &tys,
_ => &[]
},
None => &[]
}
})
}
- ty::TyTuple(ref v) => {
+ ty::TyTuple(ref v, _) => {
tuple_like = true;
v.get(idx.node).cloned()
}
hir::ExprTup(ref elts) => {
let flds = expected.only_has_type(self).and_then(|ty| {
match ty.sty {
- ty::TyTuple(ref flds) => Some(&flds[..]),
+ ty::TyTuple(ref flds, _) => Some(&flds[..]),
_ => None
}
});
};
t
});
- let tuple = tcx.mk_tup(elt_ts_iter);
+ let tuple = tcx.mk_tup(elt_ts_iter, false);
if tuple.references_error() {
tcx.types.err
} else {
},
base_t);
// Try to give some advice about indexing tuples.
- if let ty::TyTuple(_) = base_t.sty {
+ if let ty::TyTuple(..) = base_t.sty {
let mut needs_note = true;
// If the index is an integer, we can show the actual
// fixed expression:
self.add_constraints_from_mt(generics, mt, variance);
}
- ty::TyTuple(subtys) => {
+ ty::TyTuple(subtys, _) => {
for &subty in subtys {
self.add_constraints_from_ty(generics, subty, variance);
}
Some(did) if cx.tcx.lang_items.fn_trait_kind(did).is_some() => {
assert_eq!(types.len(), 1);
let inputs = match types[0].sty {
- ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
+ ty::TyTuple(ref tys, _) => tys.iter().map(|t| t.clean(cx)).collect(),
_ => {
return PathParameters::AngleBracketed {
lifetimes: lifetimes,
let output = None;
// FIXME(#20299) return type comes from a projection now
// match types[1].sty {
- // ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
+ // ty::TyTuple(ref v, _) if v.is_empty() => None, // -> ()
// _ => Some(types[1].clean(cx))
// };
PathParameters::Parenthesized {
// collect any late bound regions
let mut late_bounds = vec![];
for ty_s in self.input_types().skip(1) {
- if let ty::TyTuple(ts) = ty_s.sty {
+ if let ty::TyTuple(ts, _) = ty_s.sty {
for &ty_s in ts {
if let ty::TyRef(ref reg, _) = ty_s.sty {
if let &ty::Region::ReLateBound(..) = *reg {
Never
}
}
- ty::TyTuple(ref t) => Tuple(t.clean(cx)),
+ ty::TyTuple(ref t, _) => Tuple(t.clean(cx)),
ty::TyProjection(ref data) => data.clean(cx),
nightly_options::check_nightly_options(&matches, &opts());
if matches.opt_present("h") || matches.opt_present("help") {
- usage(&args[0]);
+ usage("rustdoc");
return 0;
} else if matches.opt_present("version") {
rustc_driver::version("rustdoc", &matches);
prog
}
+// FIXME(aburka): use a real parser to deal with multiline attributes
fn partition_source(s: &str) -> (String, String) {
use std_unicode::str::UnicodeStr;
for line in s.lines() {
let trimline = line.trim();
let header = trimline.is_whitespace() ||
- trimline.starts_with("#![feature");
+ trimline.starts_with("#![");
if !header || after_header {
after_header = true;
after.push_str(line);
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDefault {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("EscapeDefault { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K, V> fmt::Debug for IterMut<'a, K, V>
where K: fmt::Debug,
V: fmt::Debug,
#[unstable(feature = "fused", issue = "35602")]
impl<K, V> FusedIterator for IntoIter<K, V> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<K: Debug, V: Debug> fmt::Debug for IntoIter<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V>
where K: fmt::Debug,
V: fmt::Debug,
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K, V> fmt::Debug for Drain<'a, K, V>
where K: fmt::Debug,
V: fmt::Debug,
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for RandomState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("RandomState { .. }")
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K> FusedIterator for Iter<'a, K> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
#[unstable(feature = "fused", issue = "35602")]
impl<K> FusedIterator for IntoIter<K> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<K: fmt::Debug> fmt::Debug for IntoIter<K> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entries_iter = self.iter.inner.iter().map(|(k, _)| k);
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K> FusedIterator for Drain<'a, K> {}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entries_iter = self.iter.inner.iter().map(|(k, _)| k);
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T, S> fmt::Debug for Intersection<'a, T, S>
where T: fmt::Debug + Eq + Hash,
S: BuildHasher,
{
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T, S> fmt::Debug for Difference<'a, T, S>
where T: fmt::Debug + Eq + Hash,
S: BuildHasher,
{
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S>
where T: fmt::Debug + Eq + Hash,
S: BuildHasher,
{
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T, S> fmt::Debug for Union<'a, T, S>
where T: fmt::Debug + Eq + Hash,
S: BuildHasher,
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Vars {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Vars { .. }")
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for VarsOs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("VarsOs { .. }")
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for SplitPaths<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("SplitPaths { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Args { .. }")
fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for ArgsOs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("ArgsOs { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Metadata {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Metadata")
done_first: bool,
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Chain")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stdin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stdin { .. }")
fn consume(&mut self, n: usize) { self.inner.consume(n) }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StdinLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StdinLock { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stdout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stdout { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StdoutLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StdoutLock { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stderr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stderr { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StderrLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StderrLock { .. }")
fn consume(&mut self, _n: usize) {}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Empty { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Repeat { .. }")
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Sink { .. }")
#![feature(oom)]
#![feature(optin_builtin_traits)]
#![feature(panic_unwind)]
+#![feature(peek)]
#![feature(placement_in_syntax)]
#![feature(prelude_import)]
#![feature(pub_restricted)]
fn next(&mut self) -> Option<SocketAddr> { self.0.next() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+ iterator and returning socket \
+ addresses",
+ issue = "27705")]
impl fmt::Debug for LookupHost {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("LookupHost { .. }")
self.0.write_timeout()
}
+ /// Receives data on the socket from the remote adress to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peek)]
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:8000")
+ /// .expect("couldn't bind to address");
+ /// let mut buf = [0; 10];
+ /// let len = stream.peek(&mut buf).expect("peek failed");
+ /// ```
+ #[unstable(feature = "peek", issue = "38980")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
/// Sets the value of the `TCP_NODELAY` option on this socket.
///
/// If set, this option disables the Nagle algorithm. This means that
Err(e) => panic!("unexpected error {}", e),
}
}
+
+ #[test]
+ fn peek() {
+ each_ip(&mut |addr| {
+ let (txdone, rxdone) = channel();
+
+ let srv = t!(TcpListener::bind(&addr));
+ let _t = thread::spawn(move|| {
+ let mut cl = t!(srv.accept()).0;
+ cl.write(&[1,3,3,7]).unwrap();
+ t!(rxdone.recv());
+ });
+
+ let mut c = t!(TcpStream::connect(&addr));
+ let mut b = [0; 10];
+ for _ in 1..3 {
+ let len = c.peek(&mut b).unwrap();
+ assert_eq!(len, 4);
+ }
+ let len = c.read(&mut b).unwrap();
+ assert_eq!(len, 4);
+
+ t!(c.set_nonblocking(true));
+ match c.peek(&mut b) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error {}", e),
+ }
+ t!(txdone.send(()));
+ })
+ }
}
self.0.recv_from(buf)
}
+ /// Receives data from the socket, without removing it from the queue.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+ ///
+ /// On success, returns the number of bytes peeked and the address from
+ /// whence the data came.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peek)]
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// let mut buf = [0; 10];
+ /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf)
+ /// .expect("Didn't receive data");
+ /// ```
+ #[unstable(feature = "peek", issue = "38980")]
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0.peek_from(buf)
+ }
+
/// Sends data on the socket to the given address. On success, returns the
/// number of bytes written.
///
self.0.recv(buf)
}
+ /// Receives data on the socket from the remote adress to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Errors
+ ///
+ /// This method will fail if the socket is not connected. The `connect` method
+ /// will connect this socket to a remote address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peek)]
+ /// use std::net::UdpSocket;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+ /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+ /// let mut buf = [0; 10];
+ /// match socket.peek(&mut buf) {
+ /// Ok(received) => println!("received {} bytes", received),
+ /// Err(e) => println!("peek function failed: {:?}", e),
+ /// }
+ /// ```
+ #[unstable(feature = "peek", issue = "38980")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
/// Moves this UDP socket into or out of nonblocking mode.
///
/// On Unix this corresponds to calling fcntl, and on Windows this
assert_eq!(b"hello world", &buf[..]);
}
+ #[test]
+ fn connect_send_peek_recv() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.connect(addr));
+
+ t!(socket.send(b"hello world"));
+
+ for _ in 1..3 {
+ let mut buf = [0; 11];
+ let size = t!(socket.peek(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ }
+
+ let mut buf = [0; 11];
+ let size = t!(socket.recv(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ })
+ }
+
+ #[test]
+ fn peek_from() {
+ each_ip(&mut |addr, _| {
+ let socket = t!(UdpSocket::bind(&addr));
+ t!(socket.send_to(b"hello world", &addr));
+
+ for _ in 1..3 {
+ let mut buf = [0; 11];
+ let (size, _) = t!(socket.peek_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ }
+
+ let mut buf = [0; 11];
+ let (size, _) = t!(socket.recv_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+ assert_eq!(size, 11);
+ })
+ }
+
#[test]
fn ttl() {
let ttl = 100;
#[doc(hidden)] __variant2,
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("c_void")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("AssertUnwindSafe")
fn into_inner(self) -> imp::Process { self.handle }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Child {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Child")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for ChildStdin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("ChildStdin { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for ChildStdout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("ChildStdout { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for ChildStderr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("ChildStderr { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stdio {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stdio { .. }")
///
/// # Examples
///
+/// Due to this function’s behavior regarding destructors, a conventional way
+/// to use the function is to extract the actual computation to another
+/// function and compute the exit code from its return value:
+///
/// ```
-/// use std::process;
+/// use std::io::{self, Write};
+///
+/// fn run_app() -> Result<(), ()> {
+/// // Application logic here
+/// Ok(())
+/// }
///
-/// process::exit(0);
+/// fn main() {
+/// ::std::process::exit(match run_app() {
+/// Ok(_) => 0,
+/// Err(err) => {
+/// writeln!(io::stderr(), "error: {:?}", err).unwrap();
+/// 1
+/// }
+/// });
+/// }
/// ```
///
/// Due to [platform-specific behavior], the exit code for this example will be
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Barrier { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BarrierWaitResult")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Condvar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Condvar { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("MutexGuard")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Once {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Once { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RwLockReadGuard")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RwLockWriteGuard")
/// an error indicating why the exec (or another part of the setup of the
/// `Command`) failed.
///
+ /// `exec` not returning has the same implications as calling
+ /// [`process::exit`] – no destructors on the current stack or any other
+ /// thread’s stack will be run. Therefore, it is recommended to only call
+ /// `exec` at a point where it is fine to not run any destructors. Note,
+ /// that the `execvp` syscall independently guarantees that all memory is
+ /// freed and all file descriptors with the `CLOEXEC` option (set by default
+ /// on all file descriptors opened by the standard library) are closed.
+ ///
/// This function, unlike `spawn`, will **not** `fork` the process to create
/// a new child. Like spawn, however, the default behavior for the stdio
/// descriptors will be to inherited from the current process.
///
+ /// [`process::exit`]: ../../../process/fn.exit.html
+ ///
/// # Notes
///
/// The process may be in a "broken state" if this function returns in
use ffi::CStr;
use io;
-use libc::{self, c_int, size_t, sockaddr, socklen_t, EAI_SYSTEM};
+use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
+use mem;
use net::{SocketAddr, Shutdown};
use str;
use sys::fd::FileDesc;
use sys_common::{AsInner, FromInner, IntoInner};
-use sys_common::net::{getsockopt, setsockopt};
+use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
use time::Duration;
pub use sys::{cvt, cvt_r};
self.0.duplicate().map(Socket)
}
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::recv(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags)
+ })?;
+ Ok(ret as usize)
+ }
+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, MSG_PEEK)
+ }
+
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+ -> io::Result<(usize, SocketAddr)> {
+ let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
+
+ let n = cvt(unsafe {
+ libc::recvfrom(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen)
+ })?;
+ Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, MSG_PEEK)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
+pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
pub const IP_DROP_MEMBERSHIP: c_int = 13;
pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
+pub const MSG_PEEK: c_int = 0x2;
#[repr(C)]
pub struct ip_mreq {
let src = to_u16s(src)?;
let dst = to_u16s(dst)?;
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
- cvt(unsafe {
- c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL
- })?;
+ // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
+ // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
+ // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be
+ // added to dwFlags to opt into this behaviour.
+ let result = cvt(unsafe {
+ c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(),
+ flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL
+ });
+ if let Err(err) = result {
+ if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) {
+ // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE,
+ // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag.
+ cvt(unsafe {
+ c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL
+ })?;
+ } else {
+ return Err(err);
+ }
+ }
Ok(())
}
Ok(socket)
}
- pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
let len = cmp::min(buf.len(), i32::max_value() as usize) as i32;
unsafe {
- match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, 0) {
+ match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
-1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-1 => Err(last_error()),
n => Ok(n as usize)
}
}
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, c::MSG_PEEK)
+ }
+
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+ -> io::Result<(usize, SocketAddr)> {
+ let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
+ let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+
+ // On unix when a socket is shut down all further reads return 0, so we
+ // do the same on windows to map a shut down socket to returning EOF.
+ unsafe {
+ match c::recvfrom(self.0,
+ buf.as_mut_ptr() as *mut c_void,
+ len,
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen) {
+ -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => {
+ Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+ },
+ -1 => Err(last_error()),
+ n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
+ }
+ }
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, c::MSG_PEEK)
+ }
+
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
}
-fn sockaddr_to_addr(storage: &c::sockaddr_storage,
+pub fn sockaddr_to_addr(storage: &c::sockaddr_storage,
len: usize) -> io::Result<SocketAddr> {
match storage.ss_family as c_int {
c::AF_INET => {
self.inner.timeout(c::SO_SNDTIMEO)
}
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
- let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
- let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+ self.inner.recv_from(buf)
+ }
- let n = cvt(unsafe {
- c::recvfrom(*self.inner.as_inner(),
- buf.as_mut_ptr() as *mut c_void,
- len, 0,
- &mut storage as *mut _ as *mut _, &mut addrlen)
- })?;
- Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.inner.peek_from(buf)
}
pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
self.inner.read(buf)
}
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
let ret = cvt(unsafe {
init: fn() -> T,
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: 'static> fmt::Debug for LocalKey<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("LocalKey { .. }")
marker: marker::PhantomData<Cell<T>>,
}
- #[stable(feature = "std_debug", since = "1.15.0")]
impl<T> fmt::Debug for Key<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Key { .. }")
}
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[unstable(feature = "thread_id", issue = "21507")]
impl fmt::Debug for ThreadId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("ThreadId { .. }")
fn into_inner(self) -> imp::Thread { self.0.native.unwrap() }
}
-#[stable(feature = "std_debug", since = "1.15.0")]
+#[stable(feature = "std_debug", since = "1.16.0")]
impl<T> fmt::Debug for JoinHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("JoinHandle { .. }")
}
}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
impl fmt::Display for CaseMappingIter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
}
}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
+#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for ToLowercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
-#[stable(feature = "char_struct_display", since = "1.17.0")]
+#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for ToUppercase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
-use ast::{self, Attribute, Name, PatKind};
+use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
}
}
+pub type BuiltinDeriveFn =
+ for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
+
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
/// A syntax extension that is attached to an item and creates new items
///
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
- CustomDerive(Box<MultiItemModifier>),
+ /// An attribute-like procedural macro. TokenStream -> TokenStream.
+ /// The input is the annotated item.
+ /// Allows generating code to implement a Trait for a given struct
+ /// or enum item.
+ ProcMacroDerive(Box<MultiItemModifier>),
+
+ /// An attribute-like procedural macro that derives a builtin trait.
+ BuiltinDerive(BuiltinDeriveFn),
}
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
+ fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy>;
+ fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy>;
}
#[derive(Copy, Clone, Debug)]
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
+ fn resolve_builtin_macro(&mut self, _tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
+ Err(Determinacy::Determined)
+ }
+ fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy> {
+ Err(Determinacy::Determined)
+ }
}
#[derive(Clone)]
--- /dev/null
+// Copyright 2012-2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast::Name;
+use attr;
+use ast::{self, NestedMetaItem}; use ext::base::{ExtCtxt, SyntaxExtension};
+use codemap;
+use ext::build::AstBuilder;
+use feature_gate;
+use symbol::Symbol;
+use syntax_pos::Span;
+
+pub fn derive_attr_trait<'a>(cx: &mut ExtCtxt, attr: &'a ast::Attribute)
+ -> Option<&'a NestedMetaItem> {
+ if attr.name() != "derive" {
+ return None;
+ }
+ if attr.value_str().is_some() {
+ cx.span_err(attr.span, "unexpected value in `derive`");
+ return None;
+ }
+
+ let traits = attr.meta_item_list().unwrap_or(&[]);
+
+ if traits.is_empty() {
+ cx.span_warn(attr.span, "empty trait list in `derive`");
+ return None;
+ }
+
+ return traits.get(0);
+}
+
+pub fn verify_derive_attrs(cx: &mut ExtCtxt, attrs: &[ast::Attribute]) {
+ for attr in attrs {
+ if attr.name() != "derive" {
+ continue;
+ }
+
+ if attr.value_str().is_some() {
+ cx.span_err(attr.span, "unexpected value in `derive`");
+ }
+
+ let traits = attr.meta_item_list().unwrap_or(&[]).to_owned();
+
+ if traits.is_empty() {
+ cx.span_warn(attr.span, "empty trait list in `derive`");
+ attr::mark_used(&attr);
+ continue;
+ }
+ for titem in traits {
+ if titem.word().is_none() {
+ cx.span_err(titem.span, "malformed `derive` entry");
+ }
+ }
+ }
+}
+
+#[derive(PartialEq, Debug, Clone, Copy)]
+pub enum DeriveType {
+ Legacy,
+ ProcMacro,
+ Builtin
+}
+
+impl DeriveType {
+ // Classify a derive trait name by resolving the macro.
+ pub fn classify(cx: &mut ExtCtxt, tname: Name) -> DeriveType {
+ let legacy_derive_name = Symbol::intern(&format!("derive_{}", tname));
+
+ if let Ok(_) = cx.resolver.resolve_builtin_macro(legacy_derive_name) {
+ return DeriveType::Legacy;
+ }
+
+ match cx.resolver.resolve_builtin_macro(tname) {
+ Ok(ext) => match *ext {
+ SyntaxExtension::BuiltinDerive(..) => DeriveType::Builtin,
+ _ => DeriveType::ProcMacro,
+ },
+ Err(_) => DeriveType::ProcMacro,
+ }
+ }
+}
+
+pub fn get_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>,
+ derive_type: DeriveType) -> Option<ast::Attribute> {
+ for i in 0..attrs.len() {
+ if attrs[i].name() != "derive" {
+ continue;
+ }
+
+ if attrs[i].value_str().is_some() {
+ continue;
+ }
+
+ let mut traits = attrs[i].meta_item_list().unwrap_or(&[]).to_owned();
+
+ // First, weed out malformed #[derive]
+ traits.retain(|titem| titem.word().is_some());
+
+ let mut titem = None;
+
+ // See if we can find a matching trait.
+ for j in 0..traits.len() {
+ let tname = match traits[j].name() {
+ Some(tname) => tname,
+ _ => continue,
+ };
+
+ if DeriveType::classify(cx, tname) == derive_type {
+ titem = Some(traits.remove(j));
+ break;
+ }
+ }
+
+ // If we find a trait, remove the trait from the attribute.
+ if let Some(titem) = titem {
+ if traits.len() == 0 {
+ attrs.remove(i);
+ } else {
+ let derive = Symbol::intern("derive");
+ let mitem = cx.meta_list(titem.span, derive, traits);
+ attrs[i] = cx.attribute(titem.span, mitem);
+ }
+ let derive = Symbol::intern("derive");
+ let mitem = cx.meta_list(titem.span, derive, vec![titem]);
+ return Some(cx.attribute(mitem.span, mitem));
+ }
+ }
+ return None;
+}
+
+fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
+ Span {
+ expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
+ call_site: span,
+ callee: codemap::NameAndSpan {
+ format: codemap::MacroAttribute(Symbol::intern(attr_name)),
+ span: Some(span),
+ allow_internal_unstable: true,
+ },
+ }),
+ ..span
+ }
+}
+
+pub fn add_derived_markers(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) {
+ if attrs.is_empty() {
+ return;
+ }
+
+ let titems = attrs.iter().filter(|a| {
+ a.name() == "derive"
+ }).flat_map(|a| {
+ a.meta_item_list().unwrap_or(&[]).iter()
+ }).filter_map(|titem| {
+ titem.name()
+ }).collect::<Vec<_>>();
+
+ let span = attrs[0].span;
+
+ if !attrs.iter().any(|a| a.name() == "structural_match") &&
+ titems.iter().any(|t| *t == "PartialEq") && titems.iter().any(|t| *t == "Eq") {
+ let structural_match = Symbol::intern("structural_match");
+ let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
+ let meta = cx.meta_word(span, structural_match);
+ attrs.push(cx.attribute(span, meta));
+ }
+
+ if !attrs.iter().any(|a| a.name() == "rustc_copy_clone_marker") &&
+ titems.iter().any(|t| *t == "Copy") && titems.iter().any(|t| *t == "Clone") {
+ let structural_match = Symbol::intern("rustc_copy_clone_marker");
+ let span = allow_unstable(cx, span, "derive(Copy, Clone)");
+ let meta = cx.meta_word(span, structural_match);
+ attrs.push(cx.attribute(span, meta));
+ }
+}
+
+pub fn find_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>)
+ -> Option<ast::Attribute> {
+ verify_derive_attrs(cx, attrs);
+ get_derive_attr(cx, attrs, DeriveType::Legacy).and_then(|a| {
+ let titem = derive_attr_trait(cx, &a);
+ titem.and_then(|titem| {
+ let tword = titem.word().unwrap();
+ let tname = tword.name();
+ if !cx.ecfg.enable_custom_derive() {
+ feature_gate::emit_feature_err(
+ &cx.parse_sess,
+ "custom_derive",
+ titem.span,
+ feature_gate::GateIssue::Language,
+ feature_gate::EXPLAIN_CUSTOM_DERIVE
+ );
+ None
+ } else {
+ let name = Symbol::intern(&format!("derive_{}", tname));
+ if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
+ cx.span_warn(titem.span,
+ feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
+ }
+ let mitem = cx.meta_word(titem.span, name);
+ Some(cx.attribute(mitem.span, mitem))
+ }
+ })
+ }).or_else(|| {
+ get_derive_attr(cx, attrs, DeriveType::ProcMacro)
+ }).or_else(|| {
+ add_derived_markers(cx, attrs);
+ get_derive_attr(cx, attrs, DeriveType::Builtin)
+ })
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{Block, Ident, Mac_, PatKind};
+use ast::{self, Block, Ident, Mac_, PatKind};
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
-use ast;
-use ext::hygiene::Mark;
-use ext::placeholders::{placeholder, PlaceholderExpander};
use attr::{self, HasAttrs};
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
-use syntax_pos::{self, Span, ExpnId};
use config::{is_test_or_bench, StripUnconfigured};
use ext::base::*;
+use ext::derive::{find_derive_attr, derive_attr_trait};
+use ext::hygiene::Mark;
+use ext::placeholders::{placeholder, PlaceholderExpander};
use feature_gate::{self, Features};
use fold;
use fold::*;
-use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts};
use parse::parser::Parser;
use parse::token;
+use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts};
use print::pprust;
use ptr::P;
use std_inject;
+use symbol::Symbol;
use symbol::keywords;
+use syntax_pos::{self, Span, ExpnId};
use tokenstream::{TokenTree, TokenStream};
use util::small_vector::SmallVector;
use visit::Visitor;
attr: ast::Attribute,
item: Annotatable,
},
+ Derive {
+ attr: ast::Attribute,
+ item: Annotatable,
+ },
}
impl Invocation {
match self.kind {
InvocationKind::Bang { span, .. } => span,
InvocationKind::Attr { ref attr, .. } => attr.span,
+ InvocationKind::Derive { ref attr, .. } => attr.span,
}
}
}
let path = ast::Path::from_ident(attr.span, ident);
self.cx.resolver.resolve_macro(scope, &path, force)
}
+ InvocationKind::Derive { ref attr, .. } => {
+ let titem = derive_attr_trait(self.cx, &attr).unwrap();
+ let tname = titem.name().expect("Expected derive macro name");
+ let ident = Ident::with_empty_ctxt(tname);
+ let path = ast::Path::from_ident(attr.span, ident);
+ self.cx.resolver.resolve_derive_macro(scope, &path, force)
+ }
};
let ext = match resolution {
Ok(ext) => Some(ext),
match invoc.kind {
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
+ InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
}
}
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
self.parse_expansion(tok_result, kind, name, attr.span)
}
- SyntaxExtension::CustomDerive(_) => {
+ SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
kind.dummy(attr.span)
}
return kind.dummy(span);
}
- SyntaxExtension::CustomDerive(..) => {
+ SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
return kind.dummy(span);
}
})
}
+ /// Expand a derive invocation. Returns the result of expansion.
+ fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
+ let Invocation { expansion_kind: kind, .. } = invoc;
+ let (attr, item) = match invoc.kind {
+ InvocationKind::Derive { attr, item } => (attr, item),
+ _ => unreachable!(),
+ };
+
+ attr::mark_used(&attr);
+ let titem = derive_attr_trait(self.cx, &attr).unwrap();
+ let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
+ let name = Symbol::intern(&format!("derive({})", tname));
+ let mitem = &attr.value;
+
+ self.cx.bt_push(ExpnInfo {
+ call_site: attr.span,
+ callee: NameAndSpan {
+ format: MacroAttribute(attr.name()),
+ span: Some(attr.span),
+ allow_internal_unstable: false,
+ }
+ });
+
+ match *ext {
+ SyntaxExtension::ProcMacroDerive(ref ext) => {
+ let span = Span {
+ expn_id: self.cx.codemap().record_expansion(ExpnInfo {
+ call_site: mitem.span,
+ callee: NameAndSpan {
+ format: MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
+ span: None,
+ allow_internal_unstable: false,
+ },
+ }),
+ ..mitem.span
+ };
+ return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item));
+ }
+ SyntaxExtension::BuiltinDerive(func) => {
+ let span = Span {
+ expn_id: self.cx.codemap().record_expansion(ExpnInfo {
+ call_site: titem.span,
+ callee: NameAndSpan {
+ format: MacroAttribute(name),
+ span: None,
+ allow_internal_unstable: true,
+ },
+ }),
+ ..titem.span
+ };
+ let mut items = Vec::new();
+ func(self.cx, span, &mitem, &item, &mut |a| {
+ items.push(a)
+ });
+ items.insert(0, item);
+ return kind.expect_from_annotatables(items);
+ }
+ _ => {
+ let msg = &format!("macro `{}` may not be used for derive attributes", name);
+ self.cx.span_err(attr.span, &msg);
+ kind.dummy(attr.span)
+ }
+ }
+ }
+
fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
-> Expansion {
let mut parser = self.cx.new_parser_from_tts(&toks.trees().cloned().collect::<Vec<_>>());
fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
-> Expansion {
- self.collect(kind, InvocationKind::Attr { attr: attr, item: item })
+ let invoc_kind = if attr.name() == "derive" {
+ if kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems {
+ self.cx.span_err(attr.span, "`derive` can be only be applied to items");
+ return kind.expect_from_annotatables(::std::iter::once(item));
+ }
+ InvocationKind::Derive { attr: attr, item: item }
+ } else {
+ InvocationKind::Attr { attr: attr, item: item }
+ };
+
+ self.collect(kind, invoc_kind)
}
// If `item` is an attr invocation, remove and return the macro attribute.
fn classify_item<T: HasAttrs>(&mut self, mut item: T) -> (T, Option<ast::Attribute>) {
let mut attr = None;
+
item = item.map_attrs(|mut attrs| {
- attr = self.cx.resolver.find_attr_invoc(&mut attrs);
+ attr = self.cx.resolver.find_attr_invoc(&mut attrs).or_else(|| {
+ find_derive_attr(self.cx, &mut attrs)
+ });
+
attrs
});
+
(item, attr)
}
(active, abi_unadjusted, "1.16.0", None),
// Macros 1.1
- (active, proc_macro, "1.16.0", Some(35900)),
+ (active, proc_macro, "1.16.0", Some(38356)),
// Allows attributes on struct literal fields.
(active, struct_field_attributes, "1.16.0", Some(38814)),
pub mod ext {
pub mod base;
pub mod build;
+ pub mod derive;
pub mod expand;
pub mod placeholders;
pub mod hygiene;
}
// Assemble the span.
+ // FIXME(#39450) This is bogus if part of the path is macro generated.
let span = mk_sp(lo, self.prev_span.hi);
// Assemble the result.
fn visit_mac(&mut self, _mac: &Mac) {}
}
-pub struct CustomDerive {
+pub struct ProcMacroDerive {
inner: fn(TokenStream) -> TokenStream,
attrs: Vec<ast::Name>,
}
-impl CustomDerive {
- pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> CustomDerive {
- CustomDerive { inner: inner, attrs: attrs }
+impl ProcMacroDerive {
+ pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> ProcMacroDerive {
+ ProcMacroDerive { inner: inner, attrs: attrs }
}
}
-impl MultiItemModifier for CustomDerive {
+impl MultiItemModifier for ProcMacroDerive {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
Annotatable::Item(item) => item,
Annotatable::ImplItem(_) |
Annotatable::TraitItem(_) => {
- ecx.span_err(span, "custom derive attributes may only be \
+ ecx.span_err(span, "proc-macro derives may only be \
applied to struct/enum items");
return Vec::new()
}
ItemKind::Struct(..) |
ItemKind::Enum(..) => {},
_ => {
- ecx.span_err(span, "custom derive attributes may only be \
+ ecx.span_err(span, "proc-macro derives may only be \
applied to struct/enum items");
return Vec::new()
}
let stream = match res {
Ok(stream) => stream,
Err(e) => {
- let msg = "custom derive attribute panicked";
+ let msg = "proc-macro derive panicked";
let mut err = ecx.struct_span_fatal(span, msg);
if let Some(s) = e.downcast_ref::<String>() {
err.help(&format!("message: {}", s));
Ok(new_items) => new_items,
Err(_) => {
// FIXME: handle this better
- let msg = "custom derive produced unparseable tokens";
+ let msg = "proc-macro derive produced unparseable tokens";
ecx.struct_span_fatal(span, msg).emit();
panic!(FatalError);
}
use deriving;
use deriving::generic::*;
use deriving::generic::ty::*;
+use deriving::warn_if_deprecated;
use syntax::ast;
use syntax::ast::{Expr, MetaItem, Mutability};
mitem: &MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
+ warn_if_deprecated(cx, span, "Decodable");
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
}
use deriving;
use deriving::generic::*;
use deriving::generic::ty::*;
+use deriving::warn_if_deprecated;
use syntax::ast::{Expr, ExprKind, MetaItem, Mutability};
use syntax::ext::base::{Annotatable, ExtCtxt};
mitem: &MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
+ warn_if_deprecated(cx, span, "Encodable");
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
}
//! The compiler code necessary to implement the `#[derive]` extensions.
-use syntax::ast::{self, MetaItem};
-use syntax::attr::HasAttrs;
+use std::rc::Rc;
+use syntax::ast;
use syntax::codemap;
-use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
+use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
use syntax::ext::build::AstBuilder;
-use syntax::feature_gate;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
}
}
-pub fn expand_derive(cx: &mut ExtCtxt,
- span: Span,
- mitem: &MetaItem,
- annotatable: Annotatable)
- -> Vec<Annotatable> {
- debug!("expand_derive: span = {:?}", span);
- debug!("expand_derive: mitem = {:?}", mitem);
- debug!("expand_derive: annotatable input = {:?}", annotatable);
- let mut item = match annotatable {
- Annotatable::Item(item) => item,
- other => {
- cx.span_err(span, "`derive` can only be applied to items");
- return vec![other]
- }
- };
-
- let derive = Symbol::intern("derive");
- let mut derive_attrs = Vec::new();
- item = item.map_attrs(|attrs| {
- let partition = attrs.into_iter().partition(|attr| attr.name() == derive);
- derive_attrs = partition.0;
- partition.1
- });
-
- // Expand `#[derive]`s after other attribute macro invocations.
- if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
- return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
- attrs.push(cx.attribute(span, mitem.clone()));
- attrs.extend(derive_attrs);
- attrs
- }))];
- }
-
- let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
- if mitem.value_str().is_some() {
- cx.span_err(mitem.span, "unexpected value in `derive`");
- }
-
- let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
- if traits.is_empty() {
- cx.span_warn(mitem.span, "empty trait list in `derive`");
- }
- traits
- };
-
- let mut traits = get_traits(mitem, cx);
- for derive_attr in derive_attrs {
- traits.extend(get_traits(&derive_attr.value, cx));
- }
-
- // First, weed out malformed #[derive]
- traits.retain(|titem| {
- if titem.word().is_none() {
- cx.span_err(titem.span, "malformed `derive` entry");
- false
- } else {
- true
- }
- });
-
- // Next, check for old-style #[derive(Foo)]
- //
- // These all get expanded to `#[derive_Foo]` and will get expanded first. If
- // we actually add any attributes here then we return to get those expanded
- // and then eventually we'll come back to finish off the other derive modes.
- let mut new_attributes = Vec::new();
- traits.retain(|titem| {
- let tword = titem.word().unwrap();
- let tname = tword.name();
-
- if is_builtin_trait(tname) || {
- let derive_mode = ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(tname));
- cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
- if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false }
- }).unwrap_or(false)
- } {
- return true;
- }
-
- if !cx.ecfg.enable_custom_derive() {
- feature_gate::emit_feature_err(&cx.parse_sess,
- "custom_derive",
- titem.span,
- feature_gate::GateIssue::Language,
- feature_gate::EXPLAIN_CUSTOM_DERIVE);
- } else {
- let name = Symbol::intern(&format!("derive_{}", tname));
- if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
- cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
- }
- let mitem = cx.meta_word(titem.span, name);
- new_attributes.push(cx.attribute(mitem.span, mitem));
- }
- false
- });
- if new_attributes.len() > 0 {
- item = item.map(|mut i| {
- i.attrs.extend(new_attributes);
- if traits.len() > 0 {
- let list = cx.meta_list(mitem.span, derive, traits);
- i.attrs.push(cx.attribute(mitem.span, list));
- }
- i
- });
- return vec![Annotatable::Item(item)]
- }
-
- // Now check for macros-1.1 style custom #[derive].
- //
- // Expand each of them in order given, but *before* we expand any built-in
- // derive modes. The logic here is to:
- //
- // 1. Collect the remaining `#[derive]` annotations into a list. If
- // there are any left, attach a `#[derive]` attribute to the item
- // that we're currently expanding with the remaining derive modes.
- // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
- // 3. Expand the current item we're expanding, getting back a list of
- // items that replace it.
- // 4. Extend the returned list with the current list of items we've
- // collected so far.
- // 5. Return everything!
- //
- // If custom derive extensions end up threading through the `#[derive]`
- // attribute, we'll get called again later on to continue expanding
- // those modes.
- let macros_11_derive = traits.iter()
- .cloned()
- .enumerate()
- .filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap()))
- .next();
- if let Some((i, titem)) = macros_11_derive {
- let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
- let path = ast::Path::from_ident(titem.span, tname);
- let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
-
- traits.remove(i);
- if traits.len() > 0 {
- item = item.map(|mut i| {
- let list = cx.meta_list(mitem.span, derive, traits);
- i.attrs.push(cx.attribute(mitem.span, list));
- i
- });
- }
- let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
- let mitem = cx.meta_list(titem.span, derive, vec![titem]);
- let item = Annotatable::Item(item);
-
- let span = Span {
- expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
- call_site: mitem.span,
- callee: codemap::NameAndSpan {
- format: codemap::MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
- span: None,
- allow_internal_unstable: false,
- },
- }),
- ..mitem.span
- };
-
- if let SyntaxExtension::CustomDerive(ref ext) = *ext {
- return ext.expand(cx, span, &mitem, item);
- } else {
- unreachable!()
- }
- }
-
- // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
- // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.
-
- // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
- // `#[structural_match]` attribute.
- let (partial_eq, eq) = (Symbol::intern("PartialEq"), Symbol::intern("Eq"));
- if traits.iter().any(|t| t.name() == Some(partial_eq)) &&
- traits.iter().any(|t| t.name() == Some(eq)) {
- let structural_match = Symbol::intern("structural_match");
- let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
- let meta = cx.meta_word(span, structural_match);
- item = item.map(|mut i| {
- i.attrs.push(cx.attribute(span, meta));
- i
- });
- }
-
- // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
- // the same as the copy implementation.
- //
- // Add a marker attribute here picked up during #[derive(Clone)]
- let (copy, clone) = (Symbol::intern("Copy"), Symbol::intern("Clone"));
- if traits.iter().any(|t| t.name() == Some(clone)) &&
- traits.iter().any(|t| t.name() == Some(copy)) {
- let marker = Symbol::intern("rustc_copy_clone_marker");
- let span = allow_unstable(cx, span, "derive(Copy, Clone)");
- let meta = cx.meta_word(span, marker);
- item = item.map(|mut i| {
- i.attrs.push(cx.attribute(span, meta));
- i
- });
- }
-
- let mut items = Vec::new();
- for titem in traits.iter() {
- let tname = titem.word().unwrap().name();
- let name = Symbol::intern(&format!("derive({})", tname));
- let mitem = cx.meta_word(titem.span, name);
-
- let span = Span {
- expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
- call_site: titem.span,
- callee: codemap::NameAndSpan {
- format: codemap::MacroAttribute(name),
- span: None,
- allow_internal_unstable: true,
- },
- }),
- ..titem.span
- };
-
- let my_item = Annotatable::Item(item);
- expand_builtin(&tname.as_str(), cx, span, &mitem, &my_item, &mut |a| {
- items.push(a);
- });
- item = my_item.expect_item();
- }
-
- items.insert(0, Annotatable::Item(item));
- return items
-}
-
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
pub fn is_builtin_trait(name: ast::Name) -> bool {
}
}
- fn expand_builtin(name: &str,
- ecx: &mut ExtCtxt,
- span: Span,
- mitem: &MetaItem,
- item: &Annotatable,
- push: &mut FnMut(Annotatable)) {
- match name {
- $(
- $name => {
- warn_if_deprecated(ecx, span, $name);
- $func(ecx, span, mitem, item, push);
- }
- )*
- _ => panic!("not a builtin derive mode: {}", name),
- }
+ pub fn register_builtin_derives(resolver: &mut Resolver) {
+ $(
+ resolver.add_ext(
+ ast::Ident::with_empty_ctxt(Symbol::intern($name)),
+ Rc::new(SyntaxExtension::BuiltinDerive($func))
+ );
+ )*
}
}
}
#![feature(staged_api)]
extern crate fmt_macros;
-#[macro_use]
extern crate log;
#[macro_use]
extern crate syntax;
use std::rc::Rc;
use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension};
+use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
use syntax::symbol::Symbol;
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
user_exts: Vec<NamedSyntaxExtension>,
enable_quotes: bool) {
+ deriving::register_builtin_derives(resolver);
+
let mut register = |name, ext| {
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
};
register(Symbol::intern("format_args"),
NormalTT(Box::new(format::expand_format_args), None, true));
- register(Symbol::intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
-
for (name, ext) in user_exts {
register(name, ext);
}
use deriving;
-struct CustomDerive {
+struct ProcMacroDerive {
trait_name: ast::Name,
function_name: Ident,
span: Span,
}
struct CollectProcMacros<'a> {
- derives: Vec<CustomDerive>,
+ derives: Vec<ProcMacroDerive>,
attr_macros: Vec<AttrProcMacro>,
in_root: bool,
handler: &'a errors::Handler,
};
if self.in_root && item.vis == ast::Visibility::Public {
- self.derives.push(CustomDerive {
+ self.derives.push(ProcMacroDerive {
span: item.span,
trait_name: trait_name,
function_name: item.ident,
// }
// }
fn mk_registrar(cx: &mut ExtCtxt,
- custom_derives: &[CustomDerive],
+ custom_derives: &[ProcMacroDerive],
custom_attrs: &[AttrProcMacro]) -> P<ast::Item> {
let eid = cx.codemap().record_expansion(ExpnInfo {
call_site: DUMMY_SP,
#[derive(
A
)]
-//~^^ ERROR: custom derive produced unparseable tokens
+//~^^ ERROR: proc-macro derive produced unparseable tokens
struct A;
fn main() {}
extern crate derive_panic;
#[derive(A)]
-//~^ ERROR: custom derive attribute panicked
+//~^ ERROR: proc-macro derive panicked
//~| HELP: message: nope!
struct Foo;
#![feature(rustc_attrs)]
extern crate derive_a;
-//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
+//~^ WARN proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
#[rustc_error]
fn main() {} //~ ERROR compilation successful
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+#![deny(resolve_trait_on_defaulted_unit)]
+
+trait Deserialize: Sized {
+ fn deserialize() -> Result<Self, String>;
+}
+
+impl Deserialize for () {
+ fn deserialize() -> Result<(), String> {
+ Ok(())
+ }
+}
+
+fn doit() -> Result<(), String> {
+ let _ = match Deserialize::deserialize() {
+ //~^ ERROR code relies on type
+ //~| WARNING previously accepted
+ Ok(x) => x,
+ Err(e) => return Err(e),
+ };
+ Ok(())
+}
+
+trait ImplementedForUnitButNotNever {}
+
+impl ImplementedForUnitButNotNever for () {}
+
+fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
+
+fn smeg() {
+ let _x = return;
+ foo(_x);
+ //~^ ERROR code relies on type
+ //~| WARNING previously accepted
+}
+
+fn main() {
+ let _ = doit();
+}
+
// ignore-tidy-linelength
#[derive(Eqr)]
-//~^ ERROR `#[derive]` for custom traits is not stable enough for use. It is deprecated and will be removed in v1.15 (see issue #29644)
+//~^ ERROR cannot find derive macro `Eqr` in this scope
struct Foo;
pub fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(FromPrimitive)] //~ERROR `#[derive]` for custom traits is not stable
+#[derive(FromPrimitive)] //~ERROR cannot find derive macro `FromPrimitive` in this scope
enum Foo {}
fn main() {}
foo!(0); // Check that we report errors at macro definition, not expansion.
let _: cfg!(foo) = (); //~ ERROR non-type macro in type position
- derive!(); //~ ERROR `derive` can only be used in attributes
+ derive!(); //~ ERROR macro undefined: 'derive!'
}
#![feature(asm)]
#![feature(trace_macros, concat_idents)]
-#[derive(Default, //~ ERROR
- Zero)] //~ ERROR
-enum CantDeriveThose {}
+#[derive(Zero)] //~ ERROR
+struct CantDeriveThis;
+
+#[derive(Default)] //~ ERROR
+enum OrDeriveThis {}
fn main() {
doesnt_exist!(); //~ ERROR
#[no_link]
extern crate empty_struct;
-//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
+//~^ WARN proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
fn main() {
empty_struct::XEmpty1; //~ ERROR cannot find value `XEmpty1` in module `empty_struct`
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:derive-foo.rs
+// ignore-stage1
+// pp-exact
+// Testing that both the inner item and next outer item are
+// preserved, and that the first outer item parsed in main is not
+// accidentally carried over to each inner function
+
+#[macro_use]
+extern crate derive_foo;
+
+#[derive(Foo)]
+struct X;
+
+#[derive(Foo)]
+#[Bar]
+struct Y;
+
+#[derive(Foo)]
+struct WithRef {
+ x: X,
+ #[Bar]
+ y: Y,
+}
+
+#[derive(Foo)]
+enum Enum {
+
+ #[Bar]
+ Asdf,
+ Qwerty,
+}
+
+fn main() { }
+++ /dev/null
-// Copyright 2012 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// pp-exact
-// Testing that both the inner item and next outer item are
-// preserved, and that the first outer item parsed in main is not
-// accidentally carried over to each inner function
-
-#![feature(custom_attribute)]
-#![feature(custom_derive)]
-
-#[derive(Serialize, Deserialize)]
-struct X;
-
-#[derive(Serialize, Deserialize)]
-struct WithRef<'a, T: 'a> {
- #[serde(skip_deserializing)]
- t: Option<&'a T>,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- x: X,
-}
-
-#[derive(Serialize, Deserialize)]
-enum EnumWith<T> {
- Unit,
- Newtype(
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X),
- Tuple(T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X),
- Struct {
- t: T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- x: X,
- },
-}
-
-#[derive(Serialize, Deserialize)]
-struct Tuple<T>(T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X);
-
-fn main() { }
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Foo, attributes(Bar))]
+pub fn derive(input: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(cfg_target_has_atomic, no_core, intrinsics, lang_items)]
+#![feature(cfg_target_has_atomic, no_core, intrinsics, lang_items, i128_type)]
#![crate_type="rlib"]
#![no_core]
pub unsafe fn atomic_i64(x: *mut i64) {
atomic_xadd(x, 1);
}
+#[cfg(target_has_atomic = "128")]
+pub unsafe fn atomic_u128(x: *mut u128) {
+ atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "128")]
+pub unsafe fn atomic_i128(x: *mut i128) {
+ atomic_xadd(x, 1);
+}
#[cfg(target_has_atomic = "ptr")]
pub unsafe fn atomic_usize(x: *mut usize) {
atomic_xadd(x, 1);
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--test
+
+// This file tests the source-partitioning behavior of rustdoc.
+// Each test contains some code that should be put into the generated
+// `fn main` and some attributes should be left outside (except the first
+// one, which has no attributes).
+// If the #![recursion_limit] attribute is incorrectly left inside,
+// then the tests will fail because the macro recurses 128 times.
+
+/// ```
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn simple() {}
+
+/// ```
+/// #![recursion_limit = "1024"]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn non_feature_attr() {}
+
+/// ```
+/// #![feature(core_intrinsics)]
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn feature_attr() {}
+
+/// ```
+/// #![feature(core_intrinsics)]
+/// #![recursion_limit = "1024"]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn both_attrs() {}
+
+/// ```
+/// #![recursion_limit = "1024"]
+/// #![feature(core_intrinsics)]
+/// macro_rules! recurse {
+/// (()) => {};
+/// (() $($rest:tt)*) => { recurse!($($rest)*); }
+/// }
+/// recurse!(() () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ()
+/// () () () () () () () ());
+/// assert_eq!(1 + 1, 2);
+/// ```
+pub fn both_attrs_reverse() {}
+
-error: custom derive attribute panicked
+error: proc-macro derive panicked
--> $DIR/issue-36935.rs:17:15
|
17 | #[derive(Foo, Bar)]
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Foo;
+
+use Foo1;
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `Foo`
+ --> $DIR/issue-38054-do-not-show-unresolved-names.rs:11:5
+ |
+11 | use Foo;
+ | ^^^ no `Foo` in the root
+
+error[E0432]: unresolved import `Foo1`
+ --> $DIR/issue-38054-do-not-show-unresolved-names.rs:13:5
+ |
+13 | use Foo1;
+ | ^^^^ no `Foo1` in the root
+
+error: aborting due to 2 previous errors
+