Auto merge of #32496 - Manishearth:rollup, r=Manishearth

Rollup of 11 pull requests

- Successful merges: #32131, #32199, #32257, #32325, #32435, #32447, #32448, #32456, #32469, #32476, #32482
- Failed merges: #32240
This commit is contained in:
bors 2016-03-26 01:13:31 -07:00
commit d322f990b0
48 changed files with 824 additions and 306 deletions

View File

@ -1953,7 +1953,10 @@ impl StrExt for str {
#[inline]
fn is_char_boundary(&self, index: usize) -> bool {
if index == self.len() { return true; }
// 0 and len are always ok.
// Test for 0 explicitly so that it can optimize out the check
// easily and skip reading string data for that case.
if index == 0 || index == self.len() { return true; }
match self.as_bytes().get(index) {
None => false,
Some(&b) => b < 128 || b >= 192,
@ -2026,6 +2029,7 @@ impl StrExt for str {
self.find(pat)
}
#[inline]
fn split_at(&self, mid: usize) -> (&str, &str) {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {

View File

@ -1261,7 +1261,7 @@ compiled:
fn foo<T: Index<u8>>(x: T){}
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
trait Index<Idx> { ... }
trait Index<Idx> { /* ... */ }
foo(true); // `bool` does not implement `Index<u8>`
```
@ -1291,7 +1291,7 @@ compiled:
fn foo<T: Index<u8>>(x: T){}
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
trait Index<Idx> { ... }
trait Index<Idx> { /* ... */ }
foo(true); // `bool` does not implement `Index<u8>`
```
@ -1319,7 +1319,7 @@ compiled:
fn foo<T: Index<u8>>(x: T){}
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
trait Index<Idx> { ... }
trait Index<Idx> { /* ... */ }
foo(true); // `bool` does not implement `Index<u8>`
```

View File

@ -136,6 +136,19 @@ declare_lint! {
"type parameter default erroneously allowed in invalid location"
}
declare_lint! {
pub ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
Warn,
"floating-point constants cannot be used in patterns"
}
declare_lint! {
pub ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
Deny,
"constants of struct or enum type can only be used in a pattern if \
the struct or enum has `#[derive(PartialEq, Eq)]`"
}
declare_lint! {
pub MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
Deny,
@ -193,6 +206,8 @@ impl LintPass for HardwiredLints {
PRIVATE_IN_PUBLIC,
INACCESSIBLE_EXTERN_CRATE,
INVALID_TYPE_PARAM_DEFAULT,
ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
CONST_ERR,
RAW_POINTER_DERIVE,

View File

@ -478,15 +478,24 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
Some(Def::Const(did)) => {
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
if let Some(ref mut renaming_map) = self.renaming_map {
// Record any renamings we do here
record_renamings(const_expr, &pat, renaming_map);
match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) {
Ok(new_pat) => {
if let Some(ref mut map) = self.renaming_map {
// Record any renamings we do here
record_renamings(const_expr, &pat, map);
}
new_pat
}
new_pat
})
Err(def_id) => {
self.failed = true;
self.tcx.sess.span_err(
pat.span,
&format!("constants of the type `{}` \
cannot be used in patterns",
self.tcx.item_path_str(def_id)));
pat
}
}
} else {
self.failed = true;
span_err!(self.tcx.sess, pat.span, E0158,

View File

@ -16,6 +16,7 @@ use self::EvalHint::*;
use front::map as ast_map;
use front::map::blocks::FnLikeNode;
use lint;
use middle::cstore::{self, CrateStore, InlinedItem};
use middle::{infer, subst, traits};
use middle::def::Def;
@ -323,10 +324,41 @@ impl ConstVal {
}
}
pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, span: Span)
-> Result<P<hir::Pat>, DefId> {
let pat_ty = tcx.expr_ty(expr);
debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
match pat_ty.sty {
ty::TyFloat(_) => {
tcx.sess.add_lint(
lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
pat_id,
span,
format!("floating point constants cannot be used in patterns"));
}
ty::TyEnum(adt_def, _) |
ty::TyStruct(adt_def, _) => {
if !tcx.has_attr(adt_def.did, "structural_match") {
tcx.sess.add_lint(
lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
pat_id,
span,
format!("to use a constant of type `{}` \
in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
tcx.item_path_str(adt_def.did),
tcx.item_path_str(adt_def.did)));
}
}
_ => { }
}
let pat = match expr.node {
hir::ExprTup(ref exprs) =>
PatKind::Tup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect()),
PatKind::Tup(try!(exprs.iter()
.map(|expr| const_expr_to_pat(tcx, &expr,
pat_id, span))
.collect())),
hir::ExprCall(ref callee, ref args) => {
let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
@ -336,31 +368,41 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
let path = match def.full_def() {
Def::Struct(def_id) => def_to_path(tcx, def_id),
Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
Def::Fn(..) => return P(hir::Pat {
Def::Fn(..) => return Ok(P(hir::Pat {
id: expr.id,
node: PatKind::Lit(P(expr.clone())),
span: span,
}),
})),
_ => unreachable!()
};
let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
let pats = try!(args.iter()
.map(|expr| const_expr_to_pat(tcx, &**expr,
pat_id, span))
.collect());
PatKind::TupleStruct(path, Some(pats))
}
hir::ExprStruct(ref path, ref fields, None) => {
let field_pats = fields.iter().map(|field| codemap::Spanned {
span: codemap::DUMMY_SP,
node: hir::FieldPat {
name: field.name.node,
pat: const_expr_to_pat(tcx, &field.expr, span),
is_shorthand: false,
},
}).collect();
let field_pats =
try!(fields.iter()
.map(|field| Ok(codemap::Spanned {
span: codemap::DUMMY_SP,
node: hir::FieldPat {
name: field.name.node,
pat: try!(const_expr_to_pat(tcx, &field.expr,
pat_id, span)),
is_shorthand: false,
},
}))
.collect());
PatKind::Struct(path.clone(), field_pats, false)
}
hir::ExprVec(ref exprs) => {
let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
let pats = try!(exprs.iter()
.map(|expr| const_expr_to_pat(tcx, &expr,
pat_id, span))
.collect());
PatKind::Vec(pats, None, hir::HirVec::new())
}
@ -373,7 +415,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
Some(Def::AssociatedConst(def_id)) => {
let substs = Some(tcx.node_id_item_substs(expr.id).substs);
let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
return const_expr_to_pat(tcx, expr, span);
return const_expr_to_pat(tcx, expr, pat_id, span);
},
_ => unreachable!(),
}
@ -381,7 +423,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
_ => PatKind::Lit(P(expr.clone()))
};
P(hir::Pat { id: expr.id, node: pat, span: span })
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
}
pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal {

View File

@ -614,9 +614,15 @@ macro_rules! make_mir_visitor {
fn super_constant(&mut self,
constant: & $($mutability)* Constant<'tcx>) {
self.visit_span(& $($mutability)* constant.span);
self.visit_ty(& $($mutability)* constant.ty);
self.visit_literal(& $($mutability)* constant.literal);
let Constant {
ref $($mutability)* span,
ref $($mutability)* ty,
ref $($mutability)* literal,
} = *constant;
self.visit_span(span);
self.visit_ty(ty);
self.visit_literal(literal);
}
fn super_typed_const_val(&mut self,
@ -626,6 +632,7 @@ macro_rules! make_mir_visitor {
ref $($mutability)* ty,
ref $($mutability)* value,
} = *constant;
self.visit_span(span);
self.visit_ty(ty);
self.visit_const_usize(value);

View File

@ -252,7 +252,13 @@ impl Session {
let lint_id = lint::LintId::of(lint);
let mut lints = self.lints.borrow_mut();
match lints.get_mut(&id) {
Some(arr) => { arr.push((lint_id, sp, msg)); return; }
Some(arr) => {
let tuple = (lint_id, sp, msg);
if !arr.contains(&tuple) {
arr.push(tuple);
}
return;
}
None => {}
}
lints.insert(id, vec!((lint_id, sp, msg)));

View File

@ -179,6 +179,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
id: LintId::of(OVERLAPPING_INHERENT_IMPLS),
reference: "issue #22889 <https://github.com/rust-lang/rust/issues/22889>",
},
FutureIncompatibleInfo {
id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN),
reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
},
FutureIncompatibleInfo {
id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
},
]);
// We have one lint pass defined specially

View File

@ -90,9 +90,16 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs);
match const_eval::lookup_const_by_id(self.cx.tcx, def_id, substs) {
Some((const_expr, _const_ty)) => {
let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
pat.span);
return self.to_pattern(&pat);
match const_eval::const_expr_to_pat(self.cx.tcx,
const_expr,
pat.id,
pat.span) {
Ok(pat) =>
return self.to_pattern(&pat),
Err(_) =>
self.cx.tcx.sess.span_bug(
pat.span, "illegal constant"),
}
}
None => {
self.cx.tcx.sess.span_bug(

View File

@ -12,7 +12,8 @@
//! We want to do this once just before trans, so trans does not have to take
//! care erasing regions all over the place.
use rustc::middle::ty::{self, TyCtxt};
use rustc::middle::subst::Substs;
use rustc::middle::ty::{Ty, TyCtxt};
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::{MirPass, Pass};
@ -28,94 +29,16 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
tcx: tcx
}
}
fn erase_regions_return_ty(&mut self, fn_output: &mut ty::FnOutput<'tcx>) {
match *fn_output {
ty::FnConverging(ref mut ty) => {
*ty = self.tcx.erase_regions(ty);
},
ty::FnDiverging => {}
}
}
fn erase_regions_tys<'b, T>(&mut self, tys: T)
where T: Iterator<Item = &'b mut ty::Ty<'tcx>>,
'tcx: 'b
{
for ty in tys {
*ty = self.tcx.erase_regions(ty);
}
}
}
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
self.erase_regions_return_ty(&mut mir.return_ty);
self.erase_regions_tys(mir.var_decls.iter_mut().map(|d| &mut d.ty));
self.erase_regions_tys(mir.arg_decls.iter_mut().map(|d| &mut d.ty));
self.erase_regions_tys(mir.temp_decls.iter_mut().map(|d| &mut d.ty));
self.super_mir(mir);
fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
let old_ty = *ty;
*ty = self.tcx.erase_regions(&old_ty);
}
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
match terminator.kind {
TerminatorKind::Goto { .. } |
TerminatorKind::Resume |
TerminatorKind::Return |
TerminatorKind::If { .. } |
TerminatorKind::Switch { .. } |
TerminatorKind::Drop { .. } |
TerminatorKind::Call { .. } => {
/* nothing to do */
},
TerminatorKind::SwitchInt { ref mut switch_ty, .. } => {
*switch_ty = self.tcx.erase_regions(switch_ty);
},
}
self.super_terminator(bb, terminator);
}
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
match *rvalue {
Rvalue::Use(_) |
Rvalue::Len(_) |
Rvalue::BinaryOp(_, _, _) |
Rvalue::UnaryOp(_, _) |
Rvalue::Slice { input: _, from_start: _, from_end: _ } |
Rvalue::InlineAsm {..} => {},
Rvalue::Repeat(_, ref mut value) => value.ty = self.tcx.erase_regions(&value.ty),
Rvalue::Ref(ref mut region, _, _) => *region = ty::ReStatic,
Rvalue::Cast(_, _, ref mut ty) => *ty = self.tcx.erase_regions(ty),
Rvalue::Box(ref mut ty) => *ty = self.tcx.erase_regions(ty),
Rvalue::Aggregate(AggregateKind::Vec, _) |
Rvalue::Aggregate(AggregateKind::Tuple, _) => {},
Rvalue::Aggregate(AggregateKind::Adt(_, _, ref mut substs), _) =>
*substs = self.tcx.mk_substs(self.tcx.erase_regions(*substs)),
Rvalue::Aggregate(AggregateKind::Closure(def_id, ref mut closure_substs), _) => {
let cloned = Box::new(closure_substs.clone());
let ty = self.tcx.mk_closure_from_closure_substs(def_id, cloned);
let erased = self.tcx.erase_regions(&ty);
*closure_substs = match erased.sty {
ty::TyClosure(_, ref closure_substs) => &*closure_substs,
_ => unreachable!()
};
}
}
self.super_rvalue(rvalue);
}
fn visit_constant(&mut self, constant: &mut Constant<'tcx>) {
constant.ty = self.tcx.erase_regions(&constant.ty);
match constant.literal {
Literal::Item { ref mut substs, .. } => {
*substs = self.tcx.mk_substs(self.tcx.erase_regions(substs));
}
Literal::Value { .. } => { /* nothing to do */ }
}
self.super_constant(constant);
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
*substs = self.tcx.mk_substs(self.tcx.erase_regions(*substs));
}
}

