Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,7 @@ dependencies = [
name = "panic_abort"
version = "0.0.0"
dependencies = [
"alloc",
"cfg-if 0.1.10",
"compiler_builtins",
"core",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ impl DiagnosticSpanLine {
h_end: usize,
) -> DiagnosticSpanLine {
DiagnosticSpanLine {
text: sf.get_line(index).map_or(String::new(), |l| l.into_owned()),
text: sf.get_line(index).map_or_else(String::new, |l| l.into_owned()),
highlight_start: h_start,
highlight_end: h_end,
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,10 @@ impl<'tcx> InstanceDef<'tcx> {
// drops of `Option::None` before LTO. We also respect the intent of
// `#[inline]` on `Drop::drop` implementations.
return ty.ty_adt_def().map_or(true, |adt_def| {
adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| {
tcx.codegen_fn_attrs(dtor.did).requests_inline()
})
adt_def.destructor(tcx).map_or_else(
|| adt_def.is_enum(),
|dtor| tcx.codegen_fn_attrs(dtor.did).requests_inline(),
)
});
}
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/query/on_disk_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ impl<'sess> OnDiskCache<'sess> {
) {
let mut current_diagnostics = self.current_diagnostics.borrow_mut();

let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new());
let x = current_diagnostics.entry(dep_node_index).or_default();

x.extend(Into::<Vec<_>>::into(diagnostics));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl OutlivesSuggestionBuilder {
debug!("Collected {:?}: {:?}", fr, outlived_fr);

// Add to set of constraints for final help note.
self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
self.constraints_to_add.entry(fr).or_default().push(outlived_fr);
}

/// Emit an intermediate note on the given `Diagnostic` if the involved regions are
Expand Down
45 changes: 35 additions & 10 deletions compiler/rustc_parse/src/parser/attr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,46 @@ impl<'a> Parser<'a> {
}
impl CreateTokenStream for LazyTokenStreamImpl {
fn create_token_stream(&self) -> TokenStream {
// The token produced by the final call to `next` or `next_desugared`
// was not actually consumed by the callback. The combination
// of chaining the initial token and using `take` produces the desired
// result - we produce an empty `TokenStream` if no calls were made,
// and omit the final token otherwise.
if self.num_calls == 0 {
return TokenStream::new(vec![]);
}

let mut cursor_snapshot = self.cursor_snapshot.clone();
let tokens = std::iter::once(self.start_token.clone())
.chain((0..self.num_calls).map(|_| {
if self.desugar_doc_comments {
// Don't skip `None` delimiters, since we want to pass them to
// proc macros. Normally, we'll end up capturing `TokenKind::Interpolated`,
// which gets converted to a `None`-delimited group when we invoke
// a proc-macro. However, it's possible to already have a `None`-delimited
// group in the stream (such as when parsing the output of a proc-macro,
// or in certain unusual cases with cross-crate `macro_rules!` macros).
cursor_snapshot.skip_none_delims = false;

// The token produced by the final call to `next` or `next_desugared`
// was not actually consumed by the callback.
let num_calls = self.num_calls - 1;
let mut i = 0;
let tokens =
std::iter::once(self.start_token.clone()).chain(std::iter::from_fn(|| {
if i >= num_calls {
return None;
}

let token = if self.desugar_doc_comments {
cursor_snapshot.next_desugared()
} else {
cursor_snapshot.next()
};

// When the `LazyTokenStreamImpl` was original produced, we did *not*
// include `NoDelim` tokens in `num_calls`, since they are normally ignored
// by the parser. Therefore, we only increment our counter for other types of tokens.
if !matches!(
token.0.kind,
token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
) {
i += 1;
}
}))
.take(self.num_calls);
Some(token)
}));

make_token_stream(tokens, self.append_unglued_token.clone())
}
Expand Down
25 changes: 20 additions & 5 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ struct TokenCursor {
// appended to the captured stream when
// we evaluate a `LazyTokenStream`
append_unglued_token: Option<TreeAndSpacing>,
// If `true`, skip the delimiters for `None`-delimited groups,
// and just yield the inner tokens. This is `true` during
// normal parsing, since the parser code is not currently prepared
// to handle `None` delimiters. When capturing a `TokenStream`,
// however, we want to handle `None`-delimiters, since
// proc-macros always see `None`-delimited groups.
skip_none_delims: bool,
}

#[derive(Clone)]
Expand All @@ -184,13 +191,13 @@ struct TokenCursorFrame {
}

impl TokenCursorFrame {
fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream, skip_none_delims: bool) -> Self {
TokenCursorFrame {
delim,
span,
open_delim: delim == token::NoDelim,
open_delim: delim == token::NoDelim && skip_none_delims,
tree_cursor: tts.into_trees(),
close_delim: delim == token::NoDelim,
close_delim: delim == token::NoDelim && skip_none_delims,
}
}
}
Expand Down Expand Up @@ -218,7 +225,7 @@ impl TokenCursor {
return (token, spacing);
}
TokenTree::Delimited(sp, delim, tts) => {
let frame = TokenCursorFrame::new(sp, delim, tts);
let frame = TokenCursorFrame::new(sp, delim, tts, self.skip_none_delims);
self.stack.push(mem::replace(&mut self.frame, frame));
}
}
Expand Down Expand Up @@ -276,6 +283,7 @@ impl TokenCursor {
.cloned()
.collect::<TokenStream>()
},
self.skip_none_delims,
),
));

