Auto merge of #64209 - Centril:rollup-x9kvjb7, r=Centril

Rollup of 10 pull requests

Successful merges:

 - #63676 (Use wasi crate for Core API)
 - #64094 (Improve searching in rustdoc and add tests)
 - #64111 (or-patterns: Uniformly use `PatKind::Or` in AST & Fix/Cleanup resolve)
 - #64156 (Assume non-git LLVM is fresh if the stamp file exists)
 - #64161 (Point at variant on pattern field count mismatch)
 - #64174 (Add missing code examples on Iterator trait)
 - #64175 (Fix invalid span generation when it should be div)
 - #64186 (std: Improve downstream codegen in `Command::env`)
 - #64190 (fill metadata in rustc_lexer's Cargo.toml)
 - #64198 (Add Fuchsia to actually_monotonic)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-09-06 07:37:41 +00:00
commit 1fb3c4ec7c
73 changed files with 1984 additions and 1156 deletions

View file

@ -3870,6 +3870,7 @@ dependencies = [
"rustc_msan",
"rustc_tsan",
"unwind",
"wasi",
]
[[package]]
@ -4686,6 +4687,17 @@ dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "winapi"
version = "0.2.8"

View file

@ -81,26 +81,29 @@ impl Step for Llvm {
(info, "src/llvm-project/llvm", builder.llvm_out(target), dir.join("bin"))
};
if !llvm_info.is_git() {
println!(
"git could not determine the LLVM submodule commit hash. \
Assuming that an LLVM build is necessary.",
);
}
let build_llvm_config = llvm_config_ret_dir
.join(exe("llvm-config", &*builder.config.build));
let done_stamp = out_dir.join("llvm-finished-building");
if let Some(llvm_commit) = llvm_info.sha() {
if done_stamp.exists() {
if done_stamp.exists() {
if let Some(llvm_commit) = llvm_info.sha() {
let done_contents = t!(fs::read(&done_stamp));
// If LLVM was already built previously and the submodule's commit didn't change
// from the previous build, then no action is required.
if done_contents == llvm_commit.as_bytes() {
return build_llvm_config
return build_llvm_config;
}
} else {
builder.info(
"Could not determine the LLVM submodule commit hash. \
Assuming that an LLVM rebuild is not necessary.",
);
builder.info(&format!(
"To force LLVM to rebuild, remove the file `{}`",
done_stamp.display()
));
return build_llvm_config;
}
}
@ -303,9 +306,7 @@ impl Step for Llvm {
cfg.build();
if let Some(llvm_commit) = llvm_info.sha() {
t!(fs::write(&done_stamp, llvm_commit));
}
t!(fs::write(&done_stamp, llvm_info.sha().unwrap_or("")));
build_llvm_config
}

View file

@ -2546,6 +2546,16 @@ pub trait Iterator {
/// Lexicographically compares the elements of this `Iterator` with those
/// of another.
///
/// # Examples
///
/// ```
/// use std::cmp::Ordering;
///
/// assert_eq!([1].iter().cmp([1].iter()), Ordering::Equal);
/// assert_eq!([1].iter().cmp([1, 2].iter()), Ordering::Less);
/// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn cmp<I>(mut self, other: I) -> Ordering where
I: IntoIterator<Item = Self::Item>,
@ -2578,6 +2588,18 @@ pub trait Iterator {
/// Lexicographically compares the elements of this `Iterator` with those
/// of another.
///
/// # Examples
///
/// ```
/// use std::cmp::Ordering;
///
/// assert_eq!([1.].iter().partial_cmp([1.].iter()), Some(Ordering::Equal));
/// assert_eq!([1.].iter().partial_cmp([1., 2.].iter()), Some(Ordering::Less));
/// assert_eq!([1., 2.].iter().partial_cmp([1.].iter()), Some(Ordering::Greater));
///
/// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where
I: IntoIterator,
@ -2610,6 +2632,13 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are equal to those of
/// another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().eq([1].iter()), true);
/// assert_eq!([1].iter().eq([1, 2].iter()), false);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn eq<I>(mut self, other: I) -> bool where
I: IntoIterator,
@ -2635,6 +2664,13 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are unequal to those of
/// another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().ne([1].iter()), false);
/// assert_eq!([1].iter().ne([1, 2].iter()), true);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn ne<I>(self, other: I) -> bool where
I: IntoIterator,
@ -2646,6 +2682,14 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are lexicographically
/// less than those of another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().lt([1].iter()), false);
/// assert_eq!([1].iter().lt([1, 2].iter()), true);
/// assert_eq!([1, 2].iter().lt([1].iter()), false);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn lt<I>(self, other: I) -> bool where
I: IntoIterator,
@ -2657,6 +2701,14 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are lexicographically
/// less or equal to those of another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().le([1].iter()), true);
/// assert_eq!([1].iter().le([1, 2].iter()), true);
/// assert_eq!([1, 2].iter().le([1].iter()), false);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn le<I>(self, other: I) -> bool where
I: IntoIterator,
@ -2671,6 +2723,14 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are lexicographically
/// greater than those of another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().gt([1].iter()), false);
/// assert_eq!([1].iter().gt([1, 2].iter()), false);
/// assert_eq!([1, 2].iter().gt([1].iter()), true);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn gt<I>(self, other: I) -> bool where
I: IntoIterator,
@ -2682,6 +2742,14 @@ pub trait Iterator {
/// Determines if the elements of this `Iterator` are lexicographically
/// greater than or equal to those of another.
///
/// # Examples
///
/// ```
/// assert_eq!([1].iter().ge([1].iter()), true);
/// assert_eq!([1].iter().ge([1, 2].iter()), false);
/// assert_eq!([1, 2].iter().ge([1].iter()), true);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn ge<I>(self, other: I) -> bool where
I: IntoIterator,
@ -2730,6 +2798,18 @@ pub trait Iterator {
/// function to determine the ordering of two elements. Apart from that, it's equivalent to
/// [`is_sorted`]; see its documentation for more information.
///
/// # Examples
///
/// ```
/// #![feature(is_sorted)]
///
/// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
/// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
/// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
/// assert!(std::iter::empty::<i32>().is_sorted_by(|a, b| a.partial_cmp(b)));
/// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
/// ```
///
/// [`is_sorted`]: trait.Iterator.html#method.is_sorted
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
fn is_sorted_by<F>(mut self, mut compare: F) -> bool

View file

@ -425,19 +425,44 @@ impl<'a> LoweringContext<'a> {
impl<'tcx, 'interner> Visitor<'tcx> for MiscCollector<'tcx, 'interner> {
fn visit_pat(&mut self, p: &'tcx Pat) {
match p.node {
if let PatKind::Paren(..) | PatKind::Rest = p.node {
// Doesn't generate a HIR node
PatKind::Paren(..) | PatKind::Rest => {},
_ => {
if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner);
}
}
};
} else if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner);
}
visit::walk_pat(self, p)
}
// HACK(or_patterns; Centril | dlrobertson): Avoid creating
// HIR nodes for `PatKind::Or` for the top level of a `ast::Arm`.
// This is a temporary hack that should go away once we push down
// `arm.pats: HirVec<P<Pat>>` -> `arm.pat: P<Pat>` to HIR. // Centril
fn visit_arm(&mut self, arm: &'tcx Arm) {
match &arm.pat.node {
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
_ => self.visit_pat(&arm.pat),
}
walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&arm.body);
walk_list!(self, visit_attribute, &arm.attrs);
}
// HACK(or_patterns; Centril | dlrobertson): Same as above. // Centril
fn visit_expr(&mut self, e: &'tcx Expr) {
if let ExprKind::Let(pat, scrutinee) = &e.node {
walk_list!(self, visit_attribute, e.attrs.iter());
match &pat.node {
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
_ => self.visit_pat(&pat),
}
self.visit_expr(scrutinee);
self.visit_expr_post(e);
return;
}
visit::walk_expr(self, e)
}
fn visit_item(&mut self, item: &'tcx Item) {
let hir_id = self.lctx.allocate_hir_id_counter(item.id);

View file

@ -68,7 +68,7 @@ impl LoweringContext<'_> {
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::AddrOf(m, ohs)
}
ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee),
ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee),
ExprKind::If(ref cond, ref then, ref else_opt) => {
self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
}
@ -227,16 +227,11 @@ impl LoweringContext<'_> {
}
}
/// Emit an error and lower `ast::ExprKind::Let(pats, scrutinee)` into:
/// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
/// ```rust
/// match scrutinee { pats => true, _ => false }
/// ```
fn lower_expr_let(
&mut self,
span: Span,
pats: &[AstP<Pat>],
scrutinee: &Expr
) -> hir::ExprKind {
fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind {
// If we got here, the `let` expression is not allowed.
self.sess
.struct_span_err(span, "`let` expressions are not supported here")
@ -246,23 +241,23 @@ impl LoweringContext<'_> {
// For better recovery, we emit:
// ```
// match scrutinee { pats => true, _ => false }
// match scrutinee { pat => true, _ => false }
// ```
// While this doesn't fully match the user's intent, it has key advantages:
// 1. We can avoid using `abort_if_errors`.
// 2. We can typeck both `pats` and `scrutinee`.
// 3. `pats` is allowed to be refutable.
// 2. We can typeck both `pat` and `scrutinee`.
// 3. `pat` is allowed to be refutable.
// 4. The return type of the block is `bool` which seems like what the user wanted.
let scrutinee = self.lower_expr(scrutinee);
let then_arm = {
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let pat = self.lower_pat_top_hack(pat);
let expr = self.expr_bool(span, true);
self.arm(pats, P(expr))
self.arm(pat, P(expr))
};
let else_arm = {
let pats = hir_vec![self.pat_wild(span)];
let pat = self.pat_wild(span);
let expr = self.expr_bool(span, false);
self.arm(pats, P(expr))
self.arm(hir_vec![pat], P(expr))
};
hir::ExprKind::Match(
P(scrutinee),
@ -291,13 +286,12 @@ impl LoweringContext<'_> {
// Handle then + scrutinee:
let then_blk = self.lower_block(then, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar) = match cond.node {
let (then_pat, scrutinee, desugar) = match cond.node {
// `<pat> => <then>`:
ExprKind::Let(ref pats, ref scrutinee) => {
ExprKind::Let(ref pat, ref scrutinee) => {
let scrutinee = self.lower_expr(scrutinee);
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
(pats, scrutinee, desugar)
let pat = self.lower_pat_top_hack(pat);
(pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause })
}
// `true => <then>`:
_ => {
@ -312,13 +306,11 @@ impl LoweringContext<'_> {
// to preserve drop semantics since `if cond { ... }` does not
// let temporaries live outside of `cond`.
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
let pats = hir_vec![self.pat_bool(span, true)];
(pats, cond, desugar)
let pat = self.pat_bool(span, true);
(hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause })
}
};
let then_arm = self.arm(then_pats, P(then_expr));
let then_arm = self.arm(then_pat, P(then_expr));
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
}
@ -345,8 +337,8 @@ impl LoweringContext<'_> {
// Handle then + scrutinee:
let then_blk = self.lower_block(body, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
let (then_pats, scrutinee, desugar, source) = match cond.node {
ExprKind::Let(ref pats, ref scrutinee) => {
let (then_pat, scrutinee, desugar, source) = match cond.node {
ExprKind::Let(ref pat, ref scrutinee) => {
// to:
//
// [opt_ident]: loop {
@ -356,9 +348,8 @@ impl LoweringContext<'_> {
// }
// }
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
let desugar = hir::MatchSource::WhileLetDesugar;
(pats, scrutinee, desugar, hir::LoopSource::WhileLet)
let pat = self.lower_pat_top_hack(pat);
(pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
}
_ => {
// We desugar: `'label: while $cond $body` into:
@ -383,14 +374,12 @@ impl LoweringContext<'_> {
// to preserve drop semantics since `while cond { ... }` does not
// let temporaries live outside of `cond`.
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
let desugar = hir::MatchSource::WhileDesugar;
// `true => <then>`:
let pats = hir_vec![self.pat_bool(span, true)];
(pats, cond, desugar, hir::LoopSource::While)
let pat = self.pat_bool(span, true);
(hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
}
};
let then_arm = self.arm(then_pats, P(then_expr));
let then_arm = self.arm(then_pat, P(then_expr));
// `match <scrutinee> { ... }`
let match_expr = self.expr_match(
@ -440,7 +429,7 @@ impl LoweringContext<'_> {
hir::Arm {
hir_id: self.next_id(),
attrs: self.lower_attrs(&arm.attrs),
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
pats: self.lower_pat_top_hack(&arm.pat),
guard: match arm.guard {
Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))),
_ => None,
@ -450,6 +439,16 @@ impl LoweringContext<'_> {
}
}
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec<P<hir::Pat>> {
match pat.node {
PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(),
_ => hir_vec![self.lower_pat(pat)],
}
}
pub(super) fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
@ -1255,7 +1254,6 @@ impl LoweringContext<'_> {
ThinVec::from(attrs.clone()),
));
let ok_pat = self.pat_ok(span, val_pat);
self.arm(hir_vec![ok_pat], val_expr)
};
@ -1486,7 +1484,10 @@ impl LoweringContext<'_> {
}
}
fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
fn arm(&mut self, pats: HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
hir::Arm {
hir_id: self.next_id(),
attrs: hir_vec![],

View file

@ -2,8 +2,14 @@
authors = ["The Rust Project Developers"]
name = "rustc_lexer"
version = "0.1.0"
license = "MIT OR Apache-2.0"
edition = "2018"
repository = "https://github.com/rust-lang/rust/"
description = """
Rust lexer used by rustc. No stability guarantees are provided.
"""
# Note: do not remove this blank `[lib]` section.
# This will be used when publishing this crate as `rustc-ap-rustc_lexer`.
[lib]

View file

@ -772,7 +772,7 @@ impl EarlyLintPass for UnusedDocComment {
}
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi());
let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs);
}