View File

@ -205,51 +205,6 @@ about what constitutes an Item declaration and what does not:
https://doc.rust-lang.org/reference.html#statements
"##,
E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type:
```compile_fail
struct u8 {
// ...
}
```
To fix this, simply name it something else.
Such an error may also occur if you define a type parameter which shadows a
primitive type. An example would be something like:
```compile_fail
impl<u8> MyTrait for Option<u8> {
// ...
}
```
In such a case, if you meant for `u8` to be a generic type parameter (i.e. any
type can be used in its place), use something like `T` instead:
```ignore
impl<T> MyTrait for Option<T> {
// ...
}
```
On the other hand, if you wished to refer to the specific type `u8`, remove it
from the type parameter list:
```ignore
impl MyTrait for Option<u8> {
// ...
}
See the Types section of the reference for more information about the primitive
types:
https://doc.rust-lang.org/reference.html#types
"##,
E0364: r##"
Private items cannot be publicly re-exported. This error indicates that you
attempted to `pub use` a type or value that was not itself public.

View File

@ -1619,15 +1619,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
intravisit::walk_crate(self, krate);
}
fn check_if_primitive_type_name(&self, name: Name, span: Span) {
if let Some(_) = self.primitive_type_table.primitive_types.get(&name) {
span_err!(self.session,
span,
E0317,
"user-defined types or type parameters cannot shadow the primitive types");
}
}
fn resolve_item(&mut self, item: &Item) {
let name = item.name;
@ -1637,8 +1628,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ItemEnum(_, ref generics) |
ItemTy(_, ref generics) |
ItemStruct(_, ref generics) => {
self.check_if_primitive_type_name(name, item.span);
self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind),
|this| intravisit::walk_item(this, item));
}
@ -1659,8 +1648,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
self.check_if_primitive_type_name(name, item.span);
// Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
@ -1695,8 +1682,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
});
}
hir::TypeTraitItem(..) => {
this.check_if_primitive_type_name(trait_item.name,
trait_item.span);
this.with_type_parameter_rib(NoTypeParameters, |this| {
intravisit::walk_trait_item(this, trait_item)
});
@ -1720,28 +1705,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
ItemUse(ref view_path) => {
// check for imports shadowing primitive types
let check_rename = |this: &Self, id, name| {
match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
Some(Def::Enum(..)) | Some(Def::TyAlias(..)) | Some(Def::Struct(..)) |
Some(Def::Trait(..)) | None => {
this.check_if_primitive_type_name(name, item.span);
}
_ => {}
}
};
match view_path.node {
hir::ViewPathSimple(name, _) => {
check_rename(self, item.id, name);
}
hir::ViewPathList(ref prefix, ref items) => {
for item in items {
if let Some(name) = item.node.rename() {
check_rename(self, item.node.id(), name);
}
}
// Resolve prefix of an import with empty braces (issue #28388)
if items.is_empty() && !prefix.segments.is_empty() {
match self.resolve_crate_relative_path(prefix.span,
@ -1922,9 +1887,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
fn resolve_generics(&mut self, generics: &Generics) {
for type_parameter in generics.ty_params.iter() {
self.check_if_primitive_type_name(type_parameter.name, type_parameter.span);
}
for predicate in &generics.where_clause.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(_) |
@ -2658,15 +2620,37 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Try to find a path to an item in a module.
let last_ident = segments.last().unwrap().identifier;
if segments.len() <= 1 {
let unqualified_def = self.resolve_identifier(last_ident, namespace, true);
return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
.map(|def| {
PathResolution::new(def, path_depth)
});
// Resolve a single identifier with fallback to primitive types
let resolve_identifier_with_fallback = |this: &mut Self, record_used| {
let def = this.resolve_identifier(last_ident, namespace, record_used);
match def {
None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS =>
this.primitive_type_table
.primitive_types
.get(&last_ident.unhygienic_name)
.map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))),
_ => def
}
};
if segments.len() == 1 {
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
// don't report an error right away, but try to fallback to a primitive type.
// So, we are still able to successfully resolve something like
//
// use std::u8; // bring module u8 in scope
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
// // not to non-existent std::u8::max_value
// }
//
// Such behavior is required for backward compatibility.
// The same fallback is used when `a` resolves to nothing.
let unqualified_def = resolve_identifier_with_fallback(self, true);
return unqualified_def.and_then(|def| self.adjust_local_def(def, span)).map(mk_res);
}
let unqualified_def = self.resolve_identifier(last_ident, namespace, false);
let unqualified_def = resolve_identifier_with_fallback(self, false);
let def = self.resolve_module_relative_path(span, segments, namespace);
match (def, unqualified_def) {
(Some(d), Some(ref ud)) if d == ud.def => {
@ -2692,15 +2676,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return Some(LocalDef::from_def(Def::Err));
}
// First, check to see whether the name is a primitive type.
if namespace == TypeNS {
if let Some(&prim_ty) = self.primitive_type_table
.primitive_types
.get(&identifier.unhygienic_name) {
return Some(LocalDef::from_def(Def::PrimTy(prim_ty)));
}
}
self.resolve_identifier_in_local_ribs(identifier, namespace, record_used)
}

View File

@ -80,6 +80,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
mir_map: &'a MirMap<'tcx>,
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
available_monomorphizations: RefCell<FnvHashSet<String>>,
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
use_dll_storage_attrs: bool,
@ -105,7 +106,6 @@ pub struct LocalCrateContext<'tcx> {
/// Cache instances of monomorphic and polymorphic items
instances: RefCell<FnvHashMap<Instance<'tcx>, ValueRef>>,
monomorphizing: RefCell<DefIdMap<usize>>,
available_monomorphizations: RefCell<FnvHashSet<String>>,
/// Cache generated vtables
vtables: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
/// Cache of constant strings,
@ -357,6 +357,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
},
check_overflow: check_overflow,
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
available_monomorphizations: RefCell::new(FnvHashSet()),
available_drop_glues: RefCell::new(FnvHashMap()),
use_dll_storage_attrs: use_dll_storage_attrs,
translation_items: RefCell::new(FnvHashMap()),
@ -474,7 +475,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
external_srcs: RefCell::new(NodeMap()),
instances: RefCell::new(FnvHashMap()),
monomorphizing: RefCell::new(DefIdMap()),
available_monomorphizations: RefCell::new(FnvHashSet()),
vtables: RefCell::new(FnvHashMap()),
const_cstr_cache: RefCell::new(FnvHashMap()),
const_unsized: RefCell::new(FnvHashMap()),
@ -723,7 +723,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
}
pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
&self.local.available_monomorphizations
&self.shared.available_monomorphizations
}
pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {

View File

@ -1152,9 +1152,10 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f32 {
match self {
NEG_INFINITY => NEG_INFINITY,
x => (x + ((x * x) + 1.0).sqrt()).ln(),
if self == NEG_INFINITY {
NEG_INFINITY
} else {
(self + ((self * self) + 1.0).sqrt()).ln()
}
}

View File

@ -1023,9 +1023,10 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asinh(self) -> f64 {
match self {
NEG_INFINITY => NEG_INFINITY,
x => (x + ((x * x) + 1.0).sqrt()).ln(),
if self == NEG_INFINITY {
NEG_INFINITY
} else {
(self + ((self * self) + 1.0).sqrt()).ln()
}
}

View File

@ -339,7 +339,7 @@ impl Command {
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn status(&mut self) -> io::Result<ExitStatus> {
self.inner.spawn(imp::Stdio::Inherit, false).map(Child::from_inner)
self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
.and_then(|mut p| p.wait())
}
}

View File

@ -13,7 +13,7 @@ use prelude::v1::*;
use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CString;
use ffi::CStr;
use io;
use libc;
use mem;
@ -84,15 +84,12 @@ impl Thread {
#[cfg(any(target_os = "linux",
target_os = "android",
target_os = "emscripten"))]
pub fn set_name(name: &str) {
pub fn set_name(name: &CStr) {
const PR_SET_NAME: libc::c_int = 15;
let cname = CString::new(name).unwrap_or_else(|_| {
panic!("thread name may not contain interior null bytes")
});
// pthread wrapper only appeared in glibc 2.12, so we use syscall
// directly.
unsafe {
libc::prctl(PR_SET_NAME, cname.as_ptr() as libc::c_ulong, 0, 0, 0);
libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
}
}
@ -100,32 +97,30 @@ impl Thread {
target_os = "dragonfly",
target_os = "bitrig",
target_os = "openbsd"))]
pub fn set_name(name: &str) {
let cname = CString::new(name).unwrap();
pub fn set_name(name: &CStr) {
unsafe {
libc::pthread_set_name_np(libc::pthread_self(), cname.as_ptr());
libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn set_name(name: &str) {
let cname = CString::new(name).unwrap();
pub fn set_name(name: &CStr) {
unsafe {
libc::pthread_setname_np(cname.as_ptr());
libc::pthread_setname_np(name.as_ptr());
}
}
#[cfg(target_os = "netbsd")]
pub fn set_name(name: &str) {
pub fn set_name(name: &CStr) {
use ffi::CString;
let cname = CString::new(&b"%s"[..]).unwrap();
let carg = CString::new(name).unwrap();
unsafe {
libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
carg.as_ptr() as *mut libc::c_void);
name.as_ptr() as *mut libc::c_void);
}
}
#[cfg(any(target_env = "newlib", target_os = "solaris"))]
pub fn set_name(_name: &str) {
pub fn set_name(_name: &CStr) {
// Newlib and Illumos has no way to set a thread name.
}

View File

@ -12,6 +12,7 @@ use prelude::v1::*;
use alloc::boxed::FnBox;
use io;
use ffi::CStr;
use mem;
use libc::c_void;
use ptr;
@ -54,7 +55,7 @@ impl Thread {
}
}
pub fn set_name(_name: &str) {
pub fn set_name(_name: &CStr) {
// Windows threads are nameless
// The names in MSVC debugger are obtained using a "magic" exception,
// which requires a use of MS C++ extensions.

View File

@ -166,6 +166,8 @@ use any::Any;
use cell::UnsafeCell;
use fmt;
use io;
use str;
use ffi::{CStr, CString};
use sync::{Mutex, Condvar, Arc};
use sys::thread as imp;
use sys_common::thread_info;
@ -267,7 +269,7 @@ impl Builder {
let their_packet = my_packet.clone();
let main = move || {
if let Some(name) = their_thread.name() {
if let Some(name) = their_thread.cname() {
imp::Thread::set_name(name);
}
unsafe {
@ -450,7 +452,7 @@ pub fn park_timeout(dur: Duration) {
/// The internal representation of a `Thread` handle
struct Inner {
name: Option<String>,
name: Option<CString>, // Guaranteed to be UTF-8
lock: Mutex<bool>, // true when there is a buffered unpark
cvar: Condvar,
}
@ -465,9 +467,12 @@ pub struct Thread {
impl Thread {
// Used only internally to construct a thread object without spawning
fn new(name: Option<String>) -> Thread {
let cname = name.map(|n| CString::new(n).unwrap_or_else(|_| {
panic!("thread name may not contain interior null bytes")
}));
Thread {
inner: Arc::new(Inner {
name: name,
name: cname,
lock: Mutex::new(false),
cvar: Condvar::new(),
})
@ -489,6 +494,10 @@ impl Thread {
/// Gets the thread's name.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn name(&self) -> Option<&str> {
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } )
}
fn cname(&self) -> Option<&CStr> {
self.inner.name.as_ref().map(|s| &**s)
}
}
@ -622,6 +631,12 @@ mod tests {
}).unwrap().join().unwrap();
}
#[test]
#[should_panic]
fn test_invalid_named_thread() {
let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
}
#[test]
fn test_run_basic() {
let (tx, rx) = channel();

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ops::{Add, Sub, Mul, Div};
use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
@ -105,6 +105,13 @@ impl Add for Duration {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl AddAssign for Duration {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
#[stable(feature = "duration", since = "1.3.0")]
impl Sub for Duration {
type Output = Duration;
@ -124,6 +131,13 @@ impl Sub for Duration {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl SubAssign for Duration {
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}
#[stable(feature = "duration", since = "1.3.0")]
impl Mul<u32> for Duration {
type Output = Duration;
@ -141,6 +155,13 @@ impl Mul<u32> for Duration {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl MulAssign<u32> for Duration {
fn mul_assign(&mut self, rhs: u32) {
*self = *self * rhs;
}
}
#[stable(feature = "duration", since = "1.3.0")]
impl Div<u32> for Duration {
type Output = Duration;
@ -155,6 +176,13 @@ impl Div<u32> for Duration {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl DivAssign<u32> for Duration {
fn div_assign(&mut self, rhs: u32) {
*self = *self / rhs;
}
}
#[cfg(test)]
mod tests {
use super::Duration;

View File

@ -24,7 +24,7 @@
use error::Error;
use fmt;
use ops::{Add, Sub};
use ops::{Add, Sub, AddAssign, SubAssign};
use sys::time;
use sys_common::FromInner;
@ -172,6 +172,13 @@ impl Add<Duration> for Instant {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
#[stable(feature = "time2", since = "1.8.0")]
impl Sub<Duration> for Instant {
type Output = Instant;
@ -181,6 +188,13 @@ impl Sub<Duration> for Instant {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
#[stable(feature = "time2", since = "1.8.0")]
impl Sub<Instant> for Instant {
type Output = Duration;
@ -254,6 +268,13 @@ impl Add<Duration> for SystemTime {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl AddAssign<Duration> for SystemTime {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
#[stable(feature = "time2", since = "1.8.0")]
impl Sub<Duration> for SystemTime {
type Output = SystemTime;
@ -263,6 +284,13 @@ impl Sub<Duration> for SystemTime {
}
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl SubAssign<Duration> for SystemTime {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
#[stable(feature = "time2", since = "1.8.0")]
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View File

@ -1304,6 +1304,31 @@ impl CodeMap {
return a;
}
/// Check if the backtrace `subtrace` contains `suptrace` as a prefix.
pub fn more_specific_trace(&self,
mut subtrace: ExpnId,
suptrace: ExpnId)
-> bool {
loop {
if subtrace == suptrace {
return true;
}
let stop = self.with_expn_info(subtrace, |opt_expn_info| {
if let Some(expn_info) = opt_expn_info {
subtrace = expn_info.call_site.expn_id;
false
} else {
true
}
});
if stop {
return false;
}
}
}
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
let mut expansions = self.expansions.borrow_mut();
expansions.push(expn_info);

View File

@ -33,7 +33,7 @@ use visit::Visitor;
use std_inject;
use std::collections::HashSet;
use std::env;
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
let expr_span = e.span;
@ -1275,11 +1275,41 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
/* this discards information in the case of macro-defining macros */
Span {
lo: sp.lo,
hi: sp.hi,
expn_id: cx.backtrace(),
debug!("new_span(sp={:?})", sp);
if cx.codemap().more_specific_trace(sp.expn_id, cx.backtrace()) {
// If the span we are looking at has a backtrace that has more
// detail than our current backtrace, then we keep that
// backtrace. Honestly, I have no idea if this makes sense,
// because I have no idea why we are stripping the backtrace
// below. But the reason I made this change is because, in
// deriving, we were generating attributes with a specific
// backtrace, which was essential for `#[structural_match]` to
// be properly supported, but these backtraces were being
// stripped and replaced with a null backtrace. Sort of
// unclear why this is the case. --nmatsakis
debug!("new_span: keeping trace from {:?} because it is more specific",
sp.expn_id);
sp
} else {
// This discards information in the case of macro-defining macros.
//
// The comment above was originally added in
// b7ec2488ff2f29681fe28691d20fd2c260a9e454 in Feb 2012. I
// *THINK* the reason we are doing this is because we want to
// replace the backtrace of the macro contents with the
// backtrace that contains the macro use. But it's pretty
// unclear to me. --nmatsakis
let sp1 = Span {
lo: sp.lo,
hi: sp.hi,
expn_id: cx.backtrace(),
};
debug!("new_span({:?}) = {:?}", sp, sp1);
if sp.expn_id.into_u32() == 0 && env::var_os("NDM").is_some() {
panic!("NDM");
}
sp1
}
}