Expand Down Expand Up @@ -371,12 +379,19 @@ impl<'a> Parser<'a> {
prev_token: Token::dummy(),
restrictions: Restrictions::empty(),
expected_tokens: Vec::new(),
// Skip over the delimiters for `None`-delimited groups
token_cursor: TokenCursor {
frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens),
frame: TokenCursorFrame::new(
DelimSpan::dummy(),
token::NoDelim,
tokens,
/* skip_none_delims */ true,
),
stack: Vec::new(),
num_next_calls: 0,
desugar_doc_comments,
append_unglued_token: None,
skip_none_delims: true,
},
desugar_doc_comments,
unmatched_angle_bracket_count: 0,
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,13 @@ impl<'a> Iterator for Parser<'a> {
Some(String(self.string(pos + 1)))
} else {
let arg = self.argument();
if let Some(end) = self.must_consume('}') {
let start = self.to_span_index(pos);
let end = self.to_span_index(end + 1);
if let Some(rbrace_byte_idx) = self.must_consume('}') {
let lbrace_inner_offset = self.to_span_index(pos);
let rbrace_inner_offset = self.to_span_index(rbrace_byte_idx);
if self.is_literal {
self.arg_places.push(start.to(end));
self.arg_places.push(
lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)),
);
}
}
Some(NextArgument(arg))
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2327,7 +2327,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {

ExprKind::Call(ref callee, ref arguments) => {
self.resolve_expr(callee, Some(expr));
let const_args = self.r.legacy_const_generic_args(callee).unwrap_or(Vec::new());
let const_args = self.r.legacy_const_generic_args(callee).unwrap_or_default();
for (idx, argument) in arguments.iter().enumerate() {
// Constant arguments need to be treated as AnonConst since
// that is how they will be later lowered to HIR.
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
_ => None,
}
.map_or(String::new(), |res| format!("{} ", res.descr()));
.map_or_else(String::new, |res| format!("{} ", res.descr()));
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
};
(
Expand Down Expand Up @@ -1042,10 +1042,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
if let Some(span) = self.def_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
let fields =
self.r.field_names.get(&def_id).map_or("/* fields */".to_string(), |fields| {
vec!["_"; fields.len()].join(", ")
});
let fields = self.r.field_names.get(&def_id).map_or_else(
|| "/* fields */".to_string(),
|fields| vec!["_"; fields.len()].join(", "),
);
err.span_suggestion(
span,
"use the tuple variant pattern syntax instead",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,61 +163,65 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::from_desugaring, None));
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
}
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
// but the parser won't allow you to use it
flags.push((sym::_Self, Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
}

for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
trait_ref.substs[param.index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
let name = param.name;
flags.push((name, Some(value)));
}
// Add all types without trimmed paths.
ty::print::with_no_trimmed_paths(|| {
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
// but the parser won't allow you to use it
flags.push((sym::_Self, Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
}

if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
flags.push((sym::crate_local, None));
}
for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
trait_ref.substs[param.index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
let name = param.name;
flags.push((name, Some(value)));
}

// Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() {
flags.push((sym::_Self, Some("{integral}".to_owned())));
}
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
flags.push((sym::crate_local, None));
}

if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
let type_string = self.tcx.type_of(def.did).to_string();
flags.push((sym::_Self, Some(format!("[{}]", type_string))));
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() {
flags.push((sym::_Self, Some("{integral}".to_owned())));
}

let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
let string = match len {
Some(n) => format!("[{}; {}]", type_string, n),
None => format!("[{}; _]", type_string),
};
flags.push((sym::_Self, Some(string)));
if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
let type_string = self.tcx.type_of(def.did).to_string();
flags.push((sym::_Self, Some(format!("[{}]", type_string))));

let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
let string = match len {
Some(n) => format!("[{}; {}]", type_string, n),
None => format!("[{}; _]", type_string),
};
flags.push((sym::_Self, Some(string)));
}
}
}
if let ty::Dynamic(traits, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
if let ty::Dynamic(traits, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
}
}
}
}
});

if let Ok(Some(command)) =
OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
),
on(
_Self = "[]",
label = "borrow the array with `&` or call `.iter()` on it to iterate over it",
note = "arrays are not iterators, but slices like the following are: `&[1, 2, 3]`"
label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`",
note = "see <https://github.com/rust-lang/rust/pull/65819> for more details"
),
on(
_Self = "{integral}",
Expand Down
26 changes: 26 additions & 0 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![stable(feature = "rust1", since = "1.0.0")]

use crate::ascii;
use crate::intrinsics;
use crate::mem;
use crate::str::FromStr;
Expand Down Expand Up @@ -661,6 +662,31 @@ impl u8 {
pub const fn is_ascii_control(&self) -> bool {
matches!(*self, b'\0'..=b'\x1F' | b'\x7F')
}

/// Returns an iterator that produces an escaped version of a `u8`,
/// treating it as an ASCII character.
///
/// The behavior is identical to [`ascii::escape_default`].
///
/// # Examples
///
/// ```
/// #![feature(inherent_ascii_escape)]
///
/// assert_eq!("0", b'0'.escape_ascii().to_string());
/// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
/// assert_eq!("\\r", b'\r'.escape_ascii().to_string());
/// assert_eq!("\\n", b'\n'.escape_ascii().to_string());
/// assert_eq!("\\'", b'\''.escape_ascii().to_string());
/// assert_eq!("\\\"", b'"'.escape_ascii().to_string());
/// assert_eq!("\\\\", b'\\'.escape_ascii().to_string());
/// assert_eq!("\\x9d", b'\x9d'.escape_ascii().to_string());
/// ```
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
#[inline]
pub fn escape_ascii(&self) -> ascii::EscapeDefault {
ascii::escape_default(*self)
}
}

#[lang = "u16"]
Expand Down
Loading