View file

@ -493,10 +493,8 @@ impl EarlyLintPass for UnusedParens {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
use syntax::ast::ExprKind::*;
let (value, msg, followed_by_block, left_pos, right_pos) = match e.node {
Let(ref pats, ..) => {
for p in pats {
self.check_unused_parens_pat(cx, p, false, false);
}
Let(ref pat, ..) => {
self.check_unused_parens_pat(cx, pat, false, false);
return;
}
@ -594,9 +592,7 @@ impl EarlyLintPass for UnusedParens {
}
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
for p in &arm.pats {
self.check_unused_parens_pat(cx, p, false, false);
}
self.check_unused_parens_pat(cx, &arm.pat, false, false);
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(inner_deref)]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(mem_take)]

View file

@ -897,32 +897,23 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
}
}
fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
fn process_var_decl(&mut self, pat: &'l ast::Pat) {
// The pattern could declare multiple new vars,
// we must walk the pattern and collect them all.
let mut collector = PathCollector::new();
for pattern in pats {
// collect paths from the arm's patterns
collector.visit_pat(&pattern);
self.visit_pat(&pattern);
}
collector.visit_pat(&pat);
self.visit_pat(&pat);
// process collected paths
for (id, ident, immut) in collector.collected_idents {
// Process collected paths.
for (id, ident, _) in collector.collected_idents {
match self.save_ctxt.get_path_res(id) {
Res::Local(hir_id) => {
let mut value = if immut == ast::Mutability::Immutable {
self.span.snippet(ident.span)
} else {
"<mutable>".to_owned()
};
let id = self.tcx.hir().hir_to_node_id(hir_id);
let typ = self.save_ctxt
.tables
.node_type_opt(hir_id)
let typ = self.save_ctxt.tables.node_type_opt(hir_id)
.map(|t| t.to_string())
.unwrap_or_default();
value.push_str(": ");
value.push_str(&typ);
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = id_from_node_id(id, &self.save_ctxt);
@ -972,61 +963,6 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
}
}
fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
// The local could declare multiple new vars, we must walk the
// pattern and collect them all.
let mut collector = PathCollector::new();
collector.visit_pat(&p);
self.visit_pat(&p);
for (id, ident, immut) in collector.collected_idents {
let mut value = match immut {
ast::Mutability::Immutable => value.to_string(),
_ => String::new(),
};
let hir_id = self.tcx.hir().node_to_hir_id(id);
let typ = match self.save_ctxt.tables.node_type_opt(hir_id) {
Some(typ) => {
let typ = typ.to_string();
if !value.is_empty() {
value.push_str(": ");
}
value.push_str(&typ);
typ
}
None => String::new(),
};
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&Access {
public: false,
reachable: false,
},
Def {
kind: DefKind::Local,
id,
span,
name: ident.to_string(),
qualname,
value: typ,
parent: None,
children: vec![],
decl_id: None,
docs: String::new(),
sig: None,
attributes: vec![],
},
);
}
}
}
/// Extracts macro use and definition information from the AST node defined
/// by the given NodeId, using the expansion information from the node's
/// span.
@ -1565,14 +1501,13 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
});
}
ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value);
self.process_var_decl(pattern);
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
self.visit_expr(subexpression);
visit::walk_block(self, block);
}
ast::ExprKind::Let(ref pats, ref scrutinee) => {
self.process_var_decl_multi(pats);
ast::ExprKind::Let(ref pat, ref scrutinee) => {
self.process_var_decl(pat);
self.visit_expr(scrutinee);
}
ast::ExprKind::Repeat(ref element, ref count) => {
@ -1599,7 +1534,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
}
fn visit_arm(&mut self, arm: &'l ast::Arm) {
self.process_var_decl_multi(&arm.pats);
self.process_var_decl(&arm.pat);
if let Some(expr) = &arm.guard {
self.visit_expr(expr);
}
@ -1617,11 +1552,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
fn visit_local(&mut self, l: &'l ast::Local) {
self.process_macro_use(l.span);
let value = l.init
.as_ref()
.map(|i| self.span.snippet(i.span))
.unwrap_or_default();
self.process_var_decl(&l.pat, value);
self.process_var_decl(&l.pat);
// Just walk the initialiser and type (don't want to walk the pattern again).
walk_list!(self, visit_ty, &l.ty);

View file

@ -1,5 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(nll)]
#![feature(inner_deref)]
#![recursion_limit="256"]

View file

@ -675,21 +675,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span);
}
} else {
let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
let fields_ending = if variant.fields.len() == 1 { "" } else { "s" };
struct_span_err!(tcx.sess, pat.span, E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(), subpats_ending, res.descr(),
variant.fields.len(), fields_ending)
.span_label(pat.span, format!("expected {} field{}, found {}",
variant.fields.len(), fields_ending, subpats.len()))
.emit();
// Pattern has wrong number of fields.
self.e0023(pat.span, res, &subpats, &variant.fields);
on_error();
return tcx.types.err;
}
pat_ty
}
fn e0023(&self, pat_span: Span, res: Res, subpats: &'tcx [P<Pat>], fields: &[ty::FieldDef]) {
let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
let fields_ending = if fields.len() == 1 { "" } else { "s" };
let res_span = self.tcx.def_span(res.def_id());
struct_span_err!(
self.tcx.sess,
pat_span,
E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(),
subpats_ending,
res.descr(),
fields.len(),
fields_ending,
)
.span_label(pat_span, format!(
"expected {} field{}, found {}",
fields.len(),
fields_ending,
subpats.len(),
))
.span_label(res_span, format!("{} defined here", res.descr()))
.emit();
}
fn check_pat_tuple(
&self,
span: Span,

View file

@ -3554,7 +3554,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
let ns_id = cx.derive_id(format!("{}.{}",
variant.name.as_ref().unwrap(),
ItemType::Variant.name_space()));
write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
write!(w, "<div id=\"{id}\" class=\"variant small-section-header\">\
<a href=\"#{id}\" class=\"anchor field\"></a>\
<code id='{ns_id}'>{name}",
id = id,
@ -3572,7 +3572,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
write!(w, ")")?;
}
}
write!(w, "</code></span>")?;
write!(w, "</code></div>")?;
document(w, cx, variant)?;
document_non_exhaustive(w, variant)?;
@ -3583,7 +3583,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
let variant_id = cx.derive_id(format!("{}.{}.fields",
ItemType::Variant,
variant.name.as_ref().unwrap()));
write!(w, "<span class='autohide sub-variant' id='{id}'>",
write!(w, "<div class='autohide sub-variant' id='{id}'>",
id = variant_id)?;
write!(w, "<h3>Fields of <b>{name}</b></h3><div>",
name = variant.name.as_ref().unwrap())?;
@ -3609,7 +3609,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
document(w, cx, field)?;
}
}
write!(w, "</div></span>")?;
write!(w, "</div></div>")?;
}
render_stability_since(w, variant, it)?;
}

View file