View File

@ -109,6 +109,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
// to bootstrap fix for #5723.
("issue_5723_bootstrap", "1.0.0", None, Accepted),
("structural_match", "1.8.0", Some(31434), Active),
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
("opt_out_copy", "1.0.0", None, Removed),
@ -304,6 +306,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
("link_args", Normal, Ungated),
("macro_escape", Normal, Ungated),
// RFC #1445.
("structural_match", Whitelisted, Gated("structural_match",
"the semantics of constant patterns is \
not yet settled")),
// Not used any more, but we can't feature gate it
("no_stack_check", Normal, Ungated),
@ -682,7 +689,7 @@ impl<'a> Context<'a> {
fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
let has_feature = self.has_feature(feature);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
if !has_feature {
if !has_feature && !self.cm.span_allows_unstable(span) {
emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
}
}

View File

@ -268,8 +268,8 @@ pub struct Parser<'a> {
/// Used to determine the path to externally loaded source files
pub filename: Option<String>,
pub mod_path_stack: Vec<InternedString>,
/// Stack of spans of open delimiters. Used for error message.
pub open_braces: Vec<Span>,
/// Stack of open delimiters and their spans. Used for error message.
pub open_braces: Vec<(token::DelimToken, Span)>,
/// Flag if this parser "owns" the directory that it is currently parsing
/// in. This will affect how nested files are looked up.
pub owns_directory: bool,
@ -895,7 +895,7 @@ impl<'a> Parser<'a> {
sep: SeqSep,
f: F)
-> Vec<T>
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
}
@ -2755,8 +2755,8 @@ impl<'a> Parser<'a> {
let mut err: DiagnosticBuilder<'a> =
self.diagnostic().struct_span_err(self.span,
"this file contains an un-closed delimiter");
for sp in &self.open_braces {
err.span_help(*sp, "did you mean to close this delimiter?");
for &(_, sp) in &self.open_braces {
err.span_help(sp, "did you mean to close this delimiter?");
}
Err(err)
@ -2766,23 +2766,66 @@ impl<'a> Parser<'a> {
let pre_span = self.span;
// Parse the open delimiter.
self.open_braces.push(self.span);
self.open_braces.push((delim, self.span));
let open_span = self.span;
self.bump();
// Parse the token trees within the delimiters
let tts = self.parse_seq_to_before_end(&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree());
// Parse the token trees within the delimiters.
// We stop at any delimiter so we can try to recover if the user
// uses an incorrect delimiter.
let tts = self.parse_seq_to_before_tokens(&[&token::CloseDelim(token::Brace),
&token::CloseDelim(token::Paren),
&token::CloseDelim(token::Bracket)],
SeqSep::none(),
|p| p.parse_token_tree(),
|mut e| e.emit());
// Parse the close delimiter.
let close_span = self.span;
self.bump();
self.open_braces.pop().unwrap();
// Expand to cover the entire delimited token tree
let span = Span { hi: close_span.hi, ..pre_span };
match self.token {
// Correct delmiter.
token::CloseDelim(d) if d == delim => {
self.open_braces.pop().unwrap();
// Parse the close delimiter.
self.bump();
}
// Incorect delimiter.
token::CloseDelim(other) => {
let token_str = self.this_token_to_string();
let mut err = self.diagnostic().struct_span_err(self.span,
&format!("incorrect close delimiter: `{}`", token_str));
// This is a conservative error: only report the last unclosed delimiter.
// The previous unclosed delimiters could actually be closed! The parser
// just hasn't gotten to them yet.
if let Some(&(_, sp)) = self.open_braces.last() {
err.span_note(sp, "unclosed delimiter");
};
err.emit();
self.open_braces.pop().unwrap();
// If the incorrect delimter matches an earlier opening
// delimiter, then don't consume it (it can be used to
// close the earlier one)Otherwise, consume it.
// E.g., we try to recover from:
// fn foo() {
// bar(baz(
// } // Incorrect delimiter but matches the earlier `{`
if !self.open_braces.iter().any(|&(b, _)| b == other) {
self.bump();
}
}
token::Eof => {
// Silently recover, the EOF token will be seen again
// and an error emitted then. Thus we don't pop from
// self.open_braces here.
},
_ => unreachable!(),
}
Ok(TokenTree::Delimited(span, Rc::new(Delimited {
delim: delim,
open_span: open_span,
@ -2798,16 +2841,11 @@ impl<'a> Parser<'a> {
maybe_whole!(deref self, NtTT);
match self.token {
token::CloseDelim(_) => {
// An unexpected closing delimiter (i.e., there is no
// matching opening delimiter).
let token_str = self.this_token_to_string();
let mut err = self.diagnostic().struct_span_err(self.span,
&format!("incorrect close delimiter: `{}`", token_str));
// This is a conservative error: only report the last unclosed delimiter.
// The previous unclosed delimiters could actually be closed! The parser
// just hasn't gotten to them yet.
if let Some(&sp) = self.open_braces.last() {
err.span_note(sp, "unclosed delimiter");
};
let err = self.diagnostic().struct_span_err(self.span,
&format!("unexpected close delimiter: `{}`", token_str));
Err(err)
},
/* we ought to allow different depths of unquotation */
@ -3825,7 +3863,9 @@ impl<'a> Parser<'a> {
fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) {
let mut brace_depth = 0;
let mut bracket_depth = 0;
debug!("recover_stmt_ enter loop");
loop {
debug!("recover_stmt_ loop {:?}", self.token);
match self.token {
token::OpenDelim(token::DelimToken::Brace) => {
brace_depth += 1;
@ -3837,6 +3877,7 @@ impl<'a> Parser<'a> {
}
token::CloseDelim(token::DelimToken::Brace) => {
if brace_depth == 0 {
debug!("recover_stmt_ return - close delim {:?}", self.token);
return;
}
brace_depth -= 1;
@ -3849,12 +3890,16 @@ impl<'a> Parser<'a> {
}
self.bump();
}
token::Eof => return,
token::Eof => {
debug!("recover_stmt_ return - Eof");
return;
}
token::Semi => {
self.bump();
if break_on_semi == SemiColonMode::Break &&
brace_depth == 0 &&
bracket_depth == 0 {
debug!("recover_stmt_ return - Semi");
return;
}
}
@ -4043,6 +4088,8 @@ impl<'a> Parser<'a> {
while !self.eat(&token::CloseDelim(token::Brace)) {
let Spanned {node, span} = if let Some(s) = self.parse_stmt_() {
s
} else if self.token == token::Eof {
break;
} else {
// Found only `;` or `}`.
continue;

View File

@ -10,4 +10,5 @@ crate-type = ["dylib"]
[dependencies]
fmt_macros = { path = "../libfmt_macros" }
log = { path = "../liblog" }
syntax = { path = "../libsyntax" }

View File

@ -78,7 +78,10 @@ fn expand_derive(cx: &mut ExtCtxt,
mitem: &MetaItem,
annotatable: Annotatable)
-> Annotatable {
annotatable.map_item_or(|item| {
debug!("expand_derive: span = {:?}", span);
debug!("expand_derive: mitem = {:?}", mitem);
debug!("expand_derive: annotatable input = {:?}", annotatable);
let annot = annotatable.map_item_or(|item| {
item.map(|mut item| {
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
@ -89,6 +92,9 @@ fn expand_derive(cx: &mut ExtCtxt,
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
let mut found_partial_eq = false;
let mut found_eq = false;
for titem in traits.iter().rev() {
let tname = match titem.node {
MetaItemKind::Word(ref tname) => tname,
@ -107,17 +113,64 @@ fn expand_derive(cx: &mut ExtCtxt,
continue;
}
if &tname[..] == "Eq" {
found_eq = true;
} else if &tname[..] == "PartialEq" {
found_partial_eq = true;
}
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
intern_and_get_ident(&format!("derive_{}", tname)))));
}
// RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
// `#[structural_match]` attribute.
if found_partial_eq && found_eq {
// This span is **very** sensitive and crucial to
// getting the stability behavior we want. What we are
// doing is marking `#[structural_match]` with the
// span of the `#[deriving(...)]` attribute (the
// entire attribute, not just the `PartialEq` or `Eq`
// part), but with the current backtrace. The current
// backtrace will contain a topmost entry that IS this
// `#[deriving(...)]` attribute and with the
// "allow-unstable" flag set to true.
//
// Note that we do NOT use the span of the `Eq`
// text itself. You might think this is
// equivalent, because the `Eq` appears within the
// `#[deriving(Eq)]` attribute, and hence we would
// inherit the "allows unstable" from the
// backtrace. But in fact this is not always the
// case. The actual source text that led to
// deriving can be `#[$attr]`, for example, where
// `$attr == deriving(Eq)`. In that case, the
// "#[structural_match]" would be considered to
// originate not from the deriving call but from
// text outside the deriving call, and hence would
// be forbidden from using unstable
// content.
//
// See tests src/run-pass/rfc1445 for
// examples. --nmatsakis
let span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
debug!("inserting structural_match with span {:?}", span);
let structural_match = intern_and_get_ident("structural_match");
item.attrs.push(cx.attribute(span,
cx.meta_word(span,
structural_match)));
}
item
})
}, |a| {
cx.span_err(span, "`derive` can only be applied to items");
a
})
});
debug!("expand_derive: annotatable output = {:?}", annot);
annot
}
macro_rules! derive_traits {

View File

@ -24,6 +24,7 @@
#![feature(str_char)]
extern crate fmt_macros;
#[macro_use] extern crate log;
#[macro_use]
extern crate syntax;

View File

@ -1,4 +1,4 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -11,11 +11,9 @@
// FIXME(31528) we emit a bunch of silly errors here due to continuing past the
// first one. This would be easy-ish to address by better recovery in tokenisation.
// compile-flags: -Z parse-only
pub fn trace_option(option: Option<isize>) { //~ HELP did you mean to close this delimiter?
pub fn trace_option(option: Option<isize>) {
option.map(|some| 42; //~ NOTE: unclosed delimiter
//~^ ERROR: expected one of
//~^^ ERROR: mismatched types
} //~ ERROR: incorrect close delimiter
//~^ ERROR: expected one of
//~ ERROR: this file contains an un-closed delimiter

View File

@ -0,0 +1,16 @@
// 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.
// Test that error recovery in the parser to an EOF does not give an infinite
// spew of errors.
fn main() {
let
} //~ ERROR unexpected token: `}`

View File

@ -24,9 +24,13 @@ fn main() { //~ ERROR compilation successful
_ => {},
};
//~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
//~| WARNING floating point constants cannot be used
//~| WARNING this was previously accepted
match [x, 1.0] {
[NAN, _] => {},
_ => {},
};
//~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
//~| WARNING floating point constants cannot be used
//~| WARNING this was previously accepted
}

View File

@ -0,0 +1,36 @@
// 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.
// Test that structural match is only permitted with a feature gate,
// and that if a feature gate is supplied, it permits the type to be
// used in a match.
// revisions: with_gate no_gate
#![allow(dead_code)]
#![deny(future_incompatible)]
#![feature(rustc_attrs)]
#![cfg_attr(with_gate, feature(structural_match))]
#[structural_match] //[no_gate]~ ERROR semantics of constant patterns is not yet settled
struct Foo {
x: u32
}
const FOO: Foo = Foo { x: 0 };
#[rustc_error]
fn main() { //[with_gate]~ ERROR compilation successful
let y = Foo { x: 1 };
match y {
FOO => { }
_ => { }
}
}

View File

@ -0,0 +1,39 @@
// 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.
#![allow(dead_code)]
#![deny(future_incompatible)]
use std::f32;
#[derive(PartialEq)]
struct Foo {
x: u32
}
const FOO: Foo = Foo { x: 0 };
fn main() {
let y = Foo { x: 1 };
match y {
FOO => { }
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
//~| WARNING will become a hard error
_ => { }
}
let x = 0.0;
match x {
f32::INFINITY => { }
//~^ ERROR floating point constants cannot be used in patterns
//~| WARNING will become a hard error
_ => { }
}
}

View File

@ -0,0 +1,35 @@
// 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.
#![allow(dead_code)]
#![deny(future_incompatible)]
#[derive(Eq)]
struct Foo {
x: u32
}
impl PartialEq for Foo {
fn eq(&self, _: &Foo) -> bool {
false // ha ha sucker!
}
}
const FOO: Foo = Foo { x: 0 };
fn main() {
let y = Foo { x: 1 };
match y {
FOO => { }
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
//~| WARNING will become a hard error
_ => { }
}
}

View File

@ -0,0 +1,17 @@
// 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.
// Test that we do some basic error correcton in the tokeniser (and don't ICE).
fn main() {
if foo { //~ NOTE: unclosed delimiter
//~^ ERROR: unresolved name `foo`
) //~ ERROR: incorrect close delimiter: `)`
}

View File

@ -0,0 +1,33 @@
// 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.
// Test that we do some basic error correcton in the tokeniser (and don't spew
// too many bogus errors).
pub mod raw {
use std::{io, fs};
use std::path::Path;
pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
callback: F)
-> io::Result<bool> {
if !is_directory(path.as_ref()) { //~ ERROR: unresolved name `is_directory`
callback(path.as_ref(); //~ NOTE: unclosed delimiter
//~^ ERROR: expected one of
fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: expected one of
} else { //~ ERROR: incorrect close delimiter: `}`
Ok(false);
}
panic!();
}
}
fn main() {}

View File

@ -0,0 +1,20 @@
// 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.
// Test that we do some basic error correcton in the tokeniser.
fn main() {
foo(bar(; //~ NOTE: unclosed delimiter
//~^ NOTE: unclosed delimiter
//~^^ ERROR: unexpected token: `;`
//~^^^ ERROR: unresolved name `bar`
//~^^^^ ERROR: unresolved name `foo`
} //~ ERROR: incorrect close delimiter: `}`
//~^ ERROR: incorrect close delimiter: `}`

View File

@ -21,15 +21,18 @@
const CONSTANT: u64 = 3;
#[derive(PartialEq, Eq)]
struct Struct {
a: isize,
b: usize,
}
const STRUCT: Struct = Struct { a: 1, b: 2 };
#[derive(PartialEq, Eq)]
struct TupleStruct(u32);
const TUPLE_STRUCT: TupleStruct = TupleStruct(4);
#[derive(PartialEq, Eq)]
enum Enum {
Variant1(char),
Variant2 { a: u8 },

View File

@ -10,4 +10,4 @@
// compile-flags: -Z parse-only
static foo: isize = 2; } //~ ERROR incorrect close delimiter:
static foo: isize = 2; } //~ ERROR unexpected close delimiter:

View File

@ -14,4 +14,4 @@ fn main() {
foo! (
bar, "baz", 1, 2.0
} //~ ERROR incorrect close delimiter
}
} //~ ERROR unexpected close delimiter: `}`

View File

@ -17,6 +17,7 @@ use empty_struct::XEmpty2 as XFoo;
struct Foo;
#[derive(PartialEq, Eq)]
enum Bar {
Var1,
Var2,

View File

@ -18,7 +18,10 @@ use empty_struct::*;
struct Empty1 {}
struct Empty2;
#[derive(PartialEq, Eq)]
struct Empty3 {}
const Empty3: Empty3 = Empty3 {};
enum E {

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// pretty-expanded FIXME #23616
#![feature(collections)]
extern crate collections;

View File

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -9,17 +9,17 @@
// except according to those terms.
// aux-build:i8.rs
// ignore-pretty (#23623)
extern crate i8;
use std::string as i16;
static i32: i32 = 0;
const i64: i64 = 0;
fn u8(f32: f32) {}
fn f<f64>(f64: f64) {}
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
type u16 = u16; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
enum u32 {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
struct u64; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
trait bool {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
enum u32 {}
struct u64;
trait bool {}
mod char {
extern crate i8;
@ -40,29 +40,52 @@ mod char {
use super::u8_ as u8;
use super::f_ as f64;
use super::u16_ as u16;
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
use super::u32_ as u32;
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
use super::u64_ as u64;
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
use super::bool_ as bool;
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
use super::{bool_ as str};
//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
use super::char_ as char;
}
}
trait isize_ {
type isize; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
type isize;
}
fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize }
mod reuse {
use std::mem::size_of;
type u8 = u64;
use std::string::String as i16;
pub fn check<u16>() {
assert_eq!(size_of::<u8>(), 8);
assert_eq!(size_of::<::u64>(), 0);
assert_eq!(size_of::<i16>(), 3 * size_of::<*const ()>());
assert_eq!(size_of::<u16>(), 0);
}
}
mod guard {
pub fn check() {
use std::u8; // bring module u8 in scope
fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
u8::max_value() // OK, resolves to associated function <u8>::max_value,
// not to non-existent std::u8::max_value
}
assert_eq!(f(), u8::MAX); // OK, resolves to std::u8::MAX
}
}
fn main() {
let bool = true;
match bool {
let _ = match bool {
str @ true => if str { i32 as i64 } else { i64 },
false => i64,
};
reuse::check::<u64>();
guard::check();
}

View File

@ -9,18 +9,24 @@
// except according to those terms.
#[derive(PartialEq, Eq)]
struct NewBool(bool);
#[derive(PartialEq, Eq)]
enum Direction {
North,
East,
South,
West
}
#[derive(PartialEq, Eq)]
struct Foo {
bar: Option<Direction>,
baz: NewBool
}
#[derive(PartialEq, Eq)]
enum EnumWithStructVariants {
Variant1(bool),
Variant2 {
@ -37,7 +43,7 @@ const VARIANT2_NORTH: EnumWithStructVariants = EnumWithStructVariants::Variant2
dir: Direction::North };
pub mod glfw {
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct InputState(usize);
pub const RELEASE : InputState = InputState(0);
@ -82,6 +88,7 @@ fn issue_14576() {
_ => unreachable!()
}
#[derive(PartialEq, Eq)]
enum C { D = 3, E = 4 }
const F : C = C::D;
@ -89,6 +96,7 @@ fn issue_14576() {
}
fn issue_13731() {
#[derive(PartialEq, Eq)]
enum A { AA(()) }
const B: A = A::AA(());
@ -99,6 +107,7 @@ fn issue_13731() {
fn issue_15393() {
#![allow(dead_code)]
#[derive(PartialEq, Eq)]
struct Flags {
bits: usize
}

View File

@ -0,0 +1,41 @@
// 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.
use std::env;
use std::io;
use std::io::Write;
use std::process::{Command, Stdio};
fn main() {
let mut args = env::args();
let me = args.next().unwrap();
let arg = args.next();
match arg.as_ref().map(|s| &s[..]) {
None => {
let mut s = Command::new(&me)
.arg("a1")
.stdin(Stdio::piped())
.spawn()
.unwrap();
s.stdin.take().unwrap().write_all(b"foo\n").unwrap();
let s = s.wait().unwrap();
assert!(s.success());
}
Some("a1") => {
let s = Command::new(&me).arg("a2").status().unwrap();
assert!(s.success());
}
Some(..) => {
let mut s = String::new();
io::stdin().read_line(&mut s).unwrap();
assert_eq!(s, "foo\n");
}
}
}

View File

@ -0,0 +1,32 @@
// 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.
#![allow(dead_code)]
macro_rules! foo {
(#[$attr:meta] $x:ident) => {
#[$attr]
struct $x {
x: u32
}
}
}
foo! { #[derive(PartialEq, Eq)] Foo }
const FOO: Foo = Foo { x: 0 };
fn main() {
let y = Foo { x: 1 };
match y {
FOO => { }
_ => { }
}
}

View File

@ -0,0 +1,26 @@
// 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.
#![allow(dead_code)]
#[derive(PartialEq, Eq)]
struct Foo {
x: u32
}
const FOO: Foo = Foo { x: 0 };
fn main() {
let y = Foo { x: 1 };
match y {
FOO => { }
_ => { }
}
}