- 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.
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";
//! * 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"
}
}
- /// 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
/// `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
/// `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
///
/// [`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>
}
}
+#[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]
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");
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
}
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();
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.
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),
}
}
- ident.span = ident.span.modern();
+ ident = modern_ident;
let mut poisoned = None;
loop {
let opt_module = if let Some(node_id) = record_used_id {
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 {
}
}
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 {
}
}
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);
} 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
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();
}
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> {
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)
})?;
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]);
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;
&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,
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:
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()
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);
}
}
+ /// 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 } &&
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();
}
}
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)
}
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();
}
}
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 {
// 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);
}
}
}
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;
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) => {
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);
// 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),
));
// 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)
}
}
/// 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);
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
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(); // `..` || `...`
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..",
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)
}
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",
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",
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);
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;
}
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
}
}
}
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)
}
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;
}
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)
}
}
// 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;
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",
name = "example"
version = "0.1.0"
authors = ["Hideki Sekine <sekineh@me.com>"]
-# edition = "2018"
+edition = "2018"
[dependencies]
cortex-m = "0.5.4"
// #![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);
// 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);
--- /dev/null
+// 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());
+}
--- /dev/null
+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
+
+++ /dev/null
-#![feature(existential_type)]
-
-trait UnwrapItemsExt {
- type Iter;
- fn unwrap_items(self) -> Self::Iter;
-}
-
-impl<I, T, E> UnwrapItemsExt for I
-where
- I: Iterator<Item = Result<T, E>>,
- E: std::fmt::Debug,
-{
- existential type Iter: Iterator<Item = T>;
- //~^ ERROR: could not find defining uses
-
- fn unwrap_items(self) -> Self::Iter {
- //~^ ERROR: type parameter `T` is part of concrete type
- //~| ERROR: type parameter `E` is part of concrete type
- self.map(|x| x.unwrap())
- }
-}
-
-fn main() {}
+++ /dev/null
-error: type parameter `T` is part of concrete type but not used in parameter list for existential type
- --> $DIR/issue-58887.rs:16:41
- |
-LL | fn unwrap_items(self) -> Self::Iter {
- | _________________________________________^
-LL | |
-LL | |
-LL | | self.map(|x| x.unwrap())
-LL | | }
- | |_____^
-
-error: type parameter `E` is part of concrete type but not used in parameter list for existential type
- --> $DIR/issue-58887.rs:16:41
- |
-LL | fn unwrap_items(self) -> Self::Iter {
- | _________________________________________^
-LL | |
-LL | |
-LL | | self.map(|x| x.unwrap())
-LL | | }
- | |_____^
-
-error: could not find defining uses
- --> $DIR/issue-58887.rs:13:5
- |
-LL | existential type Iter: Iterator<Item = T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
+++ /dev/null
-trait Bug {
- type Item: Bug;
-
- const FUN: fn() -> Self::Item;
-}
-
-impl Bug for &() {
- existential type Item: Bug; //~ ERROR existential types are unstable
- //~^ ERROR the trait bound `(): Bug` is not satisfied
- //~^^ ERROR could not find defining uses
-
- const FUN: fn() -> Self::Item = || ();
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: existential types are unstable
- --> $DIR/issue-60371.rs:8:5
- |
-LL | existential type Item: Bug;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/63063
- = help: add `#![feature(existential_type)]` to the crate attributes to enable
-
-error[E0277]: the trait bound `(): Bug` is not satisfied
- --> $DIR/issue-60371.rs:8:5
- |
-LL | existential type Item: Bug;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()`
- |
- = help: the following implementations were found:
- <&() as Bug>
- = note: the return type of a function must have a statically known size
-
-error: could not find defining uses
- --> $DIR/issue-60371.rs:8:5
- |
-LL | existential type Item: Bug;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0277, E0658.
-For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_assignments)]
-#![allow(unused_variables)]
-#![feature(existential_type)]
-
-fn main() {
- assert_eq!(foo().to_string(), "foo");
- assert_eq!(bar1().to_string(), "bar1");
- assert_eq!(bar2().to_string(), "bar2");
- let mut x = bar1();
- x = bar2();
- assert_eq!(boo::boo().to_string(), "boo");
- assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
-}
-
-// single definition
-existential type Foo: std::fmt::Display;
-
-fn foo() -> Foo {
- "foo"
-}
-
-// two definitions
-existential type Bar: std::fmt::Display;
-
-fn bar1() -> Bar {
- "bar1"
-}
-
-fn bar2() -> Bar {
- "bar2"
-}
-
-// definition in submodule
-existential type Boo: std::fmt::Display;
-
-mod boo {
- pub fn boo() -> super::Boo {
- "boo"
- }
-}
-
-existential type MyIter<T>: Iterator<Item = T>;
-
-fn my_iter<T>(t: T) -> MyIter<T> {
- std::iter::once(t)
-}
-
-fn my_iter2<T>(t: T) -> MyIter<T> {
- std::iter::once(t)
-}
-
-// param names should not have an effect!
-fn my_iter3<U>(u: U) -> MyIter<U> {
- std::iter::once(u)
-}
-
-// param position should not have an effect!
-fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
- std::iter::once(v)
-}
-
-// param names should not have an effect!
-existential type MyOtherIter<T>: Iterator<Item = T>;
-
-fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
- std::iter::once(u)
-}
-
-trait Trait {}
-existential type GenericBound<'a, T: Trait>: Sized + 'a;
-
-fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
- t
-}
-
-mod pass_through {
- pub existential type Passthrough<T>: Sized + 'static;
-
- fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
- t
- }
-}
-
-fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
- x
-}
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![feature(existential_type)]
+
+fn main() {
+ assert_eq!(foo().to_string(), "foo");
+ assert_eq!(bar1().to_string(), "bar1");
+ assert_eq!(bar2().to_string(), "bar2");
+ let mut x = bar1();
+ x = bar2();
+ assert_eq!(boo::boo().to_string(), "boo");
+ assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
+}
+
+// single definition
+existential type Foo: std::fmt::Display;
+
+fn foo() -> Foo {
+ "foo"
+}
+
+// two definitions
+existential type Bar: std::fmt::Display;
+
+fn bar1() -> Bar {
+ "bar1"
+}
+
+fn bar2() -> Bar {
+ "bar2"
+}
+
+// definition in submodule
+existential type Boo: std::fmt::Display;
+
+mod boo {
+ pub fn boo() -> super::Boo {
+ "boo"
+ }
+}
+
+existential type MyIter<T>: Iterator<Item = T>;
+
+fn my_iter<T>(t: T) -> MyIter<T> {
+ std::iter::once(t)
+}
+
+fn my_iter2<T>(t: T) -> MyIter<T> {
+ std::iter::once(t)
+}
+
+// param names should not have an effect!
+fn my_iter3<U>(u: U) -> MyIter<U> {
+ std::iter::once(u)
+}
+
+// param position should not have an effect!
+fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
+ std::iter::once(v)
+}
+
+// param names should not have an effect!
+existential type MyOtherIter<T>: Iterator<Item = T>;
+
+fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
+ std::iter::once(u)
+}
+
+trait Trait {}
+existential type GenericBound<'a, T: Trait>: Sized + 'a;
+
+fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
+ t
+}
+
+mod pass_through {
+ pub existential type Passthrough<T>: Sized + 'static;
+
+ fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
+ t
+ }
+}
+
+fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
+ x
+}
--- /dev/null
+// 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() {}
--- /dev/null
+#![feature(existential_type)]
+
+trait UnwrapItemsExt {
+ type Iter;
+ fn unwrap_items(self) -> Self::Iter;
+}
+
+impl<I, T, E> UnwrapItemsExt for I
+where
+ I: Iterator<Item = Result<T, E>>,
+ E: std::fmt::Debug,
+{
+ existential type Iter: Iterator<Item = T>;
+ //~^ ERROR: could not find defining uses
+
+ fn unwrap_items(self) -> Self::Iter {
+ //~^ ERROR: type parameter `T` is part of concrete type
+ //~| ERROR: type parameter `E` is part of concrete type
+ self.map(|x| x.unwrap())
+ }
+}
+
+fn main() {}
--- /dev/null
+error: type parameter `T` is part of concrete type but not used in parameter list for existential type
+ --> $DIR/issue-58887.rs:16:41
+ |
+LL | fn unwrap_items(self) -> Self::Iter {
+ | _________________________________________^
+LL | |
+LL | |
+LL | | self.map(|x| x.unwrap())
+LL | | }
+ | |_____^
+
+error: type parameter `E` is part of concrete type but not used in parameter list for existential type
+ --> $DIR/issue-58887.rs:16:41
+ |
+LL | fn unwrap_items(self) -> Self::Iter {
+ | _________________________________________^
+LL | |
+LL | |
+LL | | self.map(|x| x.unwrap())
+LL | | }
+ | |_____^
+
+error: could not find defining uses
+ --> $DIR/issue-58887.rs:13:5
+ |
+LL | existential type Iter: Iterator<Item = T>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+trait Bug {
+ type Item: Bug;
+
+ const FUN: fn() -> Self::Item;
+}
+
+impl Bug for &() {
+ existential type Item: Bug; //~ ERROR existential types are unstable
+ //~^ ERROR the trait bound `(): Bug` is not satisfied
+ //~^^ ERROR could not find defining uses
+
+ const FUN: fn() -> Self::Item = || ();
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: existential types are unstable
+ --> $DIR/issue-60371.rs:8:5
+ |
+LL | existential type Item: Bug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/63063
+ = help: add `#![feature(existential_type)]` to the crate attributes to enable
+
+error[E0277]: the trait bound `(): Bug` is not satisfied
+ --> $DIR/issue-60371.rs:8:5
+ |
+LL | existential type Item: Bug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <&() as Bug>
+ = note: the return type of a function must have a statically known size
+
+error: could not find defining uses
+ --> $DIR/issue-60371.rs:8:5
+ |
+LL | existential type Item: Bug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// 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
+}
--- /dev/null
+#![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())
+ }
+}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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)]
+ | ^^^^^^^^^^^^^^
+
--- /dev/null
+// 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() {}
--- /dev/null
+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)]
+ | ^^^^^^^^^^^^^^
+
+++ /dev/null
-// 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() {}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+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`.
--- /dev/null
+// 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];
+}
--- /dev/null
+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
+
--- /dev/null
+// 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 @ ..
+ => {}
+ }
+}
description = """
Hack for the compiler's own build system
"""
+edition = "2018"
[lib]
path = "lib.rs"
--- /dev/null
+//! 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()
+ );
+ }
+ },
+ );
+}
pub mod errors;
pub mod features;
pub mod cargo;
+pub mod edition;
pub mod pal;
pub mod deps;
pub mod extdeps;
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);