@ -547,6 +547,11 @@ if (!DOMTokenList.prototype.remove) {
results.sort(function(aaa, bbb) {
var a, b;
// sort by exact match with regard to the last word (mismatch goes later)
a = (aaa.word !== val);
b = (bbb.word !== val);
if (a !== b) { return a - b; }
// Sort by non levenshtein results and then levenshtein results by the distance
// (less changes required to match means higher rankings)
a = (aaa.lev);
@ -558,11 +563,6 @@ if (!DOMTokenList.prototype.remove) {
b = (bbb.item.crate !== window.currentCrate);
if (a !== b) { return a - b; }
// sort by exact match (mismatch goes later)
a = (aaa.word !== valLower);
b = (bbb.word !== valLower);
if (a !== b) { return a - b; }
// sort by item name length (longer goes later)
a = aaa.word.length;
b = bbb.word.length;
@ -1028,7 +1028,7 @@ if (!DOMTokenList.prototype.remove) {
if (lev > MAX_LEV_DISTANCE) {
continue;
} else if (lev > 0) {
lev_add = 1;
lev_add = lev / 10;
}
}
@ -1099,10 +1099,6 @@ if (!DOMTokenList.prototype.remove) {
if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
if (index !== -1 && paths.length < 2) {
lev = 0;
} else if (searchWords[j] === val) {
// Small trick to fix when you're looking for a one letter type
// and there are other short named types.
lev = -1;
}
if (results[fullId] === undefined) {
results[fullId] = {

View file

@ -56,6 +56,9 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] }
[build-dependencies]
cc = "1.0"

View file

@ -4,14 +4,16 @@ use crate::io;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::{unsupported, Void};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
env: CommandEnv<DefaultEnvKey>,
env: CommandEnv,
}
// passed back to std::process with the pipes connected to the child, if any
@ -37,7 +39,7 @@ impl Command {
pub fn arg(&mut self, _arg: &OsStr) {}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}

View file

@ -4,14 +4,16 @@ use crate::io;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::{unsupported, Void};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
env: CommandEnv<DefaultEnvKey>
env: CommandEnv,
}
// passed back to std::process with the pipes connected to the child, if any
@ -38,7 +40,7 @@ impl Command {
pub fn arg(&mut self, _arg: &OsStr) {
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}

View file

@ -1,5 +1,6 @@
pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
pub use self::process_inner::Process;
pub use crate::ffi::OsString as EnvKey;
mod process_common;
#[cfg(not(target_os = "fuchsia"))]

View file

@ -7,7 +7,7 @@ use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
use crate::collections::BTreeMap;
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
@ -69,7 +69,7 @@ pub struct Command {
program: CString,
args: Vec<CString>,
argv: Argv,
env: CommandEnv<DefaultEnvKey>,
env: CommandEnv,
cwd: Option<CString>,
uid: Option<uid_t>,
@ -201,7 +201,7 @@ impl Command {
self.stderr = Some(stderr);
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}
@ -271,7 +271,7 @@ impl CStringArray {
}
}
fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
let mut result = CStringArray::with_capacity(env.len());
for (k, v) in env {
let mut k: OsString = k.into();

View file

@ -311,6 +311,7 @@ mod inner {
pub fn actually_monotonic() -> bool {
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) ||
(cfg!(target_os = "linux") && cfg!(target_arch = "x86")) ||
cfg!(target_os = "fuchsia") ||
false // last clause, used so `||` is always trailing above
}

View file

@ -7,11 +7,13 @@ use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
use crate::collections::BTreeMap;
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
@ -37,7 +39,7 @@ pub struct Command {
program: CString,
args: Vec<CString>,
argv: Argv,
env: CommandEnv<DefaultEnvKey>,
env: CommandEnv,
cwd: Option<CString>,
uid: Option<uid_t>,
@ -170,7 +172,7 @@ impl Command {
self.stderr = Some(stderr);
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}
@ -240,7 +242,7 @@ impl CStringArray {
}
}
fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
let mut result = CStringArray::with_capacity(env.len());
for (k, v) in env {
let mut k: OsString = k.into();

View file

@ -1,11 +1,10 @@
use crate::ffi::CStr;
use crate::io;
use crate::sys::cvt_wasi;
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStringExt;
use crate::vec;
use ::wasi::wasi_unstable as wasi;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
}
@ -19,31 +18,17 @@ pub struct Args {
/// Returns the command line arguments
pub fn args() -> Args {
maybe_args().unwrap_or_else(|_| {
Args {
iter: Vec::new().into_iter(),
_dont_send_or_sync_me: PhantomData
}
})
}
fn maybe_args() -> io::Result<Args> {
unsafe {
let (mut argc, mut argv_buf_size) = (0, 0);
cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?;
let mut argc = vec![core::ptr::null_mut::<libc::c_char>(); argc];
let mut argv_buf = vec![0; argv_buf_size];
cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?;
let args = argc.into_iter()
.map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec())
.map(|bytes| OsString::from_vec(bytes))
.collect::<Vec<_>>();
Ok(Args {
iter: args.into_iter(),
_dont_send_or_sync_me: PhantomData,
})
let buf = wasi::args_sizes_get().and_then(|args_sizes| {
let mut buf = Vec::with_capacity(args_sizes.get_count());
wasi::args_get(args_sizes, |arg| {
let arg = OsString::from_vec(arg.to_vec());
buf.push(arg);
})?;
Ok(buf)
}).unwrap_or(vec![]);
Args {
iter: buf.into_iter(),
_dont_send_or_sync_me: PhantomData
}
}

View file

@ -8,6 +8,8 @@ use crate::os::wasi::ffi::OsStrExt;
use crate::path::{Path, PathBuf};
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
use ::wasi::wasi_unstable as wasi;
/// WASI-specific extensions to [`File`].
///
/// [`File`]: ../../../../std/fs/struct.File.html
@ -336,16 +338,16 @@ pub trait FileTypeExt {
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool {
self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE
self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
}
fn is_character_device(&self) -> bool {
self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE
self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
}
fn is_socket_dgram(&self) -> bool {
self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM
self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
}
fn is_socket_stream(&self) -> bool {
self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM
self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
}
}

View file

@ -8,6 +8,8 @@ use crate::sys;
use crate::net;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use ::wasi::wasi_unstable as wasi;
/// Raw file descriptors.
pub type RawFd = u32;
@ -125,18 +127,18 @@ impl IntoRawFd for fs::File {
impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd {
libc::STDIN_FILENO as u32
wasi::STDIN_FD
}
}
impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd {
libc::STDOUT_FILENO as u32
wasi::STDOUT_FD
}
}
impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd {
libc::STDERR_FILENO as u32
wasi::STDERR_FD
}
}

View file

@ -3,348 +3,248 @@
use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
use crate::mem;
use crate::net::Shutdown;
use crate::sys::cvt_wasi;
use libc::{self, c_char, c_void};
use super::err2io;
use ::wasi::wasi_unstable as wasi;
#[derive(Debug)]
pub struct WasiFd {
fd: libc::__wasi_fd_t,
fd: wasi::Fd,
}
// FIXME: these should probably all be fancier structs, builders, enums, etc
pub type LookupFlags = u32;
pub type FdFlags = u16;
pub type Advice = u8;
pub type Rights = u64;
pub type Oflags = u16;
pub type DirCookie = u64;
pub type Timestamp = u64;
pub type FstFlags = u16;
pub type RiFlags = u16;
pub type RoFlags = u16;
pub type SiFlags = u16;
fn iovec(a: &mut [IoSliceMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) {
fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::IoVec] {
assert_eq!(
mem::size_of::<IoSliceMut<'_>>(),
mem::size_of::<libc::__wasi_iovec_t>()
mem::size_of::<wasi::IoVec>()
);
assert_eq!(
mem::align_of::<IoSliceMut<'_>>(),
mem::align_of::<libc::__wasi_iovec_t>()
mem::align_of::<wasi::IoVec>()
);
(a.as_ptr() as *const libc::__wasi_iovec_t, a.len())
/// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout
unsafe { mem::transmute(a) }
}
fn ciovec(a: &[IoSlice<'_>]) -> (*const libc::__wasi_ciovec_t, usize) {
fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::CIoVec] {
assert_eq!(
mem::size_of::<IoSlice<'_>>(),
mem::size_of::<libc::__wasi_ciovec_t>()
mem::size_of::<wasi::CIoVec>()
);
assert_eq!(
mem::align_of::<IoSlice<'_>>(),
mem::align_of::<libc::__wasi_ciovec_t>()
mem::align_of::<wasi::CIoVec>()
);
(a.as_ptr() as *const libc::__wasi_ciovec_t, a.len())
/// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout
unsafe { mem::transmute(a) }
}
impl WasiFd {
pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd {
pub unsafe fn from_raw(fd: wasi::Fd) -> WasiFd {
WasiFd { fd }
}
pub fn into_raw(self) -> libc::__wasi_fd_t {
pub fn into_raw(self) -> wasi::Fd {
let ret = self.fd;
mem::forget(self);
ret
}
pub fn as_raw(&self) -> libc::__wasi_fd_t {
pub fn as_raw(&self) -> wasi::Fd {
self.fd
}
pub fn datasync(&self) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) })
unsafe { wasi::fd_datasync(self.fd).map_err(err2io) }
}
pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
let mut read = 0;
let (ptr, len) = iovec(bufs);
cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?;
Ok(read)
unsafe { wasi::fd_pread(self.fd, iovec(bufs), offset).map_err(err2io) }
}
pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
let mut read = 0;
let (ptr, len) = ciovec(bufs);
cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?;
Ok(read)
unsafe { wasi::fd_pwrite(self.fd, ciovec(bufs), offset).map_err(err2io) }
}
pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut read = 0;
let (ptr, len) = iovec(bufs);
cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?;
Ok(read)
unsafe { wasi::fd_read(self.fd, iovec(bufs)).map_err(err2io) }
}
pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut read = 0;
let (ptr, len) = ciovec(bufs);
cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?;
Ok(read)
unsafe { wasi::fd_write(self.fd, ciovec(bufs)).map_err(err2io) }
}
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
let (whence, offset) = match pos {
SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64),
SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos),
SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos),
SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64),
SeekFrom::End(pos) => (wasi::WHENCE_END, pos),
SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos),
};
let mut pos = 0;
cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?;
Ok(pos)
unsafe { wasi::fd_seek(self.fd, offset, whence).map_err(err2io) }
}
pub fn tell(&self) -> io::Result<u64> {
let mut pos = 0;
cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?;
Ok(pos)
unsafe { wasi::fd_tell(self.fd).map_err(err2io) }
}
// FIXME: __wasi_fd_fdstat_get
pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) })
pub fn set_flags(&self, flags: wasi::FdFlags) -> io::Result<()> {
unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) }
}
pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) })
pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> {
unsafe { wasi::fd_fdstat_set_rights(self.fd, base, inheriting).map_err(err2io) }
}
pub fn sync(&self) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) })
unsafe { wasi::fd_sync(self.fd).map_err(err2io) }
}
pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) })
pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
unsafe { wasi::fd_advise(self.fd, offset, len, advice).map_err(err2io) }
}
pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) })
unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) }
}
pub fn create_directory(&self, path: &[u8]) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len())
})
unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) }
}
pub fn link(
&self,
old_flags: LookupFlags,
old_flags: wasi::LookupFlags,
old_path: &[u8],
new_fd: &WasiFd,
new_path: &[u8],
) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_link(
self.fd,
old_flags,
old_path.as_ptr() as *const c_char,
old_path.len(),
new_fd.fd,
new_path.as_ptr() as *const c_char,
new_path.len(),
)
})
unsafe {
wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path)
.map_err(err2io)
}
}
pub fn open(
&self,
dirflags: LookupFlags,
dirflags: wasi::LookupFlags,
path: &[u8],
oflags: Oflags,
fs_rights_base: Rights,
fs_rights_inheriting: Rights,
fs_flags: FdFlags,
oflags: wasi::OFlags,
fs_rights_base: wasi::Rights,
fs_rights_inheriting: wasi::Rights,
fs_flags: wasi::FdFlags,
) -> io::Result<WasiFd> {
unsafe {
let mut fd = 0;
cvt_wasi(libc::__wasi_path_open(
wasi::path_open(
self.fd,
dirflags,
path.as_ptr() as *const c_char,
path.len(),
path,
oflags,
fs_rights_base,
fs_rights_inheriting,
fs_flags,
&mut fd,
))?;
Ok(WasiFd::from_raw(fd))
).map(|fd| WasiFd::from_raw(fd)).map_err(err2io)
}
}
pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result<usize> {
let mut used = 0;
cvt_wasi(unsafe {
libc::__wasi_fd_readdir(
self.fd,
buf.as_mut_ptr() as *mut c_void,
buf.len(),
cookie,
&mut used,
)
})?;
Ok(used)
pub fn readdir(&self, buf: &mut [u8], cookie: wasi::DirCookie) -> io::Result<usize> {
unsafe { wasi::fd_readdir(self.fd, buf, cookie).map_err(err2io) }
}
pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> {
let mut used = 0;
cvt_wasi(unsafe {
libc::__wasi_path_readlink(
self.fd,
path.as_ptr() as *const c_char,
path.len(),
buf.as_mut_ptr() as *mut c_char,
buf.len(),
&mut used,
)
})?;
Ok(used)
unsafe { wasi::path_readlink(self.fd, path, buf).map_err(err2io) }
}
pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_rename(
self.fd,
old_path.as_ptr() as *const c_char,
old_path.len(),
new_fd.fd,
new_path.as_ptr() as *const c_char,
new_path.len(),
)
})
unsafe {
wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io)
}
}
pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) })
pub fn filestat_get(&self) -> io::Result<wasi::FileStat> {
unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) }
}
pub fn filestat_set_times(
&self,
atim: Timestamp,
mtim: Timestamp,
fstflags: FstFlags,
atim: wasi::Timestamp,
mtim: wasi::Timestamp,
fstflags: wasi::FstFlags,
) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) })
unsafe {
wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io)
}
}
pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) })
unsafe { wasi::fd_filestat_set_size(self.fd, size).map_err(err2io) }
}
pub fn path_filestat_get(
&self,
flags: LookupFlags,
flags: wasi::LookupFlags,
path: &[u8],
buf: *mut libc::__wasi_filestat_t,
) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_filestat_get(
self.fd,
flags,
path.as_ptr() as *const c_char,
path.len(),
buf,
)
})
) -> io::Result<wasi::FileStat> {
unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) }
}
pub fn path_filestat_set_times(
&self,
flags: LookupFlags,
flags: wasi::LookupFlags,
path: &[u8],
atim: Timestamp,
mtim: Timestamp,
fstflags: FstFlags,
atim: wasi::Timestamp,
mtim: wasi::Timestamp,
fstflags: wasi::FstFlags,
) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_filestat_set_times(
unsafe {
wasi::path_filestat_set_times(
self.fd,
flags,
path.as_ptr() as *const c_char,
path.len(),
path,
atim,
mtim,
fstflags,
)
})
).map_err(err2io)
}
}
pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_symlink(
old_path.as_ptr() as *const c_char,
old_path.len(),
self.fd,
new_path.as_ptr() as *const c_char,
new_path.len(),
)
})
unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) }
}
pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len())
})
unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) }
}
pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> {
cvt_wasi(unsafe {
libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len())
})
unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) }
}
pub fn sock_recv(
&self,
ri_data: &mut [IoSliceMut<'_>],
ri_flags: RiFlags,
) -> io::Result<(usize, RoFlags)> {
let mut ro_datalen = 0;
let mut ro_flags = 0;
let (ptr, len) = iovec(ri_data);
cvt_wasi(unsafe {
libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags)
})?;
Ok((ro_datalen, ro_flags))
ri_flags: wasi::RiFlags,
) -> io::Result<(usize, wasi::RoFlags)> {
unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) }
}
pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: SiFlags) -> io::Result<usize> {
let mut so_datalen = 0;
let (ptr, len) = ciovec(si_data);
cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?;
Ok(so_datalen)
pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::SiFlags) -> io::Result<usize> {
unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) }
}
pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Read => libc::__WASI_SHUT_RD,
Shutdown::Write => libc::__WASI_SHUT_WR,
Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD,
Shutdown::Read => wasi::SHUT_RD,
Shutdown::Write => wasi::SHUT_WR,
Shutdown::Both => wasi::SHUT_WR | wasi::SHUT_RD,
};
cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?;
Ok(())
unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) }
}
}
impl Drop for WasiFd {
fn drop(&mut self) {
unsafe {
// FIXME: can we handle the return code here even though we can't on
// unix?
libc::__wasi_fd_close(self.fd);
}
// FIXME: can we handle the return code here even though we can't on
// unix?
let _ = unsafe { wasi::fd_close(self.fd) };
}
}

View file

