mirror of
https://github.com/rust-lang/rust
synced 2024-10-06 08:40:35 +00:00
Auto merge of #63124 - Centril:rollup-onohtqt, r=Centril
Rollup of 12 pull requests Successful merges: - #61965 (Remove mentions of removed `offset_to` method from `align_offset` docs) - #62928 (Syntax: Recover on `for ( $pat in $expr ) $block`) - #63000 (Impl Debug for Chars) - #63083 (Make generic parameters always use modern hygiene) - #63087 (Add very simple edition check to tidy.) - #63093 (Properly check the defining scope of existential types) - #63096 (Add tests for some `existential_type` ICEs) - #63099 (vxworks: Remove Linux-specific comments.) - #63106 (ci: Skip installing SWIG/xz on OSX ) - #63108 (Add links to None in Option doc) - #63109 (std: Fix a failing `fs` test on Windows) - #63111 (Add syntactic and semantic tests for rest patterns, i.e. `..`) Failed merges: r? @ghost
This commit is contained in:
commit
4eeaaa722d
|
@ -62,17 +62,6 @@ steps:
|
|||
- template: install-sccache.yml
|
||||
- template: install-clang.yml
|
||||
|
||||
# Install some dependencies needed to build LLDB/Clang, currently only needed
|
||||
# during the `dist` target
|
||||
- bash: |
|
||||
set -e
|
||||
brew update
|
||||
brew install xz
|
||||
brew install swig@3
|
||||
brew link --force swig@3
|
||||
displayName: Install build dependencies (OSX)
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'), eq(variables['SCRIPT'],'./x.py dist'))
|
||||
|
||||
# Switch to XCode 9.3 on OSX since it seems to be the last version that supports
|
||||
# i686-apple-darwin. We'll eventually want to upgrade this and it will probably
|
||||
# force us to drop i686-apple-darwin, but let's keep the wheels turning for now.
|
||||
|
|
|
@ -1108,6 +1108,16 @@ fn test_iterator_last() {
|
|||
assert_eq!(it.last(), Some('m'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chars_debug() {
|
||||
let s = "ศไทย中华Việt Nam";
|
||||
let c = s.chars();
|
||||
assert_eq!(
|
||||
format!("{:?}", c),
|
||||
r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytesator() {
|
||||
let s = "ศไทย中华Việt Nam";
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//! * Initial values
|
||||
//! * Return values for functions that are not defined
|
||||
//! over their entire input range (partial functions)
|
||||
//! * Return value for otherwise reporting simple errors, where `None` is
|
||||
//! * Return value for otherwise reporting simple errors, where [`None`] is
|
||||
//! returned on error
|
||||
//! * Optional struct fields
|
||||
//! * Struct fields that can be loaned or "taken"
|
||||
|
@ -752,7 +752,7 @@ pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`.
|
||||
/// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`].
|
||||
///
|
||||
/// [`Some`]: #variant.Some
|
||||
/// [`None`]: #variant.None
|
||||
|
|
|
@ -1609,7 +1609,7 @@ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
|||
/// `usize::max_value()`.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
/// used with the `offset` or `offset_to` methods.
|
||||
/// used with the `add` method.
|
||||
///
|
||||
/// There are no guarantees whatsover that offsetting the pointer will not overflow or go
|
||||
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
|
||||
|
@ -2410,7 +2410,7 @@ pub unsafe fn swap(self, with: *mut T)
|
|||
/// `usize::max_value()`.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
/// used with the `offset` or `offset_to` methods.
|
||||
/// used with the `add` method.
|
||||
///
|
||||
/// There are no guarantees whatsover that offsetting the pointer will not overflow or go
|
||||
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
|
||||
|
|
|
@ -464,7 +464,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||
///
|
||||
/// [`chars`]: ../../std/primitive.str.html#method.chars
|
||||
/// [`str`]: ../../std/primitive.str.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Chars<'a> {
|
||||
iter: slice::Iter<'a, u8>
|
||||
|
@ -600,6 +600,16 @@ fn last(mut self) -> Option<char> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "chars_debug_impl", since = "1.38.0")]
|
||||
impl fmt::Debug for Chars<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Chars(")?;
|
||||
f.debug_list().entries(self.clone()).finish()?;
|
||||
write!(f, ")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> DoubleEndedIterator for Chars<'a> {
|
||||
#[inline]
|
||||
|
|
|
@ -1189,11 +1189,7 @@ pub fn may_define_existential_type(
|
|||
opaque_hir_id: hir::HirId,
|
||||
) -> bool {
|
||||
let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
trace!(
|
||||
"may_define_existential_type(def={:?}, opaque_node={:?})",
|
||||
tcx.hir().get(hir_id),
|
||||
tcx.hir().get(opaque_hir_id)
|
||||
);
|
||||
|
||||
|
||||
// Named existential types can be defined by any siblings or children of siblings.
|
||||
let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope");
|
||||
|
@ -1202,5 +1198,12 @@ pub fn may_define_existential_type(
|
|||
hir_id = tcx.hir().get_parent_item(hir_id);
|
||||
}
|
||||
// Syntactically, we are allowed to define the concrete type if:
|
||||
hir_id == scope
|
||||
let res = hir_id == scope;
|
||||
trace!(
|
||||
"may_define_existential_type(def={:?}, opaque_node={:?}) = {}",
|
||||
tcx.hir().get(hir_id),
|
||||
tcx.hir().get(opaque_hir_id),
|
||||
res
|
||||
);
|
||||
res
|
||||
}
|
||||
|
|
|
@ -2568,7 +2568,7 @@ fn check_lifetime_params(
|
|||
let lifetimes: Vec<_> = params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => Some((param, param.name)),
|
||||
GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -869,8 +869,7 @@ fn visit_fn(&mut self,
|
|||
debug!("(resolving function) entering function");
|
||||
let rib_kind = match function_kind {
|
||||
FnKind::ItemFn(..) => FnItemRibKind,
|
||||
FnKind::Method(..) => AssocItemRibKind,
|
||||
FnKind::Closure(_) => NormalRibKind,
|
||||
FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
|
||||
};
|
||||
|
||||
// Create a value rib for the function.
|
||||
|
@ -2307,21 +2306,32 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
|||
if ident.name == kw::Invalid {
|
||||
return Some(LexicalScopeBinding::Res(Res::Err));
|
||||
}
|
||||
ident.span = if ident.name == kw::SelfUpper {
|
||||
let (general_span, modern_span) = if ident.name == kw::SelfUpper {
|
||||
// FIXME(jseyfried) improve `Self` hygiene
|
||||
ident.span.with_ctxt(SyntaxContext::empty())
|
||||
let empty_span = ident.span.with_ctxt(SyntaxContext::empty());
|
||||
(empty_span, empty_span)
|
||||
} else if ns == TypeNS {
|
||||
ident.span.modern()
|
||||
let modern_span = ident.span.modern();
|
||||
(modern_span, modern_span)
|
||||
} else {
|
||||
ident.span.modern_and_legacy()
|
||||
(ident.span.modern_and_legacy(), ident.span.modern())
|
||||
};
|
||||
ident.span = general_span;
|
||||
let modern_ident = Ident { span: modern_span, ..ident };
|
||||
|
||||
// Walk backwards up the ribs in scope.
|
||||
let record_used = record_used_id.is_some();
|
||||
let mut module = self.graph_root;
|
||||
for i in (0 .. self.ribs[ns].len()).rev() {
|
||||
debug!("walk rib\n{:?}", self.ribs[ns][i].bindings);
|
||||
if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() {
|
||||
// Use the rib kind to determine whether we are resolving parameters
|
||||
// (modern hygiene) or local variables (legacy hygiene).
|
||||
let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind {
|
||||
modern_ident
|
||||
} else {
|
||||
ident
|
||||
};
|
||||
if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() {
|
||||
// The ident resolves to a type parameter or local variable.
|
||||
return Some(LexicalScopeBinding::Res(
|
||||
self.validate_res_from_ribs(ns, i, res, record_used, path_span),
|
||||
|
@ -2357,7 +2367,7 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
|||
}
|
||||
}
|
||||
|
||||
ident.span = ident.span.modern();
|
||||
ident = modern_ident;
|
||||
let mut poisoned = None;
|
||||
loop {
|
||||
let opt_module = if let Some(node_id) = record_used_id {
|
||||
|
|
|
@ -1664,6 +1664,7 @@ fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'thi
|
|||
intravisit::NestedVisitorMap::All(&self.tcx.hir())
|
||||
}
|
||||
fn visit_item(&mut self, it: &'tcx Item) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
let def_id = self.tcx.hir().local_def_id(it.hir_id);
|
||||
// The existential type itself or its children are not within its reveal scope.
|
||||
if def_id != self.def_id {
|
||||
|
@ -1672,6 +1673,7 @@ fn visit_item(&mut self, it: &'tcx Item) {
|
|||
}
|
||||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx ImplItem) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
let def_id = self.tcx.hir().local_def_id(it.hir_id);
|
||||
// The existential type itself or its children are not within its reveal scope.
|
||||
if def_id != self.def_id {
|
||||
|
@ -1680,6 +1682,7 @@ fn visit_impl_item(&mut self, it: &'tcx ImplItem) {
|
|||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx TraitItem) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
let def_id = self.tcx.hir().local_def_id(it.hir_id);
|
||||
self.check(def_id);
|
||||
intravisit::walk_trait_item(self, it);
|
||||
|
@ -1703,9 +1706,23 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem) {
|
|||
} else {
|
||||
debug!("find_existential_constraints: scope={:?}", tcx.hir().get(scope));
|
||||
match tcx.hir().get(scope) {
|
||||
Node::Item(ref it) => intravisit::walk_item(&mut locator, it),
|
||||
Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
|
||||
Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
|
||||
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
|
||||
// This allows our visitor to process the defining item itself, causing
|
||||
// it to pick up any 'sibling' defining uses.
|
||||
//
|
||||
// For example, this code:
|
||||
// ```
|
||||
// fn foo() {
|
||||
// existential type Blah: Debug;
|
||||
// let my_closure = || -> Blah { true };
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// requires us to explicitly process `foo()` in order
|
||||
// to notice the defining usage of `Blah`.
|
||||
Node::Item(ref it) => locator.visit_item(it),
|
||||
Node::ImplItem(ref it) => locator.visit_impl_item(it),
|
||||
Node::TraitItem(ref it) => locator.visit_trait_item(it),
|
||||
other => bug!(
|
||||
"{:?} is not a valid scope for an existential type item",
|
||||
other
|
||||
|
|
|
@ -3316,11 +3316,11 @@ fn realpath_works_tricky() {
|
|||
fs::create_dir_all(&d).unwrap();
|
||||
File::create(&f).unwrap();
|
||||
if cfg!(not(windows)) {
|
||||
symlink_dir("../d/e", &c).unwrap();
|
||||
symlink_file("../d/e", &c).unwrap();
|
||||
symlink_file("../f", &e).unwrap();
|
||||
}
|
||||
if cfg!(windows) {
|
||||
symlink_dir(r"..\d\e", &c).unwrap();
|
||||
symlink_file(r"..\d\e", &c).unwrap();
|
||||
symlink_file(r"..\f", &e).unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -287,22 +287,7 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
|||
let fd = cvt_r(|| unsafe {
|
||||
open(path.as_ptr(), flags, opts.mode as c_int)
|
||||
})?;
|
||||
let fd = FileDesc::new(fd);
|
||||
// Currently the standard library supports Linux 2.6.18 which did not
|
||||
// have the O_CLOEXEC flag (passed above). If we're running on an older
|
||||
// Linux kernel then the flag is just ignored by the OS. After we open
|
||||
// the first file, we check whether it has CLOEXEC set. If it doesn't,
|
||||
// we will explicitly ask for a CLOEXEC fd for every further file we
|
||||
// open, if it does, we will skip that step.
|
||||
//
|
||||
// The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
|
||||
// that we support, so we only do this on Linux currently.
|
||||
fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
ensure_cloexec(&fd)?;
|
||||
Ok(File(fd))
|
||||
Ok(File(FileDesc::new(fd)))
|
||||
}
|
||||
|
||||
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||
|
|
|
@ -141,10 +141,6 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
|
|||
|
||||
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
|
||||
-> io::Result<Socket> {
|
||||
// Unfortunately the only known way right now to accept a socket and
|
||||
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
|
||||
// Linux. This was added in 2.6.28, however, and because we support
|
||||
// 2.6.18 we must detect this support dynamically.
|
||||
let fd = cvt_r(|| unsafe {
|
||||
libc::accept(self.0.raw(), storage, len)
|
||||
})?;
|
||||
|
|
|
@ -11,11 +11,6 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
|
|||
static INVALID: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
let mut fds = [0; 2];
|
||||
|
||||
// Unfortunately the only known way right now to create atomically set the
|
||||
// CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
|
||||
// 2.6.27, however, and because we support 2.6.18 we must detect this
|
||||
// support dynamically.
|
||||
cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
|
||||
|
||||
let fd0 = FileDesc::new(fds[0]);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
use crate::util::parser::AssocOp;
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
|
||||
use log::{debug, trace};
|
||||
use std::mem;
|
||||
|
||||
|
@ -199,6 +199,10 @@ pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
|||
&self.sess.span_diagnostic
|
||||
}
|
||||
|
||||
crate fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
|
||||
self.sess.source_map().span_to_snippet(span)
|
||||
}
|
||||
|
||||
crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
|
||||
let mut err = self.struct_span_err(
|
||||
self.token.span,
|
||||
|
@ -549,8 +553,10 @@ pub fn maybe_annotate_with_ascription(
|
|||
ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
|
||||
// respan to include both operators
|
||||
let op_span = op.span.to(self.token.span);
|
||||
let mut err = self.diagnostic().struct_span_err(op_span,
|
||||
"chained comparison operators require parentheses");
|
||||
let mut err = self.struct_span_err(
|
||||
op_span,
|
||||
"chained comparison operators require parentheses",
|
||||
);
|
||||
if op.node == BinOpKind::Lt &&
|
||||
*outer_op == AssocOp::Less || // Include `<` to provide this recommendation
|
||||
*outer_op == AssocOp::Greater // even in a case like the following:
|
||||
|
@ -717,8 +723,6 @@ pub fn maybe_annotate_with_ascription(
|
|||
path.span = ty_span.to(self.prev_span);
|
||||
|
||||
let ty_str = self
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(ty_span)
|
||||
.unwrap_or_else(|_| pprust::ty_to_string(&ty));
|
||||
self.diagnostic()
|
||||
|
@ -889,7 +893,7 @@ pub fn unexpected_try_recover(
|
|||
err.span_label(await_sp, "while parsing this incorrect await expression");
|
||||
err
|
||||
})?;
|
||||
let expr_str = self.sess.source_map().span_to_snippet(expr.span)
|
||||
let expr_str = self.span_to_snippet(expr.span)
|
||||
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
|
||||
let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
|
||||
let sp = lo.to(expr.span);
|
||||
|
@ -923,6 +927,48 @@ pub fn unexpected_try_recover(
|
|||
}
|
||||
}
|
||||
|
||||
/// Recover a situation like `for ( $pat in $expr )`
|
||||
/// and suggest writing `for $pat in $expr` instead.
|
||||
///
|
||||
/// This should be called before parsing the `$block`.
|
||||
crate fn recover_parens_around_for_head(
|
||||
&mut self,
|
||||
pat: P<Pat>,
|
||||
expr: &Expr,
|
||||
begin_paren: Option<Span>,
|
||||
) -> P<Pat> {
|
||||
match (&self.token.kind, begin_paren) {
|
||||
(token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
|
||||
self.bump();
|
||||
|
||||
let pat_str = self
|
||||
// Remove the `(` from the span of the pattern:
|
||||
.span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap())
|
||||
.unwrap_or_else(|_| pprust::pat_to_string(&pat));
|
||||
|
||||
self.struct_span_err(self.prev_span, "unexpected closing `)`")
|
||||
.span_label(begin_par_sp, "opening `(`")
|
||||
.span_suggestion(
|
||||
begin_par_sp.to(self.prev_span),
|
||||
"remove parenthesis in `for` loop",
|
||||
format!("{} in {}", pat_str, pprust::expr_to_string(&expr)),
|
||||
// With e.g. `for (x) in y)` this would replace `(x) in y)`
|
||||
// with `x) in y)` which is syntactically invalid.
|
||||
// However, this is prevented before we get here.
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
|
||||
pat.and_then(|pat| match pat.node {
|
||||
PatKind::Paren(pat) => pat,
|
||||
_ => P(pat),
|
||||
})
|
||||
}
|
||||
_ => pat,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
|
||||
self.token.is_ident() &&
|
||||
if let ast::ExprKind::Path(..) = node { true } else { false } &&
|
||||
|
@ -1105,17 +1151,14 @@ pub fn unexpected_try_recover(
|
|||
crate fn check_for_for_in_in_typo(&mut self, in_span: Span) {
|
||||
if self.eat_keyword(kw::In) {
|
||||
// a common typo: `for _ in in bar {}`
|
||||
let mut err = self.sess.span_diagnostic.struct_span_err(
|
||||
self.prev_span,
|
||||
"expected iterable, found keyword `in`",
|
||||
);
|
||||
err.span_suggestion_short(
|
||||
in_span.until(self.prev_span),
|
||||
"remove the duplicated `in`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`")
|
||||
.span_suggestion_short(
|
||||
in_span.until(self.prev_span),
|
||||
"remove the duplicated `in`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1128,12 +1171,12 @@ pub fn unexpected_try_recover(
|
|||
|
||||
crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) {
|
||||
if let token::DocComment(_) = self.token.kind {
|
||||
let mut err = self.diagnostic().struct_span_err(
|
||||
self.struct_span_err(
|
||||
self.token.span,
|
||||
"documentation comments cannot be applied to a function parameter's type",
|
||||
);
|
||||
err.span_label(self.token.span, "doc comments are not allowed here");
|
||||
err.emit();
|
||||
)
|
||||
.span_label(self.token.span, "doc comments are not allowed here")
|
||||
.emit();
|
||||
self.bump();
|
||||
} else if self.token == token::Pound && self.look_ahead(1, |t| {
|
||||
*t == token::OpenDelim(token::Bracket)
|
||||
|
@ -1145,12 +1188,12 @@ pub fn unexpected_try_recover(
|
|||
}
|
||||
let sp = lo.to(self.token.span);
|
||||
self.bump();
|
||||
let mut err = self.diagnostic().struct_span_err(
|
||||
self.struct_span_err(
|
||||
sp,
|
||||
"attributes cannot be applied to a function parameter's type",
|
||||
);
|
||||
err.span_label(sp, "attributes are not allowed here");
|
||||
err.emit();
|
||||
)
|
||||
.span_label(sp, "attributes are not allowed here")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,18 +1249,19 @@ pub fn unexpected_try_recover(
|
|||
self.expect(&token::Colon)?;
|
||||
let ty = self.parse_ty()?;
|
||||
|
||||
let mut err = self.diagnostic().struct_span_err_with_code(
|
||||
pat.span,
|
||||
"patterns aren't allowed in methods without bodies",
|
||||
DiagnosticId::Error("E0642".into()),
|
||||
);
|
||||
err.span_suggestion_short(
|
||||
pat.span,
|
||||
"give this argument a name or use an underscore to ignore it",
|
||||
"_".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
self.diagnostic()
|
||||
.struct_span_err_with_code(
|
||||
pat.span,
|
||||
"patterns aren't allowed in methods without bodies",
|
||||
DiagnosticId::Error("E0642".into()),
|
||||
)
|
||||
.span_suggestion_short(
|
||||
pat.span,
|
||||
"give this argument a name or use an underscore to ignore it",
|
||||
"_".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
|
||||
let pat = P(Pat {
|
||||
|
|
|
@ -2329,19 +2329,19 @@ fn maybe_parse_struct_expr(
|
|||
// This is a struct literal, but we don't can't accept them here
|
||||
let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone());
|
||||
if let (Ok(expr), false) = (&expr, struct_allowed) {
|
||||
let mut err = self.diagnostic().struct_span_err(
|
||||
self.struct_span_err(
|
||||
expr.span,
|
||||
"struct literals are not allowed here",
|
||||
);
|
||||
err.multipart_suggestion(
|
||||
)
|
||||
.multipart_suggestion(
|
||||
"surround the struct literal with parentheses",
|
||||
vec![
|
||||
(lo.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
return Some(expr);
|
||||
}
|
||||
|
@ -2370,18 +2370,18 @@ fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Att
|
|||
}
|
||||
}
|
||||
if self.token == token::Comma {
|
||||
let mut err = self.sess.span_diagnostic.mut_span_err(
|
||||
self.struct_span_err(
|
||||
exp_span.to(self.prev_span),
|
||||
"cannot use a comma after the base struct",
|
||||
);
|
||||
err.span_suggestion_short(
|
||||
)
|
||||
.span_suggestion_short(
|
||||
self.token.span,
|
||||
"remove this comma",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.note("the base struct must always be the last field");
|
||||
err.emit();
|
||||
)
|
||||
.note("the base struct must always be the last field")
|
||||
.emit();
|
||||
self.recover_stmt();
|
||||
}
|
||||
break;
|
||||
|
@ -2736,15 +2736,14 @@ fn parse_prefix_expr(&mut self,
|
|||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
let span_of_tilde = lo;
|
||||
let mut err = self.diagnostic()
|
||||
.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator");
|
||||
err.span_suggestion_short(
|
||||
span_of_tilde,
|
||||
"use `!` to perform bitwise negation",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator")
|
||||
.span_suggestion_short(
|
||||
span_of_tilde,
|
||||
"use `!` to perform bitwise negation",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
(lo.to(span), self.mk_unary(UnOp::Not, e))
|
||||
}
|
||||
token::BinOp(token::Minus) => {
|
||||
|
@ -2792,21 +2791,20 @@ fn parse_prefix_expr(&mut self,
|
|||
if cannot_continue_expr {
|
||||
self.bump();
|
||||
// Emit the error ...
|
||||
let mut err = self.diagnostic()
|
||||
.struct_span_err(self.token.span,
|
||||
&format!("unexpected {} after identifier",
|
||||
self.this_token_descr()));
|
||||
// span the `not` plus trailing whitespace to avoid
|
||||
// trailing whitespace after the `!` in our suggestion
|
||||
let to_replace = self.sess.source_map()
|
||||
.span_until_non_whitespace(lo.to(self.token.span));
|
||||
err.span_suggestion_short(
|
||||
to_replace,
|
||||
self.struct_span_err(
|
||||
self.token.span,
|
||||
&format!("unexpected {} after identifier",self.this_token_descr())
|
||||
)
|
||||
.span_suggestion_short(
|
||||
// Span the `not` plus trailing whitespace to avoid
|
||||
// trailing whitespace after the `!` in our suggestion
|
||||
self.sess.source_map()
|
||||
.span_until_non_whitespace(lo.to(self.token.span)),
|
||||
"use `!` to perform logical negation",
|
||||
"!".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
// —and recover! (just as if we were in the block
|
||||
// for the `token::Not` arm)
|
||||
let e = self.parse_prefix_expr(None);
|
||||
|
@ -2884,7 +2882,7 @@ fn parse_assoc_expr_with(
|
|||
// We've found an expression that would be parsed as a statement, but the next
|
||||
// token implies this should be parsed as an expression.
|
||||
// For example: `if let Some(x) = x { x } else { 0 } / 2`
|
||||
let mut err = self.sess.span_diagnostic.struct_span_err(self.token.span, &format!(
|
||||
let mut err = self.struct_span_err(self.token.span, &format!(
|
||||
"expected expression, found `{}`",
|
||||
pprust::token_to_string(&self.token),
|
||||
));
|
||||
|
@ -3072,28 +3070,29 @@ fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
|
|||
// in AST and continue parsing.
|
||||
let msg = format!("`<` is interpreted as a start of generic \
|
||||
arguments for `{}`, not a {}", path, op_noun);
|
||||
let mut err =
|
||||
self.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
|
||||
let span_after_type = parser_snapshot_after_type.token.span;
|
||||
err.span_label(self.look_ahead(1, |t| t.span).to(span_after_type),
|
||||
"interpreted as generic arguments");
|
||||
err.span_label(self.token.span, format!("not interpreted as {}", op_noun));
|
||||
|
||||
let expr = mk_expr(self, P(Ty {
|
||||
span: path.span,
|
||||
node: TyKind::Path(None, path),
|
||||
id: ast::DUMMY_NODE_ID
|
||||
}));
|
||||
|
||||
let expr_str = self.sess.source_map().span_to_snippet(expr.span)
|
||||
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
&format!("try {} the cast value", op_verb),
|
||||
format!("({})", expr_str),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
let expr_str = self.span_to_snippet(expr.span)
|
||||
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
|
||||
|
||||
self.struct_span_err(self.token.span, &msg)
|
||||
.span_label(
|
||||
self.look_ahead(1, |t| t.span).to(span_after_type),
|
||||
"interpreted as generic arguments"
|
||||
)
|
||||
.span_label(self.token.span, format!("not interpreted as {}", op_noun))
|
||||
.span_suggestion(
|
||||
expr.span,
|
||||
&format!("try {} the cast value", op_verb),
|
||||
format!("({})", expr_str),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
@ -3276,26 +3275,40 @@ fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
|
|||
}
|
||||
|
||||
/// Parse a 'for' .. 'in' expression ('for' token already eaten)
|
||||
fn parse_for_expr(&mut self, opt_label: Option<Label>,
|
||||
span_lo: Span,
|
||||
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
||||
fn parse_for_expr(
|
||||
&mut self,
|
||||
opt_label: Option<Label>,
|
||||
span_lo: Span,
|
||||
mut attrs: ThinVec<Attribute>
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
|
||||
|
||||
// Record whether we are about to parse `for (`.
|
||||
// This is used below for recovery in case of `for ( $stuff ) $block`
|
||||
// in which case we will suggest `for $stuff $block`.
|
||||
let begin_paren = match self.token.kind {
|
||||
token::OpenDelim(token::Paren) => Some(self.token.span),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let pat = self.parse_top_level_pat()?;
|
||||
if !self.eat_keyword(kw::In) {
|
||||
let in_span = self.prev_span.between(self.token.span);
|
||||
let mut err = self.sess.span_diagnostic
|
||||
.struct_span_err(in_span, "missing `in` in `for` loop");
|
||||
err.span_suggestion_short(
|
||||
in_span, "try adding `in` here", " in ".into(),
|
||||
// has been misleading, at least in the past (closed Issue #48492)
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(in_span, "missing `in` in `for` loop")
|
||||
.span_suggestion_short(
|
||||
in_span,
|
||||
"try adding `in` here", " in ".into(),
|
||||
// has been misleading, at least in the past (closed Issue #48492)
|
||||
Applicability::MaybeIncorrect
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let in_span = self.prev_span;
|
||||
self.check_for_for_in_in_typo(in_span);
|
||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||
|
||||
let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren);
|
||||
|
||||
let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(iattrs);
|
||||
|
||||
|
@ -3522,15 +3535,14 @@ fn parse_pats(&mut self) -> PResult<'a, Vec<P<Pat>>> {
|
|||
pats.push(self.parse_top_level_pat()?);
|
||||
|
||||
if self.token == token::OrOr {
|
||||
let mut err = self.struct_span_err(self.token.span,
|
||||
"unexpected token `||` after pattern");
|
||||
err.span_suggestion(
|
||||
self.token.span,
|
||||
"use a single `|` to specify multiple patterns",
|
||||
"|".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(self.token.span, "unexpected token `||` after pattern")
|
||||
.span_suggestion(
|
||||
self.token.span,
|
||||
"use a single `|` to specify multiple patterns",
|
||||
"|".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
} else if self.eat(&token::BinOp(token::Or)) {
|
||||
// This is a No-op. Continue the loop to parse the next
|
||||
|
@ -3627,15 +3639,14 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<source_map::Spanned<ast::Fiel
|
|||
|
||||
if self.token == token::DotDotDot { // Issue #46718
|
||||
// Accept `...` as if it were `..` to avoid further errors
|
||||
let mut err = self.struct_span_err(self.token.span,
|
||||
"expected field pattern, found `...`");
|
||||
err.span_suggestion(
|
||||
self.token.span,
|
||||
"to omit remaining fields, use one fewer `.`",
|
||||
"..".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(self.token.span, "expected field pattern, found `...`")
|
||||
.span_suggestion(
|
||||
self.token.span,
|
||||
"to omit remaining fields, use one fewer `.`",
|
||||
"..".to_owned(),
|
||||
Applicability::MachineApplicable
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.bump(); // `..` || `...`
|
||||
|
||||
|
@ -3788,7 +3799,7 @@ fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
|
|||
let seq_span = pat.span.to(self.prev_span);
|
||||
let mut err = self.struct_span_err(comma_span,
|
||||
"unexpected `,` in pattern");
|
||||
if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) {
|
||||
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
|
||||
err.span_suggestion(
|
||||
seq_span,
|
||||
"try adding parentheses to match on a tuple..",
|
||||
|
@ -4137,7 +4148,7 @@ fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
|
|||
let parser_snapshot_after_type = self.clone();
|
||||
mem::replace(self, parser_snapshot_before_type);
|
||||
|
||||
let snippet = self.sess.source_map().span_to_snippet(pat.span).unwrap();
|
||||
let snippet = self.span_to_snippet(pat.span).unwrap();
|
||||
err.span_label(pat.span, format!("while parsing the type for `{}`", snippet));
|
||||
(Some((parser_snapshot_after_type, colon_sp, err)), None)
|
||||
}
|
||||
|
@ -4557,7 +4568,7 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
|||
if self.eat(&token::Semi) {
|
||||
stmt_span = stmt_span.with_hi(self.prev_span.hi());
|
||||
}
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(stmt_span) {
|
||||
if let Ok(snippet) = self.span_to_snippet(stmt_span) {
|
||||
e.span_suggestion(
|
||||
stmt_span,
|
||||
"try placing this code inside a block",
|
||||
|
@ -4730,7 +4741,7 @@ fn parse_generic_bounds_common(&mut self,
|
|||
lo.to(self.prev_span),
|
||||
"parenthesized lifetime bounds are not supported"
|
||||
);
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(inner_span) {
|
||||
if let Ok(snippet) = self.span_to_snippet(inner_span) {
|
||||
err.span_suggestion_short(
|
||||
lo.to(self.prev_span),
|
||||
"remove the parentheses",
|
||||
|
@ -4788,7 +4799,7 @@ fn parse_generic_bounds_common(&mut self,
|
|||
let mut new_bound_list = String::new();
|
||||
if !bounds.is_empty() {
|
||||
let mut snippets = bounds.iter().map(|bound| bound.span())
|
||||
.map(|span| self.sess.source_map().span_to_snippet(span));
|
||||
.map(|span| self.span_to_snippet(span));
|
||||
while let Some(Ok(snippet)) = snippets.next() {
|
||||
new_bound_list.push_str(" + ");
|
||||
new_bound_list.push_str(&snippet);
|
||||
|
@ -5853,15 +5864,16 @@ fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'
|
|||
if let token::DocComment(_) = self.token.kind {
|
||||
if self.look_ahead(1,
|
||||
|tok| tok == &token::CloseDelim(token::Brace)) {
|
||||
let mut err = self.diagnostic().struct_span_err_with_code(
|
||||
self.diagnostic().struct_span_err_with_code(
|
||||
self.token.span,
|
||||
"found a documentation comment that doesn't document anything",
|
||||
DiagnosticId::Error("E0584".into()),
|
||||
);
|
||||
err.help("doc comments must come before what they document, maybe a \
|
||||
)
|
||||
.help(
|
||||
"doc comments must come before what they document, maybe a \
|
||||
comment was intended with `//`?",
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
continue;
|
||||
}
|
||||
|
@ -6305,12 +6317,15 @@ pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibili
|
|||
let sp = path.span;
|
||||
let help_msg = format!("make this visible only to module `{}` with `in`", path);
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
let mut err = struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg);
|
||||
err.help(suggestion);
|
||||
err.span_suggestion(
|
||||
sp, &help_msg, format!("in {}", path), Applicability::MachineApplicable
|
||||
);
|
||||
err.emit(); // emit diagnostic, but continue with public visibility
|
||||
struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg)
|
||||
.help(suggestion)
|
||||
.span_suggestion(
|
||||
sp,
|
||||
&help_msg,
|
||||
format!("in {}", path),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit(); // emit diagnostic, but continue with public visibility
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6744,14 +6759,10 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> {
|
|||
}
|
||||
ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp);
|
||||
|
||||
let mut err = self.struct_span_err(fixed_name_sp, error_msg);
|
||||
err.span_label(fixed_name_sp, "dash-separated idents are not valid");
|
||||
err.multipart_suggestion(
|
||||
suggestion_msg,
|
||||
replacement,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(fixed_name_sp, error_msg)
|
||||
.span_label(fixed_name_sp, "dash-separated idents are not valid")
|
||||
.multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable)
|
||||
.emit();
|
||||
}
|
||||
Ok(ident)
|
||||
}
|
||||
|
@ -6906,14 +6917,14 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef>
|
|||
if !self.eat(&token::Comma) {
|
||||
if self.token.is_ident() && !self.token.is_reserved_ident() {
|
||||
let sp = self.sess.source_map().next_point(self.prev_span);
|
||||
let mut err = self.struct_span_err(sp, "missing comma");
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
"missing comma",
|
||||
",".to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(sp, "missing comma")
|
||||
.span_suggestion_short(
|
||||
sp,
|
||||
"missing comma",
|
||||
",".to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -6952,15 +6963,16 @@ fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
|
|||
Some(abi) => Ok(Some(abi)),
|
||||
None => {
|
||||
let prev_span = self.prev_span;
|
||||
let mut err = struct_span_err!(
|
||||
struct_span_err!(
|
||||
self.sess.span_diagnostic,
|
||||
prev_span,
|
||||
E0703,
|
||||
"invalid ABI: found `{}`",
|
||||
symbol);
|
||||
err.span_label(prev_span, "invalid ABI");
|
||||
err.help(&format!("valid ABIs: {}", abi::all_names().join(", ")));
|
||||
err.emit();
|
||||
symbol
|
||||
)
|
||||
.span_label(prev_span, "invalid ABI")
|
||||
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
|
||||
.emit();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -7130,16 +7142,15 @@ fn parse_item_implementation(
|
|||
// CONST ITEM
|
||||
if self.eat_keyword(kw::Mut) {
|
||||
let prev_span = self.prev_span;
|
||||
let mut err = self.diagnostic()
|
||||
.struct_span_err(prev_span, "const globals cannot be mutable");
|
||||
err.span_label(prev_span, "cannot be mutable");
|
||||
err.span_suggestion(
|
||||
const_span,
|
||||
"you might want to declare a static instead",
|
||||
"static".to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
self.struct_span_err(prev_span, "const globals cannot be mutable")
|
||||
.span_label(prev_span, "cannot be mutable")
|
||||
.span_suggestion(
|
||||
const_span,
|
||||
"you might want to declare a static instead",
|
||||
"static".to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
|
||||
let prev_span = self.prev_span;
|
||||
|
@ -7407,7 +7418,7 @@ fn parse_item_implementation(
|
|||
sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable
|
||||
);
|
||||
} else {
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(ident_sp) {
|
||||
if let Ok(snippet) = self.span_to_snippet(ident_sp) {
|
||||
err.span_suggestion(
|
||||
full_sp,
|
||||
"if you meant to call a macro, try",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "example"
|
||||
version = "0.1.0"
|
||||
authors = ["Hideki Sekine <sekineh@me.com>"]
|
||||
# edition = "2018"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.5.4"
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
// #![feature(stdsimd)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate cortex_m;
|
||||
|
||||
extern crate cortex_m_rt as rt;
|
||||
extern crate cortex_m_semihosting as semihosting;
|
||||
extern crate panic_halt;
|
||||
|
||||
use core::fmt::Write;
|
||||
use cortex_m::asm;
|
||||
use rt::entry;
|
||||
use cortex_m_rt::entry;
|
||||
use cortex_m_semihosting as semihosting;
|
||||
|
||||
//FIXME: This imports the provided #[panic_handler].
|
||||
#[allow(rust_2018_idioms)]
|
||||
extern crate panic_halt;
|
||||
|
||||
entry!(main);
|
||||
|
||||
|
@ -22,7 +20,7 @@ fn main() -> ! {
|
|||
|
||||
// write something through semihosting interface
|
||||
let mut hstdout = semihosting::hio::hstdout().unwrap();
|
||||
write!(hstdout, "x = {}\n", x);
|
||||
let _ = write!(hstdout, "x = {}\n", x);
|
||||
|
||||
// exit from qemu
|
||||
semihosting::debug::exit(semihosting::debug::EXIT_SUCCESS);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// Checks to ensure that we properly detect when a closure constrains an existential type
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {
|
||||
existential type Existential: Debug;
|
||||
fn _unused() -> Existential { String::new() }
|
||||
//~^ ERROR: concrete type differs from previous defining existential type use
|
||||
let null = || -> Existential { 0 };
|
||||
println!("{:?}", null());
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
error: concrete type differs from previous defining existential type use
|
||||
--> $DIR/issue-52843-closure-constrain.rs:8:5
|
||||
|
|
||||
LL | fn _unused() -> Existential { String::new() }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, got `std::string::String`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/issue-52843-closure-constrain.rs:6:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | existential type Existential: Debug;
|
||||
LL | | fn _unused() -> Existential { String::new() }
|
||||
LL | |
|
||||
LL | | let null = || -> Existential { 0 };
|
||||
LL | | println!("{:?}", null());
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(const_fn, generators, generator_trait, existential_type)]
|
||||
|
||||
use std::ops::Generator;
|
||||
|
||||
existential type GenOnce<Y, R>: Generator<Yield = Y, Return = R>;
|
||||
|
||||
const fn const_generator<Y, R>(yielding: Y, returning: R) -> GenOnce<Y, R> {
|
||||
move || {
|
||||
yield yielding;
|
||||
|
||||
return returning;
|
||||
}
|
||||
}
|
||||
|
||||
const FOO: GenOnce<usize, usize> = const_generator(10, 100);
|
||||
|
||||
fn main() {}
|
15
src/test/ui/existential_types/issue-60407.rs
Normal file
15
src/test/ui/existential_types/issue-60407.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(existential_type)]
|
||||
|
||||
existential type Debuggable: core::fmt::Debug;
|
||||
|
||||
static mut TEST: Option<Debuggable> = None;
|
||||
|
||||
fn main() {
|
||||
unsafe { TEST = Some(foo()) }
|
||||
}
|
||||
|
||||
fn foo() -> Debuggable {
|
||||
0u32
|
||||
}
|
26
src/test/ui/existential_types/issue-60564.rs
Normal file
26
src/test/ui/existential_types/issue-60564.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
#![feature(existential_type)]
|
||||
|
||||
trait IterBits {
|
||||
type BitsIter: Iterator<Item = u8>;
|
||||
fn iter_bits(self, n: u8) -> Self::BitsIter;
|
||||
}
|
||||
|
||||
existential type IterBitsIter<T, E, I>: std::iter::Iterator<Item = I>;
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
impl<T, E> IterBits for T
|
||||
where
|
||||
T: std::ops::Shr<Output = T>
|
||||
+ std::ops::BitAnd<T, Output = T>
|
||||
+ std::convert::From<u8>
|
||||
+ std::convert::TryInto<u8, Error = E>,
|
||||
E: std::fmt::Debug,
|
||||
{
|
||||
type BitsIter = IterBitsIter<T, E, u8>;
|
||||
fn iter_bits(self, n: u8) -> Self::BitsIter {
|
||||
//~^ ERROR type parameter `E` is part of concrete type but not used
|
||||
(0u8..n)
|
||||
.rev()
|
||||
.map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
|
||||
}
|
||||
}
|
25
src/test/ui/existential_types/issue-60564.stderr
Normal file
25
src/test/ui/existential_types/issue-60564.stderr
Normal file
|
@ -0,0 +1,25 @@
|
|||
error[E0601]: `main` function not found in crate `issue_60564`
|
||||
|
|
||||
= note: consider adding a `main` function to `$DIR/issue-60564.rs`
|
||||
|
||||
error: type parameter `E` is part of concrete type but not used in parameter list for existential type
|
||||
--> $DIR/issue-60564.rs:20:49
|
||||
|
|
||||
LL | fn iter_bits(self, n: u8) -> Self::BitsIter {
|
||||
| _________________________________________________^
|
||||
LL | |
|
||||
LL | | (0u8..n)
|
||||
LL | | .rev()
|
||||
LL | | .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/issue-60564.rs:8:1
|
||||
|
|
||||
LL | existential type IterBitsIter<T, E, I>: std::iter::Iterator<Item = I>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0601`.
|
19
src/test/ui/hygiene/duplicate_lifetimes.rs
Normal file
19
src/test/ui/hygiene/duplicate_lifetimes.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Ensure that lifetime parameter names are modernized before we check for
|
||||
// duplicates.
|
||||
|
||||
#![feature(decl_macro, rustc_attrs)]
|
||||
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
macro m($a:lifetime) {
|
||||
fn g<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "transparent"]
|
||||
macro n($a:lifetime) {
|
||||
fn h<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
|
||||
}
|
||||
|
||||
m!('a);
|
||||
n!('a);
|
||||
|
||||
fn main() {}
|
27
src/test/ui/hygiene/duplicate_lifetimes.stderr
Normal file
27
src/test/ui/hygiene/duplicate_lifetimes.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error[E0263]: lifetime name `'a` declared twice in the same scope
|
||||
--> $DIR/duplicate_lifetimes.rs:8:14
|
||||
|
|
||||
LL | fn g<$a, 'a>() {}
|
||||
| ^^ declared twice
|
||||
...
|
||||
LL | m!('a);
|
||||
| -------
|
||||
| | |
|
||||
| | previous declaration here
|
||||
| in this macro invocation
|
||||
|
||||
error[E0263]: lifetime name `'a` declared twice in the same scope
|
||||
--> $DIR/duplicate_lifetimes.rs:13:14
|
||||
|
|
||||
LL | fn h<$a, 'a>() {}
|
||||
| ^^ declared twice
|
||||
...
|
||||
LL | n!('a);
|
||||
| -------
|
||||
| | |
|
||||
| | previous declaration here
|
||||
| in this macro invocation
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0263`.
|
104
src/test/ui/hygiene/generic_params.rs
Normal file
104
src/test/ui/hygiene/generic_params.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Ensure that generic parameters always have modern hygiene.
|
||||
|
||||
// check-pass
|
||||
// ignore-pretty pretty-printing is unhygienic
|
||||
|
||||
#![feature(decl_macro, rustc_attrs, const_generics)]
|
||||
|
||||
mod type_params {
|
||||
macro m($T:ident) {
|
||||
fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) {
|
||||
(t1.clone(), t2 == t2)
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
macro n($T:ident) {
|
||||
fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) {
|
||||
(t1.clone(), t2.clone())
|
||||
}
|
||||
fn h<T: Clone>(t1: $T, t2: T) -> (T, $T) {
|
||||
(t1.clone(), t2.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "transparent"]
|
||||
macro p($T:ident) {
|
||||
fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) {
|
||||
(t1.clone(), t2.clone())
|
||||
}
|
||||
fn k<T: Clone>(t1: $T, t2: T) -> (T, $T) {
|
||||
(t1.clone(), t2.clone())
|
||||
}
|
||||
}
|
||||
|
||||
m!(T);
|
||||
n!(T);
|
||||
p!(T);
|
||||
}
|
||||
|
||||
mod lifetime_params {
|
||||
macro m($a:lifetime) {
|
||||
fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
macro n($a:lifetime) {
|
||||
fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
|
||||
(t1, t2)
|
||||
}
|
||||
fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "transparent"]
|
||||
macro p($a:lifetime) {
|
||||
fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
|
||||
(t1, t2)
|
||||
}
|
||||
fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
m!('a);
|
||||
n!('a);
|
||||
p!('a);
|
||||
}
|
||||
|
||||
mod const_params {
|
||||
macro m($C:ident) {
|
||||
fn f<const $C: usize, const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
macro n($C:ident) {
|
||||
fn g<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
|
||||
(t1, t2)
|
||||
}
|
||||
fn h<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "transparent"]
|
||||
macro p($C:ident) {
|
||||
fn j<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
|
||||
(t1, t2)
|
||||
}
|
||||
fn k<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
|
||||
(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
m!(C);
|
||||
n!(C);
|
||||
p!(C);
|
||||
}
|
||||
|
||||
fn main() {}
|
6
src/test/ui/hygiene/generic_params.stderr
Normal file
6
src/test/ui/hygiene/generic_params.stderr
Normal file
|
@ -0,0 +1,6 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/generic_params.rs:6:37
|
||||
|
|
||||
LL | #![feature(decl_macro, rustc_attrs, const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
32
src/test/ui/hygiene/issue-61574-const-parameters.rs
Normal file
32
src/test/ui/hygiene/issue-61574-const-parameters.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// A more comprehensive test that const parameters have correctly implemented
|
||||
// hygiene
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(const_generics)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
struct VectorLike<T, const SIZE: usize>([T; {SIZE}]);
|
||||
|
||||
macro_rules! impl_operator_overload {
|
||||
($trait_ident:ident, $method_ident:ident) => {
|
||||
|
||||
impl<T, const SIZE: usize> $trait_ident for VectorLike<T, {SIZE}>
|
||||
where
|
||||
T: $trait_ident,
|
||||
{
|
||||
type Output = VectorLike<T, {SIZE}>;
|
||||
|
||||
fn $method_ident(self, _: VectorLike<T, {SIZE}>) -> VectorLike<T, {SIZE}> {
|
||||
let _ = SIZE;
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl_operator_overload!(Add, add);
|
||||
|
||||
fn main() {}
|
6
src/test/ui/hygiene/issue-61574-const-parameters.stderr
Normal file
6
src/test/ui/hygiene/issue-61574-const-parameters.stderr
Normal file
|
@ -0,0 +1,6 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/issue-61574-const-parameters.rs:6:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// check-pass
|
||||
// ignore-pretty pretty-printing is unhygienic
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
macro m($T:ident) {
|
||||
fn f<T, $T>(t: T, t2: $T) -> (T, $T) {
|
||||
(t, t2)
|
||||
}
|
||||
}
|
||||
|
||||
m!(T);
|
||||
|
||||
fn main() {}
|
15
src/test/ui/parser/recover-for-loop-parens-around-head.rs
Normal file
15
src/test/ui/parser/recover-for-loop-parens-around-head.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Here we test that the parser is able to recover in a situation like
|
||||
// `for ( $pat in $expr )` since that is familiar syntax in other languages.
|
||||
// Instead we suggest that the user writes `for $pat in $expr`.
|
||||
|
||||
#![deny(unused)] // Make sure we don't trigger `unused_parens`.
|
||||
|
||||
fn main() {
|
||||
let vec = vec![1, 2, 3];
|
||||
|
||||
for ( elem in vec ) {
|
||||
//~^ ERROR expected one of `)`, `,`, or `@`, found `in`
|
||||
//~| ERROR unexpected closing `)`
|
||||
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
error: expected one of `)`, `,`, or `@`, found `in`
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:16
|
||||
|
|
||||
LL | for ( elem in vec ) {
|
||||
| ^^ expected one of `)`, `,`, or `@` here
|
||||
|
||||
error: unexpected closing `)`
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:23
|
||||
|
|
||||
LL | for ( elem in vec ) {
|
||||
| --------------^
|
||||
| |
|
||||
| opening `(`
|
||||
| help: remove parenthesis in `for` loop: `elem in vec`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:13:38
|
||||
|
|
||||
LL | const RECOVERY_WITNESS: () = 0;
|
||||
| ^ expected (), found integer
|
||||
|
|
||||
= note: expected type `()`
|
||||
found type `{integer}`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
82
src/test/ui/pattern/rest-pat-semantic-disallowed.rs
Normal file
82
src/test/ui/pattern/rest-pat-semantic-disallowed.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Here we test that rest patterns, i.e. `..`, are not allowed
|
||||
// outside of slice (+ ident patterns witin those), tuple,
|
||||
// and tuple struct patterns and that duplicates are caught in these contexts.
|
||||
|
||||
#![feature(slice_patterns, box_patterns)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
macro_rules! mk_pat {
|
||||
() => { .. } //~ ERROR `..` patterns are not allowed here
|
||||
}
|
||||
|
||||
fn rest_patterns() {
|
||||
let mk_pat!();
|
||||
|
||||
// Top level:
|
||||
fn foo(..: u8) {} //~ ERROR `..` patterns are not allowed here
|
||||
let ..; //~ ERROR `..` patterns are not allowed here
|
||||
|
||||
// Box patterns:
|
||||
let box ..; //~ ERROR `..` patterns are not allowed here
|
||||
|
||||
// In or-patterns:
|
||||
match 1 {
|
||||
1 | .. => {} //~ ERROR `..` patterns are not allowed here
|
||||
}
|
||||
|
||||
// Ref patterns:
|
||||
let &..; //~ ERROR `..` patterns are not allowed here
|
||||
let &mut ..; //~ ERROR `..` patterns are not allowed here
|
||||
|
||||
// Ident patterns:
|
||||
let x @ ..; //~ ERROR `..` patterns are not allowed here
|
||||
let ref x @ ..; //~ ERROR `..` patterns are not allowed here
|
||||
let ref mut x @ ..; //~ ERROR `..` patterns are not allowed here
|
||||
|
||||
// Tuple:
|
||||
let (..): (u8,); // OK.
|
||||
let (..,): (u8,); // OK.
|
||||
let (
|
||||
..,
|
||||
.., //~ ERROR `..` can only be used once per tuple pattern
|
||||
.. //~ ERROR `..` can only be used once per tuple pattern
|
||||
): (u8, u8, u8);
|
||||
let (
|
||||
..,
|
||||
x,
|
||||
.. //~ ERROR `..` can only be used once per tuple pattern
|
||||
): (u8, u8, u8);
|
||||
|
||||
struct A(u8, u8, u8);
|
||||
|
||||
// Tuple struct (same idea as for tuple patterns):
|
||||
let A(..); // OK.
|
||||
let A(..,); // OK.
|
||||
let A(
|
||||
..,
|
||||
.., //~ ERROR `..` can only be used once per tuple struct pattern
|
||||
.. //~ ERROR `..` can only be used once per tuple struct pattern
|
||||
);
|
||||
let A(
|
||||
..,
|
||||
x,
|
||||
.. //~ ERROR `..` can only be used once per tuple struct pattern
|
||||
);
|
||||
|
||||
// Array/Slice:
|
||||
let [..]: &[u8]; // OK.
|
||||
let [..,]: &[u8]; // OK.
|
||||
let [
|
||||
..,
|
||||
.., //~ ERROR `..` can only be used once per slice pattern
|
||||
.. //~ ERROR `..` can only be used once per slice pattern
|
||||
]: &[u8];
|
||||
let [
|
||||
..,
|
||||
ref x @ .., //~ ERROR `..` can only be used once per slice pattern
|
||||
ref mut y @ .., //~ ERROR `..` can only be used once per slice pattern
|
||||
(ref z @ ..), //~ ERROR `..` patterns are not allowed here
|
||||
.. //~ ERROR `..` can only be used once per slice pattern
|
||||
]: &[u8];
|
||||
}
|
188
src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
Normal file
188
src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
Normal file
|
@ -0,0 +1,188 @@
|
|||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:10:13
|
||||
|
|
||||
LL | () => { .. }
|
||||
| ^^
|
||||
...
|
||||
LL | let mk_pat!();
|
||||
| --------- in this macro invocation
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:18:9
|
||||
|
|
||||
LL | let ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:21:13
|
||||
|
|
||||
LL | let box ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:25:13
|
||||
|
|
||||
LL | 1 | .. => {}
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:29:10
|
||||
|
|
||||
LL | let &..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:30:14
|
||||
|
|
||||
LL | let &mut ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:33:13
|
||||
|
|
||||
LL | let x @ ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:34:17
|
||||
|
|
||||
LL | let ref x @ ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:35:21
|
||||
|
|
||||
LL | let ref mut x @ ..;
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` can only be used once per tuple pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:42:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
| ^^ can only be used once per tuple pattern
|
||||
|
||||
error: `..` can only be used once per tuple pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:43:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
LL | ..
|
||||
| ^^ can only be used once per tuple pattern
|
||||
|
||||
error: `..` can only be used once per tuple pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:48:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | x,
|
||||
LL | ..
|
||||
| ^^ can only be used once per tuple pattern
|
||||
|
||||
error: `..` can only be used once per tuple struct pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:58:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
| ^^ can only be used once per tuple struct pattern
|
||||
|
||||
error: `..` can only be used once per tuple struct pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:59:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
LL | ..
|
||||
| ^^ can only be used once per tuple struct pattern
|
||||
|
||||
error: `..` can only be used once per tuple struct pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:64:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | x,
|
||||
LL | ..
|
||||
| ^^ can only be used once per tuple struct pattern
|
||||
|
||||
error: `..` can only be used once per slice pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:72:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
| ^^ can only be used once per slice pattern
|
||||
|
||||
error: `..` can only be used once per slice pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:73:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ..,
|
||||
LL | ..
|
||||
| ^^ can only be used once per slice pattern
|
||||
|
||||
error: `..` can only be used once per slice pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:77:17
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ref x @ ..,
|
||||
| ^^ can only be used once per slice pattern
|
||||
|
||||
error: `..` can only be used once per slice pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:78:21
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
LL | ref x @ ..,
|
||||
LL | ref mut y @ ..,
|
||||
| ^^ can only be used once per slice pattern
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:79:18
|
||||
|
|
||||
LL | (ref z @ ..),
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: `..` can only be used once per slice pattern
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:80:9
|
||||
|
|
||||
LL | ..,
|
||||
| -- previously used here
|
||||
...
|
||||
LL | ..
|
||||
| ^^ can only be used once per slice pattern
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/rest-pat-semantic-disallowed.rs:17:12
|
||||
|
|
||||
LL | fn foo(..: u8) {}
|
||||
| ^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
|
70
src/test/ui/pattern/rest-pat-syntactic.rs
Normal file
70
src/test/ui/pattern/rest-pat-syntactic.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Here we test that `..` is allowed in all pattern locations *syntactically*.
|
||||
// The semantic test is in `rest-pat-semantic-disallowed.rs`.
|
||||
|
||||
// check-pass
|
||||
|
||||
fn main() {}
|
||||
|
||||
macro_rules! accept_pat {
|
||||
($p:pat) => {}
|
||||
}
|
||||
|
||||
accept_pat!(..);
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn rest_patterns() {
|
||||
// Top level:
|
||||
fn foo(..: u8) {}
|
||||
let ..;
|
||||
|
||||
// Box patterns:
|
||||
let box ..;
|
||||
|
||||
// In or-patterns:
|
||||
match x {
|
||||
.. | .. => {}
|
||||
}
|
||||
|
||||
// Ref patterns:
|
||||
let &..;
|
||||
let &mut ..;
|
||||
|
||||
// Ident patterns:
|
||||
let x @ ..;
|
||||
let ref x @ ..;
|
||||
let ref mut x @ ..;
|
||||
|
||||
// Tuple:
|
||||
let (..); // This is interpreted as a tuple pattern, not a parenthesis one.
|
||||
let (..,); // Allowing trailing comma.
|
||||
let (.., .., ..); // Duplicates also.
|
||||
let (.., P, ..); // Including with things in between.
|
||||
|
||||
// Tuple struct (same idea as for tuple patterns):
|
||||
let A(..);
|
||||
let A(..,);
|
||||
let A(.., .., ..);
|
||||
let A(.., P, ..);
|
||||
|
||||
// Array/Slice (like with tuple patterns):
|
||||
let [..];
|
||||
let [..,];
|
||||
let [.., .., ..];
|
||||
let [.., P, ..];
|
||||
|
||||
// Random walk to guard against special casing:
|
||||
match x {
|
||||
.. |
|
||||
[
|
||||
(
|
||||
box ..,
|
||||
&(..),
|
||||
&mut ..,
|
||||
x @ ..
|
||||
),
|
||||
ref x @ ..,
|
||||
] |
|
||||
ref mut x @ ..
|
||||
=> {}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ license = 'MIT OR Apache-2.0'
|
|||
description = """
|
||||
Hack for the compiler's own build system
|
||||
"""
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
|
45
src/tools/tidy/src/edition.rs
Normal file
45
src/tools/tidy/src/edition.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
//! Tidy check to ensure that crate `edition` is '2018'
|
||||
//!
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
fn filter_dirs(path: &Path) -> bool {
|
||||
// FIXME: just use super::filter_dirs after the submodules are updated.
|
||||
if super::filter_dirs(path) {
|
||||
return true;
|
||||
}
|
||||
let skip = [
|
||||
"src/doc/book/second-edition",
|
||||
"src/doc/book/2018-edition",
|
||||
"src/doc/book/ci/stable-check",
|
||||
"src/doc/reference/stable-check",
|
||||
];
|
||||
skip.iter().any(|p| path.ends_with(p))
|
||||
}
|
||||
|
||||
fn is_edition_2018(mut line: &str) -> bool {
|
||||
line = line.trim();
|
||||
line == "edition = \"2018\"" || line == "edition = \'2018\'"
|
||||
}
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
super::walk(
|
||||
path,
|
||||
&mut |path| filter_dirs(path) || path.ends_with("src/test"),
|
||||
&mut |entry, contents| {
|
||||
let file = entry.path();
|
||||
let filename = file.file_name().unwrap();
|
||||
if filename != "Cargo.toml" {
|
||||
return;
|
||||
}
|
||||
let has_edition = contents.lines().any(is_edition_2018);
|
||||
if !has_edition {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"{} doesn't have `edition = \"2018\"` on a separate line",
|
||||
file.display()
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
|
@ -34,6 +34,7 @@ macro_rules! tidy_error {
|
|||
pub mod errors;
|
||||
pub mod features;
|
||||
pub mod cargo;
|
||||
pub mod edition;
|
||||
pub mod pal;
|
||||
pub mod deps;
|
||||
pub mod extdeps;
|
||||
|
|
|
@ -22,6 +22,7 @@ fn main() {
|
|||
style::check(&path, &mut bad);
|
||||
errors::check(&path, &mut bad);
|
||||
cargo::check(&path, &mut bad);
|
||||
edition::check(&path, &mut bad);
|
||||
let collected = features::check(&path, &mut bad, verbose);
|
||||
pal::check(&path, &mut bad);
|
||||
unstable_book::check(&path, collected, &mut bad);
|
||||
|
|
Loading…
Reference in a new issue