@ -7,7 +7,7 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
use crate::path::{Path, PathBuf};
use crate::ptr;
use crate::sync::Arc;
use crate::sys::fd::{DirCookie, WasiFd};
use crate::sys::fd::WasiFd;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
use crate::sys_common::FromInner;
@ -15,18 +15,20 @@ use crate::sys_common::FromInner;
pub use crate::sys_common::fs::copy;
pub use crate::sys_common::fs::remove_dir_all;
use ::wasi::wasi_unstable as wasi;
pub struct File {
fd: WasiFd,
}
#[derive(Clone)]
pub struct FileAttr {
meta: libc::__wasi_filestat_t,
meta: wasi::FileStat,
}
pub struct ReadDir {
inner: Arc<ReadDirInner>,
cookie: Option<DirCookie>,
cookie: Option<wasi::DirCookie>,
buf: Vec<u8>,
offset: usize,
cap: usize,
@ -38,7 +40,7 @@ struct ReadDirInner {
}
pub struct DirEntry {
meta: libc::__wasi_dirent_t,
meta: wasi::Dirent,
name: Vec<u8>,
inner: Arc<ReadDirInner>,
}
@ -47,11 +49,11 @@ pub struct DirEntry {
pub struct OpenOptions {
read: bool,
write: bool,
dirflags: libc::__wasi_lookupflags_t,
fdflags: libc::__wasi_fdflags_t,
oflags: libc::__wasi_oflags_t,
rights_base: Option<libc::__wasi_rights_t>,
rights_inheriting: Option<libc::__wasi_rights_t>,
dirflags: wasi::LookupFlags,
fdflags: wasi::FdFlags,
oflags: wasi::OFlags,
rights_base: Option<wasi::Rights>,
rights_inheriting: Option<wasi::Rights>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
@ -61,19 +63,13 @@ pub struct FilePermissions {
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct FileType {
bits: libc::__wasi_filetype_t,
bits: wasi::FileType,
}
#[derive(Debug)]
pub struct DirBuilder {}
impl FileAttr {
fn zero() -> FileAttr {
FileAttr {
meta: unsafe { mem::zeroed() },
}
}
pub fn size(&self) -> u64 {
self.meta.st_size
}
@ -101,7 +97,7 @@ impl FileAttr {
Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim))
}
pub fn as_wasi(&self) -> &libc::__wasi_filestat_t {
pub fn as_wasi(&self) -> &wasi::FileStat {
&self.meta
}
}
@ -118,18 +114,18 @@ impl FilePermissions {
impl FileType {
pub fn is_dir(&self) -> bool {
self.bits == libc::__WASI_FILETYPE_DIRECTORY
self.bits == wasi::FILETYPE_DIRECTORY
}
pub fn is_file(&self) -> bool {
self.bits == libc::__WASI_FILETYPE_REGULAR_FILE
self.bits == wasi::FILETYPE_REGULAR_FILE
}
pub fn is_symlink(&self) -> bool {
self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK
self.bits == wasi::FILETYPE_SYMBOLIC_LINK
}
pub fn bits(&self) -> libc::__wasi_filetype_t {
pub fn bits(&self) -> wasi::FileType {
self.bits
}
}
@ -173,7 +169,7 @@ impl Iterator for ReadDir {
// must have been truncated at the end of the buffer, so reset our
// offset so we can go back and reread into the buffer, picking up
// where we last left off.
let dirent_size = mem::size_of::<libc::__wasi_dirent_t>();
let dirent_size = mem::size_of::<wasi::Dirent>();
if data.len() < dirent_size {
assert!(self.cookie.is_some());
assert!(self.buf.len() >= dirent_size);
@ -182,7 +178,7 @@ impl Iterator for ReadDir {
}
let (dirent, data) = data.split_at(dirent_size);
let dirent =
unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) };
unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) };
// If the file name was truncated, then we need to reinvoke
// `readdir` so we truncate our buffer to start over and reread this
@ -241,7 +237,7 @@ impl DirEntry {
})
}
pub fn ino(&self) -> libc::__wasi_inode_t {
pub fn ino(&self) -> wasi::Inode {
self.meta.d_ino
}
}
@ -249,7 +245,7 @@ impl DirEntry {
impl OpenOptions {
pub fn new() -> OpenOptions {
let mut base = OpenOptions::default();
base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW;
base.dirflags = wasi::LOOKUP_SYMLINK_FOLLOW;
return base;
}
@ -262,23 +258,23 @@ impl OpenOptions {
}
pub fn truncate(&mut self, truncate: bool) {
self.oflag(libc::__WASI_O_TRUNC, truncate);
self.oflag(wasi::O_TRUNC, truncate);
}
pub fn create(&mut self, create: bool) {
self.oflag(libc::__WASI_O_CREAT, create);
self.oflag(wasi::O_CREAT, create);
}
pub fn create_new(&mut self, create_new: bool) {
self.oflag(libc::__WASI_O_EXCL, create_new);
self.oflag(libc::__WASI_O_CREAT, create_new);
self.oflag(wasi::O_EXCL, create_new);
self.oflag(wasi::O_CREAT, create_new);
}
pub fn directory(&mut self, directory: bool) {
self.oflag(libc::__WASI_O_DIRECTORY, directory);
self.oflag(wasi::O_DIRECTORY, directory);
}
fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) {
fn oflag(&mut self, bit: wasi::OFlags, set: bool) {
if set {
self.oflags |= bit;
} else {
@ -287,26 +283,26 @@ impl OpenOptions {
}
pub fn append(&mut self, set: bool) {
self.fdflag(libc::__WASI_FDFLAG_APPEND, set);
self.fdflag(wasi::FDFLAG_APPEND, set);
}
pub fn dsync(&mut self, set: bool) {
self.fdflag(libc::__WASI_FDFLAG_DSYNC, set);
self.fdflag(wasi::FDFLAG_DSYNC, set);
}
pub fn nonblock(&mut self, set: bool) {
self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set);
self.fdflag(wasi::FDFLAG_NONBLOCK, set);
}
pub fn rsync(&mut self, set: bool) {
self.fdflag(libc::__WASI_FDFLAG_RSYNC, set);
self.fdflag(wasi::FDFLAG_RSYNC, set);
}
pub fn sync(&mut self, set: bool) {
self.fdflag(libc::__WASI_FDFLAG_SYNC, set);
self.fdflag(wasi::FDFLAG_SYNC, set);
}
fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) {
fn fdflag(&mut self, bit: wasi::FdFlags, set: bool) {
if set {
self.fdflags |= bit;
} else {
@ -314,15 +310,15 @@ impl OpenOptions {
}
}
pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) {
pub fn fs_rights_base(&mut self, rights: wasi::Rights) {
self.rights_base = Some(rights);
}
pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) {
pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) {
self.rights_inheriting = Some(rights);
}
fn rights_base(&self) -> libc::__wasi_rights_t {
fn rights_base(&self) -> wasi::Rights {
if let Some(rights) = self.rights_base {
return rights;
}
@ -334,52 +330,52 @@ impl OpenOptions {
// based on that.
let mut base = 0;
if self.read {
base |= libc::__WASI_RIGHT_FD_READ;
base |= libc::__WASI_RIGHT_FD_READDIR;
base |= wasi::RIGHT_FD_READ;
base |= wasi::RIGHT_FD_READDIR;
}
if self.write {
base |= libc::__WASI_RIGHT_FD_WRITE;
base |= libc::__WASI_RIGHT_FD_DATASYNC;
base |= libc::__WASI_RIGHT_FD_ALLOCATE;
base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE;
base |= wasi::RIGHT_FD_WRITE;
base |= wasi::RIGHT_FD_DATASYNC;
base |= wasi::RIGHT_FD_ALLOCATE;
base |= wasi::RIGHT_FD_FILESTAT_SET_SIZE;
}
// FIXME: some of these should probably be read-only or write-only...
base |= libc::__WASI_RIGHT_FD_ADVISE;
base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS;
base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES;
base |= libc::__WASI_RIGHT_FD_SEEK;
base |= libc::__WASI_RIGHT_FD_SYNC;
base |= libc::__WASI_RIGHT_FD_TELL;
base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
base |= libc::__WASI_RIGHT_PATH_CREATE_FILE;
base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET;
base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE;
base |= libc::__WASI_RIGHT_PATH_LINK_TARGET;
base |= libc::__WASI_RIGHT_PATH_OPEN;
base |= libc::__WASI_RIGHT_PATH_READLINK;
base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY;
base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE;
base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET;
base |= libc::__WASI_RIGHT_PATH_SYMLINK;
base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE;
base |= libc::__WASI_RIGHT_POLL_FD_READWRITE;
base |= wasi::RIGHT_FD_ADVISE;
base |= wasi::RIGHT_FD_FDSTAT_SET_FLAGS;
base |= wasi::RIGHT_FD_FILESTAT_SET_TIMES;
base |= wasi::RIGHT_FD_SEEK;
base |= wasi::RIGHT_FD_SYNC;
base |= wasi::RIGHT_FD_TELL;
base |= wasi::RIGHT_PATH_CREATE_DIRECTORY;
base |= wasi::RIGHT_PATH_CREATE_FILE;
base |= wasi::RIGHT_PATH_FILESTAT_GET;
base |= wasi::RIGHT_PATH_LINK_SOURCE;
base |= wasi::RIGHT_PATH_LINK_TARGET;
base |= wasi::RIGHT_PATH_OPEN;
base |= wasi::RIGHT_PATH_READLINK;
base |= wasi::RIGHT_PATH_REMOVE_DIRECTORY;
base |= wasi::RIGHT_PATH_RENAME_SOURCE;
base |= wasi::RIGHT_PATH_RENAME_TARGET;
base |= wasi::RIGHT_PATH_SYMLINK;
base |= wasi::RIGHT_PATH_UNLINK_FILE;
base |= wasi::RIGHT_POLL_FD_READWRITE;
return base;
}
fn rights_inheriting(&self) -> libc::__wasi_rights_t {
fn rights_inheriting(&self) -> wasi::Rights {
self.rights_inheriting.unwrap_or_else(|| self.rights_base())
}
pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) {
pub fn lookup_flags(&mut self, flags: wasi::LookupFlags) {
self.dirflags = flags;
}
}
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?;
let (dir, file) = open_parent(path, wasi::RIGHT_PATH_OPEN)?;
open_at(&dir, &file, opts)
}
@ -388,14 +384,12 @@ impl File {
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut ret = FileAttr::zero();
self.fd.filestat_get(&mut ret.meta)?;
Ok(ret)
self.fd.filestat_get().map(|meta| FileAttr { meta })
}
pub fn metadata_at(
&self,
flags: libc::__wasi_lookupflags_t,
flags: wasi::LookupFlags,
path: &Path,
) -> io::Result<FileAttr> {
metadata_at(&self.fd, flags, path)
@ -477,7 +471,7 @@ impl DirBuilder {
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?;
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_CREATE_DIRECTORY)?;
dir.create_directory(file.as_os_str().as_bytes())
}
}
@ -508,13 +502,13 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
}
pub fn unlink(p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?;
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_UNLINK_FILE)?;
dir.unlink_file(file.as_os_str().as_bytes())
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?;
let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?;
let (old, old_file) = open_parent(old, wasi::RIGHT_PATH_RENAME_SOURCE)?;
let (new, new_file) = open_parent(new, wasi::RIGHT_PATH_RENAME_TARGET)?;
old.rename(
old_file.as_os_str().as_bytes(),
&new,
@ -529,12 +523,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
}
pub fn rmdir(p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?;
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_REMOVE_DIRECTORY)?;
dir.remove_directory(file.as_os_str().as_bytes())
}
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?;
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_READLINK)?;
read_link(&dir, &file)
}
@ -570,15 +564,15 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
}
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?;
let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_SYMLINK)?;
dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes())
}
pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?;
let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?;
let (src, src_file) = open_parent(src, wasi::RIGHT_PATH_LINK_SOURCE)?;
let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_LINK_TARGET)?;
src.link(
libc::__WASI_LOOKUP_SYMLINK_FOLLOW,
wasi::LOOKUP_SYMLINK_FOLLOW,
src_file.as_os_str().as_bytes(),
&dst,
dst_file.as_os_str().as_bytes(),
@ -586,23 +580,22 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
}
pub fn stat(p: &Path) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file)
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?;
metadata_at(&dir, wasi::LOOKUP_SYMLINK_FOLLOW, &file)
}
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?;
metadata_at(&dir, 0, &file)
}
fn metadata_at(
fd: &WasiFd,
flags: libc::__wasi_lookupflags_t,
flags: wasi::LookupFlags,
path: &Path,
) -> io::Result<FileAttr> {
let mut ret = FileAttr::zero();
fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?;
Ok(ret)
fd.path_filestat_get(flags, path.as_os_str().as_bytes())
.map(|meta| FileAttr { meta })
}
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
@ -652,12 +645,12 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
/// to any preopened file descriptor.
fn open_parent(
p: &Path,
rights: libc::__wasi_rights_t,
rights: wasi::Rights,
) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
let p = CString::new(p.as_os_str().as_bytes())?;
unsafe {
let mut ret = ptr::null();
let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
if fd == -1 {
let msg = format!(
"failed to find a preopened file descriptor \
@ -677,15 +670,4 @@ fn open_parent(
return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
}
// FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API
// there is published
extern "C" {
pub fn __wasilibc_find_relpath(
path: *const libc::c_char,
rights_base: libc::__wasi_rights_t,
rights_inheriting: libc::__wasi_rights_t,
relative_path: *mut *const libc::c_char,
) -> libc::c_int;
}
}

View file

@ -1,11 +1,12 @@
use crate::marker::PhantomData;
use crate::slice;
use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void};
use ::wasi::wasi_unstable as wasi;
use core::ffi::c_void;
#[repr(transparent)]
pub struct IoSlice<'a> {
vec: __wasi_ciovec_t,
vec: wasi::CIoVec,
_p: PhantomData<&'a [u8]>,
}
@ -13,7 +14,7 @@ impl<'a> IoSlice<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice {
vec: __wasi_ciovec_t {
vec: wasi::CIoVec {
buf: buf.as_ptr() as *const c_void,
buf_len: buf.len(),
},
@ -43,7 +44,7 @@ impl<'a> IoSlice<'a> {
#[repr(transparent)]
pub struct IoSliceMut<'a> {
vec: __wasi_iovec_t,
vec: wasi::IoVec,
_p: PhantomData<&'a mut [u8]>,
}
@ -51,7 +52,7 @@ impl<'a> IoSliceMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut {
vec: __wasi_iovec_t {
vec: wasi::IoVec {
buf: buf.as_mut_ptr() as *mut c_void,
buf_len: buf.len()
},

View file

@ -14,10 +14,10 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
use libc;
use crate::io::{Error, ErrorKind};
use crate::io as std_io;
use crate::mem;
use crate::os::raw::c_char;
use ::wasi::wasi_unstable as wasi;
pub mod alloc;
pub mod args;
@ -56,31 +56,42 @@ pub mod ext;
pub fn init() {
}
pub fn unsupported<T>() -> crate::io::Result<T> {
pub fn unsupported<T>() -> std_io::Result<T> {
Err(unsupported_err())
}
pub fn unsupported_err() -> Error {
Error::new(ErrorKind::Other, "operation not supported on wasm yet")
pub fn unsupported_err() -> std_io::Error {
std_io::Error::new(
std_io::ErrorKind::Other,
"operation not supported on wasm yet",
)
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
libc::ECONNRESET => ErrorKind::ConnectionReset,
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
libc::EPIPE => ErrorKind::BrokenPipe,
libc::ENOTCONN => ErrorKind::NotConnected,
libc::ECONNABORTED => ErrorKind::ConnectionAborted,
libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
libc::EADDRINUSE => ErrorKind::AddrInUse,
libc::ENOENT => ErrorKind::NotFound,
libc::EINTR => ErrorKind::Interrupted,
libc::EINVAL => ErrorKind::InvalidInput,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
libc::EAGAIN => ErrorKind::WouldBlock,
_ => ErrorKind::Other,
pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
use std_io::ErrorKind::*;
if errno > u16::max_value() as i32 || errno < 0 {
return Other;
}
let code = match wasi::Error::new(errno as u16) {
Some(code) => code,
None => return Other,
};
match code {
wasi::ECONNREFUSED => ConnectionRefused,
wasi::ECONNRESET => ConnectionReset,
wasi::EPERM | wasi::EACCES => PermissionDenied,
wasi::EPIPE => BrokenPipe,
wasi::ENOTCONN => NotConnected,
wasi::ECONNABORTED => ConnectionAborted,
wasi::EADDRNOTAVAIL => AddrNotAvailable,
wasi::EADDRINUSE => AddrInUse,
wasi::ENOENT => NotFound,
wasi::EINTR => Interrupted,
wasi::EINVAL => InvalidInput,
wasi::ETIMEDOUT => TimedOut,
wasi::EEXIST => AlreadyExists,
wasi::EAGAIN => WouldBlock,
_ => Other,
}
}
@ -105,40 +116,16 @@ pub unsafe fn abort_internal() -> ! {
pub fn hashmap_random_keys() -> (u64, u64) {
let mut ret = (0u64, 0u64);
unsafe {
let base = &mut ret as *mut (u64, u64) as *mut libc::c_void;
let base = &mut ret as *mut (u64, u64) as *mut core::ffi::c_void;
let len = mem::size_of_val(&ret);
cvt_wasi(libc::__wasi_random_get(base, len)).unwrap();
let ret = wasi::raw::__wasi_random_get(base, len);
if ret != 0 {
panic!("__wasi_random_get failure")
}
}
return ret
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
if t.is_minus_one() {
Err(Error::last_os_error())
} else {
Ok(t)
}
}
pub fn cvt_wasi(r: u16) -> crate::io::Result<()> {
if r != libc::__WASI_ESUCCESS {
Err(Error::from_raw_os_error(r as i32))
} else {
Ok(())
}
fn err2io(err: wasi::Error) -> std_io::Error {
std_io::Error::from_raw_os_error(err.get() as i32)
}

View file

@ -9,7 +9,7 @@ use crate::path::{self, PathBuf};
use crate::ptr;
use crate::str;
use crate::sys::memchr;
use crate::sys::{cvt, unsupported, Void};
use crate::sys::{unsupported, Void};
use crate::vec;
#[cfg(not(target_feature = "atomics"))]
@ -28,16 +28,11 @@ pub fn errno() -> i32 {
}
pub fn error_string(errno: i32) -> String {
extern {
fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char,
buflen: libc::size_t) -> libc::c_int;
}
let mut buf = [0 as libc::c_char; 1024];
let p = buf.as_mut_ptr();
unsafe {
if strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
panic!("strerror_r failure");
}
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
@ -89,7 +84,6 @@ impl StdError for JoinPathsError {
pub fn current_exe() -> io::Result<PathBuf> {
unsupported()
}
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
@ -182,3 +176,26 @@ pub fn exit(code: i32) -> ! {
pub fn getpid() -> u32 {
panic!("unsupported");
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}

View file

@ -4,14 +4,16 @@ use crate::io;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::{unsupported, Void};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
env: CommandEnv<DefaultEnvKey>
env: CommandEnv
}
// passed back to std::process with the pipes connected to the child, if any
@ -38,7 +40,7 @@ impl Command {
pub fn arg(&mut self, _arg: &OsStr) {
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}

View file

@ -1,8 +1,9 @@
use crate::io::{self, IoSlice, IoSliceMut};
use crate::libc;
use crate::mem::ManuallyDrop;
use crate::sys::fd::WasiFd;
use ::wasi::wasi_unstable as wasi;
pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
@ -17,7 +18,7 @@ impl Stdin {
}
pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDIN_FD) })
.read(data)
}
}
@ -32,7 +33,7 @@ impl Stdout {
}
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) })
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDOUT_FD) })
.write(data)
}
@ -51,7 +52,7 @@ impl Stderr {
}
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) })
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDERR_FD) })
.write(data)
}
@ -73,7 +74,7 @@ impl io::Write for Stderr {
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(libc::__WASI_EBADF as i32)
err.raw_os_error() == Some(wasi::EBADF.get() as i32)
}
pub fn panic_output() -> Option<impl io::Write> {

View file

@ -1,10 +1,10 @@
use crate::cmp;
use crate::ffi::CStr;
use crate::io;
use crate::sys::cvt;
use crate::mem;
use crate::sys::{unsupported, Void};
use crate::time::Duration;
use libc;
use ::wasi::wasi_unstable as wasi;
pub struct Thread(Void);
@ -19,8 +19,8 @@ impl Thread {
}
pub fn yield_now() {
let ret = unsafe { libc::__wasi_sched_yield() };
debug_assert_eq!(ret, 0);
let ret = wasi::sched_yield();
debug_assert_eq!(ret, Ok(()));
}
pub fn set_name(_name: &CStr) {
@ -28,19 +28,37 @@ impl Thread {
}
pub fn sleep(dur: Duration) {
let mut secs = dur.as_secs();
let mut nsecs = dur.subsec_nanos() as i32;
let nanos = dur.as_nanos();
assert!(nanos <= u64::max_value() as u128);
unsafe {
while secs > 0 || nsecs > 0 {
let mut ts = libc::timespec {
tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
tv_nsec: nsecs,
};
secs -= ts.tv_sec as u64;
cvt(libc::nanosleep(&ts, &mut ts)).unwrap();
nsecs = 0;
}
const CLOCK_ID: wasi::Userdata = 0x0123_45678;
let clock = wasi::raw::__wasi_subscription_u_clock_t {
identifier: CLOCK_ID,
clock_id: wasi::CLOCK_MONOTONIC,
timeout: nanos as u64,
precision: 0,
flags: 0,
};
let in_ = [wasi::Subscription {
userdata: 0,
type_: wasi::EVENTTYPE_CLOCK,
u: wasi::raw::__wasi_subscription_u { clock: clock },
}];
let (res, event) = unsafe {
let mut out: [wasi::Event; 1] = mem::zeroed();
let res = wasi::poll_oneoff(&in_, &mut out);
(res, out[0])
};
match (res, event) {
(Ok(1), wasi::Event {
userdata: CLOCK_ID,
error: 0,
type_: wasi::EVENTTYPE_CLOCK,
..
}) => {}
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
}
}

View file

@ -1,7 +1,5 @@
use crate::time::Duration;
use crate::mem;
use crate::sys::cvt_wasi;
use libc;
use ::wasi::wasi_unstable as wasi;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(Duration);
@ -12,23 +10,19 @@ pub struct SystemTime(Duration);
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
fn current_time(clock: u32) -> Duration {
unsafe {
let mut ts = mem::zeroed();
cvt_wasi(libc::__wasi_clock_time_get(
clock,
1, // precision... seems ignored though?
&mut ts,
)).unwrap();
Duration::new(
(ts / 1_000_000_000) as u64,
(ts % 1_000_000_000) as u32,
)
}
let ts = wasi::clock_time_get(
clock,
1, // precision... seems ignored though?
).unwrap();
Duration::new(
(ts / 1_000_000_000) as u64,
(ts % 1_000_000_000) as u32,
)
}
impl Instant {
pub fn now() -> Instant {
Instant(current_time(libc::__WASI_CLOCK_MONOTONIC))
Instant(current_time(wasi::CLOCK_MONOTONIC))
}
pub const fn zero() -> Instant {
@ -54,10 +48,10 @@ impl Instant {
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime(current_time(libc::__WASI_CLOCK_REALTIME))
SystemTime(current_time(wasi::CLOCK_REALTIME))
}
pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime {
pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
SystemTime(Duration::from_nanos(ts))
}

View file

@ -4,14 +4,16 @@ use crate::io;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::{unsupported, Void};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::sys_common::process::CommandEnv;
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
env: CommandEnv<DefaultEnvKey>
env: CommandEnv,
}
// passed back to std::process with the pipes connected to the child, if any
@ -38,7 +40,7 @@ impl Command {
pub fn arg(&mut self, _arg: &OsStr) {
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}

View file

@ -19,7 +19,7 @@ use crate::sys::pipe::{self, AnonPipe};
use crate::sys::stdio;
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::sys_common::process::{CommandEnv, EnvKey};
use crate::sys_common::process::CommandEnv;
use crate::borrow::Borrow;
use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
@ -30,30 +30,28 @@ use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[doc(hidden)]
pub struct WindowsEnvKey(OsString);
pub struct EnvKey(OsString);
impl From<OsString> for WindowsEnvKey {
impl From<OsString> for EnvKey {
fn from(k: OsString) -> Self {
let mut buf = k.into_inner().into_inner();
buf.make_ascii_uppercase();
WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
EnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
}
}
impl From<WindowsEnvKey> for OsString {
fn from(k: WindowsEnvKey) -> Self { k.0 }
impl From<EnvKey> for OsString {
fn from(k: EnvKey) -> Self { k.0 }
}
impl Borrow<OsStr> for WindowsEnvKey {
impl Borrow<OsStr> for EnvKey {
fn borrow(&self) -> &OsStr { &self.0 }
}
impl AsRef<OsStr> for WindowsEnvKey {
impl AsRef<OsStr> for EnvKey {
fn as_ref(&self) -> &OsStr { &self.0 }
}
impl EnvKey for WindowsEnvKey {}
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
if str.as_ref().encode_wide().any(|b| b == 0) {
@ -66,7 +64,7 @@ fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
pub struct Command {
program: OsString,
args: Vec<OsString>,
env: CommandEnv<WindowsEnvKey>,
env: CommandEnv,
cwd: Option<OsString>,
flags: u32,
detach: bool, // not currently exposed in std::process
@ -110,7 +108,7 @@ impl Command {
pub fn arg(&mut self, arg: &OsStr) {
self.args.push(arg.to_os_string())
}
pub fn env_mut(&mut self) -> &mut CommandEnv<WindowsEnvKey> {
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}
pub fn cwd(&mut self, dir: &OsStr) {
@ -498,7 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
}
}
fn make_envp(maybe_env: Option<BTreeMap<WindowsEnvKey, OsString>>)
fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>)
-> io::Result<(*mut c_void, Vec<u16>)> {
// On Windows we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final

View file

@ -1,47 +1,20 @@
#![allow(dead_code)]
#![unstable(feature = "process_internals", issue = "0")]
use crate::ffi::{OsStr, OsString};
use crate::env;
use crate::collections::BTreeMap;
use crate::borrow::Borrow;
pub trait EnvKey:
From<OsString> + Into<OsString> +
Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
Ord + Clone {}
// Implement a case-sensitive environment variable key
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct DefaultEnvKey(OsString);
impl From<OsString> for DefaultEnvKey {
fn from(k: OsString) -> Self { DefaultEnvKey(k) }
}
impl From<DefaultEnvKey> for OsString {
fn from(k: DefaultEnvKey) -> Self { k.0 }
}
impl Borrow<OsStr> for DefaultEnvKey {
fn borrow(&self) -> &OsStr { &self.0 }
}
impl AsRef<OsStr> for DefaultEnvKey {
fn as_ref(&self) -> &OsStr { &self.0 }
}
impl EnvKey for DefaultEnvKey {}
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::sys::process::EnvKey;
// Stores a set of changes to an environment
#[derive(Clone, Debug)]
pub struct CommandEnv<K> {
pub struct CommandEnv {
clear: bool,
saw_path: bool,
vars: BTreeMap<K, Option<OsString>>
vars: BTreeMap<EnvKey, Option<OsString>>
}
impl<K: EnvKey> Default for CommandEnv<K> {
impl Default for CommandEnv {
fn default() -> Self {
CommandEnv {
clear: false,
@ -51,10 +24,10 @@ impl<K: EnvKey> Default for CommandEnv<K> {
}
}
impl<K: EnvKey> CommandEnv<K> {
impl CommandEnv {
// Capture the current environment with these changes applied
pub fn capture(&self) -> BTreeMap<K, OsString> {
let mut result = BTreeMap::<K, OsString>::new();
pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
let mut result = BTreeMap::<EnvKey, OsString>::new();
if !self.clear {
for (k, v) in env::vars_os() {
result.insert(k.into(), v);
@ -90,7 +63,7 @@ impl<K: EnvKey> CommandEnv<K> {
!self.clear && self.vars.is_empty()
}
pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> {
if self.is_unchanged() {
None
} else {
@ -103,6 +76,7 @@ impl<K: EnvKey> CommandEnv<K> {
self.maybe_saw_path(&key);
self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
}
pub fn remove(&mut self, key: &OsStr) {
self.maybe_saw_path(&key);
if self.clear {
@ -111,13 +85,16 @@ impl<K: EnvKey> CommandEnv<K> {
self.vars.insert(key.to_owned().into(), None);
}
}
pub fn clear(&mut self) {
self.clear = true;
self.vars.clear();
}
pub fn have_changed_path(&self) -> bool {
self.saw_path || self.clear
}
fn maybe_saw_path(&mut self, key: &OsStr) {
if !self.saw_path && key == "PATH" {
self.saw_path = true;

View file

@ -561,29 +561,31 @@ impl Pat {
}))
}
pub fn walk<F>(&self, it: &mut F) -> bool
where
F: FnMut(&Pat) -> bool,
{
/// Walk top-down and call `it` in each place where a pattern occurs
/// starting with the root pattern `walk` is called on. If `it` returns
/// false then we will descend no further but siblings will be processed.
pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
if !it(self) {
return false;
return;
}
match &self.node {
PatKind::Ident(_, _, Some(p)) => p.walk(it),
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
PatKind::TupleStruct(_, s)
| PatKind::Tuple(s)
| PatKind::Slice(s)
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
PatKind::Box(s)
| PatKind::Ref(s, _)
| PatKind::Paren(s) => s.walk(it),
PatKind::Wild
| PatKind::Rest
| PatKind::Lit(_)
| PatKind::Range(..)
| PatKind::Ident(..)
| PatKind::Path(..)
| PatKind::Mac(_) => true,
| PatKind::Mac(_) => {},
}
}
@ -928,7 +930,7 @@ pub struct Local {
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Arm {
pub attrs: Vec<Attribute>,
pub pats: Vec<P<Pat>>,
pub pat: P<Pat>,
pub guard: Option<P<Expr>>,
pub body: P<Expr>,
pub span: Span,
@ -1146,12 +1148,9 @@ pub enum ExprKind {
Cast(P<Expr>, P<Ty>),
/// A type ascription (e.g., `42: usize`).
Type(P<Expr>, P<Ty>),
/// A `let pats = expr` expression that is only semantically allowed in the condition
/// A `let pat = expr` expression that is only semantically allowed in the condition
/// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
///
/// The `Vec<P<Pat>>` is for or-patterns at the top level.
/// FIXME(54883): Change this to just `P<Pat>`.
Let(Vec<P<Pat>>, P<Expr>),
Let(P<Pat>, P<Expr>),
/// An `if` block, with an optional `else` block.
///
/// `if expr { block } else { expr }`

View file

@ -537,9 +537,9 @@ impl<'a> ExtCtxt<'a> {
let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
// `Ok(__try_var) => __try_var`
let ok_arm = self.arm(sp, vec![ok_pat], binding_expr);
let ok_arm = self.arm(sp, ok_pat, binding_expr);
// `Err(__try_var) => return Err(__try_var)`
let err_arm = self.arm(sp, vec![err_pat], err_expr);
let err_arm = self.arm(sp, err_pat, err_expr);
// `match head { Ok() => ..., Err() => ... }`
self.expr_match(sp, head, vec![ok_arm, err_arm])
@ -606,10 +606,10 @@ impl<'a> ExtCtxt<'a> {
self.pat_tuple_struct(span, path, vec![pat])
}
pub fn arm(&self, span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm {
ast::Arm {
attrs: vec![],
pats,
pat,
guard: None,
body: expr,
span,
@ -618,7 +618,7 @@ impl<'a> ExtCtxt<'a> {
}
pub fn arm_unreachable(&self, span: Span) -> ast::Arm {
self.arm(span, vec![self.pat_wild(span)], self.expr_unreachable(span))
self.arm(span, self.pat_wild(span), self.expr_unreachable(span))
}
pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {

View file

@ -402,14 +402,11 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
vis.visit_span(span);
}
pub fn noop_flat_map_arm<T: MutVisitor>(
mut arm: Arm,
vis: &mut T,
) -> SmallVec<[Arm; 1]> {
let Arm { attrs, pats, guard, body, span, id } = &mut arm;
pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
let Arm { attrs, pat, guard, body, span, id } = &mut arm;
visit_attrs(attrs, vis);
vis.visit_id(id);
visit_vec(pats, |pat| vis.visit_pat(pat));
vis.visit_pat(pat);
visit_opt(guard, |guard| vis.visit_expr(guard));
vis.visit_expr(body);
vis.visit_span(span);
@ -1132,8 +1129,8 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr,
vis.visit_ty(ty);
}
ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs),
ExprKind::Let(pats, scrutinee) => {
visit_vec(pats, |pat| vis.visit_pat(pat));
ExprKind::Let(pat, scrutinee) => {
vis.visit_pat(pat);
vis.visit_expr(scrutinee);
}
ExprKind::If(cond, tr, fl) => {

View file

@ -1250,8 +1250,7 @@ impl<'a> Parser<'a> {
/// The `let` token has already been eaten.
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let lo = self.prev_span;
// FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead.
let pat = self.parse_top_pat_unpack(GateOr::No)?;
let pat = self.parse_top_pat(GateOr::No)?;
self.expect(&token::Eq)?;
let expr = self.with_res(
Restrictions::NO_STRUCT_LITERAL,
@ -1393,8 +1392,7 @@ impl<'a> Parser<'a> {
crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
// FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead.
let pat = self.parse_top_pat_unpack(GateOr::No)?;
let pat = self.parse_top_pat(GateOr::No)?;
let guard = if self.eat_keyword(kw::If) {
Some(self.parse_expr()?)
} else {
@ -1455,7 +1453,7 @@ impl<'a> Parser<'a> {
Ok(ast::Arm {
attrs,
pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`.
pat,
guard,
body: expr,
span: lo.to(hi),

View file

@ -36,16 +36,6 @@ impl<'a> Parser<'a> {
self.parse_pat_with_range_pat(true, expected)
}
// FIXME(or_patterns, Centril | dlrobertson):
// remove this and use `parse_top_pat` everywhere it is used instead.
pub(super) fn parse_top_pat_unpack(&mut self, gate_or: GateOr) -> PResult<'a, Vec<P<Pat>>> {
self.parse_top_pat(gate_or)
.map(|pat| pat.and_then(|pat| match pat.node {
PatKind::Or(pats) => pats,
node => vec![self.mk_pat(pat.span, node)],
}))
}
/// Entry point to the main pattern parser.
/// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> {

View file

@ -1710,11 +1710,11 @@ impl<'a> State<'a> {
self.ann.post(self, AnnNode::Block(blk))
}
/// Print a `let pats = scrutinee` expression.
crate fn print_let(&mut self, pats: &[P<ast::Pat>], scrutinee: &ast::Expr) {
/// Print a `let pat = scrutinee` expression.
crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
self.s.word("let ");
self.print_pats(pats);
self.print_pat(pat);
self.s.space();
self.word_space("=");
@ -2040,8 +2040,8 @@ impl<'a> State<'a> {
self.word_space(":");
self.print_type(ty);
}
ast::ExprKind::Let(ref pats, ref scrutinee) => {
self.print_let(pats, scrutinee);
ast::ExprKind::Let(ref pat, ref scrutinee) => {
self.print_let(pat, scrutinee);
}
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e));
@ -2451,21 +2451,16 @@ impl<'a> State<'a> {
self.ann.post(self, AnnNode::Pat(pat))
}
fn print_pats(&mut self, pats: &[P<ast::Pat>]) {
self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
}
fn print_arm(&mut self, arm: &ast::Arm) {
// I have no idea why this check is necessary, but here it
// is :(
// I have no idea why this check is necessary, but here it is :(
if arm.attrs.is_empty() {
self.s.space();
}
self.cbox(INDENT_UNIT);
self.ibox(0);
self.maybe_print_comment(arm.pats[0].span.lo());
self.maybe_print_comment(arm.pat.span.lo());
self.print_outer_attributes(&arm.attrs);
self.print_pats(&arm.pats);
self.print_pat(&arm.pat);
self.s.space();
if let Some(ref e) = arm.guard {
self.word_space("if");

View file

@ -678,9 +678,8 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo
}
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
for attr in expression.attrs.iter() {
visitor.visit_attribute(attr);
}
walk_list!(visitor, visit_attribute, expression.attrs.iter());
match expression.node {
ExprKind::Box(ref subexpression) => {
visitor.visit_expr(subexpression)
@ -719,8 +718,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
ExprKind::Let(ref pats, ref scrutinee) => {
walk_list!(visitor, visit_pat, pats);
ExprKind::Let(ref pat, ref scrutinee) => {
visitor.visit_pat(pat);
visitor.visit_expr(scrutinee);
}
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
@ -831,10 +830,10 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
}
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
walk_list!(visitor, visit_pat, &arm.pats);
if let Some(ref e) = &arm.guard {
visitor.visit_expr(e);
}
visitor.visit_pat(&arm.pat);
// NOTE(or_patterns; Centril | dlrobertson):
// If you change this, also change the hack in `lowering.rs`.
walk_list!(visitor, visit_expr, &arm.guard);
visitor.visit_expr(&arm.body);
walk_list!(visitor, visit_attribute, &arm.attrs);
}

View file

@ -95,11 +95,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
cx.expr_call_global(span, cmp_path.clone(), args)
};
let eq_arm = cx.arm(span,
vec![cx.pat_path(span, equals_path.clone())],
old);
let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
cx.pat_ident(span, test_id),
cx.expr_ident(span, test_id));
cx.expr_match(span, new, vec![eq_arm, neq_arm])

View file

@ -160,10 +160,10 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
};
let eq_arm = cx.arm(span,
vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
cx.pat_some(span, cx.pat_path(span, ordering.clone())),
old);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
cx.pat_ident(span, test_id),
cx.expr_ident(span, test_id));
cx.expr_match(span, new, vec![eq_arm, neq_arm])

View file

@ -119,9 +119,7 @@ fn decodable_substructure(cx: &mut ExtCtxt<'_>,
vec![idx, exprdecode.clone()]))
});
arms.push(cx.arm(v_span,
vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))],
decoded));
arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded));
}
arms.push(cx.arm_unreachable(trait_span));

View file

@ -1071,7 +1071,7 @@ impl<'a> MethodDef<'a> {
for (arg_expr, pat) in self_args.iter().zip(patterns) {
body = cx.expr_match(trait_.span,
arg_expr.clone(),
vec![cx.arm(trait_.span, vec![pat.clone()], body)])
vec![cx.arm(trait_.span, pat.clone(), body)])
}
body
@ -1311,7 +1311,7 @@ impl<'a> MethodDef<'a> {
nonself_args,
&substructure);
cx.arm(sp, vec![single_pat], arm_expr)
cx.arm(sp, single_pat, arm_expr)
})
.collect();
@ -1337,7 +1337,7 @@ impl<'a> MethodDef<'a> {
_ => None,
};
if let Some(arm) = default {
match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm));
match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
}
// We will usually need the catch-all after matching the

View file

@ -716,7 +716,7 @@ impl<'a, 'b> Context<'a, 'b> {
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
let pat = self.ecx.pat_tuple(self.fmtsp, pats);
let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array);
let arm = self.ecx.arm(self.fmtsp, pat, args_array);
let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads));
let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]);

View file

@ -4,5 +4,6 @@ const EXPECTED = {
'others': [
{ 'path': 'std::vec::Vec', 'name': 'new' },
{ 'path': 'std::vec::Vec', 'name': 'ne' },
{ 'path': 'std::rc::Rc', 'name': 'ne' },
],
};

View file

@ -0,0 +1,9 @@
const QUERY = 'si::pc';
const EXPECTED = {
'others': [
{ 'path': 'exact_match::Si', 'name': 'pc' },
{ 'path': 'exact_match::Psi', 'name': 'pc' },
{ 'path': 'exact_match::Si', 'name': 'pa' },
],
};

View file

@ -0,0 +1,68 @@
macro_rules! imp {
($name:ident) => {
pub struct $name {
pub op: usize,
}
impl $name {
pub fn op() {}
pub fn cmp() {}
pub fn map() {}
pub fn pop() {}
pub fn ptr() {}
pub fn rpo() {}
pub fn drop() {}
pub fn copy() {}
pub fn zip() {}
pub fn sup() {}
pub fn pa() {}
pub fn pb() {}
pub fn pc() {}
pub fn pd() {}
pub fn pe() {}
pub fn pf() {}
pub fn pg() {}
pub fn ph() {}
pub fn pi() {}
pub fn pj() {}
pub fn pk() {}
pub fn pl() {}
pub fn pm() {}
pub fn pn() {}
pub fn po() {}
}
};
($name:ident, $($names:ident),*) => {
imp!($name);
imp!($($names),*);
};
}
macro_rules! en {
($name:ident) => {
pub enum $name {
Ptr,
Rp,
Rpo,
Pt,
Drop,
Dr,
Dro,
Sup,
Op,
Cmp,
Map,
Mp,
}
};
($name:ident, $($names:ident),*) => {
en!($name);
en!($($names),*);
};
}
imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd);
imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp);
imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp);
en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
pub struct P;

View file

@ -0,0 +1,9 @@
const QUERY = 'ig::pc';
const EXPECTED = {
'others': [
{ 'path': 'module_substring::Sig', 'name': 'pc' },
{ 'path': 'module_substring::Si', 'name': 'pc' },
{ 'path': 'module_substring::Si', 'name': 'pa' },
],
};

View file

@ -0,0 +1,68 @@
macro_rules! imp {
($name:ident) => {
pub struct $name {
pub op: usize,
}
impl $name {
pub fn op() {}
pub fn cmp() {}
pub fn map() {}
pub fn pop() {}
pub fn ptr() {}
pub fn rpo() {}
pub fn drop() {}
pub fn copy() {}
pub fn zip() {}
pub fn sup() {}
pub fn pa() {}
pub fn pb() {}
pub fn pc() {}
pub fn pd() {}
pub fn pe() {}
pub fn pf() {}
pub fn pg() {}
pub fn ph() {}
pub fn pi() {}
pub fn pj() {}
pub fn pk() {}
pub fn pl() {}
pub fn pm() {}
pub fn pn() {}
pub fn po() {}
}
};
($name:ident, $($names:ident),*) => {
imp!($name);
imp!($($names),*);
};
}
macro_rules! en {
($name:ident) => {
pub enum $name {
Ptr,
Rp,
Rpo,
Pt,
Drop,
Dr,
Dro,
Sup,
Op,
Cmp,
Map,
Mp,
}
};
($name:ident, $($names:ident),*) => {
en!($name);
en!($($names),*);
};
}
imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd);
imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp);
imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp);
en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
pub struct P;

View file

@ -3,6 +3,8 @@ const QUERY = 'P';
const EXPECTED = {
'others': [
{ 'path': 'search_short_types', 'name': 'P' },
{ 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' },
{ 'path': 'search_short_types', 'name': 'Ap' },
{ 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' },
],
};

View file

@ -66,3 +66,9 @@ imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp,
en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar);
pub struct P;
pub struct VeryLongTypeName;
impl VeryLongTypeName {
pub fn p() {}
pub fn ap() {}
}

View file

@ -150,12 +150,12 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
},
19 => {
let ps = vec![P(Pat {
let pat = P(Pat {
id: DUMMY_NODE_ID,
node: PatKind::Wild,
span: DUMMY_SP,
})];
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e)))
});
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e)))
},
_ => panic!("bad counter value in iter_exprs"),
}

View file

@ -1,18 +1,27 @@
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
--> $DIR/E0023.rs:10:9
|
LL | Apple(String, String),
| --------------------- tuple variant defined here
...
LL | Fruit::Apple(a) => {},
| ^^^^^^^^^^^^^^^ expected 2 fields, found 1
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/E0023.rs:11:9
|
LL | Apple(String, String),
| --------------------- tuple variant defined here
...
LL | Fruit::Apple(a, b, c) => {},
| ^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field
--> $DIR/E0023.rs:12:9
|
LL | Pear(u32),
| --------- tuple variant defined here
...
LL | Fruit::Pear(1, 2) => {},
| ^^^^^^^^^^^^^^^^^ expected 1 field, found 2

View file

@ -33,10 +33,8 @@ fn or_patterns_no_lint() {
if let &mut (0 | 1) = &mut 0 {} // Same.
fn foo((Ok(a) | Err(a)): Result<u8, u8>) {} // Doesn't parse if we remove parens for now.
//~^ ERROR identifier `a` is bound more than once
let _ = |(Ok(a) | Err(a)): Result<u8, u8>| 1; // `|Ok(a) | Err(a)| 1` parses as bit-or.
//~^ ERROR identifier `a` is bound more than once
}
fn or_patterns_will_lint() {

View file

@ -1,15 +1,3 @@
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/issue-54538-unused-parens-lint.rs:35:25
|
LL | fn foo((Ok(a) | Err(a)): Result<u8, u8>) {} // Doesn't parse if we remove parens for now.
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/issue-54538-unused-parens-lint.rs:38:27
|
LL | let _ = |(Ok(a) | Err(a)): Result<u8, u8>| 1; // `|Ok(a) | Err(a)| 1` parses as bit-or.
| ^ used in a pattern more than once
warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
--> $DIR/issue-54538-unused-parens-lint.rs:3:12
|
@ -61,113 +49,112 @@ LL | let _ = |(a): u8| 0;
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:43:12
--> $DIR/issue-54538-unused-parens-lint.rs:41:12
|
LL | if let (0 | 1) = 0 {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:44:13
--> $DIR/issue-54538-unused-parens-lint.rs:42:13
|
LL | if let ((0 | 1),) = (0,) {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:45:13
--> $DIR/issue-54538-unused-parens-lint.rs:43:13
|
LL | if let [(0 | 1)] = [0] {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:46:16
--> $DIR/issue-54538-unused-parens-lint.rs:44:16
|
LL | if let 0 | (1 | 2) = 0 {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:48:15
--> $DIR/issue-54538-unused-parens-lint.rs:46:15
|
LL | if let TS((0 | 1)) = TS(0) {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:50:20
--> $DIR/issue-54538-unused-parens-lint.rs:48:20
|
LL | if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:60:9
--> $DIR/issue-54538-unused-parens-lint.rs:58:9
|
LL | (_) => {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:61:9
--> $DIR/issue-54538-unused-parens-lint.rs:59:9
|
LL | (y) => {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:62:9
--> $DIR/issue-54538-unused-parens-lint.rs:60:9
|
LL | (ref r) => {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:63:9
--> $DIR/issue-54538-unused-parens-lint.rs:61:9
|
LL | (e @ 1...2) => {}
| ^^^^^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:69:9
--> $DIR/issue-54538-unused-parens-lint.rs:67:9
|
LL | (e @ &(1...2)) => {}
| ^^^^^^^^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:70:10
--> $DIR/issue-54538-unused-parens-lint.rs:68:10
|
LL | &(_) => {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:81:9
--> $DIR/issue-54538-unused-parens-lint.rs:79:9
|
LL | (_) => {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:82:9
--> $DIR/issue-54538-unused-parens-lint.rs:80:9
|
LL | (y) => {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:83:9
--> $DIR/issue-54538-unused-parens-lint.rs:81:9
|
LL | (ref r) => {}
| ^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:84:9
--> $DIR/issue-54538-unused-parens-lint.rs:82:9
|
LL | (e @ 1..=2) => {}
| ^^^^^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:90:9
--> $DIR/issue-54538-unused-parens-lint.rs:88:9
|
LL | (e @ &(1..=2)) => {}
| ^^^^^^^^^^^^^^ help: remove these parentheses
error: unnecessary parentheses around pattern
--> $DIR/issue-54538-unused-parens-lint.rs:91:10
--> $DIR/issue-54538-unused-parens-lint.rs:89:10
|
LL | &(_) => {}
| ^^^ help: remove these parentheses
error: aborting due to 26 previous errors
error: aborting due to 24 previous errors
For more information about this error, try `rustc --explain E0416`.

View file

@ -1,6 +1,9 @@
error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
--> $DIR/match-pattern-field-mismatch.rs:10:11
|
LL | Rgb(usize, usize, usize),
| ------------------------ tuple variant defined here
...
LL | Color::Rgb(_, _) => { }
| ^^^^^^^^^^^^^^^^ expected 3 fields, found 2

View file

@ -0,0 +1,46 @@
// This test ensures that the "already bound identifier in a product pattern"
// correctly accounts for or-patterns.
#![feature(or_patterns)]
//~^ WARN the feature `or_patterns` is incomplete
enum E<T> { A(T, T), B(T) }
use E::*;
fn main() {
let (a, a) = (0, 1); // Standard duplication without an or-pattern.
//~^ ERROR identifier `a` is bound more than once in the same pattern
let (a, A(a, _) | B(a)) = (0, A(1, 2));
//~^ ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR identifier `a` is bound more than once in the same pattern
let (A(a, _) | B(a), a) = (A(0, 1), 2);
//~^ ERROR identifier `a` is bound more than once in the same pattern
let A(a, a) | B(a) = A(0, 1);
//~^ ERROR identifier `a` is bound more than once in the same pattern
let B(a) | A(a, a) = A(0, 1);
//~^ ERROR identifier `a` is bound more than once in the same pattern
match A(0, 1) {
B(a) | A(a, a) => {} // Let's ensure `match` has no funny business.
//~^ ERROR identifier `a` is bound more than once in the same pattern
}
let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
//~^ ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR mismatched types
let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
//~^ ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR variable `a` is not bound in all patterns
let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
//~^ ERROR identifier `a` is bound more than once in the same pattern
//~| ERROR identifier `a` is bound more than once in the same pattern
}

View file

@ -0,0 +1,105 @@
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:12:13
|
LL | let (a, a) = (0, 1); // Standard duplication without an or-pattern.
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:15:15
|
LL | let (a, A(a, _) | B(a)) = (0, A(1, 2));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:15:25
|
LL | let (a, A(a, _) | B(a)) = (0, A(1, 2));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:19:26
|
LL | let (A(a, _) | B(a), a) = (A(0, 1), 2);
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:22:14
|
LL | let A(a, a) | B(a) = A(0, 1);
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:25:21
|
LL | let B(a) | A(a, a) = A(0, 1);
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:29:21
|
LL | B(a) | A(a, a) => {} // Let's ensure `match` has no funny business.
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:33:36
|
LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:33:46
|
LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:38:36
|
LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:38:46
|
LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/already-bound-name.rs:38:9
|
LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
| ^^^^ pattern doesn't bind `a` - variable not in all patterns
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:43:49
|
LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/already-bound-name.rs:43:59
|
LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1));
| ^ used in a pattern more than once
warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
--> $DIR/already-bound-name.rs:4:12
|
LL | #![feature(or_patterns)]
| ^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/already-bound-name.rs:33:31
|
LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
| ^ expected integer, found enum `E`
|
= note: expected type `{integer}`
found type `E<{integer}>`
error: aborting due to 15 previous errors
Some errors have detailed explanations: E0308, E0408, E0416.
For more information about an error, try `rustc --explain E0308`.

View file

@ -0,0 +1,46 @@
// Check that or-patterns with consistent bindings across arms are allowed.
// edition:2018
#![feature(or_patterns)]
//~^ WARN the feature `or_patterns` is incomplete
fn main() {
// One level:
let Ok(a) | Err(a) = Ok(0);
let Ok(ref a) | Err(ref a) = Ok(0);
let Ok(ref mut a) | Err(ref mut a) = Ok(0);
// Two levels:
enum Tri<S, T, U> { V1(S), V2(T), V3(U) }
use Tri::*;
let Ok((V1(a) | V2(a) | V3(a), b)) | Err(Ok((a, b)) | Err((a, b)))
: Result<_, Result<_, _>>
= Ok((V1(1), 1));
let Ok((V1(a) | V2(a) | V3(a), ref b)) | Err(Ok((a, ref b)) | Err((a, ref b)))
: Result<_, Result<_, _>>
= Ok((V1(1), 1));
// Three levels:
let (
a,
Err((ref mut b, ref c, d)) |
Ok((
Ok(
V1((ref c, d)) |
V2((d, ref c)) |
V3((ref c, Ok((_, d)) | Err((d, _))))
) |
Err((ref c, d)),
ref mut b
))
) =
(1, Ok((Ok(V3((1, Ok((1, 1))))), 1)));
// FIXME(or_patterns; Centril | dlrobertson): remove this line below and
// change this test to check-pass once MIR can handle or-patterns with bindings.
let () = 0;
//~^ ERROR mismatched types
}

View file

@ -0,0 +1,20 @@
warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
--> $DIR/consistent-bindings.rs:5:12
|
LL | #![feature(or_patterns)]
| ^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/consistent-bindings.rs:44:9
|
LL | let () = 0;
| ^^ expected integer, found ()
|
= note: expected type `{integer}`
found type `()`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,28 @@
// This test ensures that or patterns require binding mode consistency across arms.
#![feature(or_patterns)]
//~^ WARN the feature `or_patterns` is incomplete
#![allow(non_camel_case_types)]
fn main() {
// One level:
let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0);
//~^ ERROR variable `a` is bound in inconsistent ways
let Ok(ref mut a) | Err(a): Result<u8, &mut u8> = Ok(0);
//~^ ERROR variable `a` is bound in inconsistent ways
let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
//~^ ERROR variable `a` is bound in inconsistent ways
//~| ERROR mismatched types
let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
//~^ ERROR variable `a` is bound in inconsistent ways
//~| ERROR variable `b` is bound in inconsistent ways
//~| ERROR mismatched types
// Two levels:
let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0);
//~^ ERROR variable `a` is bound in inconsistent ways
// Three levels:
let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1);
//~^ ERROR variable `a` is bound in inconsistent ways
}

View file

@ -0,0 +1,80 @@
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:9:25
|
LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0);
| - ^ bound in different ways
| |
| first binding
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:11:29
|
LL | let Ok(ref mut a) | Err(a): Result<u8, &mut u8> = Ok(0);
| - ^ bound in different ways
| |
| first binding
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:13:33
|
LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
| - first binding ^ bound in different ways
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:16:39
|
LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
| - first binding ^ bound in different ways
error[E0409]: variable `b` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:16:46
|
LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
| - first binding ^ bound in different ways
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:22:38
|
LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0);
| - ^ bound in different ways
| |
| first binding
error[E0409]: variable `a` is bound in inconsistent ways within the same match arm
--> $DIR/inconsistent-modes.rs:26:34
|
LL | let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1);
| - ^ bound in different ways
| |
| first binding
warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
--> $DIR/inconsistent-modes.rs:3:12
|
LL | #![feature(or_patterns)]
| ^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/inconsistent-modes.rs:13:25
|
LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
| ^^^^^^^^^ types differ in mutability
|
= note: expected type `&&u8`
found type `&mut &mut u8`
error[E0308]: mismatched types
--> $DIR/inconsistent-modes.rs:16:31
|
LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
| ^^^^^^^^^ types differ in mutability
|
= note: expected type `&{integer}`
found type `&mut _`
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0308, E0409.
For more information about an error, try `rustc --explain E0308`.

View file

@ -0,0 +1,84 @@
// This test ensures that or patterns do not allow missing bindings in any of the arms.
// edition:2018
#![feature(or_patterns)]
//~^ WARN the feature `or_patterns` is incomplete
#![allow(non_camel_case_types)]
fn main() {}
fn check_handling_of_paths() {
mod bar {
pub enum foo {
alpha,
beta,
charlie
}
}
use bar::foo::{alpha, charlie};
let alpha | beta | charlie = alpha; //~ ERROR variable `beta` is not bound in all patterns
match Some(alpha) {
Some(alpha | beta) => {} //~ ERROR variable `beta` is not bound in all patterns
}
}
fn check_misc_nesting() {
enum E<T> { A(T, T), B(T) }
use E::*;
enum Vars3<S, T, U> { V1(S), V2(T), V3(U) }
use Vars3::*;
// One level:
const X: E<u8> = B(0);
let A(a, _) | _ = X; //~ ERROR variable `a` is not bound in all patterns
let _ | B(a) = X; //~ ERROR variable `a` is not bound in all patterns
let A(..) | B(a) = X; //~ ERROR variable `a` is not bound in all patterns
let A(a, _) | B(_) = X; //~ ERROR variable `a` is not bound in all patterns
let A(_, a) | B(_) = X; //~ ERROR variable `a` is not bound in all patterns
let A(a, b) | B(a) = X; //~ ERROR variable `b` is not bound in all patterns
// Two levels:
const Y: E<E<u8>> = B(B(0));
let A(A(..) | B(_), _) | B(a) = Y; //~ ERROR variable `a` is not bound in all patterns
let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y;
//~^ ERROR variable `a` is not bound in all patterns
let A(A(a, b) | B(c), d) | B(e) = Y;
//~^ ERROR variable `a` is not bound in all patterns
//~| ERROR variable `a` is not bound in all patterns
//~| ERROR variable `b` is not bound in all patterns
//~| ERROR variable `b` is not bound in all patterns
//~| ERROR variable `c` is not bound in all patterns
//~| ERROR variable `c` is not bound in all patterns
//~| ERROR variable `d` is not bound in all patterns
//~| ERROR variable `e` is not bound in all patterns
// Three levels:
let (
V1(
//~^ ERROR variable `b` is not bound in all patterns
//~| ERROR variable `c` is not bound in all patterns
A(
Ok(a) | Err(_), //~ ERROR variable `a` is not bound in all patterns
_
) |
B(Ok(a) | Err(a))
) |
V2(
A(
A(_, a) | //~ ERROR variable `b` is not bound in all patterns
B(b), //~ ERROR variable `a` is not bound in all patterns
_
) |
B(_)
//~^ ERROR variable `a` is not bound in all patterns
//~| ERROR variable `b` is not bound in all patterns
) |
V3(c),
//~^ ERROR variable `a` is not bound in all patterns
)
: (Vars3<E<Result<u8, u8>>, E<E<u8>>, u8>,)
= (V3(0),);
}

View file

@ -0,0 +1,250 @@
error[E0408]: variable `beta` is not bound in all patterns
--> $DIR/missing-bindings.rs:22:9
|
LL | let alpha | beta | charlie = alpha;
| ^^^^^ ---- ^^^^^^^ pattern doesn't bind `beta`
| | |
| | variable not in all patterns
| pattern doesn't bind `beta`
error[E0408]: variable `beta` is not bound in all patterns
--> $DIR/missing-bindings.rs:24:14
|
LL | Some(alpha | beta) => {}
| ^^^^^ ---- variable not in all patterns
| |
| pattern doesn't bind `beta`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:36:19
|
LL | let A(a, _) | _ = X;
| - ^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:37:9
|
LL | let _ | B(a) = X;
| ^ - variable not in all patterns
| |
| pattern doesn't bind `a`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:38:9
|
LL | let A(..) | B(a) = X;
| ^^^^^ - variable not in all patterns
| |
| pattern doesn't bind `a`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:39:19
|
LL | let A(a, _) | B(_) = X;
| - ^^^^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:40:19
|
LL | let A(_, a) | B(_) = X;
| - ^^^^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:41:19
|
LL | let A(a, b) | B(a) = X;
| - ^^^^ pattern doesn't bind `b`
| |
| variable not in all patterns
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:45:9
|
LL | let A(A(..) | B(_), _) | B(a) = Y;
| ^^^^^^^^^^^^^^^^^^ - variable not in all patterns
| |
| pattern doesn't bind `a`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:46:11
|
LL | let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y;
| ^^^^^ - variable not in all patterns
| |
| pattern doesn't bind `a`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:21
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:21
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `b`
| |
| variable not in all patterns
error[E0408]: variable `c` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:11
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| ^^^^^^^ - variable not in all patterns
| |
| pattern doesn't bind `c`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:32
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:32
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `b`
| |
| variable not in all patterns
error[E0408]: variable `c` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:32
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `c`
| |
| variable not in all patterns
error[E0408]: variable `d` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:32
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| - ^^^^ pattern doesn't bind `d`
| |
| variable not in all patterns
error[E0408]: variable `e` is not bound in all patterns
--> $DIR/missing-bindings.rs:48:9
|
LL | let A(A(a, b) | B(c), d) | B(e) = Y;
| ^^^^^^^^^^^^^^^^^^^^ - variable not in all patterns
| |
| pattern doesn't bind `e`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:64:29
|
LL | Ok(a) | Err(_),
| - ^^^^^^ pattern doesn't bind `a`
| |
| variable not in all patterns
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:72:21
|
LL | A(_, a) |
| - variable not in all patterns
LL | B(b),
| ^^^^ pattern doesn't bind `a`
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:71:21
|
LL | A(_, a) |
| ^^^^^^^ pattern doesn't bind `b`
LL | B(b),
| - variable not in all patterns
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:75:17
|
LL | A(_, a) |
| - variable not in all patterns
...
LL | B(_)
| ^^^^ pattern doesn't bind `a`
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:75:17
|
LL | B(b),
| - variable not in all patterns
...
LL | B(_)
| ^^^^ pattern doesn't bind `b`
error[E0408]: variable `a` is not bound in all patterns
--> $DIR/missing-bindings.rs:79:13
|
LL | B(Ok(a) | Err(a))
| - variable not in all patterns
...
LL | A(_, a) |
| - variable not in all patterns
...
LL | V3(c),
| ^^^^^ pattern doesn't bind `a`
error[E0408]: variable `b` is not bound in all patterns
--> $DIR/missing-bindings.rs:60:13
|
LL | / V1(
LL | |
LL | |
LL | | A(
... |
LL | | B(Ok(a) | Err(a))
LL | | ) |
| |_____________^ pattern doesn't bind `b`
...
LL | B(b),
| - variable not in all patterns
...
LL | V3(c),
| ^^^^^ pattern doesn't bind `b`
error[E0408]: variable `c` is not bound in all patterns
--> $DIR/missing-bindings.rs:60:13
|
LL | / V1(
LL | |
LL | |
LL | | A(
... |
LL | | B(Ok(a) | Err(a))
LL | | ) |
| |_____________^ pattern doesn't bind `c`
LL | / V2(
LL | | A(
LL | | A(_, a) |
LL | | B(b),
... |
LL | |
LL | | ) |
| |_____________^ pattern doesn't bind `c`
LL | V3(c),
| - variable not in all patterns
warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
--> $DIR/missing-bindings.rs:5:12
|
LL | #![feature(or_patterns)]
| ^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error: aborting due to 26 previous errors
For more information about this error, try `rustc --explain E0408`.

View file

@ -19,12 +19,18 @@ LL | (1, 2, .., 3, 4) => {}
error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
--> $DIR/pat-tuple-overfield.rs:10:9
|
LL | struct S(u8, u8, u8);
| --------------------- tuple struct defined here
...
LL | S(1, 2, 3, 4) => {}
| ^^^^^^^^^^^^^ expected 3 fields, found 4
error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
--> $DIR/pat-tuple-overfield.rs:12:9
|
LL | struct S(u8, u8, u8);
| --------------------- tuple struct defined here
...
LL | S(1, 2, .., 3, 4) => {}
| ^^^^^^^^^^^^^^^^^ expected 3 fields, found 4

View file

@ -15,6 +15,9 @@ LL | A::D(_) => (),
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/pattern-error-continue.rs:17:9
|
LL | B(isize, isize),
| --------------- tuple variant defined here
...
LL | A::B(_, _, _) => (),
| ^^^^^^^^^^^^^ expected 2 fields, found 3

View file

@ -1,8 +1,8 @@
error[E0416]: identifier `a` is bound more than once in the same pattern
error[E0415]: identifier `a` is bound more than once in this parameter list
--> $DIR/shadowing-in-the-same-pattern.rs:3:10
|
LL | fn f((a, a): (isize, isize)) {}
| ^ used in a pattern more than once
| ^ used as parameter more than once
error[E0416]: identifier `a` is bound more than once in the same pattern
--> $DIR/shadowing-in-the-same-pattern.rs:6:13
@ -12,4 +12,5 @@ LL | let (a, a) = (1, 1);
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0416`.
Some errors have detailed explanations: E0415, E0416.
For more information about an error, try `rustc --explain E0415`.

View file

@ -15,6 +15,7 @@ const LICENSES: &[&str] = &[
"Apache-2.0 / MIT",
"MIT OR Apache-2.0",
"Apache-2.0 OR MIT",
"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
"MIT",
"Unlicense/MIT",
"Unlicense OR MIT",
@ -172,6 +173,7 @@ const WHITELIST: &[Crate<'_>] = &[
Crate("vcpkg"),
Crate("version_check"),
Crate("void"),
Crate("wasi"),
Crate("winapi"),
Crate("winapi-build"),
Crate("winapi-i686-pc-windows-gnu"),