"humantime 2.0.1",
"ignore",
"im-rc",
- "itertools 0.10.1",
+ "itertools",
"jobserver",
"lazy_static",
"lazycell",
"libgit2-sys",
"log",
"memchr",
- "num_cpus",
"opener",
"openssl",
"os_info",
"flate2",
"git2",
"glob",
- "itertools 0.10.1",
+ "itertools",
"lazy_static",
"remove_dir_all",
"serde_json",
"chalk-ir",
"ena",
"indexmap",
- "itertools 0.10.1",
+ "itertools",
"petgraph",
"rustc-hash",
"tracing",
"filetime",
"futures 0.3.19",
"if_chain",
- "itertools 0.10.1",
+ "itertools",
"num_cpus",
"parking_lot",
"quote",
"cargo_metadata",
"clap 2.34.0",
"indoc",
- "itertools 0.10.1",
+ "itertools",
"opener",
"regex",
"shell-escape",
"cargo_metadata",
"clippy_utils",
"if_chain",
- "itertools 0.10.1",
+ "itertools",
"pulldown-cmark",
"quine-mc_cluskey",
"regex-syntax",
[[package]]
name = "git2"
-version = "0.13.23"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
+checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
dependencies = [
"bitflags",
"libc",
[[package]]
name = "git2-curl"
-version = "0.14.1"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
+checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
dependencies = [
"curl",
"git2",
"cfg-if 1.0.0",
]
-[[package]]
-name = "itertools"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itertools"
version = "0.10.1"
[[package]]
name = "libgit2-sys"
-version = "0.12.24+1.3.0"
+version = "0.13.1+1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
+checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
dependencies = [
"cc",
"libc",
[[package]]
name = "minifier"
-version = "0.0.42"
+version = "0.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
+checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e"
dependencies = [
"macro-utils",
]
"futures 0.3.19",
"heck",
"home",
- "itertools 0.10.1",
+ "itertools",
"jsonrpc-core",
"lazy_static",
"log",
"derive-new",
"env_logger 0.9.0",
"fst",
- "itertools 0.10.1",
+ "itertools",
"json",
"lazy_static",
"log",
name = "rustc_ast_passes"
version = "0.0.0"
dependencies = [
- "itertools 0.10.1",
+ "itertools",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr",
version = "0.0.0"
dependencies = [
"either",
- "itertools 0.10.1",
+ "itertools",
"polonius-engine",
"rustc_const_eval",
"rustc_data_structures",
dependencies = [
"bitflags",
"cc",
- "itertools 0.10.1",
+ "itertools",
"jobserver",
"libc",
"object 0.28.1",
version = "0.0.0"
dependencies = [
"coverage_test_macros",
- "itertools 0.10.1",
+ "itertools",
"rustc_ast",
"rustc_attr",
"rustc_const_eval",
"askama",
"atty",
"expect-test",
- "itertools 0.10.1",
+ "itertools",
"minifier",
"pulldown-cmark",
"rayon",
"env_logger 0.8.4",
"getopts",
"ignore",
- "itertools 0.9.0",
+ "itertools",
"lazy_static",
"log",
"regex",
dependencies = [
"combine",
"indexmap",
- "itertools 0.10.1",
+ "itertools",
"kstring",
"serde",
]
[workspace]
+default-members = ["src/bootstrap"]
members = [
"src/bootstrap",
"compiler/rustc",
impl LitKind {
/// Converts literal token into a semantic literal.
- fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
+ pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
let token::Lit { kind, symbol, suffix } = lit;
if suffix.is_some() && !kind.may_have_suffix() {
return Err(LitError::InvalidSuffix);
)),
_ => None,
});
- if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
- itctx
- {
+ if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
capturable_lifetimes.extend(lt_def_names.clone());
}
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
- if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
- itctx
- {
+ if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
for param in lt_def_names {
capturable_lifetimes.remove(¶m);
}
edition = "2021"
[dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
/// certain positions.
is_assoc_ty_bound_banned: bool,
- /// Used to allow `let` expressions in certain syntactic locations.
- is_let_allowed: bool,
+ /// See [ForbiddenLetReason]
+ forbidden_let_reason: Option<ForbiddenLetReason>,
lint_buffer: &'a mut LintBuffer,
}
self.is_tilde_const_allowed = old;
}
- fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
- let old = mem::replace(&mut self.is_let_allowed, allowed);
+ fn with_let_management(
+ &mut self,
+ forbidden_let_reason: Option<ForbiddenLetReason>,
+ f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
+ ) {
+ let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
f(self, old);
- self.is_let_allowed = old;
+ self.forbidden_let_reason = old;
}
/// Emits an error banning the `let` expression provided in the given location.
- fn ban_let_expr(&self, expr: &'a Expr) {
+ fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
let sess = &self.session;
if sess.opts.unstable_features.is_nightly_build() {
- sess.struct_span_err(expr.span, "`let` expressions are not supported here")
- .note("only supported directly in conditions of `if`- and `while`-expressions")
- .note("as well as when nested within `&&` and parentheses in those conditions")
- .emit();
+ let err = "`let` expressions are not supported here";
+ let mut diag = sess.struct_span_err(expr.span, err);
+ diag.note("only supported directly in conditions of `if` and `while` expressions");
+ diag.note("as well as when nested within `&&` and parentheses in those conditions");
+ if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
+ diag.span_note(span, "`||` operators are not allowed in let chain expressions");
+ }
+ diag.emit();
} else {
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
.note("variable declaration using `let` is a statement")
}
fn visit_expr(&mut self, expr: &'a Expr) {
- self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
- ExprKind::If(cond, then, opt_else) => {
- this.visit_block(then);
- walk_list!(this, visit_expr, opt_else);
- this.with_let_allowed(true, |this, _| this.visit_expr(cond));
- return;
- }
- ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
- ExprKind::Match(expr, arms) => {
- this.visit_expr(expr);
- for arm in arms {
- this.visit_expr(&arm.body);
- this.visit_pat(&arm.pat);
- walk_list!(this, visit_attribute, &arm.attrs);
- if let Some(ref guard) = arm.guard {
- if let ExprKind::Let(_, ref expr, _) = guard.kind {
- this.with_let_allowed(true, |this, _| this.visit_expr(expr));
+ self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
+ match &expr.kind {
+ ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
+ let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
+ this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
+ this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
+ }
+ ExprKind::If(cond, then, opt_else) => {
+ this.visit_block(then);
+ walk_list!(this, visit_expr, opt_else);
+ this.with_let_management(None, |this, _| this.visit_expr(cond));
+ return;
+ }
+ ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
+ this.ban_let_expr(expr, elem);
+ },
+ ExprKind::Match(scrutinee, arms) => {
+ this.visit_expr(scrutinee);
+ for arm in arms {
+ this.visit_expr(&arm.body);
+ this.visit_pat(&arm.pat);
+ walk_list!(this, visit_attribute, &arm.attrs);
+ if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
+ this.with_let_management(None, |this, _| {
+ this.visit_expr(guard_expr)
+ });
return;
}
}
}
+ ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
+ this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
+ return;
+ }
+ ExprKind::While(cond, then, opt_label) => {
+ walk_list!(this, visit_label, opt_label);
+ this.visit_block(then);
+ this.with_let_management(None, |this, _| this.visit_expr(cond));
+ return;
+ }
+ _ => visit::walk_expr(this, expr),
}
- ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
- this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
- return;
- }
- ExprKind::While(cond, then, opt_label) => {
- walk_list!(this, visit_label, opt_label);
- this.visit_block(then);
- this.with_let_allowed(true, |this, _| this.visit_expr(cond));
- return;
- }
- _ => visit::walk_expr(this, expr),
});
}
is_tilde_const_allowed: false,
is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false,
- is_let_allowed: false,
+ forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
lint_buffer: lints,
};
visit::walk_crate(&mut validator, krate);
validator.has_proc_macro_decls
}
+
+/// Used to forbid `let` expressions in certain syntactic locations.
+#[derive(Clone, Copy)]
+enum ForbiddenLetReason {
+ /// A let chain with the `||` operator
+ ForbiddenWithOr(Span),
+ /// `let` is not valid and the source environment is not important
+ GenericForbidden,
+}
)
.emit();
}
- } else {
- if attr.has_name(sym::deprecated) {
- self.sess
- .struct_span_err(attr.span, "`#[deprecated]` cannot be used in staged API")
- .span_label(attr.span, "use `#[rustc_deprecated]` instead")
- .emit();
- }
}
}
//!
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
-#![feature(iter_is_partitioned)]
+#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
+#![feature(if_let_guard)]
+#![feature(iter_is_partitioned)]
+#![feature(let_chains)]
#![feature(let_else)]
#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
pub mod ast_validation;
pub mod feature_gate;
{
let mut depr: Option<(Deprecation, Span)> = None;
let diagnostic = &sess.parse_sess.span_diagnostic;
+ let is_rustc = sess.features_untracked().staged_api;
'outer: for attr in attrs_iter {
if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
continue 'outer;
}
}
- sym::note if attr.has_name(sym::deprecated) => {
+ sym::note => {
if !get(mi, &mut note) {
continue 'outer;
}
}
+ // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
+ // error specific to the renaming would be a good idea as well.
sym::reason if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
- sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
+ sym::suggestion => {
+ if !sess.features_untracked().deprecated_suggestion {
+ let mut diag = sess.struct_span_err(
+ mi.span,
+ "suggestions on deprecated items are unstable",
+ );
+ if sess.is_nightly_build() {
+ diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
+ }
+ // FIXME(jhpratt) change this to an actual tracking issue
+ diag.note("see #XXX for more details").emit();
+ }
+
if !get(mi, &mut suggestion) {
continue 'outer;
}
if attr.has_name(sym::deprecated) {
&["since", "note"]
} else {
- &["since", "reason", "suggestion"]
+ &["since", "note", "suggestion"]
},
),
);
}
}
- if suggestion.is_some() && attr.has_name(sym::deprecated) {
- unreachable!("only allowed on rustc_deprecated")
- }
-
- if attr.has_name(sym::rustc_deprecated) {
+ if is_rustc {
if since.is_none() {
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
continue;
}
if note.is_none() {
- struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+ struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
continue;
}
}
- let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
- depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
+ depr = Some((
+ Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
+ attr.span,
+ ));
}
depr
[dependencies]
either = "1.5.0"
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
polonius-engine = "0.13.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
use either::Either;
-use rustc_const_eval::util::{CallDesugaringKind, CallKind};
+use rustc_const_eval::util::CallKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::symbol::sym;
-use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::TraitEngineExt as _;
is_loop_move = true;
}
- if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
- let place_name = self
- .describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(|| "value".to_owned());
- match kind {
- CallKind::FnCall { fn_trait_id, .. }
- if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
- {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this call{}",
- place_name, partially_str, loop_message
- ),
- );
- err.span_note(
- var_span,
- "this value implements `FnOnce`, which causes it to be moved when called",
- );
- }
- CallKind::Operator { self_arg, .. } => {
- let self_arg = self_arg.unwrap();
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to usage in operator{}",
- place_name, partially_str, loop_message
- ),
- );
- if self.fn_self_span_reported.insert(fn_span) {
- err.span_note(
- // Check whether the source is accessible
- if self
- .infcx
- .tcx
- .sess
- .source_map()
- .span_to_snippet(self_arg.span)
- .is_ok()
- {
- self_arg.span
- } else {
- fn_call_span
- },
- "calling this operator moves the left-hand side",
- );
- }
- }
- CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
- let self_arg = self_arg.unwrap();
- if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this implicit call to `.into_iter()`{}",
- place_name, partially_str, loop_message
- ),
- );
- let sess = self.infcx.tcx.sess;
- let ty = used_place.ty(self.body, self.infcx.tcx).ty;
- // If we have a `&mut` ref, we need to reborrow.
- if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
- // If we are in a loop this will be suggested later.
- if !is_loop_move {
- err.span_suggestion_verbose(
- move_span.shrink_to_lo(),
- &format!(
- "consider creating a fresh reborrow of {} here",
- self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(
- || "the mutable reference".to_string()
- ),
- ),
- "&mut *".to_string(),
- Applicability::MachineApplicable,
- );
- }
- } else if let Ok(snippet) =
- sess.source_map().span_to_snippet(move_span)
- {
- err.span_suggestion(
- move_span,
- "consider borrowing to avoid moving into the for loop",
- format!("&{}", snippet),
- Applicability::MaybeIncorrect,
- );
- }
- } else {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this method call{}",
- place_name, partially_str, loop_message
- ),
- );
- }
- if is_option_or_result && maybe_reinitialized_locations.is_empty() {
- err.span_suggestion_verbose(
- fn_call_span.shrink_to_lo(),
- "consider calling `.as_ref()` to borrow the type's contents",
- "as_ref().".to_string(),
- Applicability::MachineApplicable,
- );
- }
- // Avoid pointing to the same function in multiple different
- // error messages.
- if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
- {
- err.span_note(
- self_arg.span,
- &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
- );
- }
- }
- // Other desugarings takes &self, which cannot cause a move
- _ => unreachable!(),
- }
- } else {
- err.span_label(
- move_span,
- format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
- );
- // If the move error occurs due to a loop, don't show
- // another message for the same span
- if loop_message.is_empty() {
- move_spans.var_span_label(
- &mut err,
- format!(
- "variable {}moved due to use{}",
- partially_str,
- move_spans.describe()
- ),
- "moved",
- );
- }
- }
+ self.explain_captures(
+ &mut err,
+ span,
+ move_span,
+ move_spans,
+ *moved_place,
+ Some(used_place),
+ partially_str,
+ loop_message,
+ move_msg,
+ is_loop_move,
+ maybe_reinitialized_locations.is_empty(),
+ );
if let (UseSpans::PatUse(span), []) =
(move_spans, &maybe_reinitialized_locations[..])
self.mir_hir_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
- fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
- let errors = fulfill_cx.select_where_possible(&infcx);
+ fulfill_cx.register_bound(
+ &infcx,
+ self.param_env,
+ // Erase any region vids from the type, which may not be resolved
+ infcx.tcx.erase_regions(ty),
+ copy_did,
+ cause,
+ );
+ // Select all, including ambiguous predicates
+ let errors = fulfill_cx.select_all_or_error(&infcx);
// Only emit suggestion if all required predicates are on generic
errors
//! Borrow checker diagnostics.
-use rustc_const_eval::util::call_kind;
-use rustc_errors::Diagnostic;
+use rustc_const_eval::util::{call_kind, CallDesugaringKind};
+use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_hir::GeneratorKind;
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
BorrowedContentSource::DerefSharedRef
}
}
-}
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
/// name where required.
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
let span = self.body.source_info(borrow.reserve_location).span;
self.borrow_spans(span, borrow.reserve_location)
}
+
+ fn explain_captures(
+ &mut self,
+ err: &mut Diagnostic,
+ span: Span,
+ move_span: Span,
+ move_spans: UseSpans<'tcx>,
+ moved_place: Place<'tcx>,
+ used_place: Option<PlaceRef<'tcx>>,
+ partially_str: &str,
+ loop_message: &str,
+ move_msg: &str,
+ is_loop_move: bool,
+ maybe_reinitialized_locations_is_empty: bool,
+ ) {
+ if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+ let place_name = self
+ .describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "value".to_owned());
+ match kind {
+ CallKind::FnCall { fn_trait_id, .. }
+ if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+ {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this call{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ err.span_note(
+ var_span,
+ "this value implements `FnOnce`, which causes it to be moved when called",
+ );
+ }
+ CallKind::Operator { self_arg, .. } => {
+ let self_arg = self_arg.unwrap();
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to usage in operator{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ if self.fn_self_span_reported.insert(fn_span) {
+ err.span_note(
+ // Check whether the source is accessible
+ if self
+ .infcx
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(self_arg.span)
+ .is_ok()
+ {
+ self_arg.span
+ } else {
+ fn_call_span
+ },
+ "calling this operator moves the left-hand side",
+ );
+ }
+ }
+ CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+ let self_arg = self_arg.unwrap();
+ if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
+ let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+ let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+ Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+ type_known_to_meet_bound_modulo_regions(
+ &infcx,
+ self.param_env,
+ infcx.tcx.mk_imm_ref(
+ infcx.tcx.lifetimes.re_erased,
+ infcx.tcx.erase_regions(ty),
+ ),
+ def_id,
+ DUMMY_SP,
+ )
+ }),
+ _ => false,
+ };
+ if suggest {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider iterating over a slice of the `{}`'s content to \
+ avoid moving into the `for` loop",
+ ty,
+ ),
+ "&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this implicit call to `.into_iter()`{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ // If we have a `&mut` ref, we need to reborrow.
+ if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
+ .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+ {
+ // If we are in a loop this will be suggested later.
+ if !is_loop_move {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "the mutable reference".to_string()),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ } else {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this method call{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ }
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "consider calling `.as_ref()` to borrow the type's contents",
+ "as_ref().".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ // Avoid pointing to the same function in multiple different
+ // error messages.
+ if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+ err.span_note(
+ self_arg.span,
+ &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+ );
+ }
+ }
+ // Other desugarings takes &self, which cannot cause a move
+ _ => {}
+ }
+ } else {
+ if move_span != span || !loop_message.is_empty() {
+ err.span_label(
+ move_span,
+ format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+ );
+ }
+ // If the move error occurs due to a loop, don't show
+ // another message for the same span
+ if loop_message.is_empty() {
+ move_spans.var_span_label(
+ err,
+ format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+ "moved",
+ );
+ }
+ }
+ }
}
-use rustc_const_eval::util::CallDesugaringKind;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty;
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::{sym, Span, DUMMY_SP};
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_span::{sym, Span};
-use crate::diagnostics::{CallKind, UseSpans};
+use crate::diagnostics::UseSpans;
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
".as_ref()".to_string(),
Applicability::MaybeIncorrect,
);
- } else if let Some(UseSpans::FnSelfUse {
- kind:
- CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
- ..
- }) = use_spans
- {
- let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
- Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
- type_known_to_meet_bound_modulo_regions(
- &infcx,
- self.param_env,
- infcx
- .tcx
- .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)),
- def_id,
- DUMMY_SP,
- )
- }),
- _ => false,
- };
- if suggest {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &format!("consider iterating over a slice of the `{}`'s content", ty),
- "&".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
+ } else if let Some(use_spans) = use_spans {
+ self.explain_captures(
+ &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+ );
}
err
}
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
- use_spans.var_span_label(
- err,
- format!("move occurs due to use{}", use_spans.describe()),
- "moved",
- );
}
}
}
PlaceRef {
local,
projection:
- [
- proj_base @ ..,
+ &[
+ ref proj_base @ ..,
ProjectionElem::Deref,
ProjectionElem::Field(field, _),
ProjectionElem::Deref,
Applicability::MachineApplicable,
);
let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
}
}
let tcx = self.infcx.tcx;
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
{
- if let ty::Closure(id, _) = ty.kind() {
+ if let ty::Closure(id, _) = *ty.kind() {
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
}
}
fn show_mutating_upvar(
&self,
tcx: TyCtxt<'_>,
- id: &hir::def_id::DefId,
+ id: hir::def_id::DefId,
the_place_err: PlaceRef<'tcx>,
err: &mut Diagnostic,
) {
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
let root_hir_id = upvar_id.var_path.hir_id;
// we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
- let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
+ let captured_places = tables.closure_min_captures[&id].get(&root_hir_id).unwrap();
let origin_projection = closure_kind_origin
.projections
fn get_mut_span_in_struct_field<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
- field: &mir::Field,
+ field: mir::Field,
) -> Option<Span> {
// Expect our local to be a reference to a struct of some kind.
if let ty::Ref(_, ty, _) = ty.kind()
}
impl LocationIndex {
- fn is_start(&self) -> bool {
+ fn is_start(self) -> bool {
// even indices are start points; odd indices are mid points
(self.index() % 2) == 0
}
) {
all_facts
.path_is_var
- .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v)));
+ .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
for (child, move_path) in move_data.move_paths.iter_enumerated() {
if let Some(parent) = move_path.parent {
}
}
- for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() {
+ for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
if body.local_kind(local) != LocalKind::Arg {
// Non-arguments start out deinitialised; we simulate this with an
// initial move:
fr1={:?}, fr2={:?}",
fr1, fr2
);
- all_facts.known_placeholder_subset.push((*fr1, *fr2));
+ all_facts.known_placeholder_subset.push((fr1, fr2));
}
}
}
debug!("try_promote_type_test: ur={:?}", ur);
- let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur);
+ let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
// This is slightly too conservative. To show T: '1, given `'2: '1`
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
// avoid potential non-determinism we approximate this by requiring
// T: '1 and T: '2.
- for &upper_bound in non_local_ub {
+ for upper_bound in non_local_ub {
debug_assert!(self.universal_regions.is_universal_region(upper_bound));
debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
let shorter_fr_plus =
- self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
+ self.universal_region_relations.non_local_upper_bounds(shorter_fr);
debug!(
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
shorter_fr_plus
);
- for &&fr in &shorter_fr_plus {
+ for fr in shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
assert!(self.universal_regions.is_universal_region(fr1));
assert!(self.universal_regions.is_universal_region(fr2));
- *self
- .inverse_outlives
- .postdom_upper_bound(&fr1, &fr2)
- .unwrap_or(&self.universal_regions.fr_static)
+ self.inverse_outlives
+ .postdom_upper_bound(fr1, fr2)
+ .unwrap_or(self.universal_regions.fr_static)
}
/// Finds an "upper bound" for `fr` that is not local. In other
/// outlives `fr` and (b) is not local.
///
/// (*) If there are multiple competing choices, we return all of them.
- crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
+ crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
debug!("non_local_upper_bound(fr={:?})", fr);
let res = self.non_local_bounds(&self.inverse_outlives, fr);
assert!(!res.is_empty(), "can't find an upper bound!?");
/// Returns the "postdominating" bound of the set of
/// `non_local_upper_bounds` for the given region.
crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
- let upper_bounds = self.non_local_upper_bounds(&fr);
+ let upper_bounds = self.non_local_upper_bounds(fr);
// In case we find more than one, reduce to one for
// convenience. This is to prevent us from generating more
debug!("non_local_bound: post_dom={:?}", post_dom);
post_dom
- .and_then(|&post_dom| {
+ .and_then(|post_dom| {
// If the mutual immediate postdom is not local, then
// there is no non-local result we can return.
if !self.universal_regions.is_local_free_region(post_dom) {
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
debug!("non_local_lower_bound(fr={:?})", fr);
- let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
+ let lower_bounds = self.non_local_bounds(&self.outlives, fr);
// In case we find more than one, reduce to one for
// convenience. This is to prevent us from generating more
debug!("non_local_bound: post_dom={:?}", post_dom);
- post_dom.and_then(|&post_dom| {
+ post_dom.and_then(|post_dom| {
// If the mutual immediate postdom is not local, then
// there is no non-local result we can return.
if !self.universal_regions.is_local_free_region(post_dom) {
fn non_local_bounds<'a>(
&self,
relation: &'a TransitiveRelation<RegionVid>,
- fr0: &'a RegionVid,
- ) -> Vec<&'a RegionVid> {
+ fr0: RegionVid,
+ ) -> Vec<RegionVid> {
// This method assumes that `fr0` is one of the universally
// quantified region variables.
- assert!(self.universal_regions.is_universal_region(*fr0));
+ assert!(self.universal_regions.is_universal_region(fr0));
let mut external_parents = vec![];
let mut queue = vec![fr0];
// Keep expanding `fr` into its parents until we reach
// non-local regions.
while let Some(fr) = queue.pop() {
- if !self.universal_regions.is_local_free_region(*fr) {
+ if !self.universal_regions.is_local_free_region(fr) {
external_parents.push(fr);
continue;
}
///
/// This will only ever be true for universally quantified regions.
crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
- self.outlives.contains(&fr1, &fr2)
+ self.outlives.contains(fr1, fr2)
}
/// Returns a vector of free regions `x` such that `fr1: x` is
/// known to hold.
- crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
- self.outlives.reachable_from(&fr1)
+ crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
+ self.outlives.reachable_from(fr1)
}
/// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
- crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
+ crate fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
self.outlives.base_edges()
}
}
tcx,
self.param_env,
proj,
- |this, field, &()| {
+ |this, field, ()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
return;
}
let TyAndLayout { ty, layout } = place.layout();
- let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } =
- layout;
+ let rustc_target::abi::LayoutS {
+ size,
+ align,
+ abi: _,
+ variants: _,
+ fields: _,
+ largest_niche: _,
+ } = layout.0.0;
let (kind, extra) = match *place.inner() {
CPlaceInner::Var(place_local, var) => {
use rustc_errors::ErrorGuaranteed;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
- read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+ read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use rustc_middle::ty::ConstKind;
use rustc_span::DUMMY_SP;
&mut fx.constants_cx,
fx.module,
alloc_id,
- alloc.mutability,
+ alloc.inner().mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
pub(crate) fn pointer_for_allocation<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
- alloc: &'tcx Allocation,
+ alloc: ConstAllocation<'tcx>,
) -> crate::pointer::Pointer {
let alloc_id = fx.tcx.create_memory_alloc(alloc);
- let data_id =
- data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
+ let data_id = data_id_for_alloc_id(
+ &mut fx.constants_cx,
+ &mut *fx.module,
+ alloc_id,
+ alloc.inner().mutability,
+ );
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
module
.declare_anonymous_data(
- alloc.mutability == rustc_hir::Mutability::Mut,
+ alloc.inner().mutability == rustc_hir::Mutability::Mut,
false,
)
.unwrap()
}
let mut data_ctx = DataContext::new();
+ let alloc = alloc.inner();
data_ctx.set_align(alloc.align.bytes());
if let Some(section_name) = section_name {
continue;
}
GlobalAlloc::Memory(target_alloc) => {
- data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability)
+ data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
}
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
};
raw_eq, (v lhs_ref, v rhs_ref) {
- let size = fx.layout_of(substs.type_at(0)).layout.size;
+ let size = fx.layout_of(substs.type_at(0)).layout.size();
// FIXME add and use emit_small_memcmp
let is_eq_value =
if size == Size::ZERO {
let idx_bytes = match idx_const {
ConstValue::ByRef { alloc, offset } => {
let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
- alloc.get_bytes(fx, alloc_range(offset, size)).unwrap()
+ alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
}
_ => unreachable!("{:?}", idx_const),
};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::ScalarInt;
use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_span::Symbol;
use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
bytes_in_context(self, bytes)
}
- fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
- // TODO(antoyo): handle null_terminated.
- if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
- return value;
- }
-
- let global = self.global_string(symbol.as_str());
-
- self.const_cstr_cache.borrow_mut().insert(symbol, global);
- global
- }
-
fn global_string(&self, string: &str) -> LValue<'gcc> {
// TODO(antoyo): handle non-null-terminated strings.
let string = self.context.new_string_literal(&*string);
}
fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
- let len = s.as_str().len();
- let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+ let s_str = s.as_str();
+ let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+ self.global_string(s_str)
+ });
+ let len = s_str.len();
+ let cs = self.const_ptrcast(str_global.get_address(None),
self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
);
(cs, self.const_usize(len as u64))
match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_gcc(self, alloc);
+ let alloc = alloc.inner();
let value =
match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
}
}
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
const_alloc_to_gcc(self, alloc)
}
- fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
- assert_eq!(alloc.align, layout.align.abi);
+ fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+ assert_eq!(alloc.inner().align, layout.align.abi);
let ty = self.type_ptr_to(layout.gcc_type(self, true));
let value =
if layout.size == Size::ZERO {
- let value = self.const_usize(alloc.align.bytes());
+ let value = self.const_usize(alloc.inner().align.bytes());
self.context.new_cast(None, value, ty)
}
else {
let init = const_alloc_to_gcc(self, alloc);
- let base_addr = self.static_addr_of(init, alloc.align, None);
+ let base_addr = self.static_addr_of(init, alloc.inner().align, None);
let array = self.const_bitcast(base_addr, self.type_i8p());
let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
}
}
-pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
+ let alloc = alloc.inner();
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
cx.const_struct(&llvals, true)
}
-pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_gcc(cx, alloc), alloc))
}
pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
/// Cache of constant strings,
- pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+ pub const_str_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
/// Cache of globals.
pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
function_instances: Default::default(),
vtables: Default::default(),
const_globals: Default::default(),
- const_cstr_cache: Default::default(),
+ const_str_cache: Default::default(),
globals: Default::default(),
scalar_types: Default::default(),
types: Default::default(),
use rustc_target::abi::Abi::*;
let tp_ty = substs.type_at(0);
let layout = self.layout_of(tp_ty).layout;
- let _use_integer_compare = match layout.abi {
+ let _use_integer_compare = match layout.abi() {
Scalar(_) | ScalarPair(_, _) => true,
Uninhabited | Vector { .. } => false,
Aggregate { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
// so we re-use that same threshold here.
- layout.size <= self.data_layout().pointer_size * 2
+ layout.size() <= self.data_layout().pointer_size * 2
}
};
let a = args[0].immediate();
let b = args[1].immediate();
- if layout.size.bytes() == 0 {
+ if layout.size().bytes() == 0 {
self.const_bool(true)
}
/*else if use_integer_compare {
let void_ptr_type = self.context.new_type::<*const ()>();
let a_ptr = self.bitcast(a, void_ptr_type);
let b_ptr = self.bitcast(b, void_ptr_type);
- let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+ let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
let builtin = self.context.get_builtin_function("memcmp");
let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
//! Set and unset common attributes on LLVM values.
use rustc_codegen_ssa::traits::*;
+use rustc_data_structures::small_str::SmallStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, TyCtxt};
}
}
- if !function_features.is_empty() {
- let global_features = cx.tcx.global_backend_features(()).iter().map(|s| &s[..]);
- let val = global_features
- .chain(function_features.iter().map(|s| &s[..]))
- .intersperse(",")
- .collect::<String>();
- to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &val));
+ let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
+ let function_features = function_features.iter().map(|s| s.as_str());
+ let target_features =
+ global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
+ if !target_features.is_empty() {
+ to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
}
attributes::apply_to_llfn(llfn, Function, &to_add);
info!("linking {:?}", name);
let data = bc_decoded.data();
linker.add(data).map_err(|()| {
- let msg = format!("failed to load bc of {:?}", name);
+ let msg = format!("failed to load bitcode of module {:?}", name);
write::llvm_err(diag_handler, &msg)
})?;
serialized_bitcode.push(bc_decoded);
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::ScalarInt;
use rustc_span::symbol::Symbol;
bytes_in_context(self.llcx, bytes)
}
- fn const_cstr(&self, s: Symbol, null_terminated: bool) -> &'ll Value {
- unsafe {
- if let Some(&llval) = self.const_cstr_cache.borrow().get(&s) {
- return llval;
- }
-
- let s_str = s.as_str();
- let sc = llvm::LLVMConstStringInContext(
- self.llcx,
- s_str.as_ptr() as *const c_char,
- s_str.len() as c_uint,
- !null_terminated as Bool,
- );
- let sym = self.generate_local_symbol_name("str");
- let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
- bug!("symbol `{}` is already defined", sym);
- });
- llvm::LLVMSetInitializer(g, sc);
- llvm::LLVMSetGlobalConstant(g, True);
- llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
-
- self.const_cstr_cache.borrow_mut().insert(s, g);
- g
- }
- }
-
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
assert_eq!(idx as c_uint as u64, idx);
}
fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
- let len = s.as_str().len();
+ let s_str = s.as_str();
+ let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+ let sc = self.const_bytes(s_str.as_bytes());
+ let sym = self.generate_local_symbol_name("str");
+ let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
+ bug!("symbol `{}` is already defined", sym);
+ });
+ unsafe {
+ llvm::LLVMSetInitializer(g, sc);
+ llvm::LLVMSetGlobalConstant(g, True);
+ llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
+ }
+ g
+ });
+ let len = s_str.len();
let cs = consts::ptrcast(
- self.const_cstr(s, false),
+ str_global,
self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
);
(cs, self.const_usize(len as u64))
let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_llvm(self, alloc);
+ let alloc = alloc.inner();
let value = match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
_ => self.static_addr_of(init, alloc.align, None),
}
}
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
const_alloc_to_llvm(self, alloc)
}
fn from_const_alloc(
&self,
layout: TyAndLayout<'tcx>,
- alloc: &Allocation,
+ alloc: ConstAllocation<'tcx>,
offset: Size,
) -> PlaceRef<'tcx, &'ll Value> {
- assert_eq!(alloc.align, layout.align.abi);
+ let alloc_align = alloc.inner().align;
+ assert_eq!(alloc_align, layout.align.abi);
let llty = self.type_ptr_to(layout.llvm_type(self));
let llval = if layout.size == Size::ZERO {
- let llval = self.const_usize(alloc.align.bytes());
+ let llval = self.const_usize(alloc_align.bytes());
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else {
let init = const_alloc_to_llvm(self, alloc);
- let base_addr = self.static_addr_of(init, alloc.align, None);
+ let base_addr = self.static_addr_of(init, alloc_align, None);
let llval = unsafe {
llvm::LLVMRustConstInBoundsGEP2(
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
- read_target_uint, Allocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+ read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
Scalar as InterpScalar,
};
use rustc_middle::mir::mono::MonoItem;
use std::ops::Range;
use tracing::debug;
-pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
+pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
+ let alloc = alloc.inner();
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
pub fn codegen_static_initializer<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
-) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
+) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
// Error has already been reported
return;
};
+ let alloc = alloc.inner();
let g = self.get_static(def_id);
pub vtables:
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
/// Cache of constant strings,
- pub const_cstr_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
+ pub const_str_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
/// Reverse-direction for const ptrs cast from globals.
///
codegen_unit,
instances: Default::default(),
vtables: Default::default(),
- const_cstr_cache: Default::default(),
+ const_str_cache: Default::default(),
const_unsized: Default::default(),
const_globals: Default::default(),
statics_to_rauw: RefCell::new(Vec::new()),
/// call. Since the function is never called, all other `CodeRegion`s can be
/// added as `unreachable_region`s.
fn define_unused_fn(&self, def_id: DefId) {
- let instance = declare_unused_fn(self, &def_id);
+ let instance = declare_unused_fn(self, def_id);
codegen_unused_fn_and_counter(self, instance);
add_unused_function_coverage(self, instance, def_id);
}
}
}
-fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: &DefId) -> Instance<'tcx> {
+fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> {
let tcx = cx.tcx;
let instance = Instance::new(
- *def_id,
- InternalSubsts::for_item(tcx, *def_id, |param, _| {
+ def_id,
+ InternalSubsts::for_item(tcx, def_id, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
}
- ty::Adt(def, _) if def.is_box() => {
+ // Box<T, A> may have a non-ZST allocator A. In that case, we
+ // cannot treat Box<T, A> as just an owned alias of `*mut T`.
+ ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
}
ty::FnDef(..) | ty::FnPtr(_) => subroutine_type_metadata(cx, unique_type_id),
use abi::Abi::*;
let tp_ty = substs.type_at(0);
let layout = self.layout_of(tp_ty).layout;
- let use_integer_compare = match layout.abi {
+ let use_integer_compare = match layout.abi() {
Scalar(_) | ScalarPair(_, _) => true,
Uninhabited | Vector { .. } => false,
Aggregate { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
// so we re-use that same threshold here.
- layout.size <= self.data_layout().pointer_size * 2
+ layout.size() <= self.data_layout().pointer_size * 2
}
};
let a = args[0].immediate();
let b = args[1].immediate();
- if layout.size.bytes() == 0 {
+ if layout.size().bytes() == 0 {
self.const_bool(true)
} else if use_integer_compare {
- let integer_ty = self.type_ix(layout.size.bits());
+ let integer_ty = self.type_ix(layout.size().bits());
let ptr_ty = self.type_ptr_to(integer_ty);
let a_ptr = self.bitcast(a, ptr_ty);
- let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+ let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
let b_ptr = self.bitcast(b, ptr_ty);
- let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+ let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
self.icmp(IntPredicate::IntEQ, a_val, b_val)
} else {
let i8p_ty = self.type_i8p();
let a_ptr = self.bitcast(a, i8p_ty);
let b_ptr = self.bitcast(b, i8p_ty);
- let n = self.const_usize(layout.size.bytes());
+ let n = self.const_usize(layout.size().bytes());
let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
}
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.
- // FIXME: There are some perf issues with the new pass manager
- // when targeting s390x, so it is temporarily disabled for that
- // arch, see https://github.com/rust-lang/rust/issues/89609
- user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
+ // There are some perf issues with the new pass manager when targeting
+ // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
+ // See https://github.com/rust-lang/rust/issues/89609.
+ let min_version = if target_arch == "s390x" { 14 } else { 13 };
+ user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
}
[dependencies]
bitflags = "1.2.1"
cc = "1.0.69"
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
libc = "0.2.50"
jobserver = "0.1.22"
// calculate the range of values for the dataful variant
let dataful_discriminant_range =
- dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
+ dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
let min = dataful_discriminant_range.start;
let min = tag.value.size(&tcx).truncate(min);
use super::BackendTypes;
use crate::mir::place::PlaceRef;
-use rustc_middle::mir::interpret::{Allocation, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::Symbol;
use rustc_target::abi::{self, Size};
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value;
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
fn from_const_alloc(
&self,
layout: TyAndLayout<'tcx>,
- alloc: &Allocation,
+ alloc: ConstAllocation<'tcx>,
offset: Size,
) -> PlaceRef<'tcx, Self::Value>;
"the raw bytes of the constant ({}",
display_allocation(
*ecx.tcx,
- ecx.tcx.global_alloc(alloc_id).unwrap_memory()
+ ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner()
)
));
},
use rustc_target::spec::abi::Abi;
use crate::interpret::{
- self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, OpTy,
- PlaceTy, Scalar, StackPopUnwind,
+ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+ OpTy, PlaceTy, Scalar, StackPopUnwind,
};
use super::error::*;
fn before_access_global(
memory_extra: &MemoryExtra,
alloc_id: AllocId,
- allocation: &Allocation,
+ alloc: ConstAllocation<'tcx>,
static_def_id: Option<DefId>,
is_write: bool,
) -> InterpResult<'tcx> {
+ let alloc = alloc.inner();
if is_write {
// Write access. These are never allowed, but we give a targeted error message.
- if allocation.mutability == Mutability::Not {
+ if alloc.mutability == Mutability::Not {
Err(err_ub!(WriteToReadOnly(alloc_id)).into())
} else {
Err(ConstEvalErrKind::ModifiedGlobal.into())
// But make sure we never accept a read from something mutable, that would be
// unsound. The reason is that as the content of this allocation may be different
// now and at run-time, so if we permit reading now we might return the wrong value.
- assert_eq!(allocation.mutability, Mutability::Not);
+ assert_eq!(alloc.mutability, Mutability::Not);
Ok(())
}
}
let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!(
- tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability,
+ tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability,
Mutability::Not,
"deref_const cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics",
Ok(())
}
- fn misc_cast(
+ pub fn misc_cast(
&self,
src: &ImmTy<'tcx, M::PointerTag>,
cast_ty: Ty<'tcx>,
if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
assert!(src.layout.is_zst());
let discr_layout = self.layout_of(discr.ty)?;
- return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
+ return Ok(self.cast_from_int_like(discr.val, discr_layout, cast_ty).into());
}
}
Variants::Multiple { .. } => {}
}
}
- // # The remaining source values are scalar.
+ // # The remaining source values are scalar and "int-like".
// For all remaining casts, we either
// (a) cast a raw ptr to usize, or
// (b) cast from an integer-like (including bool, char, enums).
// In both cases we want the bits.
let bits = src.to_scalar()?.to_bits(src.layout.size)?;
- Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into())
+ Ok(self.cast_from_int_like(bits, src.layout, cast_ty).into())
}
- pub(super) fn cast_from_scalar(
+ fn cast_from_int_like(
&self,
v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
src_layout: TyAndLayout<'tcx>,
}
/// State of a local variable including a memoized layout
-#[derive(Clone, PartialEq, Eq, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable)]
pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
pub value: LocalValue<Tag>,
/// Don't modify if `Some`, this is only used to prevent computing the layout twice
self.size_and_align_of(&mplace.meta, &mplace.layout)
}
+ #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
pub fn push_stack_frame(
&mut self,
instance: ty::Instance<'tcx>,
return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
+ debug!("body: {:#?}", body);
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
/// `Drop` impls for any locals that have been initialized at this point.
/// The cleanup block ends with a special `Resume` terminator, which will
/// cause us to continue unwinding.
+ #[instrument(skip(self), level = "debug")]
pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
info!(
"popping stack frame ({})",
return Ok(());
}
+ debug!("locals: {:#?}", frame.locals);
+
// Cleanup: deallocate all locals that are backed by an allocation.
for local in &frame.locals {
self.deallocate_local(local.value)?;
Ok(())
}
+ #[instrument(skip(self), level = "debug")]
fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
// All locals have a backing allocation, even if the allocation is empty
use rustc_ast::Mutability;
-use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor};
+use super::{
+ AllocId, Allocation, ConstAllocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy,
+ ValueVisitor,
+};
use crate::const_eval;
pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
alloc.mutability = Mutability::Not;
};
// link the alloc id to the actual allocation
- let alloc = tcx.intern_const_alloc(alloc);
leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id));
+ let alloc = tcx.intern_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
None
}
// pointers, ... So we can't intern them according to their type rules
let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
+ debug!(?todo);
+ debug!("dead_alloc_map: {:#?}", ecx.memory.dead_alloc_map);
while let Some(alloc_id) = todo.pop() {
if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) {
// We can't call the `intern_shallow` method here, as its logic is tailored to safe
}
let alloc = tcx.intern_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
- for &(_, alloc_id) in alloc.relocations().iter() {
+ for &(_, alloc_id) in alloc.inner().relocations().iter() {
if leftover_allocations.insert(alloc_id) {
todo.push(alloc_id);
}
&mut InterpCx<'mir, 'tcx, M>,
&PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ()>,
- ) -> InterpResult<'tcx, &'tcx Allocation> {
+ ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
let dest = self.allocate(layout, MemoryKind::Stack)?;
f(self, &dest.into())?;
let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
sym::type_name => {
ensure_monomorphic_enough(tcx, tp_ty)?;
let alloc = type_name::alloc_type_name(tcx, tp_ty);
- ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
+ ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
}
sym::needs_drop => {
ensure_monomorphic_enough(tcx, tp_ty)?;
sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(&args[0])?;
let r = self.read_immediate(&args[1])?;
- let is_add = intrinsic_name == sym::saturating_add;
- let (val, overflowed, _ty) = self.overflowing_binary_op(
- if is_add { BinOp::Add } else { BinOp::Sub },
+ let val = self.saturating_arith(
+ if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
&l,
&r,
)?;
- let val = if overflowed {
- let size = l.layout.size;
- let num_bits = size.bits();
- if l.layout.abi.is_signed() {
- // For signed ints the saturated value depends on the sign of the first
- // term since the sign of the second term can be inferred from this and
- // the fact that the operation has overflowed (if either is 0 no
- // overflow can occur)
- let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
- let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
- if first_term_positive {
- // Negative overflow not possible since the positive first term
- // can only increase an (in range) negative term for addition
- // or corresponding negated positive term for subtraction
- Scalar::from_uint(
- (1u128 << (num_bits - 1)) - 1, // max positive
- Size::from_bits(num_bits),
- )
- } else {
- // Positive overflow not possible for similar reason
- // max negative
- Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
- }
- } else {
- // unsigned
- if is_add {
- // max unsigned
- Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
- } else {
- // underflow to 0
- Scalar::from_uint(0u128, Size::from_bits(num_bits))
- }
- }
- } else {
- val
- };
self.write_scalar(val, dest)?;
}
sym::discriminant_value => {
self.write_pointer(offset_ptr, dest)?;
}
sym::ptr_offset_from => {
- let a = self.read_immediate(&args[0])?.to_scalar()?;
- let b = self.read_immediate(&args[1])?.to_scalar()?;
+ let a = self.read_pointer(&args[0])?;
+ let b = self.read_pointer(&args[1])?;
// Special case: if both scalars are *equal integers*
// and not null, we pretend there is an allocation of size 0 right there,
// and their offset is 0. (There's never a valid object at null, making it an
// exception from the exception.)
// This is the dual to the special exception for offset-by-0
- // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
- //
- // Control flow is weird because we cannot early-return (to reach the
- // `go_to_block` at the end).
- let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) {
- let a = a.try_to_machine_usize(*self.tcx).unwrap();
- let b = b.try_to_machine_usize(*self.tcx).unwrap();
- if a == b && a != 0 {
+ // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below).
+ match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) {
+ (Err(a), Err(b)) if a == b && a != 0 => {
+ // Both are the same non-null integer.
self.write_scalar(Scalar::from_machine_isize(0, self), dest)?;
- true
- } else {
- false
}
- } else {
- false
- };
-
- if !done {
- // General case: we need two pointers.
- let a = self.scalar_to_ptr(a);
- let b = self.scalar_to_ptr(b);
- let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?;
- let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?;
- if a_alloc_id != b_alloc_id {
- throw_ub_format!(
- "ptr_offset_from cannot compute offset of pointers into different \
- allocations.",
- );
+ (Err(offset), _) | (_, Err(offset)) => {
+ throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest));
+ }
+ (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
+ // Both are pointers. They must be into the same allocation.
+ if a_alloc_id != b_alloc_id {
+ throw_ub_format!(
+ "ptr_offset_from cannot compute offset of pointers into different \
+ allocations.",
+ );
+ }
+ // And they must both be valid for zero-sized accesses ("in-bounds or one past the end").
+ self.memory.check_ptr_access_align(
+ a,
+ Size::ZERO,
+ Align::ONE,
+ CheckInAllocMsg::OffsetFromTest,
+ )?;
+ self.memory.check_ptr_access_align(
+ b,
+ Size::ZERO,
+ Align::ONE,
+ CheckInAllocMsg::OffsetFromTest,
+ )?;
+
+ // Compute offset.
+ let usize_layout = self.layout_of(self.tcx.types.usize)?;
+ let isize_layout = self.layout_of(self.tcx.types.isize)?;
+ let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
+ let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
+ let (val, _overflowed, _ty) =
+ self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+ let pointee_layout = self.layout_of(substs.type_at(0))?;
+ let val = ImmTy::from_scalar(val, isize_layout);
+ let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
+ self.exact_div(&val, &size, dest)?;
}
- let usize_layout = self.layout_of(self.tcx.types.usize)?;
- let isize_layout = self.layout_of(self.tcx.types.isize)?;
- let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
- let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
- let (val, _overflowed, _ty) =
- self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
- let pointee_layout = self.layout_of(substs.type_at(0))?;
- let val = ImmTy::from_scalar(val, isize_layout);
- let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
- self.exact_div(&val, &size, dest)?;
}
}
self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
}
+ pub fn saturating_arith(
+ &self,
+ mir_op: BinOp,
+ l: &ImmTy<'tcx, M::PointerTag>,
+ r: &ImmTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+ assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
+ let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
+ Ok(if overflowed {
+ let size = l.layout.size;
+ let num_bits = size.bits();
+ if l.layout.abi.is_signed() {
+ // For signed ints the saturated value depends on the sign of the first
+ // term since the sign of the second term can be inferred from this and
+ // the fact that the operation has overflowed (if either is 0 no
+ // overflow can occur)
+ let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
+ let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
+ if first_term_positive {
+ // Negative overflow not possible since the positive first term
+ // can only increase an (in range) negative term for addition
+ // or corresponding negated positive term for subtraction
+ Scalar::from_int(size.signed_int_max(), size)
+ } else {
+ // Positive overflow not possible for similar reason
+ // max negative
+ Scalar::from_int(size.signed_int_min(), size)
+ }
+ } else {
+ // unsigned
+ if matches!(mir_op, BinOp::Add) {
+ // max unsigned
+ Scalar::from_uint(size.unsigned_int_max(), size)
+ } else {
+ // underflow to 0
+ Scalar::from_uint(0u128, size)
+ }
+ }
+ } else {
+ val
+ })
+ }
+
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
use rustc_middle::ty::{
self,
print::{PrettyPrinter, Print, Printer},
}
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
tcx.intern_const_alloc(alloc)
use rustc_target::spec::abi::Abi;
use super::{
- AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace,
- Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
+ AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+ LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
+ StackPopUnwind,
};
/// Data returned by Machine::stack_pop,
fn before_access_global(
_memory_extra: &Self::MemoryExtra,
_alloc_id: AllocId,
- _allocation: &Allocation,
+ _allocation: ConstAllocation<'tcx>,
_static_def_id: Option<DefId>,
_is_write: bool,
) -> InterpResult<'tcx> {
Ok(new_ptr)
}
+ #[instrument(skip(self), level = "debug")]
pub fn deallocate(
&mut self,
ptr: Pointer<Option<M::PointerTag>>,
.into());
};
+ debug!(?alloc);
+
if alloc.mutability == Mutability::Not {
throw_ub_format!("deallocating immutable allocation {}", alloc_id);
}
CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => {
AllocCheck::Dereferenceable
}
- CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => {
- AllocCheck::Live
- }
+ CheckInAllocMsg::PointerArithmeticTest
+ | CheckInAllocMsg::OffsetFromTest
+ | CheckInAllocMsg::InboundsTest => AllocCheck::Live,
};
let (size, align) = self.get_size_and_align(alloc_id, check)?;
Ok((size, align, ()))
}
};
M::before_access_global(&self.extra, id, alloc, def_id, is_write)?;
- let alloc = Cow::Borrowed(alloc);
// We got tcx memory. Let the machine initialize its "extra" stuff.
let alloc = M::init_allocation_extra(
self,
id, // always use the ID we got as input, not the "hidden" one.
- alloc,
+ Cow::Borrowed(alloc.inner()),
M::GLOBAL_KIND.map(MemoryKind::Machine),
);
Ok(alloc)
Some(GlobalAlloc::Memory(alloc)) => {
// Need to duplicate the logic here, because the global allocations have
// different associated types than the interpreter-local ones.
+ let alloc = alloc.inner();
Ok((alloc.size(), alloc.align))
}
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
&mut *fmt,
self.mem.tcx,
&mut allocs_to_print,
- alloc,
+ alloc.inner(),
)?;
}
Some(GlobalAlloc::Function(func)) => {
let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
- let tag_val = tag_val.to_scalar()?;
- trace!("tag value: {:?}", tag_val);
+ trace!("tag value: {}", tag_val);
// Figure out which discriminant and variant this corresponds to.
Ok(match *tag_encoding {
TagEncoding::Direct => {
+ // Generate a specific error if `tag_val` is not an integer.
+ // (`tag_bits` itself is only used for error messages below.)
let tag_bits = tag_val
+ .to_scalar()?
.try_to_int()
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
.assert_bits(tag_layout.size);
// Cast bits from tag layout to discriminant layout.
- let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+ // After the checks we did above, this cannot fail.
+ let discr_val =
+ self.misc_cast(&tag_val, discr_layout.ty).unwrap().to_scalar().unwrap();
let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match *op.layout.ty.kind() {
(discr_val, index.0)
}
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ let tag_val = tag_val.to_scalar()?;
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32();
// Shift ops can have an RHS with a different numeric type.
if bin_op == Shl || bin_op == Shr {
- let signed = left_layout.abi.is_signed();
let size = u128::from(left_layout.size.bits());
+ // Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its
+ // zero-extended form). This matches the codegen backend:
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/base.rs#L315-L317>.
+ // The overflow check is also ignorant to the sign:
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/mir/rvalue.rs#L728>.
+ // This would behave rather strangely if we had integer types of size 256: a shift by
+ // -1i8 would actually shift by 255, but that would *not* be considered overflowing. A
+ // shift by -1i16 though would be considered overflowing. If we had integers of size
+ // 512, then a shift by -1i8 would even produce a different result than one by -1i16:
+ // the first shifts by 255, the latter by u16::MAX % 512 = 511. Lucky enough, our
+ // integers are maximally 128bits wide, so negative shifts *always* overflow and we have
+ // consistent results for the same value represented at different bit widths.
+ assert!(size <= 128);
let overflow = r >= size;
// The shift offset is implicitly masked to the type size, to make sure this operation
// is always defined. This is the one MIR operator that does *not* directly map to a
// single LLVM operation. See
- // <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
// for the corresponding truncation in our codegen backends.
let r = r % size;
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
- let result = if signed {
+ let result = if left_layout.abi.is_signed() {
let l = self.sign_extend(l, left_layout) as i128;
let result = match bin_op {
Shl => l.checked_shl(r).unwrap(),
}
}
- self.check_item_predicates();
-
for (idx, local) in body.local_decls.iter_enumerated() {
// Handle the return place below.
if idx == RETURN_PLACE || local.internal {
match *ty.kind() {
ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
- ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
- ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
-
- ty::Dynamic(preds, _) => {
- for pred in preds.iter() {
- match pred.skip_binder() {
- ty::ExistentialPredicate::AutoTrait(_)
- | ty::ExistentialPredicate::Projection(_) => {
- self.check_op(ops::ty::DynTrait(kind))
- }
- ty::ExistentialPredicate::Trait(trait_ref) => {
- if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
- self.check_op(ops::ty::DynTrait(kind))
- }
- }
- }
- }
- }
_ => {}
}
}
}
- fn check_item_predicates(&mut self) {
- let ConstCx { tcx, .. } = *self.ccx;
-
- let mut current = self.def_id().to_def_id();
- loop {
- let predicates = tcx.predicates_of(current);
- for (predicate, _) in predicates.predicates {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
- | ty::PredicateKind::WellFormed(_)
- | ty::PredicateKind::Projection(_)
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
- ty::PredicateKind::ObjectSafe(_) => {
- bug!("object safe predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::ClosureKind(..) => {
- bug!("closure kind predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
- bug!("subtype/coerce predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Trait(pred) => {
- if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
- continue;
- }
- match pred.self_ty().kind() {
- ty::Param(p) => {
- let generics = tcx.generics_of(current);
- let def = generics.type_param(p, tcx);
- let span = tcx.def_span(def.def_id);
-
- // These are part of the function signature, so treat them like
- // arguments when determining importance.
- let kind = LocalKind::Arg;
-
- self.check_op_spanned(ops::ty::TraitBound(kind), span);
- }
- // other kinds of bounds are either tautologies
- // or cause errors in other passes
- _ => continue,
- }
- }
- }
- }
- match predicates.parent {
- Some(parent) => current = parent,
- None => break,
- }
- }
- }
-
fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
match self.const_kind() {
// In a const fn all borrows are transient or point to the places given via
),
_,
_,
- ) => self.check_op(ops::FnPtrCast),
+ ) => {
+ // Nothing to do here. Function pointer casts are allowed now.
+ }
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
// Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
}
}
-#[derive(Debug)]
-pub struct FnPtrCast;
-impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_fn_ptr_basics)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_fn_ptr_basics,
- span,
- &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
- )
- }
-}
-
#[derive(Debug)]
pub struct Generator(pub hir::GeneratorKind);
impl<'tcx> NonConstOp<'tcx> for Generator {
)
}
}
-
- #[derive(Debug)]
- pub struct FnPtr(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for FnPtr {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_fn_ptr_basics)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_fn_ptr_basics,
- span,
- &format!("function pointers cannot appear in {}s", ccx.const_kind()),
- )
- }
- }
-
- #[derive(Debug)]
- pub struct ImplTrait;
- impl<'tcx> NonConstOp<'tcx> for ImplTrait {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
- Status::Unstable(sym::const_impl_trait)
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_impl_trait,
- span,
- &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
- )
- }
- }
-
- #[derive(Debug)]
- pub struct TraitBound(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for TraitBound {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_trait_bound)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_trait_bound,
- span,
- "trait bounds other than `Sized` on const fn parameters are unstable",
- );
-
- match ccx.fn_sig() {
- Some(fn_sig) if !fn_sig.span.contains(span) => {
- err.span_label(fn_sig.span, "function declared as const here");
- }
- _ => {}
- }
-
- err
- }
- }
-
- #[derive(Debug)]
- pub struct DynTrait(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for DynTrait {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_trait_bound)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_trait_bound,
- span,
- "trait objects in const fn are unstable",
- );
-
- match ccx.fn_sig() {
- Some(fn_sig) if !fn_sig.span.contains(span) => {
- err.span_label(fn_sig.span, "function declared as const here");
- }
- _ => {}
- }
-
- err
- }
- }
-
- /// A trait bound with the `?const Trait` opt-out
- #[derive(Debug)]
- pub struct TraitBoundNotConst;
- impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
- fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
- Status::Unstable(sym::const_trait_bound_opt_out)
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_trait_bound_opt_out,
- span,
- "`?const Trait` syntax is unstable",
- )
- }
- }
}
rayon = { version = "0.3.2", package = "rustc-rayon" }
rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
rustc-hash = "1.1.0"
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
bitflags = "1.2.1"
measureme = "10.0.0"
+use crate::stable_hasher::{HashStable, StableHasher};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
impl<'a, T> Eq for Interned<'a, T> {}
-// In practice you can't intern any `T` that doesn't implement `Eq`, because
-// that's needed for hashing. Therefore, we won't be interning any `T` that
-// implements `PartialOrd` without also implementing `Ord`. So we can have the
-// bound `T: Ord` here and avoid duplication with the `Ord` impl below.
-impl<'a, T: Ord> PartialOrd for Interned<'a, T> {
+impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> {
fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
- Some(self.cmp(other))
+ // Pointer equality implies equality, due to the uniqueness constraint,
+ // but the contents must be compared otherwise.
+ if ptr::eq(self.0, other.0) {
+ Some(Ordering::Equal)
+ } else {
+ let res = self.0.partial_cmp(&other.0);
+ debug_assert_ne!(res, Some(Ordering::Equal));
+ res
+ }
}
}
}
}
+impl<T, CTX> HashStable<CTX> for Interned<'_, T>
+where
+ T: HashStable<CTX>,
+{
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.0.hash_stable(hcx, hasher);
+ }
+}
+
#[cfg(test)]
mod tests;
pub mod owning_ref;
pub mod sip128;
pub mod small_c_str;
+pub mod small_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
impl Deref for SmallCStr {
type Target = ffi::CStr;
+ #[inline]
fn deref(&self) -> &ffi::CStr {
self.as_c_str()
}
--- /dev/null
+use smallvec::SmallVec;
+
+#[cfg(test)]
+mod tests;
+
+/// Like SmallVec but for strings.
+#[derive(Default)]
+pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
+
+impl<const N: usize> SmallStr<N> {
+ #[inline]
+ pub fn new() -> Self {
+ SmallStr(SmallVec::default())
+ }
+
+ #[inline]
+ pub fn push_str(&mut self, s: &str) {
+ self.0.extend_from_slice(s.as_bytes());
+ }
+
+ #[inline]
+ pub fn empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ #[inline]
+ pub fn spilled(&self) -> bool {
+ self.0.spilled()
+ }
+
+ #[inline]
+ pub fn as_str(&self) -> &str {
+ unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
+ }
+}
+
+impl<const N: usize> std::ops::Deref for SmallStr<N> {
+ type Target = str;
+
+ #[inline]
+ fn deref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
+ #[inline]
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = A>,
+ {
+ let mut s = SmallStr::default();
+ s.extend(iter);
+ s
+ }
+}
+
+impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
+ #[inline]
+ fn extend<T>(&mut self, iter: T)
+ where
+ T: IntoIterator<Item = A>,
+ {
+ for a in iter.into_iter() {
+ self.push_str(a.as_ref());
+ }
+ }
+}
--- /dev/null
+use super::*;
+
+#[test]
+fn empty() {
+ let s = SmallStr::<1>::new();
+ assert!(s.empty());
+ assert_eq!("", s.as_str());
+ assert!(!s.spilled());
+}
+
+#[test]
+fn from_iter() {
+ let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
+ assert_eq!("aabbcc", s.as_str());
+ assert!(!s.spilled());
+
+ let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
+ assert_eq!("aabbccdd", s.as_str());
+ assert!(s.spilled());
+}
target: Index,
}
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
pub fn is_empty(&self) -> bool {
self.edges.is_empty()
}
self.elements.iter()
}
- fn index(&self, a: &T) -> Option<Index> {
- self.elements.get_index_of(a).map(Index)
+ fn index(&self, a: T) -> Option<Index> {
+ self.elements.get_index_of(&a).map(Index)
}
fn add_index(&mut self, a: T) -> Index {
/// `None`.
pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
where
- F: FnMut(&T) -> Option<U>,
- U: Clone + Debug + Eq + Hash + Clone,
+ F: FnMut(T) -> Option<U>,
+ U: Clone + Debug + Eq + Hash + Copy,
{
let mut result = TransitiveRelation::default();
for edge in &self.edges {
- result.add(f(&self.elements[edge.source.0])?, f(&self.elements[edge.target.0])?);
+ result.add(f(self.elements[edge.source.0])?, f(self.elements[edge.target.0])?);
}
Some(result)
}
}
/// Checks whether `a < target` (transitively)
- pub fn contains(&self, a: &T, b: &T) -> bool {
+ pub fn contains(&self, a: T, b: T) -> bool {
match (self.index(a), self.index(b)) {
(Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)),
(None, _) | (_, None) => false,
/// Really this probably ought to be `impl Iterator<Item = &T>`, but
/// I'm too lazy to make that work, and -- given the caching
/// strategy -- it'd be a touch tricky anyhow.
- pub fn reachable_from(&self, a: &T) -> Vec<&T> {
+ pub fn reachable_from(&self, a: T) -> Vec<T> {
match self.index(a) {
Some(a) => {
- self.with_closure(|closure| closure.iter(a.0).map(|i| &self.elements[i]).collect())
+ self.with_closure(|closure| closure.iter(a.0).map(|i| self.elements[i]).collect())
}
None => vec![],
}
/// a -> a1
/// b -> b1
/// ```
- pub fn postdom_upper_bound(&self, a: &T, b: &T) -> Option<&T> {
+ pub fn postdom_upper_bound(&self, a: T, b: T) -> Option<T> {
let mubs = self.minimal_upper_bounds(a, b);
self.mutual_immediate_postdominator(mubs)
}
/// Viewing the relation as a graph, computes the "mutual
/// immediate postdominator" of a set of points (if one
/// exists). See `postdom_upper_bound` for details.
- pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<&'a T>) -> Option<&'a T> {
+ pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<T>) -> Option<T> {
loop {
match mubs.len() {
0 => return None,
/// internal indices).
///
/// Note that this set can, in principle, have any size.
- pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
+ pub fn minimal_upper_bounds(&self, a: T, b: T) -> Vec<T> {
let (Some(mut a), Some(mut b)) = (self.index(a), self.index(b)) else {
return vec![];
};
lub_indices
.into_iter()
.rev() // (4)
- .map(|i| &self.elements[i])
+ .map(|i| self.elements[i])
.collect()
}
///
/// then `parents(a)` returns `[b, c]`. The `postdom_parent` function
/// would further reduce this to just `f`.
- pub fn parents(&self, a: &T) -> Vec<&T> {
+ pub fn parents(&self, a: T) -> Vec<T> {
let Some(a) = self.index(a) else {
return vec![];
};
ancestors
.into_iter()
.rev() // (4)
- .map(|i| &self.elements[i])
+ .map(|i| self.elements[i])
.collect()
}
/// Lists all the base edges in the graph: the initial _non-transitive_ set of element
/// relations, which will be later used as the basis for the transitive closure computation.
- pub fn base_edges(&self) -> impl Iterator<Item = (&T, &T)> {
+ pub fn base_edges(&self) -> impl Iterator<Item = (T, T)> + '_ {
self.edges
.iter()
- .map(move |edge| (&self.elements[edge.source.0], &self.elements[edge.target.0]))
+ .map(move |edge| (self.elements[edge.source.0], self.elements[edge.target.0]))
}
}
use super::*;
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
/// A "best" parent in some sense. See `parents` and
/// `postdom_upper_bound` for more details.
- fn postdom_parent(&self, a: &T) -> Option<&T> {
+ fn postdom_parent(&self, a: T) -> Option<T> {
self.mutual_immediate_postdominator(self.parents(a))
}
}
let mut relation = TransitiveRelation::default();
relation.add("a", "b");
relation.add("a", "c");
- assert!(relation.contains(&"a", &"c"));
- assert!(relation.contains(&"a", &"b"));
- assert!(!relation.contains(&"b", &"a"));
- assert!(!relation.contains(&"a", &"d"));
+ assert!(relation.contains("a", "c"));
+ assert!(relation.contains("a", "b"));
+ assert!(!relation.contains("b", "a"));
+ assert!(!relation.contains("a", "d"));
}
#[test]
relation.add("e", "g");
- assert!(relation.contains(&"a", &"b"));
- assert!(relation.contains(&"a", &"c"));
- assert!(relation.contains(&"a", &"d"));
- assert!(relation.contains(&"a", &"e"));
- assert!(relation.contains(&"a", &"f"));
- assert!(relation.contains(&"a", &"g"));
+ assert!(relation.contains("a", "b"));
+ assert!(relation.contains("a", "c"));
+ assert!(relation.contains("a", "d"));
+ assert!(relation.contains("a", "e"));
+ assert!(relation.contains("a", "f"));
+ assert!(relation.contains("a", "g"));
- assert!(relation.contains(&"b", &"g"));
+ assert!(relation.contains("b", "g"));
- assert!(!relation.contains(&"a", &"x"));
- assert!(!relation.contains(&"b", &"f"));
+ assert!(!relation.contains("a", "x"));
+ assert!(!relation.contains("b", "f"));
}
#[test]
let mut relation = TransitiveRelation::default();
relation.add("a", "tcx");
relation.add("b", "tcx");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"tcx"]);
- assert_eq!(relation.parents(&"a"), vec![&"tcx"]);
- assert_eq!(relation.parents(&"b"), vec![&"tcx"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["tcx"]);
+ assert_eq!(relation.parents("a"), vec!["tcx"]);
+ assert_eq!(relation.parents("b"), vec!["tcx"]);
}
#[test]
relation.add("3", "1");
relation.add("3", "2");
- assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"2"]);
- assert_eq!(relation.parents(&"0"), vec![&"2"]);
- assert_eq!(relation.parents(&"2"), vec![&"1"]);
- assert!(relation.parents(&"1").is_empty());
+ assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["2"]);
+ assert_eq!(relation.parents("0"), vec!["2"]);
+ assert_eq!(relation.parents("2"), vec!["1"]);
+ assert!(relation.parents("1").is_empty());
}
#[test]
relation.add("3", "1");
relation.add("3", "2");
- assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
- assert_eq!(relation.parents(&"0"), vec![&"1"]);
- assert_eq!(relation.parents(&"1"), vec![&"2"]);
- assert!(relation.parents(&"2").is_empty());
+ assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+ assert_eq!(relation.parents("0"), vec!["1"]);
+ assert_eq!(relation.parents("1"), vec!["2"]);
+ assert!(relation.parents("2").is_empty());
}
#[test]
relation.add("3", "1");
relation.add("3", "2");
- assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1", &"2"]);
- assert_eq!(relation.parents(&"0"), vec![&"1", &"2"]);
- assert_eq!(relation.parents(&"3"), vec![&"1", &"2"]);
+ assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1", "2"]);
+ assert_eq!(relation.parents("0"), vec!["1", "2"]);
+ assert_eq!(relation.parents("3"), vec!["1", "2"]);
}
#[test]
relation.add("3", "1");
relation.add("3", "2");
- assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
- assert_eq!(relation.parents(&"0"), vec![&"1"]);
+ assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+ assert_eq!(relation.parents("0"), vec!["1"]);
}
#[test]
relation.add("a1", "x");
relation.add("b1", "x");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
- assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
- assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
- assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+ assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
+ assert_eq!(relation.postdom_parent("a"), Some("x"));
+ assert_eq!(relation.postdom_parent("b"), Some("x"));
}
#[test]
relation.add("a3", "x");
relation.add("b2", "x");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
- assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), vec![&"a2", &"b2"]);
- assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+ assert_eq!(relation.minimal_upper_bounds("a1", "b1"), vec!["a2", "b2"]);
+ assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
- assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
- assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+ assert_eq!(relation.postdom_parent("a"), Some("x"));
+ assert_eq!(relation.postdom_parent("b"), Some("x"));
}
#[test]
relation.add("a1", "x");
relation.add("b1", "x");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"x"]);
- assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["x"]);
+ assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
- assert_eq!(relation.postdom_parent(&"a"), Some(&"a1"));
- assert_eq!(relation.postdom_parent(&"b"), Some(&"b1"));
- assert_eq!(relation.postdom_parent(&"a1"), Some(&"x"));
- assert_eq!(relation.postdom_parent(&"b1"), Some(&"x"));
+ assert_eq!(relation.postdom_parent("a"), Some("a1"));
+ assert_eq!(relation.postdom_parent("b"), Some("b1"));
+ assert_eq!(relation.postdom_parent("a1"), Some("x"));
+ assert_eq!(relation.postdom_parent("b1"), Some("x"));
}
#[test]
relation.add("c", "d");
relation.add("b", "d");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"d"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["d"]);
}
#[test]
relation.add("a", "d");
relation.add("b", "d");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
}
#[test]
relation.add("b", "d");
relation.add("b", "c");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
}
#[test]
relation.add("b", "d");
relation.add("b", "e");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
}
#[test]
relation.add("a", "d");
relation.add("b", "e");
- assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+ assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
}
#[test]
relation.add(a, b);
}
- let p = relation.postdom_parent(&3);
- assert_eq!(p, Some(&0));
+ let p = relation.postdom_parent(3);
+ assert_eq!(p, Some(0));
}
use crate::ToolMetadata;
use rustc_lint_defs::Applicability;
use rustc_serialize::json::Json;
+use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;
use std::hash::{Hash, Hasher};
self
}
+ /// Help the user upgrade to the latest edition.
+ /// This is factored out to make sure it does the right thing with `Cargo.toml`.
+ pub fn help_use_latest_edition(&mut self) -> &mut Self {
+ if std::env::var_os("CARGO").is_some() {
+ self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
+ } else {
+ self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
+ }
+ self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ self
+ }
+
/// Disallow attaching suggestions this diagnostic.
/// Any suggestions attached e.g. with the `span_suggestion_*` methods
/// (before and after the call to `disable_suggestions`) will be ignored.
sp: impl Into<MultiSpan>,
msg: &str,
) -> &mut Self);
+ forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
let mut lines = complete.lines();
+ if lines.clone().next().is_none() {
+ // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
+ let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
+ for line in line_start..=line_end {
+ buffer.puts(
+ row_num - 1 + line - line_start,
+ 0,
+ &self.maybe_anonymized(line),
+ Style::LineNumber,
+ );
+ buffer.puts(
+ row_num - 1 + line - line_start,
+ max_line_num_len + 1,
+ "- ",
+ Style::Removal,
+ );
+ buffer.puts(
+ row_num - 1 + line - line_start,
+ max_line_num_len + 3,
+ &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()),
+ Style::Removal,
+ );
+ }
+ row_num += line_end - line_start;
+ }
for (line_pos, (line, highlight_parts)) in
lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
{
let warnings = match self.deduplicated_warn_count {
0 => String::new(),
1 => "1 warning emitted".to_string(),
- count => format!("{} warnings emitted", count),
+ count => format!("{count} warnings emitted"),
};
let errors = match self.deduplicated_err_count {
0 => String::new(),
1 => "aborting due to previous error".to_string(),
- count => format!("aborting due to {} previous errors", count),
+ count => format!("aborting due to {count} previous errors"),
};
if self.treat_err_as_bug() {
return;
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
+#![feature(let_chains)]
#![feature(let_else)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
crate mod macro_check;
crate mod macro_parser;
crate mod macro_rules;
+crate mod metavar_expr;
crate mod quoted;
crate mod transcribe;
+use metavar_expr::MetaVarExpr;
use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
use rustc_ast::tokenstream::DelimSpan;
-
+use rustc_data_structures::sync::Lrc;
use rustc_span::symbol::Ident;
use rustc_span::Span;
-use rustc_data_structures::sync::Lrc;
-
/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
/// that the delimiter itself might be `NoDelim`.
#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
ZeroOrOne,
}
-/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
-/// are "first-class" token trees. Useful for parsing macros.
+/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, `$(...)`,
+/// and `${...}` are "first-class" token trees. Useful for parsing macros.
#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
enum TokenTree {
Token(Token),
MetaVar(Span, Ident),
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
+ /// A meta-variable expression inside `${...}`
+ MetaVarExpr(DelimSpan, MetaVarExpr),
}
impl TokenTree {
TokenTree::Token(Token { span, .. })
| TokenTree::MetaVar(span, _)
| TokenTree::MetaVarDecl(span, _, _) => span,
- TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
+ TokenTree::Delimited(span, _)
+ | TokenTree::MetaVarExpr(span, _)
+ | TokenTree::Sequence(span, _) => span.entire(),
}
}
binders.insert(name, BinderInfo { span, ops: ops.into() });
}
}
+ // `MetaVarExpr` can not appear in the LHS of a macro arm
+ TokenTree::MetaVarExpr(..) => {}
TokenTree::Delimited(_, ref del) => {
for tt in &del.tts {
check_binders(sess, node_id, tt, macros, binders, ops, valid);
let name = MacroRulesNormalizedIdent::new(name);
check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name);
}
+ // FIXME(c410-f3r) Check token (https://github.com/rust-lang/rust/issues/93902)
+ TokenTree::MetaVarExpr(..) => {}
TokenTree::Delimited(_, ref del) => {
check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
}
/// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
///
-/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
+/// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have
/// descended into.
#[derive(Clone)]
struct MatcherTtFrame<'tt> {
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 192);
+rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 240);
impl<'root, 'tt> MatcherPos<'root, 'tt> {
/// Generates the top-level matcher position in which the "dot" is before the first token of
ms.iter().fold(0, |count, elt| {
count
+ match *elt {
- TokenTree::Sequence(_, ref seq) => seq.num_captures,
TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
TokenTree::MetaVar(..) => 0,
TokenTree::MetaVarDecl(..) => 1,
+ // FIXME(c410-f3r) MetaVarExpr should be handled instead of being ignored
+ // https://github.com/rust-lang/rust/issues/9390
+ TokenTree::MetaVarExpr(..) => 0,
+ TokenTree::Sequence(_, ref seq) => seq.num_captures,
TokenTree::Token(..) => 0,
}
})
}
Occupied(..) => return Err((sp, format!("duplicated bind name: {}", bind_name))),
},
- TokenTree::MetaVar(..) | TokenTree::Token(..) => (),
+ TokenTree::Token(..) => (),
+ TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
}
Ok(())
/// successful execution of this function.
/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
/// the function `parse`.
-/// - `eof_items`: the set of items that would be valid if this was the EOF.
/// - `bb_items`: the set of items that are waiting for the black-box parser.
/// - `token`: the current token of the parser.
///
/// # Returns
///
-/// A `ParseResult`. Note that matches are kept track of through the items generated.
-fn inner_parse_loop<'root, 'tt>(
+/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept track of
+/// through the items generated.
+fn parse_tt_inner<'root, 'tt>(
sess: &ParseSess,
+ ms: &[TokenTree],
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
- next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
+ next_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
- eof_items: &mut EofItems<'root, 'tt>,
token: &Token,
-) -> Result<(), (rustc_span::Span, String)> {
+) -> Option<NamedParseResult> {
+ // Matcher positions that would be valid if the macro invocation was over now
+ let mut eof_items = EofItems::None;
+
// Pop items from `cur_items` until it is empty.
while let Some(mut item) = cur_items.pop() {
// When unzipped trees end, remove them. This corresponds to backtracking out of a
// then we could be at the end of a sequence or at the beginning of the next
// repetition.
if let Some(repetition) = &item.repetition {
+ debug_assert!(matches!(item.top_elts, Tt(TokenTree::Sequence(..))));
+
// At this point, regardless of whether there is a separator, we should add all
// matches from the complete repetition of the sequence to the shared, top-level
// `matches` list (actually, `up.matches`, which could itself not be the top-level,
} else {
// If we are not in a repetition, then being at the end of a matcher means that we
// have reached the potential end of the input.
- *eof_items = match eof_items {
+ eof_items = match eof_items {
EofItems::None => EofItems::One(item),
EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
}
// We need to match a metavar (but the identifier is invalid)... this is an error
TokenTree::MetaVarDecl(span, _, None) => {
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
- return Err((span, "missing fragment specifier".to_string()));
+ return Some(Error(span, "missing fragment specifier".to_string()));
}
}
// rules. NOTE that this is not necessarily an error unless _all_ items in
// `cur_items` end up doing this. There may still be some other matchers that do
// end up working out.
- TokenTree::Token(..) | TokenTree::MetaVar(..) => {}
+ TokenTree::Token(..) => {}
+
+ TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
}
}
}
- // Yay a successful parse (so far)!
- Ok(())
+ // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
+ // either the parse is ambiguous (which should never happen) or there is a syntax error.
+ if *token == token::Eof {
+ Some(match eof_items {
+ EofItems::One(mut eof_item) => {
+ let matches =
+ eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
+ nameize(sess, ms, matches)
+ }
+ EofItems::Multiple => {
+ Error(token.span, "ambiguity: multiple successful parses".to_string())
+ }
+ EofItems::None => Failure(
+ Token::new(
+ token::Eof,
+ if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
+ ),
+ "missing tokens in macro arguments",
+ ),
+ })
+ } else {
+ None
+ }
}
/// Use the given sequence of token trees (`ms`) as a matcher. Match the token
macro_name: Ident,
) -> NamedParseResult {
// A queue of possible matcher positions. We initialize it with the matcher position in which
- // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
+ // the "dot" is before the first token of the first token tree in `ms`. `parse_tt_inner` then
// processes all of these possible matcher positions and produces possible next positions into
// `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
// and we start over again.
// there are frequently *no* others! -- are allocated on the heap.
let mut initial = MatcherPos::new(ms);
let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
- let mut next_items = Vec::new();
loop {
- assert!(next_items.is_empty());
+ let mut next_items = SmallVec::new();
// Matcher positions black-box parsed by parser.rs (`parser`)
let mut bb_items = SmallVec::new();
- // Matcher positions that would be valid if the macro invocation was over now
- let mut eof_items = EofItems::None;
-
// Process `cur_items` until either we have finished the input or we need to get some
// parsing from the black-box parser done. The result is that `next_items` will contain a
// bunch of possible next matcher positions in `next_items`.
- match inner_parse_loop(
+ if let Some(result) = parse_tt_inner(
parser.sess,
+ ms,
&mut cur_items,
&mut next_items,
&mut bb_items,
- &mut eof_items,
&parser.token,
) {
- Ok(()) => {}
- Err((sp, msg)) => return Error(sp, msg),
+ return result;
}
- // inner parse loop handled all cur_items, so it's empty
+ // `parse_tt_inner` handled all cur_items, so it's empty.
assert!(cur_items.is_empty());
- // We need to do some post processing after the `inner_parse_loop`.
+ // We need to do some post processing after the `parse_tt_inner`.
//
// Error messages here could be improved with links to original rules.
- // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
- // either the parse is ambiguous (which should never happen) or there is a syntax error.
- if parser.token == token::Eof {
- return match eof_items {
- EofItems::One(mut eof_item) => {
- let matches =
- eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
- nameize(parser.sess, ms, matches)
- }
- EofItems::Multiple => {
- Error(parser.token.span, "ambiguity: multiple successful parses".to_string())
- }
- EofItems::None => Failure(
- Token::new(
- token::Eof,
- if parser.token.span.is_dummy() {
- parser.token.span
- } else {
- parser.token.span.shrink_to_hi()
- },
- ),
- "missing tokens in macro arguments",
- ),
- };
- }
- // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
- // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
- // unnecessary implicit clone later in `Rc::make_mut`.
- drop(eof_items);
-
- // If there are no possible next positions AND we aren't waiting for the black-box parser,
- // then there is a syntax error.
- if bb_items.is_empty() && next_items.is_empty() {
- return Failure(parser.token.clone(), "no rules expected this token in macro call");
- }
+ match (next_items.len(), bb_items.len()) {
+ (0, 0) => {
+ // There are no possible next positions AND we aren't waiting for the black-box
+ // parser: syntax error.
+ return Failure(parser.token.clone(), "no rules expected this token in macro call");
+ }
- if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
- // We need to call out to parse some rust nonterminal (black-box) parser. But something
- // is wrong, because there is not EXACTLY ONE of these.
- let nts = bb_items
- .iter()
- .map(|item| match item.top_elts.get_tt(item.idx) {
- TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
- _ => panic!(),
- })
- .collect::<Vec<String>>()
- .join(" or ");
-
- return Error(
- parser.token.span,
- format!(
- "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
- match next_items.len() {
- 0 => format!("built-in NTs {}.", nts),
- 1 => format!("built-in NTs {} or 1 other option.", nts),
- n => format!("built-in NTs {} or {} other options.", nts, n),
- }
- ),
- );
- }
+ (_, 0) => {
+ // Dump all possible `next_items` into `cur_items` for the next iteration. Then
+ // process the next token.
+ cur_items.extend(next_items.drain(..));
+ parser.to_mut().bump();
+ }
- if !next_items.is_empty() {
- // Dump all possible `next_items` into `cur_items` for the next iteration. Then process
- // the next token.
- cur_items.extend(next_items.drain(..));
- parser.to_mut().bump();
- } else {
- // Finally, we have the case where we need to call the black-box parser to get some
- // nonterminal.
- assert_eq!(bb_items.len(), 1);
-
- let mut item = bb_items.pop().unwrap();
- if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
- let match_cur = item.match_cur;
- // We use the span of the metavariable declaration to determine any
- // edition-specific matching behavior for non-terminals.
- let nt = match parser.to_mut().parse_nonterminal(kind) {
- Err(mut err) => {
- err.span_label(
- span,
- format!("while parsing argument for this `{}` macro fragment", kind),
- )
- .emit();
- return ErrorReported;
- }
- Ok(nt) => nt,
- };
- item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
- item.idx += 1;
- item.match_cur += 1;
- } else {
- unreachable!()
+ (0, 1) => {
+ // We need to call the black-box parser to get some nonterminal.
+ let mut item = bb_items.pop().unwrap();
+ if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx)
+ {
+ let match_cur = item.match_cur;
+ // We use the span of the metavariable declaration to determine any
+ // edition-specific matching behavior for non-terminals.
+ let nt = match parser.to_mut().parse_nonterminal(kind) {
+ Err(mut err) => {
+ err.span_label(
+ span,
+ format!("while parsing argument for this `{kind}` macro fragment"),
+ )
+ .emit();
+ return ErrorReported;
+ }
+ Ok(nt) => nt,
+ };
+ item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
+ item.idx += 1;
+ item.match_cur += 1;
+ } else {
+ unreachable!()
+ }
+ cur_items.push(item);
+ }
+
+ (_, _) => {
+ // We need to call the black-box parser to get some nonterminal, but something is
+ // wrong.
+ return bb_items_ambiguity_error(
+ macro_name,
+ next_items,
+ bb_items,
+ parser.token.span,
+ );
}
- cur_items.push(item);
}
assert!(!cur_items.is_empty());
}
}
+
+fn bb_items_ambiguity_error<'root, 'tt>(
+ macro_name: Ident,
+ next_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+ bb_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+ token_span: rustc_span::Span,
+) -> NamedParseResult {
+ let nts = bb_items
+ .iter()
+ .map(|item| match item.top_elts.get_tt(item.idx) {
+ TokenTree::MetaVarDecl(_, bind, Some(kind)) => {
+ format!("{} ('{}')", kind, bind)
+ }
+ _ => panic!(),
+ })
+ .collect::<Vec<String>>()
+ .join(" or ");
+
+ Error(
+ token_span,
+ format!(
+ "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
+ match next_items.len() {
+ 0 => format!("built-in NTs {}.", nts),
+ 1 => format!("built-in NTs {} or 1 other option.", nts),
+ n => format!("built-in NTs {} or {} other options.", nts, n),
+ }
+ ),
+ )
+}
use mbe::TokenTree;
for tt in tts {
match *tt {
- TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
+ TokenTree::Token(..)
+ | TokenTree::MetaVar(..)
+ | TokenTree::MetaVarDecl(..)
+ | TokenTree::MetaVarExpr(..) => (),
TokenTree::Delimited(_, ref del) => {
if !check_lhs_no_empty_seq(sess, &del.tts) {
return false;
let mut first = TokenSet::empty();
for tt in tts.iter().rev() {
match *tt {
- TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+ TokenTree::Token(..)
+ | TokenTree::MetaVar(..)
+ | TokenTree::MetaVarDecl(..)
+ | TokenTree::MetaVarExpr(..) => {
first.replace_with(tt.clone());
}
TokenTree::Delimited(span, ref delimited) => {
for tt in tts.iter() {
assert!(first.maybe_empty);
match *tt {
- TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+ TokenTree::Token(..)
+ | TokenTree::MetaVar(..)
+ | TokenTree::MetaVarDecl(..)
+ | TokenTree::MetaVarExpr(..) => {
first.add_one(tt.clone());
return first;
}
// First, update `last` so that it corresponds to the set
// of NT tokens that might end the sequence `... token`.
match *token {
- TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+ TokenTree::Token(..)
+ | TokenTree::MetaVar(..)
+ | TokenTree::MetaVarDecl(..)
+ | TokenTree::MetaVarExpr(..) => {
if token_can_be_followed_by_any(token) {
// don't need to track tokens that work with any,
last.replace_with_irrelevant();
--- /dev/null
+use rustc_ast::token;
+use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
+use rustc_ast::{LitIntType, LitKind};
+use rustc_ast_pretty::pprust;
+use rustc_errors::{Applicability, PResult};
+use rustc_session::parse::ParseSess;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// A meta-variable expression, for expansions based on properties of meta-variables.
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
+crate enum MetaVarExpr {
+ /// The number of repetitions of an identifier, optionally limited to a number
+ /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
+ Count(Ident, Option<usize>),
+
+ /// Ignore a meta-variable for repetition without expansion.
+ Ignore(Ident),
+
+ /// The index of the repetition at a particular depth, where 0 is the inner-most
+ /// repetition. The `usize` is the depth.
+ Index(usize),
+
+ /// The length of the repetition at a particular depth, where 0 is the inner-most
+ /// repetition. The `usize` is the depth.
+ Length(usize),
+}
+
+impl MetaVarExpr {
+ /// Attempt to parse a meta-variable expression from a token stream.
+ crate fn parse<'sess>(
+ input: &TokenStream,
+ outer_span: Span,
+ sess: &'sess ParseSess,
+ ) -> PResult<'sess, MetaVarExpr> {
+ let mut tts = input.trees();
+ let ident = parse_ident(&mut tts, sess, outer_span)?;
+ let Some(TokenTree::Delimited(_, token::Paren, args)) = tts.next() else {
+ let msg = "meta-variable expression parameter must be wrapped in parentheses";
+ return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
+ };
+ check_trailing_token(&mut tts, sess)?;
+ let mut iter = args.trees();
+ let rslt = match &*ident.as_str() {
+ "count" => parse_count(&mut iter, sess, ident.span)?,
+ "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
+ "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),
+ "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
+ _ => {
+ let err_msg = "unrecognized meta-variable expression";
+ let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg);
+ err.span_suggestion(
+ ident.span,
+ "supported expressions are count, ignore, index and length",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ return Err(err);
+ }
+ };
+ check_trailing_token(&mut iter, sess)?;
+ Ok(rslt)
+ }
+
+ crate fn ident(&self) -> Option<&Ident> {
+ match self {
+ MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(&ident),
+ MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
+ }
+ }
+}
+
+// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
+fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PResult<'sess, ()> {
+ if let Some(tt) = iter.next() {
+ let mut diag = sess.span_diagnostic.struct_span_err(
+ tt.span(),
+ &format!("unexpected token: {}", pprust::tt_to_string(&tt)),
+ );
+ diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
+ Err(diag)
+ } else {
+ Ok(())
+ }
+}
+
+/// Parse a meta-variable `count` expression: `count(ident[, depth])`
+fn parse_count<'sess>(
+ iter: &mut Cursor,
+ sess: &'sess ParseSess,
+ span: Span,
+) -> PResult<'sess, MetaVarExpr> {
+ let ident = parse_ident(iter, sess, span)?;
+ let depth = if try_eat_comma(iter) { Some(parse_depth(iter, sess, span)?) } else { None };
+ Ok(MetaVarExpr::Count(ident, depth))
+}
+
+/// Parses the depth used by index(depth) and length(depth).
+fn parse_depth<'sess>(
+ iter: &mut Cursor,
+ sess: &'sess ParseSess,
+ span: Span,
+) -> PResult<'sess, usize> {
+ let Some(tt) = iter.next() else { return Ok(0) };
+ let TokenTree::Token(token::Token {
+ kind: token::TokenKind::Literal(lit), ..
+ }) = tt else {
+ return Err(sess.span_diagnostic.struct_span_err(
+ span,
+ "meta-variable expression depth must be a literal"
+ ));
+ };
+ if let Ok(lit_kind) = LitKind::from_lit_token(lit)
+ && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
+ && let Ok(n_usize) = usize::try_from(n_u128)
+ {
+ Ok(n_usize)
+ }
+ else {
+ let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
+ Err(sess.span_diagnostic.struct_span_err(span, msg))
+ }
+}
+
+/// Parses an generic ident
+fn parse_ident<'sess>(
+ iter: &mut Cursor,
+ sess: &'sess ParseSess,
+ span: Span,
+) -> PResult<'sess, Ident> {
+ let err_fn = |msg| sess.span_diagnostic.struct_span_err(span, msg);
+ if let Some(tt) = iter.next() && let TokenTree::Token(token) = tt {
+ if let Some((elem, false)) = token.ident() {
+ return Ok(elem);
+ }
+ let token_str = pprust::token_to_string(&token);
+ let mut err = err_fn(&format!("expected identifier, found `{}`", &token_str));
+ err.span_suggestion(
+ token.span,
+ &format!("try removing `{}`", &token_str),
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ return Err(err);
+ }
+ Err(err_fn("expected identifier"))
+}
+
+/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
+/// iterator is not modified and the result is `false`.
+fn try_eat_comma(iter: &mut Cursor) -> bool {
+ if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. })) = iter.look_ahead(0) {
+ let _ = iter.next();
+ return true;
+ }
+ false
+}
use crate::mbe::macro_parser;
-use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree};
+use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream;
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_feature::Features;
-use rustc_session::parse::ParseSess;
-use rustc_span::symbol::{kw, Ident};
+use rustc_session::parse::{feature_err, ParseSess};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::edition::Edition;
use rustc_span::{Span, SyntaxContext};
/// # Parameters
///
/// - `input`: a token stream to read from, the contents of which we are parsing.
-/// - `expect_matchers`: `parse` can be used to parse either the "patterns" or the "body" of a
-/// macro. Both take roughly the same form _except_ that in a pattern, metavars are declared with
-/// their "matcher" type. For example `$var:expr` or `$id:ident`. In this example, `expr` and
-/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
-/// pattern, so we pass a parameter to indicate whether to expect them or not.
+/// - `parsing_patterns`: `parse` can be used to parse either the "patterns" or the "body" of a
+/// macro. Both take roughly the same form _except_ that:
+/// - In a pattern, metavars are declared with their "matcher" type. For example `$var:expr` or
+/// `$id:ident`. In this example, `expr` and `ident` are "matchers". They are not present in the
+/// body of a macro rule -- just in the pattern.
+/// - Metavariable expressions are only valid in the "body", not the "pattern".
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `node_id`: the NodeId of the macro we are parsing.
/// - `features`: language features so we can do feature gating.
-/// - `edition`: the edition of the crate defining the macro
///
/// # Returns
///
/// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
pub(super) fn parse(
input: tokenstream::TokenStream,
- expect_matchers: bool,
+ parsing_patterns: bool,
sess: &ParseSess,
node_id: NodeId,
features: &Features,
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
- let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
+ let tree = parse_tree(tree, &mut trees, parsing_patterns, sess, node_id, features, edition);
match tree {
- TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
+ TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
let span = match trees.next() {
Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
match trees.next() {
result
}
+/// Asks for the `macro_metavar_expr` feature if it is not already declared
+fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) {
+ if !features.macro_metavar_expr {
+ let msg = "meta-variable expressions are unstable";
+ feature_err(&sess, sym::macro_metavar_expr, span, msg).emit();
+ }
+}
+
/// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a
/// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree`
/// for use in parsing a macro.
/// - `tree`: the tree we wish to convert.
/// - `outer_trees`: an iterator over trees. We may need to read more tokens from it in order to finish
/// converting `tree`
-/// - `expect_matchers`: same as for `parse` (see above).
+/// - `parsing_patterns`: same as [parse].
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `features`: language features so we can do feature gating.
-/// - `edition` - the edition of the crate defining the macro
fn parse_tree(
tree: tokenstream::TokenTree,
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
- expect_matchers: bool,
+ parsing_patterns: bool,
sess: &ParseSess,
node_id: NodeId,
features: &Features,
}
match next {
- // `tree` is followed by a delimited set of token trees. This indicates the beginning
- // of a repetition sequence in the macro (e.g. `$(pat)*`).
- Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => {
- // Must have `(` not `{` or `[`
- if delim != token::Paren {
- let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
- let msg = format!("expected `(`, found `{}`", tok);
- sess.span_diagnostic.span_err(span.entire(), &msg);
+ // `tree` is followed by a delimited set of token trees.
+ Some(tokenstream::TokenTree::Delimited(delim_span, delim, tts)) => {
+ if parsing_patterns {
+ if delim != token::Paren {
+ span_dollar_dollar_or_metavar_in_the_lhs_err(
+ sess,
+ &Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
+ );
+ }
+ } else {
+ match delim {
+ token::Brace => {
+ // The delimiter is `{`. This indicates the beginning
+ // of a meta-variable expression (e.g. `${count(ident)}`).
+ // Try to parse the meta-variable expression.
+ match MetaVarExpr::parse(&tts, delim_span.entire(), sess) {
+ Err(mut err) => {
+ err.emit();
+ // Returns early the same read `$` to avoid spanning
+ // unrelated diagnostics that could be performed afterwards
+ return TokenTree::token(token::Dollar, span);
+ }
+ Ok(elem) => {
+ maybe_emit_macro_metavar_expr_feature(
+ features,
+ sess,
+ delim_span.entire(),
+ );
+ return TokenTree::MetaVarExpr(delim_span, elem);
+ }
+ }
+ }
+ token::Paren => {}
+ _ => {
+ let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
+ let msg = format!("expected `(` or `{{`, found `{}`", tok);
+ sess.span_diagnostic.span_err(delim_span.entire(), &msg);
+ }
+ }
}
- // Parse the contents of the sequence itself
- let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
+ // If we didn't find a metavar expression above, then we must have a
+ // repetition sequence in the macro (e.g. `$(pat)*`). Parse the
+ // contents of the sequence itself
+ let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
// Get the Kleene operator and optional separator
let (separator, kleene) =
- parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
+ parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
// Count the number of captured "names" (i.e., named metavars)
let name_captures = macro_parser::count_names(&sequence);
TokenTree::Sequence(
- span,
+ delim_span,
Lrc::new(SequenceRepetition {
tts: sequence,
separator,
}
}
- // `tree` is followed by a random token. This is an error.
+ // `tree` is followed by another `$`. This is an escaped `$`.
+ Some(tokenstream::TokenTree::Token(Token { kind: token::Dollar, span })) => {
+ if parsing_patterns {
+ span_dollar_dollar_or_metavar_in_the_lhs_err(
+ sess,
+ &Token { kind: token::Dollar, span },
+ );
+ } else {
+ maybe_emit_macro_metavar_expr_feature(features, sess, span);
+ }
+ TokenTree::token(token::Dollar, span)
+ }
+
+ // `tree` is followed by some other token. This is an error.
Some(tokenstream::TokenTree::Token(token)) => {
let msg = format!(
"expected identifier, found `{}`",
span,
Lrc::new(Delimited {
delim,
- tts: parse(tts, expect_matchers, sess, node_id, features, edition),
+ tts: parse(tts, parsing_patterns, sess, node_id, features, edition),
}),
),
}
// Return a dummy
(None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
}
+
+// `$$` or a meta-variable is the lhs of a macro but shouldn't.
+//
+// For example, `macro_rules! foo { ( ${length()} ) => {} }`
+fn span_dollar_dollar_or_metavar_in_the_lhs_err<'sess>(sess: &'sess ParseSess, token: &Token) {
+ sess.span_diagnostic
+ .span_err(token.span, &format!("unexpected token: {}", pprust::token_to_string(token)));
+ sess.span_diagnostic.span_note_without_error(
+ token.span,
+ "`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
+ );
+}
}
}
+ // Replace meta-variable expressions with the result of their expansion.
+ mbe::TokenTree::MetaVarExpr(sp, expr) => {
+ transcribe_metavar_expr(cx, expr, interp, &repeats, &mut result, &sp)?;
+ }
+
// If we are entering a new delimiter, we push its contents to the `stack` to be
// processed, and we push all of the currently produced results to the `result_stack`.
// We will produce all of the results of the inside of the `Delimited` and then we will
_ => LockstepIterSize::Unconstrained,
}
}
+ TokenTree::MetaVarExpr(_, ref expr) => {
+ let default_rslt = LockstepIterSize::Unconstrained;
+ let Some(ident) = expr.ident() else { return default_rslt; };
+ let name = MacroRulesNormalizedIdent::new(ident.clone());
+ match lookup_cur_matched(name, interpolations, repeats) {
+ Some(MatchedSeq(ref ads)) => {
+ default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
+ }
+ _ => default_rslt,
+ }
+ }
TokenTree::Token(..) => LockstepIterSize::Unconstrained,
}
}
+
+fn transcribe_metavar_expr<'a>(
+ _cx: &ExtCtxt<'a>,
+ _expr: mbe::MetaVarExpr,
+ _interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
+ _repeats: &[(usize, usize)],
+ _result: &mut Vec<TreeAndSpacing>,
+ _sp: &DelimSpan,
+) -> PResult<'a, ()> {
+ Ok(())
+}
(accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
/// Allows calling constructor functions in `const fn`.
(accepted, const_constructor, "1.40.0", Some(61456), None),
+ /// Allows using and casting function pointers in a `const fn`.
+ (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563), None),
+ /// Allows trait bounds in `const fn`.
+ (accepted, const_fn_trait_bound, "1.61.0", Some(93706), None),
/// Allows calling `transmute` in const fn
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
/// Allows accessing fields of unions inside `const` functions.
(accepted, const_generics_defaults, "1.59.0", Some(44580), None),
/// Allows the use of `if` and `match` in constants.
(accepted, const_if_match, "1.46.0", Some(49146), None),
+ /// Allows argument and return position `impl Trait` in a `const fn`.
+ (accepted, const_impl_trait, "1.61.0", Some(77463), None),
/// Allows indexing into constant arrays.
(accepted, const_indexing, "1.26.0", Some(29947), None),
/// Allows let bindings, assignments and destructuring in `const` functions and constants.
(active, staged_api, "1.0.0", None, None),
/// Added for testing E0705; perma-unstable.
(active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+ /// Added for testing unstable lints; perma-unstable.
+ (active, test_unstable_lint, "1.60.0", None, None),
/// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
/// Marked `incomplete` since perma-unstable and unsound.
(incomplete, unsafe_pin_internals, "1.60.0", None, None),
(active, const_extern_fn, "1.40.0", Some(64926), None),
/// Allows basic arithmetic on floating point types in a `const fn`.
(active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
- /// Allows using and casting function pointers in a `const fn`.
- (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
- /// Allows trait bounds in `const fn`.
- (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),
- /// Allows argument and return position `impl Trait` in a `const fn`.
- (active, const_impl_trait, "1.48.0", Some(77463), None),
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),
/// Be more precise when looking for live drops in a const context.
(active, default_alloc_error_handler, "1.48.0", Some(66741), None),
/// Allows default type parameters to influence type inference.
(active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
+ /// Allows having using `suggestion` in the `#[deprecated]` attribute.
+ (active, deprecated_suggestion, "1.61.0", Some(94785), None),
/// Allows `#[derive(Default)]` and `#[default]` on enums.
(active, derive_default_enum, "1.56.0", Some(86985), None),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
(active, link_cfg, "1.14.0", Some(37406), None),
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
(active, lint_reasons, "1.31.0", Some(54503), None),
+ /// Give access to additional metadata about declarative macro meta-variables.
+ (active, macro_metavar_expr, "1.61.0", Some(83527), None),
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
(active, marker_trait_attr, "1.30.0", Some(29864), None),
/// A minimal, sound subset of specialization intended to be used by the
// DuplicatesOk since it has its own validation
ungated!(
rustc_deprecated, Normal,
- template!(List: r#"since = "version", reason = "...""#), DuplicatesOk // See E0550
+ template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
),
// DuplicatesOk since it has its own validation
ungated!(
rustc_attr!(
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
// ==========================================================================
/// the code base.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Encodable, Decodable)]
+#[rustc_pass_by_value]
pub struct HirId {
pub owner: LocalDefId,
pub local_id: ItemLocalId,
#![feature(once_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(rustc_attrs)]
#![recursion_limit = "256"]
#[macro_use]
impl<T: Idx> BitRelations<HybridBitSet<T>> for ChunkedBitSet<T> {
fn union(&mut self, other: &HybridBitSet<T>) -> bool {
- // FIXME: this is slow if `other` is dense, and could easily be
- // improved, but it hasn't been a problem in practice so far.
+ // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+ // in practice so far.
+ // If a a faster implementation of this operation is required, consider
+ // reopening https://github.com/rust-lang/rust/pull/94625
assert_eq!(self.domain_size, other.domain_size());
sequential_update(|elem| self.insert(elem), other.iter())
}
fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
- // FIXME: this is slow if `other` is dense, and could easily be
- // improved, but it hasn't been a problem in practice so far.
+ // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+ // in practice so far.
+ // If a a faster implementation of this operation is required, consider
+ // reopening https://github.com/rust-lang/rust/pull/94625
assert_eq!(self.domain_size, other.domain_size());
sequential_update(|elem| self.remove(elem), other.iter())
}
/// Check whether `r_a <= r_b` is found in the relation.
fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
- r_a == r_b || self.relation.contains(&r_a, &r_b)
+ r_a == r_b || self.relation.contains(r_a, r_b)
}
/// True for free regions other than `'static`.
let result = if r_a == r_b {
r_a
} else {
- match self.relation.postdom_upper_bound(&r_a, &r_b) {
+ match self.relation.postdom_upper_bound(r_a, r_b) {
None => tcx.lifetimes.re_static,
- Some(r) => *r,
+ Some(r) => r,
}
};
debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
type Lifted = FreeRegionMap<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
- self.relation.maybe_map(|&fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
+ self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
}
}
+//! Greatest lower bound. See [`lattice`].
+
use super::combine::CombineFields;
use super::lattice::{self, LatticeDir};
use super::InferCtxt;
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
- /// Replaces all regions (resp. types) bound by `binder` with placeholder
- /// regions (resp. types) and return a map indicating which bound-region
- /// placeholder region. This is the first step of checking subtyping
- /// when higher-ranked things are involved.
+ /// Replaces all bound variables (lifetimes, types, and constants) bound by
+ /// `binder` with placeholder variables.
///
- /// **Important:** You have to be careful to not leak these placeholders,
- /// for more information about how placeholders and HRTBs work, see
- /// the [rustc dev guide].
+ /// This is the first step of checking subtyping when higher-ranked things are involved.
+ /// For more details visit the relevant sections of the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
-//! # Lattice Variables
+//! # Lattice variables
//!
-//! This file contains generic code for operating on inference variables
-//! that are characterized by an upper- and lower-bound. The logic and
-//! reasoning is explained in detail in the large comment in `infer.rs`.
+//! Generic code for operating on [lattices] of inference variables
+//! that are characterized by an upper- and lower-bound.
//!
-//! The code in here is defined quite generically so that it can be
+//! The code is defined quite generically so that it can be
//! applied both to type variables, which represent types being inferred,
//! and fn variables, which represent function types being inferred.
-//! It may eventually be applied to their types as well, who knows.
+//! (It may eventually be applied to their types as well.)
//! In some cases, the functions are also generic with respect to the
//! operation on the lattice (GLB vs LUB).
//!
-//! Although all the functions are generic, we generally write the
-//! comments in a way that is specific to type variables and the LUB
-//! operation. It's just easier that way.
+//! ## Note
//!
-//! In general all of the functions are defined parametrically
-//! over a `LatticeValue`, which is a value defined with respect to
-//! a lattice.
+//! Although all the functions are generic, for simplicity, comments in the source code
+//! generally refer to type variables and the LUB operation.
+//!
+//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty};
+/// Trait for returning data about a lattice, and for abstracting
+/// over the "direction" of the lattice operation (LUB/GLB).
+///
+/// GLB moves "down" the lattice (to smaller values); LUB moves
+/// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
+/// Relates two types using a given lattice.
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
this: &mut L,
a: Ty<'tcx>,
+//! Least upper bound. See [`lattice`].
+
use super::combine::CombineFields;
use super::lattice::{self, LatticeDir};
use super::InferCtxt;
let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
debug!("compare_layouts({:?}, {:?})", a, b);
- let a_layout = &cx.layout_of(a)?.layout.abi;
- let b_layout = &cx.layout_of(b)?.layout.abi;
+ let a_layout = &cx.layout_of(a)?.layout.abi();
+ let b_layout = &cx.layout_of(b)?.layout.abi();
debug!(
"comparing layouts: {:?} == {:?} = {}",
a_layout,
builtin::{self, FORBIDDEN_LINT_GROUPS},
Level, Lint, LintExpectationId, LintId,
};
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
self.store
}
+ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+ &self.sets.list[self.cur].specs
+ }
+
+ fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
+ &mut self.sets.list[self.cur].specs
+ }
+
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
- let mut specs = FxHashMap::default();
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
+ self.cur =
+ self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
for &(ref lint_name, level) in &sess.opts.lint_opts {
store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
let orig_level = level;
};
for id in ids {
// ForceWarn and Forbid cannot be overriden
- if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
+ if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
continue;
}
- self.check_gated_lint(id, DUMMY_SP);
- let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
- specs.insert(id, (level, src));
+ if self.check_gated_lint(id, DUMMY_SP) {
+ let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
+ self.current_specs_mut().insert(id, (level, src));
+ }
}
}
-
- self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
}
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
/// (e.g. if a forbid was already inserted on the same scope), then emits a
/// diagnostic with no change to `specs`.
- fn insert_spec(
- &mut self,
- specs: &mut FxHashMap<LintId, LevelAndSource>,
- id: LintId,
- (level, src): LevelAndSource,
- ) {
+ fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
let (old_level, old_src) =
- self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
+ self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
// Setting to a non-forbid level is an error if the lint previously had
// a forbid level. Note that this is not necessarily true even with a
// `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
};
debug!(
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
- fcw_warning, specs, old_src, id_name
+ fcw_warning,
+ self.current_specs(),
+ old_src,
+ id_name
);
let decorate_diag = |diag: &mut Diagnostic| {
}
}
if let Level::ForceWarn = old_level {
- specs.insert(id, (old_level, old_src));
+ self.current_specs_mut().insert(id, (old_level, old_src));
} else {
- specs.insert(id, (level, src));
+ self.current_specs_mut().insert(id, (level, src));
}
}
is_crate_node: bool,
source_hir_id: Option<HirId>,
) -> BuilderPush {
- let mut specs = FxHashMap::default();
+ let prev = self.cur;
+ self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
+
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
for (attr_index, attr) in attrs.iter().enumerate() {
};
if metas.is_empty() {
- // FIXME (#55112): issue unused-attributes lint for `#[level()]`
+ // This emits the unused_attributes lint for `#[level()]`
continue;
}
ast::MetaItemKind::Word => {} // actual lint names handled later
ast::MetaItemKind::NameValue(ref name_value) => {
if item.path == sym::reason {
- // FIXME (#55112): issue unused-attributes lint if we thereby
- // don't have any lint names (`#[level(reason = "foo")]`)
if let ast::LitKind::Str(rationale, _) = name_value.kind {
if !self.sess.features_untracked().lint_reasons {
feature_err(
reason,
);
for &id in *ids {
- self.check_gated_lint(id, attr.span);
- self.insert_spec(&mut specs, id, (level, src));
+ if self.check_gated_lint(id, attr.span) {
+ self.insert_spec(id, (level, src));
+ }
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
reason,
);
for id in ids {
- self.insert_spec(&mut specs, *id, (level, src));
+ self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
}
Err((Some(ids), ref new_lint_name)) => {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
- let (lvl, src) =
- self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+ let (lvl, src) = self.sets.get_lint_level(
+ lint,
+ self.cur,
+ Some(self.current_specs()),
+ &sess,
+ );
struct_lint_level(
self.sess,
lint,
reason,
);
for id in ids {
- self.insert_spec(&mut specs, *id, (level, src));
+ self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
CheckLintNameResult::Warning(msg, renamed) => {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
- let (renamed_lint_level, src) =
- self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+ let (renamed_lint_level, src) = self.sets.get_lint_level(
+ lint,
+ self.cur,
+ Some(self.current_specs()),
+ &sess,
+ );
struct_lint_level(
self.sess,
lint,
}
CheckLintNameResult::NoLint(suggestion) => {
let lint = builtin::UNKNOWN_LINTS;
- let (level, src) =
- self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+ let (level, src) = self.sets.get_lint_level(
+ lint,
+ self.cur,
+ Some(self.current_specs()),
+ self.sess,
+ );
struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
let name = if let Some(tool_ident) = tool_ident {
format!("{}::{}", tool_ident.name, name)
{
let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
for &id in ids {
- self.check_gated_lint(id, attr.span);
- self.insert_spec(&mut specs, id, (level, src));
+ if self.check_gated_lint(id, attr.span) {
+ self.insert_spec(id, (level, src));
+ }
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
}
if !is_crate_node {
- for (id, &(level, ref src)) in specs.iter() {
+ for (id, &(level, ref src)) in self.current_specs().iter() {
if !id.lint.crate_level_only {
continue;
}
let lint = builtin::UNUSED_ATTRIBUTES;
let (lint_level, lint_src) =
- self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+ self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
struct_lint_level(
self.sess,
lint,
}
}
- let prev = self.cur;
- if !specs.is_empty() {
- self.cur = self.sets.list.push(LintSet { specs, parent: prev });
+ if self.current_specs().is_empty() {
+ self.sets.list.pop();
+ self.cur = prev;
}
BuilderPush { prev, changed: prev != self.cur }
}
/// Checks if the lint is gated on a feature that is not enabled.
- fn check_gated_lint(&self, lint_id: LintId, span: Span) {
+ ///
+ /// Returns `true` if the lint's feature is enabled.
+ fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
if let Some(feature) = lint_id.lint.feature_gate {
if !self.sess.features_untracked().enabled(feature) {
- feature_err(
- &self.sess.parse_sess,
- feature,
- span,
- &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
- )
- .emit();
+ let lint = builtin::UNKNOWN_LINTS;
+ let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+ struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
+ let mut db =
+ lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
+ db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
+ add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
+ db.emit();
+ });
+ return false;
}
}
+ true
}
/// Called after `push` when the scope of a set of attributes are exited.
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
- (0, _) => unreachable!("Non-null optimisation extended to a non-zero value."),
+ (0, x) if x == field_ty_scalar.value.size(&cx.tcx).unsigned_int_max() - 1 => {
+ return Some(get_nullable_type(cx, field_ty).unwrap());
+ }
(1, _) => {
return Some(get_nullable_type(cx, field_ty).unwrap());
}
let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum tag.
- let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
+ let bytes = variant_layout.size().bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes
SUSPICIOUS_AUTO_TRAIT_IMPLS,
UNEXPECTED_CFGS,
DEPRECATED_WHERE_CLAUSE_LOCATION,
+ TEST_UNSTABLE_LINT,
]
}
/// // ^^^^^^^^
/// // This call to try_into matches both Foo:try_into and TryInto::try_into as
/// // `TryInto` has been added to the Rust prelude in 2021 edition.
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
///
Warn,
"deprecated where clause location"
}
+
+declare_lint! {
+ /// The `test_unstable_lint` lint tests unstable lints and is perma-unstable.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// #![allow(test_unstable_lint)]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In order to test the behavior of unstable lints, a permanently-unstable
+ /// lint is required. This lint can be used to trigger warnings and errors
+ /// from the compiler related to unstable lints.
+ pub TEST_UNSTABLE_LINT,
+ Deny,
+ "this unstable lint is only for testing",
+ @feature_gate = sym::test_unstable_lint;
+}
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Pass.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Support/Signals.h"
#include "llvm/ADT/Optional.h"
#(#attrs)*
#[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
#[rustc_layout_scalar_valid_range_end(#max)]
+ #[rustc_pass_by_value]
#vis struct #name {
private: u32,
}
.layout;
// In both stdcall and fastcall, we always round up the argument size to the
// nearest multiple of 4 bytes.
- (layout.size.bytes_usize() + 3) & !3
+ (layout.size().bytes_usize() + 3) & !3
})
.sum()
}
macro_rules! arena_types {
($macro:path) => (
$macro!([
- [] layout: rustc_target::abi::Layout,
+ [] layout: rustc_target::abi::LayoutS<'tcx>,
[] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
// AdtDef are interned and compared by address
[decode] adt_def: rustc_middle::ty::AdtDef,
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(trusted_len)]
+#![feature(type_alias_impl_trait)]
#![feature(crate_visibility_modifier)]
#![feature(associated_type_bounds)]
#![feature(rustc_attrs)]
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use crate::ty::TyCtxt;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::Node;
/// conditional expression or repeating block. (Note that the
/// enclosing scope ID for the block associated with a closure is
/// the closure itself.)
- pub parent_map: FxHashMap<Scope, (Scope, ScopeDepth)>,
+ pub parent_map: FxIndexMap<Scope, (Scope, ScopeDepth)>,
/// Maps from a variable or binding ID to the block in which that
/// variable is declared.
- var_map: FxHashMap<hir::ItemLocalId, Scope>,
+ var_map: FxIndexMap<hir::ItemLocalId, Scope>,
/// Maps from a `NodeId` to the associated destruction scope (if any).
- destruction_scopes: FxHashMap<hir::ItemLocalId, Scope>,
+ destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
/// `rvalue_scopes` includes entries for those expressions whose
/// cleanup scope is larger than the default. The map goes from the
/// Returns explicitly-requested zero-based version of the counter id, used
/// during codegen. LLVM expects zero-based indexes.
- pub fn zero_based_index(&self) -> u32 {
+ pub fn zero_based_index(self) -> u32 {
let one_based_index = self.as_u32();
debug_assert!(one_based_index > 0);
one_based_index - 1
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};
+use std::fmt;
use std::iter;
use std::ops::{Deref, Range};
use std::ptr;
use rustc_ast::Mutability;
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_span::DUMMY_SP;
use rustc_target::abi::{Align, HasDataLayout, Size};
pub extra: Extra,
}
+/// Interned types generally have an `Outer` type and an `Inner` type, where
+/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
+/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
+/// outer type and `TyS` is its inner type.
+///
+/// Here things are different because only const allocations are interned. This
+/// means that both the inner type (`Allocation`) and the outer type
+/// (`ConstAllocation`) are used quite a bit.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>(
+ pub Interned<'tcx, Allocation<Tag, Extra>>,
+);
+
+impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This matches how `Allocation` is printed. We print it like this to
+ // avoid having to update expected output in a lot of tests.
+ write!(f, "{:?}", self.inner())
+ }
+}
+
+impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> {
+ pub fn inner(self) -> &'tcx Allocation<Tag, Extra> {
+ self.0.0
+ }
+}
+
/// We have our own error type that does not know about the `AllocId`; that information
/// is added when converting to `InterpError`.
#[derive(Debug)]
MemoryAccessTest,
/// We are doing pointer arithmetic.
PointerArithmeticTest,
+ /// We are doing pointer offset_from.
+ OffsetFromTest,
/// None of the above -- generic/unspecific inbounds test.
InboundsTest,
}
CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
+ CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
CheckInAllocMsg::InboundsTest => "",
}
)
DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
write!(f, "null pointer is not a valid pointer for this operation")
}
+ DanglingIntPointer(0, msg) => {
+ write!(f, "{}null pointer is not a valid pointer", msg)
+ }
DanglingIntPointer(i, msg) => {
write!(f, "{}0x{:x} is not a valid pointer", msg, i)
}
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
pub use self::allocation::{
- alloc_range, AllocRange, Allocation, InitChunk, InitChunkIter, InitMask, Relocations,
+ alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask,
+ Relocations,
};
pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
let alloc_id = decoder.with_position(pos, |decoder| {
match alloc_kind {
AllocDiscriminant::Alloc => {
- let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder);
+ let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
// We already have a reserved `AllocId`.
let alloc_id = alloc_id.unwrap();
trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
/// This is also used to break the cycle in recursive statics.
Static(DefId),
/// The alloc ID points to memory.
- Memory(&'tcx Allocation),
+ Memory(ConstAllocation<'tcx>),
}
impl<'tcx> GlobalAlloc<'tcx> {
/// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
#[track_caller]
#[inline]
- pub fn unwrap_memory(&self) -> &'tcx Allocation {
+ pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
match *self {
GlobalAlloc::Memory(mem) => mem,
_ => bug!("expected memory, got {:?}", self),
/// Statics with identical content will still point to the same `Allocation`, i.e.,
/// their data will be deduplicated through `Allocation` interning -- but they
/// are different places in memory and as such need different IDs.
- pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId {
+ pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
let id = self.reserve_alloc_id();
self.set_alloc_id_memory(id, mem);
id
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
/// call this function twice, even with the same `Allocation` will ICE the compiler.
- pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) {
+ pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
}
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
/// twice for the same `(AllocId, Allocation)` pair.
- fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) {
+ fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
}
}
pub fn eval_static_initializer(
self,
def_id: DefId,
- ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
trace!("eval_static_initializer: Need to compute {:?}", def_id);
assert!(self.is_static(def_id));
let instance = ty::Instance::mono(self, def_id);
self,
gid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
let param_env = param_env.with_const();
trace!("eval_to_allocation: Need to compute {:?}", gid);
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
use super::{
- AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic, Provenance,
+ AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
};
/// Represents the result of const evaluation via the `eval_to_allocation` query.
Scalar(Scalar),
/// Used only for `&[u8]` and `&str`
- Slice { data: &'tcx Allocation, start: usize, end: usize },
+ Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
/// A value not represented/representable by `Scalar` or `Slice`
ByRef {
/// The backing memory of the value, may contain more memory than needed for just the value
- /// in order to share `Allocation`s between values
- alloc: &'tcx Allocation,
+ /// in order to share `ConstAllocation`s between values
+ alloc: ConstAllocation<'tcx>,
/// Offset into `alloc`
offset: Size,
},
pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
if let ConstValue::Slice { data, start, end } = val {
let len = end - start;
- data.get_bytes(
- cx,
- AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
- )
- .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
+ data.inner()
+ .get_bytes(
+ cx,
+ AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
+ )
+ .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
} else {
bug!("expected const slice, but found another const value");
}
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
/// Type for MIR `Assert` terminator error messages.
pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
+// FIXME: Change `Successors` to `impl Iterator<Item = BasicBlock>`.
+#[allow(rustc::pass_by_value)]
pub type Successors<'a> =
iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
pub type SuccessorsMut<'a> =
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
-// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
+// This type is fairly frequently used, so we shouldn't unintentionally increase
+// its size.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PlaceElem<'_>, 24);
(base, proj)
})
}
+
+ /// Generates a new place by appending `more_projections` to the existing ones
+ /// and interning the result.
+ pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
+ if more_projections.is_empty() {
+ return self;
+ }
+
+ let mut v: Vec<PlaceElem<'tcx>>;
+
+ let new_projections = if self.projection.is_empty() {
+ more_projections
+ } else {
+ v = Vec::with_capacity(self.projection.len() + more_projections.len());
+ v.extend(self.projection);
+ v.extend(more_projections);
+ &v
+ };
+
+ Place { local: self.local, projection: tcx.intern_place_elems(new_projections) }
+ }
}
impl From<Local> for Place<'_> {
Operand::Copy(_) | Operand::Move(_) => None,
}
}
+
+ /// Gets the `ty::FnDef` from an operand if it's a constant function item.
+ ///
+ /// While this is unlikely in general, it's the normal case of what you'll
+ /// find as the `func` in a [`TerminatorKind::Call`].
+ pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> {
+ let const_ty = self.constant()?.literal.ty();
+ if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None }
+ }
}
///////////////////////////////////////////////////////////////////////////
impl<'tcx> Constant<'tcx> {
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
- match self.literal.const_for_ty()?.val().try_to_scalar() {
+ match self.literal.try_to_scalar() {
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
#[inline]
fn from(ct: ty::Const<'tcx>) -> Self {
- Self::Ty(ct)
+ match ct.val() {
+ ty::ConstKind::Value(cv) => {
+ // FIXME Once valtrees are introduced we need to convert those
+ // into `ConstValue` instances here
+ Self::Val(cv, ct.ty())
+ }
+ _ => Self::Ty(ct),
+ }
}
}
Self::Val(val, _) => val.try_to_machine_usize(tcx),
}
}
+
+ pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+ let cv = ConstValue::from_bool(v);
+ Self::Val(cv, tcx.types.bool)
+ }
+
+ pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
+ let cv = ConstValue::Scalar(Scalar::ZST);
+ Self::Val(cv, ty)
+ }
+
+ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+ let ty = tcx.types.usize;
+ let size = tcx
+ .layout_of(ty::ParamEnv::empty().and(ty))
+ .unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
+ .size;
+ let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
+
+ Self::Val(cv, ty)
+ }
}
/// A collection of projections into user types.
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_middle::mir::interpret::{
- read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance,
+ read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, Pointer,
+ Provenance,
};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::MirSource;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::Size;
-use std::ops::ControlFlow;
const INDENT: &str = " ";
/// Alignment for lining up comments following MIR statements
body: &Body<'_>,
w: &mut dyn Write,
) -> io::Result<()> {
- fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
- alloc.relocations().values().map(|id| *id)
+ fn alloc_ids_from_alloc(
+ alloc: ConstAllocation<'_>,
+ ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
+ alloc.inner().relocations().values().map(|id| *id)
}
fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
- ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => {
+ ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
Either::Left(Either::Left(std::iter::once(ptr.provenance)))
}
ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
}
}
struct CollectAllocIds(BTreeSet<AllocId>);
- impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
- fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+
+ impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+ fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
if let ty::ConstKind::Value(val) = c.val() {
self.0.extend(alloc_ids_from_const(val));
}
- c.super_visit_with(self)
+ }
+
+ fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+ match c.literal {
+ ConstantKind::Ty(c) => self.visit_const(c, loc),
+ ConstantKind::Val(val, _) => {
+ self.0.extend(alloc_ids_from_const(val));
+ }
+ }
}
}
+
let mut visitor = CollectAllocIds(Default::default());
- body.visit_with(&mut visitor);
+ visitor.visit_body(body);
+
// `seen` contains all seen allocations, including the ones we have *not* printed yet.
// The protocol is to first `insert` into `seen`, and only if that returns `true`
// then push to `todo`.
let mut todo: Vec<_> = seen.iter().copied().collect();
while let Some(id) = todo.pop() {
let mut write_allocation_track_relocs =
- |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> {
+ |w: &mut dyn Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
// `.rev()` because we are popping them from the back of the `todo` vector.
for id in alloc_ids_from_alloc(alloc).rev() {
if seen.insert(id) {
todo.push(id);
}
}
- write!(w, "{}", display_allocation(tcx, alloc))
+ write!(w, "{}", display_allocation(tcx, alloc.inner()))
};
write!(w, "\n{}", id)?;
match tcx.get_global_alloc(id) {
/// not carry a `Ty` for `T`.)
///
/// Note that the resulting type has not been normalized.
- pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
+ pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
let answer = match self.ty.kind() {
ty::Adt(adt_def, substs) => {
let variant_def = match self.variant_index {
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
- self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty)
+ self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
- mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
+ mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
- T: ::std::fmt::Debug,
+ T: ::std::fmt::Debug + Copy,
{
let answer = match *elem {
ProjectionElem::Deref => {
ProjectionElem::Downcast(_name, index) => {
PlaceTy { ty: self.ty, variant_index: Some(index) }
}
- ProjectionElem::Field(ref f, ref fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
+ ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
self.super_var_debug_info(var_debug_info);
}
+ #[allow(rustc::pass_by_value)]
fn visit_local(&mut self,
_local: & $($mutability)? Local,
_context: PlaceContext,
_location: Location) {
}
+ #[allow(rustc::pass_by_value)]
fn visit_source_scope(&mut self,
scope: & $($mutability)? SourceScope) {
self.super_source_scope(scope);
}
}
+ #[allow(rustc::pass_by_value)]
fn super_source_scope(&mut self,
_scope: & $($mutability)? SourceScope) {
}
use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
};
/// This is only distinguished from `Literal` so that we can register some
/// info for diagnostics.
StaticRef {
- literal: Const<'tcx>,
+ alloc_id: AllocId,
+ ty: Ty<'tcx>,
def_id: DefId,
},
/// Inline assembly, i.e. `asm!()`.
}
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
- StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+ StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
for op in &**operands {
use InlineAsmOperand::*;
/// let mut t = (0,1);
///
/// let c = || {
- /// println!("{}",t); // L1
+ /// println!("{t}"); // L1
/// t.1 = 4; // L2
/// };
/// ```
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::mir::{
self,
- interpret::{AllocId, Allocation},
+ interpret::{AllocId, ConstAllocation},
};
use crate::thir;
use crate::traits;
}
}
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ self.inner().encode(e)
+ }
+}
+
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
e.encode_alloc_id(self)
}
}
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
- fn decode(decoder: &mut D) -> &'tcx Self {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
}
}
&'tcx ty::List<Ty<'tcx>>,
&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
&'tcx traits::ImplSource<'tcx, ()>,
- &'tcx Allocation,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,
&'tcx mir::BorrowCheckResult<'tcx>,
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability;
-use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
+use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
use crate::mir::{
Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
};
use rustc_span::source_map::{MultiSpan, SourceMap};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
use rustc_type_ir::TypeFlags;
const_: InternedSet<'tcx, ConstS<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
- layout: InternedSet<'tcx, Layout>,
+ layout: InternedSet<'tcx, LayoutS<'tcx>>,
adt_def: InternedSet<'tcx, AdtDef>,
}
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
}
-// Deprecated: we are in the process of converting all uses to `nop_lift`.
-macro_rules! nop_lift_old {
- ($set:ident; $ty:ty => $lifted:ty) => {
- impl<'a, 'tcx> Lift<'tcx> for $ty {
- type Lifted = $lifted;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
- Some(unsafe { mem::transmute(self) })
- } else {
- None
- }
- }
- }
- };
-}
-
macro_rules! nop_lift {
($set:ident; $ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for $ty {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; Const<'a> => Const<'tcx>}
-nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
direct_interners! {
region: mk_region(RegionKind): Region -> Region<'tcx>,
const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+ const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
+ layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
}
macro_rules! direct_interners_old {
// FIXME: eventually these should all be converted to `direct_interners`.
direct_interners_old! {
- const_allocation: intern_const_alloc(Allocation),
- layout: intern_layout(Layout),
adt_def: intern_adt_def(AdtDef),
}
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
use rustc_attr as attr;
+use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
}
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
- fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
+ fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
let dl = self.data_layout();
let b_align = b.value.align(dl);
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
.chain(Niche::from_scalar(dl, Size::ZERO, a))
.max_by_key(|niche| niche.available(dl));
- Layout {
+ LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: vec![Size::ZERO, b_offset],
fields: &[TyAndLayout<'_>],
repr: &ReprOptions,
kind: StructKind,
- ) -> Result<Layout, LayoutError<'tcx>> {
+ ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
let dl = self.data_layout();
let pack = repr.pack;
if pack.is_some() && repr.align.is_some() {
// Two non-ZST fields, and they're both scalars.
(
- Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
- Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
+ Some((
+ i,
+ &TyAndLayout {
+ layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)),
+ ..
+ },
+ )),
+ Some((
+ j,
+ &TyAndLayout {
+ layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)),
+ ..
+ },
+ )),
None,
) => {
// Order by the memory placement, not source order.
abi = Abi::Uninhabited;
}
- Ok(Layout {
+ Ok(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets, memory_index },
abi,
})
}
- fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
let tcx = self.tcx;
let param_env = self.param_env;
let dl = self.data_layout();
assert!(size.bits() <= 128);
Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
};
- let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
+ let scalar =
+ |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
Ok(match *ty.kind() {
// Basic scalars.
- ty::Bool => tcx.intern_layout(Layout::scalar(
+ ty::Bool => tcx.intern_layout(LayoutS::scalar(
self,
Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
)),
- ty::Char => tcx.intern_layout(Layout::scalar(
+ ty::Char => tcx.intern_layout(LayoutS::scalar(
self,
Scalar {
value: Int(I32, false),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range = ptr.valid_range.with_start(1);
- tcx.intern_layout(Layout::scalar(self, ptr))
+ tcx.intern_layout(LayoutS::scalar(self, ptr))
}
// The never type.
- ty::Never => tcx.intern_layout(Layout {
+ ty::Never => tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
abi: Abi::Uninhabited,
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
- return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
}
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
let metadata = match unsized_part.kind() {
ty::Foreign(..) => {
- return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
}
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
let largest_niche = if count != 0 { element.largest_niche } else { None };
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: element.size, count },
abi,
}
ty::Slice(element) => {
let element = self.layout_of(element)?;
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: element.size, count: 0 },
abi: Abi::Aggregate { sized: false },
size: Size::ZERO,
})
}
- ty::Str => tcx.intern_layout(Layout {
+ ty::Str => tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
abi: Abi::Aggregate { sized: false },
// Extract the number of elements from the layout of the array field:
let Ok(TyAndLayout {
- layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
+ layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)),
..
}) = self.layout_of(f0_ty) else {
return Err(LayoutError::Unknown(ty));
FieldsShape::Array { stride: e_ly.size, count: e_len }
};
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields,
abi: Abi::Vector { element: e_abi, count: e_len },
align = align.min(AbiAndPrefAlign::new(pack));
}
- return Ok(tcx.intern_layout(Layout {
+ return Ok(tcx.intern_layout(LayoutS {
variants: Variants::Single { index },
fields: FieldsShape::Union(
NonZeroUsize::new(variants[index].len())
align = align.max(st.align);
- Ok(st)
+ Ok(tcx.intern_layout(st))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
- let offset = st[i].fields.offset(field_index) + niche.offset;
- let size = st[i].size;
+ let offset = st[i].fields().offset(field_index) + niche.offset;
+ let size = st[i].size();
- let abi = if st.iter().all(|v| v.abi.is_uninhabited()) {
+ let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
Abi::Uninhabited
} else {
- match st[i].abi {
+ match st[i].abi() {
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
Abi::ScalarPair(first, second) => {
// We need to use scalar_unit to reset the
let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
- niche_filling_layout = Some(Layout {
+ niche_filling_layout = Some(LayoutS {
variants: Variants::Multiple {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
- let tagged_layout = Layout {
+ let layout_variants =
+ layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
+
+ let tagged_layout = LayoutS {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
ty: Ty<'tcx>,
def_id: hir::def_id::DefId,
substs: SubstsRef<'tcx>,
- ) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+ ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
use SavedLocalEligibility::*;
let tcx = self.tcx;
let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
value: Primitive::Int(discr_int, false),
valid_range: WrappingRange { start: 0, end: max_discr },
};
- let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
+ let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals
size = size.max(variant.size);
align = align.max(variant.align);
- Ok(variant)
+ Ok(tcx.intern_layout(variant))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
size = size.align_to(align.abi);
- let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited())
- {
- Abi::Uninhabited
- } else {
- Abi::Aggregate { sized: true }
- };
+ let abi =
+ if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
- let layout = tcx.intern_layout(Layout {
+ let layout = tcx.intern_layout(LayoutS {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
_ => bug!(),
};
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: variant_index },
fields: match NonZeroUsize::new(fields) {
Some(fields) => FieldsShape::Union(fields),
})
}
- Variants::Multiple { ref variants, .. } => &variants[variant_index],
+ Variants::Multiple { ref variants, .. } => variants[variant_index],
};
- assert_eq!(layout.variants, Variants::Single { index: variant_index });
+ assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
TyAndLayout { ty: this.ty, layout }
}
) -> TyMaybeWithLayout<'tcx> {
let tcx = cx.tcx();
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
- let layout = Layout::scalar(cx, tag);
- TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
+ TyAndLayout {
+ layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+ ty: tag.value.to_ty(tcx),
+ }
};
match *this.ty.kind() {
Some(GlobalAlloc::Memory(alloc)) => {
let len = int.assert_bits(self.tcx().data_layout.pointer_size);
let range = AllocRange { start: offset, size: Size::from_bytes(len) };
- if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) {
+ if let Ok(byte_str) = alloc.inner().get_bytes(&self.tcx(), range) {
p!(pretty_print_byte_str(byte_str))
} else {
p!("<too short allocation>")
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
// this result to affect interpreter execution.
- let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let byte_str =
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
self.pretty_print_byte_str(byte_str)
}
(
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
- let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let slice =
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
p!(write("{:?}", String::from_utf8_lossy(slice)));
Ok(self)
}
// cast is ok because we already checked for pointer size (32 or 64 bit) above
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
- let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap();
+ let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap();
p!("*");
p!(pretty_print_byte_str(byte_str));
Ok(self)
substs: SubstsRef<'tcx>,
) -> ty::TraitRef<'tcx> {
let defs = tcx.generics_of(trait_id);
-
ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
}
}
}
}
+ #[inline]
+ pub fn is_array_slice(self) -> bool {
+ match self.kind() {
+ Slice(_) => true,
+ RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+ _ => false,
+ }
+ }
+
#[inline]
pub fn is_array(self) -> bool {
matches!(self.kind(), Array(..))
}
}
}
+
+ /// Fast path helper for primitives which are always `Copy` and which
+ /// have a side-effect-free `Clone` impl.
+ ///
+ /// Returning true means the type is known to be pure and `Copy+Clone`.
+ /// Returning `false` means nothing -- could be `Copy`, might not be.
+ ///
+ /// This is mostly useful for optimizations, as there are the types
+ /// on which we can replace cloning with dereferencing.
+ pub fn is_trivially_pure_clone_copy(self) -> bool {
+ match self.kind() {
+ ty::Bool | ty::Char | ty::Never => true,
+
+ // These aren't even `Clone`
+ ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
+
+ ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+
+ // The voldemort ZSTs are fine.
+ ty::FnDef(..) => true,
+
+ ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
+
+ // A 100-tuple isn't "trivial", so doing this only for reasonable sizes.
+ ty::Tuple(field_tys) => {
+ field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
+ }
+
+ // Sometimes traits aren't implemented for every ABI or arity,
+ // because we can't be generic over everything yet.
+ ty::FnPtr(..) => false,
+
+ // Definitely absolutely not copy.
+ ty::Ref(_, _, hir::Mutability::Mut) => false,
+
+ // Thin pointers & thin shared references are pure-clone-copy, but for
+ // anything with custom metadata it might be more complicated.
+ ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
+
+ ty::Generator(..) | ty::GeneratorWitness(..) => false,
+
+ // Might be, but not "trivial" so just giving the safe answer.
+ ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false,
+
+ ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+
+ ty::Bound(..) | ty::Placeholder(..) => {
+ bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
+ }
+ }
+ }
}
/// Extra information about why we ended up with a particular variance.
tcx_at: TyCtxtAt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
- tcx_at.is_copy_raw(param_env.and(self))
+ self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
}
/// Checks whether values of this type `T` have a size known at
use crate::build::CFG;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
impl<'tcx> CFG<'tcx> {
crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
Rvalue::Use(Operand::Constant(Box::new(Constant {
span: source_info.span,
user_ty: None,
- literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
+ literal: ConstantKind::from_zero_sized(tcx.types.unit),
}))),
);
}
//! See docs in build/expr/mod.rs
use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
assert_eq!(literal.ty(), ty);
Constant { span, user_ty, literal: literal.into() }
}
- ExprKind::StaticRef { literal, .. } => {
- Constant { span, user_ty: None, literal: literal.into() }
+ ExprKind::StaticRef { alloc_id, ty, .. } => {
+ let const_val =
+ ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+ let literal = ConstantKind::Val(const_val, ty);
+
+ Constant { span, user_ty: None, literal }
}
ExprKind::ConstBlock { value } => {
Constant { span: span, user_ty: None, literal: value.into() }
use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
use std::iter;
impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant {
span: expr_span,
user_ty: None,
- literal: ty::Const::from_bool(this.tcx, true).into(),
+ literal: ConstantKind::from_bool(this.tcx, true),
},
);
Constant {
span: expr_span,
user_ty: None,
- literal: ty::Const::from_bool(this.tcx, false).into(),
+ literal: ConstantKind::from_bool(this.tcx, false),
},
);
span: expr_span,
user_ty: None,
literal: match op {
- LogicalOp::And => ty::Const::from_bool(this.tcx, false).into(),
- LogicalOp::Or => ty::Const::from_bool(this.tcx, true).into(),
+ LogicalOp::And => ConstantKind::from_bool(this.tcx, false),
+ LogicalOp::Or => ConstantKind::from_bool(this.tcx, true),
},
},
);
Constant {
span: source_info.span,
user_ty: None,
- literal: ty::Const::from_usize(self.tcx, value).into(),
+ literal: ConstantKind::from_usize(self.tcx, value),
},
);
temp
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+
+ // FIXME Do we want to use `from_inline_const` once valtrees
+ // are introduced? This would create `ValTree`s that will never be used...
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
let kind = if self.tcx.is_thread_local_static(id) {
ExprKind::ThreadLocalRef(id)
} else {
- let ptr = self.tcx.create_static_alloc(id);
- ExprKind::StaticRef {
- literal: ty::Const::from_scalar(
- self.tcx,
- Scalar::from_pointer(ptr.into(), &self.tcx),
- ty,
- ),
- def_id: id,
- }
+ let alloc_id = self.tcx.create_static_alloc(id);
+ ExprKind::StaticRef { alloc_id, ty, def_id: id }
};
ExprKind::Deref {
arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_errors::{
- error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+ ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::def::*;
};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
-use rustc_span::{DesugaringKind, ExpnKind, Span};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span};
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match def_id.as_local() {
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
match &ex.kind {
- hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
+ hir::ExprKind::Match(scrut, arms, source) => {
+ self.check_match(scrut, arms, *source, ex.span)
+ }
hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
self.check_let(pat, init, *span)
}
scrut: &hir::Expr<'_>,
hir_arms: &'tcx [hir::Arm<'tcx>],
source: hir::MatchSource,
+ expr_span: Span,
) {
let mut cx = self.new_cx(scrut.hir_id);
}
// Check if the match is exhaustive.
- let is_empty_match = arms.is_empty();
let witnesses = report.non_exhaustiveness_witnesses;
if !witnesses.is_empty() {
if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
let pat = hir_arms[1].pat.for_loop_some().unwrap();
self.check_irrefutable(pat, "`for` loop binding", None);
} else {
- non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+ non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span);
}
}
}
}
let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
+
+ let mut bindings = vec![];
+
let mut err = struct_span_err!(
self.tcx.sess,
pat.span,
false
}
_ => {
+ pat.walk(&mut |pat: &hir::Pat<'_>| {
+ match pat.kind {
+ hir::PatKind::Binding(_, _, ident, _) => {
+ bindings.push(ident);
+ }
+ _ => {}
+ }
+ true
+ });
+
err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
true
}
"`let` bindings require an \"irrefutable pattern\", like a `struct` or \
an `enum` with only one variant",
);
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- err.span_suggestion(
- span,
- "you might want to use `if let` to ignore the variant that isn't matched",
- format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
+ if self.tcx.sess.source_map().span_to_snippet(span).is_ok() {
+ let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
+ let start_span = span.shrink_to_lo();
+ let end_span = semi_span.shrink_to_lo();
+ err.multipart_suggestion(
+ &format!(
+ "you might want to use `if let` to ignore the variant{} that {} matched",
+ pluralize!(witnesses.len()),
+ match witnesses.len() {
+ 1 => "isn't",
+ _ => "aren't",
+ },
+ ),
+ vec![
+ match &bindings[..] {
+ [] => (start_span, "if ".to_string()),
+ [binding] => (start_span, format!("let {} = if ", binding)),
+ bindings => (
+ start_span,
+ format!(
+ "let ({}) = if ",
+ bindings
+ .iter()
+ .map(|ident| ident.to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ ),
+ ),
+ },
+ match &bindings[..] {
+ [] => (semi_span, " { todo!() }".to_string()),
+ [binding] => {
+ (end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
+ }
+ bindings => (
+ end_span,
+ format!(
+ " {{ ({}) }} else {{ todo!() }}",
+ bindings
+ .iter()
+ .map(|ident| ident.to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ ),
+ ),
+ },
+ ],
Applicability::HasPlaceholders,
);
+ if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+ err.span_suggestion_verbose(
+ semi_span.shrink_to_lo(),
+ &format!(
+ "alternatively, on nightly, you might want to use \
+ `#![feature(let_else)]` to handle the variant{} that {} matched",
+ pluralize!(witnesses.len()),
+ match witnesses.len() {
+ 1 => "isn't",
+ _ => "aren't",
+ },
+ ),
+ " else { todo!() }".to_string(),
+ Applicability::HasPlaceholders,
+ );
+ }
}
err.note(
"for more information, visit \
let ty_path = cx.tcx.def_path_str(edef.did);
let mut err = lint.build(&format!(
"pattern binding `{}` is named the same as one \
- of the variants of the type `{}`",
+ of the variants of the type `{}`",
ident, ty_path
));
err.code(error_code!(E0170));
scrut_ty: Ty<'tcx>,
sp: Span,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
- is_empty_match: bool,
+ arms: &[hir::Arm<'tcx>],
+ expr_span: Span,
) {
+ let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
_ => false,
// In the case of an empty match, replace the '`_` not covered' diagnostic with something more
// informative.
let mut err;
+ let pattern;
+ let mut patterns_len = 0;
if is_empty_match && !non_empty_enum {
err = create_e0004(
cx.tcx.sess,
sp,
format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
);
+ pattern = "_".to_string();
} else {
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
err = create_e0004(
format!("non-exhaustive patterns: {} not covered", joined_patterns),
);
err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+ patterns_len = witnesses.len();
+ pattern = if witnesses.len() < 4 {
+ witnesses
+ .iter()
+ .map(|witness| witness.to_pat(cx).to_string())
+ .collect::<Vec<String>>()
+ .join(" | ")
+ } else {
+ "_".to_string()
+ };
};
let is_variant_list_non_exhaustive = match scrut_ty.kind() {
};
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.help(
- "ensure that all possible cases are being handled, \
- possibly by adding wildcards or more match arms",
- );
err.note(&format!(
"the matched value is of type `{}`{}",
scrut_ty,
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
{
err.note(&format!(
- "`{}` does not have a fixed maximum value, \
- so a wildcard `_` is necessary to match exhaustively",
+ "`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+ exhaustively",
scrut_ty,
));
if cx.tcx.sess.is_nightly_build() {
err.help(&format!(
- "add `#![feature(precise_pointer_size_matching)]` \
- to the crate attributes to enable precise `{}` matching",
+ "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+ enable precise `{}` matching",
scrut_ty,
));
}
err.note("references are always considered inhabited");
}
}
+
+ let mut suggestion = None;
+ let sm = cx.tcx.sess.source_map();
+ match arms {
+ [] if sp.ctxt() == expr_span.ctxt() => {
+ // Get the span for the empty match body `{}`.
+ let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
+ (format!("\n{}", snippet), " ")
+ } else {
+ (" ".to_string(), "")
+ };
+ suggestion = Some((
+ sp.shrink_to_hi().with_hi(expr_span.hi()),
+ format!(
+ " {{{indentation}{more}{pattern} => todo!(),{indentation}}}",
+ indentation = indentation,
+ more = more,
+ pattern = pattern,
+ ),
+ ));
+ }
+ [only] => {
+ let pre_indentation = if let (Some(snippet), true) = (
+ sm.indentation_before(only.span),
+ sm.is_multiline(sp.shrink_to_hi().with_hi(only.span.lo())),
+ ) {
+ format!("\n{}", snippet)
+ } else {
+ " ".to_string()
+ };
+ let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+ suggestion = Some((
+ only.span.shrink_to_hi(),
+ format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
+ ));
+ }
+ [.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
+ if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
+ let comma =
+ if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+ suggestion = Some((
+ last.span.shrink_to_hi(),
+ format!(
+ "{}{}{} => todo!()",
+ comma,
+ snippet.strip_prefix(",").unwrap_or(&snippet),
+ pattern
+ ),
+ ));
+ }
+ }
+ _ => {}
+ }
+
+ let msg = format!(
+ "ensure that all possible cases are being handled by adding a match arm with a wildcard \
+ pattern{}{}",
+ if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() {
+ ", a match arm with multiple or-patterns"
+ } else {
+ // we are either not suggesting anything, or suggesting `_`
+ ""
+ },
+ match patterns_len {
+ // non-exhaustive enum case
+ 0 if suggestion.is_some() => " as shown",
+ 0 => "",
+ 1 if suggestion.is_some() => " or an explicit pattern as shown",
+ 1 => " or an explicit pattern",
+ _ if suggestion.is_some() => " as shown, or multiple match arms",
+ _ => " or multiple match arms",
+ },
+ );
+ if let Some((span, sugg)) = suggestion {
+ err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ } else {
+ err.help(&msg);
+ }
err.emit();
}
) {
let ty = ty.peel_refs();
if let ty::Adt(def, _) = ty.kind() {
- if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
- err.span_label(sp, format!("`{}` defined here", ty));
- }
-
- if witnesses.len() < 4 {
+ let mut spans = vec![];
+ if witnesses.len() < 5 {
for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
- err.span_label(sp, "not covered");
+ spans.push(sp);
}
}
+ let def_span = cx
+ .tcx
+ .hir()
+ .get_if_local(def.did)
+ .and_then(|node| node.ident())
+ .map(|ident| ident.span)
+ .unwrap_or_else(|| cx.tcx.def_span(def.did));
+ let mut span: MultiSpan =
+ if spans.is_empty() { def_span.into() } else { spans.clone().into() };
+
+ span.push_span_label(def_span, String::new());
+ for pat in spans {
+ span.push_span_label(pat, "not covered".to_string());
+ }
+ err.span_note(span, &format!("`{}` defined here", ty));
}
}
}
impl MoveOutIndex {
- pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex {
- move_data.moves[*self].path
+ pub fn move_path_index(self, move_data: &MoveData<'_>) -> MovePathIndex {
+ move_data.moves[self].path
}
}
/// `MovePathIndex`es.
pub fn iter_locals_enumerated(
&self,
- ) -> impl DoubleEndedIterator<Item = (Local, &MovePathIndex)> + ExactSizeIterator {
- self.locals.iter_enumerated()
+ ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
+ self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
}
}
doctest = false
[dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
&AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
self.tcx.unsafety_check_result(def_id.expect_local());
- self.register_violations(violations, used_unsafe_blocks);
+ self.register_violations(
+ violations,
+ used_unsafe_blocks.iter().map(|(&h, &d)| (h, d)),
+ );
}
},
_ => {}
fn register_violations<'a>(
&mut self,
violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
- new_used_unsafe_blocks: impl IntoIterator<Item = (&'a HirId, &'a UsedUnsafeBlockData)>,
+ new_used_unsafe_blocks: impl IntoIterator<Item = (HirId, UsedUnsafeBlockData)>,
) {
use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn};
new_used_unsafe_blocks
.into_iter()
- .for_each(|(&hir_id, &usage_data)| update_entry(self, hir_id, usage_data));
+ .for_each(|(hir_id, usage_data)| update_entry(self, hir_id, usage_data));
}
fn check_mut_borrowing_layout_constrained_field(
&mut self,
use crate::MirPass;
use rustc_const_eval::const_eval::ConstEvalErr;
use rustc_const_eval::interpret::{
- self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
- Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
+ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
+ ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
};
fn before_access_global(
_memory_extra: &(),
_alloc_id: AllocId,
- allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
+ alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>,
_static_def_id: Option<DefId>,
is_write: bool,
) -> InterpResult<'tcx> {
}
// If the static allocation is mutable, then we can't const prop it as its content
// might be different at runtime.
- if allocation.mutability == Mutability::Mut {
+ if alloc.inner().mutability == Mutability::Mut {
throw_machine_stop_str!("can't access mutable globals in ConstProp");
}
let mut bcb_successors = Vec::new();
for successor in
bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
- .filter_map(|&successor_bb| bb_to_bcb[successor_bb])
+ .filter_map(|successor_bb| bb_to_bcb[successor_bb])
{
if !seen[successor] {
seen[successor] = true;
fn bcb_filtered_successors<'a, 'tcx>(
body: &'tcx &'a mir::Body<'tcx>,
term_kind: &'tcx TerminatorKind<'tcx>,
-) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
+) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
let mut successors = term_kind.successors();
Box::new(
match &term_kind {
// `next().into_iter()`) into the `mir::Successors` aliased type.
_ => successors.next().into_iter().chain(&[]),
}
- .filter(move |&&successor| {
- body[successor].terminator().kind != TerminatorKind::Unreachable
- }),
+ .copied()
+ .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
)
}
F: Fn(
&'tcx &'a mir::Body<'tcx>,
&'tcx TerminatorKind<'tcx>,
- ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+ ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
> {
body: &'tcx &'a mir::Body<'tcx>,
visited: BitSet<BasicBlock>,
F: Fn(
&'tcx &'a mir::Body<'tcx>,
&'tcx TerminatorKind<'tcx>,
- ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+ ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
> ShortCircuitPreorder<'a, 'tcx, F>
{
pub fn new(
F: Fn(
&'tcx &'a mir::Body<'tcx>,
&'tcx TerminatorKind<'tcx>,
- ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+ ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
> Iterator for ShortCircuitPreorder<'a, 'tcx, F>
{
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
use rustc_hir::Mutability;
use rustc_middle::mir::{
BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
- StatementKind, UnOp,
+ Statement, StatementKind, Terminator, TerminatorKind, UnOp,
};
use rustc_middle::ty::{self, TyCtxt};
_ => {}
}
}
+
+ ctx.combine_primitive_clone(
+ &mut block.terminator.as_mut().unwrap(),
+ &mut block.statements,
+ );
}
}
}
}
}
}
+
+ fn combine_primitive_clone(
+ &self,
+ terminator: &mut Terminator<'tcx>,
+ statements: &mut Vec<Statement<'tcx>>,
+ ) {
+ let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind
+ else { return };
+
+ // It's definitely not a clone if there are multiple arguments
+ if args.len() != 1 {
+ return;
+ }
+
+ let Some((destination_place, destination_block)) = *destination
+ else { return };
+
+ // Only bother looking more if it's easy to know what we're calling
+ let Some((fn_def_id, fn_substs)) = func.const_fn_def()
+ else { return };
+
+ // Clone needs one subst, so we can cheaply rule out other stuff
+ if fn_substs.len() != 1 {
+ return;
+ }
+
+ // These types are easily available from locals, so check that before
+ // doing DefId lookups to figure out what we're actually calling.
+ let arg_ty = args[0].ty(self.local_decls, self.tcx);
+
+ let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind()
+ else { return };
+
+ if !inner_ty.is_trivially_pure_clone_copy() {
+ return;
+ }
+
+ let trait_def_id = self.tcx.trait_of_item(fn_def_id);
+ if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() {
+ return;
+ }
+
+ if !self.tcx.consider_optimizing(|| {
+ format!(
+ "InstCombine - Call: {:?} SourceInfo: {:?}",
+ (fn_def_id, fn_substs),
+ terminator.source_info
+ )
+ }) {
+ return;
+ }
+
+ let Some(arg_place) = args.pop().unwrap().place()
+ else { return };
+
+ statements.push(Statement {
+ source_info: terminator.source_info,
+ kind: StatementKind::Assign(box (
+ destination_place,
+ Rvalue::Use(Operand::Copy(
+ arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
+ )),
+ )),
+ });
+ terminator.kind = TerminatorKind::Goto { target: destination_block };
+ }
}
) -> StatementEquality {
let helper = |rhs: &Rvalue<'tcx>,
place: &Place<'tcx>,
- variant_index: &VariantIdx,
+ variant_index: VariantIdx,
switch_value: u128,
side_to_choose| {
let place_type = place.ty(self.body, self.tcx).ty;
};
// We need to make sure that the switch value that targets the bb with
// SetDiscriminant is the same as the variant discriminant.
- let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val;
+ let variant_discr = adt.discriminant_for_variant(self.tcx, variant_index).val;
if variant_discr != switch_value {
trace!(
"NO: variant discriminant {} does not equal switch value {}",
);
return StatementEquality::NotEqual;
}
- let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
+ let variant_is_fieldless = adt.variants[variant_index].fields.is_empty();
if !variant_is_fieldless {
trace!("NO: variant {:?} was not fieldless", variant_index);
return StatementEquality::NotEqual;
// check for case A
(
StatementKind::Assign(box (_, rhs)),
- StatementKind::SetDiscriminant { place, variant_index },
+ &StatementKind::SetDiscriminant { ref place, variant_index },
) if y_target_and_value.value.is_some() => {
// choose basic block of x, as that has the assign
helper(
)
}
(
- StatementKind::SetDiscriminant { place, variant_index },
- StatementKind::Assign(box (_, rhs)),
+ &StatementKind::SetDiscriminant { ref place, variant_index },
+ &StatementKind::Assign(box (_, ref rhs)),
) if x_target_and_value.value.is_some() => {
// choose basic block of y, as that has the assign
helper(
Variants::Multiple { variants, .. } => variants
.iter_enumerated()
.filter_map(|(idx, layout)| {
- (layout.abi != Abi::Uninhabited)
+ (layout.abi() != Abi::Uninhabited)
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
})
.collect(),
recursion_depth_reset = None;
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
- for &id in alloc.relocations().values() {
+ for &id in alloc.inner().relocations().values() {
collect_miri(tcx, id, &mut neighbors);
}
}
}
GlobalAlloc::Memory(alloc) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
- for &inner in alloc.relocations().values() {
+ for &inner in alloc.inner().relocations().values() {
rustc_data_structures::stack::ensure_sufficient_stack(|| {
collect_miri(tcx, inner, output);
});
match value {
ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output),
ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => {
- for &id in alloc.relocations().values() {
+ for &id in alloc.inner().relocations().values() {
collect_miri(tcx, id, output);
}
}
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
let mut async_block_err = |e: &mut Diagnostic, span: Span| {
recover_async = true;
e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
- e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
- e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ e.help_use_latest_edition();
};
while self.token != token::CloseDelim(close_delim) {
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
-use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_span::edition::Edition;
use rustc_span::lev_distance::lev_distance;
use rustc_span::source_map::{self, Span};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
let diag = self.diagnostic();
struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
.span_label(span, "to use `async fn`, switch to Rust 2018 or later")
- .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
- .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+ .help_use_latest_edition()
.emit();
}
}
//! conflicts between multiple such attributes attached to the same
//! item.
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
}
- // Warn on useless empty attributes.
- if matches!(
- attr.name_or_empty(),
- sym::macro_use
- | sym::allow
- | sym::warn
- | sym::deny
- | sym::forbid
- | sym::feature
- | sym::repr
- | sym::target_feature
- ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
- {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("unused attribute")
- .span_suggestion(
- attr.span,
- "remove this attribute",
- String::new(),
- Applicability::MachineApplicable,
- )
- .note(&format!(
- "attribute `{}` with an empty list has no effect",
- attr.name_or_empty()
- ))
- .emit();
- });
- }
+ self.check_unused_attribute(hir_id, attr)
}
if !is_valid {
target: Target,
item: Option<ItemLike<'_>>,
) -> bool {
- let is_function = matches!(target, Target::Fn | Target::Method(..));
+ let is_function = matches!(target, Target::Fn);
if !is_function {
self.tcx
.sess
});
}
}
+
+ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+ // Warn on useless empty attributes.
+ let note = if matches!(
+ attr.name_or_empty(),
+ sym::macro_use
+ | sym::allow
+ | sym::expect
+ | sym::warn
+ | sym::deny
+ | sym::forbid
+ | sym::feature
+ | sym::repr
+ | sym::target_feature
+ ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+ {
+ format!(
+ "attribute `{}` with an empty list has no effect",
+ attr.name_or_empty()
+ )
+ } else if matches!(
+ attr.name_or_empty(),
+ sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+ ) && let Some(meta) = attr.meta_item_list()
+ && meta.len() == 1
+ && let Some(item) = meta[0].meta_item()
+ && let MetaItemKind::NameValue(_) = &item.kind
+ && item.path == sym::reason
+ {
+ format!(
+ "attribute `{}` without any lints has no effect",
+ attr.name_or_empty()
+ )
+ } else {
+ return;
+ };
+
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("unused attribute")
+ .span_suggestion(
+ attr.span,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .note(¬e)
+ .emit();
+ });
+ }
}
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
self.tcx.sess,
*span,
E0549,
- "rustc_deprecated attribute must be paired with \
+ "deprecated attribute must be paired with \
either stable or unstable attribute"
)
.emit();
self.visit(self.ev.tcx.type_of(param.def_id));
}
}
- GenericParamDefKind::Const { has_default, .. } => {
+ GenericParamDefKind::Const { has_default } => {
self.visit(self.ev.tcx.type_of(param.def_id));
if has_default {
self.visit(self.ev.tcx.const_param_default(param.def_id));
// NOTE: This should be kept in sync with `default_configuration` and
// `fill_well_known_values`
const WELL_KNOWN_NAMES: &[Symbol] = &[
+ // rustc
sym::unix,
sym::windows,
sym::target_os,
sym::debug_assertions,
sym::proc_macro,
sym::test,
+ sym::feature,
+ // rustdoc
sym::doc,
sym::doctest,
- sym::feature,
+ // miri
+ sym::miri,
];
// We only insert well-known names if `names()` was activated
// No-values
for name in [
+ sym::doc,
+ sym::miri,
sym::unix,
- sym::windows,
- sym::debug_assertions,
- sym::proc_macro,
sym::test,
- sym::doc,
sym::doctest,
+ sym::windows,
+ sym::proc_macro,
+ sym::debug_assertions,
sym::target_thread_local,
] {
self.values_valid.entry(name).or_default();
name => early_error(
efmt,
&format!(
- "argument to `unpretty` must be one of `normal`, \
- `expanded`, `identified`, `expanded,identified`, \
- `expanded,hygiene`, `everybody_loops`, \
+ "argument to `unpretty` must be one of `normal`, `identified`, \
+ `expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
- `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
+ `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {}",
name
),
),
explain: &str,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+ add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
+ err
+}
+
+/// Adds the diagnostics for a feature to an existing error.
+pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
+ add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
+}
+/// Adds the diagnostics for a feature to an existing error.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer
+/// `add_feature_diagnostics`.
+pub fn add_feature_diagnostics_for_issue<'a>(
+ err: &mut Diagnostic,
+ sess: &'a ParseSess,
+ feature: Symbol,
+ issue: GateIssue,
+) {
if let Some(n) = find_feature_issue(feature, issue) {
err.note(&format!(
"see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
if sess.unstable_features.is_nightly_build() {
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
}
-
- err
}
/// Info about a parsing session.
}
#[inline]
- pub fn as_def_id(&self) -> DefId {
- DefId { krate: *self, index: CRATE_DEF_INDEX }
+ pub fn as_def_id(self) -> DefId {
+ DefId { krate: self, index: CRATE_DEF_INDEX }
}
}
// On below-64 bit systems we can simply use the derived `Hash` impl
#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
#[repr(C)]
+#[rustc_pass_by_value]
// We guarantee field order. Note that the order is essential here, see below why.
pub struct DefId {
// cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
/// A unique ID associated with a macro invocation and expansion.
pub struct LocalExpnId {
ENCODABLE = custom
+ ORD_IMPL = custom
DEBUG_FORMAT = "expn{}"
}
}
+// To ensure correctness of incremental compilation,
+// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalExpnId {}
+impl !PartialOrd for LocalExpnId {}
+
/// Assert that the provided `HashStableContext` is configured with the 'default'
/// `HashingControls`. We should always have bailed out before getting to here
/// with a non-default mode. With this check in place, we can avoid the need
delay_span_bug_from_inside_query,
deny,
deprecated,
+ deprecated_suggestion,
deref,
deref_method,
deref_mut,
macro_export,
macro_lifetime_matcher,
macro_literal_matcher,
+ macro_metavar_expr,
macro_reexport,
macro_use,
macro_vis_matcher,
minnumf32,
minnumf64,
mips_target_feature,
+ miri,
misc,
mmx_reg,
modifiers,
test_case,
test_removed_feature,
test_runner,
+ test_unstable_lint,
then_with,
thread,
thread_local,
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
- let slice =
- data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let slice = data
+ .inner()
+ .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
self.push("e");
use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
use std::str::FromStr;
+use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable_Generic;
use rustc_serialize::json::{Json, ToJson};
}
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum Variants {
+pub enum Variants<'a> {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
tag: Scalar,
tag_encoding: TagEncoding,
tag_field: usize,
- variants: IndexVec<VariantIdx, Layout>,
+ variants: IndexVec<VariantIdx, Layout<'a>>,
},
}
}
}
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub struct Layout {
+#[derive(PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct LayoutS<'a> {
/// Says where the fields are located within the layout.
pub fields: FieldsShape,
///
/// To access all fields of this layout, both `fields` and the fields of the active variant
/// must be taken into account.
- pub variants: Variants,
+ pub variants: Variants<'a>,
/// The `abi` defines how this data is passed between functions, and it defines
/// value restrictions via `valid_range`.
pub size: Size,
}
-impl Layout {
+impl<'a> LayoutS<'a> {
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.value.size(cx);
let align = scalar.value.align(cx);
- Layout {
+ LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
abi: Abi::Scalar(scalar),
}
}
+impl<'a> fmt::Debug for LayoutS<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This is how `Layout` used to print before it become
+ // `Interned<LayoutS>`. We print it like this to avoid having to update
+ // expected output in a lot of tests.
+ f.debug_struct("Layout")
+ .field("fields", &self.fields)
+ .field("variants", &self.variants)
+ .field("abi", &self.abi)
+ .field("largest_niche", &self.largest_niche)
+ .field("align", &self.align)
+ .field("size", &self.size)
+ .finish()
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
+
+impl<'a> fmt::Debug for Layout<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // See comment on `<LayoutS as Debug>::fmt` above.
+ self.0.0.fmt(f)
+ }
+}
+
+impl<'a> Layout<'a> {
+ pub fn fields(self) -> &'a FieldsShape {
+ &self.0.0.fields
+ }
+
+ pub fn variants(self) -> &'a Variants<'a> {
+ &self.0.0.variants
+ }
+
+ pub fn abi(self) -> Abi {
+ self.0.0.abi
+ }
+
+ pub fn largest_niche(self) -> Option<Niche> {
+ self.0.0.largest_niche
+ }
+
+ pub fn align(self) -> AbiAndPrefAlign {
+ self.0.0.align
+ }
+
+ pub fn size(self) -> Size {
+ self.0.0.size
+ }
+}
+
/// The layout of a type, alongside the type itself.
/// Provides various type traversal APIs (e.g., recursing into fields).
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct TyAndLayout<'a, Ty> {
pub ty: Ty,
- pub layout: &'a Layout,
+ pub layout: Layout<'a>,
}
impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
- type Target = &'a Layout;
- fn deref(&self) -> &&'a Layout {
- &self.layout
+ type Target = &'a LayoutS<'a>;
+ fn deref(&self) -> &&'a LayoutS<'a> {
+ &self.layout.0.0
}
}
//! LLVM.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bool_to_option)]
-#![feature(let_else)]
-#![feature(nll)]
-#![feature(never_type)]
#![feature(associated_type_bounds)]
+#![feature(bool_to_option)]
#![feature(exhaustive_patterns)]
+#![feature(let_else)]
#![feature(min_specialization)]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(rustc_attrs)]
#![feature(step_trait)]
use std::iter::FromIterator;
span: Span,
) -> Result<(), NotConstEvaluatable> {
debug!("is_const_evaluatable({:?})", uv);
- if infcx.tcx.features().generic_const_exprs {
- let tcx = infcx.tcx;
+ let tcx = infcx.tcx;
+
+ if tcx.features().generic_const_exprs {
match AbstractConst::new(tcx, uv)? {
// We are looking at a generic abstract constant.
Some(ct) => {
- for pred in param_env.caller_bounds() {
- match pred.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(uv) => {
- if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
- // Try to unify with each subtree in the AbstractConst to allow for
- // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
- // predicate for `(N + 1) * 2`
- let result =
- walk_abstract_const(tcx, b_ct, |b_ct| {
- match try_unify(tcx, ct, b_ct) {
- true => ControlFlow::BREAK,
- false => ControlFlow::CONTINUE,
- }
- });
-
- if let ControlFlow::Break(()) = result {
- debug!("is_const_evaluatable: abstract_const ~~> ok");
- return Ok(());
- }
- }
- }
- _ => {} // don't care
- }
+ if satisfied_from_param_env(tcx, ct, param_env)? {
+ return Ok(());
}
// We were unable to unify the abstract constant with
}
}
+ // If we're evaluating a foreign constant, under a nightly compiler without generic
+ // const exprs, AND it would've passed if that expression had been evaluated with
+ // generic const exprs, then suggest using generic const exprs.
+ if concrete.is_err()
+ && tcx.sess.is_nightly_build()
+ && !uv.def.did.is_local()
+ && !tcx.features().generic_const_exprs
+ && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+ && satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
+ {
+ tcx.sess
+ .struct_span_fatal(
+ // Slightly better span than just using `span` alone
+ if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+ "failed to evaluate generic const expression",
+ )
+ .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+ .span_suggestion_verbose(
+ rustc_span::DUMMY_SP,
+ "consider enabling this feature",
+ "#![feature(generic_const_exprs)]\n".to_string(),
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
+ .emit();
+ rustc_errors::FatalError.raise();
+ }
+
debug!(?concrete, "is_const_evaluatable");
match concrete {
Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
}
}
+fn satisfied_from_param_env<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ct: AbstractConst<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> Result<bool, NotConstEvaluatable> {
+ for pred in param_env.caller_bounds() {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+ // Try to unify with each subtree in the AbstractConst to allow for
+ // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
+ // predicate for `(N + 1) * 2`
+ let result =
+ walk_abstract_const(tcx, b_ct, |b_ct| match try_unify(tcx, ct, b_ct) {
+ true => ControlFlow::BREAK,
+ false => ControlFlow::CONTINUE,
+ });
+
+ if let ControlFlow::Break(()) = result {
+ debug!("is_const_evaluatable: abstract_const ~~> ok");
+ return Ok(true);
+ }
+ }
+ }
+ _ => {} // don't care
+ }
+ }
+
+ Ok(false)
+}
+
/// A tree representing an anonymous constant.
///
/// This is only able to represent a subset of `MIR`,
use crate::infer::InferCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind};
use rustc_span::symbol::sym;
use std::iter;
use super::InferCtxtPrivExt;
-crate trait InferCtxtExt<'tcx> {
+pub trait InferCtxtExt<'tcx> {
/*private*/
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
- ) -> Option<DefId>;
+ ) -> Option<(DefId, SubstsRef<'tcx>)>;
/*private*/
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
- ) -> Option<DefId> {
+ ) -> Option<(DefId, SubstsRef<'tcx>)> {
let tcx = self.tcx;
let param_env = obligation.param_env;
let trait_ref = tcx.erase_late_bound_regions(trait_ref);
let impl_self_ty = impl_trait_ref.self_ty();
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
- self_match_impls.push(def_id);
+ self_match_impls.push((def_id, impl_substs));
if iter::zip(
trait_ref.substs.types().skip(1),
)
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
{
- fuzzy_match_impls.push(def_id);
+ fuzzy_match_impls.push((def_id, impl_substs));
}
}
});
- let impl_def_id = if self_match_impls.len() == 1 {
+ let impl_def_id_and_substs = if self_match_impls.len() == 1 {
self_match_impls[0]
} else if fuzzy_match_impls.len() == 1 {
fuzzy_match_impls[0]
return None;
};
- tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
+ tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
+ .then_some(impl_def_id_and_substs)
}
/// Used to set on_unimplemented's `ItemContext`
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> OnUnimplementedNote {
- let def_id =
- self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
+ let (def_id, substs) = self
+ .impl_similar_to(trait_ref, obligation)
+ .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
let trait_ref = trait_ref.skip_binder();
let mut flags = vec![(
for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize].to_string()
+ substs[param.index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
flags.push((name, Some(value)));
if let GenericParamDefKind::Type { .. } = param.kind {
- let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+ let param_ty = substs[param.index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() {
// We also want to be able to select the parameter's
// original signature with no type arguments resolved
flags.push((sym::_Self, Some("{integral}".to_owned())));
}
+ if self_ty.is_array_slice() {
+ flags.push((sym::_Self, Some("&[]".to_owned())));
+ }
+
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 Ok(Some(command)) =
- OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
- {
+ if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags)
} else {
OnUnimplementedNote::default()
}
hir::Node::Item(hir::Item {
kind:
- hir::ItemKind::Trait(_, _, generics, _, _)
+ hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. }),
..
}) if projection.is_some() => {
let obligation = &mut pending_obligation.obligation;
+ debug!(?obligation, "process_obligation pre-resolve");
+
if obligation.predicate.has_infer_types_or_consts() {
obligation.predicate =
self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
let infcx = self.selcx.infcx();
+ if obligation.predicate.has_projections() {
+ let mut obligations = Vec::new();
+ let predicate = crate::traits::project::try_normalize_with_depth_to(
+ self.selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.predicate,
+ &mut obligations,
+ );
+ if predicate != obligation.predicate {
+ obligations.push(obligation.with(predicate));
+ return ProcessResult::Changed(mk_pending(obligations));
+ }
+ }
let binder = obligation.predicate.kind();
match binder.no_bound_vars() {
None => match binder.skip_binder() {
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
items: &[NestedMetaItem],
span: Span,
is_root: bool,
let mut item_iter = items.iter();
let parse_value = |value_str| {
- OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+ OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
};
let condition = if is_root {
{
if let Some(items) = item.meta_item_list() {
if let Ok(subcommand) =
- Self::parse(tcx, trait_def_id, &items, item.span(), false)
+ Self::parse(tcx, item_def_id, &items, item.span(), false)
{
subcommands.push(subcommand);
} else {
}
}
- pub fn of_item(
- tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
- impl_def_id: DefId,
- ) -> Result<Option<Self>, ErrorGuaranteed> {
- let attrs = tcx.get_attrs(impl_def_id);
+ pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+ let attrs = tcx.get_attrs(item_def_id);
let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
return Ok(None);
};
let result = if let Some(items) = attr.meta_item_list() {
- Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
+ Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
} else if let Some(value) = attr.value_str() {
Ok(Some(OnUnimplementedDirective {
condition: None,
subcommands: vec![],
label: Some(OnUnimplementedFormatString::try_parse(
tcx,
- trait_def_id,
+ item_def_id,
value,
attr.span,
)?),
} else {
return Err(ErrorGuaranteed);
};
- debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
+ debug!("of_item({:?}) = {:?}", item_def_id, result);
result
}
impl<'tcx> OnUnimplementedFormatString {
fn try_parse(
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
from: Symbol,
err_sp: Span,
) -> Result<Self, ErrorGuaranteed> {
let result = OnUnimplementedFormatString(from);
- result.verify(tcx, trait_def_id, err_sp)?;
+ result.verify(tcx, item_def_id, err_sp)?;
Ok(result)
}
fn verify(
&self,
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
span: Span,
) -> Result<(), ErrorGuaranteed> {
- let name = tcx.item_name(trait_def_id);
- let generics = tcx.generics_of(trait_def_id);
+ let trait_def_id = if tcx.is_trait(item_def_id) {
+ item_def_id
+ } else {
+ tcx.trait_id_of_impl(item_def_id)
+ .expect("expected `on_unimplemented` to correspond to a trait")
+ };
+ let trait_name = tcx.item_name(trait_def_id);
+ let generics = tcx.generics_of(item_def_id);
let s = self.0.as_str();
let parser = Parser::new(s, None, None, false, ParseMode::Format);
let mut result = Ok(());
// `{Self}` is allowed
Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
// `{ThisTraitsName}` is allowed
- Position::ArgumentNamed(s, _) if s == name => (),
+ Position::ArgumentNamed(s, _) if s == trait_name => (),
// `{from_method}` is allowed
Position::ArgumentNamed(s, _) if s == sym::from_method => (),
// `{from_desugaring}` is allowed
tcx.sess,
span,
E0230,
- "there is no parameter `{}` on trait `{}`",
+ "there is no parameter `{}` on {}",
s,
- name
+ if trait_def_id == item_def_id {
+ format!("trait `{}`", trait_name)
+ } else {
+ "impl".to_string()
+ }
)
.emit();
result = Err(ErrorGuaranteed);
result
}
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ value: T,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+ T: TypeFoldable<'tcx>,
+{
+ debug!(obligations.len = obligations.len());
+ let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement(
+ selcx,
+ param_env,
+ cause,
+ depth,
+ obligations,
+ );
+ let result = ensure_sufficient_stack(|| normalizer.fold(value));
+ debug!(?result, obligations.len = normalizer.obligations.len());
+ debug!(?normalizer.obligations,);
+ result
+}
+
pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool {
match reveal {
Reveal::UserFacing => value
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
+ /// If true, when a projection is unable to be completed, an inference
+ /// variable will be created and an obligation registered to project to that
+ /// inference variable. Also, constants will be eagerly evaluated.
+ eager_inference_replacement: bool,
}
impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
depth: usize,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
- AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: true,
+ }
+ }
+
+ fn new_without_eager_inference_replacement(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: false,
+ }
}
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
// there won't be bound vars there.
let data = data.super_fold_with(self);
- let normalized_ty = normalize_projection_type(
- self.selcx,
- self.param_env,
- data,
- self.cause.clone(),
- self.depth,
- &mut self.obligations,
- );
+ let normalized_ty = if self.eager_inference_replacement {
+ normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ } else {
+ opt_normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ .ok()
+ .flatten()
+ .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+ };
debug!(
?self.depth,
?ty,
}
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
- if self.selcx.tcx().lazy_normalization() {
+ if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
constant
} else {
let constant = constant.super_fold_with(self);
&mut self,
constant: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
- constant.try_super_fold_with(self)
+ let constant_kind = match constant {
+ mir::ConstantKind::Ty(c) => {
+ let const_folded = c.try_fold_with(self)?;
+ match const_folded.val() {
+ ty::ConstKind::Value(cv) => {
+ // FIXME With Valtrees we need to convert `cv: ValTree`
+ // to a `ConstValue` here.
+ mir::ConstantKind::Val(cv, const_folded.ty())
+ }
+ _ => mir::ConstantKind::Ty(const_folded),
+ }
+ }
+ mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
+ };
+
+ Ok(constant_kind)
}
}
NonScalar,
UnknownExprPtrKind,
UnknownCastPtrKind,
+ /// Cast of int to (possibly) fat raw pointer.
+ ///
+ /// Argument is the specific name of the metadata in plain words, such as "a vtable"
+ /// or "a length". If this argument is None, then the metadata is unknown, for example,
+ /// when we're typechecking a type parameter with a ?Sized bound.
+ IntToFatCast(Option<&'static str>),
}
impl From<ErrorGuaranteed> for CastError {
.diagnostic()
.emit();
}
+ CastError::IntToFatCast(known_metadata) => {
+ let mut err = struct_span_err!(
+ fcx.tcx.sess,
+ self.cast_span,
+ E0606,
+ "cannot cast `{}` to a pointer that {} wide",
+ fcx.ty_to_string(self.expr_ty),
+ if known_metadata.is_some() { "is" } else { "may be" }
+ );
+
+ err.span_label(
+ self.cast_span,
+ format!(
+ "creating a `{}` requires both an address and {}",
+ self.cast_ty,
+ known_metadata.unwrap_or("type-specific metadata"),
+ ),
+ );
+
+ if fcx.tcx.sess.is_nightly_build() {
+ err.span_label(
+ self.expr.span,
+ "consider casting this expression to `*const ()`, \
+ then using `core::ptr::from_raw_parts`",
+ );
+ }
+
+ err.emit();
+ }
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
let unknown_cast_to = match e {
CastError::UnknownCastPtrKind => true,
match fcx.pointer_kind(m_cast.ty, self.span)? {
None => Err(CastError::UnknownCastPtrKind),
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
- _ => Err(CastError::IllegalCast),
+ Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
+ Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
+ Some(
+ PointerKind::OfProjection(_)
+ | PointerKind::OfOpaque(_, _)
+ | PointerKind::OfParam(_),
+ ) => Err(CastError::IntToFatCast(None)),
}
}
impl_trait_ref,
&impl_.items,
);
- let trait_def_id = impl_trait_ref.def_id;
- check_on_unimplemented(tcx, trait_def_id, it);
+ check_on_unimplemented(tcx, it);
}
}
hir::ItemKind::Trait(_, _, _, _, ref items) => {
- check_on_unimplemented(tcx, it.def_id.to_def_id(), it);
+ check_on_unimplemented(tcx, it);
for item in items.iter() {
let item = tcx.hir().trait_item(item.id);
}
}
-pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id());
+ let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
use rustc_session::parse::feature_err;
-use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::Span;
// We know by construction that `<expr>.await` is either on Rust 2015
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
err.note("to `.await` a `Future`, switch to Rust 2018 or later");
- err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
- err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ err.help_use_latest_edition();
}
err.emit();
self.fcx.var_for_def(self.span, param)
}
}
- GenericParamDefKind::Const { has_default, .. } => {
+ GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
};
+ let minimum_input_count = formal_input_tys.len();
+
// Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so
})
}
- let minimum_input_count = formal_input_tys.len();
for (idx, arg) in provided_args.iter().enumerate() {
// Warn only for the first loop (the "no closures" one).
// Closure arguments themselves can't be diverging, but
err.emit();
}
- // We also need to make sure we at least write the ty of the other
- // arguments which we skipped above.
- if c_variadic {
- fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
- use crate::structured_errors::MissingCastForVariadicArg;
+ for arg in provided_args.iter().skip(minimum_input_count) {
+ let arg_ty = self.check_expr(&arg);
- MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
- }
+ if c_variadic {
+ // We also need to make sure we at least write the ty of the other
+ // arguments which we skipped above, either because they were additional
+ // c_variadic args, or because we had an argument count mismatch.
+ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
+ use crate::structured_errors::MissingCastForVariadicArg;
- for arg in provided_args.iter().skip(expected_arg_count) {
- let arg_ty = self.check_expr(&arg);
+ MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
+ }
// There are a few types which get autopromoted when passed via varargs
// in C but we just error out instead and require explicit casts.
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, MultiSpan, Span};
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
- FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
};
use std::cmp::Ordering;
}
}
- let mut label_span_not_found = || {
- if unsatisfied_predicates.is_empty() {
- err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
- let is_string_or_ref_str = match actual.kind() {
- ty::Ref(_, ty, _) => {
- ty.is_str()
- || matches!(
- ty.kind(),
- ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
- )
- }
- ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
- _ => false,
- };
- if is_string_or_ref_str && item_name.name == sym::iter {
- err.span_suggestion_verbose(
- item_name.span,
- "because of the in-memory representation of `&str`, to obtain \
- an `Iterator` over each of its codepoint use method `chars`",
- String::from("chars"),
- Applicability::MachineApplicable,
- );
- }
- if let ty::Adt(adt, _) = rcvr_ty.kind() {
- let mut inherent_impls_candidate = self
- .tcx
- .inherent_impls(adt.did)
- .iter()
- .copied()
- .filter(|def_id| {
- if let Some(assoc) = self.associated_value(*def_id, item_name) {
- // Check for both mode is the same so we avoid suggesting
- // incorrect associated item.
- match (mode, assoc.fn_has_self_parameter, source) {
- (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
- // We check that the suggest type is actually
- // different from the received one
- // So we avoid suggestion method with Box<Self>
- // for instance
- self.tcx.at(span).type_of(*def_id) != actual
- && self.tcx.at(span).type_of(*def_id) != rcvr_ty
- }
- (Mode::Path, false, _) => true,
- _ => false,
- }
- } else {
- false
- }
- })
- .collect::<Vec<_>>();
- if !inherent_impls_candidate.is_empty() {
- inherent_impls_candidate.sort();
- inherent_impls_candidate.dedup();
-
- // number of type to shows at most.
- let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
- let type_candidates = inherent_impls_candidate
- .iter()
- .take(limit)
- .map(|impl_item| {
- format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
- })
- .collect::<Vec<_>>()
- .join("\n");
- let additional_types = if inherent_impls_candidate.len() > limit {
- format!(
- "\nand {} more types",
- inherent_impls_candidate.len() - limit
- )
- } else {
- "".to_string()
- };
- err.note(&format!(
- "the {item_kind} was found for\n{}{}",
- type_candidates, additional_types
- ));
- }
- }
- } else {
- err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
- }
- };
-
- // If the method name is the name of a field with a function or closure type,
- // give a helping note that it has to be called as `(x.f)(...)`.
- if let SelfSource::MethodCall(expr) = source {
- let field_receiver =
- self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
- ty::Adt(def, substs) if !def.is_enum() => {
- let variant = &def.non_enum_variant();
- self.tcx.find_field_index(item_name, variant).map(|index| {
- let field = &variant.fields[index];
- let field_ty = field.ty(tcx, substs);
- (field, field_ty)
- })
- }
- _ => None,
- });
-
- if let Some((field, field_ty)) = field_receiver {
- let scope = self.tcx.parent_module(self.body_id).to_def_id();
- let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
-
- if is_accessible {
- if self.is_fn_ty(field_ty, span) {
- let expr_span = expr.span.to(item_name.span);
- err.multipart_suggestion(
- &format!(
- "to call the function stored in `{}`, \
- surround the field access with parentheses",
- item_name,
- ),
- vec![
- (expr_span.shrink_to_lo(), '('.to_string()),
- (expr_span.shrink_to_hi(), ')'.to_string()),
- ],
- Applicability::MachineApplicable,
- );
- } else {
- let call_expr = self
- .tcx
- .hir()
- .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
- if let Some(span) = call_expr.span.trim_start(item_name.span) {
- err.span_suggestion(
- span,
- "remove the arguments",
- String::new(),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-
- let field_kind = if is_accessible { "field" } else { "private field" };
- err.span_label(item_name.span, format!("{}, not a method", field_kind));
- } else if lev_candidate.is_none() && static_sources.is_empty() {
- label_span_not_found();
- }
- } else {
- label_span_not_found();
- }
-
if self.is_fn_ty(rcvr_ty, span) {
fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
err.note(
}
}
+ let mut custom_span_label = false;
+
if !static_sources.is_empty() {
err.note(
"found the following associated functions; to be used as methods, \
functions must have a `self` parameter",
);
err.span_label(span, "this is an associated function, not a method");
+ custom_span_label = true;
}
if static_sources.len() == 1 {
let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
report_candidates(span, &mut err, static_sources, sugg_span);
}
+ let mut bound_spans = vec![];
let mut restrict_type_params = false;
let mut unsatisfied_bounds = false;
if item_name.name == sym::count && self.is_slice_ty(actual, span) {
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
};
let mut type_params = FxHashMap::default();
- let mut bound_spans = vec![];
+
+ // Pick out the list of unimplemented traits on the receiver.
+ // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+ let mut unimplemented_traits = FxHashMap::default();
+ for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
+ if let (ty::PredicateKind::Trait(p), Some(cause)) =
+ (predicate.kind().skip_binder(), cause.as_ref())
+ {
+ if p.trait_ref.self_ty() != rcvr_ty {
+ // This is necessary, not just to keep the errors clean, but also
+ // because our derived obligations can wind up with a trait ref that
+ // requires a different param_env to be correctly compared.
+ continue;
+ }
+ unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+ predicate.kind().rebind(p.trait_ref),
+ Obligation {
+ cause: cause.clone(),
+ param_env: self.param_env,
+ predicate: predicate.clone(),
+ recursion_depth: 0,
+ },
+ ));
+ }
+ }
let mut collect_type_param_suggestions =
|self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
- bound_spans.sort();
- bound_spans.dedup();
- for (span, msg) in bound_spans.into_iter() {
- err.span_label(span, &msg);
- }
+
if !bound_list.is_empty() || !skip_list.is_empty() {
let bound_list = bound_list
.into_iter()
.collect::<Vec<_>>()
.join("\n");
let actual_prefix = actual.prefix_string(self.tcx);
- err.set_primary_message(&format!(
+ info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+ let (primary_message, label) = if unimplemented_traits.len() == 1 {
+ unimplemented_traits
+ .into_iter()
+ .next()
+ .map(|(_, (trait_ref, obligation))| {
+ if trait_ref.self_ty().references_error()
+ || actual.references_error()
+ {
+ // Avoid crashing.
+ return (None, None);
+ }
+ let OnUnimplementedNote { message, label, .. } =
+ self.infcx.on_unimplemented_note(trait_ref, &obligation);
+ (message, label)
+ })
+ .unwrap_or((None, None))
+ } else {
+ (None, None)
+ };
+ let primary_message = primary_message.unwrap_or_else(|| format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
+ err.set_primary_message(&primary_message);
+ if let Some(label) = label {
+ custom_span_label = true;
+ err.span_label(span, label);
+ }
if !bound_list.is_empty() {
err.note(&format!(
"the following trait bounds were not satisfied:\n{bound_list}"
}
}
+ let mut label_span_not_found = || {
+ if unsatisfied_predicates.is_empty() {
+ err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ let is_string_or_ref_str = match actual.kind() {
+ ty::Ref(_, ty, _) => {
+ ty.is_str()
+ || matches!(
+ ty.kind(),
+ ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
+ )
+ }
+ ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
+ _ => false,
+ };
+ if is_string_or_ref_str && item_name.name == sym::iter {
+ err.span_suggestion_verbose(
+ item_name.span,
+ "because of the in-memory representation of `&str`, to obtain \
+ an `Iterator` over each of its codepoint use method `chars`",
+ String::from("chars"),
+ Applicability::MachineApplicable,
+ );
+ }
+ if let ty::Adt(adt, _) = rcvr_ty.kind() {
+ let mut inherent_impls_candidate = self
+ .tcx
+ .inherent_impls(adt.did)
+ .iter()
+ .copied()
+ .filter(|def_id| {
+ if let Some(assoc) = self.associated_value(*def_id, item_name) {
+ // Check for both mode is the same so we avoid suggesting
+ // incorrect associated item.
+ match (mode, assoc.fn_has_self_parameter, source) {
+ (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+ // We check that the suggest type is actually
+ // different from the received one
+ // So we avoid suggestion method with Box<Self>
+ // for instance
+ self.tcx.at(span).type_of(*def_id) != actual
+ && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ }
+ (Mode::Path, false, _) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ if !inherent_impls_candidate.is_empty() {
+ inherent_impls_candidate.sort();
+ inherent_impls_candidate.dedup();
+
+ // number of type to shows at most.
+ let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+ let type_candidates = inherent_impls_candidate
+ .iter()
+ .take(limit)
+ .map(|impl_item| {
+ format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+ })
+ .collect::<Vec<_>>()
+ .join("\n");
+ let additional_types = if inherent_impls_candidate.len() > limit {
+ format!(
+ "\nand {} more types",
+ inherent_impls_candidate.len() - limit
+ )
+ } else {
+ "".to_string()
+ };
+ err.note(&format!(
+ "the {item_kind} was found for\n{}{}",
+ type_candidates, additional_types
+ ));
+ }
+ }
+ } else {
+ err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+ }
+ };
+
+ // If the method name is the name of a field with a function or closure type,
+ // give a helping note that it has to be called as `(x.f)(...)`.
+ if let SelfSource::MethodCall(expr) = source {
+ let field_receiver =
+ self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+ ty::Adt(def, substs) if !def.is_enum() => {
+ let variant = &def.non_enum_variant();
+ self.tcx.find_field_index(item_name, variant).map(|index| {
+ let field = &variant.fields[index];
+ let field_ty = field.ty(tcx, substs);
+ (field, field_ty)
+ })
+ }
+ _ => None,
+ });
+
+ if let Some((field, field_ty)) = field_receiver {
+ let scope = self.tcx.parent_module(self.body_id).to_def_id();
+ let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+
+ if is_accessible {
+ if self.is_fn_ty(field_ty, span) {
+ let expr_span = expr.span.to(item_name.span);
+ err.multipart_suggestion(
+ &format!(
+ "to call the function stored in `{}`, \
+ surround the field access with parentheses",
+ item_name,
+ ),
+ vec![
+ (expr_span.shrink_to_lo(), '('.to_string()),
+ (expr_span.shrink_to_hi(), ')'.to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let call_expr = self
+ .tcx
+ .hir()
+ .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+
+ if let Some(span) = call_expr.span.trim_start(item_name.span) {
+ err.span_suggestion(
+ span,
+ "remove the arguments",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
+ let field_kind = if is_accessible { "field" } else { "private field" };
+ err.span_label(item_name.span, format!("{}, not a method", field_kind));
+ } else if lev_candidate.is_none() && !custom_span_label {
+ label_span_not_found();
+ }
+ } else if !custom_span_label {
+ label_span_not_found();
+ }
+
+ bound_spans.sort();
+ bound_spans.dedup();
+ for (span, msg) in bound_spans.into_iter() {
+ err.span_label(span, &msg);
+ }
+
if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
} else {
self.suggest_traits_to_import(
// the consumer's responsibility to ensure all bytes that have been read
// have defined values.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) {
- if alloc.relocations().len() != 0 {
+ if alloc.inner().relocations().len() != 0 {
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
extra levels of indirection such as references";
/// let s: String; // hir_id_s
/// let mut p: Point; // his_id_p
/// let c = || {
- /// println!("{}", s); // L1
+ /// println!("{s}"); // L1
/// p.x += 10; // L2
- /// println!("{}" , p.y) // L3
- /// println!("{}", p) // L4
+ /// println!("{}" , p.y); // L3
+ /// println!("{p}"); // L4
/// drop(s); // L5
/// };
/// ```
// Add a label pointing to where a captured variable affected by drop order
// is dropped
if lint_note.reason.drop_order {
- let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
+ let drop_location_span = drop_location_span(self.tcx, closure_hir_id);
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
}
/// Returns the Span of where the value with the provided HirId would be dropped
-fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span {
- let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap();
+fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span {
+ let owner_id = tcx.hir().get_enclosing_scope(hir_id).unwrap();
let owner_node = tcx.hir().get(owner_id);
let owner_span = match owner_node {
fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
fn upvar_is_local_variable<'tcx>(
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
- upvar_id: &hir::HirId,
+ upvar_id: hir::HirId,
body_owner_is_closure: bool,
) -> bool {
- upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure)
+ upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
}
debug!("walk_captures({:?})", closure_expr);
PlaceBase::Upvar(upvar_id) => {
if upvar_is_local_variable(
upvars,
- &upvar_id.var_path.hir_id,
+ upvar_id.var_path.hir_id,
body_owner_is_closure,
) {
// The nested closure might be fake reading the current (enclosing) closure's local variables.
// if there is no `#[alloc_error_handler]`
#[rustc_std_internal_symbol]
pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
- panic!("memory allocation of {} bytes failed", size)
+ panic!("memory allocation of {size} bytes failed")
}
// if there is an `#[alloc_error_handler]`
/// let readonly = [1, 2];
/// let borrowed = Items::new((&readonly[..]).into());
/// match borrowed {
-/// Items { values: Cow::Borrowed(b) } => println!("borrowed {:?}", b),
+/// Items { values: Cow::Borrowed(b) } => println!("borrowed {b:?}"),
/// _ => panic!("expect borrowed value"),
/// }
///
//! }
//!
//! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
-//! println!("{:?}", list);
+//! println!("{list:?}");
//! ```
//!
//! This will print `Cons(1, Cons(2, Nil))`.
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_box", issue = "92521")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
}
/// let slice: &[u8] = &[104, 101, 108, 108, 111];
/// let boxed_slice: Box<[u8]> = Box::from(slice);
///
- /// println!("{:?}", boxed_slice);
+ /// println!("{boxed_slice:?}");
/// ```
fn from(slice: &[T]) -> Box<[T]> {
let len = slice.len();
///
/// ```rust
/// let boxed: Box<str> = Box::from("hello");
- /// println!("{}", boxed);
+ /// println!("{boxed}");
/// ```
#[inline]
fn from(s: &str) -> Box<str> {
///
/// let unboxed = Cow::Borrowed("hello");
/// let boxed: Box<str> = Box::from(unboxed);
- /// println!("{}", boxed);
+ /// println!("{boxed}");
/// ```
///
/// ```rust
/// # use std::borrow::Cow;
/// let unboxed = Cow::Owned("hello".to_string());
/// let boxed: Box<str> = Box::from(unboxed);
- /// println!("{}", boxed);
+ /// println!("{boxed}");
/// ```
#[inline]
fn from(cow: Cow<'_, str>) -> Box<str> {
///
/// ```rust
/// let boxed: Box<[u8]> = Box::from([4, 2]);
- /// println!("{:?}", boxed);
+ /// println!("{boxed:?}");
/// ```
fn from(array: [T; N]) -> Box<[T]> {
box array
/// // We can iterate over the items in the heap, although they are returned in
/// // a random order.
/// for x in &heap {
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // If we instead pop these scores, they should come back in order.
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns
+ /// In other words, remove all elements `e` for which `f(&e)` returns
/// `false`. The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.iter() {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
///
/// // Will print in some order
/// for x in vec {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
/// assert!(!heap.is_empty());
///
/// for x in heap.drain() {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// assert!(heap.is_empty());
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.into_iter() {
/// // x has type i32, not &i32
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
fn into_iter(self) -> IntoIter<T> {
/// let to_find = ["Up!", "Office Space"];
/// for movie in &to_find {
/// match movie_reviews.get(movie) {
-/// Some(review) => println!("{}: {}", movie, review),
-/// None => println!("{} is unreviewed.", movie)
+/// Some(review) => println!("{movie}: {review}"),
+/// None => println!("{movie} is unreviewed.")
/// }
/// }
///
///
/// // iterate over everything.
/// for (movie, review) in &movie_reviews {
-/// println!("{}: \"{}\"", movie, review);
+/// println!("{movie}: \"{review}\"");
/// }
/// ```
///
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+ /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
/// The elements are visited in ascending key order.
///
/// # Examples
/// map.insert(5, "b");
/// map.insert(8, "c");
/// for (&key, &value) in map.range((Included(&4), Included(&8))) {
- /// println!("{}: {}", key, value);
+ /// println!("{key}: {value}");
/// }
/// assert_eq!(Some((&5, &"b")), map.range(4..).next());
/// ```
/// *balance += 100;
/// }
/// for (name, balance) in &map {
- /// println!("{} => {}", name, balance);
+ /// println!("{name} => {balance}");
/// }
/// ```
#[stable(feature = "btree_range", since = "1.17.0")]
/// map.insert(1, "a");
///
/// for (key, value) in map.iter() {
- /// println!("{}: {}", key, value);
+ /// println!("{key}: {value}");
/// }
///
/// let (first_key, first_value) = map.iter().next().unwrap();
use core::mem;
use super::super::borrow::DormantMutRef;
-use super::super::node::{marker, Handle, InsertResult::*, NodeRef};
+use super::super::node::{marker, Handle, NodeRef};
use super::BTreeMap;
use Entry::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(self, value: V) -> &'a mut V {
let out_ptr = match self.handle.insert_recursing(self.key, value) {
- (Fit(_), val_ptr) => {
+ (None, val_ptr) => {
// SAFETY: We have consumed self.handle and the handle returned.
let map = unsafe { self.dormant_map.awaken() };
map.length += 1;
val_ptr
}
- (Split(ins), val_ptr) => {
+ (Some(ins), val_ptr) => {
drop(ins.left);
// SAFETY: We have consumed self.handle and the reference returned.
let map = unsafe { self.dormant_map.awaken() };
}
fn map_debug<K: Debug>(mut map: BTreeMap<K, ()>) {
- format!("{:?}", map);
+ format!("{map:?}");
format!("{:?}", map.iter());
format!("{:?}", map.iter_mut());
format!("{:?}", map.keys());
/// this edge. This method splits the node if there isn't enough room.
///
/// The returned pointer points to the inserted value.
- fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
+ fn insert(mut self, key: K, val: V) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
if self.node.len() < CAPACITY {
let val_ptr = self.insert_fit(key, val);
- let kv = unsafe { Handle::new_kv(self.node, self.idx) };
- (InsertResult::Fit(kv), val_ptr)
+ (None, val_ptr)
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
},
};
let val_ptr = insertion_edge.insert_fit(key, val);
- (InsertResult::Split(result), val_ptr)
+ (Some(result), val_ptr)
}
}
}
key: K,
val: V,
edge: Root<K, V>,
- ) -> InsertResult<'a, K, V, marker::Internal> {
+ ) -> Option<SplitResult<'a, K, V, marker::Internal>> {
assert!(edge.height == self.node.height - 1);
if self.node.len() < CAPACITY {
self.insert_fit(key, val, edge);
- let kv = unsafe { Handle::new_kv(self.node, self.idx) };
- InsertResult::Fit(kv)
+ None
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
},
};
insertion_edge.insert_fit(key, val, edge);
- InsertResult::Split(result)
+ Some(result)
}
}
}
/// this edge. This method splits the node if there isn't enough room, and tries to
/// insert the split off portion into the parent node recursively, until the root is reached.
///
- /// If the returned result is a `Fit`, its handle's node can be this edge's node or an ancestor.
- /// If the returned result is a `Split`, the `left` field will be the root node.
- /// The returned pointer points to the inserted value.
+ /// If the returned result is some `SplitResult`, the `left` field will be the root node.
+ /// The returned pointer points to the inserted value, which in the case of `SplitResult`
+ /// is in the `left` or `right` tree.
pub fn insert_recursing(
self,
key: K,
value: V,
- ) -> (InsertResult<'a, K, V, marker::LeafOrInternal>, *mut V) {
+ ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
let (mut split, val_ptr) = match self.insert(key, value) {
- (InsertResult::Fit(handle), ptr) => {
- return (InsertResult::Fit(handle.forget_node_type()), ptr);
- }
- (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr),
+ (None, val_ptr) => return (None, val_ptr),
+ (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
};
loop {
split = match split.left.ascend() {
Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) {
- InsertResult::Fit(handle) => {
- return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
- }
- InsertResult::Split(split) => split.forget_node_type(),
+ None => return (None, val_ptr),
+ Some(split) => split.forget_node_type(),
},
- Err(root) => {
- return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
- }
+ Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
};
}
}
}
}
-impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV> {
- pub fn forget_node_type(
- self,
- ) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
- unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
- }
-}
-
impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, Type> {
/// Checks whether the underlying node is an `Internal` node or a `Leaf` node.
pub fn force(
pub struct SplitResult<'a, K, V, NodeType> {
// Altered node in existing tree with elements and edges that belong to the left of `kv`.
pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
- // Some key and value split off, to be inserted elsewhere.
+ // Some key and value that existed before and were split off, to be inserted elsewhere.
pub kv: (K, V),
// Owned, unattached, new node with elements and edges that belong to the right of `kv`.
pub right: NodeRef<marker::Owned, K, V, NodeType>,
}
}
-pub enum InsertResult<'a, K, V, NodeType> {
- Fit(Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV>),
- Split(SplitResult<'a, K, V, NodeType>),
-}
-
pub mod marker {
use core::marker::PhantomData;
///
/// // Iterate over everything.
/// for book in &books {
-/// println!("{}", book);
+/// println!("{book}");
/// }
/// ```
///
/// set.insert(5);
/// set.insert(8);
/// for &elem in set.range((Included(&4), Included(&8))) {
- /// println!("{}", elem);
+ /// println!("{elem}");
/// }
/// assert_eq!(Some(&5), set.range(4..).next());
/// ```
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
/// The elements are visited in ascending order.
///
/// # Examples
set.insert(1);
set.insert(2);
- let set_str = format!("{:?}", set);
+ let set_str = format!("{set:?}");
assert_eq!(set_str, "{1, 2}");
- assert_eq!(format!("{:?}", empty), "{}");
+ assert_eq!(format!("{empty:?}"), "{}");
}
#[test]
}
fn set_debug<K: Debug>(set: BTreeSet<K>) {
- format!("{:?}", set);
+ format!("{set:?}");
format!("{:?}", set.iter());
format!("{:?}", set.into_iter());
}
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns false.
+ /// In other words, remove all elements `e` for which `f(&e)` returns false.
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
///
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns false.
+ /// In other words, remove all elements `e` for which `f(&e)` returns false.
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
///
//! fn main() {
//! let myvector = Vector2D { x: 3, y: 4 };
//!
-//! println!("{}", myvector); // => "(3, 4)"
-//! println!("{:?}", myvector); // => "Vector2D {x: 3, y:4}"
-//! println!("{:10.3b}", myvector); // => " 5.000"
+//! println!("{myvector}"); // => "(3, 4)"
+//! println!("{myvector:?}"); // => "Vector2D {x: 3, y:4}"
+//! println!("{myvector:10.3b}"); // => " 5.000"
//! }
//! ```
//!
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(const_deref)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
#![feature(const_mut_refs)]
#![feature(const_ptr_write)]
#![feature(const_precise_live_drops)]
#[test]
fn test_show() {
let foo = Rc::new(75);
- assert_eq!(format!("{:?}", foo), "75");
+ assert_eq!(format!("{foo:?}"), "75");
}
#[test]
use std::ffi::{CStr, CString};
let x: Rc<CStr> = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
- assert_eq!(format!("{:?}", x), "\"swordfish\"");
+ assert_eq!(format!("{x:?}"), "\"swordfish\"");
let y: Weak<CStr> = Rc::downgrade(&x);
drop(x);
let b: Box<dyn Debug> = box ();
let r: Rc<dyn Debug> = Rc::from(b);
- assert_eq!(format!("{:?}", r), "()");
+ assert_eq!(format!("{r:?}"), "()");
}
#[test]
//! ```
//! let numbers = &[0, 1, 2];
//! for n in numbers {
-//! println!("{} is a number!", n);
+//! println!("{n} is a number!");
//! }
//! ```
//!
/// let v1 = Vec::from(s1);
///
/// for b in v1 {
- /// println!("{}", b);
+ /// println!("{b}");
/// }
/// ```
fn from(string: String) -> Vec<u8> {
/// let five = Arc::clone(&five);
///
/// thread::spawn(move || {
-/// println!("{:?}", five);
+/// println!("{five:?}");
/// });
/// }
/// ```
///
/// thread::spawn(move || {
/// let v = val.fetch_add(1, Ordering::SeqCst);
-/// println!("{:?}", v);
+/// println!("{v:?}");
/// });
/// }
/// ```
#[test]
fn show_arc() {
let a = Arc::new(5);
- assert_eq!(format!("{:?}", a), "5");
+ assert_eq!(format!("{a:?}"), "5");
}
// Make sure deriving works with Arc<T>
#[test]
fn test_unsized() {
let x: Arc<[i32]> = Arc::new([1, 2, 3]);
- assert_eq!(format!("{:?}", x), "[1, 2, 3]");
+ assert_eq!(format!("{x:?}"), "[1, 2, 3]");
let y = Arc::downgrade(&x.clone());
drop(x);
assert!(y.upgrade().is_none());
use std::ffi::{CStr, CString};
let x: Arc<CStr> = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
- assert_eq!(format!("{:?}", x), "\"swordfish\"");
+ assert_eq!(format!("{x:?}"), "\"swordfish\"");
let y: Weak<CStr> = Arc::downgrade(&x);
drop(x);
let b: Box<dyn Debug> = box ();
let r: Arc<dyn Debug> = Arc::from(b);
- assert_eq!(format!("{:?}", r), "()");
+ assert_eq!(format!("{r:?}"), "()");
}
#[test]
fn test_show() {
let a = Box::new(8) as Box<dyn Any>;
let b = Box::new(Test) as Box<dyn Any>;
- let a_str = format!("{:?}", a);
- let b_str = format!("{:?}", b);
+ let a_str = format!("{a:?}");
+ let b_str = format!("{b:?}");
assert_eq!(a_str, "Any { .. }");
assert_eq!(b_str, "Any { .. }");
static TEST: Test = Test;
let a = &EIGHT as &dyn Any;
let b = &TEST as &dyn Any;
- let s = format!("{:?}", a);
+ let s = format!("{a:?}");
assert_eq!(s, "Any { .. }");
- let s = format!("{:?}", b);
+ let s = format!("{b:?}");
assert_eq!(s, "Any { .. }");
}
/// vec.extend([1, 2, 3].iter().copied());
///
/// for x in &vec {
-/// println!("{}", x);
+/// println!("{x}");
/// }
/// assert_eq!(vec, [7, 1, 2, 3]);
/// ```
///
/// while let Some(top) = stack.pop() {
/// // Prints 3, 2, 1
-/// println!("{}", top);
+/// println!("{top}");
/// }
/// ```
///
#[cold]
#[inline(never)]
fn assert_failed(index: usize, len: usize) -> ! {
- panic!("swap_remove index (is {}) should be < len (is {})", index, len);
+ panic!("swap_remove index (is {index}) should be < len (is {len})");
}
let len = self.len();
#[cold]
#[inline(never)]
fn assert_failed(index: usize, len: usize) -> ! {
- panic!("insertion index (is {}) should be <= len (is {})", index, len);
+ panic!("insertion index (is {index}) should be <= len (is {len})");
}
let len = self.len();
#[inline(never)]
#[track_caller]
fn assert_failed(index: usize, len: usize) -> ! {
- panic!("removal index (is {}) should be < len (is {})", index, len);
+ panic!("removal index (is {index}) should be < len (is {len})");
}
let len = self.len();
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
///
#[cold]
#[inline(never)]
fn assert_failed(at: usize, len: usize) -> ! {
- panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+ panic!("`at` split index (is {at}) should be <= len (is {len})");
}
if at > self.len() {
/// let v = vec!["a".to_string(), "b".to_string()];
/// for s in v.into_iter() {
/// // s has type String, not &String
- /// println!("{}", s);
+ /// println!("{s}");
/// }
/// ```
#[inline]
*boxed = 42;
assert!(*boxed == 42);
- *boxed
+ *Box::leak(boxed)
};
assert!(VALUE == 42);
}
t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
- t!(format!("{:x}", A), "aloha");
- t!(format!("{:X}", B), "adios");
+ t!(format!("{A:x}"), "aloha");
+ t!(format!("{B:X}"), "adios");
t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
t!(format!("{1} {0}", 0, 1), "1 0");
t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
t!(format!("{_foo}", _foo = 6usize), "6");
t!(format!("{foo_bar}", foo_bar = 1), "1");
t!(format!("{}", 5 + 5), "10");
- t!(format!("{:#4}", C), "☃123");
- t!(format!("{:b}", D), "aa☃bb");
+ t!(format!("{C:#4}"), "☃123");
+ t!(format!("{D:b}"), "aa☃bb");
let a: &dyn fmt::Debug = &1;
- t!(format!("{:?}", a), "1");
+ t!(format!("{a:?}"), "1");
// Formatting strings and their arguments
t!(format!("{}", "a"), "a");
// Test that pointers don't get truncated.
{
let val = usize::MAX;
- let exp = format!("{:#x}", val);
+ let exp = format!("{val:#x}");
t!(format!("{:p}", val as *const isize), exp);
}
// make sure that format! doesn't move out of local variables
let a = Box::new(3);
- format!("{}", a);
- format!("{}", a);
+ format!("{a}");
+ format!("{a}");
// make sure that format! doesn't cause spurious unused-unsafe warnings when
// it's inside of an outer unsafe block
unsafe {
let a: isize = ::std::mem::transmute(3_usize);
- format!("{}", a);
+ format!("{a}");
}
// test that trailing commas are acceptable
#[test]
fn test_refcell() {
let refcell = RefCell::new(5);
- assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
let borrow = refcell.borrow_mut();
- assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: <borrowed> }");
drop(borrow);
- assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
}
#[test]
fn test_show() {
let list: LinkedList<_> = (0..10).collect();
- assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+ assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
- assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
+ assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
}
#[test]
a(v.rsplit_mut(p), b, "rsplit_mut");
for n in 0..=3 {
- a(v.splitn(n, p), b, f!("splitn, n = {}", n));
- a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {}", n));
- a(v.rsplitn(n, p), b, f!("rsplitn, n = {}", n));
- a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {}", n));
+ a(v.splitn(n, p), b, f!("splitn, n = {n}"));
+ a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}"));
+ a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}"));
+ a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}"));
}
}
}
macro_rules! test_show_vec {
($x:expr, $x_str:expr) => {{
let (x, x_str) = ($x, $x_str);
- assert_eq!(format!("{:?}", x), x_str);
- assert_eq!(format!("{:?}", x), x_str);
+ assert_eq!(format!("{x:?}"), x_str);
+ assert_eq!(format!("{x:?}"), x_str);
}};
}
let empty = Vec::<i32>::new();
let s = "ศไทย中华Việt Nam";
let c = s.chars();
assert_eq!(
- format!("{:?}", c),
+ format!("{c:?}"),
r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
);
}
}
if let Some(err) = err {
- panic!("Input skipped range at {}", err);
+ panic!("Input skipped range at {err}");
}
if first_index != haystack.len() {
fn check_str_eq(a: String, b: String) {
let mut i: isize = 0;
for ab in a.bytes() {
- println!("{}", i);
- println!("{}", ab);
+ println!("{i}");
+ println!("{ab}");
let bb: u8 = b.as_bytes()[i as usize];
- println!("{}", bb);
+ println!("{bb}");
assert_eq!(ab, bb);
i += 1;
}
#[test]
fn test_vectors() {
let x: Vec<i32> = vec![];
- assert_eq!(format!("{:?}", x), "[]");
+ assert_eq!(format!("{x:?}"), "[]");
assert_eq!(format!("{:?}", vec![1]), "[1]");
assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
fn test_str_concat() {
let a: String = "hello".to_string();
let b: String = "world".to_string();
- let s: String = format!("{}{}", a, b);
+ let s: String = format!("{a}{b}");
assert_eq!(s.as_bytes()[9], 'd' as u8);
}
assert_eq!("[0, 1]", format!("{:?}", vec2));
let slice: &[isize] = &[4, 5];
- assert_eq!("[4, 5]", format!("{:?}", slice));
+ assert_eq!("[4, 5]", format!("{slice:?}"));
}
#[test]
fn test_into_iter_debug() {
let vec = vec!['a', 'b', 'c'];
let into_iter = vec.into_iter();
- let debug = format!("{:?}", into_iter);
+ let debug = format!("{into_iter:?}");
assert_eq!(debug, "IntoIter(['a', 'b', 'c'])");
}
let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
if !ok {
- panic!("expected: {:?}\ngot: {:?}\n", expected, vec);
+ panic!("expected: {expected:?}\ngot: {vec:?}\n");
}
}
#[test]
fn test_show() {
let ringbuf: VecDeque<_> = (0..10).collect();
- assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+ assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
- assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]");
+ assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
}
#[test]
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
}
}
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
}
}
//! println!("String ({}): {}", as_string.len(), as_string);
//! }
//! None => {
-//! println!("{:?}", value);
+//! println!("{value:?}");
//! }
//! }
//! }
}
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> Index<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const Index<I> for [T; N]
where
- [T]: Index<I>,
+ [T]: ~const Index<I>,
{
type Output = <[T] as Index<I>>::Output;
}
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> IndexMut<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const IndexMut<I> for [T; N]
where
- [T]: IndexMut<I>,
+ [T]: ~const IndexMut<I>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
b'\'' => ([b'\\', b'\'', 0, 0], 2),
b'"' => ([b'\\', b'"', 0, 0], 2),
b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
- _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
+ _ => {
+ let hex_digits: &[u8; 16] = b"0123456789abcdef";
+ ([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4)
+ }
};
return EscapeDefault { range: 0..len, data };
-
- fn hexify(b: u8) -> u8 {
- match b {
- 0..=9 => b'0' + b,
- _ => b'a' + b - 10,
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
type Item = u8;
+
+ #[inline]
fn next(&mut self) -> Option<u8> {
self.range.next().map(|i| self.data[i as usize])
}
//! // of scope then the subsequent borrow would cause a dynamic thread panic.
//! // This is the major hazard of using `RefCell`.
//! let total: i32 = shared_map.borrow().values().sum();
-//! println!("{}", total);
+//! println!("{total}");
//! }
//! ```
//!
}
/// An error which can be returned when parsing a char.
+///
+/// This `struct` is created when using the [`char::from_str`] method.
#[stable(feature = "char_from_str", since = "1.20.0")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseCharError {
}
}
-/// The error type returned when a conversion from u32 to char fails.
+/// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails.
+///
+/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>) method.
+/// See its documentation for more.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CharTryFromError(());
///
/// ```
/// for c in '❤'.escape_unicode() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in '\n'.escape_debug() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in '"'.escape_default() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in 'İ'.to_lowercase() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in 'ß'.to_uppercase() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
/// allocations.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- fn clone_from(&mut self, source: &Self) {
+ #[default_method_body_is_const]
+ fn clone_from(&mut self, source: &Self)
+ where
+ Self: ~const Drop,
+ {
*self = source.clone()
}
}
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Clone for $t {
+ #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+ impl const Clone for $t {
#[inline]
fn clone(&self) -> Self {
*self
}
#[unstable(feature = "never_type", issue = "35121")]
- impl Clone for ! {
+ #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+ impl const Clone for ! {
#[inline]
fn clone(&self) -> Self {
*self
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Clone for *const T {
+ #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+ impl<T: ?Sized> const Clone for *const T {
#[inline]
fn clone(&self) -> Self {
*self
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Clone for *mut T {
+ #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+ impl<T: ?Sized> const Clone for *mut T {
#[inline]
fn clone(&self) -> Self {
*self
/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Clone for &T {
+ #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+ impl<T: ?Sized> const Clone for &T {
#[inline]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {
/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
/// details.
///
-/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`].
+/// **Note: This trait must not fail**. The `From` trait is intended for perfect conversions.
+/// If the conversion can fail or is not perfect, use [`TryFrom`].
///
/// # Generic Implementations
///
pub enum Infallible {}
#[stable(feature = "convert_infallible", since = "1.34.0")]
-impl Clone for Infallible {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl const Clone for Infallible {
fn clone(&self) -> Infallible {
match *self {}
}
///
/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
///
-/// assert_eq!(format!("{}", pythagorean_triple), "(3, 4, 5)");
+/// assert_eq!(format!("{pythagorean_triple}"), "(3, 4, 5)");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result = result::Result<(), Error>;
/// use std::fmt::{Error, Write};
///
/// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
- /// f.write_fmt(format_args!("{}", s))
+ /// f.write_fmt(format_args!("{s}"))
/// }
///
/// let mut buf = String::new();
///
/// let origin = Point { x: 0, y: 0 };
///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
/// ```
///
/// Manually implementing:
///
/// let origin = Point { x: 0, y: 0 };
///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
/// ```
///
/// There are a number of helper methods on the [`Formatter`] struct to help you with manual
///
/// let origin = Point { x: 0, y: 0 };
///
-/// assert_eq!(format!("The origin is: {:#?}", origin),
+/// assert_eq!(format!("The origin is: {origin:#?}"),
/// "The origin is: Point {
/// x: 0,
/// y: 0,
/// }
///
/// let position = Position { longitude: 1.987, latitude: 2.983 };
- /// assert_eq!(format!("{:?}", position), "(1.987, 2.983)");
+ /// assert_eq!(format!("{position:?}"), "(1.987, 2.983)");
///
- /// assert_eq!(format!("{:#?}", position), "(
+ /// assert_eq!(format!("{position:#?}"), "(
/// 1.987,
/// 2.983,
/// )");
///
/// let origin = Point { x: 0, y: 0 };
///
-/// assert_eq!(format!("The origin is: {}", origin), "The origin is: (0, 0)");
+/// assert_eq!(format!("The origin is: {origin}"), "The origin is: (0, 0)");
/// ```
#[rustc_on_unimplemented(
on(
/// ```
/// let x = 42; // 42 is '52' in octal
///
-/// assert_eq!(format!("{:o}", x), "52");
-/// assert_eq!(format!("{:#o}", x), "0o52");
+/// assert_eq!(format!("{x:o}"), "52");
+/// assert_eq!(format!("{x:#o}"), "0o52");
///
/// assert_eq!(format!("{:o}", -16), "37777777760");
/// ```
///
/// let l = Length(9);
///
-/// assert_eq!(format!("l as octal is: {:o}", l), "l as octal is: 11");
+/// assert_eq!(format!("l as octal is: {l:o}"), "l as octal is: 11");
///
-/// assert_eq!(format!("l as octal is: {:#06o}", l), "l as octal is: 0o0011");
+/// assert_eq!(format!("l as octal is: {l:#06o}"), "l as octal is: 0o0011");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Octal {
/// ```
/// let x = 42; // 42 is '101010' in binary
///
-/// assert_eq!(format!("{:b}", x), "101010");
-/// assert_eq!(format!("{:#b}", x), "0b101010");
+/// assert_eq!(format!("{x:b}"), "101010");
+/// assert_eq!(format!("{x:#b}"), "0b101010");
///
/// assert_eq!(format!("{:b}", -16), "11111111111111111111111111110000");
/// ```
///
/// let l = Length(107);
///
-/// assert_eq!(format!("l as binary is: {:b}", l), "l as binary is: 1101011");
+/// assert_eq!(format!("l as binary is: {l:b}"), "l as binary is: 1101011");
///
/// assert_eq!(
-/// format!("l as binary is: {:#032b}", l),
+/// format!("l as binary is: {l:#032b}"),
/// "l as binary is: 0b000000000000000000000001101011"
/// );
/// ```
/// ```
/// let x = 42; // 42 is '2a' in hex
///
-/// assert_eq!(format!("{:x}", x), "2a");
-/// assert_eq!(format!("{:#x}", x), "0x2a");
+/// assert_eq!(format!("{x:x}"), "2a");
+/// assert_eq!(format!("{x:#x}"), "0x2a");
///
/// assert_eq!(format!("{:x}", -16), "fffffff0");
/// ```
///
/// let l = Length(9);
///
-/// assert_eq!(format!("l as hex is: {:x}", l), "l as hex is: 9");
+/// assert_eq!(format!("l as hex is: {l:x}"), "l as hex is: 9");
///
-/// assert_eq!(format!("l as hex is: {:#010x}", l), "l as hex is: 0x00000009");
+/// assert_eq!(format!("l as hex is: {l:#010x}"), "l as hex is: 0x00000009");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait LowerHex {
/// ```
/// let x = 42; // 42 is '2A' in hex
///
-/// assert_eq!(format!("{:X}", x), "2A");
-/// assert_eq!(format!("{:#X}", x), "0x2A");
+/// assert_eq!(format!("{x:X}"), "2A");
+/// assert_eq!(format!("{x:#X}"), "0x2A");
///
/// assert_eq!(format!("{:X}", -16), "FFFFFFF0");
/// ```
///
/// let l = Length(i32::MAX);
///
-/// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:X}"), "l as hex is: 7FFFFFFF");
///
-/// assert_eq!(format!("l as hex is: {:#010X}", l), "l as hex is: 0x7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:#010X}"), "l as hex is: 0x7FFFFFFF");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait UpperHex {
/// ```
/// let x = &42;
///
-/// let address = format!("{:p}", x); // this produces something like '0x7f06092ac6d0'
+/// let address = format!("{x:p}"); // this produces something like '0x7f06092ac6d0'
/// ```
///
/// Implementing `Pointer` on a type:
///
/// let l = Length(42);
///
-/// println!("l is in memory here: {:p}", l);
+/// println!("l is in memory here: {l:p}");
///
-/// let l_ptr = format!("{:018p}", l);
+/// let l_ptr = format!("{l:018p}");
/// assert_eq!(l_ptr.len(), 18);
/// assert_eq!(&l_ptr[..2], "0x");
/// ```
/// ```
/// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
///
-/// assert_eq!(format!("{:e}", x), "4.2e1");
+/// assert_eq!(format!("{x:e}"), "4.2e1");
/// ```
///
/// Implementing `LowerExp` on a type:
/// let l = Length(100);
///
/// assert_eq!(
-/// format!("l in scientific notation is: {:e}", l),
+/// format!("l in scientific notation is: {l:e}"),
/// "l in scientific notation is: 1e2"
/// );
///
/// assert_eq!(
-/// format!("l in scientific notation is: {:05e}", l),
+/// format!("l in scientific notation is: {l:05e}"),
/// "l in scientific notation is: 001e2"
/// );
/// ```
/// ```
/// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
///
-/// assert_eq!(format!("{:E}", x), "4.2E1");
+/// assert_eq!(format!("{x:E}"), "4.2E1");
/// ```
///
/// Implementing `UpperExp` on a type:
/// let l = Length(100);
///
/// assert_eq!(
-/// format!("l in scientific notation is: {:E}", l),
+/// format!("l in scientific notation is: {l:E}"),
/// "l in scientific notation is: 1E2"
/// );
///
/// assert_eq!(
-/// format!("l in scientific notation is: {:05E}", l),
+/// format!("l in scientific notation is: {l:05E}"),
/// "l in scientific notation is: 001E2"
/// );
/// ```
/// }
/// }
///
- /// assert_eq!(&format!("{:<4}", Foo), "Foo ");
- /// assert_eq!(&format!("{:0>4}", Foo), "0Foo");
+ /// assert_eq!(&format!("{Foo:<4}"), "Foo ");
+ /// assert_eq!(&format!("{Foo:0>4}"), "0Foo");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pad(&mut self, s: &str) -> Result {
/// }
/// }
///
- /// assert_eq!(&format!("{}", Foo), "Foo");
- /// assert_eq!(&format!("{:0>8}", Foo), "Foo");
+ /// assert_eq!(&format!("{Foo}"), "Foo");
+ /// assert_eq!(&format!("{Foo:0>8}"), "Foo");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write_str(&mut self, data: &str) -> Result {
/// let c = formatter.fill();
/// if let Some(width) = formatter.width() {
/// for _ in 0..width {
- /// write!(formatter, "{}", c)?;
+ /// write!(formatter, "{c}")?;
/// }
/// Ok(())
/// } else {
- /// write!(formatter, "{}", c)
+ /// write!(formatter, "{c}")
/// }
/// }
/// }
///
/// // We set alignment to the right with ">".
- /// assert_eq!(&format!("{:G>3}", Foo), "GGG");
- /// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
+ /// assert_eq!(&format!("{Foo:G>3}"), "GGG");
+ /// assert_eq!(&format!("{Foo:t>6}"), "tttttt");
/// ```
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
/// } else {
/// "into the void"
/// };
- /// write!(formatter, "{}", s)
+ /// write!(formatter, "{s}")
/// }
/// }
///
- /// assert_eq!(&format!("{:<}", Foo), "left");
- /// assert_eq!(&format!("{:>}", Foo), "right");
- /// assert_eq!(&format!("{:^}", Foo), "center");
- /// assert_eq!(&format!("{}", Foo), "into the void");
+ /// assert_eq!(&format!("{Foo:<}"), "left");
+ /// assert_eq!(&format!("{Foo:>}"), "right");
+ /// assert_eq!(&format!("{Foo:^}"), "center");
+ /// assert_eq!(&format!("{Foo}"), "into the void");
/// ```
#[must_use]
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
/// Which kind of future are we turning this into?
#[unstable(feature = "into_future", issue = "67644")]
- type Future: Future<Output = Self::Output>;
+ type IntoFuture: Future<Output = Self::Output>;
/// Creates a future from a value.
#[unstable(feature = "into_future", issue = "67644")]
#[lang = "into_future"]
- fn into_future(self) -> Self::Future;
+ fn into_future(self) -> Self::IntoFuture;
}
#[unstable(feature = "into_future", issue = "67644")]
impl<F: Future> IntoFuture for F {
type Output = F::Output;
- type Future = F;
+ type IntoFuture = F;
- fn into_future(self) -> Self::Future {
+ fn into_future(self) -> Self::IntoFuture {
self
}
}
pub const fn black_box<T>(dummy: T) -> T {
crate::intrinsics::black_box(dummy)
}
+
+/// An identity function that causes an `unused_must_use` warning to be
+/// triggered if the given value is not used (returned, stored in a variable,
+/// etc) by the caller.
+///
+/// This is primarily intended for use in macro-generated code, in which a
+/// [`#[must_use]` attribute][must_use] either on a type or a function would not
+/// be convenient.
+///
+/// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+///
+/// # Example
+///
+/// ```
+/// #![feature(hint_must_use)]
+///
+/// use core::fmt;
+///
+/// pub struct Error(/* ... */);
+///
+/// #[macro_export]
+/// macro_rules! make_error {
+/// ($($args:expr),*) => {
+/// core::hint::must_use({
+/// let error = $crate::make_error(core::format_args!($($args),*));
+/// error
+/// })
+/// };
+/// }
+///
+/// // Implementation detail of make_error! macro.
+/// #[doc(hidden)]
+/// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
+/// Error(/* ... */)
+/// }
+///
+/// fn demo() -> Option<Error> {
+/// if true {
+/// // Oops, meant to write `return Some(make_error!("..."));`
+/// Some(make_error!("..."));
+/// }
+/// None
+/// }
+/// #
+/// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
+/// # fn main() {}
+/// ```
+///
+/// In the above example, we'd like an `unused_must_use` lint to apply to the
+/// value created by `make_error!`. However, neither `#[must_use]` on a struct
+/// nor `#[must_use]` on a function is appropriate here, so the macro expands
+/// using `core::hint::must_use` instead.
+///
+/// - We wouldn't want `#[must_use]` on the `struct Error` because that would
+/// make the following unproblematic code trigger a warning:
+///
+/// ```
+/// # struct Error;
+/// #
+/// fn f(arg: &str) -> Result<(), Error>
+/// # { Ok(()) }
+///
+/// #[test]
+/// fn t() {
+/// // Assert that `f` returns error if passed an empty string.
+/// // A value of type `Error` is unused here but that's not a problem.
+/// f("").unwrap_err();
+/// }
+/// ```
+///
+/// - Using `#[must_use]` on `fn make_error` can't help because the return value
+/// *is* used, as the right-hand side of a `let` statement. The `let`
+/// statement looks useless but is in fact necessary for ensuring that
+/// temporaries within the `format_args` expansion are not kept alive past the
+/// creation of the `Error`, as keeping them alive past that point can cause
+/// autotrait issues in async code:
+///
+/// ```
+/// # #![feature(hint_must_use)]
+/// #
+/// # struct Error;
+/// #
+/// # macro_rules! make_error {
+/// # ($($args:expr),*) => {
+/// # core::hint::must_use({
+/// # // If `let` isn't used, then `f()` produces a non-Send future.
+/// # let error = make_error(core::format_args!($($args),*));
+/// # error
+/// # })
+/// # };
+/// # }
+/// #
+/// # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
+/// # Error
+/// # }
+/// #
+/// async fn f() {
+/// // Using `let` inside the make_error expansion causes temporaries like
+/// // `unsync()` to drop at the semicolon of that `let` statement, which
+/// // is prior to the await point. They would otherwise stay around until
+/// // the semicolon on *this* statement, which is after the await point,
+/// // and the enclosing Future would not implement Send.
+/// log(make_error!("look: {:p}", unsync())).await;
+/// }
+///
+/// async fn log(error: Error) {/* ... */}
+///
+/// // Returns something without a Sync impl.
+/// fn unsync() -> *const () {
+/// 0 as *const ()
+/// }
+/// #
+/// # fn test() {
+/// # fn assert_send(_: impl Send) {}
+/// # assert_send(f());
+/// # }
+/// ```
+#[unstable(feature = "hint_must_use", issue = "94745")]
+#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[must_use] // <-- :)
+pub const fn must_use<T>(value: T) -> T {
+ value
+}
///
/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) }) {
-/// println!("{:?}", pair);
+/// println!("{pair:?}");
/// }
/// ```
///
/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) })
/// .rev() {
-/// println!("{:?}", pair);
+/// println!("{pair:?}");
/// }
/// ```
#[must_use = "iterators are lazy and do nothing unless consumed"]
//! let values = vec![1, 2, 3, 4, 5];
//!
//! for x in values {
-//! println!("{}", x);
+//! println!("{x}");
//! }
//! ```
//!
//! let values = vec![1, 2, 3, 4, 5];
//!
//! for x in values {
-//! println!("{}", x);
+//! println!("{x}");
//! }
//! ```
//!
//! None => break,
//! };
//! let x = next;
-//! let () = { println!("{}", x); };
+//! let () = { println!("{x}"); };
//! },
//! };
//! result
//! ```
//! # #![allow(unused_must_use)]
//! let v = vec![1, 2, 3, 4, 5];
-//! v.iter().map(|x| println!("{}", x));
+//! v.iter().map(|x| println!("{x}"));
//! ```
//!
//! This will not print any values, as we only created an iterator, rather than
//! ```
//! let v = vec![1, 2, 3, 4, 5];
//!
-//! v.iter().for_each(|x| println!("{}", x));
+//! v.iter().for_each(|x| println!("{x}"));
//! // or
//! for x in &v {
-//! println!("{}", x);
+//! println!("{x}");
//! }
//! ```
//!
//! let five_numbers = numbers.take(5);
//!
//! for number in five_numbers {
-//! println!("{}", number);
+//! println!("{number}");
//! }
//! ```
//!
//! let ones = std::iter::repeat(1);
//! let least = ones.min().unwrap(); // Oh no! An infinite loop!
//! // `ones.min()` causes an infinite loop, so we won't reach this point!
-//! println!("The smallest number one is {}.", least);
+//! println!("The smallest number one is {least}.");
//! ```
//!
//! [`take`]: Iterator::take
///
/// // this will give us all of the files in .foo as well as .foorc
/// for f in files {
-/// println!("{:?}", f);
+/// println!("{f:?}");
/// }
/// ```
#[stable(feature = "iter_once", since = "1.2.0")]
///
/// // this will give us all of the files in .foo as well as .foorc
/// for f in files {
-/// println!("{:?}", f);
+/// println!("{f:?}");
/// }
/// ```
#[inline]
/// created from an iterator. This is common for types which describe a
/// collection of some kind.
///
-/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead
-/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s
-/// documentation for more examples.
+/// If you want to create a collection from the contents of an iterator, the
+/// [`Iterator::collect()`] method is preferred. However, when you need to
+/// specify the container type, [`FromIterator::from_iter()`] can be more
+/// readable than using a turbofish (e.g. `::<Vec<_>>()`). See the
+/// [`Iterator::collect()`] documentation for more examples of its use.
///
/// See also: [`IntoIterator`].
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
///
+/// Using [`FromIterator::from_iter()`] as a more readable alternative to
+/// [`Iterator::collect()`]:
+///
+/// ```
+/// use std::collections::VecDeque;
+/// let first = (0..10).collect::<VecDeque<i32>>();
+/// let second = VecDeque::from_iter(0..10);
+///
+/// assert_eq!(first, second);
+/// ```
+///
/// Implementing `FromIterator` for your type:
///
/// ```
/// {
/// collection
/// .into_iter()
-/// .map(|item| format!("{:?}", item))
+/// .map(|item| format!("{item:?}"))
/// .collect()
/// }
/// ```
/// c.extend(vec![1, 2, 3]);
///
/// // we've added these elements onto the end
-/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
+/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{c:?}"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Extend<A> {
/// let zero = "0".to_string();
///
/// let result = numbers.iter().rfold(zero, |acc, &x| {
- /// format!("({} + {})", x, acc)
+ /// format!("({x} + {acc})")
/// });
///
/// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
to have a bounded `RangeInclusive`: `0..=end`"
),
+ on(
+ _Self = "[]",
+ label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
+ ),
+ on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
on(
_Self = "&str",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
/// ```
/// # #![allow(unused_must_use)]
/// // don't do this:
- /// (0..5).map(|x| println!("{}", x));
+ /// (0..5).map(|x| println!("{x}"));
///
/// // it won't even execute, as it is lazy. Rust will warn you about this.
///
/// // Instead, use for:
/// for x in 0..5 {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[inline]
/// (0..5).flat_map(|x| x * 100 .. x * 110)
/// .enumerate()
/// .filter(|&(i, x)| (i + x) % 3 == 0)
- /// .for_each(|(i, x)| println!("{}:{}", i, x));
+ /// .for_each(|(i, x)| println!("{i}:{x}"));
/// ```
#[inline]
#[stable(feature = "iterator_for_each", since = "1.21.0")]
/// .filter(|x| x % 2 == 0)
/// .fold(0, |sum, i| sum + i);
///
- /// println!("{}", sum);
+ /// println!("{sum}");
///
/// // let's add some inspect() calls to investigate what's happening
/// let sum = a.iter()
/// .cloned()
- /// .inspect(|x| println!("about to filter: {}", x))
+ /// .inspect(|x| println!("about to filter: {x}"))
/// .filter(|x| x % 2 == 0)
- /// .inspect(|x| println!("made it through filter: {}", x))
+ /// .inspect(|x| println!("made it through filter: {x}"))
/// .fold(0, |sum, i| sum + i);
///
- /// println!("{}", sum);
+ /// println!("{sum}");
/// ```
///
/// This will print:
/// .map(|line| line.parse::<i32>())
/// .inspect(|num| {
/// if let Err(ref e) = *num {
- /// println!("Parsing error: {}", e);
+ /// println!("Parsing error: {e}");
/// }
/// })
/// .filter_map(Result::ok)
/// .sum();
///
- /// println!("Sum: {}", sum);
+ /// println!("Sum: {sum}");
/// ```
///
/// This will print:
try_process(self, |i| i.collect())
}
+ /// Collects all the items from an iterator into a collection.
+ ///
+ /// This method consumes the iterator and adds all its items to the
+ /// passed collection. The collection is then returned, so the call chain
+ /// can be continued.
+ ///
+ /// This is useful when you already have a collection and wants to add
+ /// the iterator items to it.
+ ///
+ /// This method is a convenience method to call [Extend::extend](trait.Extend.html),
+ /// but instead of being called on a collection, it's called on an iterator.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(iter_collect_into)]
+ ///
+ /// let a = [1, 2, 3];
+ /// let mut vec: Vec::<i32> = vec![0, 1];
+ ///
+ /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+ /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+ ///
+ /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec);
+ /// ```
+ ///
+ /// `Vec` can have a manual set capacity to avoid reallocating it:
+ ///
+ /// ```
+ /// #![feature(iter_collect_into)]
+ ///
+ /// let a = [1, 2, 3];
+ /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+ ///
+ /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+ /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+ ///
+ /// assert_eq!(6, vec.capacity());
+ /// println!("{:?}", vec);
+ /// ```
+ ///
+ /// The returned mutable reference can be used to continue the call chain:
+ ///
+ /// ```
+ /// #![feature(iter_collect_into)]
+ ///
+ /// let a = [1, 2, 3];
+ /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+ ///
+ /// let count = a.iter().collect_into(&mut vec).iter().count();
+ ///
+ /// assert_eq!(count, vec.len());
+ /// println!("Vec len is {}", count);
+ ///
+ /// let count = a.iter().collect_into(&mut vec).iter().count();
+ ///
+ /// assert_eq!(count, vec.len());
+ /// println!("Vec len now is {}", count);
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
+ fn collect_into<E: Extend<Self::Item>>(self, collection: &mut E) -> &mut E
+ where
+ Self: Sized,
+ {
+ collection.extend(self);
+ collection
+ }
+
/// Consumes an iterator, creating two collections from it.
///
/// The predicate passed to `partition()` can return `true`, or `false`.
///
/// let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"];
///
- /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{}", x));
+ /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{x}"));
/// assert!(res.is_ok());
///
/// let mut it = data.iter().cloned();
/// let zero = "0".to_string();
///
/// let result = numbers.iter().fold(zero, |acc, &x| {
- /// format!("({} + {})", acc, x)
+ /// format!("({acc} + {x})")
/// });
///
/// assert_eq!(result, "(((((0 + 1) + 2) + 3) + 4) + 5)");
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_char_convert)]
+#![feature(const_clone)]
#![feature(const_discriminant)]
#![feature(const_eval_select)]
#![feature(const_float_bits_conv)]
#![feature(variant_count)]
#![feature(const_array_from_ref)]
#![feature(const_slice_from_ref)]
+#![feature(const_slice_index)]
+#![feature(const_is_char_boundary)]
//
// Language features:
#![feature(abi_unadjusted)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)]
#![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_impl_trait)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_impl_trait))]
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]
#![feature(const_refs_to_cell)]
#![feature(decl_macro)]
#![feature(derive_default_enum)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
#![feature(doc_cfg)]
#![feature(doc_notable_trait)]
#![feature(rustdoc_internals)]
#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
#[allow(rustdoc::bare_urls)]
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
mod core_simd;
#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
pub mod simd {
#[unstable(feature = "portable_simd", issue = "86656")]
pub use crate::core_simd::simd::*;
///
/// ```
/// let path: &'static str = env!("PATH");
- /// println!("the $PATH variable at the time of compiling was: {}", path);
+ /// println!("the $PATH variable at the time of compiling was: {path}");
/// ```
///
/// You can customize the error message by passing a string as the second
///
/// ```
/// let key: Option<&'static str> = option_env!("SECRET_KEY");
- /// println!("the secret key might be: {:?}", key);
+ /// println!("the secret key might be: {key:?}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
///
/// ```
/// let current_line = line!();
- /// println!("defined on line: {}", current_line);
+ /// println!("defined on line: {current_line}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
///
/// ```
/// let current_col = column!();
- /// println!("defined on column: {}", current_col);
+ /// println!("defined on column: {current_col}");
/// ```
///
/// `column!` counts Unicode code points, not bytes or graphemes. As a result, the first two
///
/// ```
/// let this_file = file!();
- /// println!("defined in file: {}", this_file);
+ /// println!("defined in file: {this_file}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
/// fn main() {
/// let my_str = include_str!("spanish.in");
/// assert_eq!(my_str, "adiós\n");
- /// print!("{}", my_str);
+ /// print!("{my_str}");
/// }
/// ```
///
/// fn main() {
/// let my_string = include!("monkeys.in");
/// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
- /// println!("{}", my_string);
+ /// println!("{my_string}");
/// }
/// ```
///
///
/// // `x` has moved into `y`, and so cannot be used
///
-/// // println!("{:?}", x); // error: use of moved value
+/// // println!("{x:?}"); // error: use of moved value
/// ```
///
/// However, if a type implements `Copy`, it instead has 'copy semantics':
///
/// // `y` is a copy of `x`
///
-/// println!("{:?}", x); // A-OK!
+/// println!("{x:?}"); // A-OK!
/// ```
///
/// It's important to note that in these two examples, the only difference is whether you
/// * '2.5E-10'
/// * '5.'
/// * '.5', or, equivalently, '0.5'
- /// * 'inf', '-inf', 'NaN'
+ /// * 'inf', '-inf', '+infinity', 'NaN'
+ ///
+ /// Note that alphabetical characters are not case-sensitive.
///
/// Leading and trailing whitespace represent an error.
///
/// # Grammar
///
- /// All strings that adhere to the following [EBNF] grammar
- /// will result in an [`Ok`] being returned:
+ /// All strings that adhere to the following [EBNF] grammar when
+ /// lowercased will result in an [`Ok`] being returned:
///
/// ```txt
- /// Float ::= Sign? ( 'inf' | 'NaN' | Number )
+ /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
/// Number ::= ( Digit+ |
+ /// '.' Digit* |
/// Digit+ '.' Digit* |
/// Digit* '.' Digit+ ) Exp?
- /// Exp ::= [eE] Sign? Digit+
+ /// Exp ::= 'e' Sign? Digit+
/// Sign ::= [+-]
/// Digit ::= [0-9]
/// ```
/// use std::str::FromStr;
///
/// if let Err(e) = f64::from_str("a.12") {
-/// println!("Failed conversion to f64: {}", e);
+/// println!("Failed conversion to f64: {e}");
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
///
/// ```
/// if let Err(e) = i32::from_str_radix("a12", 10) {
-/// println!("Failed conversion to i32: {}", e);
+/// println!("Failed conversion to i32: {e}");
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
let r = try_opt!(self.checked_rem(rhs));
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
- try_opt!(r.checked_add(rhs))
+ // r + rhs cannot overflow because they have opposite signs
+ r + rhs
} else {
r
};
if m == 0 {
Some(self)
} else {
- self.checked_add(try_opt!(rhs.checked_sub(m)))
+ // rhs - m cannot overflow because m has the same sign as rhs
+ self.checked_add(rhs - m)
}
}
ascii::escape_default(self)
}
- pub(crate) fn is_utf8_char_boundary(self) -> bool {
+ pub(crate) const fn is_utf8_char_boundary(self) -> bool {
// This is bit magic equivalent to: b < 128 || b >= 192
(self as i8) >= -0x40
}
}
nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }
+
+macro_rules! nonzero_min_max_unsigned {
+ ( $( $Ty: ident($Int: ident); )+ ) => {
+ $(
+ impl $Ty {
+ /// The smallest value that can be represented by this non-zero
+ /// integer type, 1.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_min_max)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")]
+ /// ```
+ #[unstable(feature = "nonzero_min_max", issue = "89065")]
+ pub const MIN: Self = Self::new(1).unwrap();
+
+ /// The largest value that can be represented by this non-zero
+ /// integer type,
+ #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_min_max)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+ /// ```
+ #[unstable(feature = "nonzero_min_max", issue = "89065")]
+ pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+ }
+ )+
+ }
+}
+
+macro_rules! nonzero_min_max_signed {
+ ( $( $Ty: ident($Int: ident); )+ ) => {
+ $(
+ impl $Ty {
+ /// The smallest value that can be represented by this non-zero
+ /// integer type,
+ #[doc = concat!("equal to [`", stringify!($Int), "::MIN`].")]
+ ///
+ /// Note: While most integer types are defined for every whole
+ /// number between `MIN` and `MAX`, signed non-zero integers are
+ /// a special case. They have a "gap" at 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_min_max)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")]
+ /// ```
+ #[unstable(feature = "nonzero_min_max", issue = "89065")]
+ pub const MIN: Self = Self::new(<$Int>::MIN).unwrap();
+
+ /// The largest value that can be represented by this non-zero
+ /// integer type,
+ #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+ ///
+ /// Note: While most integer types are defined for every whole
+ /// number between `MIN` and `MAX`, signed non-zero integers are
+ /// a special case. They have a "gap" at 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_min_max)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+ /// ```
+ #[unstable(feature = "nonzero_min_max", issue = "89065")]
+ pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+ }
+ )+
+ }
+}
+
+nonzero_min_max_unsigned! {
+ NonZeroU8(u8);
+ NonZeroU16(u16);
+ NonZeroU32(u32);
+ NonZeroU64(u64);
+ NonZeroU128(u128);
+ NonZeroUsize(usize);
+}
+
+nonzero_min_max_signed! {
+ NonZeroI8(i8);
+ NonZeroI16(i16);
+ NonZeroI32(i32);
+ NonZeroI64(i64);
+ NonZeroI128(i128);
+ NonZeroIsize(isize);
+}
pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
match try_opt!(self.checked_rem(rhs)) {
0 => Some(self),
- r => self.checked_add(try_opt!(rhs.checked_sub(r)))
+ // rhs - r cannot overflow because r is smaller than rhs
+ r => self.checked_add(rhs - r)
}
}
/// type Output = Weight;
///
/// fn index(&self, index: Side) -> &Self::Output {
-/// println!("Accessing {:?}-side of balance immutably", index);
+/// println!("Accessing {index:?}-side of balance immutably");
/// match index {
/// Side::Left => &self.left,
/// Side::Right => &self.right,
///
/// impl IndexMut<Side> for Balance {
/// fn index_mut(&mut self, index: Side) -> &mut Self::Output {
-/// println!("Accessing {:?}-side of balance mutably", index);
+/// println!("Accessing {index:?}-side of balance mutably");
/// match index {
/// Side::Left => &mut self.left,
/// Side::Right => &mut self.right,
/// Converts to an exclusive `Range` for `SliceIndex` implementations.
/// The caller is responsible for dealing with `end == usize::MAX`.
#[inline]
- pub(crate) fn into_slice_range(self) -> Range<usize> {
+ pub(crate) const fn into_slice_range(self) -> Range<usize> {
// If we're not exhausted, we want to simply slice `start..end + 1`.
// If we are exhausted, then slicing with `end + 1..end + 1` gives us an
// empty range that is still subject to bounds-checks for that endpoint.
/// map.insert(8, "c");
///
/// for (key, value) in map.range((Excluded(3), Included(8))) {
-/// println!("{}: {}", key, value);
+/// println!("{key}: {value}");
/// }
///
/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next());
//! // Pattern match to retrieve the value
//! match result {
//! // The division was valid
-//! Some(x) => println!("Result: {}", x),
+//! Some(x) => println!("Result: {x}"),
//! // The division was invalid
//! None => println!("Cannot divide by 0"),
//! }
//!
//! fn check_optional(optional: Option<Box<i32>>) {
//! match optional {
-//! Some(p) => println!("has value {}", p),
+//! Some(p) => println!("has value {p}"),
//! None => println!("has no value"),
//! }
//! }
//! }
//!
//! match name_of_biggest_animal {
-//! Some(name) => println!("the biggest animal is {}", name),
+//! Some(name) => println!("the biggest animal is {name}"),
//! None => println!("there are no animals :("),
//! }
//! ```
matches!(*self, Some(_))
}
- /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+ /// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
///
/// # Examples
///
/// #![feature(is_some_with)]
///
/// let x: Option<u32> = Some(2);
- /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+ /// assert_eq!(x.is_some_and(|&x| x > 1), true);
///
/// let x: Option<u32> = Some(0);
- /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+ /// assert_eq!(x.is_some_and(|&x| x > 1), false);
///
/// let x: Option<u32> = None;
- /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+ /// assert_eq!(x.is_some_and(|&x| x > 1), false);
/// ```
#[must_use]
#[inline]
#[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+ pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
matches!(self, Some(x) if f(x))
}
/// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
/// // then consume *that* with `map`, leaving `text` on the stack.
/// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
- /// println!("still can print text: {:?}", text);
+ /// println!("still can print text: {text:?}");
/// ```
#[inline]
#[rustc_const_stable(feature = "const_option", since = "1.48.0")]
/// let v = vec![1, 2, 3, 4, 5];
///
/// // prints "got: 4"
- /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x));
+ /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {x}"));
///
/// // prints nothing
- /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x));
+ /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}"));
/// ```
#[inline]
#[unstable(feature = "result_option_inspect", issue = "91345")]
/////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for Option<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T> const Clone for Option<T>
+where
+ T: ~const Clone + ~const Drop,
+{
#[inline]
fn clone(&self) -> Self {
match self {
/// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
/// let o: Option<usize> = Option::from(&s).map(|ss: &String| ss.len());
///
- /// println!("Can still print s: {:?}", s);
+ /// println!("Can still print s: {s:?}");
///
/// assert_eq!(o, Some(18));
/// ```
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-/// println!("panic occurred: {:?}", s);
+/// println!("panic occurred: {s:?}");
/// } else {
/// println!("panic occurred");
/// }
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
- /// println!("panic occurred: {:?}", s);
+ /// println!("panic occurred: {s:?}");
/// } else {
/// println!("panic occurred");
/// }
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
pub const fn panic(expr: &'static str) -> ! {
- // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
+ // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
// reduce size overhead. The format_args! macro uses str's Display trait to
// write expr, which calls Formatter::pad, which must accommodate string
// truncation and padding (even though none is used here). Using
super::intrinsics::abort()
}
- panic!("index out of bounds: the len is {} but the index is {}", len, index)
+ panic!("index out of bounds: the len is {len} but the index is {index}")
}
// This function is called directly by the codegen backend, and must not have
/// stuff(pin!(Foo { /* … */ }));
/// ```
///
-/// ### Manually polling a `Future` (wihout `Unpin` bounds)
+/// ### Manually polling a `Future` (without `Unpin` bounds)
///
/// ```rust
/// #![feature(pin_macro)]
///
/// // This loop prints: 0 1 2
/// for x in array {
-/// print!("{} ", x);
+/// print!("{x} ");
/// }
/// ```
///
/// // This creates a slice iterator, producing references to each value.
/// for item in array.into_iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // The `array_into_iter` lint suggests this change for future compatibility:
/// for item in array.iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
/// // This iterates by reference:
/// for item in array.iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // This iterates by value:
/// for item in array.into_iter().enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
/// // This iterates by reference:
/// for item in array.iter() {
/// let x: &i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // This iterates by value:
/// for item in IntoIterator::into_iter(array) {
/// let x: i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // This iterates by value:
/// for item in array {
/// let x: i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // IntoIter can also start a chain.
/// // This iterates by value:
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
///
/// unsafe {
/// if let Some(val_back) = ptr.as_ref() {
- /// println!("We got back the value: {}!", val_back);
+ /// println!("We got back the value: {val_back}!");
/// }
/// }
/// ```
///
/// unsafe {
/// let val_back = &*ptr;
- /// println!("We got back the value: {}!", val_back);
+ /// println!("We got back the value: {val_back}!");
/// }
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+ pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
where
- I: SliceIndex<[T]>,
+ I: ~const SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked(self) }
///
/// unsafe {
/// if let Some(val_back) = ptr.as_ref() {
- /// println!("We got back the value: {}!", val_back);
+ /// println!("We got back the value: {val_back}!");
/// }
/// }
/// ```
///
/// unsafe {
/// let val_back = &*ptr;
- /// println!("We got back the value: {}!", val_back);
+ /// println!("We got back the value: {val_back}!");
/// }
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
/// let first_value = unsafe { ptr.as_mut().unwrap() };
/// *first_value = 4;
/// # assert_eq!(s, [4, 2, 3]);
- /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+ /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
/// ```
///
/// # Null-unchecked version
/// let first_value = unsafe { &mut *ptr };
/// *first_value = 4;
/// # assert_eq!(s, [4, 2, 3]);
- /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+ /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline(always)]
- pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+ pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
where
- I: SliceIndex<[T]>,
+ I: ~const SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked_mut(self) }
/// let ptr = NonNull::new(&mut x as *mut _).expect("ptr is null!");
///
/// let ref_x = unsafe { ptr.as_ref() };
- /// println!("{}", ref_x);
+ /// println!("{ref_x}");
/// ```
///
/// [the module documentation]: crate::ptr#safety
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+ pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
where
- I: SliceIndex<[T]>,
+ I: ~const SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
// As a consequence, the resulting pointer cannot be null.
}
#[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Clone for NonNull<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for NonNull<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Clone for Unique<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for Unique<T> {
#[inline]
fn clone(&self) -> Self {
*self
//!
//! let version = parse_version(&[1, 2, 3, 4]);
//! match version {
-//! Ok(v) => println!("working with version: {:?}", v),
-//! Err(e) => println!("error parsing header: {:?}", e),
+//! Ok(v) => println!("working with version: {v:?}"),
+//! Err(e) => println!("error parsing header: {e:?}"),
//! }
//! ```
//!
//! .collect();
//! assert_eq!(errs.len(), 3);
//! assert_eq!(nums, [17, 99]);
-//! println!("results {:?}", results);
-//! println!("errs {:?}", errs);
-//! println!("nums {:?}", nums);
+//! println!("results {results:?}");
+//! println!("errs {errs:?}");
+//! println!("nums {nums:?}");
//! ```
//!
//! ## Collecting into `Result`
matches!(*self, Ok(_))
}
- /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+ /// Returns `true` if the result is [`Ok`] and the value inside of it matches a predicate.
///
/// # Examples
///
/// #![feature(is_some_with)]
///
/// let x: Result<u32, &str> = Ok(2);
- /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+ /// assert_eq!(x.is_ok_and(|&x| x > 1), true);
///
/// let x: Result<u32, &str> = Ok(0);
- /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+ /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
///
/// let x: Result<u32, &str> = Err("hey");
- /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+ /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
/// ```
#[must_use]
#[inline]
#[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+ pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
matches!(self, Ok(x) if f(x))
}
!self.is_ok()
}
- /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+ /// Returns `true` if the result is [`Err`] and the value inside of it matches a predicate.
///
/// # Examples
///
/// use std::io::{Error, ErrorKind};
///
/// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
- /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+ /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);
///
/// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
- /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+ /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
///
/// let x: Result<u32, Error> = Ok(123);
- /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+ /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
/// ```
#[must_use]
#[inline]
#[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+ pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool {
matches!(self, Err(x) if f(x))
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok(self) -> Option<T> {
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+ pub const fn ok(self) -> Option<T>
+ where
+ E: ~const Drop,
+ {
match self {
Ok(x) => Some(x),
- Err(_) => None,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(x) => None,
}
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn err(self) -> Option<E> {
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+ pub const fn err(self) -> Option<E>
+ where
+ T: ~const Drop,
+ {
match self {
- Ok(_) => None,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Ok(x) => None,
Err(x) => Some(x),
}
}
///
/// for num in line.lines() {
/// match num.parse::<i32>().map(|i| i * 2) {
- /// Ok(n) => println!("{}", n),
+ /// Ok(n) => println!("{n}"),
/// Err(..) => {}
/// }
/// }
/// Basic usage:
///
/// ```
- /// fn stringify(x: u32) -> String { format!("error code: {}", x) }
+ /// fn stringify(x: u32) -> String { format!("error code: {x}") }
///
/// let x: Result<u32, u32> = Ok(2);
/// assert_eq!(x.map_err(stringify), Ok(2));
///
/// let x: u8 = "4"
/// .parse::<u8>()
- /// .inspect(|x| println!("original: {}", x))
+ /// .inspect(|x| println!("original: {x}"))
/// .map(|x| x.pow(3))
/// .expect("failed to parse number");
/// ```
///
/// fn read() -> io::Result<String> {
/// fs::read_to_string("address.txt")
- /// .inspect_err(|e| eprintln!("failed to read file: {}", e))
+ /// .inspect_err(|e| eprintln!("failed to read file: {e}"))
/// }
/// ```
#[inline]
/// }
///
/// let s: String = only_good_news().into_ok();
- /// println!("{}", s);
+ /// println!("{s}");
/// ```
#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
#[inline]
/// }
///
/// let error: String = only_bad_news().into_err();
- /// println!("{}", error);
+ /// println!("{error}");
/// ```
#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
#[inline]
/// assert_eq!(x.and(y), Ok("different result type"));
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+ pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ E: ~const Drop,
+ {
match self {
- Ok(_) => res,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Ok(x) => res,
Err(e) => Err(e),
}
}
/// assert_eq!(x.or(y), Ok(2));
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+ pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
+ where
+ T: ~const Drop,
+ E: ~const Drop,
+ F: ~const Drop,
+ {
match self {
Ok(v) => Ok(v),
- Err(_) => res,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(e) => res,
}
}
/// assert_eq!(x.unwrap_or(default), default);
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or(self, default: T) -> T {
+ pub const fn unwrap_or(self, default: T) -> T
+ where
+ T: ~const Drop,
+ E: ~const Drop,
+ {
match self {
Ok(t) => t,
- Err(_) => default,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(e) => default,
}
}
#[cold]
#[track_caller]
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
- panic!("{}: {:?}", msg, error)
+ panic!("{msg}: {error:?}")
}
// This is a separate function to avoid constructing a `dyn Debug`
/////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone, E: Clone> Clone for Result<T, E> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T, E> const Clone for Result<T, E>
+where
+ T: ~const Clone + ~const Drop,
+ E: ~const Clone + ~const Drop,
+{
#[inline]
fn clone(&self) -> Self {
match self {
//! Indexing implementations for `[T]`.
+use crate::intrinsics::const_eval_select;
use crate::ops;
use crate::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::Index<I> for [T]
where
- I: SliceIndex<[T]>,
+ I: ~const SliceIndex<[T]>,
{
type Output = I::Output;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::IndexMut<I> for [T]
where
- I: SliceIndex<[T]>,
+ I: ~const SliceIndex<[T]>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
- panic!("range start index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+ // SAFETY: we are just panicking here
+ unsafe {
+ const_eval_select(
+ (index, len),
+ slice_start_index_len_fail_ct,
+ slice_start_index_len_fail_rt,
+ )
+ }
+}
+
+// FIXME const-hack
+fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
+ panic!("range start index {index} out of range for slice of length {len}");
+}
+
+const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
+ panic!("slice start index is out of range for slice");
}
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
- panic!("range end index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+ // SAFETY: we are just panicking here
+ unsafe {
+ const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
+ }
+}
+
+// FIXME const-hack
+fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
+ panic!("range end index {index} out of range for slice of length {len}");
+}
+
+const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
+ panic!("slice end index is out of range for slice");
}
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn slice_index_order_fail(index: usize, end: usize) -> ! {
- panic!("slice index starts at {} but ends at {}", index, end);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_index_order_fail(index: usize, end: usize) -> ! {
+ // SAFETY: we are just panicking here
+ unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
+}
+
+// FIXME const-hack
+fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
+ panic!("slice index starts at {index} but ends at {end}");
+}
+
+const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
+ panic!("slice index start is larger than end");
}
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn slice_start_index_overflow_fail() -> ! {
+const fn slice_start_index_overflow_fail() -> ! {
panic!("attempted to index slice from after maximum usize");
}
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn slice_end_index_overflow_fail() -> ! {
+const fn slice_end_index_overflow_fail() -> ! {
panic!("attempted to index slice up to maximum usize");
}
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for usize {
type Output = T;
#[inline]
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];
#[inline]
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
type Output = [T];
#[inline]
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
type Output = [T];
#[inline]
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
type Output = [T];
#[inline]
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
type Output = [T];
#[inline]
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
type Output = [T];
#[inline]
///
/// // Then, we iterate over it:
/// for element in slice.iter() {
-/// println!("{}", element);
+/// println!("{element}");
/// }
/// ```
///
/// }
///
/// // We now have "[2, 3, 4]":
-/// println!("{:?}", slice);
+/// println!("{slice:?}");
/// ```
///
/// [`iter_mut`]: slice::iter_mut
/// *iter.next().unwrap() += 1;
/// }
/// // Now slice is "[2, 2, 3]":
- /// println!("{:?}", slice);
+ /// println!("{slice:?}");
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "iter_to_slice", since = "1.4.0")]
use crate::ptr;
use crate::result::Result;
use crate::result::Result::{Err, Ok};
-#[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
use crate::simd::{self, Simd};
use crate::slice;
/// assert_eq!(None, v.get(0..4));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub fn get<I>(&self, index: I) -> Option<&I::Output>
+ pub const fn get<I>(&self, index: I) -> Option<&I::Output>
where
- I: SliceIndex<Self>,
+ I: ~const SliceIndex<Self>,
{
index.get(self)
}
/// assert_eq!(x, &[0, 42, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+ pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where
- I: SliceIndex<Self>,
+ I: ~const SliceIndex<Self>,
{
index.get_mut(self)
}
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+ pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where
- I: SliceIndex<Self>,
+ I: ~const SliceIndex<Self>,
{
// SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
// the slice is dereferenceable because `self` is a safe reference.
/// assert_eq!(x, &[1, 13, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+ pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where
- I: SliceIndex<Self>,
+ I: ~const SliceIndex<Self>,
{
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
// the slice is dereferenceable because `self` is a safe reference.
/// let v = [10, 40, 30, 20, 60, 50];
///
/// for group in v.splitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
+ /// println!("{group:?}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// let v = [10, 40, 30, 20, 60, 50];
///
/// for group in v.rsplitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
+ /// println!("{group:?}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
/// ```
#[unstable(feature = "portable_simd", issue = "86656")]
- #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
where
Simd<T, LANES>: AsRef<[T; LANES]>,
/// be lifted in a way that would make it possible to see panics from this
/// method for something like `LANES == 3`.
#[unstable(feature = "portable_simd", issue = "86656")]
- #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
where
Simd<T, LANES>: AsMut<[T; LANES]>,
#[inline(never)]
#[cold]
#[track_caller]
-fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+ // SAFETY: panics for both branches
+ unsafe {
+ crate::intrinsics::const_eval_select(
+ (s, begin, end),
+ slice_error_fail_ct,
+ slice_error_fail_rt,
+ )
+ }
+}
+
+const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
+ panic!("failed to slice string");
+}
+
+fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
const MAX_DISPLAY_LENGTH: usize = 256;
let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
let s_trunc = &s[..trunc_len];
// 1. out of bounds
if begin > s.len() || end > s.len() {
let oob_index = if begin > s.len() { begin } else { end };
- panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
+ panic!("byte index {oob_index} is out of bounds of `{s_trunc}`{ellipsis}");
}
// 2. begin <= end
/// ```
#[must_use]
#[stable(feature = "is_char_boundary", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "none")]
#[inline]
- pub fn is_char_boundary(&self, index: usize) -> bool {
+ pub const fn is_char_boundary(&self, index: usize) -> bool {
// 0 is always ok.
// Test for 0 explicitly so that it can optimize out the check
// easily and skip reading string data for that case.
/// assert!(v.get(..42).is_none());
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+ pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
i.get(self)
}
/// assert_eq!("HEllo", v);
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+ pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
i.get_mut(self)
}
/// }
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
+ pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
// the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
/// }
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
#[inline]
- pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
+ pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+ &mut self,
+ i: I,
+ ) -> &mut I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
// the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
///
/// ```
/// for c in "❤\n!".escape_debug() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in "❤\n!".escape_default() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
///
/// ```
/// for c in "❤\n!".escape_unicode() {
- /// print!("{}", c);
+ /// print!("{c}");
/// }
/// println!();
/// ```
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::Index<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::Index<I> for str
where
- I: SliceIndex<str>,
+ I: ~const SliceIndex<str>,
{
type Output = I::Output;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::IndexMut<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::IndexMut<I> for str
where
- I: SliceIndex<str>,
+ I: ~const SliceIndex<str>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
#[inline(never)]
#[cold]
#[track_caller]
-fn str_index_overflow_fail() -> ! {
+const fn str_index_overflow_fail() -> ! {
panic!("attempted to index str up to maximum usize");
}
///
/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFull {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
/// // &s[3 .. 100];
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::Range<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
/// Panics if `end` does not point to the starting byte offset of a
/// character (as defined by `is_char_boundary`), or if `end > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
/// Panics if `begin` does not point to the starting byte offset of
/// a character (as defined by `is_char_boundary`), or if `begin > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
/// to the ending byte offset of a character (`end + 1` is either a starting
/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
/// (`end + 1` is either a starting byte offset as defined by
/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
//! }
//!
//! if let Err(panic) = thread.join() {
-//! println!("Thread had an error: {:?}", panic);
+//! println!("Thread had an error: {panic:?}");
//! }
//! }
//! ```
/// let a = &*AtomicBool::from_mut_slice(&mut some_bools);
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| a[i].store(true, Ordering::Relaxed));
+ /// s.spawn(move || a[i].store(true, Ordering::Relaxed));
/// }
/// });
/// assert_eq!(some_bools, [true; 10]);
/// let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| {
+ /// s.spawn(move || {
/// let name = Box::new(format!("thread{i}"));
/// a[i].store(Box::into_raw(name), Ordering::Relaxed);
/// });
/// ```
/// use std::sync::atomic::AtomicBool;
/// let atomic_bool = AtomicBool::from(true);
- /// assert_eq!(format!("{:?}", atomic_bool), "true")
+ /// assert_eq!(format!("{atomic_bool:?}"), "true")
/// ```
#[inline]
fn from(b: bool) -> Self {
#[doc = concat!("let a = &*", stringify!($atomic_type), "::from_mut_slice(&mut some_ints);")]
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| a[i].store(i as _, Ordering::Relaxed));
+ /// s.spawn(move || a[i].store(i as _, Ordering::Relaxed));
/// }
/// });
/// for (i, n) in some_ints.into_iter().enumerate() {
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
-/// println!("Failed conversion to Duration: {}", e);
+/// println!("Failed conversion to Duration: {e}");
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
/// use std::io::*;
/// let data = vec![1, 2, 3, 4, 5];
/// let res: Result<()> = data.iter()
-/// .map(|x| writeln!(stdout(), "{}", x))
+/// .map(|x| writeln!(stdout(), "{x}"))
/// .collect();
/// assert!(res.is_ok());
/// ```
match a.downcast_ref::<usize>() {
Some(&5) => {}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match a.downcast_ref::<Test>() {
None => {}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
}
assert_eq!(*x, 5);
*x = 612;
}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match b_r.downcast_mut::<usize>() {
assert_eq!(*x, 7);
*x = 413;
}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match a_r.downcast_mut::<Test>() {
None => (),
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match b_r.downcast_mut::<Test>() {
None => (),
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match a_r.downcast_mut::<usize>() {
Some(&mut 612) => {}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
match b_r.downcast_mut::<usize>() {
Some(&mut 413) => {}
- x => panic!("Unexpected value {:?}", x),
+ x => panic!("Unexpected value {x:?}"),
}
}
#[test]
fn cell_has_sensible_show() {
let x = Cell::new("foo bar");
- assert!(format!("{:?}", x).contains(x.get()));
+ assert!(format!("{x:?}").contains(x.get()));
x.set("baz qux");
- assert!(format!("{:?}", x).contains(x.get()));
+ assert!(format!("{x:?}").contains(x.get()));
}
#[test]
let refcell = RefCell::new("foo");
let refcell_refmut = refcell.borrow_mut();
- assert!(format!("{:?}", refcell_refmut).contains("foo"));
+ assert!(format!("{refcell_refmut:?}").contains("foo"));
drop(refcell_refmut);
let refcell_ref = refcell.borrow();
- assert!(format!("{:?}", refcell_ref).contains("foo"));
+ assert!(format!("{refcell_ref:?}").contains("foo"));
drop(refcell_ref);
}
}
}
- assert_eq!("Foo", format!("{:?}", Foo));
- assert_eq!("Foo", format!("{:#?}", Foo));
+ assert_eq!("Foo", format!("{Foo:?}"));
+ assert_eq!("Foo", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!("Foo { bar: true }", format!("{:?}", Foo));
+ assert_eq!("Foo { bar: true }", format!("{Foo:?}"));
assert_eq!(
"Foo {
bar: true,
}",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{:?}", Foo));
+ assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}"));
assert_eq!(
"Foo {
bar: true,
baz: 10/20,
}",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
assert_eq!(
"Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }",
- format!("{:?}", Bar)
+ format!("{Bar:?}")
);
assert_eq!(
"Bar {
},
hello: \"world\",
}",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
}
- assert_eq!("Foo { .. }", format!("{:?}", Foo));
- assert_eq!("Foo { .. }", format!("{:#?}", Foo));
+ assert_eq!("Foo { .. }", format!("{Foo:?}"));
+ assert_eq!("Foo { .. }", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
+ assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}"));
assert_eq!(
"Foo {
bar: true,
baz: 10/20,
..
}",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
assert_eq!(
"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
- format!("{:?}", Bar)
+ format!("{Bar:?}")
);
assert_eq!(
"Bar {
hello: \"world\",
..
}",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
}
}
- assert_eq!("Foo", format!("{:?}", Foo));
- assert_eq!("Foo", format!("{:#?}", Foo));
+ assert_eq!("Foo", format!("{Foo:?}"));
+ assert_eq!("Foo", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!("Foo(true)", format!("{:?}", Foo));
+ assert_eq!("Foo(true)", format!("{Foo:?}"));
assert_eq!(
"Foo(
true,
)",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("Foo(true, 10/20)", format!("{:?}", Foo));
+ assert_eq!("Foo(true, 10/20)", format!("{Foo:?}"));
assert_eq!(
"Foo(
true,
10/20,
)",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{:?}", Bar));
+ assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}"));
assert_eq!(
"Bar(
Foo(
),
\"world\",
)",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
}
}
- assert_eq!("{}", format!("{:?}", Foo));
- assert_eq!("{}", format!("{:#?}", Foo));
+ assert_eq!("{}", format!("{Foo:?}"));
+ assert_eq!("{}", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
- assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+ assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+ assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
- assert_eq!("{\"bar\": true}", format!("{:?}", Entry));
+ assert_eq!("{\"bar\": true}", format!("{Entry:?}"));
assert_eq!(
"{
\"bar\": true,
}",
- format!("{:#?}", Entry)
+ format!("{Entry:#?}")
);
}
}
}
- assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
- assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+ assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+ assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
- assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Entry));
+ assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}"));
assert_eq!(
"{
\"bar\": true,
10: 10/20,
}",
- format!("{:#?}", Entry)
+ format!("{Entry:#?}")
);
}
assert_eq!(
"{\"foo\": {\"bar\": true, 10: 10/20}, \
{\"bar\": true, 10: 10/20}: \"world\"}",
- format!("{:?}", Bar)
+ format!("{Bar:?}")
);
assert_eq!(
"{
10: 10/20,
}: \"world\",
}",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
}
- format!("{:?}", Foo);
+ format!("{Foo:?}");
}
#[test]
}
}
- format!("{:?}", Foo);
+ format!("{Foo:?}");
}
#[test]
}
}
- format!("{:?}", Foo);
+ format!("{Foo:?}");
}
}
}
}
- assert_eq!("{}", format!("{:?}", Foo));
- assert_eq!("{}", format!("{:#?}", Foo));
+ assert_eq!("{}", format!("{Foo:?}"));
+ assert_eq!("{}", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!("{true}", format!("{:?}", Foo));
+ assert_eq!("{true}", format!("{Foo:?}"));
assert_eq!(
"{
true,
}",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("{true, 10/20}", format!("{:?}", Foo));
+ assert_eq!("{true, 10/20}", format!("{Foo:?}"));
assert_eq!(
"{
true,
10/20,
}",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("{{true, 10/20}, \"world\"}", format!("{:?}", Bar));
+ assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}"));
assert_eq!(
"{
{
},
\"world\",
}",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
}
}
- assert_eq!("[]", format!("{:?}", Foo));
- assert_eq!("[]", format!("{:#?}", Foo));
+ assert_eq!("[]", format!("{Foo:?}"));
+ assert_eq!("[]", format!("{Foo:#?}"));
}
#[test]
}
}
- assert_eq!("[true]", format!("{:?}", Foo));
+ assert_eq!("[true]", format!("{Foo:?}"));
assert_eq!(
"[
true,
]",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("[true, 10/20]", format!("{:?}", Foo));
+ assert_eq!("[true, 10/20]", format!("{Foo:?}"));
assert_eq!(
"[
true,
10/20,
]",
- format!("{:#?}", Foo)
+ format!("{Foo:#?}")
);
}
}
}
- assert_eq!("[[true, 10/20], \"world\"]", format!("{:?}", Bar));
+ assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}"));
assert_eq!(
"[
[
],
\"world\",
]",
- format!("{:#?}", Bar)
+ format!("{Bar:#?}")
);
}
}
set.insert(1024);
set.insert(7);
- assert_eq!(format!("{:03?}", struct_), "Foo { bar: 1024, baz: 007 }");
- assert_eq!(format!("{:03?}", tuple), "(1024, 007)");
- assert_eq!(format!("{:03?}", list), "[1024, 007]");
- assert_eq!(format!("{:03?}", map), r#"{"bar": 1024, "baz": 007}"#);
- assert_eq!(format!("{:03?}", set), "{007, 1024}");
+ assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }");
+ assert_eq!(format!("{tuple:03?}"), "(1024, 007)");
+ assert_eq!(format!("{list:03?}"), "[1024, 007]");
+ assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#);
+ assert_eq!(format!("{set:03?}"), "{007, 1024}");
assert_eq!(
- format!("{:#03?}", struct_),
+ format!("{struct_:#03?}"),
"
Foo {
bar: 1024,
.trim()
);
assert_eq!(
- format!("{:#03?}", tuple),
+ format!("{tuple:#03?}"),
"
(
1024,
.trim()
);
assert_eq!(
- format!("{:#03?}", list),
+ format!("{list:#03?}"),
"
[
1024,
.trim()
);
assert_eq!(
- format!("{:#03?}", map),
+ format!("{map:#03?}"),
r#"
{
"bar": 1024,
.trim()
);
assert_eq!(
- format!("{:#03?}", set),
+ format!("{set:#03?}"),
"
{
007,
fn test_format_flags() {
// No residual flags left by pointer formatting
let p = "".as_ptr();
- assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p));
+ assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10"));
assert_eq!(format!("{: >3}", 'a'), " a");
}
fn test_pointer_formats_data_pointer() {
let b: &[u8] = b"";
let s: &str = "";
- assert_eq!(format!("{:p}", s), format!("{:p}", s.as_ptr()));
- assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
+ assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
+ assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
}
#[test]
}
}
- assert_eq!(format!("{:<03}", Bar), "1 0051 ");
+ assert_eq!(format!("{Bar:<03}"), "1 0051 ");
}
fn test_format_int_exp_precision() {
//test that float and integer match
let big_int: u32 = 314_159_265;
- assert_eq!(format!("{:.1e}", big_int), format!("{:.1e}", f64::from(big_int)));
+ assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
//test adding precision
assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
assert_eq!(v, Continue(vec![4, 5]));
}
+#[test]
+fn test_collect_into() {
+ let a = vec![1, 2, 3, 4, 5];
+ let mut b = Vec::new();
+ a.iter().cloned().collect_into(&mut b);
+ assert!(a == b);
+}
+
// just tests by whether or not this compiles
fn _empty_impl_all_auto_traits<T>() {
use std::panic::{RefUnwindSafe, UnwindSafe};
x.set(42).unwrap();
let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
- println!("{}", at_x); // <------- up until here ---------------------------+
+ println!("{at_x}"); // <------- up until here ---------------------------+
}
#[test]
#![feature(slice_partition_dedup)]
#![feature(int_log)]
#![feature(iter_advance_by)]
+#![feature(iter_collect_into)]
#![feature(iter_partition_in_place)]
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
for input in inputs {
assert_eq!(input.parse(), Ok(x64));
assert_eq!(input.parse(), Ok(x32));
- let neg_input = &format!("-{}", input);
+ let neg_input = &format!("-{input}");
assert_eq!(neg_input.parse(), Ok(-x64));
assert_eq!(neg_input.parse(), Ok(-x32));
}
#[test]
fn massive_exponent() {
let max = i64::MAX;
- assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
- assert_eq!(format!("1e-{}000", max).parse(), Ok(0.0));
- assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
+ assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
+ assert_eq!(format!("1e-{max}000").parse(), Ok(0.0));
+ assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
}
#[test]
assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1)));
assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101)));
let zeros = "0".repeat(25);
- let s = format!("1.5e{}", zeros);
+ let s = format!("1.5e{zeros}");
assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15)));
}
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
}
}
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
}
}
assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
- assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
+ assert!(format!("{meta:?}").starts_with("DynMetadata(0x"));
}
#[test]
let ok: Result<isize, &'static str> = Ok(100);
let err: Result<isize, &'static str> = Err("Err");
- let s = format!("{:?}", ok);
+ let s = format!("{ok:?}");
assert_eq!(s, "Ok(100)");
- let s = format!("{:?}", err);
+ let s = format!("{err:?}");
assert_eq!(s, "Err(\"Err\")");
}
fn main() {
{
let (energy_before, energy_after) = nbody::run(1000);
- println!("Energy before: {}", energy_before);
- println!("Energy after: {}", energy_after);
+ println!("Energy before: {energy_before}");
+ println!("Energy after: {energy_after}");
}
}
#![feature(rustc_allow_const_fn_unstable)]
#![feature(nll)]
#![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_fn_fn_ptr_basics)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
#![feature(allow_internal_unstable)]
#![feature(decl_macro)]
#![feature(extern_types)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn f32_unsuffixed(n: f32) -> Literal {
if !n.is_finite() {
- panic!("Invalid float literal {}", n);
+ panic!("Invalid float literal {n}");
}
let mut repr = n.to_string();
if !repr.contains('.') {
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn f32_suffixed(n: f32) -> Literal {
if !n.is_finite() {
- panic!("Invalid float literal {}", n);
+ panic!("Invalid float literal {n}");
}
Literal(bridge::client::Literal::f32(&n.to_string()))
}
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn f64_unsuffixed(n: f64) -> Literal {
if !n.is_finite() {
- panic!("Invalid float literal {}", n);
+ panic!("Invalid float literal {n}");
}
let mut repr = n.to_string();
if !repr.contains('.') {
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn f64_suffixed(n: f64) -> Literal {
if !n.is_finite() {
- panic!("Invalid float literal {}", n);
+ panic!("Invalid float literal {n}");
}
Literal(bridge::client::Literal::f64(&n.to_string()))
}
///
/// fn main() {
/// let a = Box::new(4); // Allocates from the system allocator.
-/// println!("{}", a);
+/// println!("{a}");
/// }
/// ```
///
\n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
\n]";
- assert_eq!(format!("{:#?}", backtrace), expected);
+ assert_eq!(format!("{backtrace:#?}"), expected);
// Format the backtrace a second time, just to make sure lazily resolved state is stable
- assert_eq!(format!("{:#?}", backtrace), expected);
+ assert_eq!(format!("{backtrace:#?}"), expected);
}
#[test]
let mut iter = frames.iter().zip(expected.iter());
- assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e));
+ assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
}
/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
/// for &book in &to_find {
/// match book_reviews.get(book) {
-/// Some(review) => println!("{}: {}", book, review),
-/// None => println!("{} is unreviewed.", book)
+/// Some(review) => println!("{book}: {review}"),
+/// None => println!("{book} is unreviewed.")
/// }
/// }
///
///
/// // Iterate over everything.
/// for (book, review) in &book_reviews {
-/// println!("{}: \"{}\"", book, review);
+/// println!("{book}: \"{review}\"");
/// }
/// ```
///
///
/// // Use derived implementation to print the status of the vikings.
/// for (viking, health) in &vikings {
-/// println!("{:?} has {} hp", viking, health);
+/// println!("{viking:?} has {health} hp");
/// }
/// ```
/// ]);
///
/// for key in map.keys() {
- /// println!("{}", key);
+ /// println!("{key}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// ]);
///
/// for val in map.values() {
- /// println!("{}", val);
+ /// println!("{val}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// }
///
/// for val in map.values() {
- /// println!("{}", val);
+ /// println!("{val}");
/// }
/// ```
#[stable(feature = "map_values_mut", since = "1.10.0")]
/// ]);
///
/// for (key, val) in map.iter() {
- /// println!("key: {} val: {}", key, val);
+ /// println!("key: {key} val: {val}");
/// }
/// ```
#[rustc_lint_query_instability]
/// }
///
/// for (key, val) in &map {
- /// println!("key: {} val: {}", key, val);
+ /// println!("key: {key} val: {val}");
/// }
/// ```
#[rustc_lint_query_instability]
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+ /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
/// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
map.insert(1, 2);
map.insert(3, 4);
- let map_str = format!("{:?}", map);
+ let map_str = format!("{map:?}");
assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
- assert_eq!(format!("{:?}", empty), "{}");
+ assert_eq!(format!("{empty:?}"), "{}");
}
#[test]
// Test for #19292
fn check(m: &HashMap<i32, ()>) {
for k in m.keys() {
- assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+ assert!(m.contains_key(k), "{k} is in keys() but not in the map?");
}
}
///
/// // Iterate over everything.
/// for book in &books {
-/// println!("{}", book);
+/// println!("{book}");
/// }
/// ```
///
///
/// // Use derived implementation to print the vikings.
/// for x in &vikings {
-/// println!("{:?}", x);
+/// println!("{x:?}");
/// }
/// ```
///
///
/// // Will print in an arbitrary order.
/// for x in set.iter() {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[inline]
///
/// // print 1, 2, 3 in an arbitrary order
/// for i in set.drain() {
- /// println!("{}", i);
+ /// println!("{i}");
/// }
///
/// assert!(set.is_empty());
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
/// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
///
/// // Can be seen as `a - b`.
/// for x in a.difference(&b) {
- /// println!("{}", x); // Print 1
+ /// println!("{x}"); // Print 1
/// }
///
/// let diff: HashSet<_> = a.difference(&b).collect();
///
/// // Print 1, 4 in arbitrary order.
/// for x in a.symmetric_difference(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
///
/// // Print 2, 3 in arbitrary order.
/// for x in a.intersection(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let intersection: HashSet<_> = a.intersection(&b).collect();
///
/// // Print 1, 2, 3, 4 in arbitrary order.
/// for x in a.union(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let union: HashSet<_> = a.union(&b).collect();
///
/// // Will print in an arbitrary order.
/// for x in &v {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[inline]
set.insert(1);
set.insert(2);
- let set_str = format!("{:?}", set);
+ let set_str = format!("{set:?}");
assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
- assert_eq!(format!("{:?}", empty), "{}");
+ assert_eq!(format!("{empty:?}"), "{}");
}
#[test]
//! ```
//! let vec = vec![1, 2, 3, 4];
//! for x in vec.iter() {
-//! println!("vec contained {}", x);
+//! println!("vec contained {x:?}");
//! }
//! ```
//!
//! ```
//! let vec = vec![1, 2, 3, 4];
//! for x in vec.iter().rev() {
-//! println!("vec contained {}", x);
+//! println!("vec contained {x:?}");
//! }
//! ```
//!
//!
//! println!("Number of occurrences of each character");
//! for (char, count) in &count {
-//! println!("{}: {}", char, count);
+//! println!("{char}: {count}");
//! }
//! ```
//!
//! // Check if they're sober enough to have another beer.
//! if person.blood_alcohol > 0.3 {
//! // Too drunk... for now.
-//! println!("Sorry {}, I have to cut you off", id);
+//! println!("Sorry {id}, I have to cut you off");
//! } else {
//! // Have another!
//! person.blood_alcohol += 0.1;
/// // We will iterate through the references to the element returned by
/// // env::vars();
/// for (key, value) in env::vars() {
-/// println!("{}: {}", key, value);
+/// println!("{key}: {value}");
/// }
/// ```
///
/// // We will iterate through the references to the element returned by
/// // env::vars_os();
/// for (key, value) in env::vars_os() {
-/// println!("{:?}: {:?}", key, value);
+/// println!("{key:?}: {value:?}");
/// }
/// ```
#[must_use]
///
/// let key = "HOME";
/// match env::var(key) {
-/// Ok(val) => println!("{}: {:?}", key, val),
-/// Err(e) => println!("couldn't interpret {}: {}", key, e),
+/// Ok(val) => println!("{key}: {val:?}"),
+/// Err(e) => println!("couldn't interpret {key}: {e}"),
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
///
/// let key = "HOME";
/// match env::var_os(key) {
-/// Some(val) => println!("{}: {:?}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
+/// Some(val) => println!("{key}: {val:?}"),
+/// None => println!("{key} is not defined in the environment.")
/// }
/// ```
#[must_use]
fn _set_var(key: &OsStr, value: &OsStr) {
os_imp::setenv(key, value).unwrap_or_else(|e| {
- panic!("failed to set environment variable `{:?}` to `{:?}`: {}", key, value, e)
+ panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
})
}
fn _remove_var(key: &OsStr) {
os_imp::unsetenv(key)
- .unwrap_or_else(|e| panic!("failed to remove environment variable `{:?}`: {}", key, e))
+ .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
}
/// An iterator that splits an environment variable into paths according to
/// println!("'{}'", path.display());
/// }
/// }
-/// None => println!("{} is not defined in the environment.", key)
+/// None => println!("{key} is not defined in the environment.")
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
/// match env::current_exe() {
/// Ok(exe_path) => println!("Path of this executable is: {}",
/// exe_path.display()),
-/// Err(e) => println!("failed to get current exe path: {}", e),
+/// Err(e) => println!("failed to get current exe path: {e}"),
/// };
/// ```
#[stable(feature = "env", since = "1.0.0")]
///
/// // Prints each argument on a separate line
/// for argument in env::args() {
-/// println!("{}", argument);
+/// println!("{argument}");
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
///
/// // Prints each argument on a separate line
/// for argument in env::args_os() {
-/// println!("{:?}", argument);
+/// println!("{argument:?}");
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
/// fn main() {
/// match get_super_error() {
/// Err(e) => {
- /// println!("Error: {}", e);
+ /// println!("Error: {e}");
/// println!("Caused by: {}", e.source().unwrap());
/// }
/// _ => println!("No error"),
/// ```
/// if let Err(e) = "xc".parse::<u32>() {
/// // Print `e` itself, no need for description().
- /// eprintln!("Error: {}", e);
+ /// eprintln!("Error: {e}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
///
/// let error = SuperError { source: SuperErrorSideKick };
/// let report = Report::new(error).pretty(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces the following output:
/// let source = SuperErrorSideKick { source };
/// let error = SuperError { source };
/// let report = Report::new(error).pretty(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces the following output:
/// let source = SuperErrorSideKick::new();
/// let error = SuperError { source };
/// let report = Report::new(error).pretty(true).show_backtrace(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces something similar to the following output:
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
for cause in sources {
- write!(f, ": {}", cause)?;
+ write!(f, ": {cause}")?;
}
Ok(())
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let error = &self.error;
- write!(f, "{}", error)?;
+ write!(f, "{error}")?;
if let Some(cause) = error.source() {
write!(f, "\n\nCaused by:")?;
writeln!(f)?;
let mut indented = Indented { inner: f };
if multiple {
- write!(indented, "{: >4}: {}", ind, error)?;
+ write!(indented, "{ind: >4}: {error}")?;
} else {
- write!(indented, " {}", error)?;
+ write!(indented, " {error}")?;
}
}
}
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
for cause in sources {
- write!(f, ": {}", cause)?;
+ write!(f, ": {cause}")?;
}
Ok(())
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let error = &self.error;
- write!(f, "{}", error)?;
+ write!(f, "{error}")?;
if let Some(cause) = error.source() {
write!(f, "\n\nCaused by:")?;
writeln!(f)?;
let mut indented = Indented { inner: f };
if multiple {
- write!(indented, "{: >4}: {}", ind, error)?;
+ write!(indented, "{ind: >4}: {error}")?;
} else {
- write!(indented, " {}", error)?;
+ write!(indented, " {error}")?;
}
}
}
error.backtrace = Some(trace);
let report = Report::new(error).pretty(true).show_backtrace(true);
- println!("Error: {}", report);
+ println!("Error: {report}");
assert_eq!(expected.trim_end(), report.to_string());
}
let error = GenericError::new_with_source("Error with two sources", error);
let report = Report::new(error).pretty(true).show_backtrace(true);
- println!("Error: {}", report);
+ println!("Error: {report}");
assert_eq!(expected.trim_end(), report.to_string());
}
1: The message goes on and on.";
let actual = report.to_string();
- println!("{}", actual);
+ println!("{actual}");
assert_eq!(expected, actual);
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.description())?;
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
- write!(f, " at byte pos {}", pos)?;
+ write!(f, " at byte pos {pos}")?;
}
Ok(())
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.error_kind {
FromBytesWithNulErrorKind::InteriorNul(pos) => {
- write!(f, "data provided contains an interior nul byte at pos {}", pos)
+ write!(f, "data provided contains an interior nul byte at pos {pos}")
}
FromBytesWithNulErrorKind::NotNulTerminated => {
write!(f, "data provided is not nul terminated")
#[test]
fn formatted() {
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
- assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+ assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}
#[test]
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.modified() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform");
/// }
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.accessed() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform");
/// }
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.created() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform or filesystem");
/// }
use crate::io::prelude::*;
+use crate::env;
use crate::fs::{self, File, OpenOptions};
use crate::io::{ErrorKind, SeekFrom};
use crate::path::Path;
($e:expr) => {
match $e {
Ok(t) => t,
- Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ Err(e) => panic!("{} failed with: {e}", stringify!($e)),
}
};
}
check!(fs::create_dir(dir));
let prefix = "foo";
for n in 0..3 {
- let f = dir.join(&format!("{}.txt", n));
+ let f = dir.join(&format!("{n}.txt"));
let mut w = check!(File::create(&f));
let msg_str = format!("{}{}", prefix, n.to_string());
let msg = msg_str.as_bytes();
// junction
assert_eq!(check!(fs::read_link(r"C:\Users\Default User")), Path::new(r"C:\Users\Default"));
// junction with special permissions
- assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")), Path::new(r"C:\Users"));
+ // Since not all localized windows versions contain the folder "Documents and Settings" in english,
+ // we will briefly check, if it exists and otherwise skip the test. Except during CI we will always execute the test.
+ if Path::new(r"C:\Documents and Settings\").exists() || env::var_os("CI").is_some() {
+ assert_eq!(
+ check!(fs::read_link(r"C:\Documents and Settings\")),
+ Path::new(r"C:\Users")
+ );
+ }
}
let tmpdir = tmpdir();
let link = tmpdir.join("link");
assert!(file.file_type().unwrap().is_file());
assert!(file.metadata().unwrap().is_file());
}
- f => panic!("unknown file name: {:?}", f),
+ f => panic!("unknown file name: {f:?}"),
}
}
}
File::create(&tmpdir.join("b")).unwrap();
let mut read_dir = tmpdir.path().read_dir().unwrap();
let dir_entry = read_dir.next().unwrap().unwrap();
- let actual = format!("{:?}", dir_entry);
+ let actual = format!("{dir_entry:?}");
let expected = format!("DirEntry({:?})", dir_entry.0.path());
assert_eq!(actual, expected);
}
|| e1.kind() == ErrorKind::Unsupported
&& e2.kind() == ErrorKind::Unsupported => {}
(a, b) => {
- panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
+ panic!("creation time must be always supported or not supported: {a:?} {b:?}")
}
}
}
///
/// let mut line = String::new();
/// let len = reader.read_line(&mut line)?;
-/// println!("First line is {} bytes long", len);
+/// println!("First line is {len} bytes long");
/// Ok(())
/// }
/// ```
///
/// let not_found = ErrorKind::NotFound;
/// let error = Error::from(not_found);
- /// assert_eq!("entity not found", format!("{}", error));
+ /// assert_eq!("entity not found", format!("{error}"));
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
/// use std::io::Error;
///
/// let os_error = Error::last_os_error();
- /// println!("last OS error: {:?}", os_error);
+ /// println!("last OS error: {os_error:?}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
///
/// fn print_os_error(err: &Error) {
/// if let Some(raw_os_err) = err.raw_os_error() {
- /// println!("raw OS error: {:?}", raw_os_err);
+ /// println!("raw OS error: {raw_os_err:?}");
/// } else {
/// println!("Not an OS error");
/// }
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
- /// println!("Inner error: {:?}", inner_err);
+ /// println!("Inner error: {inner_err:?}");
/// } else {
/// println!("No inner error");
/// }
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
- /// println!("Inner error: {}", inner_err);
+ /// println!("Inner error: {inner_err}");
/// } else {
/// println!("No inner error");
/// }
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
- /// println!("Inner error: {}", inner_err);
+ /// println!("Inner error: {inner_err}");
/// } else {
/// println!("No inner error");
/// }
match self.repr.data() {
ErrorData::Os(code) => {
let detail = sys::os::error_string(code);
- write!(fmt, "{} (os error {})", detail, code)
+ write!(fmt, "{detail} (os error {code})")
}
ErrorData::Custom(ref c) => c.error.fmt(fmt),
ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
// only run in libstd's tests, unless the user uses -Zbuild-std)
debug_assert!(
matches!(res.data(), ErrorData::Os(c) if c == code),
- "repr(os) encoding failed for {}",
- code,
+ "repr(os) encoding failed for {code}"
);
res
}
}}",
code, kind, msg
);
- assert_eq!(format!("{:?}", err), expected);
+ assert_eq!(format!("{err:?}"), expected);
}
#[test]
assert_eq!(E.kind(), ErrorKind::NotFound);
assert_eq!(E.to_string(), "hello");
- assert!(format!("{:?}", E).contains("\"hello\""));
- assert!(format!("{:?}", E).contains("NotFound"));
+ assert!(format!("{E:?}").contains("\"hello\""));
+ assert!(format!("{E:?}").contains("NotFound"));
}
#[test]
let e = &$err;
// Check that the public api is right.
assert_eq!(e.kind(), $kind);
- assert!(format!("{:?}", e).contains($msg));
+ assert!(format!("{e:?}").contains($msg));
// and we got what we expected
assert_matches!(
e.repr.data(),
//! // read a line into buffer
//! reader.read_line(&mut buffer)?;
//!
-//! println!("{}", buffer);
+//! println!("{buffer}");
//! Ok(())
//! }
//! ```
/// fn main() -> io::Result<()> {
/// let stdin = io::read_to_string(io::stdin())?;
/// println!("Stdin was:");
-/// println!("{}", stdin);
+/// println!("{stdin}");
/// Ok(())
/// }
/// ```
/// .open("foo.txt").unwrap();
///
/// let hello = "Hello!\n";
- /// write!(f, "{}", hello).unwrap();
+ /// write!(f, "{hello}").unwrap();
/// f.rewind().unwrap();
///
/// let mut buf = String::new();
/// let mut f = File::open("foo.txt")?;
///
/// let len = f.stream_len()?;
- /// println!("The file is currently {} bytes long", len);
+ /// println!("The file is currently {len} bytes long");
/// Ok(())
/// }
/// ```
/// let buffer = stdin.fill_buf().unwrap();
///
/// // work with buffer
- /// println!("{:?}", buffer);
+ /// println!("{buffer:?}");
///
/// // ensure the bytes we worked with aren't returned again later
/// let length = buffer.len();
/// let mut line = String::new();
/// stdin.read_line(&mut line).unwrap();
/// // work with line
- /// println!("{:?}", line);
+ /// println!("{line:?}");
/// }
/// ```
#[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")]
/// let mut input = String::new();
/// match io::stdin().read_line(&mut input) {
/// Ok(n) => {
- /// println!("{} bytes read", n);
- /// println!("{}", input);
+ /// println!("{n} bytes read");
+ /// println!("{input}");
/// }
- /// Err(error) => println!("error: {}", error),
+ /// Err(error) => println!("error: {error}"),
/// }
/// ```
///
}
if let Err(e) = global_s().write_fmt(args) {
- panic!("failed printing to {}: {}", label, e);
+ panic!("failed printing to {label}: {e}");
}
}
/// }
///
/// assert_eq!(last, 12);
-/// println!("{}", last);
+/// println!("{last}");
/// ```
///
/// A break expression is normally associated with the innermost loop enclosing the
///
///```rust
/// 'outer: for i in 1..=5 {
-/// println!("outer iteration (i): {}", i);
+/// println!("outer iteration (i): {i}");
///
/// '_inner: for j in 1..=200 {
-/// println!(" inner iteration (j): {}", j);
+/// println!(" inner iteration (j): {j}");
/// if j >= 3 {
/// // breaks from inner loop, lets outer loop continue.
/// break;
/// };
/// // first number in Fibonacci sequence over 10:
/// assert_eq!(result, 13);
-/// println!("{}", result);
+/// println!("{result}");
/// ```
///
/// For more details consult the [Reference on "break expression"] and the [Reference on "break and
/// if number % 2 == 0 {
/// continue;
/// }
-/// println!("{}", number);
+/// println!("{number}");
/// }
///```
///
/// }
///
/// for i in std::iter::repeat(5) {
-/// println!("turns out {} never stops being 5", i);
+/// println!("turns out {i} never stops being 5");
/// break; // would loop forever otherwise
/// }
///
/// let shadowing_example = true;
/// let shadowing_example = 123.4;
/// let shadowing_example = shadowing_example as u32;
-/// let mut shadowing_example = format!("cool! {}", shadowing_example);
+/// let mut shadowing_example = format!("cool! {shadowing_example}");
/// shadowing_example += " something else!"; // not shadowing
/// ```
///
/// let mut counter = 0;
///
/// while counter < 10 {
-/// println!("{}", counter);
+/// println!("{counter}");
/// counter += 1;
/// }
/// ```
/// if i == 10 {
/// counter = None;
/// } else {
-/// println!("{}", i);
+/// println!("{i}");
/// counter = Some (i + 1);
/// }
/// }
///
/// let mut i = 1;
/// loop {
-/// println!("i is {}", i);
+/// println!("i is {i}");
/// if i > 100 {
/// break;
/// }
///
/// let a_number = Option::Some(10);
/// match a_number {
-/// Some(x) if x <= 5 => println!("0 to 5 num = {}", x),
-/// Some(x @ 6..=10) => println!("6 to 10 num = {}", x),
+/// Some(x) if x <= 5 => println!("0 to 5 num = {x}"),
+/// Some(x @ 6..=10) => println!("6 to 10 num = {x}"),
/// None => panic!(),
/// // all other numbers
/// _ => panic!(),
///
/// let get_inner = Outer::Double(None, Some(String::new()));
/// match get_inner {
-/// Outer::Double(None, Some(st)) => println!("{}", st),
-/// Outer::Single(opt) => println!("{:?}", opt),
+/// Outer::Double(None, Some(st)) => println!("{st}"),
+/// Outer::Single(opt) => println!("{opt:?}"),
/// _ => panic!(),
/// }
/// ```
///
/// ```rust
/// let data = vec![1, 2, 3];
-/// let closure = move || println!("captured {:?} by value", data);
+/// let closure = move || println!("captured {data:?} by value");
///
/// // data is no longer available, it is owned by the closure
/// ```
/// ```rust
/// fn create_fn() -> impl Fn() {
/// let text = "Fn".to_owned();
-/// move || println!("This is a: {}", text)
+/// move || println!("This is a: {text}")
/// }
///
/// let fn_plain = create_fn();
/// let data = vec![1, 2, 3];
///
/// std::thread::spawn(move || {
-/// println!("captured {:?} by value", data)
+/// println!("captured {data:?} by value")
/// }).join().unwrap();
///
/// // data was moved to the spawned thread, so we cannot use it here
/// ```rust
/// let capture = "hello".to_owned();
/// let block = async move {
-/// println!("rust says {} from async block", capture);
+/// println!("rust says {capture} from async block");
/// };
/// ```
///
/// let maybe_name = Some(String::from("Alice"));
/// // The variable 'maybe_name' is consumed here ...
/// match maybe_name {
-/// Some(n) => println!("Hello, {}", n),
+/// Some(n) => println!("Hello, {n}"),
/// _ => println!("Hello, world"),
/// }
/// // ... and is now unavailable.
/// let maybe_name = Some(String::from("Alice"));
/// // Using `ref`, the value is borrowed, not moved ...
/// match maybe_name {
-/// Some(ref n) => println!("Hello, {}", n),
+/// Some(ref n) => println!("Hello, {n}"),
/// _ => println!("Hello, world"),
/// }
/// // ... so it's available here!
/// // With a strictly read-only static, references will have the same address
/// assert_eq!(r1, r2);
/// // A static item can be used just like a variable in many cases
-/// println!("{:?}", FOO);
+/// println!("{FOO:?}");
/// ```
///
/// # Mutable `static`s
/// # #![allow(dead_code)]
/// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
/// for elem in it {
-/// println!("{:#?}", elem);
+/// println!("{elem:#?}");
/// }
/// }
///
/// match u {
/// IntOrFloat { i: 10 } => println!("Found exactly ten!"),
/// // Matching the field `f` provides an `f32`.
-/// IntOrFloat { f } => println!("Found f = {} !", f),
+/// IntOrFloat { f } => println!("Found f = {f} !"),
/// }
/// }
/// ```
/// let i = unsafe { &mut u.i };
///
/// *i = 10;
-/// println!("f = {} and i = {}", f, i);
+/// println!("f = {f} and i = {i}");
/// ```
///
/// See the [Reference][union] for more informations on `union`s.
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(async_iterator)]
+#![feature(atomic_mut_ptr)]
#![feature(bench_black_box)]
#![feature(box_syntax)]
#![feature(c_unwind)]
#![feature(char_internals)]
#![feature(concat_bytes)]
#![feature(concat_idents)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
#![feature(const_format_args)]
#![feature(const_io_structs)]
#![feature(const_ip)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(rustdoc_internals)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
#[macro_use]
mod macros;
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+#[macro_use]
+pub mod rt;
+
// The Rust prelude
pub mod prelude;
#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
#[allow(rustdoc::bare_urls)]
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
mod std_float;
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
#[unstable(feature = "portable_simd", issue = "86656")]
pub mod simd {
#[stable(feature = "simd_x86", since = "1.27.0")]
pub use std_detect::is_x86_feature_detected;
-// The runtime entry point and a few unstable public functions used by the
-// compiler
-#[macro_use]
-pub mod rt;
-
// Platform-abstraction modules
mod sys;
mod sys_common;
fn socket_v4_to_str() {
let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
- assert_eq!(format!("{}", socket), "192.168.0.1:8080");
- assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 ");
- assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080");
- assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 ");
- assert_eq!(format!("{:.10}", socket), "192.168.0.");
+ assert_eq!(format!("{socket}"), "192.168.0.1:8080");
+ assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 ");
+ assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080");
+ assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 ");
+ assert_eq!(format!("{socket:.10}"), "192.168.0.");
}
#[test]
fn socket_v6_to_str() {
let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0);
- assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
- assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 ");
- assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53");
- assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 ");
- assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+ assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53");
+ assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 ");
+ assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53");
+ assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 ");
+ assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::");
socket.set_scope_id(5);
- assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1%5]:53");
- assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53 ");
- assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1%5]:53");
- assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 ");
- assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%5");
+ assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53");
+ assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 ");
+ assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53");
+ assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 ");
+ assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5");
}
#[test]
/// // via platform-specific APIs such as epoll or IOCP
/// wait_for_fd();
/// }
- /// Err(e) => panic!("encountered IO error: {}", e),
+ /// Err(e) => panic!("encountered IO error: {e}"),
/// };
/// };
- /// println!("bytes: {:?}", buf);
+ /// println!("bytes: {buf:?}");
/// ```
#[stable(feature = "net2_mutators", since = "1.9.0")]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
///
/// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
/// match listener.accept() {
- /// Ok((_socket, addr)) => println!("new client: {:?}", addr),
- /// Err(e) => println!("couldn't get client: {:?}", e),
+ /// Ok((_socket, addr)) => println!("new client: {addr:?}"),
+ /// Err(e) => println!("couldn't get client: {e:?}"),
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// wait_for_fd();
/// continue;
/// }
- /// Err(e) => panic!("encountered IO error: {}", e),
+ /// Err(e) => panic!("encountered IO error: {e}"),
/// }
/// }
/// ```
e.kind() == ErrorKind::ConnectionReset
|| e.kind() == ErrorKind::BrokenPipe
|| e.kind() == ErrorKind::ConnectionAborted,
- "unknown error: {}",
- e
+ "unknown error: {e}"
);
}
}
}
#[test]
-#[cfg(unix)] // test doesn't work on Windows, see #31657
+#[cfg_attr(target_env = "sgx", ignore)]
fn close_read_wakes_up() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
inner_name,
render_inner(&listener)
);
- assert_eq!(format!("{:?}", listener), compare);
+ assert_eq!(format!("{listener:?}"), compare);
let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
let compare = format!(
inner_name,
render_inner(&stream)
);
- assert_eq!(format!("{:?}", stream), compare);
+ assert_eq!(format!("{stream:?}"), compare);
}
// FIXME: re-enabled openbsd tests once their socket timeout code
match stream.read(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
}
}
match c.peek(&mut b) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
}
t!(txdone.send(()));
})
///
/// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
/// match socket.take_error() {
- /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+ /// Ok(Some(error)) => println!("UdpSocket error: {error:?}"),
/// Ok(None) => println!("No error"),
- /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+ /// Err(error) => println!("UdpSocket.take_error failed: {error:?}"),
/// }
/// ```
#[stable(feature = "net2_mutators", since = "1.9.0")]
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// let mut buf = [0; 10];
/// match socket.recv(&mut buf) {
- /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
- /// Err(e) => println!("recv function failed: {:?}", e),
+ /// Ok(received) => println!("received {received} bytes {:?}", &buf[..received]),
+ /// Err(e) => println!("recv function failed: {e:?}"),
/// }
/// ```
#[stable(feature = "net2_mutators", since = "1.9.0")]
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// let mut buf = [0; 10];
/// match socket.peek(&mut buf) {
- /// Ok(received) => println!("received {} bytes", received),
- /// Err(e) => println!("peek function failed: {:?}", e),
+ /// Ok(received) => println!("received {received} bytes"),
+ /// Err(e) => println!("peek function failed: {e:?}"),
/// }
/// ```
#[stable(feature = "peek", since = "1.18.0")]
/// // via platform-specific APIs such as epoll or IOCP
/// wait_for_fd();
/// }
- /// Err(e) => panic!("encountered IO error: {}", e),
+ /// Err(e) => panic!("encountered IO error: {e}"),
/// }
/// };
/// println!("bytes: {:?}", &buf[..num_bytes_read]);
let udpsock = t!(UdpSocket::bind(&socket_addr));
let udpsock_inner = udpsock.0.socket().as_raw();
- let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
- assert_eq!(format!("{:?}", udpsock), compare);
+ let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}");
+ assert_eq!(format!("{udpsock:?}"), compare);
}
// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
match socket.recv(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
}
})
}
///
/// // We now read 8 bytes from the offset 10.
/// let num_bytes_read = file.read_at(&mut buf, 10)?;
- /// println!("read {} bytes: {:?}", num_bytes_read, buf);
+ /// println!("read {num_bytes_read} bytes: {buf:?}");
/// Ok(())
/// }
/// ```
/// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
///
/// for p in entries {
- /// println!("{:?}", p);
+ /// println!("{p:?}");
/// }
///
/// Ok(())
/// let socket = match UnixListener::bind("/tmp/sock") {
/// Ok(sock) => sock,
/// Err(e) => {
-/// println!("Couldn't bind: {:?}", e);
+/// println!("Couldn't bind: {e:?}");
/// return
/// }
/// };
/// # Examples
///
/// ```
- /// #![feature(unix_socket_creation)]
/// use std::os::unix::net::SocketAddr;
/// use std::path::Path;
///
/// # fn main() -> std::io::Result<()> {
- /// let address = SocketAddr::from_path("/path/to/socket")?;
+ /// let address = SocketAddr::from_pathname("/path/to/socket")?;
/// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
/// # Ok(())
/// # }
/// Creating a `SocketAddr` with a NULL byte results in an error.
///
/// ```
- /// #![feature(unix_socket_creation)]
/// use std::os::unix::net::SocketAddr;
///
- /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+ /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
/// ```
- #[unstable(feature = "unix_socket_creation", issue = "93423")]
- pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+ #[stable(feature = "unix_socket_creation", since = "1.61.0")]
+ pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
where
P: AsRef<Path>,
{
/// let listener = match UnixListener::bind_addr(&addr) {
/// Ok(sock) => sock,
/// Err(err) => {
- /// println!("Couldn't bind: {:?}", err);
+ /// println!("Couldn't bind: {err:?}");
/// return Err(err);
/// }
/// };
match self.address() {
AddressKind::Unnamed => write!(fmt, "(unnamed)"),
AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
- AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+ AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
}
}
}
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
-/// println!("receive file descriptor: {}", fd);
+/// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
- /// println!("receive file descriptor: {}", fd);
+ /// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
- /// println!("receive file descriptor: {}", fd);
+ /// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
/// let sock = match UnixDatagram::bind("/path/to/the/socket") {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't bind: {:?}", e);
+ /// println!("Couldn't bind: {e:?}");
/// return
/// }
/// };
/// let sock2 = match UnixDatagram::bind_addr(&addr) {
/// Ok(sock) => sock,
/// Err(err) => {
- /// println!("Couldn't bind: {:?}", err);
+ /// println!("Couldn't bind: {err:?}");
/// return Err(err);
/// }
/// };
/// let sock = match UnixDatagram::unbound() {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't unbound: {:?}", e);
+ /// println!("Couldn't unbound: {e:?}");
/// return
/// }
/// };
/// let (sock1, sock2) = match UnixDatagram::pair() {
/// Ok((sock1, sock2)) => (sock1, sock2),
/// Err(e) => {
- /// println!("Couldn't unbound: {:?}", e);
+ /// println!("Couldn't unbound: {e:?}");
/// return
/// }
/// };
/// match sock.connect("/path/to/the/socket") {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
+ /// println!("Couldn't connect: {e:?}");
/// return Err(e)
/// }
/// };
/// match sock.connect_addr(&addr) {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
+ /// println!("Couldn't connect: {e:?}");
/// return Err(e)
/// }
/// };
/// let sock = UnixDatagram::unbound()?;
/// let mut buf = vec![0; 10];
/// let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
- /// println!("received {} bytes from {:?}", size, sender);
+ /// println!("received {size} bytes from {sender:?}");
/// Ok(())
/// }
/// ```
/// let mut ancillary_buffer = [0; 128];
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
/// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
- /// println!("received {}", size);
+ /// println!("received {size}");
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
- /// println!("receive file descriptor: {}", fd);
+ /// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
/// let mut ancillary_buffer = [0; 128];
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
/// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
- /// println!("received {}", size);
+ /// println!("received {size}");
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
- /// println!("receive file descriptor: {}", fd);
+ /// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
/// fn main() -> std::io::Result<()> {
/// let sock = UnixDatagram::unbound()?;
/// if let Ok(Some(err)) = sock.take_error() {
- /// println!("Got error: {:?}", err);
+ /// println!("Got error: {err:?}");
/// }
/// Ok(())
/// }
/// let listener = match UnixListener::bind("/path/to/the/socket") {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
+ /// println!("Couldn't connect: {e:?}");
/// return
/// }
/// };
/// let listener2 = match UnixListener::bind_addr(&addr) {
/// Ok(sock) => sock,
/// Err(err) => {
- /// println!("Couldn't bind: {:?}", err);
+ /// println!("Couldn't bind: {err:?}");
/// return Err(err);
/// }
/// };
/// let listener = UnixListener::bind("/path/to/the/socket")?;
///
/// match listener.accept() {
- /// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
- /// Err(e) => println!("accept function failed: {:?}", e),
+ /// Ok((socket, addr)) => println!("Got a client: {addr:?}"),
+ /// Err(e) => println!("accept function failed: {e:?}"),
/// }
/// Ok(())
/// }
/// let listener = UnixListener::bind("/tmp/sock")?;
///
/// if let Ok(Some(err)) = listener.take_error() {
- /// println!("Got error: {:?}", err);
+ /// println!("Got error: {err:?}");
/// }
/// Ok(())
/// }
/// stream.write_all(b"hello world")?;
/// let mut response = String::new();
/// stream.read_to_string(&mut response)?;
-/// println!("{}", response);
+/// println!("{response}");
/// Ok(())
/// }
/// ```
/// let socket = match UnixStream::connect("/tmp/sock") {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
+ /// println!("Couldn't connect: {e:?}");
/// return
/// }
/// };
/// let sock = match UnixStream::connect_addr(&addr) {
/// Ok(sock) => sock,
/// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
+ /// println!("Couldn't connect: {e:?}");
/// return Err(e)
/// }
/// };
/// let (sock1, sock2) = match UnixStream::pair() {
/// Ok((sock1, sock2)) => (sock1, sock2),
/// Err(e) => {
- /// println!("Couldn't create a pair of sockets: {:?}", e);
+ /// println!("Couldn't create a pair of sockets: {e:?}");
/// return
/// }
/// };
/// fn main() -> std::io::Result<()> {
/// let socket = UnixStream::connect("/tmp/sock")?;
/// if let Ok(Some(err)) = socket.take_error() {
- /// println!("Got error: {:?}", err);
+ /// println!("Got error: {err:?}");
/// }
/// Ok(())
/// }
/// let mut ancillary_buffer = [0; 128];
/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
/// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
- /// println!("received {}", size);
+ /// println!("received {size}");
/// for ancillary_result in ancillary.messages() {
/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
/// for fd in scm_rights {
- /// println!("receive file descriptor: {}", fd);
+ /// println!("receive file descriptor: {fd}");
/// }
/// }
/// }
($e:expr) => {
match $e {
Ok(e) => e,
- Err(e) => panic!("{}", e),
+ Err(e) => panic!("{e}"),
}
};
}
);
match UnixStream::connect(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
Ok(_) => panic!("unexpected success"),
}
match UnixListener::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
Ok(_) => panic!("unexpected success"),
}
match UnixDatagram::bind(&socket_path) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
Ok(_) => panic!("unexpected success"),
}
}
jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
) {
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
+ Err(e) => panic!("unexpected error {e}"),
Ok(_) => panic!("unexpected success"),
}
}
match stream.peek(&mut buf) {
Ok(_) => panic!("expected error"),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
- Err(e) => panic!("unexpected error: {}", e),
+ Err(e) => panic!("unexpected error: {e}"),
}
or_panic!(txdone.send(()));
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
let write = |err: &mut dyn crate::io::Write| {
- let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location);
+ let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
// Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here.
let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
- rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
+ rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
}
crate::sys::abort_internal();
}
let obj = &mut msg as *mut &mut dyn BoxMeUp;
__rust_start_panic(obj)
};
- rtabort!("failed to initiate panic, error {}", code)
+ rtabort!("failed to initiate panic, error {code}")
}
/// let path = Path::new("/tmp/foo/bar.txt");
///
/// for component in path.components() {
-/// println!("{:?}", component);
+/// println!("{component:?}");
/// }
/// ```
///
let mut components = path.components();
let expected = "Components([RootDir, Normal(\"tmp\")])";
- let actual = format!("{:?}", components);
+ let actual = format!("{components:?}");
assert_eq!(expected, actual);
let _ = components.next().unwrap();
let expected = "Components([Normal(\"tmp\")])";
- let actual = format!("{:?}", components);
+ let actual = format!("{components:?}");
assert_eq!(expected, actual);
let _ = components.next().unwrap();
let expected = "Components([])";
- let actual = format!("{:?}", components);
+ let actual = format!("{components:?}");
assert_eq!(expected, actual);
}
let mut iter = path.iter();
let expected = "Iter([\"/\", \"tmp\"])";
- let actual = format!("{:?}", iter);
+ let actual = format!("{iter:?}");
assert_eq!(expected, actual);
let _ = iter.next().unwrap();
let expected = "Iter([\"tmp\"])";
- let actual = format!("{:?}", iter);
+ let actual = format!("{iter:?}");
assert_eq!(expected, actual);
let _ = iter.next().unwrap();
let expected = "Iter([])";
- let actual = format!("{:?}", iter);
+ let actual = format!("{iter:?}");
assert_eq!(expected, actual);
}
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
let prefix = "my/home";
let mut paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
paths.sort();
fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
let mut set = BTreeSet::new();
fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
let prefix = "my/home";
let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
let mut set = BTreeSet::new();
fn bench_path_hashset(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
let mut set = HashSet::new();
fn bench_path_hashset_miss(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
let mut set = HashSet::new();
///
/// // This loop prints: 0 1 2
/// for x in array {
-/// print!("{} ", x);
+/// print!("{x} ");
/// }
/// ```
///
/// // This creates a slice iterator, producing references to each value.
/// for item in array.into_iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // The `array_into_iter` lint suggests this change for future compatibility:
/// for item in array.iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
/// // This iterates by reference:
/// for item in array.iter().enumerate() {
/// let (i, x): (usize, &i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
///
/// // This iterates by value:
/// for item in array.into_iter().enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
/// // This iterates by reference:
/// for item in array.iter() {
/// let x: &i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // This iterates by value:
/// for item in IntoIterator::into_iter(array) {
/// let x: i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // This iterates by value:
/// for item in array {
/// let x: i32 = item;
-/// println!("{}", x);
+/// println!("{x}");
/// }
///
/// // IntoIter can also start a chain.
/// // This iterates by value:
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
-/// println!("array[{}] = {}", i, x);
+/// println!("array[{i}] = {x}");
/// }
/// ```
///
/// .status()
/// .expect("failed to execute process");
///
- /// println!("process finished with: {}", status);
+ /// println!("process finished with: {status}");
///
/// assert!(status.success());
/// ```
/// .status()
/// .expect("ls could not be executed");
///
- /// println!("ls: {}", status);
+ /// println!("ls: {status}");
/// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
/// # } // cfg!(unix)
/// ```
/// if status.success() {
/// println!("'projects/' directory created");
/// } else {
- /// println!("failed to create 'projects/' directory: {}", status);
+ /// println!("failed to create 'projects/' directory: {status}");
/// }
/// ```
#[must_use]
/// .expect("failed to execute mkdir");
///
/// match status.code() {
- /// Some(code) => println!("Exited with status code: {}", code),
+ /// Some(code) => println!("Exited with status code: {code}"),
/// None => println!("Process terminated by signal")
/// }
/// ```
/// let mut child = Command::new("ls").spawn().unwrap();
///
/// match child.try_wait() {
- /// Ok(Some(status)) => println!("exited with: {}", status),
+ /// Ok(Some(status)) => println!("exited with: {status}"),
/// Ok(None) => {
/// println!("status not ready yet, let's really wait");
/// let res = child.wait();
- /// println!("result: {:?}", res);
+ /// println!("result: {res:?}");
/// }
- /// Err(e) => println!("error attempting to wait: {}", e),
+ /// Err(e) => println!("error attempting to wait: {e}"),
/// }
/// ```
#[stable(feature = "process_try_wait", since = "1.18.0")]
/// std::process::exit(match run_app() {
/// Ok(_) => 0,
/// Err(err) => {
-/// eprintln!("error: {:?}", err);
+/// eprintln!("error: {err:?}");
/// 1
/// }
/// });
impl<E: fmt::Debug> Termination for Result<!, E> {
fn report(self) -> ExitCode {
let Err(err) = self;
- eprintln!("Error: {:?}", err);
+ eprintln!("Error: {err:?}");
ExitCode::FAILURE.report()
}
}
p.kill().unwrap();
match p.wait().unwrap().signal() {
Some(9) => {}
- result => panic!("not terminated by signal 9 (instead, {:?})", result),
+ result => panic!("not terminated by signal 9 (instead, {result:?})"),
}
}
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
- "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
- output
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}",
);
}
assert!(
output.contains("RUN_TEST_NEW_ENV=123"),
- "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
- output
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}"
);
}
assert!(
output.contains("RUN_TEST_NEW_ENV1=123"),
- "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
- output
+ "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{output}"
);
assert!(
output.contains("RUN_TEST_NEW_ENV2=456"),
- "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
- output
+ "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{output}"
);
}
//! B = 4;
//! A = A + B;
//! C = B;
-//! println!("{} {} {}", A, B, C);
+//! println!("{A} {B} {C}");
//! C = A;
//! }
//! }
//!
//! // Unbounded receiver waiting for all senders to complete.
//! while let Ok(msg) = rx.recv() {
-//! println!("{}", msg);
+//! println!("{msg}");
//! }
//!
//! println!("completed");
/// });
///
/// for x in recv.iter() {
-/// println!("Got: {}", x);
+/// println!("Got: {x}");
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// thread::sleep(Duration::from_secs(2)); // block for two seconds
///
/// for x in receiver.try_iter() {
-/// println!("Got: {}", x);
+/// println!("Got: {x}");
/// }
/// ```
#[stable(feature = "receiver_try_iter", since = "1.15.0")]
/// });
///
/// for x in recv.into_iter() {
-/// println!("Got: {}", x);
+/// println!("Got: {x}");
/// }
/// ```
#[stable(feature = "receiver_into_iter", since = "1.1.0")]
/// let mut msg;
///
/// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
///
/// // "Thread unblocked!" will be printed now
///
/// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
///
/// msg = receiver.recv().unwrap();
///
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SyncSender<T> {
///
/// let mut msg;
/// msg = receiver.recv().unwrap();
- /// println!("message {} received", msg);
+ /// println!("message {msg} received");
///
/// msg = receiver.recv().unwrap();
- /// println!("message {} received", msg);
+ /// println!("message {msg} received");
///
/// // Third message may have never been sent
/// match receiver.try_recv() {
- /// Ok(msg) => println!("message {} received", msg),
+ /// Ok(msg) => println!("message {msg} received"),
/// Err(_) => println!("the third message was never sent"),
/// }
/// ```
match self.channels.fetch_sub(1, Ordering::SeqCst) {
1 => {}
n if n > 1 => return,
- n => panic!("bad number of channels left {}", n),
+ n => panic!("bad number of channels left {n}"),
}
match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+ Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
}
}
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+ Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
}
}
/// Ok(_) => unreachable!(),
/// Err(p_err) => {
/// let data = p_err.get_ref();
-/// println!("recovered: {}", data);
+/// println!("recovered: {data}");
/// }
/// };
/// ```
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().into_inner() {
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+ Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"),
}
}
assert!(m.is_poisoned());
match Arc::try_unwrap(m).unwrap().get_mut() {
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+ Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
}
}
pub(super) fn exit_with_code(code: isize) -> ! {
if code != 0 {
if let Some(mut out) = panic::SgxPanicOutput::new() {
- let _ = write!(out, "Exited with status code {}", code);
+ let _ = write!(out, "Exited with status code {code}");
}
}
usercalls::exit(code != 0);
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
String::from_utf8(buf.copy_user_buffer())
- .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+ .unwrap_or_else(|_| rtabort!("Usercall {usercall}: expected {arg} to be valid UTF-8"))
}
/// Usercall `bind_stream`. See the ABI documentation for more information.
{
err
} else {
- rtabort!("Usercall: returned invalid error value {}", err)
+ rtabort!("Usercall: returned invalid error value {err}")
}
}
impl ReturnValue for ! {
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
- rtabort!("Usercall {}: did not expect to be re-entered", call);
+ rtabort!("Usercall {call}: did not expect to be re-entered");
}
}
type Error = io::Error;
fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
- LookupHost::new(format!("{}:{}", host, port))
+ LookupHost::new(format!("{host}:{port}"))
}
}
if errno == RESULT_SUCCESS {
"operation successful".into()
} else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) {
- format!("user-specified error {:08x}", errno)
+ format!("user-specified error {errno:08x}")
} else {
decode_error_kind(errno).as_str().into()
}
}
let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
- eprint!("{}", s);
+ eprint!("{s}");
}
}
unsafe {
let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
- assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result);
+ assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}");
let [x1, x2] = out.assume_init();
(x1, x2)
}
};
Err(io::Error::new(
io::ErrorKind::Uncategorized,
- &format!("failed to lookup address information: {}", msg)[..],
+ &format!("failed to lookup address information: {msg}")[..],
))
}
}
}
pub fn error_string(errno: i32) -> String {
- if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) }
+ if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") }
}
pub fn getcwd() -> io::Result<PathBuf> {
unsafe impl Send for Dir {}
unsafe impl Sync for Dir {}
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+))]
pub struct DirEntry {
- entry: dirent64,
dir: Arc<InnerReadDir>,
+ entry: dirent64_min,
// We need to store an owned copy of the entry name on platforms that use
// readdir() (not readdir_r()), because a) struct dirent may use a flexible
// array to store the name, b) it lives only until the next readdir() call.
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "solaris",
- target_os = "illumos",
- target_os = "fuchsia",
- target_os = "redox"
- ))]
name: CString,
}
+// Define a minimal subset of fields we need from `dirent64`, especially since
+// we're not using the immediate `d_name` on these targets. Keeping this as an
+// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere.
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+))]
+struct dirent64_min {
+ d_ino: u64,
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ d_type: u8,
+}
+
+#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+)))]
+pub struct DirEntry {
+ dir: Arc<InnerReadDir>,
+ // The full entry includes a fixed-length `d_name`.
+ entry: dirent64,
+}
+
#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
// Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
// whole thing (#93384). Instead, copy everything except the name.
+ let mut copy: dirent64 = mem::zeroed();
+ // Can't dereference entry_ptr, so use the local entry to get
+ // offsetof(struct dirent, d_name)
+ let copy_bytes = &mut copy as *mut _ as *mut u8;
+ let copy_name = &mut copy.d_name as *mut _ as *mut u8;
+ let name_offset = copy_name.offset_from(copy_bytes) as usize;
let entry_bytes = entry_ptr as *const u8;
- let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
- let name_offset = entry_name.offset_from(entry_bytes) as usize;
- let mut entry: dirent64 = mem::zeroed();
- ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+ let entry_name = entry_bytes.add(name_offset);
+ ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset);
+
+ let entry = dirent64_min {
+ d_ino: copy.d_ino as u64,
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ d_type: copy.d_type as u8,
+ };
let ret = DirEntry {
entry,
}
}
- fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
- let pcstr = cstr(p)?;
-
+ fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
// try opening as directory
- let fd = match openat_nofollow_dironly(parent_fd, &pcstr) {
+ let fd = match openat_nofollow_dironly(parent_fd, &path) {
Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
// not a directory - don't traverse further
return match parent_fd {
// unlink...
Some(parent_fd) => {
- cvt(unsafe { unlinkat(parent_fd, pcstr.as_ptr(), 0) }).map(drop)
+ cvt(unsafe { unlinkat(parent_fd, path.as_ptr(), 0) }).map(drop)
}
// ...unless this was supposed to be the deletion root directory
None => Err(err),
let (dir, fd) = fdreaddir(fd)?;
for child in dir {
let child = child?;
+ let child_name = child.name_cstr();
match is_dir(&child) {
Some(true) => {
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+ remove_dir_all_recursive(Some(fd), child_name)?;
}
Some(false) => {
- cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+ cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
}
None => {
// POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
// if the process has the appropriate privileges. This however can causing orphaned
// directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
// into it first instead of trying to unlink() it.
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+ remove_dir_all_recursive(Some(fd), child_name)?;
}
}
}
// unlink the directory after removing its contents
cvt(unsafe {
- unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+ unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR)
})?;
Ok(())
}
if attr.file_type().is_symlink() {
crate::fs::remove_file(p)
} else {
- remove_dir_all_recursive(None, p)
+ remove_dir_all_recursive(None, &cstr(p)?)
}
}
Err(io::Error::new(
io::ErrorKind::Uncategorized,
- &format!("failed to lookup address information: {}", detail)[..],
+ &format!("failed to lookup address information: {detail}")[..],
))
}
fn slice_debug_output() {
let input = Slice::from_u8_slice(b"\xF0hello,\tworld");
let expected = r#""\xF0hello,\tworld""#;
- let output = format!("{:?}", input);
+ let output = format!("{input:?}");
assert_eq!(output, expected);
}
return Ok(None);
}
_ => {
- panic!("Failed to wait on process handle: {}", status);
+ panic!("Failed to wait on process handle: {status}");
}
}
zx_cvt(zx_object_get_info(
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => {
assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
- panic!("the CLOEXEC pipe failed: {:?}", e)
+ panic!("the CLOEXEC pipe failed: {e:?}")
}
Ok(..) => {
// pipe I/O up to PIPE_BUF bytes should be atomic
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(code) = self.code() {
- write!(f, "exit status: {}", code)
+ write!(f, "exit status: {code}")
} else if let Some(signal) = self.signal() {
if self.core_dumped() {
- write!(f, "signal: {} (core dumped)", signal)
+ write!(f, "signal: {signal} (core dumped)")
} else {
- write!(f, "signal: {}", signal)
+ write!(f, "signal: {signal}")
}
} else if let Some(signal) = self.stopped_signal() {
- write!(f, "stopped (not terminated) by signal: {}", signal)
+ write!(f, "stopped (not terminated) by signal: {signal}")
} else if self.continued() {
write!(f, "continued (WIFCONTINUED)")
} else {
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(code) = self.code() {
- write!(f, "exit code: {}", code)
+ write!(f, "exit code: {code}")
} else {
let signal = self.signal().unwrap();
- write!(f, "signal: {}", signal)
+ write!(f, "signal: {signal}")
}
}
}
} else if err == libc::EAGAIN {
return false;
} else {
- panic!("unexpected getrandom error: {}", err);
+ panic!("unexpected getrandom error: {err}");
}
} else {
read += result as usize;
}
panic!("rwlock read lock would result in deadlock");
} else {
- // According to POSIX, for a properly initialized rwlock this can only
- // return EAGAIN or EDEADLK or 0. We rely on that.
- debug_assert_eq!(r, 0);
+ // POSIX does not make guarantees about all the errors that may be returned.
+ // See issue #94705 for more details.
+ assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
self.num_readers.fetch_add(1, Ordering::Relaxed);
}
}
} as usize;
if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
n *= 2;
- } else if k >= n {
+ } else if k > n {
n = k;
+ } else if k == n {
+ // It is impossible to reach this point.
+ // On success, k is the returned string length excluding the null.
+ // On failure, k is the required buffer length including the null.
+ // Therefore k never equals n.
+ unreachable!();
} else {
return Ok(f2(&buf[..k]));
}
if res == 0 {
// Sometimes FormatMessageW can fail e.g., system doesn't like langId,
let fm_err = errno();
- return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+ return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})");
}
match String::from_utf16(&buf[..res]) {
assert_eq!(
env::var(key).ok(),
value.map(|s| s.to_string_lossy().into_owned()),
- "command environment mismatch: {} {}",
- a,
- b
+ "command environment mismatch: {a} {b}",
);
}
}
0,
) {
c::STATUS_SUCCESS => {}
- r => panic!("Unable to create keyed event handle: error {}", r),
+ r => panic!("Unable to create keyed event handle: error {r}"),
}
}
match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
if let Some(cwd) = cwd {
if let Ok(stripped) = file.strip_prefix(&cwd) {
if let Some(s) = stripped.to_str() {
- return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
+ return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
}
}
}
let mut addrs = HashMap::new();
let lh = match LookupHost::try_from(("localhost", 0)) {
Ok(lh) => lh,
- Err(e) => panic!("couldn't resolve `localhost': {}", e),
+ Err(e) => panic!("couldn't resolve `localhost': {e}"),
};
for sa in lh {
*addrs.entry(sa).or_insert(0) += 1;
match self.state.swap(EMPTY, SeqCst) {
NOTIFIED => {} // got a notification, hurray!
PARKED => {} // no notification, alas
- n => panic!("inconsistent park_timeout state: {}", n),
+ n => panic!("inconsistent park_timeout state: {n}"),
}
}
#[inline(never)]
pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
assert!(begin <= end);
- panic!("index {} and/or {} in `{:?}` do not lie on character boundary", begin, end, s);
+ panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary");
}
/// Iterator for the code points of a WTF-8 string.
fn wtf8buf_show() {
let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+ assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
}
#[test]
fn wtf8buf_show_str() {
let text = "a\té 💩\r";
let string = Wtf8Buf::from_str(text);
- assert_eq!(format!("{:?}", text), format!("{:?}", string));
+ assert_eq!(format!("{text:?}"), format!("{string:?}"));
}
#[test]
///
/// let receiver = thread::spawn(move || {
/// let value = rx.recv().expect("Unable to receive from channel");
-/// println!("{}", value);
+/// println!("{value}");
/// });
///
/// sender.join().expect("The sender thread has panicked");
/// });
///
/// let result = computation.join().unwrap();
-/// println!("{}", result);
+/// println!("{result}");
/// ```
///
/// [`channels`]: crate::sync::mpsc
/// if elapsed >= timeout {
/// break;
/// }
-/// println!("restarting park_timeout after {:?}", elapsed);
+/// println!("restarting park_timeout after {elapsed:?}");
/// timeout_remaining = timeout - elapsed;
/// }
/// ```
impl<'scope, T> Drop for Packet<'scope, T> {
fn drop(&mut self) {
+ // If this packet was for a thread that ran in a scope, the thread
+ // panicked, and nobody consumed the panic payload, we make sure
+ // the scope function will panic.
+ let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+ // Drop the result without causing unwinding.
+ // This is only relevant for threads that aren't join()ed, as
+ // join() will take the `result` and set it to None, such that
+ // there is nothing left to drop here.
+ // If this panics, we should handle that, because we're outside the
+ // outermost `catch_unwind` of our thread.
+ // We just abort in that case, since there's nothing else we can do.
+ // (And even if we tried to handle it somehow, we'd also need to handle
+ // the case where the panic payload we get out of it also panics on
+ // drop, and so on. See issue #86027.)
+ if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ *self.result.get_mut() = None;
+ })) {
+ rtabort!("thread result panicked on drop");
+ }
// Book-keeping so the scope knows when it's done.
if let Some(scope) = self.scope {
- // If this packet was for a thread that ran in a scope, the thread
- // panicked, and nobody consumed the panic payload, we make sure
- // the scope function will panic.
- let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+ // Now that there will be no more user code running on this thread
+ // that can use 'scope, mark the thread as 'finished'.
+ // It's important we only do this after the `result` has been dropped,
+ // since dropping it might still use things it borrowed from 'scope.
scope.decrement_num_running_threads(unhandled_panic);
}
}
/// A scope to spawn scoped threads in.
///
/// See [`scope`] for details.
-pub struct Scope<'env> {
+pub struct Scope<'scope, 'env: 'scope> {
data: ScopeData,
- /// Invariance over 'env, to make sure 'env cannot shrink,
+ /// Invariance over 'scope, to make sure 'scope cannot shrink,
/// which is necessary for soundness.
///
/// Without invariance, this would compile fine but be unsound:
///
- /// ```compile_fail
+ /// ```compile_fail,E0373
/// #![feature(scoped_threads)]
///
/// std::thread::scope(|s| {
- /// s.spawn(|s| {
+ /// s.spawn(|| {
/// let a = String::from("abcd");
- /// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+ /// s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
/// });
/// });
/// ```
+ scope: PhantomData<&'scope mut &'scope ()>,
env: PhantomData<&'env mut &'env ()>,
}
/// let mut x = 0;
///
/// thread::scope(|s| {
-/// s.spawn(|_| {
+/// s.spawn(|| {
/// println!("hello from the first scoped thread");
/// // We can borrow `a` here.
/// dbg!(&a);
/// });
-/// s.spawn(|_| {
+/// s.spawn(|| {
/// println!("hello from the second scoped thread");
/// // We can even mutably borrow `x` here,
/// // because no other threads are using it.
/// a.push(4);
/// assert_eq!(x, a.len());
/// ```
+///
+/// # Lifetimes
+///
+/// Scoped threads involve two lifetimes: `'scope` and `'env`.
+///
+/// The `'scope` lifetime represents the lifetime of the scope itself.
+/// That is: the time during which new scoped threads may be spawned,
+/// and also the time during which they might still be running.
+/// Once this lifetime ends, all scoped threads are joined.
+/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts.
+/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns.
+///
+/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads.
+/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`.
+/// It can be as small as the call to `scope`, meaning that anything that outlives this call,
+/// such as local variables defined right before the scope, can be borrowed by the scoped threads.
+///
+/// The `'env: 'scope` bound is part of the definition of the `Scope` type.
#[track_caller]
pub fn scope<'env, F, T>(f: F) -> T
where
- F: FnOnce(&Scope<'env>) -> T,
+ F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
{
let scope = Scope {
data: ScopeData {
a_thread_panicked: AtomicBool::new(false),
},
env: PhantomData,
+ scope: PhantomData,
};
// Run `f`, but catch panics so we can make sure to wait for all the threads to join.
}
}
-impl<'env> Scope<'env> {
+impl<'scope, 'env> Scope<'scope, 'env> {
/// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
///
/// Unlike non-scoped threads, threads spawned with this function may
/// to recover from such errors.
///
/// [`join`]: ScopedJoinHandle::join
- pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+ pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
where
- F: FnOnce(&Scope<'env>) -> T + Send + 'env,
- T: Send + 'env,
+ F: FnOnce() -> T + Send + 'scope,
+ T: Send + 'scope,
{
Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
}
/// thread::scope(|s| {
/// thread::Builder::new()
/// .name("first".to_string())
- /// .spawn_scoped(s, |_|
+ /// .spawn_scoped(s, ||
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can borrow `a` here.
/// .unwrap();
/// thread::Builder::new()
/// .name("second".to_string())
- /// .spawn_scoped(s, |_|
+ /// .spawn_scoped(s, ||
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can even mutably borrow `x` here,
/// ```
pub fn spawn_scoped<'scope, 'env, F, T>(
self,
- scope: &'scope Scope<'env>,
+ scope: &'scope Scope<'scope, 'env>,
f: F,
) -> io::Result<ScopedJoinHandle<'scope, T>>
where
- F: FnOnce(&Scope<'env>) -> T + Send + 'env,
- T: Send + 'env,
+ F: FnOnce() -> T + Send + 'scope,
+ T: Send + 'scope,
{
- Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+ Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
}
}
/// use std::thread;
///
/// thread::scope(|s| {
- /// let t = s.spawn(|_| {
+ /// let t = s.spawn(|| {
/// println!("hello");
/// });
/// println!("thread id: {:?}", t.thread().id());
/// use std::thread;
///
/// thread::scope(|s| {
- /// let t = s.spawn(|_| {
+ /// let t = s.spawn(|| {
/// panic!("oh no");
/// });
/// assert!(t.join().is_err());
}
}
-impl<'env> fmt::Debug for Scope<'env> {
+impl fmt::Debug for Scope<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Scope")
.field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
use crate::panic::panic_any;
use crate::result;
use crate::sync::{
+ atomic::{AtomicBool, Ordering},
mpsc::{channel, Sender},
Arc, Barrier,
};
-use crate::thread::{self, ThreadId};
+use crate::thread::{self, Scope, ThreadId};
use crate::time::Duration;
use crate::time::Instant;
assert!(thread::current().id() != spawned_id);
}
-// NOTE: the corresponding test for stderr is in ui/thread-stderr, due
-// to the test harness apparently interfering with stderr configuration.
+#[test]
+fn test_scoped_threads_drop_result_before_join() {
+ let actually_finished = &AtomicBool::new(false);
+ struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
+ impl Drop for X<'_, '_> {
+ fn drop(&mut self) {
+ thread::sleep(Duration::from_millis(20));
+ let actually_finished = self.1;
+ self.0.spawn(move || {
+ thread::sleep(Duration::from_millis(20));
+ actually_finished.store(true, Ordering::Relaxed);
+ });
+ }
+ }
+ thread::scope(|s| {
+ s.spawn(move || {
+ thread::sleep(Duration::from_millis(20));
+ X(s, actually_finished)
+ });
+ });
+ assert!(actually_finished.load(Ordering::Relaxed));
+}
/// }
/// Err(e) => {
/// // an error occurred!
-/// println!("Error: {:?}", e);
+/// println!("Error: {e:?}");
/// }
/// }
/// }
/// let new_sys_time = SystemTime::now();
/// let difference = new_sys_time.duration_since(sys_time)
/// .expect("Clock may have gone backwards");
- /// println!("{:?}", difference);
+ /// println!("{difference:?}");
/// ```
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
fn instant_math() {
let a = Instant::now();
let b = Instant::now();
- println!("a: {:?}", a);
- println!("b: {:?}", b);
+ println!("a: {a:?}");
+ println!("b: {b:?}");
let dur = b.duration_since(a);
- println!("dur: {:?}", dur);
+ println!("dur: {dur:?}");
assert_almost_eq!(b - dur, a);
assert_almost_eq!(a + dur, b);
}
fn usage(binary: &str, options: &getopts::Options) {
- let message = format!("Usage: {} [OPTIONS] [FILTERS...]", binary);
+ let message = format!("Usage: {binary} [OPTIONS] [FILTERS...]");
println!(
r#"{usage}
shuffle_seed = match env::var("RUST_TEST_SHUFFLE_SEED") {
Ok(val) => match val.parse::<u64>() {
Ok(n) => Some(n),
- Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{}`, should be a number.", val),
+ Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{val}`, should be a number."),
},
Err(_) => None,
};
match *result {
TestResult::TrOk => "ok".to_owned(),
TestResult::TrFailed => "failed".to_owned(),
- TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
+ TestResult::TrFailedMsg(ref msg) => format!("failed: {msg}"),
TestResult::TrIgnored => {
#[cfg(not(bootstrap))]
if let Some(msg) = ignore_message {
- format!("ignored, {}", msg)
+ format!("ignored, {msg}")
} else {
"ignored".to_owned()
}
)
})?;
if let Some(exec_time) = exec_time {
- self.write_log(|| format!(" <{}>", exec_time))?;
+ self.write_log(|| format!(" <{exec_time}>"))?;
}
self.write_log(|| "\n")
}
}
};
- writeln!(output, "{}: {}", name, fntype)?;
- st.write_log(|| format!("{} {}\n", fntype, name))?;
+ writeln!(output, "{name}: {fntype}")?;
+ st.write_log(|| format!("{fntype} {name}\n"))?;
}
fn plural(count: u32, s: &str) -> String {
match count {
- 1 => format!("{} {}", 1, s),
- n => format!("{} {}s", n, s),
+ 1 => format!("1 {s}"),
+ n => format!("{n} {s}s"),
}
}
TestResult::TrFailedMsg(msg) => {
st.failed += 1;
let mut stdout = stdout;
- stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
+ stdout.extend_from_slice(format!("note: {msg}").as_bytes());
st.failures.push((test, stdout));
}
TestResult::TrTimedFail => {
test_name,
duration.as_secs_f64()
))?;
- self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+ self.write_message(&*format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
self.write_message("</testcase>")?;
}
exec_time: Option<&time::TestExecTime>,
) -> io::Result<()> {
if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
- let time_str = format!(" <{}>", time);
+ let time_str = format!(" <{time}>");
let color = if self.use_color {
if opts.is_critical(desc, time) {
inputs: &Vec<(TestDesc, Vec<u8>)>,
results_type: &str,
) -> io::Result<()> {
- let results_out_str = format!("\n{}:\n", results_type);
+ let results_out_str = format!("\n{results_type}:\n");
self.write_plain(&results_out_str)?;
self.write_plain(&results_out_str)?;
results.sort();
for name in &results {
- self.write_plain(&format!(" {}\n", name))?;
+ self.write_plain(&format!(" {name}\n"))?;
}
Ok(())
}
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
if let Some(test_mode) = desc.test_mode() {
- self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ self.write_plain(&format!("test {name} - {test_mode} ... "))?;
} else {
- self.write_plain(&format!("test {} ... ", name))?;
+ self.write_plain(&format!("test {name} ... "))?;
}
Ok(())
fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
let noun = if test_count != 1 { "tests" } else { "test" };
let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
- format!(" (shuffle seed: {})", shuffle_seed)
+ format!(" (shuffle seed: {shuffle_seed})")
} else {
String::new()
};
- self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+ self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
}
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
self.write_plain(&s)?;
if let Some(ref exec_time) = state.exec_time {
- let time_str = format!("; finished in {}", exec_time);
+ let time_str = format!("; finished in {exec_time}");
self.write_plain(&time_str)?;
}
self.write_plain("\nsuccesses:\n")?;
successes.sort();
for name in &successes {
- self.write_plain(&format!(" {}\n", name))?;
+ self.write_plain(&format!(" {name}\n"))?;
}
Ok(())
}
self.write_plain("\nfailures:\n")?;
failures.sort();
for name in &failures {
- self.write_plain(&format!(" {}\n", name))?;
+ self.write_plain(&format!(" {name}\n"))?;
}
Ok(())
}
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
if let Some(test_mode) = desc.test_mode() {
- self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ self.write_plain(&format!("test {name} - {test_mode} ... "))?;
} else {
- self.write_plain(&format!("test {} ... ", name))?;
+ self.write_plain(&format!("test {name} ... "))?;
}
Ok(())
self.total_test_count = test_count;
let noun = if test_count != 1 { "tests" } else { "test" };
let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
- format!(" (shuffle seed: {})", shuffle_seed)
+ format!(" (shuffle seed: {shuffle_seed})")
} else {
String::new()
};
- self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+ self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
}
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
self.write_plain(&s)?;
if let Some(ref exec_time) = state.exec_time {
- let time_str = format!("; finished in {}", exec_time);
+ let time_str = format!("; finished in {exec_time}");
self.write_plain(&time_str)?;
}
if let Ok(value) = env::var("RUST_TEST_THREADS") {
match value.parse::<NonZeroUsize>().ok() {
Some(n) => n.get(),
- _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
+ _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."),
}
} else {
thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
match status.code() {
Some(code) => Ok(code),
None => match status.signal() {
- Some(signal) => Err(format!("child process exited with signal {}", signal)),
+ Some(signal) => Err(format!("child process exited with signal {signal}")),
None => Err("child process exited with unknown signal".into()),
},
}
let mut opts = match cli::parse_opts(args) {
Some(Ok(o)) => o,
Some(Err(msg)) => {
- eprintln!("error: {}", msg);
+ eprintln!("error: {msg}");
process::exit(ERROR_EXIT_CODE);
}
None => return,
}
if opts.list {
if let Err(e) = console::list_tests_console(&opts, tests) {
- eprintln!("error: io error when listing tests: {:?}", e);
+ eprintln!("error: io error when listing tests: {e:?}");
process::exit(ERROR_EXIT_CODE);
}
} else {
Ok(true) => {}
Ok(false) => process::exit(ERROR_EXIT_CODE),
Err(e) => {
- eprintln!("error: io error when listing tests: {:?}", e);
+ eprintln!("error: io error when listing tests: {e:?}");
process::exit(ERROR_EXIT_CODE);
}
}
.filter(|test| test.desc.name.as_slice() == name)
.map(make_owned_test)
.next()
- .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{}'", name));
+ .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'"));
let TestDescAndFn { desc, testfn } = test;
let testfn = match testfn {
StaticTestFn(f) => f,
Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
None
}
- Err(e) => panic!("failed to spawn thread to run test: {}", e),
+ Err(e) => panic!("failed to spawn thread to run test: {e}"),
}
} else {
runtest();
// We don't support serializing TrFailedMsg, so just
// print the message out to stderr.
if let TrFailedMsg(msg) = &test_result {
- eprintln!("{}", msg);
+ eprintln!("{msg}");
}
if let Some(info) = panic_info {
},
'e' => state = SeekIfEnd(0),
';' => (),
- _ => return Err(format!("unrecognized format option {}", cur)),
+ _ => return Err(format!("unrecognized format option {cur}")),
}
}
PushParam => {
fn test_comparison_ops() {
let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])];
for &(op, bs) in v.iter() {
- let s = format!("%{{1}}%{{2}}%{}%d", op);
+ let s = format!("%{{1}}%{{2}}%{op}%d");
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), "{}", res.unwrap_err());
assert_eq!(res.unwrap(), vec![b'0' + bs[0]]);
- let s = format!("%{{1}}%{{1}}%{}%d", op);
+ let s = format!("%{{1}}%{{1}}%{op}%d");
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), "{}", res.unwrap_err());
assert_eq!(res.unwrap(), vec![b'0' + bs[1]]);
- let s = format!("%{{2}}%{{1}}%{}%d", op);
+ let s = format!("%{{2}}%{{1}}%{op}%d");
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), "{}", res.unwrap_err());
assert_eq!(res.unwrap(), vec![b'0' + bs[2]]);
let extended = match magic {
0o0432 => false,
0o01036 => true,
- _ => return Err(format!("invalid magic number, found {:o}", magic)),
+ _ => return Err(format!("invalid magic number, found {magic:o}")),
};
// According to the spec, these fields must be >= -1 where -1 means that the feature is not
let result = match code {
TR_OK => TestResult::TrOk,
TR_FAILED => TestResult::TrFailed,
- _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+ _ => TestResult::TrFailedMsg(format!("got unexpected return code {code}")),
};
// If test is already failed (or allowed to fail), do not change the result.
extern "C-unwind" {
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
+ #[cfg_attr(
+ all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
+ )]
extern "C" {
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
version = "0.0.0"
edition = "2021"
build = "build.rs"
+default-run = "bootstrap"
[lib]
path = "lib.rs"
build.verbose = args.verbose
build.clean = args.clean
- # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then fallback to `config.toml` (if it
- # exists).
+ # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
+ # then `config.toml` in the root directory.
toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG')
- if not toml_path and os.path.exists('config.toml'):
+ using_default_path = toml_path is None
+ if using_default_path:
toml_path = 'config.toml'
-
- if toml_path:
if not os.path.exists(toml_path):
toml_path = os.path.join(build.rust_root, toml_path)
+ # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+ # but not if `config.toml` hasn't been created.
+ if not using_default_path or os.path.exists(toml_path):
with open(toml_path) as config:
build.config_toml = config.read()
build.check_vendored_status()
build_dir = build.get_toml('build-dir', 'build') or 'build'
- build.build_dir = os.path.abspath(build_dir.replace("$ROOT", build.rust_root))
+ build.build_dir = os.path.abspath(build_dir)
with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
data = json.load(f)
env = os.environ.copy()
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
env["BOOTSTRAP_PYTHON"] = sys.executable
- env["BUILD_DIR"] = build.build_dir
env["RUSTC_BOOTSTRAP"] = '1'
- if toml_path:
- env["BOOTSTRAP_CONFIG"] = toml_path
if build.rustc_commit is not None:
env["BOOTSTRAP_DOWNLOAD_RUSTC"] = '1'
run(args, env=env, verbose=build.verbose, is_bootstrap=True)
}
pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
- let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
+ let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc"));
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler))
// Note that this is *not* the sysroot_libdir because rustdoc must be linked
.env("RUSTC_STAGE", stage.to_string())
.env("RUSTC_SYSROOT", &sysroot)
.env("RUSTC_LIBDIR", &libdir)
- .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
+ .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
.env(
"RUSTDOC_REAL",
if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
// Clippy support is a hack and uses the default `cargo-clippy` in path.
// Don't override RUSTC so that the `cargo-clippy` in path will be run.
if cmd != "clippy" {
- cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
+ cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
}
// Dealing with rpath here is a little special, so let's go into some
config.save_toolstates = None;
config.dry_run = true;
config.ninja_in_file = false;
- // try to avoid spurious failures in dist where we create/delete each others file
config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
+ // try to avoid spurious failures in dist where we create/delete each others file
let dir = config
.out
.join("tmp-rustbuild-tests")
use std::cmp;
use std::collections::{HashMap, HashSet};
use std::env;
-use std::ffi::OsString;
use std::fmt;
use std::fs;
use std::path::{Path, PathBuf};
build: Option<String>,
host: Option<Vec<String>>,
target: Option<Vec<String>>,
- // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
build_dir: Option<String>,
cargo: Option<String>,
rustc: Option<String>,
}
impl Config {
- fn path_from_python(var_key: &str) -> PathBuf {
- match env::var_os(var_key) {
- Some(var_val) => Self::normalize_python_path(var_val),
- _ => panic!("expected '{}' to be set", var_key),
- }
- }
-
- /// Normalizes paths from Python slightly. We don't trust paths from Python (#49785).
- fn normalize_python_path(path: OsString) -> PathBuf {
- Path::new(&path).components().collect()
- }
-
pub fn default_opts() -> Config {
let mut config = Config::default();
config.llvm_optimize = true;
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// Undo `src/bootstrap`
config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
- config.out = Config::path_from_python("BUILD_DIR");
+ config.out = PathBuf::from("build");
config.initial_cargo = PathBuf::from(env!("CARGO"));
config.initial_rustc = PathBuf::from(env!("RUSTC"));
config.llvm_profile_use = flags.llvm_profile_use;
config.llvm_profile_generate = flags.llvm_profile_generate;
- if config.dry_run {
- let dir = config.out.join("tmp-dry-run");
- t!(fs::create_dir_all(&dir));
- config.out = dir;
- }
-
#[cfg(test)]
let get_toml = |_| TomlConfig::default();
#[cfg(not(test))]
let get_toml = |file: &Path| {
use std::process;
- let contents = t!(fs::read_to_string(file), "`include` config not found");
+ let contents =
+ t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
match toml::from_str(&contents) {
Ok(table) => table,
Err(err) => {
}
};
- let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
+ // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
+ let toml_path = flags
+ .config
+ .clone()
+ .or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from));
+ let using_default_path = toml_path.is_none();
+ let mut toml_path = toml_path.unwrap_or_else(|| PathBuf::from("config.toml"));
+ if using_default_path && !toml_path.exists() {
+ toml_path = config.src.join(toml_path);
+ }
+
+ // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+ // but not if `config.toml` hasn't been created.
+ let mut toml = if !using_default_path || toml_path.exists() {
+ get_toml(&toml_path)
+ } else {
+ TomlConfig::default()
+ };
+
if let Some(include) = &toml.profile {
let mut include_path = config.src.clone();
include_path.push("src");
}
config.changelog_seen = toml.changelog_seen;
- if let Some(cfg) = flags.config {
- config.config = cfg;
- }
+ config.config = toml_path;
let build = toml.build.unwrap_or_default();
+ set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
+ set(&mut config.out, build.build_dir.map(PathBuf::from));
+ // NOTE: Bootstrap spawns various commands with different working directories.
+ // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
+ if !config.out.is_absolute() {
+ // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
+ config.out = crate::util::absolute(&config.out);
+ }
+
+ if config.dry_run {
+ let dir = config.out.join("tmp-dry-run");
+ t!(fs::create_dir_all(&dir));
+ config.out = dir;
+ }
+
config.hosts = if let Some(arg_host) = flags.host {
arg_host
} else if let Some(file_host) = build.host {
def set(key, value):
+ if isinstance(value, list):
+ # Remove empty values, which value.split(',') tends to generate.
+ value = [v for v in value if v]
+
s = "{:20} := {}".format(key, value)
if len(s) < 70:
p(s)
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
-use std::env;
use std::path::PathBuf;
use std::process;
// Get any optional paths which occur after the subcommand
let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
- let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
let verbose = matches.opt_present("verbose");
// User passed in -h/--help?
} else {
None
},
- config: cfg_file,
+ config: matches.opt_str("config").map(PathBuf::from),
jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
cmd,
incremental: matches.opt_present("incremental"),
(None, "bootstrap", None),
(Some(Mode::Rustc), "parallel_compiler", None),
(Some(Mode::ToolRustc), "parallel_compiler", None),
- (Some(Mode::Std), "miri", None),
(Some(Mode::Std), "stdarch_intel_sde", None),
(Some(Mode::Std), "no_fp_fmt_parse", None),
(Some(Mode::Std), "no_global_oom_handling", None),
// Properties derived from the above configuration
src: PathBuf,
out: PathBuf,
+ bootstrap_out: PathBuf,
rust_info: channel::GitInfo,
cargo_info: channel::GitInfo,
rls_info: channel::GitInfo,
.expect("failed to read src/version");
let version = version.trim();
+ let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
+ out.join("bootstrap").join("debug")
+ } else {
+ let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| src.join("target"));
+ let bootstrap_out = workspace_target_dir.join("debug");
+ if !bootstrap_out.join("rustc").exists() {
+ // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
+ panic!("run `cargo build --bins` before `cargo run`")
+ }
+ bootstrap_out
+ };
+
let mut build = Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
version: version.to_string(),
src,
out,
+ bootstrap_out,
rust_info,
cargo_info,
}
if let Subcommand::Setup { profile } = &self.config.cmd {
- return setup::setup(&self.config.src, *profile);
+ return setup::setup(&self.config, *profile);
}
{
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
}
- // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
- // We also do this if the user explicitly requested static libstdc++.
- if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
- if !target.contains("msvc") && !target.contains("netbsd") {
- if target.contains("apple") {
- ldflags.push_all("-static-libstdc++");
- } else {
- ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
- }
- }
- }
-
if target.starts_with("riscv") && !target.contains("freebsd") {
// RISC-V GCC erroneously requires linking against
// `libatomic` when using 1-byte and 2-byte C++
ldflags.push_all(&flags);
}
+ // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
+ // We also do this if the user explicitly requested static libstdc++.
+ if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
+ if !target.contains("msvc") && !target.contains("netbsd") {
+ if target.contains("apple") {
+ ldflags.push_all("-static-libstdc++");
+ } else {
+ ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
+ }
+ }
+ }
+
cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared);
cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module);
cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe);
-use crate::TargetSelection;
use crate::{t, VERSION};
+use crate::{Config, TargetSelection};
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
}
}
-pub fn setup(src_path: &Path, profile: Profile) {
- let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
+pub fn setup(config: &Config, profile: Profile) {
+ let path = &config.config;
- if cfg_file.as_ref().map_or(false, |f| f.exists()) {
- let file = cfg_file.unwrap();
+ if path.exists() {
println!(
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
- file.display()
+ path.display()
);
- println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
+ println!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
println!(
"note: this will use the configuration in {}",
- profile.include_path(src_path).display()
+ profile.include_path(&config.src).display()
);
std::process::exit(1);
}
- let path = cfg_file.unwrap_or_else(|| "config.toml".into());
let settings = format!(
"# Includes one of the default files in src/bootstrap/defaults\n\
profile = \"{}\"\n\
);
t!(fs::write(path, settings));
- let include_path = profile.include_path(src_path);
+ let include_path = profile.include_path(&config.src);
println!("`x.py` will now use the configuration at {}", include_path.display());
let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
println!();
- t!(install_git_hook_maybe(src_path));
+ t!(install_git_hook_maybe(&config.src));
println!();
}
fn run(self, builder: &Builder<'_>) {
- let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
+ let rustdoc = builder.bootstrap_out.join("rustdoc");
let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
cmd.arg(rustdoc.to_str().unwrap())
.arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
.current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+ // HACK: bootstrap's tests want to know the output directory, but there's no way to set
+ // it except through config.toml. Set it through an env variable instead.
.env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
.env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
.env("RUSTC_BOOTSTRAP", "1")
println!("\n\n{}\n\n", s);
std::process::exit(1);
}
+
+/// Copied from `std::path::absolute` until it stabilizes.
+///
+/// FIXME: this shouldn't exist.
+pub(crate) fn absolute(path: &Path) -> PathBuf {
+ if path.as_os_str().is_empty() {
+ panic!("can't make empty path absolute");
+ }
+ #[cfg(unix)]
+ {
+ t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(windows)]
+ {
+ t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(not(any(unix, windows)))]
+ {
+ println!("warning: bootstrap is not supported on non-unix platforms");
+ t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
+ }
+}
+
+#[cfg(unix)]
+/// Make a POSIX path absolute without changing its semantics.
+fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
+ // This is mostly a wrapper around collecting `Path::components`, with
+ // exceptions made where this conflicts with the POSIX specification.
+ // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+ use std::os::unix::prelude::OsStrExt;
+ let mut components = path.components();
+ let path_os = path.as_os_str().as_bytes();
+
+ let mut normalized = if path.is_absolute() {
+ // "If a pathname begins with two successive <slash> characters, the
+ // first component following the leading <slash> characters may be
+ // interpreted in an implementation-defined manner, although more than
+ // two leading <slash> characters shall be treated as a single <slash>
+ // character."
+ if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+ components.next();
+ PathBuf::from("//")
+ } else {
+ PathBuf::new()
+ }
+ } else {
+ env::current_dir()?
+ };
+ normalized.extend(components);
+
+ // "Interfaces using pathname resolution may specify additional constraints
+ // when a pathname that does not name an existing directory contains at
+ // least one non- <slash> character and contains one or more trailing
+ // <slash> characters".
+ // A trailing <slash> is also meaningful if "a symbolic link is
+ // encountered during pathname resolution".
+
+ if path_os.ends_with(b"/") {
+ normalized.push("");
+ }
+
+ Ok(normalized)
+}
+
+#[cfg(windows)]
+fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
+ use std::ffi::OsString;
+ use std::io::Error;
+ use std::os::windows::ffi::{OsStrExt, OsStringExt};
+ use std::ptr::null_mut;
+ #[link(name = "kernel32")]
+ extern "system" {
+ fn GetFullPathNameW(
+ lpFileName: *const u16,
+ nBufferLength: u32,
+ lpBuffer: *mut u16,
+ lpFilePart: *mut *const u16,
+ ) -> u32;
+ }
+
+ unsafe {
+ // encode the path as UTF-16
+ let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
+ let mut buffer = Vec::new();
+ // Loop until either success or failure.
+ loop {
+ // Try to get the absolute path
+ let len = GetFullPathNameW(
+ path.as_ptr(),
+ buffer.len().try_into().unwrap(),
+ buffer.as_mut_ptr(),
+ null_mut(),
+ );
+ match len as usize {
+ // Failure
+ 0 => return Err(Error::last_os_error()),
+ // Buffer is too small, resize.
+ len if len > buffer.len() => buffer.resize(len, 0),
+ // Success!
+ len => {
+ buffer.truncate(len);
+ return Ok(OsString::from_wide(&buffer).into());
+ }
+ }
+ }
+ }
+}
# https://github.com/puppeteer/puppeteer/issues/375
#
# We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.7.2 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.8.0 --unsafe-perm=true
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
+
+[output.html.redirect]
+"/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html"
+"/documentation-tests.html" = "write-documentation/documentation-tests.html"
# The Rustdoc Book
- [What is rustdoc?](what-is-rustdoc.md)
+- [Command-line arguments](command-line-arguments.md)
- [How to read rustdoc output](how-to-read-rustdoc.md)
- [How to write documentation](how-to-write-documentation.md)
-- [What to include (and exclude)](what-to-include.md)
-- [Command-line arguments](command-line-arguments.md)
-- [The `#[doc]` attribute](the-doc-attribute.md)
-- [Documentation tests](documentation-tests.md)
-- [Linking to items by name](linking-to-items-by-name.md)
-- [Lints](lints.md)
+ - [What to include (and exclude)](write-documentation/what-to-include.md)
+ - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
+ - [Linking to items by name](write-documentation/linking-to-items-by-name.md)
+ - [Documentation tests](write-documentation/documentation-tests.md)
+- [Rustdoc-specific lints](lints.md)
- [Advanced features](advanced-features.md)
- [Unstable features](unstable-features.md)
-- [Website features](website-features.md)
-- [Passes](passes.md)
+- [Deprecated features](deprecated-features.md)
- [References](references.md)
#[doc(alias("x", "big"))]
pub struct BigX;
```
+
+## Custom search engines
+
+If you find yourself often referencing online Rust docs you might enjoy using a custom search
+engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
+Most browsers support this feature by letting you define a URL template containing `%s`
+which will be substituted for the search term. As an example, for the standard library you could use
+this template:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s
+```
+
+Note that this will take you to a results page listing all matches. If you want to navigate to the first
+result right away (which is often the best match) use the following instead:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
+```
+
+This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
+to automatically go to the first result.
```
This flag will run your code examples as tests. For more, see [the chapter
-on documentation tests](documentation-tests.md).
+on documentation tests](write-documentation/documentation-tests.md).
See also `--test-args`.
```
This flag will pass options to the test runner when running documentation tests.
-For more, see [the chapter on documentation tests](documentation-tests.md).
+For more, see [the chapter on documentation tests](write-documentation/documentation-tests.md).
See also `--test`.
Similar to `rustc --sysroot`, this lets you change the sysroot `rustdoc` uses
when compiling your code.
-### `--edition`: control the edition of docs and doctests
+## `--edition`: control the edition of docs and doctests
Using this flag looks like this:
## `--passes`: add more rustdoc passes
This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
## `--no-defaults`: don't run default passes
This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
## `-r`/`--input-format`: input format
Rustdoc only supports Rust source code and Markdown input formats. If the
file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
Otherwise, it assumes that the input file is Rust.
-
-# Unstable command line arguments
-
-## `--nocapture`
-
-When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
-captured by rustdoc. Instead, the output will be directed to your terminal,
-as if you had run the test executable manually. This is especially useful
-for debugging your tests!
-
-## `--check`
-
-When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
-documentation or run your doctests.
-
-Using this flag looks like:
-
-```bash
-rustdoc -Z unstable-options --check src/lib.rs
-```
--- /dev/null
+# Deprecated features
+
+## Passes
+
+Rustdoc has a concept called "passes". These are transformations that
+`rustdoc` runs on your documentation before producing its final output.
+
+Customizing passes is **deprecated**. The available passes are not considered stable and may
+change in any release.
+
+In the past the most common use case for customizing passes was to omit the `strip-private` pass.
+You can do this more easily, and without risk of the pass being changed, by passing
+[`--document-private-items`](./unstable-features.md#--document-private-items).
+++ /dev/null
-# Documentation tests
-
-`rustdoc` supports executing your documentation examples as tests. This makes sure
-that examples within your documentation are up to date and working.
-
-The basic idea is this:
-
-```rust,no_run
-/// # Examples
-///
-/// ```
-/// let x = 5;
-/// ```
-# fn f() {}
-```
-
-The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
-running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
-
-Please note that by default, if no language is set for the block code, rustdoc
-assumes it is Rust code. So the following:
-
-``````markdown
-```rust
-let x = 5;
-```
-``````
-
-is strictly equivalent to:
-
-``````markdown
-```
-let x = 5;
-```
-``````
-
-There's some subtlety though! Read on for more details.
-
-## Passing or failing a doctest
-
-Like regular unit tests, regular doctests are considered to "pass"
-if they compile and run without panicking.
-So if you want to demonstrate that some computation gives a certain result,
-the `assert!` family of macros works the same as other Rust code:
-
-```rust
-let foo = "foo";
-assert_eq!(foo, "foo");
-```
-
-This way, if the computation ever returns something different,
-the code panics and the doctest fails.
-
-## Pre-processing examples
-
-In the example above, you'll note something strange: there's no `main`
-function! Forcing you to write `main` for every example, no matter how small,
-adds friction and clutters the output. So `rustdoc` processes your examples
-slightly before running them. Here's the full algorithm `rustdoc` uses to
-preprocess examples:
-
-1. Some common `allow` attributes are inserted, including
- `unused_variables`, `unused_assignments`, `unused_mut`,
- `unused_attributes`, and `dead_code`. Small examples often trigger
- these lints.
-2. Any attributes specified with `#![doc(test(attr(...)))]` are added.
-3. Any leading `#![foo]` attributes are left intact as crate attributes.
-4. If the example does not contain `extern crate`, and
- `#![doc(test(no_crate_inject))]` was not specified, then `extern crate
- <mycrate>;` is inserted (note the lack of `#[macro_use]`).
-5. Finally, if the example does not contain `fn main`, the remainder of the
- text is wrapped in `fn main() { your_code }`.
-
-For more about that caveat in rule 4, see "Documenting Macros" below.
-
-## Hiding portions of the example
-
-Sometimes, you need some setup code, or other things that would distract
-from your example, but are important to make the tests work. Consider
-an example block that looks like this:
-
-```rust,no_run
-/// ```
-/// /// Some documentation.
-/// # fn foo() {} // this function will be hidden
-/// println!("Hello, World!");
-/// ```
-# fn f() {}
-```
-
-It will render like this:
-
-```rust
-/// Some documentation.
-# fn foo() {}
-println!("Hello, World!");
-```
-
-Yes, that's right: you can add lines that start with `# `, and they will
-be hidden from the output, but will be used when compiling your code. You
-can use this to your advantage. In this case, documentation comments need
-to apply to some kind of function, so if I want to show you just a
-documentation comment, I need to add a little function definition below
-it. At the same time, it's only there to satisfy the compiler, so hiding
-it makes the example more clear. You can use this technique to explain
-longer examples in detail, while still preserving the testability of your
-documentation.
-
-For example, imagine that we wanted to document this code:
-
-```rust
-let x = 5;
-let y = 6;
-println!("{}", x + y);
-```
-
-We might want the documentation to end up looking like this:
-
-> First, we set `x` to five:
->
-> ```rust
-> let x = 5;
-> # let y = 6;
-> # println!("{}", x + y);
-> ```
->
-> Next, we set `y` to six:
->
-> ```rust
-> # let x = 5;
-> let y = 6;
-> # println!("{}", x + y);
-> ```
->
-> Finally, we print the sum of `x` and `y`:
->
-> ```rust
-> # let x = 5;
-> # let y = 6;
-> println!("{}", x + y);
-> ```
-
-To keep each code block testable, we want the whole program in each block, but
-we don't want the reader to see every line every time. Here's what we put in
-our source code:
-
-``````markdown
-First, we set `x` to five:
-
-```
-let x = 5;
-# let y = 6;
-# println!("{}", x + y);
-```
-
-Next, we set `y` to six:
-
-```
-# let x = 5;
-let y = 6;
-# println!("{}", x + y);
-```
-
-Finally, we print the sum of `x` and `y`:
-
-```
-# let x = 5;
-# let y = 6;
-println!("{}", x + y);
-```
-``````
-
-By repeating all parts of the example, you can ensure that your example still
-compiles, while only showing the parts that are relevant to that part of your
-explanation.
-
-The `#`-hiding of lines can be prevented by using two consecutive hashes
-`##`. This only needs to be done with the first `#` which would've
-otherwise caused hiding. If we have a string literal like the following,
-which has a line that starts with a `#`:
-
-```rust
-let s = "foo
-## bar # baz";
-```
-
-We can document it by escaping the initial `#`:
-
-```text
-/// let s = "foo
-/// ## bar # baz";
-```
-
-
-## Using `?` in doc tests
-
-When writing an example, it is rarely useful to include a complete error
-handling, as it would add significant amounts of boilerplate code. Instead, you
-may want the following:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// ```
-# fn f() {}
-```
-
-The problem is that `?` returns a `Result<T, E>` and test functions don't
-return anything, so this will give a mismatched types error.
-
-You can get around this limitation by manually adding a `main` that returns
-`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
-
-```rust,no_run
-/// A doc test using ?
-///
-/// ```
-/// use std::io;
-///
-/// fn main() -> io::Result<()> {
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// Ok(())
-/// }
-/// ```
-# fn f() {}
-```
-
-Together with the `# ` from the section above, you arrive at a solution that
-appears to the reader as the initial idea but works with doc tests:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// # fn main() -> io::Result<()> {
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// # Ok(())
-/// # }
-/// ```
-# fn f() {}
-```
-
-As of version 1.34.0, one can also omit the `fn main()`, but you will have to
-disambiguate the error type:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// # Ok::<(), io::Error>(())
-/// ```
-# fn f() {}
-```
-
-This is an unfortunate consequence of the `?` operator adding an implicit
-conversion, so type inference fails because the type is not unique. Please note
-that you must write the `(())` in one sequence without intermediate whitespace
-so that `rustdoc` understands you want an implicit `Result`-returning function.
-
-## Showing warnings in doctests
-
-You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
-(or, if you're using cargo, `cargo test --doc -- --show-output`).
-By default, this will still hide `unused` warnings, since so many examples use private functions;
-you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
-You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
-
-[test-attr]: ./the-doc-attribute.md#testattr
-
-## Documenting macros
-
-Here’s an example of documenting a macro:
-
-```rust
-/// Panic with a given message unless an expression evaluates to true.
-///
-/// # Examples
-///
-/// ```
-/// # #[macro_use] extern crate foo;
-/// # fn main() {
-/// panic_unless!(1 + 1 == 2, “Math is broken.”);
-/// # }
-/// ```
-///
-/// ```should_panic
-/// # #[macro_use] extern crate foo;
-/// # fn main() {
-/// panic_unless!(true == false, “I’m broken.”);
-/// # }
-/// ```
-#[macro_export]
-macro_rules! panic_unless {
- ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
-}
-# fn main() {}
-```
-
-You’ll note three things: we need to add our own `extern crate` line, so that
-we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
-`main()` as well (for reasons discussed above). Finally, a judicious use of
-`#` to comment out those two things, so they don’t show up in the output.
-
-## Attributes
-
-Code blocks can be annotated with attributes that help `rustdoc` do the right
-thing when testing your code:
-
-The `ignore` attribute tells Rust to ignore your code. This is almost never
-what you want as it's the most generic. Instead, consider annotating it
-with `text` if it's not code or using `#`s to get a working example that
-only shows the part you care about.
-
-```rust
-/// ```ignore
-/// fn foo() {
-/// ```
-# fn foo() {}
-```
-
-`should_panic` tells `rustdoc` that the code should compile correctly but
-panic during execution. If the code doesn't panic, the test will fail.
-
-```rust
-/// ```should_panic
-/// assert!(false);
-/// ```
-# fn foo() {}
-```
-
-The `no_run` attribute will compile your code but not run it. This is
-important for examples such as "Here's how to retrieve a web page,"
-which you would want to ensure compiles, but might be run in a test
-environment that has no network access. This attribute can also be
-used to demonstrate code snippets that can cause Undefined Behavior.
-
-```rust
-/// ```no_run
-/// loop {
-/// println!("Hello, world");
-/// }
-/// ```
-# fn foo() {}
-```
-
-`compile_fail` tells `rustdoc` that the compilation should fail. If it
-compiles, then the test will fail. However, please note that code failing
-with the current Rust release may work in a future release, as new features
-are added.
-
-```rust
-/// ```compile_fail
-/// let x = 5;
-/// x += 2; // shouldn't compile!
-/// ```
-# fn foo() {}
-```
-
-`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
-that the code sample should be compiled using the respective edition of Rust.
-
-```rust
-/// Only runs on the 2018 edition.
-///
-/// ```edition2018
-/// let result: Result<i32, ParseIntError> = try {
-/// "1".parse::<i32>()?
-/// + "2".parse::<i32>()?
-/// + "3".parse::<i32>()?
-/// };
-/// ```
-# fn foo() {}
-```
-
-## Syntax reference
-
-The *exact* syntax for code blocks, including the edge cases, can be found
-in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
-section of the CommonMark specification.
-
-Rustdoc also accepts *indented* code blocks as an alternative to fenced
-code blocks: instead of surrounding your code with three backticks, you
-can indent each line by four or more spaces.
-
-``````markdown
- let foo = "foo";
- assert_eq!(foo, "foo");
-``````
-
-These, too, are documented in the CommonMark specification, in the
-[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
-section.
-
-However, it's preferable to use fenced code blocks over indented code blocks.
-Not only are fenced code blocks considered more idiomatic for Rust code,
-but there is no way to use attributes such as `ignore` or `should_panic` with
-indented code blocks.
-
-### Include items only when collecting doctests
-
-Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
-sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
-documentation. To this end, Rustdoc allows you to have certain items only appear when it's
-collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
-docs, or to find an arbitrary private item to include it on.
-
-When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
-Note that they will still link against only the public items of your crate; if you need to test
-private items, you need to write a unit test.
-
-In this example, we're adding doctests that we know won't compile, to verify that our struct can
-only take in valid data:
-
-```rust
-/// We have a struct here. Remember it doesn't accept negative numbers!
-pub struct MyStruct(pub usize);
-
-/// ```compile_fail
-/// let x = my_crate::MyStruct(-5);
-/// ```
-#[cfg(doctest)]
-pub struct MyStructOnlyTakesUsize;
-```
-
-Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
-API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
-collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
-but is hidden from the public documentation.
-
-Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
-without including it in your main documentation. For example, you could write this into your
-`lib.rs` to test your README as part of your doctests:
-
-```rust,no_run
-#[doc = include_str!("../README.md")]
-#[cfg(doctest)]
-pub struct ReadmeDoctests;
-```
-
-This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
-then be tested alongside the rest of your doctests.
- a button to collapse or expand the top-level documentation for that item
(`[+]` or `[-]`),
- a link to the source code (`[src]`),
- if [configured](the-doc-attribute.html#html_no_source),
+ if [configured](write-documentation/the-doc-attribute.html#html_no_source),
and present (the source may not be available if
the documentation was created with `cargo doc --no-deps`),
- and the version in which the item became stable,
it shows all the crates documented in the documentation bundle,
and quick links to the modules, structs, traits, functions, and macros available
from the current crate.
-At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
+At the top, it displays a [configurable logo](write-documentation/the-doc-attribute.html#html_logo_url)
alongside the current crate's name and version,
or the current item whose documentation is being displayed.
// Prints each argument on a separate line
for argument in env::args() {
- println!("{}", argument);
+ println!("{argument}");
}
```
+++ /dev/null
-# Linking to items by name
-
-Rustdoc is capable of directly linking to other rustdoc pages using the path of
-the item as a link. This is referred to as an 'intra-doc link'.
-
-For example, in the following code all of the links will link to the rustdoc page for `Bar`:
-
-```rust
-/// This struct is not [Bar]
-pub struct Foo1;
-
-/// This struct is also not [bar](Bar)
-pub struct Foo2;
-
-/// This struct is also not [bar][b]
-///
-/// [b]: Bar
-pub struct Foo3;
-
-/// This struct is also not [`Bar`]
-pub struct Foo4;
-
-/// This struct *is* [`Bar`]!
-pub struct Bar;
-```
-
-Unlike normal Markdown, `[bar][Bar]` syntax is also supported without needing a
-`[Bar]: ...` reference link.
-
-Backticks around the link will be stripped, so ``[`Option`]`` will correctly
-link to `Option`.
-
-## Valid links
-
-You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and
-`crate`. Associated items (functions, types, and constants) are supported, but [not for blanket
-trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in
-[the standard library documentation](../std/index.html#primitives).
-
-[#79682]: https://github.com/rust-lang/rust/pull/79682
-
-You can also refer to items with generic parameters like `Vec<T>`. The link will
-resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
-`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
-
-[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
-
-```rust,edition2018
-use std::sync::mpsc::Receiver;
-
-/// This is a version of [`Receiver<T>`] with support for [`std::future`].
-///
-/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
-pub struct AsyncReceiver<T> {
- sender: Receiver<T>
-}
-
-impl<T> AsyncReceiver<T> {
- pub async fn recv() -> T {
- unimplemented!()
- }
-}
-```
-
-Rustdoc allows using URL fragment specifiers, just like a normal link:
-
-```rust
-/// This is a special implementation of [positional parameters].
-///
-/// [positional parameters]: std::fmt#formatting-parameters
-struct MySpecialFormatter;
-```
-
-## Namespaces and Disambiguators
-
-Paths in Rust have three namespaces: type, value, and macro. Item names must be unique within
-their namespace, but can overlap with items in other namespaces. In case of ambiguity,
-rustdoc will warn about the ambiguity and suggest a disambiguator.
-
-```rust
-/// See also: [`Foo`](struct@Foo)
-struct Bar;
-
-/// This is different from [`Foo`](fn@Foo)
-struct Foo {}
-
-fn Foo() {}
-```
-
-These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
-rendered as `Foo`.
-
-You can also disambiguate for functions by adding `()` after the function name,
-or for macros by adding `!` after the macro name:
-
-```rust
-/// This is different from [`foo!`]
-fn foo() {}
-
-/// This is different from [`foo()`]
-macro_rules! foo {
- () => {}
-}
-```
-
-## Warnings, re-exports, and scoping
-
-Links are resolved in the scope of the module where the item is defined, even
-when the item is re-exported. If a link from another crate fails to resolve, no
-warning is given.
-
-```rust,edition2018
-mod inner {
- /// Link to [f()]
- pub struct S;
- pub fn f() {}
-}
-pub use inner::S; // the link to `f` will still resolve correctly
-```
-
-When re-exporting an item, rustdoc allows adding additional documentation to it.
-That additional documentation will be resolved in the scope of the re-export, not
-the original, allowing you to link to items in the new crate. The new links
-will still give a warning if they fail to resolve.
-
-```rust
-/// See also [foo()]
-pub use std::process::Command;
-
-pub fn foo() {}
-```
-
-This is especially useful for proc-macros, which must always be defined in their own dedicated crate.
-
-Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a
-`macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the
-module it is defined in.
-
-If links do not look 'sufficiently like' an intra-doc link, they will be ignored and no warning
-will be given, even if the link fails to resolve. For example, any link containing `/` or `[]`
-characters will be ignored.
-
-[#72243]: https://github.com/rust-lang/rust/issues/72243
Here is the list of the lints provided by `rustdoc`:
-## broken_intra_doc_links
+## `broken_intra_doc_links`
This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example:
-[intra-doc link]: linking-to-items-by-name.md
+[intra-doc link]: write-documentation/linking-to-items-by-name.md
```rust
/// I want to link to [`Nonexistent`] but it doesn't exist!
```
-## private_intra_doc_links
+## `private_intra_doc_links`
This lint **warns by default**. This lint detects when [intra-doc links] from public to private items.
For example:
= note: this link resolves only because you passed `--document-private-items`, but will break without
```
-[intra-doc links]: linking-to-items-by-name.html
+[intra-doc links]: write-documentation/linking-to-items-by-name.md
-## missing_docs
+## `missing_docs`
This lint is **allowed by default**. It detects items missing documentation.
For example:
Note that unlike other rustdoc lints, this lint is also available from `rustc` directly.
-## missing_crate_level_docs
+## `missing_crate_level_docs`
This lint is **allowed by default**. It detects if there is no documentation
at the crate root. For example:
get started, without providing overwhelming warnings like `missing_docs`
might.
-## missing_doc_code_examples
+## `missing_doc_code_examples`
This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
is missing a code example. For example:
pub fn no_code_example() {}
```
-## private_doc_tests
+## `private_doc_tests`
This lint is **allowed by default**. It detects documentation tests when they
are on a private item. For example:
| |___________^
```
-## invalid_codeblock_attributes
+## `invalid_codeblock_attributes`
This lint **warns by default**. It detects code block attributes in
documentation examples that have potentially mis-typed values. For example:
In the example above, the correct form is `should_panic`. This helps detect
typo mistakes for some common attributes.
-## invalid_html_tags
+## `invalid_html_tags`
This lint is **allowed by default** and is **nightly-only**. It detects unclosed
or invalid HTML tags. For example:
warning: 2 warnings emitted
```
-## invalid_rust_codeblocks
+## `invalid_rust_codeblocks`
This lint **warns by default**. It detects Rust code blocks in documentation
examples that are invalid (e.g. empty, not parsable as Rust). For example:
= note: error from rustc: unterminated character literal
```
-## bare_urls
+## `bare_urls`
This lint is **warn-by-default**. It detects URLs which are not links.
For example:
+++ /dev/null
-# Passes
-
-Rustdoc has a concept called "passes". These are transformations that
-`rustdoc` runs on your documentation before producing its final output.
-
-Customizing passes is **deprecated**. The available passes are not considered stable and may
-change in any release.
-
-In the past the most common use case for customizing passes was to omit the `strip-private` pass.
-You can do this more easily, and without risk of the pass being changed, by passing
-[`--document-private-items`](./unstable-features.md#--document-private-items).
+++ /dev/null
-# The `#[doc]` attribute
-
-The `#[doc]` attribute lets you control various aspects of how `rustdoc` does
-its job.
-
-The most basic function of `#[doc]` is to handle the actual documentation
-text. That is, `///` is syntax sugar for `#[doc]`. This means that these two
-are the same:
-
-```rust,no_run
-/// This is a doc comment.
-#[doc = " This is a doc comment."]
-# fn f() {}
-```
-
-(Note the leading space in the attribute version.)
-
-In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
-when generating documentation in macros; the `collapse-docs` pass will combine multiple
-`#[doc]` attributes into a single doc comment, letting you generate code like this:
-
-```rust,no_run
-#[doc = "This is"]
-#[doc = " a "]
-#[doc = "doc comment"]
-# fn f() {}
-```
-
-Which can feel more flexible. Note that this would generate this:
-
-```rust,no_run
-#[doc = "This is\n a \ndoc comment"]
-# fn f() {}
-```
-
-but given that docs are rendered via Markdown, it will remove these newlines.
-
-Another use case is for including external files as documentation:
-
-```rust,no_run
-#[doc = include_str!("../README.md")]
-# fn f() {}
-```
-
-The `doc` attribute has more options though! These don't involve the text of
-the output, but instead, various aspects of the presentation of the output.
-We've split them into two kinds below: attributes that are useful at the
-crate level, and ones that are useful at the item level.
-
-## At the crate level
-
-These options control how the docs look at a crate level.
-
-### `html_favicon_url`
-
-This form of the `doc` attribute lets you control the favicon of your docs.
-
-```rust,no_run
-#![doc(html_favicon_url = "https://example.com/favicon.ico")]
-```
-
-This will put `<link rel="icon" href="{}">` into your docs, where
-the string for the attribute goes into the `{}`.
-
-If you don't use this attribute, there will be no favicon.
-
-### `html_logo_url`
-
-This form of the `doc` attribute lets you control the logo in the upper
-left hand side of the docs.
-
-```rust,no_run
-#![doc(html_logo_url = "https://example.com/logo.jpg")]
-```
-
-This will put `<a href='index.html'><img src='{}' alt='logo' width='100'></a>` into
-your docs, where the string for the attribute goes into the `{}`.
-
-If you don't use this attribute, there will be no logo.
-
-### `html_playground_url`
-
-This form of the `doc` attribute lets you control where the "run" buttons
-on your documentation examples make requests to.
-
-```rust,no_run
-#![doc(html_playground_url = "https://playground.example.com/")]
-```
-
-Now, when you press "run", the button will make a request to this domain.
-
-If you don't use this attribute, there will be no run buttons.
-
-### `issue_tracker_base_url`
-
-This form of the `doc` attribute is mostly only useful for the standard library;
-When a feature is unstable, an issue number for tracking the feature must be
-given. `rustdoc` uses this number, plus the base URL given here, to link to
-the tracking issue.
-
-```rust,no_run
-#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
-```
-
-### `html_root_url`
-
-The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
-generating links to external crates. When rustdoc needs to generate a link to
-an item in an external crate, it will first check if the extern crate has been
-documented locally on-disk, and if so link directly to it. Failing that, it
-will use the URL given by the `--extern-html-root-url` command-line flag if
-available. If that is not available, then it will use the `html_root_url`
-value in the extern crate if it is available. If that is not available, then
-the extern items will not be linked.
-
-```rust,no_run
-#![doc(html_root_url = "https://docs.rs/serde/1.0")]
-```
-
-### `html_no_source`
-
-By default, `rustdoc` will include the source code of your program, with links
-to it in the docs. But if you include this:
-
-```rust,no_run
-#![doc(html_no_source)]
-```
-
-it will not.
-
-### `test(no_crate_inject)`
-
-By default, `rustdoc` will automatically add a line with `extern crate my_crate;` into each doctest.
-But if you include this:
-
-```rust,no_run
-#![doc(test(no_crate_inject))]
-```
-
-it will not.
-
-### `test(attr(...))`
-
-This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
-example, if you want your doctests to fail if they produce any warnings, you could add this:
-
-```rust,no_run
-#![doc(test(attr(deny(warnings))))]
-```
-
-## At the item level
-
-These forms of the `#[doc]` attribute are used on individual items, to control how
-they are documented.
-
-### `inline` and `no_inline`
-
-<span id="docno_inlinedocinline"></span>
-
-These attributes are used on `use` statements, and control where the documentation shows
-up. For example, consider this Rust code:
-
-```rust,no_run
-pub use bar::Bar;
-
-/// bar docs
-pub mod bar {
- /// the docs for Bar
- pub struct Bar;
-}
-# fn main() {}
-```
-
-The documentation will generate a "Re-exports" section, and say `pub use bar::Bar;`, where
-`Bar` is a link to its page.
-
-If we change the `use` line like this:
-
-```rust,no_run
-#[doc(inline)]
-pub use bar::Bar;
-# pub mod bar { pub struct Bar; }
-# fn main() {}
-```
-
-Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the
-top level, rather than `pub use`'d.
-
-Let's change our original example, by making `bar` private:
-
-```rust,no_run
-pub use bar::Bar;
-
-/// bar docs
-mod bar {
- /// the docs for Bar
- pub struct Bar;
-}
-# fn main() {}
-```
-
-Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere
-to link to. `rustdoc` will inline these definitions, and so we end up in the same case
-as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at
-the top level. If we add the `no_inline` form of the attribute:
-
-```rust,no_run
-#[doc(no_inline)]
-pub use bar::Bar;
-
-/// bar docs
-mod bar {
- /// the docs for Bar
- pub struct Bar;
-}
-# fn main() {}
-```
-
-Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
-
-One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
-not eagerly inline it as a module unless you add `#[doc(inline)]`.
-
-### `hidden`
-
-<span id="dochidden"></span>
-
-Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
-the `strip-hidden` pass is removed.
-
-### `alias`
-
-This attribute adds an alias in the search index.
-
-Let's take an example:
-
-```rust,no_run
-#[doc(alias = "TheAlias")]
-pub struct SomeType;
-```
-
-So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
-Of course, if you enter `SomeType` it'll return `SomeType` as expected!
-
-#### FFI example
-
-This doc attribute is especially useful when writing bindings for a C library.
-For example, let's say we have a C function that looks like this:
-
-```c
-int lib_name_do_something(Obj *obj);
-```
-
-It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
-be written like this:
-
-```ignore (using non-existing ffi types)
-pub struct Obj {
- inner: *mut ffi::Obj,
-}
-
-impl Obj {
- pub fn do_something(&mut self) -> i32 {
- unsafe { ffi::lib_name_do_something(self.inner) }
- }
-}
-```
-
-The function has been turned into a method to make it more convenient to use.
-However, if you want to look for the Rust equivalent of `lib_name_do_something`,
-you have no way to do so.
-
-To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
-on the `do_something` method and then it's all good!
-Users can now look for `lib_name_do_something` in our crate directly and find
-`Obj::do_something`.
nightly, you can optionally add an error number to state that a doctest should emit a specific error
number:
-[doctest-attributes]: documentation-tests.html#attributes
+[doctest-attributes]: write-documentation/documentation-tests.html#attributes
``````markdown
```compile_fail,E0044
### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
This has two effects:
### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
previous source code:
### Adding your trait to the "Notable traits" dialog
+ * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040)
+
Rustdoc keeps a list of a few traits that are believed to be "fundamental" to
types that implement them. These traits are intended to be the primary interface
for their implementers, and are often most of the API available to be documented
### Exclude certain dependencies from documentation
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
The standard library uses several dependencies which, in turn, use several types and traits from the
standard library. In addition, there are several compiler-internal crates that are not considered to
be part of the official standard library, and thus would be a distraction to include in
[unstable-masked]: ../unstable-book/language-features/doc-masked.html
[issue-masked]: https://github.com/rust-lang/rust/issues/44027
-
-## Document primitives
+### Document primitives
This is for Rust compiler internal use only.
to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
enable.
-## Document keywords
+### Document keywords
This is for Rust compiler internal use only.
### `--markdown-before-content`: include rendered Markdown before the content
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
Using this flag looks like this:
```bash
https://play.rust-lang.org does not have every crate available, so if your examples require your
crate, make sure the playground you provide has your crate available.
-[doc-playground]: the-doc-attribute.html#html_playground_url
+[doc-playground]: write-documentation/the-doc-attribute.html#html_playground_url
If both `--playground-url` and `--markdown-playground-url` are present when rendering a standalone
Markdown file, the URL given to `--markdown-playground-url` will take precedence. If both
### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
+ * Tracking issue: [#54765](https://github.com/rust-lang/rust/issues/54765)
+
Using this flag looks like this:
```bash
This feature allows the generation of a default index-page which lists the generated crates.
+### `--nocapture`: disable output capture for test
+
+When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
+captured by rustdoc. Instead, the output will be directed to your terminal,
+as if you had run the test executable manually. This is especially useful
+for debugging your tests!
+
+### `--check`: only checks the documentation
+
+When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
+documentation or run your doctests.
+
+Using this flag looks like:
+
+```bash
+rustdoc -Z unstable-options --check src/lib.rs
+```
+
### `--static-root-path`: control how static files are loaded in HTML output
Using this flag looks like this:
### `--persist-doctests`: persist doctest executables after running
+ * Tracking issue: [#56925](https://github.com/rust-lang/rust/issues/56925)
+
Using this flag looks like this:
```bash
### `--show-coverage`: calculate the percentage of items with documentation
+ * Tracking issue: [#58154](https://github.com/rust-lang/rust/issues/58154)
+
Using this flag looks like this:
```bash
### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
Using this flag looks like this:
```bash
### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
Using these options looks like this:
```bash
### `--with-examples`: include examples of uses of items as documentation
+ * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
+
This option, combined with `--scrape-examples-target-crate` and
`--scrape-examples-output-path`, is used to implement the functionality in [RFC
#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
### `--check-cfg`: check configuration flags
+ * Tracking issue: [#82450](https://github.com/rust-lang/rust/issues/82450)
+
This flag accepts the same values as `rustc --check-cfg`, and uses it to check configuration flags.
Using this flag looks like this:
+++ /dev/null
-# Website features
-
-These features are about using the website generated by `rustdoc`.
-
-## Custom search engines
-
-If you find yourself often referencing online Rust docs you might enjoy using a custom search
-engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
-Most browsers support this feature by letting you define a URL template containing `%s`
-which will be substituted for the search term. As an example, for the standard library you could use
-this template:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s
-```
-
-Note that this will take you to a results page listing all matches. If you want to navigate to the first
-result right away (which is often the best match) use the following instead:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
-```
-
-This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
-to automatically go to the first result.
+++ /dev/null
-# What to include (and exclude)
-
-It is easy to say everything must be documented in a project and often times
-that is correct, but how can we get there, and are there things that don't
-belong?
-
-At the top of the `src/lib.rs` or `main.rs` file in your binary project, include
-the following attribute:
-
-```rust
-#![warn(missing_docs)]
-```
-
-Now run `cargo doc` and examine the output. Here's a sample:
-
-```text
- Documenting docdemo v0.1.0 (/Users/username/docdemo)
-warning: missing documentation for the crate
- --> src/main.rs:1:1
- |
-1 | / #![warn(missing_docs)]
-2 | |
-3 | | fn main() {
-4 | | println!("Hello, world!");
-5 | | }
- | |_^
- |
-note: the lint level is defined here
- --> src/main.rs:1:9
- |
-1 | #![warn(missing_docs)]
- | ^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
- Finished dev [unoptimized + debuginfo] target(s) in 2.96s
-```
-
-As a library author, adding the lint `#![deny(missing_docs)]` is a great way to
-ensure the project does not drift away from being documented well, and
-`#![warn(missing_docs)]` is a good way to move towards comprehensive
-documentation. In addition to docs, `#![deny(missing_doc_code_examples)]`
-ensures each function contains a usage example. In our example above, the
-warning is resolved by adding crate level documentation.
-
-There are more lints in the upcoming chapter [Lints][rustdoc-lints].
-
-## Examples
-
-Of course this is contrived to be simple, but part of the power of documentation
-is showing code that is easy to follow, rather than being realistic. Docs often
-take shortcuts with error handling because examples can become complicated to
-follow with all the necessary set up required for a simple example.
-
-`Async` is a good example of this. In order to execute an `async` example, an
-executor needs to be available. Examples will often shortcut this, and leave
-users to figure out how to put the `async` code into their own runtime.
-
-It is preferred that `unwrap()` not be used inside an example, and some of the
-error handling components be hidden if they make the example too difficult to
-follow.
-
-``````text
-/// Example
-/// ```rust
-/// let fourtytwo = "42".parse::<u32>()?;
-/// println!("{} + 10 = {}", fourtytwo, fourtytwo+10);
-/// ```
-``````
-
-When rustdoc wraps that in a main function, it will fail to compile because the
-`ParseIntError` trait is not implemented. In order to help both your audience
-and your test suite, this example needs some additional code:
-
-``````text
-/// Example
-/// ```rust
-/// # main() -> Result<(), std::num::ParseIntError> {
-/// let fortytwo = "42".parse::<u32>()?;
-/// println!("{} + 10 = {}", fortytwo, fortytwo+10);
-/// # Ok(())
-/// # }
-/// ```
-``````
-
-The example is the same on the doc page, but has that extra information
-available to anyone trying to use your crate. More about tests in the
-upcoming [Documentation tests] chapter.
-
-## What to Exclude
-
-Certain parts of your public interface may be included by default in the output
-of rustdoc. The attribute `#[doc(hidden)]` can hide implementation details
-to encourage idiomatic use of the crate.
-
-For example, an internal `macro!` that makes the crate easier to implement can
-become a footgun for users when it appears in the public documentation. An
-internal `Error` type may exist, and `impl` details should be hidden, as
-detailed in the [API Guidelines].
-
-## Customizing the output
-
-It is possible to pass a custom css file to `rustdoc` and style the
-documentation.
-
-```bash
-rustdoc --extend-css custom.css src/lib.rs
-```
-
-A good example of using this feature to create a dark theme is documented [on
-this blog]. Just remember, dark theme is already included in the rustdoc output
-by clicking on the paintbrush. Adding additional options to the themes are
-as easy as creating a custom theme `.css` file and using the following syntax:
-
-```bash
-rustdoc --theme awesome.css src/lib.rs
-```
-
-Here is an example of a new theme, [Ayu].
-
-[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css
-[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
-[Documentation tests]: documentation-tests.md
-[on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
-[rustdoc-lints]: lints.md
--- /dev/null
+# Documentation tests
+
+`rustdoc` supports executing your documentation examples as tests. This makes sure
+that examples within your documentation are up to date and working.
+
+The basic idea is this:
+
+```rust,no_run
+/// # Examples
+///
+/// ```
+/// let x = 5;
+/// ```
+# fn f() {}
+```
+
+The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
+running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
+
+Please note that by default, if no language is set for the block code, rustdoc
+assumes it is Rust code. So the following:
+
+``````markdown
+```rust
+let x = 5;
+```
+``````
+
+is strictly equivalent to:
+
+``````markdown
+```
+let x = 5;
+```
+``````
+
+There's some subtlety though! Read on for more details.
+
+## Passing or failing a doctest
+
+Like regular unit tests, regular doctests are considered to "pass"
+if they compile and run without panicking.
+So if you want to demonstrate that some computation gives a certain result,
+the `assert!` family of macros works the same as other Rust code:
+
+```rust
+let foo = "foo";
+assert_eq!(foo, "foo");
+```
+
+This way, if the computation ever returns something different,
+the code panics and the doctest fails.
+
+## Pre-processing examples
+
+In the example above, you'll note something strange: there's no `main`
+function! Forcing you to write `main` for every example, no matter how small,
+adds friction and clutters the output. So `rustdoc` processes your examples
+slightly before running them. Here's the full algorithm `rustdoc` uses to
+preprocess examples:
+
+1. Some common `allow` attributes are inserted, including
+ `unused_variables`, `unused_assignments`, `unused_mut`,
+ `unused_attributes`, and `dead_code`. Small examples often trigger
+ these lints.
+2. Any attributes specified with `#![doc(test(attr(...)))]` are added.
+3. Any leading `#![foo]` attributes are left intact as crate attributes.
+4. If the example does not contain `extern crate`, and
+ `#![doc(test(no_crate_inject))]` was not specified, then `extern crate
+ <mycrate>;` is inserted (note the lack of `#[macro_use]`).
+5. Finally, if the example does not contain `fn main`, the remainder of the
+ text is wrapped in `fn main() { your_code }`.
+
+For more about that caveat in rule 4, see "Documenting Macros" below.
+
+## Hiding portions of the example
+
+Sometimes, you need some setup code, or other things that would distract
+from your example, but are important to make the tests work. Consider
+an example block that looks like this:
+
+```rust,no_run
+/// ```
+/// /// Some documentation.
+/// # fn foo() {} // this function will be hidden
+/// println!("Hello, World!");
+/// ```
+# fn f() {}
+```
+
+It will render like this:
+
+```rust
+/// Some documentation.
+# fn foo() {}
+println!("Hello, World!");
+```
+
+Yes, that's right: you can add lines that start with `# `, and they will
+be hidden from the output, but will be used when compiling your code. You
+can use this to your advantage. In this case, documentation comments need
+to apply to some kind of function, so if I want to show you just a
+documentation comment, I need to add a little function definition below
+it. At the same time, it's only there to satisfy the compiler, so hiding
+it makes the example more clear. You can use this technique to explain
+longer examples in detail, while still preserving the testability of your
+documentation.
+
+For example, imagine that we wanted to document this code:
+
+```rust
+let x = 5;
+let y = 6;
+println!("{}", x + y);
+```
+
+We might want the documentation to end up looking like this:
+
+> First, we set `x` to five:
+>
+> ```rust
+> let x = 5;
+> # let y = 6;
+> # println!("{}", x + y);
+> ```
+>
+> Next, we set `y` to six:
+>
+> ```rust
+> # let x = 5;
+> let y = 6;
+> # println!("{}", x + y);
+> ```
+>
+> Finally, we print the sum of `x` and `y`:
+>
+> ```rust
+> # let x = 5;
+> # let y = 6;
+> println!("{}", x + y);
+> ```
+
+To keep each code block testable, we want the whole program in each block, but
+we don't want the reader to see every line every time. Here's what we put in
+our source code:
+
+``````markdown
+First, we set `x` to five:
+
+```
+let x = 5;
+# let y = 6;
+# println!("{}", x + y);
+```
+
+Next, we set `y` to six:
+
+```
+# let x = 5;
+let y = 6;
+# println!("{}", x + y);
+```
+
+Finally, we print the sum of `x` and `y`:
+
+```
+# let x = 5;
+# let y = 6;
+println!("{}", x + y);
+```
+``````
+
+By repeating all parts of the example, you can ensure that your example still
+compiles, while only showing the parts that are relevant to that part of your
+explanation.
+
+The `#`-hiding of lines can be prevented by using two consecutive hashes
+`##`. This only needs to be done with the first `#` which would've
+otherwise caused hiding. If we have a string literal like the following,
+which has a line that starts with a `#`:
+
+```rust
+let s = "foo
+## bar # baz";
+```
+
+We can document it by escaping the initial `#`:
+
+```text
+/// let s = "foo
+/// ## bar # baz";
+```
+
+
+## Using `?` in doc tests
+
+When writing an example, it is rarely useful to include a complete error
+handling, as it would add significant amounts of boilerplate code. Instead, you
+may want the following:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// ```
+# fn f() {}
+```
+
+The problem is that `?` returns a `Result<T, E>` and test functions don't
+return anything, so this will give a mismatched types error.
+
+You can get around this limitation by manually adding a `main` that returns
+`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
+
+```rust,no_run
+/// A doc test using ?
+///
+/// ```
+/// use std::io;
+///
+/// fn main() -> io::Result<()> {
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// Ok(())
+/// }
+/// ```
+# fn f() {}
+```
+
+Together with the `# ` from the section above, you arrive at a solution that
+appears to the reader as the initial idea but works with doc tests:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// # fn main() -> io::Result<()> {
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// # Ok(())
+/// # }
+/// ```
+# fn f() {}
+```
+
+As of version 1.34.0, one can also omit the `fn main()`, but you will have to
+disambiguate the error type:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// # Ok::<(), io::Error>(())
+/// ```
+# fn f() {}
+```
+
+This is an unfortunate consequence of the `?` operator adding an implicit
+conversion, so type inference fails because the type is not unique. Please note
+that you must write the `(())` in one sequence without intermediate whitespace
+so that `rustdoc` understands you want an implicit `Result`-returning function.
+
+## Showing warnings in doctests
+
+You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
+(or, if you're using cargo, `cargo test --doc -- --show-output`).
+By default, this will still hide `unused` warnings, since so many examples use private functions;
+you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
+You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
+
+[test-attr]: the-doc-attribute.md#testattr
+
+## Documenting macros
+
+Here’s an example of documenting a macro:
+
+```rust
+/// Panic with a given message unless an expression evaluates to true.
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(1 + 1 == 2, “Math is broken.”);
+/// # }
+/// ```
+///
+/// ```should_panic
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(true == false, “I’m broken.”);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! panic_unless {
+ ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
+}
+# fn main() {}
+```
+
+You’ll note three things: we need to add our own `extern crate` line, so that
+we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
+`main()` as well (for reasons discussed above). Finally, a judicious use of
+`#` to comment out those two things, so they don’t show up in the output.
+
+## Attributes
+
+Code blocks can be annotated with attributes that help `rustdoc` do the right
+thing when testing your code:
+
+The `ignore` attribute tells Rust to ignore your code. This is almost never
+what you want as it's the most generic. Instead, consider annotating it
+with `text` if it's not code or using `#`s to get a working example that
+only shows the part you care about.
+
+```rust
+/// ```ignore
+/// fn foo() {
+/// ```
+# fn foo() {}
+```
+
+`should_panic` tells `rustdoc` that the code should compile correctly but
+panic during execution. If the code doesn't panic, the test will fail.
+
+```rust
+/// ```should_panic
+/// assert!(false);
+/// ```
+# fn foo() {}
+```
+
+The `no_run` attribute will compile your code but not run it. This is
+important for examples such as "Here's how to retrieve a web page,"
+which you would want to ensure compiles, but might be run in a test
+environment that has no network access. This attribute can also be
+used to demonstrate code snippets that can cause Undefined Behavior.
+
+```rust
+/// ```no_run
+/// loop {
+/// println!("Hello, world");
+/// }
+/// ```
+# fn foo() {}
+```
+
+`compile_fail` tells `rustdoc` that the compilation should fail. If it
+compiles, then the test will fail. However, please note that code failing
+with the current Rust release may work in a future release, as new features
+are added.
+
+```rust
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+# fn foo() {}
+```
+
+`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
+that the code sample should be compiled using the respective edition of Rust.
+
+```rust
+/// Only runs on the 2018 edition.
+///
+/// ```edition2018
+/// let result: Result<i32, ParseIntError> = try {
+/// "1".parse::<i32>()?
+/// + "2".parse::<i32>()?
+/// + "3".parse::<i32>()?
+/// };
+/// ```
+# fn foo() {}
+```
+
+## Syntax reference
+
+The *exact* syntax for code blocks, including the edge cases, can be found
+in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
+section of the CommonMark specification.
+
+Rustdoc also accepts *indented* code blocks as an alternative to fenced
+code blocks: instead of surrounding your code with three backticks, you
+can indent each line by four or more spaces.
+
+``````markdown
+ let foo = "foo";
+ assert_eq!(foo, "foo");
+``````
+
+These, too, are documented in the CommonMark specification, in the
+[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
+section.
+
+However, it's preferable to use fenced code blocks over indented code blocks.
+Not only are fenced code blocks considered more idiomatic for Rust code,
+but there is no way to use attributes such as `ignore` or `should_panic` with
+indented code blocks.
+
+### Include items only when collecting doctests
+
+Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
+sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
+documentation. To this end, Rustdoc allows you to have certain items only appear when it's
+collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
+docs, or to find an arbitrary private item to include it on.
+
+When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
+Note that they will still link against only the public items of your crate; if you need to test
+private items, you need to write a unit test.
+
+In this example, we're adding doctests that we know won't compile, to verify that our struct can
+only take in valid data:
+
+```rust
+/// We have a struct here. Remember it doesn't accept negative numbers!
+pub struct MyStruct(pub usize);
+
+/// ```compile_fail
+/// let x = my_crate::MyStruct(-5);
+/// ```
+#[cfg(doctest)]
+pub struct MyStructOnlyTakesUsize;
+```
+
+Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
+API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
+collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
+but is hidden from the public documentation.
+
+Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
+without including it in your main documentation. For example, you could write this into your
+`lib.rs` to test your README as part of your doctests:
+
+```rust,no_run
+#[doc = include_str!("../README.md")]
+#[cfg(doctest)]
+pub struct ReadmeDoctests;
+```
+
+This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
+then be tested alongside the rest of your doctests.
--- /dev/null
+# Linking to items by name
+
+Rustdoc is capable of directly linking to other rustdoc pages using the path of
+the item as a link. This is referred to as an 'intra-doc link'.
+
+For example, in the following code all of the links will link to the rustdoc page for `Bar`:
+
+```rust
+/// This struct is not [Bar]
+pub struct Foo1;
+
+/// This struct is also not [bar](Bar)
+pub struct Foo2;
+
+/// This struct is also not [bar][b]
+///
+/// [b]: Bar
+pub struct Foo3;
+
+/// This struct is also not [`Bar`]
+pub struct Foo4;
+
+/// This struct *is* [`Bar`]!
+pub struct Bar;
+```
+
+Unlike normal Markdown, `[bar][Bar]` syntax is also supported without needing a
+`[Bar]: ...` reference link.
+
+Backticks around the link will be stripped, so ``[`Option`]`` will correctly
+link to `Option`.
+
+## Valid links
+
+You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and
+`crate`. Associated items (functions, types, and constants) are supported, but [not for blanket
+trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in
+[the standard library documentation](../../std/index.html#primitives).
+
+[#79682]: https://github.com/rust-lang/rust/pull/79682
+
+You can also refer to items with generic parameters like `Vec<T>`. The link will
+resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
+`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
+
+[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
+
+```rust,edition2018
+use std::sync::mpsc::Receiver;
+
+/// This is a version of [`Receiver<T>`] with support for [`std::future`].
+///
+/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
+pub struct AsyncReceiver<T> {
+ sender: Receiver<T>
+}
+
+impl<T> AsyncReceiver<T> {
+ pub async fn recv() -> T {
+ unimplemented!()
+ }
+}
+```
+
+Rustdoc allows using URL fragment specifiers, just like a normal link:
+
+```rust
+/// This is a special implementation of [positional parameters].
+///
+/// [positional parameters]: std::fmt#formatting-parameters
+struct MySpecialFormatter;
+```
+
+## Namespaces and Disambiguators
+
+Paths in Rust have three namespaces: type, value, and macro. Item names must be unique within
+their namespace, but can overlap with items in other namespaces. In case of ambiguity,
+rustdoc will warn about the ambiguity and suggest a disambiguator.
+
+```rust
+/// See also: [`Foo`](struct@Foo)
+struct Bar;
+
+/// This is different from [`Foo`](fn@Foo)
+struct Foo {}
+
+fn Foo() {}
+```
+
+These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
+rendered as `Foo`.
+
+You can also disambiguate for functions by adding `()` after the function name,
+or for macros by adding `!` after the macro name:
+
+```rust
+/// This is different from [`foo!`]
+fn foo() {}
+
+/// This is different from [`foo()`]
+macro_rules! foo {
+ () => {}
+}
+```
+
+## Warnings, re-exports, and scoping
+
+Links are resolved in the scope of the module where the item is defined, even
+when the item is re-exported. If a link from another crate fails to resolve, no
+warning is given.
+
+```rust,edition2018
+mod inner {
+ /// Link to [f()]
+ pub struct S;
+ pub fn f() {}
+}
+pub use inner::S; // the link to `f` will still resolve correctly
+```
+
+When re-exporting an item, rustdoc allows adding additional documentation to it.
+That additional documentation will be resolved in the scope of the re-export, not
+the original, allowing you to link to items in the new crate. The new links
+will still give a warning if they fail to resolve.
+
+```rust
+/// See also [foo()]
+pub use std::process::Command;
+
+pub fn foo() {}
+```
+
+This is especially useful for proc-macros, which must always be defined in their own dedicated crate.
+
+Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a
+`macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the
+module it is defined in.
+
+If links do not look 'sufficiently like' an intra-doc link, they will be ignored and no warning
+will be given, even if the link fails to resolve. For example, any link containing `/` or `[]`
+characters will be ignored.
+
+[#72243]: https://github.com/rust-lang/rust/issues/72243
--- /dev/null
+# The `#[doc]` attribute
+
+The `#[doc]` attribute lets you control various aspects of how `rustdoc` does
+its job.
+
+The most basic function of `#[doc]` is to handle the actual documentation
+text. That is, `///` is syntax sugar for `#[doc]`. This means that these two
+are the same:
+
+```rust,no_run
+/// This is a doc comment.
+#[doc = " This is a doc comment."]
+# fn f() {}
+```
+
+(Note the leading space in the attribute version.)
+
+In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
+when generating documentation in macros; the `collapse-docs` pass will combine multiple
+`#[doc]` attributes into a single doc comment, letting you generate code like this:
+
+```rust,no_run
+#[doc = "This is"]
+#[doc = " a "]
+#[doc = "doc comment"]
+# fn f() {}
+```
+
+Which can feel more flexible. Note that this would generate this:
+
+```rust,no_run
+#[doc = "This is\n a \ndoc comment"]
+# fn f() {}
+```
+
+but given that docs are rendered via Markdown, it will remove these newlines.
+
+Another use case is for including external files as documentation:
+
+```rust,no_run
+#[doc = include_str!("../../README.md")]
+# fn f() {}
+```
+
+The `doc` attribute has more options though! These don't involve the text of
+the output, but instead, various aspects of the presentation of the output.
+We've split them into two kinds below: attributes that are useful at the
+crate level, and ones that are useful at the item level.
+
+## At the crate level
+
+These options control how the docs look at a crate level.
+
+### `html_favicon_url`
+
+This form of the `doc` attribute lets you control the favicon of your docs.
+
+```rust,no_run
+#![doc(html_favicon_url = "https://example.com/favicon.ico")]
+```
+
+This will put `<link rel="icon" href="{}">` into your docs, where
+the string for the attribute goes into the `{}`.
+
+If you don't use this attribute, there will be no favicon.
+
+### `html_logo_url`
+
+This form of the `doc` attribute lets you control the logo in the upper
+left hand side of the docs.
+
+```rust,no_run
+#![doc(html_logo_url = "https://example.com/logo.jpg")]
+```
+
+This will put `<a href='../index.html'><img src='{}' alt='logo' width='100'></a>` into
+your docs, where the string for the attribute goes into the `{}`.
+
+If you don't use this attribute, there will be no logo.
+
+### `html_playground_url`
+
+This form of the `doc` attribute lets you control where the "run" buttons
+on your documentation examples make requests to.
+
+```rust,no_run
+#![doc(html_playground_url = "https://playground.example.com/")]
+```
+
+Now, when you press "run", the button will make a request to this domain.
+
+If you don't use this attribute, there will be no run buttons.
+
+### `issue_tracker_base_url`
+
+This form of the `doc` attribute is mostly only useful for the standard library;
+When a feature is unstable, an issue number for tracking the feature must be
+given. `rustdoc` uses this number, plus the base URL given here, to link to
+the tracking issue.
+
+```rust,no_run
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+```
+
+### `html_root_url`
+
+The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
+generating links to external crates. When rustdoc needs to generate a link to
+an item in an external crate, it will first check if the extern crate has been
+documented locally on-disk, and if so link directly to it. Failing that, it
+will use the URL given by the `--extern-html-root-url` command-line flag if
+available. If that is not available, then it will use the `html_root_url`
+value in the extern crate if it is available. If that is not available, then
+the extern items will not be linked.
+
+```rust,no_run
+#![doc(html_root_url = "https://docs.rs/serde/1.0")]
+```
+
+### `html_no_source`
+
+By default, `rustdoc` will include the source code of your program, with links
+to it in the docs. But if you include this:
+
+```rust,no_run
+#![doc(html_no_source)]
+```
+
+it will not.
+
+### `test(no_crate_inject)`
+
+By default, `rustdoc` will automatically add a line with `extern crate my_crate;` into each doctest.
+But if you include this:
+
+```rust,no_run
+#![doc(test(no_crate_inject))]
+```
+
+it will not.
+
+### `test(attr(...))`
+
+This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
+example, if you want your doctests to fail if they produce any warnings, you could add this:
+
+```rust,no_run
+#![doc(test(attr(deny(warnings))))]
+```
+
+## At the item level
+
+These forms of the `#[doc]` attribute are used on individual items, to control how
+they are documented.
+
+### `inline` and `no_inline`
+
+<span id="docno_inlinedocinline"></span>
+
+These attributes are used on `use` statements, and control where the documentation shows
+up. For example, consider this Rust code:
+
+```rust,no_run
+pub use bar::Bar;
+
+/// bar docs
+pub mod bar {
+ /// the docs for Bar
+ pub struct Bar;
+}
+# fn main() {}
+```
+
+The documentation will generate a "Re-exports" section, and say `pub use bar::Bar;`, where
+`Bar` is a link to its page.
+
+If we change the `use` line like this:
+
+```rust,no_run
+#[doc(inline)]
+pub use bar::Bar;
+# pub mod bar { pub struct Bar; }
+# fn main() {}
+```
+
+Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the
+top level, rather than `pub use`'d.
+
+Let's change our original example, by making `bar` private:
+
+```rust,no_run
+pub use bar::Bar;
+
+/// bar docs
+mod bar {
+ /// the docs for Bar
+ pub struct Bar;
+}
+# fn main() {}
+```
+
+Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere
+to link to. `rustdoc` will inline these definitions, and so we end up in the same case
+as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at
+the top level. If we add the `no_inline` form of the attribute:
+
+```rust,no_run
+#[doc(no_inline)]
+pub use bar::Bar;
+
+/// bar docs
+mod bar {
+ /// the docs for Bar
+ pub struct Bar;
+}
+# fn main() {}
+```
+
+Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
+
+One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
+not eagerly inline it as a module unless you add `#[doc(inline)]`.
+
+### `hidden`
+
+<span id="dochidden"></span>
+
+Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
+the `strip-hidden` pass is removed.
+
+### `alias`
+
+This attribute adds an alias in the search index.
+
+Let's take an example:
+
+```rust,no_run
+#[doc(alias = "TheAlias")]
+pub struct SomeType;
+```
+
+So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
+Of course, if you enter `SomeType` it'll return `SomeType` as expected!
+
+#### FFI example
+
+This doc attribute is especially useful when writing bindings for a C library.
+For example, let's say we have a C function that looks like this:
+
+```c
+int lib_name_do_something(Obj *obj);
+```
+
+It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
+be written like this:
+
+```ignore (using non-existing ffi types)
+pub struct Obj {
+ inner: *mut ffi::Obj,
+}
+
+impl Obj {
+ pub fn do_something(&mut self) -> i32 {
+ unsafe { ffi::lib_name_do_something(self.inner) }
+ }
+}
+```
+
+The function has been turned into a method to make it more convenient to use.
+However, if you want to look for the Rust equivalent of `lib_name_do_something`,
+you have no way to do so.
+
+To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
+on the `do_something` method and then it's all good!
+Users can now look for `lib_name_do_something` in our crate directly and find
+`Obj::do_something`.
--- /dev/null
+# What to include (and exclude)
+
+It is easy to say everything must be documented in a project and often times
+that is correct, but how can we get there, and are there things that don't
+belong?
+
+At the top of the `src/lib.rs` or `main.rs` file in your binary project, include
+the following attribute:
+
+```rust
+#![warn(missing_docs)]
+```
+
+Now run `cargo doc` and examine the output. Here's a sample:
+
+```text
+ Documenting docdemo v0.1.0 (/Users/username/docdemo)
+warning: missing documentation for the crate
+ --> src/main.rs:1:1
+ |
+1 | / #![warn(missing_docs)]
+2 | |
+3 | | fn main() {
+4 | | println!("Hello, world!");
+5 | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> src/main.rs:1:9
+ |
+1 | #![warn(missing_docs)]
+ | ^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
+ Finished dev [unoptimized + debuginfo] target(s) in 2.96s
+```
+
+As a library author, adding the lint `#![deny(missing_docs)]` is a great way to
+ensure the project does not drift away from being documented well, and
+`#![warn(missing_docs)]` is a good way to move towards comprehensive
+documentation. In addition to docs, `#![deny(missing_doc_code_examples)]`
+ensures each function contains a usage example. In our example above, the
+warning is resolved by adding crate level documentation.
+
+There are more lints in the upcoming chapter [Lints][rustdoc-lints].
+
+## Examples
+
+Of course this is contrived to be simple, but part of the power of documentation
+is showing code that is easy to follow, rather than being realistic. Docs often
+take shortcuts with error handling because examples can become complicated to
+follow with all the necessary set up required for a simple example.
+
+`Async` is a good example of this. In order to execute an `async` example, an
+executor needs to be available. Examples will often shortcut this, and leave
+users to figure out how to put the `async` code into their own runtime.
+
+It is preferred that `unwrap()` not be used inside an example, and some of the
+error handling components be hidden if they make the example too difficult to
+follow.
+
+``````text
+/// Example
+/// ```rust
+/// let fourtytwo = "42".parse::<u32>()?;
+/// println!("{} + 10 = {}", fourtytwo, fourtytwo+10);
+/// ```
+``````
+
+When rustdoc wraps that in a main function, it will fail to compile because the
+`ParseIntError` trait is not implemented. In order to help both your audience
+and your test suite, this example needs some additional code:
+
+``````text
+/// Example
+/// ```rust
+/// # main() -> Result<(), std::num::ParseIntError> {
+/// let fortytwo = "42".parse::<u32>()?;
+/// println!("{} + 10 = {}", fortytwo, fortytwo+10);
+/// # Ok(())
+/// # }
+/// ```
+``````
+
+The example is the same on the doc page, but has that extra information
+available to anyone trying to use your crate. More about tests in the
+upcoming [Documentation tests] chapter.
+
+## What to Exclude
+
+Certain parts of your public interface may be included by default in the output
+of rustdoc. The attribute `#[doc(hidden)]` can hide implementation details
+to encourage idiomatic use of the crate.
+
+For example, an internal `macro!` that makes the crate easier to implement can
+become a footgun for users when it appears in the public documentation. An
+internal `Error` type may exist, and `impl` details should be hidden, as
+detailed in the [API Guidelines].
+
+## Customizing the output
+
+It is possible to pass a custom css file to `rustdoc` and style the
+documentation.
+
+```bash
+rustdoc --extend-css custom.css src/lib.rs
+```
+
+A good example of using this feature to create a dark theme is documented [on
+this blog]. Just remember, dark theme is already included in the rustdoc output
+by clicking on the paintbrush. Adding additional options to the themes are
+as easy as creating a custom theme `.css` file and using the following syntax:
+
+```bash
+rustdoc --theme awesome.css src/lib.rs
+```
+
+Here is an example of a new theme, [Ayu].
+
+[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css
+[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
+[Documentation tests]: documentation-tests.md
+[on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
+[rustdoc-lints]: ../lints.md
fn main() {
let answer = do_twice(add_one, 5);
- println!("The answer is: {}", answer);
+ println!("The answer is: {answer}");
println!("With CFI enabled, you should not see the next answer");
let f: fn(i32) -> i32 = unsafe {
};
let next_answer = do_twice(f, 5);
- println!("The next answer is: {}", next_answer);
+ println!("The next answer is: {next_answer}");
}
```
Fig. 1. Modified example from the [Advanced Functions and
fn main() {
let answer = do_twice(add_one, 5);
- println!("The answer is: {}", answer);
+ println!("The answer is: {answer}");
println!("With CFI enabled, you should not see the next answer");
let f: fn(i32) -> i32 =
unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
let next_answer = do_twice(f, 5);
- println!("The next answer is: {}", next_answer);
+ println!("The next answer is: {next_answer}");
}
```
Fig. 4. Another modified example from the [Advanced Functions and
let b = Some(Box::new(5));
match b {
Some(box n) if n < 0 => {
- println!("Box contains negative number {}", n);
+ println!("Box contains negative number {n}");
},
Some(box n) if n >= 0 => {
- println!("Box contains non-negative number {}", n);
+ println!("Box contains non-negative number {n}");
},
None => {
println!("No box");
askama = { version = "0.11", default-features = false, features = ["config"] }
atty = "0.2"
pulldown-cmark = { version = "0.9", default-features = false }
-minifier = "0.0.42"
+minifier = "0.0.43"
rayon = "1.5.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smallvec = "1.6.1"
tempfile = "3"
-itertools = "0.10"
+itertools = "0.10.1"
regex = "1"
rustdoc-json-types = { path = "../rustdoc-json-types" }
tracing = "0.1"
PathSegment {
name: item.name,
args: GenericArgs::AngleBracketed {
- args: ty.substs[generics.parent_count..]
- .iter()
- .map(|ty| match ty.unpack() {
- ty::subst::GenericArgKind::Lifetime(lt) => {
- GenericArg::Lifetime(lt.clean(cx).unwrap())
- }
- ty::subst::GenericArgKind::Type(ty) => GenericArg::Type(ty.clean(cx)),
- ty::subst::GenericArgKind::Const(c) => GenericArg::Const(Box::new(c.clean(cx))),
- })
- .collect(),
+ args: substs_to_args(cx, &ty.substs[generics.parent_count..], false),
bindings: Default::default(),
},
}
},
)
}
- ty::GenericParamDefKind::Const { has_default, .. } => (
+ ty::GenericParamDefKind::Const { has_default } => (
self.name,
GenericParamDefKind::Const {
did: self.def_id,
.values
.insert(a as _, Argument { name, type_: *ty, is_const: true });
} else {
- panic!("unexpected non const in position {}", pos);
+ panic!("unexpected non const in position {pos}");
}
}
_ => panic!("invalid arg index"),
});
if let Some(lt) = lifetime.cloned() {
let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() {
- lt.clean(cx)
- } else {
- self::types::Lifetime::elided()
- };
+ let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
}
indices.lifetimes += 1;
Crate { module, primitives, external_traits: cx.external_traits.clone() }
}
-fn external_generic_args(
+crate fn substs_to_args(
cx: &mut DocContext<'_>,
- did: DefId,
- has_self: bool,
- bindings: Vec<TypeBinding>,
- substs: SubstsRef<'_>,
-) -> GenericArgs {
- let mut skip_self = has_self;
- let mut ty_kind = None;
- let args: Vec<_> = substs
+ substs: &[ty::subst::GenericArg<'_>],
+ mut skip_first: bool,
+) -> Vec<GenericArg> {
+ substs
.iter()
.filter_map(|kind| match kind.unpack() {
GenericArgKind::Lifetime(lt) => match *lt {
}
_ => lt.clean(cx).map(GenericArg::Lifetime),
},
- GenericArgKind::Type(_) if skip_self => {
- skip_self = false;
+ GenericArgKind::Type(_) if skip_first => {
+ skip_first = false;
None
}
- GenericArgKind::Type(ty) => {
- ty_kind = Some(ty.kind());
- Some(GenericArg::Type(ty.clean(cx)))
- }
+ GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))),
})
- .collect();
+ .collect()
+}
+
+fn external_generic_args(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ has_self: bool,
+ bindings: Vec<TypeBinding>,
+ substs: SubstsRef<'_>,
+) -> GenericArgs {
+ let args = substs_to_args(cx, &substs, has_self);
if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
- let inputs = match ty_kind.unwrap() {
- ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
- _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
- };
+ let inputs =
+ // The trait's first substitution is the one after self, if there is one.
+ match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
+ ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
+ _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
+ };
let output = None;
// FIXME(#20299) return type comes from a projection now
// match types[1].kind {
.to_string();
let uext = UnusedExterns { lint_level, unused_extern_names };
let unused_extern_json = serde_json::to_string(&uext).unwrap();
- eprintln!("{}", unused_extern_json);
+ eprintln!("{unused_extern_json}");
}
}
// We used to check if the output contained "error[{}]: " but since we added the
// colored output, we can't anymore because of the color escape characters before
// the ":".
- lang_string.error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
+ lang_string.error_codes.retain(|err| !out.contains(&format!("error[{err}]")));
if !lang_string.error_codes.is_empty() {
return Err(TestFailure::MissingErrorCodes(lang_string.error_codes));
// Next, any attributes that came from the crate root via #![doc(test(attr(...)))].
for attr in &opts.attrs {
- prog.push_str(&format!("#![{}]\n", attr));
+ prog.push_str(&format!("#![{attr}]\n"));
line_offset += 1;
}
// parse the source, but only has false positives, not false
// negatives.
if s.contains(crate_name) {
- prog.push_str(&format!("extern crate r#{};\n", crate_name));
+ prog.push_str(&format!("extern crate r#{crate_name};\n"));
line_offset += 1;
}
}
// Give each doctest main function a unique name.
// This is for example needed for the tooling around `-C instrument-coverage`.
let inner_fn_name = if let Some(test_id) = test_id {
- format!("_doctest_main_{}", test_id)
+ format!("_doctest_main_{test_id}")
} else {
"_inner".into()
};
let (main_pre, main_post) = if returns_result {
(
format!(
- "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
- inner_attr, inner_fn_name
+ "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n",
),
- format!("\n}} {}().unwrap() }}", inner_fn_name),
+ format!("\n}} {inner_fn_name}().unwrap() }}"),
)
} else if test_id.is_some() {
(
- format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name),
- format!("\n}} {}() }}", inner_fn_name),
+ format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",),
+ format!("\n}} {inner_fn_name}() }}"),
)
} else {
("fn main() {\n".into(), "\n}".into())
prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
}
- debug!("final doctest:\n{}", prog);
+ debug!("final doctest:\n{prog}");
(prog, line_offset, supports_color)
}
}
}
- debug!("before:\n{}", before);
- debug!("crates:\n{}", crates);
- debug!("after:\n{}", after);
+ debug!("before:\n{before}");
+ debug!("crates:\n{crates}");
+ debug!("after:\n{after}");
(before, after, crates)
}
)
};
- debug!("creating test {}: {}", name, test);
+ debug!("creating test {name}: {test}");
self.tests.push(test::TestDescAndFn {
desc: test::TestDesc {
name: test::DynTestName(name),
eprint!("Some expected error codes were not found: {:?}", codes);
}
TestFailure::ExecutionError(err) => {
- eprint!("Couldn't run the test: {}", err);
+ eprint!("Couldn't run the test: {err}");
if err.kind() == io::ErrorKind::PermissionDenied {
eprint!(" - maybe your tempdir is mounted with noexec?");
}
}
TestFailure::ExecutionFailure(out) => {
let reason = if let Some(code) = out.status.code() {
- format!("exit code {}", code)
+ format!("exit code {code}")
} else {
String::from("terminated by signal")
};
- eprintln!("Test executable failed ({}).", reason);
+ eprintln!("Test executable failed ({reason}).");
// FIXME(#12309): An unfortunate side-effect of capturing the test
// executable's output is that the relative ordering between the test's
eprintln!();
if !stdout.is_empty() {
- eprintln!("stdout:\n{}", stdout);
+ eprintln!("stdout:\n{stdout}");
}
if !stderr.is_empty() {
- eprintln!("stderr:\n{}", stderr);
+ eprintln!("stderr:\n{stderr}");
}
}
}
}
}
-fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
+fn comma_sep<T: fmt::Display>(
+ items: impl Iterator<Item = T>,
+ space_after_comma: bool,
+) -> impl fmt::Display {
display_fn(move |f| {
for (i, item) in items.enumerate() {
if i != 0 {
- write!(f, ", ")?;
+ write!(f, ",{}", if space_after_comma { " " } else { "" })?;
}
fmt::Display::fmt(&item, f)?;
}
}
if f.alternate() {
- write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx))))
+ write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true))
} else {
- write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx))))
+ write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true))
}
})
}
end_newline: bool,
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| {
- if gens.where_predicates.is_empty() {
+ let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
+ !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
+ }).map(|pred| {
+ display_fn(move |f| {
+ if f.alternate() {
+ f.write_str(" ")?;
+ } else {
+ f.write_str("<br>")?;
+ }
+
+ match pred {
+ clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+ let bounds = bounds;
+ let for_prefix = if bound_params.is_empty() {
+ String::new()
+ } else if f.alternate() {
+ format!(
+ "for<{:#}> ",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ } else {
+ format!(
+ "for<{}> ",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ };
+
+ if f.alternate() {
+ write!(
+ f,
+ "{}{:#}: {:#}",
+ for_prefix,
+ ty.print(cx),
+ print_generic_bounds(bounds, cx)
+ )
+ } else {
+ write!(
+ f,
+ "{}{}: {}",
+ for_prefix,
+ ty.print(cx),
+ print_generic_bounds(bounds, cx)
+ )
+ }
+ }
+ clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+ write!(
+ f,
+ "{}: {}",
+ lifetime.print(),
+ bounds
+ .iter()
+ .map(|b| b.print(cx).to_string())
+ .collect::<Vec<_>>()
+ .join(" + ")
+ )
+ }
+ clean::WherePredicate::EqPredicate { lhs, rhs } => {
+ if f.alternate() {
+ write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+ } else {
+ write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+ }
+ }
+ }
+ })
+ }).peekable();
+
+ if where_predicates.peek().is_none() {
return Ok(());
}
+
let mut clause = String::new();
+
if f.alternate() {
clause.push_str(" where");
} else {
clause.push_str(" <span class=\"where\">where");
}
}
- for (i, pred) in gens.where_predicates.iter().enumerate() {
- if f.alternate() {
- clause.push(' ');
- } else {
- clause.push_str("<br>");
- }
- match pred {
- clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
- let bounds = bounds;
- let for_prefix = match bound_params.len() {
- 0 => String::new(),
- _ if f.alternate() => {
- format!(
- "for<{:#}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()))
- )
- }
- _ => format!(
- "for<{}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()))
- ),
- };
-
- if f.alternate() {
- clause.push_str(&format!(
- "{}{:#}: {:#}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- ));
- } else {
- clause.push_str(&format!(
- "{}{}: {}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- ));
- }
- }
- clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
- clause.push_str(&format!(
- "{}: {}",
- lifetime.print(),
- bounds
- .iter()
- .map(|b| b.print(cx).to_string())
- .collect::<Vec<_>>()
- .join(" + ")
- ));
- }
- clean::WherePredicate::EqPredicate { lhs, rhs } => {
- if f.alternate() {
- clause.push_str(&format!("{:#} == {:#}", lhs.print(cx), rhs.print(cx),));
- } else {
- clause.push_str(&format!("{} == {}", lhs.print(cx), rhs.print(cx),));
- }
- }
- }
-
- if i < gens.where_predicates.len() - 1 || end_newline {
- clause.push(',');
- }
- }
+ clause.push_str(&comma_sep(where_predicates, false).to_string());
if end_newline {
+ clause.push(',');
// add a space so stripping <br> tags and breaking spaces still renders properly
if f.alternate() {
clause.push(' ');
write!(
f,
"for<{:#}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)?;
} else {
write!(
f,
"for<{}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)?;
}
}
let modifier_str = match modifier {
hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?",
- hir::TraitBoundModifier::MaybeConst => "~const",
+ // ~const is experimental; do not display those bounds in rustdoc
+ hir::TraitBoundModifier::MaybeConst => "",
};
if f.alternate() {
write!(f, "{}{:#}", modifier_str, ty.print(cx))
write!(
f,
"for<{}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)
} else {
Ok(())
cx: &Context<'_>,
) -> fmt::Result {
let amp = if f.alternate() { "&" } else { "&" };
- let mut args = String::new();
- let mut args_plain = String::new();
+ let mut args = Buffer::html();
+ let mut args_plain = Buffer::new();
for (i, input) in self.inputs.values.iter().enumerate() {
if i == 0 {
args.push_str("<br>");
args_plain.push_str("self");
}
clean::SelfBorrowed(Some(ref lt), mtbl) => {
- args.push_str(&format!(
- "{}{} {}self",
- amp,
- lt.print(),
- mtbl.print_with_space()
- ));
- args_plain.push_str(&format!(
- "&{} {}self",
- lt.print(),
- mtbl.print_with_space()
- ));
+ write!(args, "{}{} {}self", amp, lt.print(), mtbl.print_with_space());
+ write!(args_plain, "&{} {}self", lt.print(), mtbl.print_with_space());
}
clean::SelfBorrowed(None, mtbl) => {
- args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
- args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
+ write!(args, "{}{}self", amp, mtbl.print_with_space());
+ write!(args_plain, "&{}self", mtbl.print_with_space());
}
clean::SelfExplicit(ref typ) => {
if f.alternate() {
- args.push_str(&format!("self: {:#}", typ.print(cx)));
+ write!(args, "self: {:#}", typ.print(cx));
} else {
- args.push_str(&format!("self: {}", typ.print(cx)));
+ write!(args, "self: {}", typ.print(cx));
}
- args_plain.push_str(&format!("self: {:#}", typ.print(cx)));
+ write!(args_plain, "self: {:#}", typ.print(cx));
}
}
} else {
if i > 0 {
args.push_str(" <br>");
- args_plain.push(' ');
+ args_plain.push_str(" ");
}
if input.is_const {
args.push_str("const ");
args_plain.push_str("const ");
}
if !input.name.is_empty() {
- args.push_str(&format!("{}: ", input.name));
- args_plain.push_str(&format!("{}: ", input.name));
+ write!(args, "{}: ", input.name);
+ write!(args_plain, "{}: ", input.name);
}
if f.alternate() {
- args.push_str(&format!("{:#}", input.type_.print(cx)));
+ write!(args, "{:#}", input.type_.print(cx));
} else {
- args.push_str(&input.type_.print(cx).to_string());
+ write!(args, "{}", input.type_.print(cx));
}
- args_plain.push_str(&format!("{:#}", input.type_.print(cx)));
+ write!(args_plain, "{:#}", input.type_.print(cx));
}
if i + 1 < self.inputs.values.len() {
- args.push(',');
- args_plain.push(',');
+ args.push_str(",");
+ args_plain.push_str(",");
}
}
- let mut args_plain = format!("({})", args_plain);
+ let mut args_plain = format!("({})", args_plain.into_inner());
+ let mut args = args.into_inner();
if self.c_variadic {
args.push_str(",<br> ...");
for ev in iter {
if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
- debug!("found link: {}", dest);
+ debug!("found link: {dest}");
let span = span_for_link(&dest, ev.1);
links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
}
map.insert("provided-methods".to_owned(), 1);
map.insert("implementors".to_owned(), 1);
map.insert("synthetic-implementors".to_owned(), 1);
+ map.insert("implementations-list".to_owned(), 1);
map.insert("trait-implementations-list".to_owned(), 1);
map.insert("synthetic-implementations-list".to_owned(), 1);
map.insert("blanket-implementations-list".to_owned(), 1);
// Render the list of items inside one of the sections "Trait Implementations",
// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) {
+fn render_impls(
+ cx: &Context<'_>,
+ w: &mut Buffer,
+ impls: &[&&Impl],
+ containing_item: &clean::Item,
+ toggle_open_by_default: bool,
+) {
let tcx = cx.tcx();
let mut rendered_impls = impls
.iter()
is_on_foreign_type: false,
show_default_items: true,
show_non_assoc_items: true,
- toggle_open_by_default: true,
+ toggle_open_by_default,
},
);
buffer.into_inner()
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
if !non_trait.is_empty() {
let mut tmp_buf = Buffer::empty_from(w);
- let render_mode = match what {
+ let (render_mode, id) = match what {
AssocItemRender::All => {
tmp_buf.write_str(
"<h2 id=\"implementations\" class=\"small-section-header\">\
- Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
- </h2>",
+ Implementations\
+ <a href=\"#implementations\" class=\"anchor\"></a>\
+ </h2>",
);
- RenderMode::Normal
+ (RenderMode::Normal, "implementations-list".to_owned())
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
let id =
trait_ = trait_.print(cx),
type_ = type_.print(cx),
);
- RenderMode::ForDeref { mut_: deref_mut_ }
+ (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
}
};
let mut impls_buf = Buffer::empty_from(w);
}
if !impls_buf.is_empty() {
w.push_buffer(tmp_buf);
+ write!(w, "<div id=\"{}\">", id);
w.push_buffer(impls_buf);
+ w.write_str("</div>");
}
}
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
let mut impls = Buffer::empty_from(w);
- render_impls(cx, &mut impls, &concrete, containing_item);
+ render_impls(cx, &mut impls, &concrete, containing_item, true);
let impls = impls.into_inner();
if !impls.is_empty() {
write!(
w,
"<h2 id=\"trait-implementations\" class=\"small-section-header\">\
- Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
+ Trait Implementations\
+ <a href=\"#trait-implementations\" class=\"anchor\"></a>\
</h2>\
<div id=\"trait-implementations-list\">{}</div>",
impls
</h2>\
<div id=\"synthetic-implementations-list\">",
);
- render_impls(cx, w, &synthetic, containing_item);
+ render_impls(cx, w, &synthetic, containing_item, false);
w.write_str("</div>");
}
</h2>\
<div id=\"blanket-implementations-list\">",
);
- render_impls(cx, w, &blanket_impl, containing_item);
+ render_impls(cx, w, &blanket_impl, containing_item, false);
w.write_str("</div>");
}
}
}
fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
- fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
- if layout.abi.is_unsized() {
+ fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
+ if layout.abi().is_unsized() {
write!(w, "(unsized)");
} else {
- let bytes = layout.size.bytes() - tag_size;
+ let bytes = layout.size().bytes() - tag_size;
write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
}
}
write_size_of_layout(w, ty_layout.layout, 0);
writeln!(w, "</p>");
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
- &ty_layout.layout.variants
+ &ty_layout.layout.variants()
{
if !variants.is_empty() {
w.write_str(
for (index, layout) in variants.iter_enumerated() {
let name = adt.variants[index].name;
write!(w, "<li><code>{name}</code>: ", name = name);
- write_size_of_layout(w, layout, tag_size);
+ write_size_of_layout(w, *layout, tag_size);
writeln!(w, "</li>");
}
w.write_str("</ul>");
) {
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
- let mut cols = 0;
- let mut tmp = lines;
- while tmp > 0 {
- cols += 1;
- tmp /= 10;
- }
line_numbers.write_str("<pre class=\"line-numbers\">");
match source_context {
SourceContext::Standalone => {
for line in 1..=lines {
- writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", line, cols)
+ writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
}
}
SourceContext::Embedded { offset } => {
for line in 1..=lines {
- writeln!(line_numbers, "<span>{0:1$}</span>", line + offset, cols)
+ writeln!(line_numbers, "<span>{0}</span>", line + offset)
}
}
}
text-decoration: underline;
}
+.line-numbers {
+ text-align: right;
+}
.rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
width: 100%;
overflow-x: auto;
} else {
addClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) {
- if (e.parentNode.id !== MAIN_ID ||
+ if (e.parentNode.id !== "implementations-list" ||
(!hasClass(e, "implementors-toggle") &&
!hasClass(e, "type-contents-toggle")))
{
let mut css = String::new();
for name in &options.markdown_css {
- let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
+ let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{name}\">\n");
css.push_str(&s)
}
-Subproject commit e29ac13bc97e26f886c3bfe72f9135e994c3cd0a
+Subproject commit c8eccf626fb5bb851b2ade93af8851ca1523807f
pub trait Sized {}
#[lang = "copy"]
pub trait Copy {}
+impl Copy for f32 {}
#[repr(C)]
pub struct Franta {
trait Sized {}
#[lang = "copy"]
trait Copy {}
+impl Copy for u32 {}
// Use of these requires target features to be enabled
extern "unadjusted" {
trait Sized {}
#[lang = "copy"]
trait Copy {}
+impl Copy for i64 {}
// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
#[no_mangle]
trait Sized {}
#[lang = "copy"]
trait Copy {}
+impl Copy for i64 {}
// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
#[no_mangle]
trait Sized { }
#[lang="copy"]
trait Copy { }
-
+impl Copy for u32 {}
// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] {
pub fn f() {
let a = A;
- let b = (0i32, 1i32, 2i32, 3i32);
+ let b = (0i32, 1i32, 2i32, 3 as *const i32);
let c = || {};
a(String::new(), String::new());
// CHECK-NOT: inlinehint
// CHECK-SAME: {{$}}
-// CHECK: ; <(i32, i32, i32, i32) as core::clone::Clone>::clone
+// CHECK: ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone
// CHECK-NEXT: ; Function Attrs: inlinehint
// CHECK: ; inline_hint::f::{closure#0}
trait Sized {}
#[lang = "copy"]
trait Copy {}
+impl Copy for bool {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for u64 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
// CHECK: define void @f_void()
#[no_mangle]
peach()
}
-// target features same as global (not reflected or overriden in IR)
+// target features same as global
#[no_mangle]
pub unsafe fn banana() -> u32 {
// CHECK-LABEL: @banana()
// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
// CHECK: attributes [[BANANAATTRS]]
-// CHECK-NOT: target-features
-// CHECK-SAME: }
+// COMPAT-SAME: "target-features"="+avx2,+avx"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx"
--- /dev/null
+// compile-flags: -C opt-level=0 -Z inline_mir=no
+// ignore-wasm32 compiled with panic=abort by default
+
+// EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+
+#[derive(Clone)]
+struct MyThing<T> {
+ v: T,
+ i: u64,
+ a: [f32; 3],
+}
+
+fn main() {
+ let x = MyThing::<i16> { v: 2, i: 3, a: [0.0; 3] };
+ let y = x.clone();
+
+ assert_eq!(y.v, 2);
+ assert_eq!(y.i, 3);
+ assert_eq!(y.a, [0.0; 3]);
+}
--- /dev/null
+- // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` before InstCombine
++ // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` after InstCombine
+
+ fn <impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone(_1: &MyThing<T>) -> MyThing<T> {
+ debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ let mut _0: MyThing<T>; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ let _2: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ let _3: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ let _4: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ let mut _5: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ let mut _6: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ let _7: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ let mut _8: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ let mut _9: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ let _10: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ let mut _11: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ let mut _12: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ let _13: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ scope 1 {
+ debug __self_0_0 => _2; // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ debug __self_0_1 => _3; // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ debug __self_0_2 => _4; // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ }
+
+ bb0: {
+ _2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ _3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ _4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++ _6 = _7; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ _5 = <T as Clone>::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ // mir::Constant
+ // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+ // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+- _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+- // mir::Constant
+- // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+- // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++ _10 = _3; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++ _9 = _10; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++ _8 = (*_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++ goto -> bb2; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+ }
+
+ bb2: {
+- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+- // mir::Constant
+- // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+- // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++ _13 = _4; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++ _12 = _13; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++ _11 = (*_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++ goto -> bb3; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+ }
+
+ bb3: {
+ (_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ (_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ (_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ return; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
+ }
+
+ bb4 (cleanup): {
+ drop(_5) -> bb5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+ }
+
+ bb5 (cleanup): {
+ resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+ }
+ }
+
- bb1: {
+ discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
_3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:9:23: 9:31
-- _2 = Pin::<&mut impl Generator<bool>>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
- // mir::Constant
- // + span: $DIR/inline-generator.rs:9:14: 9:22
- // + user_ty: UserType(0)
-- // + literal: Const { ty: fn(&mut impl Generator<bool>) -> Pin<&mut impl Generator<bool>> {Pin::<&mut impl Generator<bool>>::new}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new}, val: Value(Scalar(<ZST>)) }
- }
-
- bb2: {
+ StorageDead(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ StorageDead(_5); // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
-- _1 = <impl Generator<bool> as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
- // mir::Constant
- // + span: $DIR/inline-generator.rs:9:33: 9:39
-- // + literal: Const { ty: for<'r> fn(Pin<&'r mut impl Generator<bool>>, bool) -> GeneratorState<<impl Generator<bool> as Generator<bool>>::Yield, <impl Generator<bool> as Generator<bool>>::Return> {<impl Generator<bool> as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
+ StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+ _7 = const false; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+ StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
bb1: {
_3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
- // mir::Constant
- // + span: $DIR/issue-78442.rs:11:5: 11:15
-- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
_3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
nop; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:15
- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
}
bb2: {
let mut _0: bool; // return place in scope 0 at $DIR/named-lifetimes-basic.rs:12:81: 12:85
bb0: {
- _0 = const Const(Value(Scalar(0x01)): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
+ _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
return; // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:12:94: 12:94
}
}
bb0: {
StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
- _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+ _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
- _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+ _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
_4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
_5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
_6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
- _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+ _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
}
StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
_9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
- _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+ _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
// mir::Constant
// + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
bb3: {
StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
- _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+ _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
}
bb4: {
StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
- _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+ _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
// mir::Constant
// + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
bb5: {
StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
- _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+ _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
}
bb0: {
StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
- _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+ _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
- _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+ _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
_4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
_5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
_6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
- _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+ _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
}
StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
_9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
- _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+ _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
// mir::Constant
// + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
bb3: {
StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
- _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+ _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
}
bb4: {
StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
- _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+ _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
// mir::Constant
// + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
bb5: {
StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
- _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+ _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
}
// Logically, the ".docblock" and the "<p>" should have the same scroll width.
compare-elements-property: (
- "#implementations + details .docblock",
- "#implementations + details .docblock > p",
+ "#implementations-list > details .docblock",
+ "#implementations-list > details .docblock > p",
["scrollWidth"],
)
-assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"})
+assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"})
// However, since there is overflow in the <table>, its scroll width is bigger.
-assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
+assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"})
// In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)".
assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""})
// We first check that the impl block is open by default.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list details", {"open": ""})
// To ensure that we will click on the currently hidden method.
assert-text: (".sidebar-elems section .block li > a", "must_use")
click: ".sidebar-elems section .block li > a"
// We check that the impl block was opened as expected so that we can see the method.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list > details", {"open": ""})
// This test ensures that the impl blocks are open by default.
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-attribute: ("#main-content > details.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""})
size: (400, 600)
font-size: 18
+wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
// The out-of-band info (source, stable version, collapse) should be below the
// h1 when the screen gets narrow enough.
assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
size: (1000, 1000)
+wait-for: 100 // wait a bit for the resize to be fully taken into account.
assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
// On the settings page, the theme buttons should not line-wrap. Instead, they should
// all be placed as a group on a line below the setting name "Theme."
goto: file://|DOC_PATH|/settings.html
size: (400, 600)
-compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
+// Ignored for now https://github.com/rust-lang/rust/issues/93784.
+// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
// This is to ensure that the content is correctly align with the line numbers.
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+
+// Assert that the line numbers text is aligned to the right.
+assert-css: (".line-numbers", {"text-align": "right"})
// Assert the position of the toggle on the top doc block.
assert-position: (".top-doc summary::before", {"x": 4})
// Assert the position of the toggle on the impl block.
-assert-position: ("#implementations + details > summary::before", {"x": 4})
+assert-position: ("#implementations-list > details > summary::before", {"x": 4})
// Assert the position of the toggle on a method.
assert-position: (
"#trait-implementations-list .impl-items .method-toggle > summary::before",
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
// We first check that everything is visible.
assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute-false: (
+ "#blanket-implementations-list > details.rustdoc-toggle",
+ {"open": ""},
+ ALL,
+)
+
// We collapse them all.
click: "#toggle-all-docs"
wait-for: 50
assert-text: ("#toggle-all-docs", "[+]")
// We check that all <details> are collapsed (except for the impl block ones).
assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
-assert-attribute: ("details.rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
// We now check that the other impl blocks are collapsed.
assert-attribute-false: (
"#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
#![allow(incomplete_features)]
// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
-// 'pub struct Ice<const N: usize> where [(); N + 1]: ;'
+// 'pub struct Ice<const N: usize>;'
pub struct Ice<const N: usize> where [(); N + 1]:;
+// ignore-tidy-linelength
+
// @has issue_33054/impls/struct.Foo.html
// @has - '//h3[@class="code-header in-band"]' 'impl Foo'
// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
--- /dev/null
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+pub trait Trait {
+ type Gat<'a>;
+}
+
+// Make sure that the elided lifetime shows up
+
+// @has foo/type.T.html
+// @has - "pub type T = "
+// @has - "<'_>"
+pub type T = fn(&<() as Trait>::Gat<'_>);
--- /dev/null
+// Test that we do not currently display `~const` in rustdoc
+// as that syntax is currently provisional; `~const Drop` has
+// no effect on stable code so it should be hidden as well.
+//
+// To future blessers: make sure that `const_trait_impl` is
+// stabilized when changing `@!has` to `@has`, and please do
+// not remove this test.
+#![feature(const_trait_impl)]
+#![crate_name = "foo"]
+
+pub struct S<T>(T);
+
+// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+pub trait Tr<T> {
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ #[default_method_body_is_const]
+ fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+impl<T: ~const Drop + ~const Clone> const Tr<T> for T where Option<T>: ~const Drop + ~const Clone {
+ fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+pub const fn foo<F: ~const Drop + ~const Clone>() where Option<F>: ~const Drop + ~const Clone {
+ F::a()
+}
+
+impl<T> S<T> {
+ // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ pub const fn foo<B: ~const Drop + ~const Clone>() where B: ~const Drop + ~const Clone {
+ B::a()
+ }
+}
// build-fail
-//~^ ERROR cycle detected when normalizing `<() as Tr>::A`
+//~^ ERROR cycle detected when normalizing `<() as Tr>::A` [E0391]
// Cyclic assoc. const defaults don't error unless *used*
trait Tr {
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
- //~| ERROR the trait bound `Bug: Foo` is not satisfied
&self,
) -> Self::AssocType;
+ //~^ the trait bound `Bug: Foo` is not satisfied
}
fn with_factory<H>(factory: dyn ThriftService<()>) {}
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | | ) -> Self::AssocType;
+LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | | ) -> Self::AssocType;
+LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
|
LL | / fn get_service(
LL | |
-LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
| +++++
error[E0277]: the trait bound `Bug: Foo` is not satisfied
- --> $DIR/issue-59324.rs:16:8
+ --> $DIR/issue-59324.rs:19:10
|
-LL | fn get_service(
- | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL | ) -> Self::AssocType;
+ | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|
impl IntoFuture for AwaitMe {
type Output = i32;
- type Future = Pin<Box<dyn Future<Output = i32>>>;
+ type IntoFuture = Pin<Box<dyn Future<Output = i32>>>;
- fn into_future(self) -> Self::Future {
+ fn into_future(self) -> Self::IntoFuture {
Box::pin(me())
}
}
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | fn baz() { async fn foo() {} }
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn async_baz() {
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0706]: functions in traits cannot be declared `async`
--- /dev/null
+// rustc-env:CARGO=/usr/bin/cargo
+
+use std::pin::Pin;
+use std::future::Future;
+
+fn main() {}
+
+fn await_on_struct_missing() {
+ struct S;
+ let x = S;
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE unknown field
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_struct_similar() {
+ struct S {
+ awai: u8,
+ }
+ let x = S { awai: 42 };
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| HELP a field with a similar name exists
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE unknown field
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_apit(x: impl Future<Output = ()>) {
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
--- /dev/null
+error[E0609]: no field `await` on type `await_on_struct_missing::S`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7
+ |
+LL | x.await;
+ | ^^^^^ unknown field
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `await_on_struct_similar::S`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7
+ |
+LL | x.await;
+ | ^^^^^ help: a field with a similar name exists: `awai`
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7
+ |
+LL | x.await;
+ | ^^^^^ unknown field
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `impl Future<Output = ()>`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7
+ |
+LL | x.await;
+ | ^^^^^
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
//~^ ERROR no field `await` on type
//~| NOTE unknown field
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
//~^ ERROR no field `await` on type
//~| HELP a field with a similar name exists
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
//~^ ERROR no field `await` on type
//~| NOTE unknown field
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
x.await;
//~^ ERROR no field `await` on type
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
| ^^^^^ unknown field
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `await_on_struct_similar::S`
| ^^^^^ help: a field with a similar name exists: `awai`
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
| ^^^^^ unknown field
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `impl Future<Output = ()>`
| ^^^^^
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: aborting due to 4 previous errors
--> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
|
LL | (|| { let bar = foo; bar.take() })();
- | ^^ ---
- | | |
- | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
--> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
|
LL | (|| { let bar = foo; bar.take() })();
- | ^^ ---
- | | |
- | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
LL | | let _h = to_fn_once(move || -> isize { *bar });
| | ^^^^^^^^^^^^^^^^ ----
| | | |
+ | | | variable moved due to use in closure
| | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
- | | | move occurs due to use in closure
| | move out of `bar` occurs here
LL | | });
| |_____- captured by this `FnMut` closure
--> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14
|
LL | let _x = Rc::new(vec![1, 2]).into_iter();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+ | ^^^^^^^^^^^^^^^^^^^^-----------
+ | | |
+ | | value moved due to this method call
+ | move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+ |
+note: this function takes ownership of the receiver `self`, which moves value
+ --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ |
+LL | fn into_iter(self) -> Self::IntoIter;
+ | ^^^^
error: aborting due to previous error
--- /dev/null
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+ pub helpers: [Vec<&'n i64>; 2],
+ pub is_empty: bool,
+}
+
+impl DataStruct {
+ pub fn f(&self) -> HelperStruct {
+ let helpers = [vec![], vec![]];
+
+ HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+ //~^ ERROR borrow of moved value
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: borrow of moved value: `helpers`
+ --> $DIR/copy-suggestion-region-vid.rs:12:43
+ |
+LL | let helpers = [vec![], vec![]];
+ | ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
+LL |
+LL | HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+ | ------- ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--> $DIR/issue-27282-mutation-in-guard.rs:6:18
|
LL | (|| { let bar = foo; bar.take() })();
- | ^^ ---
- | | |
- | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-#![feature(const_fn_trait_bound)]
// Regression test related to issue 88434
const _CONST: &() = &f(&|_| {});
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-88434-minimal-example.rs:10:5
+ --> $DIR/issue-88434-minimal-example.rs:9:5
|
LL | const _CONST: &() = &f(&|_| {});
- | ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:4:22
+ | ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
...
LL | panic!()
| ^^^^^^^^
| |
- | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
- | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:4:25: 4:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+ | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:9:5
+ | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-#![feature(const_fn_trait_bound)]
// Regression test for issue 88434
const _CONST: &[u8] = &f(&[], |_| {});
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+ --> $DIR/issue-88434-removal-index-should-be-less.rs:9:5
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
- | -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:4:24
+ | -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
...
LL | panic!()
| ^^^^^^^^
| |
- | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
- | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+ | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:9:5
+ | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
LL | call(|| {
| __________-
LL | | y.into_iter();
- | | ^ move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+ | | ^ ----------- `y` moved due to this method call
+ | | |
+ | | move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
LL | |
LL | | });
| |_____- captured by this `Fn` closure
+ |
+note: this function takes ownership of the receiver `self`, which moves `y`
+ --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ |
+LL | fn into_iter(self) -> Self::IntoIter;
+ | ^^^^
error: aborting due to previous error
q as *const [i32]; //~ ERROR cannot cast
// #21397
- let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting
- let mut fail: *const str = 0 as *const str; //~ ERROR casting
+ let t: *mut (dyn Trait + 'static) = 0 as *mut _;
+ //~^ ERROR cannot cast `usize` to a pointer that is wide
+ let mut fail: *const str = 0 as *const str;
+ //~^ ERROR cannot cast `usize` to a pointer that is wide
+ let mut fail2: *const str = 0isize as *const str;
+ //~^ ERROR cannot cast `isize` to a pointer that is wide
+}
+
+fn foo<T: ?Sized>() {
+ let s = 0 as *const T;
+ //~^ ERROR cannot cast `usize` to a pointer that may be wide
}
LL | q as *const [i32];
| ^^^^^^^^^^^^^^^^^
-error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid
- --> $DIR/fat-ptr-cast.rs:22:41
+error[E0606]: cannot cast `usize` to a pointer that is wide
+ --> $DIR/fat-ptr-cast.rs:22:46
|
LL | let t: *mut (dyn Trait + 'static) = 0 as *mut _;
- | ^^^^^^^^^^^
+ | - ^^^^^^ creating a `*mut (dyn Trait + 'static)` requires both an address and a vtable
+ | |
+ | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
-error[E0606]: casting `usize` as `*const str` is invalid
- --> $DIR/fat-ptr-cast.rs:23:32
+error[E0606]: cannot cast `usize` to a pointer that is wide
+ --> $DIR/fat-ptr-cast.rs:24:37
|
LL | let mut fail: *const str = 0 as *const str;
- | ^^^^^^^^^^^^^^^
+ | - ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+ | |
+ | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
-error: aborting due to 9 previous errors
+error[E0606]: cannot cast `isize` to a pointer that is wide
+ --> $DIR/fat-ptr-cast.rs:26:43
+ |
+LL | let mut fail2: *const str = 0isize as *const str;
+ | ------ ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+ | |
+ | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error[E0606]: cannot cast `usize` to a pointer that may be wide
+ --> $DIR/fat-ptr-cast.rs:31:18
+ |
+LL | let s = 0 as *const T;
+ | - ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata
+ | |
+ | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error: aborting due to 11 previous errors
Some errors have detailed explanations: E0605, E0606, E0607.
For more information about an error, try `rustc --explain E0605`.
#[cfg(unix)]
fn unix() {}
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc)]
+fn doc() {}
+
fn main() {}
#[cfg(unix)]
fn unix() {}
+#[cfg(miri = "miri")]
+//~^ WARNING unexpected `cfg` condition value
+fn miri_with_value() {}
+
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc = "linux")]
+//~^ WARNING unexpected `cfg` condition value
+fn doc_with_value() {}
+
+#[cfg(doc)]
+fn doc() {}
+
fn main() {}
|
= note: no expected value for `unix`
-warning: 3 warnings emitted
+warning: unexpected `cfg` condition value
+ --> $DIR/well-known-values.rs:28:7
+ |
+LL | #[cfg(miri = "miri")]
+ | ^^^^---------
+ | |
+ | help: remove the value
+ |
+ = note: no expected value for `miri`
+
+warning: unexpected `cfg` condition value
+ --> $DIR/well-known-values.rs:35:7
+ |
+LL | #[cfg(doc = "linux")]
+ | ^^^----------
+ | |
+ | help: remove the value
+ |
+ = note: no expected value for `doc`
+
+warning: 5 warnings emitted
error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
--> $DIR/issue-88331.rs:11:20
|
-LL | pub struct Opcode(pub u8);
- | -------------------------- `Opcode` defined here
-...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode` defined here
+ --> $DIR/issue-88331.rs:4:12
+ |
+LL | pub struct Opcode(pub u8);
+ | ^^^^^^
= note: the matched value is of type `Opcode`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Opcode::OP1 => unimplemented!(),
+LL ~ Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
--> $DIR/issue-88331.rs:27:20
|
-LL | pub struct Opcode2(Opcode);
- | --------------------------- `Opcode2` defined here
-...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode2` defined here
+ --> $DIR/issue-88331.rs:18:12
+ |
+LL | pub struct Opcode2(Opcode);
+ | ^^^^^^^
= note: the matched value is of type `Opcode2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Opcode2::OP2=> unimplemented!(),
+LL ~ Opcode2(Opcode(0_u8)) | Opcode2(Opcode(2_u8..=u8::MAX)) => todo!(),
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/non-exhaustive-match.rs:26:25
|
-LL | enum L1 { A, B }
- | ----------------
- | | |
- | | not covered
- | `L1` defined here
-...
LL | let _b = || { match l1 { L1::A => () } };
| ^^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L1` defined here
+ --> $DIR/non-exhaustive-match.rs:12:14
+ |
+LL | enum L1 { A, B }
+ | -- ^ not covered
= note: the matched value is of type `L1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | let _b = || { match l1 { L1::A => (), B => todo!() } };
+ | ++++++++++++++
error[E0004]: non-exhaustive patterns: type `E1` is non-empty
--> $DIR/non-exhaustive-match.rs:37:25
LL | let _d = || { match e1 {} };
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+ |
+LL | pub enum E1 {}
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _d = || { match e1 {
+LL + _ => todo!(),
+LL ~ } };
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/non-exhaustive-match.rs:39:25
LL | let _e = || { match e2 { E2::A => (), E2::B => () } };
| ^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+ |
+LL | pub enum E2 { A, B }
+ | ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
+ | ++++++++++++++
error[E0505]: cannot move out of `e3` because it is borrowed
--> $DIR/non-exhaustive-match.rs:46:22
LL | let c1 = || match x { };
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let c1 = || match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/pattern-matching-should-fail.rs:8:23
pub trait Sized { }
#[lang="copy"]
pub trait Copy { }
+impl Copy for u32 {}
extern "rust-intrinsic" {
pub fn transmute<T, U>(e: T) -> U;
pub trait Sized { }
#[lang="copy"]
pub trait Copy { }
+impl Copy for u32 {}
extern "rust-intrinsic" {
pub fn transmute<T, U>(e: T) -> U;
trait Sized { }
#[lang="copy"]
trait Copy { }
+impl Copy for u32 {}
#[no_mangle]
#[cmse_nonsecure_entry]
trait Sized { }
#[lang="copy"]
trait Copy { }
+impl Copy for u32 {}
#[no_mangle]
#[cmse_nonsecure_entry]
--- /dev/null
+#![feature(generic_const_exprs)]
+
+use std::str::FromStr;
+
+pub struct If<const CONDITION: bool>;
+
+pub trait True {}
+
+impl True for If<true> {}
+
+pub struct FixedI32<const FRAC: u32>;
+
+impl<const FRAC: u32> FromStr for FixedI32<FRAC>
+where
+ If<{ FRAC <= 32 }>: True,
+{
+ type Err = ();
+ fn from_str(_s: &str) -> Result<Self, Self::Err> {
+ unimplemented!()
+ }
+}
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait _Contains<T> {
--- /dev/null
+// aux-build:issue-94287-aux.rs
+// build-fail
+
+extern crate issue_94287_aux;
+
+use std::str::FromStr;
+
+fn main() {
+ let _ = <issue_94287_aux::FixedI32<16>>::from_str("");
+}
--- /dev/null
+error: failed to evaluate generic const expression
+ --> $DIR/auxiliary/issue-94287-aux.rs:15:8
+ |
+LL | If<{ FRAC <= 32 }>: True,
+ | ^^^^^^^^^^^^^^
+ |
+ = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
+help: consider enabling this feature
+ |
+LL | #![feature(generic_const_exprs)]
+ |
+
+error: aborting due to previous error
+
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait MiniTypeId {
// Crate that exports a const fn. Used for testing cross-crate.
-#![feature(const_fn_fn_ptr_basics)]
#![crate_type="rlib"]
pub const fn foo() -> usize { 22 }
#![allow(unused)]
-#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
+#![feature(const_trait_impl, inline_const, negative_impls)]
const fn f<T: ~const Drop>(x: T) {}
-//~ERROR constructed but no error reported
// compile-flags: -Ztreat-err-as-bug=2
+//~^ ERROR 1:1: 1:1: ty::ConstKind::Error constructed but no error reported
// build-fail
// failure-status: 101
// rustc-env:RUST_BACKTRACE=1
|
LL | X_CONST(x)
| ^^^^^^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr.rs:18:14
- |
-LL | const fn foo(x: fn(usize) -> usize, y: usize) -> usize {
- | ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr.rs:19:5
- |
-LL | x(y)
- | ^
help: skipping check that does not even have a feature gate
--> $DIR/const_fn_ptr.rs:19:5
|
LL | x(y)
| ^^^^
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr_fail2.rs:11:14
- |
-LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
- | ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr_fail2.rs:12:5
- |
-LL | x(y)
- | ^
help: skipping check that does not even have a feature gate
--> $DIR/const_fn_ptr_fail2.rs:12:5
|
// issue-49296: Unsafe shenigans in constants can result in missing errors
-#![feature(const_fn_trait_bound)]
-
use std::mem::transmute;
const fn wat(x: u64) -> &'static u64 {
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-49296.rs:11:16
+ --> $DIR/issue-49296.rs:9:16
|
LL | const X: u64 = *wat(42);
| ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
// check-pass
-#![feature(const_fn_fn_ptr_basics)]
const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
x
const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x }
const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
//~^ ERROR floating point arithmetic
const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:4:41
- |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
- | ^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:4:48
- |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
- | ^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
error[E0658]: floating point arithmetic is not allowed in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:7:42
+ --> $DIR/const-extern-fn-min-const-fn.rs:5:42
|
LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
| ^^^^^^^^^
= help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
error: pointers cannot be cast to integers during const eval
- --> $DIR/const-extern-fn-min-const-fn.rs:9:48
+ --> $DIR/const-extern-fn-min-const-fn.rs:7:48
|
LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
| ^^^^^^^^^^^^
= note: at compile-time, pointers do not have an integer value
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
// A very basic test of const fn functionality.
#![feature(const_indexing)]
-#![feature(const_fn_trait_bound)]
const fn add(x: u32, y: u32) -> u32 {
x + y
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | A = { if let 0 = 0 { /* */ } 0 },
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | A = { if let 0 = 0 { todo!() } 0 },
+ | ++ ~~~~~~~~~~~
error: aborting due to previous error
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | let x: [i32; { if let 0 = 0 { /* */ } 0 }] = [];
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
+ | ++ ~~~~~~~~~~~
error: aborting due to previous error
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
+ | ++ ~~~~~~~~~~~
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:8:23
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
+ | ++ ~~~~~~~~~~~
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:13:26
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
+ | ++ ~~~~~~~~~~~
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/const-match-check.rs:19:26
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
+ | ++ ~~~~~~~~~~~
error: aborting due to 4 previous errors
+++ /dev/null
-error: fatal error triggered by #[rustc_error]
- --> $DIR/const_fn_trait_bound.rs:17:1
- |
-LL | fn main() {}
- | ^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// gate-test-const_fn_trait_bound
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_trait_bound))]
-
-const fn test1<T: std::ops::Add>() {}
-//[stock]~^ trait bounds
-const fn test2(_x: &dyn Send) {}
-//[stock]~^ trait objects in const fn are unstable
-const fn test3() -> &'static dyn Send { loop {} }
-//[stock]~^ trait objects in const fn are unstable
-
-
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
+++ /dev/null
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/const_fn_trait_bound.rs:8:16
- |
-LL | const fn test1<T: std::ops::Add>() {}
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/const_fn_trait_bound.rs:10:16
- |
-LL | const fn test2(_x: &dyn Send) {}
- | ^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/const_fn_trait_bound.rs:12:21
- |
-LL | const fn test3() -> &'static dyn Send { loop {} }
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+const fn f<T>(_: Box<T>) {}
+//~^ ERROR destructors cannot be evaluated at compile-time
+
+fn main() {}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop_box.rs:1:15
+ |
+LL | const fn f<T>(_: Box<T>) {}
+ | ^ - value is dropped here
+ | |
+ | constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
+// check-pass
+
const fn x() {
let t = true;
- let x = || t; //~ ERROR function pointer
+ let x = || t;
}
fn main() {}
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/issue-37550-1.rs:3:9
- |
-LL | let x = || t;
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
#![allow(dead_code)]
#![allow(unused_variables)]
-#![feature(const_fn_fn_ptr_basics)]
-
const fn x() {
let t = true;
let x = || t;
// run-pass
-#![feature(const_fn_fn_ptr_basics)]
#![deny(const_err)]
pub struct Data<T> {
-#![feature(const_fn_fn_ptr_basics)]
-
const fn foo() { (||{})() }
//~^ ERROR cannot call non-const closure
error[E0015]: cannot call non-const closure in constant functions
- --> $DIR/issue-56164.rs:3:18
+ --> $DIR/issue-56164.rs:1:18
|
LL | const fn foo() { (||{})() }
| ^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: function pointers are not allowed in const fn
- --> $DIR/issue-56164.rs:7:5
+ --> $DIR/issue-56164.rs:5:5
|
LL | input()
| ^^^^^^^
// regression test for #88071
#![feature(const_btree_new)]
-#![feature(const_fn_trait_bound)]
use std::collections::BTreeMap;
--- /dev/null
+#![feature(const_trait_impl, const_mut_refs)]
+
+struct Foo<'a> {
+ bar: &'a mut Vec<usize>,
+}
+
+impl<'a> Foo<'a> {
+ const fn spam(&mut self, baz: &mut Vec<u32>) {
+ self.bar[0] = baz.len();
+ //~^ ERROR cannot call non-const fn `Vec::<u32>::len` in constant functions
+ //~| ERROR the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+ //~| ERROR cannot call non-const operator in constant functions
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions
+ --> $DIR/issue-94675.rs:9:27
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0277]: the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize`
+ |
+ = help: the trait `~const IndexMut<usize>` is not implemented for `Vec<usize>`
+note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that implementation is not `const`
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^
+
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ |
+LL | impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
+++ /dev/null
-#![feature(rustc_attrs, staged_api, rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {}
-//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-const fn compiles(_: fn()) {}
-
-fn main() {}
+++ /dev/null
-error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
- --> $DIR/allow_const_fn_ptr.rs:7:16
- |
-LL | const fn error(_: fn()) {}
- | ^
- |
-help: if it is not part of the public API, make this function unstably const
- |
-LL | #[rustc_const_unstable(feature = "...", issue = "...")]
- |
-help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
- |
-LL | #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
- |
-
-error: aborting due to previous error
-
// run-pass
#![feature(rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
#![feature(rustc_attrs, staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
const fn takes_fn_ptr(_: fn()) {}
const FN: fn() = || ();
+++ /dev/null
-fn main() {}
-
-const fn unsize(x: &[u8; 3]) -> &[u8] { x }
-const fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
-const fn closure2() {
- (|| {}) as fn();
-//~^ ERROR function pointer
-}
-const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointer
-//~| ERROR function pointer
-//~| ERROR function pointer cast
-const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:4:23
- |
-LL | const fn closure() -> fn() { || {} }
- | ^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:4:30
- |
-LL | const fn closure() -> fn() { || {} }
- | ^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:8:5
- |
-LL | (|| {}) as fn();
- | ^^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:11:16
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:11:28
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^^^^^^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:11:42
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:15:21
- |
-LL | const fn reify2() { main as unsafe fn(); }
- | ^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:15:21
- |
-LL | const fn reify2() { main as unsafe fn(); }
- | ^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+fn main() {}
+
+const fn unsize(x: &[u8; 3]) -> &[u8] { x }
+const fn closure() -> fn() { || {} }
+const fn closure2() {
+ (|| {}) as fn();
+}
+const fn reify(f: fn()) -> unsafe fn() { f }
+const fn reify2() { main as unsafe fn(); }
const fn cmp(x: fn(), y: fn()) -> bool {
- //~^ ERROR function pointer
- //~| ERROR function pointer
unsafe { x == y }
//~^ ERROR pointers cannot be reliably compared
}
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cmp_fn_pointers.rs:1:14
- |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cmp_fn_pointers.rs:1:23
- |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
error: pointers cannot be reliably compared during const eval
- --> $DIR/cmp_fn_pointers.rs:4:14
+ --> $DIR/cmp_fn_pointers.rs:2:14
|
LL | unsafe { x == y }
| ^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { core::ptr::null() }
const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { core::ptr::null_mut() }
-// not ok
const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo11_2<T: Send>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+
+// not ok
static BAR: u32 = 42;
const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
fn main() {}
impl<T: std::fmt::Debug> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo(&self) {}
}
impl<T: std::fmt::Debug + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo2(&self) {}
}
impl<T: Sync + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo3(&self) {}
}
struct AlanTuring<T>(T);
const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
const fn no_apit(_x: impl std::fmt::Debug) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-//~^ ERROR trait objects in const fn are unstable
const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-//~^ ERROR trait objects in const fn are unstable
const fn no_unsafe() { unsafe {} }
-const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
+const fn traits_are_ok_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointer
-const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+const fn fn_ptrs(_x: fn()) {}
+const fn fn_ptrs2() -> fn() { fn foo() {} foo }
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:84:16
- |
-LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:86:18
- |
-LL | const fn foo11_2<T: Send>(t: T) -> T { t }
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0013]: constant functions cannot refer to statics
- --> $DIR/min_const_fn.rs:90:27
+ --> $DIR/min_const_fn.rs:89:27
|
LL | const fn foo25() -> u32 { BAR }
| ^^^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constant functions cannot refer to statics
- --> $DIR/min_const_fn.rs:91:37
+ --> $DIR/min_const_fn.rs:90:37
|
LL | const fn foo26() -> &'static u32 { &BAR }
| ^^^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:92:42
+ --> $DIR/min_const_fn.rs:91:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:94:63
+ --> $DIR/min_const_fn.rs:93:63
|
LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:96:42
+ --> $DIR/min_const_fn.rs:95:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:98:63
+ --> $DIR/min_const_fn.rs:97:63
|
LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error[E0658]: mutable references are not allowed in constant functions
- --> $DIR/min_const_fn.rs:101:14
+ --> $DIR/min_const_fn.rs:100:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:110:6
- |
-LL | impl<T: std::fmt::Debug> Foo<T> {
- | ^
-LL |
-LL | const fn foo(&self) {}
- | ------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:115:6
- |
-LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
- | ^
-LL |
-LL | const fn foo2(&self) {}
- | -------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:120:6
- |
-LL | impl<T: Sync + Sized> Foo<T> {
- | ^
-LL |
-LL | const fn foo3(&self) {}
- | -------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:126:34
- |
-LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:126:19
+ --> $DIR/min_const_fn.rs:122:19
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:129:22
- |
-LL | const fn no_apit(_x: impl std::fmt::Debug) {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:129:18
+ --> $DIR/min_const_fn.rs:124:18
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {}
| ^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:132:23
- |
-LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
- | ^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:134:32
- |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:41
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:42
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:42
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn.rs:144:21
- |
-LL | const fn no_fn_ptrs(_x: fn()) {}
- | ^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn.rs:146:27
- |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
- | ^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/min_const_fn.rs:146:46
- |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
- | ^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 39 previous errors
+error: aborting due to 24 previous errors
Some errors have detailed explanations: E0013, E0493, E0658.
For more information about an error, try `rustc --explain E0013`.
+// check-pass
+
struct HasDyn {
field: &'static dyn std::fmt::Debug,
}
const fn no_inner_dyn_trait(_x: Hide) {}
const fn no_inner_dyn_trait2(x: Hide) {
x.0.field;
-//~^ ERROR trait objects in const fn are unstable
}
const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait objects in const fn are unstable
fn main() {}
+++ /dev/null
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn_dyn.rs:9:5
- |
-LL | const fn no_inner_dyn_trait2(x: Hide) {
- | ------------------------------------- function declared as const here
-LL | x.0.field;
- | ^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn_dyn.rs:12:66
- |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
- | ----------------------------------------- ^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// gate-test-const_fn_fn_ptr_basics
-
-struct HasPtr {
- field: fn(),
-}
-
-struct Hide(HasPtr);
-
-fn field() {}
-
-const fn no_inner_dyn_trait(_x: Hide) {}
-const fn no_inner_dyn_trait2(x: Hide) {
- x.0.field;
-//~^ ERROR function pointer
-}
-const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointer
-
-fn main() {}
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn_fn_ptr.rs:13:5
- |
-LL | x.0.field;
- | ^^^^^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/min_const_fn_fn_ptr.rs:16:59
- |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
- | ^^^^^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// gate-test-const_impl_trait
-
-struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
- AlanTuring(0)
-}
-
-const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
-
-fn main() {}
+++ /dev/null
-error[E0658]: `impl Trait` is not allowed in constant functions
- --> $DIR/min_const_fn_impl_trait.rs:4:24
- |
-LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
- = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error[E0658]: `impl Trait` is not allowed in constant functions
- --> $DIR/min_const_fn_impl_trait.rs:8:23
- |
-LL | const fn no_rpit() -> impl std::fmt::Debug {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
- = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/abi-mismatch.rs:9:23
- |
-LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
- | ^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/abi-mismatch.rs:10:5
- |
-LL | my_fn();
- | ^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/abi-mismatch.rs:10:5
|
-#![feature(const_ptr_offset_from)]
+#![feature(const_ptr_offset_from, const_ptr_offset)]
#![feature(core_intrinsics)]
use std::intrinsics::ptr_offset_from;
//~| 0x10 is not a valid pointer
};
+const OUT_OF_BOUNDS_1: isize = {
+ let start_ptr = &4 as *const _ as *const u8;
+ let length = 10;
+ let end_ptr = (start_ptr).wrapping_add(length);
+ // First ptr is out of bounds
+ unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
+ //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_2: isize = {
+ let start_ptr = &4 as *const _ as *const u8;
+ let length = 10;
+ let end_ptr = (start_ptr).wrapping_add(length);
+ // Second ptr is out of bounds
+ unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+ //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_SAME: isize = {
+ let start_ptr = &4 as *const _ as *const u8;
+ let length = 10;
+ let end_ptr = (start_ptr).wrapping_add(length);
+ unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+ //~| pointer at offset 10 is out-of-bounds
+};
+
fn main() {}
LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | 0x2a is not a valid pointer
+ | out-of-bounds offset_from: 0x2a is not a valid pointer
| inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $DIR/offset_from_ub.rs:23:14
--> $DIR/offset_from_ub.rs:36:14
|
LL | unsafe { ptr_offset_from(ptr, ptr) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:43:14
|
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x10 is not a valid pointer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x10 is not a valid pointer
-error: aborting due to 5 previous errors
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:52:14
+ |
+LL | unsafe { ptr_offset_from(end_ptr, start_ptr) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:61:14
+ |
+LL | unsafe { ptr_offset_from(start_ptr, end_ptr) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:69:14
+ |
+LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
+
+error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0080`.
LL | unsafe { intrinsics::offset(self, count) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | pointer arithmetic failed: 0x0 is not a valid pointer
+ | pointer arithmetic failed: null pointer is not a valid pointer
| inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $DIR/offset_ub.rs:22:50
#![stable(feature = "core", since = "1.6.0")]
#![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
enum Opt<T> {
Some(T),
error[E0015]: cannot call non-const closure in constant functions
- --> $DIR/unstable-const-fn-in-libcore.rs:23:26
+ --> $DIR/unstable-const-fn-in-libcore.rs:22:26
|
LL | Opt::None => f(),
| ^^^
| +++++++++++++++++++++++++++++
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:18:53
+ --> $DIR/unstable-const-fn-in-libcore.rs:17:53
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^ constant functions cannot evaluate destructors
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:18:47
+ --> $DIR/unstable-const-fn-in-libcore.rs:17:47
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^^^^ constant functions cannot evaluate destructors
--- /dev/null
+// build-pass
+// compile-flags: -Cdebuginfo=2
+// fixes issue #94725
+
+#![feature(allocator_api)]
+
+use std::alloc::{AllocError, Allocator, Layout};
+use std::ptr::NonNull;
+
+struct ZST;
+
+unsafe impl Allocator for &ZST {
+ fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+ todo!()
+ }
+ unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+ todo!()
+ }
+}
+
+fn main() {
+ let _ = Box::<i32, &ZST>::new_in(43, &ZST);
+}
-// check-pass
+// build-pass
// compile-flags: -Cdebuginfo=2
// fixes issue #94149
+++ /dev/null
-#![feature(staged_api)]
-#![stable(feature = "stable_test_feature", since = "1.0.0")]
-#[deprecated] //~ ERROR `#[deprecated]` cannot be used in staged API
-fn main() {}
+++ /dev/null
-error: `#[deprecated]` cannot be used in staged API
- --> $DIR/deprecation-in-staged-api.rs:3:1
- |
-LL | #[deprecated]
- | ^^^^^^^^^^^^^ use `#[rustc_deprecated]` instead
-
-error: aborting due to previous error
-
--- /dev/null
+// compile-flags: --crate-type=lib
+
+#![no_implicit_prelude]
+
+#[deprecated(suggestion = "foo")] //~ ERROR suggestions on deprecated items are unstable
+struct Foo {}
--- /dev/null
+error: suggestions on deprecated items are unstable
+ --> $DIR/feature-gate-deprecated_suggestion.rs:5:14
+ |
+LL | #[deprecated(suggestion = "foo")]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(deprecated_suggestion)]` to the crate root
+ = note: see #XXX for more details
+
+error: aborting due to previous error
+
+++ /dev/null
-#![deny(deprecated_in_future)]
-
-#![feature(staged_api)]
-
-#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-
-#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-pub struct S1;
-
-#[rustc_deprecated(since = "TBD", reason = "literally never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-pub struct S2;
-
-fn main() {
- let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
- let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never
-}
+++ /dev/null
-error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
- --> $DIR/rustc_deprecation-in-future.rs:16:13
- |
-LL | let _ = S1;
- | ^^
- |
-note: the lint level is defined here
- --> $DIR/rustc_deprecation-in-future.rs:1:9
- |
-LL | #![deny(deprecated_in_future)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never
- --> $DIR/rustc_deprecation-in-future.rs:17:13
- |
-LL | let _ = S2;
- | ^^
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+#![deny(deprecated_in_future)]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+
+#[deprecated(since = "99.99.99", note = "effectively never")]
+#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+pub struct S1;
+
+#[deprecated(since = "TBD", note = "literally never")]
+#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+pub struct S2;
+
+fn main() {
+ let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
+ let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never
+}
--- /dev/null
+error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
+ --> $DIR/staged-deprecation-in-future.rs:16:13
+ |
+LL | let _ = S1;
+ | ^^
+ |
+note: the lint level is defined here
+ --> $DIR/staged-deprecation-in-future.rs:1:9
+ |
+LL | #![deny(deprecated_in_future)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never
+ --> $DIR/staged-deprecation-in-future.rs:17:13
+ |
+LL | let _ = S2;
+ | ^^
+
+error: aborting due to 2 previous errors
+
// run-rustfix
#![feature(staged_api)]
+#![feature(deprecated_suggestion)]
#![stable(since = "1.0.0", feature = "test")]
struct Foo;
impl Foo {
- #[rustc_deprecated(
+ #[deprecated(
since = "1.0.0",
- reason = "replaced by `replacement`",
+ note = "replaced by `replacement`",
suggestion = "replacement",
)]
#[stable(since = "1.0.0", feature = "test")]
}
mod bar {
- #[rustc_deprecated(
+ #[deprecated(
since = "1.0.0",
- reason = "replaced by `replacement`",
+ note = "replaced by `replacement`",
suggestion = "replacement",
)]
#[stable(since = "1.0.0", feature = "test")]
// run-rustfix
#![feature(staged_api)]
+#![feature(deprecated_suggestion)]
#![stable(since = "1.0.0", feature = "test")]
struct Foo;
impl Foo {
- #[rustc_deprecated(
+ #[deprecated(
since = "1.0.0",
- reason = "replaced by `replacement`",
+ note = "replaced by `replacement`",
suggestion = "replacement",
)]
#[stable(since = "1.0.0", feature = "test")]
}
mod bar {
- #[rustc_deprecated(
+ #[deprecated(
since = "1.0.0",
- reason = "replaced by `replacement`",
+ note = "replaced by `replacement`",
suggestion = "replacement",
)]
#[stable(since = "1.0.0", feature = "test")]
error: use of deprecated function `bar::deprecated`: replaced by `replacement`
- --> $DIR/suggestion.rs:41:10
+ --> $DIR/suggestion.rs:42:10
|
LL | bar::deprecated();
| ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement`
|
note: the lint level is defined here
- --> $DIR/suggestion.rs:7:9
+ --> $DIR/suggestion.rs:8:9
|
LL | #![deny(deprecated)]
| ^^^^^^^^^^
error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
- --> $DIR/suggestion.rs:39:9
+ --> $DIR/suggestion.rs:40:9
|
LL | foo.deprecated();
| ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
async fn foo() {
//~^ ERROR `async fn` is not permitted in Rust 2015
//~| NOTE to use `async fn`, switch to Rust 2018 or later
-//~| HELP set `edition = "2021"` in `Cargo.toml`
+//~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
let x = async {};
let x = 42;
//~^ ERROR expected identifier, found keyword `let`
//~| NOTE expected identifier, found keyword
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
42
};
42
//~^ ERROR expected identifier, found `42`
//~| NOTE expected identifier
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
};
y.await;
LL | async fn foo() {
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: expected identifier, found keyword `let`
LL | let x = 42;
| ^^^ expected identifier, found keyword
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: expected identifier, found `42`
LL | 42
| ^^ expected identifier
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0422]: cannot find struct, variant or union type `async` in this scope
+#![feature(lint_reasons)]
+
#![deny(unused_attributes)]
#![allow()] //~ ERROR unused attribute
+#![expect()] //~ ERROR unused attribute
#![warn()] //~ ERROR unused attribute
#![deny()] //~ ERROR unused attribute
#![forbid()] //~ ERROR unused attribute
error: unused attribute
- --> $DIR/empty-attributes.rs:8:1
+ --> $DIR/empty-attributes.rs:11:1
|
LL | #[repr()]
| ^^^^^^^^^ help: remove this attribute
|
note: the lint level is defined here
- --> $DIR/empty-attributes.rs:1:9
+ --> $DIR/empty-attributes.rs:3:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
= note: attribute `repr` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:11:1
+ --> $DIR/empty-attributes.rs:14:1
|
LL | #[target_feature()]
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
= note: attribute `target_feature` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:2:1
+ --> $DIR/empty-attributes.rs:4:1
|
LL | #![allow()]
| ^^^^^^^^^^^ help: remove this attribute
= note: attribute `allow` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:3:1
+ --> $DIR/empty-attributes.rs:5:1
+ |
+LL | #![expect()]
+ | ^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+ --> $DIR/empty-attributes.rs:6:1
|
LL | #![warn()]
| ^^^^^^^^^^ help: remove this attribute
= note: attribute `warn` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:4:1
+ --> $DIR/empty-attributes.rs:7:1
|
LL | #![deny()]
| ^^^^^^^^^^ help: remove this attribute
= note: attribute `deny` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:5:1
+ --> $DIR/empty-attributes.rs:8:1
|
LL | #![forbid()]
| ^^^^^^^^^^^^ help: remove this attribute
= note: attribute `forbid` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:6:1
+ --> $DIR/empty-attributes.rs:9:1
|
LL | #![feature()]
| ^^^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `feature` with an empty list has no effect
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
--> $DIR/empty-never-array.rs:10:9
|
-LL | / enum Helper<T, U> {
-LL | | T(T, [!; 0]),
- | | - not covered
-LL | | #[allow(dead_code)]
-LL | | U(U),
-LL | | }
- | |_- `Helper<T, U>` defined here
-...
-LL | let Helper::U(u) = Helper::T(t, []);
- | ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+LL | let Helper::U(u) = Helper::T(t, []);
+ | ^^^^^^^^^^^^ pattern `T(_, _)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Helper<T, U>` defined here
+ --> $DIR/empty-never-array.rs:4:5
+ |
+LL | enum Helper<T, U> {
+ | ------
+LL | T(T, [!; 0]),
+ | ^ not covered
= note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Helper::U(u) = Helper::T(t, []) { /* */ }
+LL | let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
+ | ++++++++++ ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
|
+LL | let Helper::U(u) = Helper::T(t, []) else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
LL | match x { }
| ^ patterns `None` and `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | None,
- | ---- not covered
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + None | Some(_) => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
--> $DIR/E0004.rs:9:11
|
-LL | / enum Terminator {
-LL | | HastaLaVistaBaby,
- | | ---------------- not covered
-LL | | TalkToMyHand,
-LL | | }
- | |_- `Terminator` defined here
-...
-LL | match x {
- | ^ pattern `HastaLaVistaBaby` not covered
+LL | match x {
+ | ^ pattern `HastaLaVistaBaby` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Terminator` defined here
+ --> $DIR/E0004.rs:2:5
+ |
+LL | enum Terminator {
+ | ----------
+LL | HastaLaVistaBaby,
+ | ^^^^^^^^^^^^^^^^ not covered
= note: the matched value is of type `Terminator`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Terminator::TalkToMyHand => {}
+LL + HastaLaVistaBaby => todo!()
+ |
error: aborting due to previous error
LL | let Some(y) = x;
| ^^^^^^^ pattern `None` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | None,
- | ---- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Some(y) = x { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let y = if let Some(y) = x { y } else { todo!() };
+ | ++++++++++ ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ |
+LL | let Some(y) = x else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
LL | for Some(x) in xs {}
| ^^^^^^^ pattern `None` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | None,
- | ---- not covered
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
error: aborting due to previous error
--> $DIR/E0507.rs:12:5
|
LL | x.borrow().nothing_is_true();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+ | ^^^^^^^^^^^-----------------
+ | | |
+ | | value moved due to this method call
+ | move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+ |
+note: this function takes ownership of the receiver `self`, which moves value
+ --> $DIR/E0507.rs:6:24
+ |
+LL | fn nothing_is_true(self) {}
+ | ^^^^
error: aborting due to previous error
LL | let Ok(_x) = foo();
| ^^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, !>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Ok(_x) = foo() { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let _x = if let Ok(_x) = foo() { _x } else { todo!() };
+ | +++++++++++ +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ |
+LL | let Ok(_x) = foo() else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
+// check-fail
+
#![deny(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
#![allow(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
fn main() {
enum Foo {
}
#[allow(non_exhaustive_omitted_patterns)]
+ //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+ //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+ //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+ //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
match Foo::A {
Foo::A => {}
Foo::B => {}
}
- //~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
- //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
- //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
- //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+ //~^^^^ ERROR non-exhaustive patterns: `C` not covered
match Foo::A {
Foo::A => {}
#[warn(non_exhaustive_omitted_patterns)]
_ => {}
}
- //~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
- //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+ //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+ //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
}
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
|
LL | #![deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unknown_lints)]` on by default
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
|
LL | #![allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
|
LL | #[allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
|
LL | #[allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
|
LL | #![deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
|
LL | #![allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
|
LL | #[allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
|
LL | #[allow(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
- --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `non_exhaustive_omitted_patterns` lint is unstable
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
-error: aborting due to 10 previous errors
+error[E0004]: non-exhaustive patterns: `C` not covered
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
+ |
+LL | match Foo::A {
+ | ^^^^^^ pattern `C` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
+ |
+LL | enum Foo {
+ | ---
+LL | A, B, C,
+ | ^ not covered
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::B => {}
+LL + C => todo!()
+ |
+
+error: aborting due to previous error; 10 warnings emitted
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0004`.
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0..=usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN..=isize::MAX => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
-#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
fn main() {}
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
--> $DIR/feature-gate-rustc-attrs-1.rs:5:1
|
LL | #[rustc_nonnull_optimization_guaranteed]
--- /dev/null
+// check-pass
+
+// `test_unstable_lint` is for testing and should never be stabilized.
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
--- /dev/null
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unknown_lints)]` on by default
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
+++ /dev/null
-// Testing gating of `#[rustc_deprecated]` in "weird" places.
-//
-// This file sits on its own because these signal errors, making
-// this test incompatible with the "warnings only" nature of
-// issue-43106-gating-of-builtin-attrs.rs
-
-#![rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-
-#[rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-mod rustc_deprecated {
- mod inner {
- #![rustc_deprecated()]
- //~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR missing 'since' [E0542]
- }
-
- #[rustc_deprecated()]
- //~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR missing 'since' [E0542]
- fn f() {}
-
- #[rustc_deprecated()]
- //~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR missing 'since' [E0542]
- //~| ERROR missing 'since' [E0542]
- struct S;
-
- #[rustc_deprecated()]
- //~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR missing 'since' [E0542]
- type T = S;
-
- #[rustc_deprecated()]
- //~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR missing 'since' [E0542]
- impl S {}
-}
-
-fn main() {}
+++ /dev/null
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
- |
-LL | #![rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
- |
-LL | #![rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
- |
-LL | #![rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
- |
-LL | #![rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Type {
+ type Ref<'a>;
+}
+
+pub trait AsBytes {}
+
+impl AsBytes for &str {}
+
+pub struct Utf8;
+
+impl Type for Utf8 {
+ type Ref<'a> = &'a str;
+}
+
+pub struct Bytes<T: Type> {
+ _marker: PhantomData<T>,
+}
+
+impl<T: Type> Bytes<T>
+where
+ for<'a> T::Ref<'a>: AsBytes,
+{
+ pub fn new() -> Self {
+ Self {
+ _marker: PhantomData,
+ }
+ }
+}
+
+fn main() {
+ let _b = Bytes::<Utf8>::new();
+}
--- /dev/null
+error[E0311]: the parameter type `T` may not live long enough
+ --> $DIR/issue-91139.rs:27:12
+ |
+LL | fn foo<T>() {
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
-// check-pass
+// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
+
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[nll] check-pass
+//[migrate] check-fail
#![feature(generic_associated_types)]
fn foo<T>() {
let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+ //[migrate]~^ the parameter type `T` may not live long enough
}
pub fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+use std::marker::PhantomData;
+
+pub struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>);
+
+fn new_id() -> Id<'static> {
+ Id(PhantomData)
+}
+
+pub trait HasLifetime where {
+ type AtLifetime<'a>;
+}
+
+pub struct ExistentialLifetime<S: HasLifetime>(S::AtLifetime<'static>);
+
+impl<S: HasLifetime> ExistentialLifetime<S> {
+ pub fn new<F>(f: F) -> ExistentialLifetime<S>
+ where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
+ ExistentialLifetime(f(new_id()))
+ }
+}
+
+
+struct ExampleS<'id>(Id<'id>);
+
+struct ExampleMarker;
+
+impl HasLifetime for ExampleMarker {
+ type AtLifetime<'id> = ExampleS<'id>;
+}
+
+
+fn broken0() -> ExistentialLifetime<ExampleMarker> {
+ fn new_helper<'id>(id: Id<'id>) -> ExampleS<'id> {
+ ExampleS(id)
+ }
+
+ ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken1() -> ExistentialLifetime<ExampleMarker> {
+ fn new_helper<'id>(id: Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {
+ ExampleS(id)
+ }
+
+ ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken2() -> ExistentialLifetime<ExampleMarker> {
+ ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Scalar: 'static {
+ type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+impl Scalar for i32 {
+ type RefType<'a> = i32;
+}
+
+impl Scalar for String {
+ type RefType<'a> = &'a str;
+}
+
+impl Scalar for bool {
+ type RefType<'a> = i32;
+}
+
+impl<'a> ScalarRef<'a> for bool {}
+
+impl<'a> ScalarRef<'a> for i32 {}
+
+impl<'a> ScalarRef<'a> for &'a str {}
+
+fn str_contains(a: &str, b: &str) -> bool {
+ a.contains(b)
+}
+
+pub struct BinaryExpression<A: Scalar, B: Scalar, O: Scalar, F>
+where
+ F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+ f: F,
+ _phantom: PhantomData<(A, B, O)>,
+}
+
+impl<A: Scalar, B: Scalar, O: Scalar, F> BinaryExpression<A, B, O, F>
+where
+ F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+ pub fn new(f: F) -> Self {
+ Self {
+ f,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+fn main() {
+ BinaryExpression::<String, String, bool, _>::new(str_contains);
+}
LL | m!(0f32, f32::NEG_INFINITY..);
| ^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8
LL | m!(0f32, ..f32::INFINITY);
| ^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
LL | m!('a', ..core::char::MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
LL | m!('a', ..ALMOST_MAX);
| ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10fffe}'..='\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
LL | m!('a', ALMOST_MIN..);
| ^^^ pattern `'\u{0}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{0}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
LL | m!('a', ..=ALMOST_MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
LL | m!('a', ..=VAL | VAL_2..);
| ^^^ pattern `'b'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 'b' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:31:8
LL | m!('a', ..VAL_1 | VAL_2..);
| ^^^ pattern `'b'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 'b' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
LL | m!(0, ..u8::MAX);
| ^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `254_u8..=u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 254_u8..=u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
LL | m!(0, ..u16::MAX);
| ^ pattern `u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `65534_u16..=u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 65534_u16..=u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
LL | m!(0, ..u32::MAX);
| ^ pattern `u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `4294967294_u32..=u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 4294967294_u32..=u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
LL | m!(0, ..u64::MAX);
| ^ pattern `u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 18446744073709551614_u64..=u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
LL | m!(0, ..u128::MAX);
| ^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
LL | m!(0, ..i8::MAX);
| ^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `126_i8..=i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 126_i8..=i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i8::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
LL | m!(0, ..i16::MAX);
| ^ pattern `i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `32766_i16..=i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 32766_i16..=i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i16::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
LL | m!(0, ..i32::MAX);
| ^ pattern `i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `2147483646_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 2147483646_i32..=i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i32::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
LL | m!(0, ..i64::MAX);
| ^ pattern `i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 9223372036854775806_i64..=i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i64::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
LL | m!(0, ..i128::MAX);
| ^ pattern `i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i128::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i128 => todo!() }
+ |
error: aborting due to 68 previous errors
+// check-pass
+
// FamilyType (GAT workaround)
pub trait FamilyLt<'a> {
type Out;
fn main() {
task(annotate(
- //~^ the size
- //~^^ the trait bound
Annotate::<RefMutFamily<usize>>::new(),
|value: &mut usize| {
*value = 2;
+++ /dev/null
-error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-... |
-LL | | }
-LL | | ));
- | |_____^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `impl Execute`
-note: required by a bound in `task`
- --> $DIR/issue-62529-1.rs:69:9
- |
-LL | fn task<P>(processor: P) -> Task
- | ^ required by this bound in `task`
-help: consider relaxing the implicit `Sized` restriction
- |
-LL | fn task<P: ?Sized>(processor: P) -> Task
- | ++++++++
-
-error[E0277]: the trait bound `impl Execute: Execute` is not satisfied
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-... |
-LL | | }
-LL | | ));
- | |_____^ the trait `Execute` is not implemented for `impl Execute`
- |
-note: required by a bound in `task`
- --> $DIR/issue-62529-1.rs:70:10
- |
-LL | fn task<P>(processor: P) -> Task
- | ---- required by a bound in this
-LL | where P: Execute + 'static {
- | ^^^^^^^ required by this bound in `task`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
+ --> $DIR/issue-71955.rs:54:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
+ --> $DIR/issue-71955.rs:58:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
-error: fatal error triggered by #[rustc_error]
- --> $DIR/issue-71955.rs:47:1
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
|
-LL | fn main() {
- | ^^^^^^^^^
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&&str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&Wrapper<'_>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
-error: aborting due to previous error
+error: aborting due to 4 previous errors
+For more information about this error, try `rustc --explain E0308`.
struct Wrapper<'a>(&'a str);
-// Because nll currently succeeds and migrate doesn't
-#[rustc_error]
fn main() {
- //[nll]~^ fatal
fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
(&s[..1], &s[..])
}
foo(bar, "string", |s| s.len() == 5);
//[migrate]~^ ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
foo(baz, "string", |s| s.0.len() == 5);
//[migrate]~^ ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
}
fn give_me_ice<T>() {
callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
- //~^ ERROR: the trait bound `T: SomeTrait<'_>` is not satisfied
+ //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
+ //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
}
fn callee<T: Fn<(&'static (),)>>() {
LL | fn give_me_ice<T: SomeTrait<'_>>() {
| +++++++++++++++
-error: aborting due to previous error
+error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+ --> $DIR/issue-85455.rs:8:14
+ |
+LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn give_me_ice<T: SomeTrait<'_>>() {
+ | +++++++++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
| |
| `async` blocks are only allowed in Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
#[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have
fn foo8<X>() {}
+impl S {
+ #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+ fn foo9<const X: usize>() {}
+}
+
#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute
fn bar1() {}
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
error: malformed `rustc_legacy_const_generics` attribute input
- --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1
|
LL | #[rustc_legacy_const_generics]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
error: malformed `rustc_legacy_const_generics` attribute input
- --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:35:1
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1
|
LL | #[rustc_legacy_const_generics = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
LL | fn foo8<X>() {}
| - non-const generic parameter
+error: attribute should be applied to a function
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
+ |
+LL | #[rustc_legacy_const_generics(0)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn foo9<const X: usize>() {}
+ | ---------------------------- not a function
+
error: attribute should be applied to a function
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
|
|
= help: replace the const parameters with concrete consts
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
For more information about this error, try `rustc --explain E0044`.
impl Foo {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn foo(self) {}
}
-error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
--> $DIR/issue-21596.rs:4:22
|
LL | println!("{}", z.to_string());
- | ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
+ | ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
|
= note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
= note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
// run-pass
-// ignore-wasm32-bare FIXME(#93923) llvm miscompilation
use std::collections::HashMap;
use std::path::Path;
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
|
LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
- | ^^ ---
- | | |
- | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
LL | let mut bad_letters = vec!['e', 't', 'o', 'i'];
| --------------- move occurs because `bad_letters` has type `Vec<char>`, which does not implement the `Copy` trait
LL | for l in bad_letters {
- | -----------
- | |
- | `bad_letters` moved due to this implicit call to `.into_iter()`
- | help: consider borrowing to avoid moving into the for loop: `&bad_letters`
+ | ----------- `bad_letters` moved due to this implicit call to `.into_iter()`
...
LL | bad_letters.push('s');
| ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop
+ |
+LL | for l in &bad_letters {
+ | +
error: aborting due to previous error
LL | let orig = vec![true];
| ---- move occurs because `orig` has type `Vec<bool>`, which does not implement the `Copy` trait
LL | for _val in orig {}
- | ----
- | |
- | `orig` moved due to this implicit call to `.into_iter()`
- | help: consider borrowing to avoid moving into the for loop: `&orig`
+ | ---- `orig` moved due to this implicit call to `.into_iter()`
LL | let _closure = || orig;
| ^^ ---- use occurs due to use in closure
| |
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+ |
+LL | for _val in &orig {}
+ | +
error: aborting due to previous error
// test for #87707
// edition:2018
// run-fail
+// exec-env:RUST_BACKTRACE=0
// check-run-results
use std::sync::Once;
-thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:12:24
+thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:13:24
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:14:7
+thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:15:7
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub mod unstable_mod {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
pub fn unstable() {}
#![unstable(feature = "unstable_test_feature", issue = "none")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn foo() -> usize {
20
}
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
pub fn deprecated_future() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_unstable() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_unstable_text() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl MethodTester {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated(&self) {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_unstable(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_unstable_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub trait Trait {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated(&self) {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_unstable(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_unstable_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
type TypeUnstable = u8;
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
type TypeDeprecated = u8;
}
pub trait UnstableTrait { fn dummy(&self) { } }
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub trait DeprecatedTrait {
#[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
}
pub enum StableEnum {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableUnitStruct;
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub enum Enum {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedUnstableVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
UnstableVariant,
}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
pub inherit: u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub override2: u8,
#[stable(feature = "rust2", since = "2.0.0")]
pub struct Stable2(#[stable(feature = "rust2", since = "2.0.0")] pub u8,
#[unstable(feature = "unstable_test_feature", issue = "none")] pub u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8,
+ #[deprecated(since = "1.0.0", note = "text")] pub u8,
pub u8);
#[stable(feature = "rust1", since = "1.0.0")]
Override1,
#[unstable(feature = "unstable_test_feature", issue = "none")]
Override2,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
Override3,
}
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
pub override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub override2: u8,
}
pub struct Unstable2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8);
+ #[deprecated(since = "1.0.0", note = "text")] pub u8);
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct Deprecated {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct Deprecated2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "unstable_test_feature", issue = "none")] pub u8);
mod this_crate {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub trait Trait {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl Trait for MethodTester {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
}
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableUnitStruct;
pub enum Enum {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
UnstableVariant,
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableTupleStruct(isize);
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_fn_body() {
fn fn_in_body() {}
fn_in_body();
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
fn_in_body();
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub trait DeprecatedTrait {
fn dummy(&self) { }
}
mod this_crate {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub trait Trait {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl Trait for MethodTester {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
}
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableUnitStruct;
pub enum Enum {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
UnstableVariant,
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableTupleStruct(isize);
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_fn_body() {
fn fn_in_body() {}
fn_in_body(); //~ WARN use of deprecated function `this_crate::test_fn_body::fn_in_body`: text
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
fn_in_body(); //~ WARN use of deprecated function `this_crate::MethodTester::test_method_body::fn_in_body`: text
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub trait DeprecatedTrait {
fn dummy(&self) { }
}
inherit: u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
override2: u8,
}
struct Stable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+ #[deprecated(since = "1.0.0", note = "text")] u8);
#[unstable(feature = "unstable_test_feature", issue = "none")]
struct Unstable {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
override2: u8,
}
struct Unstable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+ #[deprecated(since = "1.0.0", note = "text")] u8);
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
struct Deprecated {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
struct Deprecated2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")] u8);
inherit: u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
override2: u8,
#[stable(feature = "rust2", since = "2.0.0")]
struct Stable2(u8,
#[stable(feature = "rust2", since = "2.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+ #[deprecated(since = "1.0.0", note = "text")] u8);
#[unstable(feature = "unstable_test_feature", issue = "none")]
struct Unstable {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
override1: u8,
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
override2: u8,
}
struct Unstable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+ #[deprecated(since = "1.0.0", note = "text")] u8);
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
struct Deprecated {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
struct Deprecated2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "unstable_test_feature", issue = "none")] u8);
mod this_crate {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "99.99.99", reason = "text")]
+ #[deprecated(since = "99.99.99", note = "text")]
pub fn deprecated_future() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub trait Trait {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl Trait for MethodTester {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
}
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableUnitStruct;
pub enum Enum {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
UnstableVariant,
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableTupleStruct(isize);
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_fn_body() {
fn fn_in_body() {}
fn_in_body();
impl MethodTester {
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
fn_in_body();
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub trait DeprecatedTrait {
fn dummy(&self) { }
}
+// check-pass
+
// edition:2018
-#![deny(must_not_suspend)] //~ ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
+#![deny(must_not_suspend)]
+//~^ WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
async fn other() {}
pub async fn uhoh(m: std::sync::Mutex<()>) {
- let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+ let _guard = m.lock().unwrap();
other().await;
}
-error[E0658]: the `must_not_suspend` lint is unstable
- --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+ --> $DIR/gated.rs:4:1
|
LL | #![deny(must_not_suspend)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unknown_lints)]` on by default
+ = note: the `must_not_suspend` lint is unstable
= note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
= help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
-error[E0658]: the `must_not_suspend` lint is unstable
- --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+ --> $DIR/gated.rs:4:1
|
LL | #![deny(must_not_suspend)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `must_not_suspend` lint is unstable
= note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
= help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
-error[E0658]: the `must_not_suspend` lint is unstable
- --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+ --> $DIR/gated.rs:4:1
|
LL | #![deny(must_not_suspend)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: the `must_not_suspend` lint is unstable
= note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
= help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
-error: `MutexGuard` held across a suspend point, but should not be
- --> $DIR/gated.rs:9:9
- |
-LL | let _guard = m.lock().unwrap();
- | ^^^^^^
-LL | other().await;
- | ------ the value is held across this suspend point
- |
-note: the lint level is defined here
- --> $DIR/gated.rs:2:9
- |
-LL | #![deny(must_not_suspend)]
- | ^^^^^^^^^^^^^^^^
-note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
- --> $DIR/gated.rs:9:9
- |
-LL | let _guard = m.lock().unwrap();
- | ^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/gated.rs:9:9
- |
-LL | let _guard = m.lock().unwrap();
- | ^^^^^^
-
-error: aborting due to 4 previous errors
+warning: 3 warnings emitted
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+#![feature(lint_reasons)]
+
+#![deny(unused_attributes)]
+
+#[allow(reason = "I want to allow something")]//~ ERROR unused attribute
+#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute
+#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute
+#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute
+#[forbid(reason = "Just some reason")]//~ ERROR unused attribute
+
+#[allow(clippy::box_collection, reason = "This is still valid")]
+#[warn(dead_code, reason = "This is also reasonable")]
+
+fn main() {}
--- /dev/null
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:5:1
+ |
+LL | #[allow(reason = "I want to allow something")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: the lint level is defined here
+ --> $DIR/lint-attribute-only-with-reason.rs:3:9
+ |
+LL | #![deny(unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: attribute `allow` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:6:1
+ |
+LL | #[expect(reason = "I don't know what I'm waiting for")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `expect` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:7:1
+ |
+LL | #[warn(reason = "This should be warn by default")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `warn` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:8:1
+ |
+LL | #[deny(reason = "All listed lints are denied")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `deny` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:9:1
+ |
+LL | #[forbid(reason = "Just some reason")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `forbid` without any lints has no effect
+
+error: aborting due to 5 previous errors
+
LL | fn foo(x: Vec<S>) {
| - move occurs because `x` has type `Vec<S>`, which does not implement the `Copy` trait
LL | for y in x {
- | -
- | |
- | `x` moved due to this implicit call to `.into_iter()`
- | help: consider borrowing to avoid moving into the for loop: `&x`
+ | - `x` moved due to this implicit call to `.into_iter()`
...
LL | let z = x;
| ^ value used here after move
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
+ |
+LL | for y in &x {
+ | +
error: aborting due to previous error
warning: Linking globals named 'foo': symbol multiply defined!
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
+error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
error: aborting due to previous error; 1 warning emitted
macro_rules! unstable_macro{ () => () }
#[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
+#[deprecated(since = "1.0.0", note = "deprecation note")]
#[macro_export]
macro_rules! deprecated_macro{ () => () }
macro local_unstable_modern() {}
#[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
#[macro_export]
macro_rules! local_deprecated{ () => () }
// unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
deprecated_macro!();
- //~^ WARN use of deprecated macro `deprecated_macro`: deprecation reason
+ //~^ WARN use of deprecated macro `deprecated_macro`: deprecation note
local_deprecated!();
- //~^ WARN use of deprecated macro `local_deprecated`: local deprecation reason
+ //~^ WARN use of deprecated macro `local_deprecated`: local deprecation note
}
|
= help: add `#![feature(unstable_macros)]` to the crate attributes to enable
-warning: use of deprecated macro `deprecated_macro`: deprecation reason
+warning: use of deprecated macro `deprecated_macro`: deprecation note
--> $DIR/macro-stability.rs:27:5
|
LL | deprecated_macro!();
|
= note: `#[warn(deprecated)]` on by default
-warning: use of deprecated macro `local_deprecated`: local deprecation reason
+warning: use of deprecated macro `local_deprecated`: local deprecation note
--> $DIR/macro-stability.rs:29:5
|
LL | local_deprecated!();
--- /dev/null
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! nested {
+ ( $a:ident ) => {
+ macro_rules! $a {
+ ( $$( $b:ident ),* ) => {
+ $$(
+ macro_rules! $b {
+ ( $$$$( $c:ident ),* ) => {
+ $$$$(
+ fn $c() -> &'static str { stringify!($c) }
+ ),*
+ };
+ }
+ )*
+ };
+ }
+ };
+}
+
+fn main() {
+ nested!(a);
+ a!(b);
+ b!(c);
+ assert_eq!(c(), "c");
+}
--- /dev/null
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! ignore {
+ ( $( $i:ident ),* ) => {{
+ let array: [i32; 0] = [$( ${ignore(i)} )*];
+ array
+ }};
+}
+
+fn main() {
+ assert_eq!(ignore!(a, b, c), []);
+}
--- /dev/null
+macro_rules! count {
+ ( $( $e:stmt ),* ) => {
+ ${ count(e) }
+ //~^ ERROR meta-variable expressions are unstable
+ };
+}
+
+fn main() {
+}
--- /dev/null
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:3:10
+ |
+LL | ${ count(e) }
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+#![feature(macro_metavar_expr)]
+
+// `curly` = Right hand side curly brackets
+// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function"
+// `round` = Left hand side round brackets
+
+macro_rules! curly__no_rhs_dollar__round {
+ ( $( $i:ident ),* ) => { ${ count(i) } };
+}
+
+macro_rules! curly__no_rhs_dollar__no_round {
+ ( $i:ident ) => { ${ count(i) } };
+}
+
+macro_rules! curly__rhs_dollar__round {
+ ( $( $i:ident ),* ) => { ${ count($i) } };
+ //~^ ERROR expected identifier, found `$`
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! curly__rhs_dollar__no_round {
+ ( $i:ident ) => { ${ count($i) } };
+ //~^ ERROR expected identifier, found `$`
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! no_curly__no_rhs_dollar__round {
+ ( $( $i:ident ),* ) => { count(i) };
+ //~^ ERROR cannot find function `count` in this scope
+ //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__no_rhs_dollar__no_round {
+ ( $i:ident ) => { count(i) };
+ //~^ ERROR cannot find function `count` in this scope
+ //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__rhs_dollar__round {
+ ( $( $i:ident ),* ) => { count($i) };
+ //~^ ERROR variable 'i' is still repeating at this depth
+}
+
+macro_rules! no_curly__rhs_dollar__no_round {
+ ( $i:ident ) => { count($i) };
+ //~^ ERROR cannot find function `count` in this scope
+}
+
+// Other scenarios
+
+macro_rules! dollar_dollar_in_the_lhs {
+ ( $$ $a:ident ) => {
+ //~^ ERROR unexpected token: $
+ };
+}
+
+macro_rules! extra_garbage_after_metavar {
+ ( $( $i:ident ),* ) => {
+ ${count() a b c}
+ //~^ ERROR unexpected token: a
+ //~| ERROR expected expression, found `$`
+ ${count(i a b c)}
+ //~^ ERROR unexpected token: a
+ ${count(i, 1 a b c)}
+ //~^ ERROR unexpected token: a
+ ${count(i) a b c}
+ //~^ ERROR unexpected token: a
+
+ ${ignore(i) a b c}
+ //~^ ERROR unexpected token: a
+ ${ignore(i a b c)}
+ //~^ ERROR unexpected token: a
+
+ ${index() a b c}
+ //~^ ERROR unexpected token: a
+ ${index(1 a b c)}
+ //~^ ERROR unexpected token: a
+
+ ${index() a b c}
+ //~^ ERROR unexpected token: a
+ ${index(1 a b c)}
+ //~^ ERROR unexpected token: a
+ };
+}
+
+const IDX: usize = 1;
+macro_rules! metavar_depth_is_not_literal {
+ ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ //~^ ERROR meta-variable expression depth must be a literal
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_in_the_lhs {
+ ( ${ length() } ) => {
+ //~^ ERROR unexpected token: {
+ //~| ERROR expected one of: `*`, `+`, or `?`
+ };
+}
+
+macro_rules! metavar_token_without_ident {
+ ( $( $i:ident ),* ) => { ${ ignore() } };
+ //~^ ERROR expected identifier
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_with_literal_suffix {
+ ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_without_parens {
+ ( $( $i:ident ),* ) => { ${ count{i} } };
+ //~^ ERROR meta-variable expression parameter must be wrapped in parentheses
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! open_brackets_without_tokens {
+ ( $( $i:ident ),* ) => { ${ {} } };
+ //~^ ERROR expected expression, found `$`
+ //~| ERROR expected identifier
+}
+
+macro_rules! unknown_metavar {
+ ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ //~^ ERROR unrecognized meta-variable expression
+ //~| ERROR expected expression
+}
+
+fn main() {
+ curly__no_rhs_dollar__round!(a, b, c);
+ curly__no_rhs_dollar__no_round!(a);
+ curly__rhs_dollar__round!(a, b, c);
+ curly__rhs_dollar__no_round!(a);
+ no_curly__no_rhs_dollar__round!(a, b, c);
+ no_curly__no_rhs_dollar__no_round!(a);
+ no_curly__rhs_dollar__round!(a, b, c);
+ no_curly__rhs_dollar__no_round!(a);
+ //~^ ERROR cannot find value `a` in this scope
+
+ extra_garbage_after_metavar!(a);
+ unknown_metavar!(a);
+ metavar_without_parens!(a);
+ metavar_token_without_ident!(a);
+ metavar_depth_is_not_literal!(a);
+ metavar_with_literal_suffix!(a);
+ open_brackets_without_tokens!(a)
+}
--- /dev/null
+error: expected identifier, found `$`
+ --> $DIR/syntax-errors.rs:16:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ count($i) } };
+ | ^^^^^ - help: try removing `$`
+
+error: expected identifier, found `$`
+ --> $DIR/syntax-errors.rs:22:26
+ |
+LL | ( $i:ident ) => { ${ count($i) } };
+ | ^^^^^ - help: try removing `$`
+
+error: unexpected token: $
+ --> $DIR/syntax-errors.rs:52:8
+ |
+LL | ( $$ $a:ident ) => {
+ | ^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+ --> $DIR/syntax-errors.rs:52:8
+ |
+LL | ( $$ $a:ident ) => {
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:59:19
+ |
+LL | ${count() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:59:19
+ |
+LL | ${count() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:62:19
+ |
+LL | ${count(i a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:62:19
+ |
+LL | ${count(i a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:64:22
+ |
+LL | ${count(i, 1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:64:22
+ |
+LL | ${count(i, 1 a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:66:20
+ |
+LL | ${count(i) a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:66:20
+ |
+LL | ${count(i) a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:69:21
+ |
+LL | ${ignore(i) a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:69:21
+ |
+LL | ${ignore(i) a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:71:20
+ |
+LL | ${ignore(i a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:71:20
+ |
+LL | ${ignore(i a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:74:19
+ |
+LL | ${index() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:74:19
+ |
+LL | ${index() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:76:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:76:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:79:19
+ |
+LL | ${index() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:79:19
+ |
+LL | ${index() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:81:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:81:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+
+error: meta-variable expression depth must be a literal
+ --> $DIR/syntax-errors.rs:88:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ | ^^^^^
+
+error: unexpected token: {
+ --> $DIR/syntax-errors.rs:94:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+ --> $DIR/syntax-errors.rs:94:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+error: expected one of: `*`, `+`, or `?`
+ --> $DIR/syntax-errors.rs:94:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+error: expected identifier
+ --> $DIR/syntax-errors.rs:101:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ ignore() } };
+ | ^^^^^^
+
+error: only unsuffixes integer literals are supported in meta-variable expressions
+ --> $DIR/syntax-errors.rs:107:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ | ^^^^^
+
+error: meta-variable expression parameter must be wrapped in parentheses
+ --> $DIR/syntax-errors.rs:113:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ count{i} } };
+ | ^^^^^
+
+error: expected identifier
+ --> $DIR/syntax-errors.rs:119:31
+ |
+LL | ( $( $i:ident ),* ) => { ${ {} } };
+ | ^^^^^^
+
+error: unrecognized meta-variable expression
+ --> $DIR/syntax-errors.rs:125:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:16:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ count($i) } };
+ | ^ expected expression
+...
+LL | curly__rhs_dollar__round!(a, b, c);
+ | ---------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:22:23
+ |
+LL | ( $i:ident ) => { ${ count($i) } };
+ | ^ expected expression
+...
+LL | curly__rhs_dollar__no_round!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable 'i' is still repeating at this depth
+ --> $DIR/syntax-errors.rs:40:36
+ |
+LL | ( $( $i:ident ),* ) => { count($i) };
+ | ^^
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:59:9
+ |
+LL | ${count() a b c}
+ | ^ expected expression
+...
+LL | extra_garbage_after_metavar!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:125:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ | ^ expected expression
+...
+LL | unknown_metavar!(a);
+ | ------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:113:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ count{i} } };
+ | ^ expected expression
+...
+LL | metavar_without_parens!(a);
+ | -------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:101:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ ignore() } };
+ | ^ expected expression
+...
+LL | metavar_token_without_ident!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:88:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ | ^ expected expression
+...
+LL | metavar_depth_is_not_literal!(a);
+ | -------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:107:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ | ^ expected expression
+...
+LL | metavar_with_literal_suffix!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:119:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ {} } };
+ | ^ expected expression
+...
+LL | open_brackets_without_tokens!(a)
+ | -------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:28:30
+ |
+LL | ( $( $i:ident ),* ) => { count(i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__round!(a, b, c);
+ | ---------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/syntax-errors.rs:28:36
+ |
+LL | ( $( $i:ident ),* ) => { count(i) };
+ | ^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__round!(a, b, c);
+ | ---------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:34:23
+ |
+LL | ( $i:ident ) => { count(i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__no_round!(a);
+ | ------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/syntax-errors.rs:34:29
+ |
+LL | ( $i:ident ) => { count(i) };
+ | ^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__no_round!(a);
+ | ------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:45:23
+ |
+LL | ( $i:ident ) => { count($i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__rhs_dollar__no_round!(a);
+ | ---------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/syntax-errors.rs:138:37
+ |
+LL | no_curly__rhs_dollar__no_round!(a);
+ | ^ not found in this scope
+
+error: aborting due to 37 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/match_non_exhaustive.rs:23:11
|
-LL | enum L { A, B }
- | ---------------
- | | |
- | | not covered
- | `L` defined here
-...
LL | match l { L::A => () };
| ^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L` defined here
+ --> $DIR/match_non_exhaustive.rs:10:13
+ |
+LL | enum L { A, B }
+ | - ^ not covered
= note: the matched value is of type `L`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match l { L::A => (), B => todo!() };
+ | ++++++++++++++
error[E0004]: non-exhaustive patterns: type `E1` is non-empty
--> $DIR/match_non_exhaustive.rs:28:11
LL | match e1 {};
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+ |
+LL | pub enum E1 {}
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match e1 {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match_non_exhaustive.rs:30:11
LL | match e2 { E2::A => (), E2::B => () };
| ^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+ |
+LL | pub enum E2 { A, B }
+ | ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match e2 { E2::A => (), E2::B => (), _ => todo!() };
+ | ++++++++++++++
error: aborting due to 3 previous errors
--- /dev/null
+fn get_slice() -> &'static [i32] {
+ &[1, 2, 3, 4]
+}
+
+fn main() {
+ let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599]
+}
--- /dev/null
+error[E0599]: `&'static [i32]` is not an iterator
+ --> $DIR/issue-94581.rs:6:29
+ |
+LL | let sqsum = get_slice().map(|i| i * i).sum();
+ | ^^^ `&'static [i32]` is not an iterator; try calling `.iter()`
+ |
+ = note: the following trait bounds were not satisfied:
+ `&'static [i32]: Iterator`
+ which is required by `&mut &'static [i32]: Iterator`
+ `[i32]: Iterator`
+ which is required by `&mut [i32]: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
let y = Foo;
y.zero()
- .take() //~ ERROR the method
+ .take() //~ ERROR not an iterator
.one(0);
y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
}
LL | fn two(self, _: isize, _: isize) -> Foo { self }
| ^^^ ---- -------- --------
-error[E0599]: the method `take` exists for struct `Foo`, but its trait bounds were not satisfied
+error[E0599]: `Foo` is not an iterator
--> $DIR/method-call-err-msg.rs:19:7
|
LL | pub struct Foo;
| doesn't satisfy `Foo: Iterator`
...
LL | .take()
- | ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds
+ | ^^^^ `Foo` is not an iterator
|
= note: the following trait bounds were not satisfied:
`Foo: Iterator`
let _ = E::A as *const u8; //~ ERROR is invalid
let _ = 'a' as *const u8; //~ ERROR is invalid
- let _ = 42usize as *const [u8]; //~ ERROR is invalid
+ let _ = 42usize as *const [u8]; //~ ERROR cannot cast `usize` to a pointer that is wide
let _ = v as *const [u8]; //~ ERROR cannot cast
let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type
let _ = foo as *const str; //~ ERROR is invalid
LL | let _ = 'a' as *const u8;
| ^^^^^^^^^^^^^^^^
-error[E0606]: casting `usize` as `*const [u8]` is invalid
- --> $DIR/cast-rfc0401.rs:51:13
+error[E0606]: cannot cast `usize` to a pointer that is wide
+ --> $DIR/cast-rfc0401.rs:51:24
|
LL | let _ = 42usize as *const [u8];
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ------- ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
+ | |
+ | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
--> $DIR/cast-rfc0401.rs:52:13
use std::iter::once;
fn main() {
once::<&str>("str").fuse().filter(|a: &str| true).count();
- //~^ ERROR the method
+ //~^ ERROR not an iterator
//~| ERROR type mismatch in closure arguments
}
LL | P: FnMut(&Self::Item) -> bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied
+error[E0599]: `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
--> $DIR/issue-36053-2.rs:7:55
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
- | -------------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds
+ | -------------- ^^^^^ `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
| |
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
| doesn't satisfy `_: FnMut<(&&str,)>`
LL | let b = Box::new(true);
| - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait
LL | test!({b});
- | ^
- | |
- | value moved here
- | value used here after move
+ | ^ value used here after move
error: aborting due to previous error
LL | let implicit_into_iter = vec![true];
| ------------------ move occurs because `implicit_into_iter` has type `Vec<bool>`, which does not implement the `Copy` trait
LL | for _val in implicit_into_iter {}
- | ------------------
- | |
- | `implicit_into_iter` moved due to this implicit call to `.into_iter()`
- | help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter`
+ | ------------------ `implicit_into_iter` moved due to this implicit call to `.into_iter()`
LL | implicit_into_iter;
| ^^^^^^^^^^^^^^^^^^ value used here after move
+ |
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+ |
+LL | for _val in &implicit_into_iter {}
+ | +
error[E0382]: use of moved value: `explicit_into_iter`
--> $DIR/move-fn-self-receiver.rs:67:5
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
...
LL | (_, 2) if take(x) => (),
- | ^
- | |
- | value moved here
- | value used here after move
+ | ^ value used here after move
error: aborting due to previous error
// Regression test for issue #55825
// Tests that we don't emit a spurious warning in NLL mode
+// check-pass
+
#![feature(nll)]
-const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
fn main() { }
+++ /dev/null
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/issue-55825-const-fn.rs:6:32
- |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+// mir borrowck previously incorrectly set `tainted_by_errors`
+// when buffering lints, which resulted in ICE later on,
+// see #94502.
+
+// Errors with `nll` which is already tested in enough other tests,
+// so we ignore it here.
+//
+// ignore-compare-mode-nll
+
+struct Repro;
+impl Repro {
+ fn get(&self) -> &i32 {
+ &3
+ }
+
+ fn insert(&mut self, _: i32) {}
+}
+
+fn main() {
+ let x = &0;
+ let mut conflict = Repro;
+ let prev = conflict.get();
+ conflict.insert(*prev + *x);
+ //~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
+ //~| WARN this borrowing pattern was not meant to be accepted
+}
--- /dev/null
+warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
+ --> $DIR/lint-no-err.rs:25:5
+ |
+LL | let prev = conflict.get();
+ | -------------- immutable borrow occurs here
+LL | conflict.insert(*prev + *x);
+ | ^^^^^^^^^^^^^^^^-----^^^^^^
+ | | |
+ | | immutable borrow later used here
+ | mutable borrow occurs here
+ |
+ = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
+ = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
+ = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
+
+warning: 1 warning emitted
+
--> $DIR/match-guards-always-borrow.rs:8:14
|
LL | (|| { let bar = foo; bar.take() })();
- | ^^ ---
- | | |
- | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
--- /dev/null
+#![feature(rustc_attrs)]
+
+trait Foo<A> {
+ fn foo(self);
+}
+
+#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
+impl<A, B, C> Foo<A> for (A, B, C) {
+ fn foo(self) {}
+}
+
+fn main() {
+ Foo::<usize>::foo((1i32, 1i32, 1i32));
+ //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+ --> $DIR/impl-substs.rs:13:23
+ |
+LL | Foo::<usize>::foo((1i32, 1i32, 1i32));
+ | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
LL | match (0u8, 0u8) {
| ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, u8)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 | 1, 2 | 3) => {}
+LL + (2_u8..=u8::MAX, _) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:9:11
LL | match ((0u8,),) {
| ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((u8,),)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((0 | 1,) | (2 | 3,),) => {}
+LL + ((4_u8..=u8::MAX)) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:13:11
LL | match (Some(0u8),) {
| ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<u8>,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None | Some(0 | 1),) => {}
+LL + (Some(2_u8..=u8::MAX)) => todo!()
+ |
error: aborting due to 3 previous errors
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | if let (0 | (1 | 2)) = 0 { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | if let (0 | (1 | 2)) = 0 { todo!() }
+ | ++ ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
--> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
LL | match 0 {
| ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ 0 | (1 | 2) => {}
+LL + i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
+ |
error: aborting due to 2 previous errors
LL | match uninhab_ref() {
| ^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&!`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_ref() {
+LL + _ => todo!(),
+LL + }
+ |
error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
--> $DIR/always-inhabited-union-ref.rs:27:11
|
-LL | / pub union Foo {
-LL | | foo: !,
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match uninhab_union() {
- | ^^^^^^^^^^^^^^^
+LL | match uninhab_union() {
+ | ^^^^^^^^^^^^^^^
+ |
+note: `Foo` defined here
+ --> $DIR/always-inhabited-union-ref.rs:10:11
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | pub union Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_union() {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to 2 previous errors
LL | match Foo::A {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:1:1
+ |
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::B => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:14:11
LL | match Foo::A {
| ^^^^^^ pattern `B` not covered
|
- ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
|
-LL | B,
- | - not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+ | | ^ not covered
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::C => {}
+LL + B => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` and `_` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:20:11
LL | match Foo::A {
| ^^^^^^ patterns `B` and `_` not covered
|
- ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
|
-LL | B,
- | - not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+ | | ^ not covered
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::A => {}
+LL + B | _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:25:11
LL | match None {
| ^^^^ patterns `Some(B)` and `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Foo>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<Foo>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Some(Foo::A) => {}
+LL + Some(B) | Some(_) => todo!()
+ |
error: aborting due to 4 previous errors
LL | match_no_arms!(0u8);
| ^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/empty-match.rs:81:20
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/empty-match.rs:82:20
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:83:20
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_no_arms!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:84:20
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_no_arms!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:85:20
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_no_arms!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/empty-match.rs:87:24
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/empty-match.rs:90:24
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/empty-match.rs:91:24
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:92:24
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + Foo(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:93:24
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + Foo(_) | Bar => todo!()
+ |
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:94:24
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error: aborting due to 22 previous errors
LL | match_no_arms!(0u8);
| ^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/empty-match.rs:81:20
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/empty-match.rs:82:20
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:83:20
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_no_arms!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:84:20
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_no_arms!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:85:20
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_no_arms!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/empty-match.rs:87:24
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/empty-match.rs:90:24
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/empty-match.rs:91:24
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:92:24
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + Foo(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:93:24
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + Foo(_) | Bar => todo!()
+ |
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:94:24
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error: aborting due to 22 previous errors
LL | match 0.0 {
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0.0..=1.0 => {}
+LL + _ => todo!()
+ |
error: unreachable pattern
--> $DIR/floats.rs:16:7
LL | match 0u8 {
| ^^^ pattern `128_u8..=u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 128 ..= 255 if true => {}
+LL + 128_u8..=u8::MAX => todo!()
+ |
error: aborting due to previous error
LL | m!(0u8, 0..255);
| ^^^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/exhaustiveness.rs:48:8
LL | m!(0u8, 0..=254);
| ^^^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u8` not covered
--> $DIR/exhaustiveness.rs:49:8
LL | m!(0u8, 1..=255);
| ^^^ pattern `0_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `42_u8` not covered
--> $DIR/exhaustiveness.rs:50:8
LL | m!(0u8, 0..42 | 43..=255);
| ^^^ pattern `42_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 42_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/exhaustiveness.rs:51:8
LL | m!(0i8, -128..127);
| ^^^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/exhaustiveness.rs:52:8
LL | m!(0i8, -128..=126);
| ^^^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
--> $DIR/exhaustiveness.rs:53:8
LL | m!(0i8, -127..=127);
| ^^^ pattern `i8::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_i8` not covered
--> $DIR/exhaustiveness.rs:54:11
LL | match 0i8 {
| ^^^ pattern `0_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= i8::MAX => {}
+LL + 0_i8 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/exhaustiveness.rs:59:8
LL | m!(0u128, 0..=ALMOST_MAX);
| ^^^^^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
--> $DIR/exhaustiveness.rs:60:8
LL | m!(0u128, 0..=4);
| ^^^^^ pattern `5_u128..=u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 5_u128..=u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u128` not covered
--> $DIR/exhaustiveness.rs:61:8
LL | m!(0u128, 1..=u128::MAX);
| ^^^^^ pattern `0_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
--> $DIR/exhaustiveness.rs:69:11
LL | match (0u8, true) {
| ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 ..= 255, true) => {}
+LL + (126_u8..=127_u8, false) => todo!()
+ |
error: aborting due to 12 previous errors
LL | match 7usize {}
| ^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to previous error
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0 ..= usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:17:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN ..= isize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:22:8
LL | m!(0usize, 0..=usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:24:8
LL | m!(0usize, 0..5 | 5..=usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:26:8
LL | m!(0usize, 0..usize::MAX | usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int.rs:28:8
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(usize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ (_, _) => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:31:8
LL | m!(0isize, isize::MIN..=isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:33:8
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:35:8
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int.rs:37:8
LL | m!((0isize, true), (isize::MIN..5, true)
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(isize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ (_, _) => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:41:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= isize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int.rs:48:11
LL | match 7usize {}
| ^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to 12 previous errors
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0..=usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/precise_pointer_matching-message.rs:11:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN..=isize::MAX => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match (T::T1(()), V::V2(true)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(T, V)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::T2(()), V::V2(b)) => (),
+LL ~ (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
+ |
error: aborting due to previous error
LL | match (a, b) {
| ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<usize>, Option<usize>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (Some(_), None) | (None, Some(_)) => {}
+LL + (None, None) | (Some(_), Some(_)) => todo!()
+ |
error: aborting due to previous error
LL | match "world" {
| ^^^^^^^ pattern `&_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&_` not covered
--> $DIR/issue-30240.rs:6:11
LL | match "world" {
| ^^^^^^^ pattern `&_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match () { }
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `()`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match () {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
LL | match x { }
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `*const Bottom`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
--> $DIR/issue-31561.rs:8:9
|
-LL | / enum Thing {
-LL | | Foo(u8),
-LL | | Bar,
- | | --- not covered
-LL | | Baz
- | | --- not covered
-LL | | }
- | |_- `Thing` defined here
-...
-LL | let Thing::Foo(y) = Thing::Foo(1);
- | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+LL | let Thing::Foo(y) = Thing::Foo(1);
+ | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Thing` defined here
+ --> $DIR/issue-31561.rs:3:5
+ |
+LL | enum Thing {
+ | -----
+LL | Foo(u8),
+LL | Bar,
+ | ^^^ not covered
+LL | Baz
+ | ^^^ not covered
= note: the matched value is of type `Thing`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
+LL | let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
+ | ++++++++++ ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
|
+LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
LL | match (A, ()) {
| ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Enum, ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (A, _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
--> $DIR/issue-35609.rs:14:11
LL | match (A, A) {
| ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Enum, Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (_, A) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:18:11
LL | match ((A, ()), ()) {
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:22:11
LL | match ((A, ()), A) {
| ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:26:11
LL | match ((A, ()), ()) {
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, _), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
--> $DIR/issue-35609.rs:31:11
|
-LL | struct S(Enum, ());
- | ------------------- `S` defined here
-...
LL | match S(A, ()) {
| ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `S` defined here
+ --> $DIR/issue-35609.rs:6:8
+ |
+LL | struct S(Enum, ());
+ | ^
= note: the matched value is of type `S`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ S(A, _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
--> $DIR/issue-35609.rs:35:11
|
-LL | struct Sd { x: Enum, y: () }
- | ---------------------------- `Sd` defined here
-...
LL | match (Sd { x: A, y: () }) {
| ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Sd` defined here
+ --> $DIR/issue-35609.rs:7:8
+ |
+LL | struct Sd { x: Enum, y: () }
+ | ^^
= note: the matched value is of type `Sd`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Sd { x: A, y: _ } => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
--> $DIR/issue-35609.rs:39:11
LL | match Some(A) {
| ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Option<Enum>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_^
= note: the matched value is of type `Option<Enum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ None => (),
+LL + _ => todo!()
+ |
error: aborting due to 8 previous errors
LL | box NodeKind::Element(ed) => match ed.kind {
| ^^^^^^^ pattern `box _` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Box<ElementKind>` defined here
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+ |
+LL | / pub struct Box<
+LL | | T: ?Sized,
+LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+LL | | >(Unique<T>, A);
+ | |________________^
= note: the matched value is of type `Box<ElementKind>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL + box _ => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
--> $DIR/issue-39362.rs:10:11
|
-LL | / enum Foo {
-LL | | Bar { bar: Bar, id: usize }
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match f {
- | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+LL | match f {
+ | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/issue-39362.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | Bar { bar: Bar, id: usize }
+ | ^^^ not covered
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Foo::Bar { bar: Bar::B, .. } => (),
+LL ~ _ => todo!(),
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `C(QA)` not covered
--> $DIR/issue-40221.rs:11:11
|
-LL | / enum P {
-LL | | C(PC),
- | | - not covered
-LL | | }
- | |_- `P` defined here
-...
-LL | match proto {
- | ^^^^^ pattern `C(QA)` not covered
+LL | match proto {
+ | ^^^^^ pattern `C(QA)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `P` defined here
+ --> $DIR/issue-40221.rs:2:5
+ |
+LL | enum P {
+ | -
+LL | C(PC),
+ | ^ not covered
= note: the matched value is of type `P`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ P::C(PC::Q) => (),
+LL ~ C(QA) => todo!(),
+ |
error: aborting due to previous error
LL | println!("foo {:}", match tup {
| ^^^ pattern `(true, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (true, true) => "baz",
+LL + (true, false) => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
--> $DIR/issue-50900.rs:15:11
|
-LL | pub struct Tag(pub Context, pub u16);
- | ------------------------------------- `Tag` defined here
-...
LL | match Tag::ExifIFDPointer {
| ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Tag` defined here
+ --> $DIR/issue-50900.rs:2:12
+ |
+LL | pub struct Tag(pub Context, pub u16);
+ | ^^^
= note: the matched value is of type `Tag`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Tag::ExifIFDPointer => {}
+LL + Tag(Exif, _) => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
--> $DIR/issue-56379.rs:8:11
|
-LL | / enum Foo {
-LL | | A(bool),
- | | - not covered
-LL | | B(bool),
- | | - not covered
-LL | | C(bool),
- | | - not covered
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match Foo::A(true) {
- | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
+LL | match Foo::A(true) {
+ | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/issue-56379.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | A(bool),
+ | ^ not covered
+LL | B(bool),
+ | ^ not covered
+LL | C(bool),
+ | ^ not covered
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::C(true) => {}
+LL + A(false) | B(false) | C(false) => todo!()
+ |
error: aborting due to previous error
LL | match (x, y) {
| ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(X, Option<X>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+LL ~ _ => todo!(),
+ |
error: aborting due to previous error
enum A {}
//~^ NOTE `A` defined here
+ //~| NOTE
fn f(a: &A) {
match a {}
error[E0004]: non-exhaustive patterns: type `&A` is non-empty
- --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11
|
-LL | enum A {}
- | --------- `A` defined here
-...
LL | match a {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6
+ |
+LL | enum A {}
+ | ^
= note: the matched value is of type `&A`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match a {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to previous error
LL | match (true, false) {
| ^^^^^^^^^^^^^ pattern `(true, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (false, true) => (),
+LL + (true, false) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
--> $DIR/match-arm-statics-2.rs:29:11
LL | match Some(Some(North)) {
| ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Option<Direction>>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^
+ | | |
+ | | not covered
+ | | not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Option<Option<Direction>>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ----
- | |
- | not covered
- | not covered
+LL ~ None => (),
+LL + Some(Some(West)) => todo!()
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Option<Option<Direction>>`
error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
--> $DIR/match-arm-statics-2.rs:48:11
|
-LL | / struct Foo {
-LL | | bar: Option<Direction>,
-LL | | baz: NewBool
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/match-arm-statics-2.rs:40:8
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { bar: Some(EAST), .. } => (),
+LL + Foo { bar: Some(North), baz: NewBool(true) } => todo!()
+ |
error: aborting due to 3 previous errors
LL | match buf {
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8; 4]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
--> $DIR/match-byte-array-patterns-2.rs:10:11
LL | match buf {
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match 0 { 1 => () }
| ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
+ | ++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-non-exhaustive.rs:3:11
LL | match 0 { 0 if false => () }
| ^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match 0 { 0 if false => (), _ => todo!() }
+ | ++++++++++++++
error: aborting due to 2 previous errors
LL | match private::DATA {
| ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Private>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ }) => {}
+LL + Some(Private { misc: true, .. }) => todo!()
+ |
error: aborting due to previous error
LL | match list {
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[Option<()>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[.., Some(_), _] => {}
+LL ~ &[_, Some(_), .., None, _] => todo!(),
+ |
error: aborting due to previous error
#[derive(Clone)]
enum E {
-//~^ `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
+ //~^ NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
A,
B,
- //~^ not covered
- //~| not covered
- //~| not covered
- //~| not covered
- //~| not covered
- //~| not covered
+ //~^ NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
C
//~^ not covered
//~| not covered
fn by_val(e: E) {
let e1 = e.clone();
match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
+ //~^ NOTE patterns `B` and `C` not covered
+ //~| NOTE the matched value is of type `E`
E::A => {}
}
let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
+ //~^ NOTE patterns `B` and `C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `E`
}
fn by_ref_once(e: &E) {
match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
+ //~^ NOTE patterns `&B` and `&C` not covered
+ //~| NOTE the matched value is of type `&E`
E::A => {}
}
let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
+ //~^ NOTE patterns `&B` and `&C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&E`
}
fn by_ref_thrice(e: & &mut &E) {
match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+ //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE the matched value is of type `&&mut &E`
E::A => {}
}
let E::A = e;
//~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&&mut &E`
}
enum Opt {
-//~^ `Opt` defined here
-//~| `Opt` defined here
+ //~^ NOTE
+ //~| NOTE
Some(u8),
None,
- //~^ not covered
+ //~^ NOTE `Opt` defined here
+ //~| NOTE `Opt` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
}
fn ref_pat(e: Opt) {
match e {//~ ERROR non-exhaustive patterns: `None` not covered
+ //~^ NOTE pattern `None` not covered
+ //~| NOTE the matched value is of type `Opt`
Opt::Some(ref _x) => {}
}
let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+ //~^ NOTE the matched value is of type `Opt`
+ //~| NOTE pattern `None` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
}
fn main() {}
error[E0004]: non-exhaustive patterns: `B` and `C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:32:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e1 {
- | ^^ patterns `B` and `C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:38:11
+ |
+LL | match e1 {
+ | ^^ patterns `B` and `C` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + B | C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `B` and `C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:36:9
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `B` and `C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:44:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `B` and `C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | if let E::A = e { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:40:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e {
- | ^ patterns `&B` and `&C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:52:11
+ |
+LL | match e {
+ | ^ patterns `&B` and `&C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &B | &C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:44:9
+ --> $DIR/non-exhaustive-defined-here.rs:58:9
|
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `&B` and `&C` not covered
+LL | let E::A = e;
+ | ^^^^ patterns `&B` and `&C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
|
-LL | if let E::A = e { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:48:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e {
- | ^ patterns `&&mut &B` and `&&mut &C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:66:11
+ |
+LL | match e {
+ | ^ patterns `&&mut &B` and `&&mut &C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&&mut &E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &&mut &B | &&mut &C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:52:9
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:72:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
- = note: the matched value is of type `&&mut &E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
|
-LL | if let E::A = e { /* */ }
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
+ = note: the matched value is of type `&&mut &E`
+help: you might want to use `if let` to ignore the variants that aren't matched
|
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `None` not covered
- --> $DIR/non-exhaustive-defined-here.rs:65:11
- |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | | Some(u8),
-LL | | None,
- | | ---- not covered
-LL | |
-LL | | }
- | |_- `Opt` defined here
-...
-LL | match e {
- | ^ pattern `None` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:92:11
+ |
+LL | match e {
+ | ^ pattern `None` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:84:5
+ |
+LL | enum Opt {
+ | ---
+...
+LL | None,
+ | ^^^^ not covered
= note: the matched value is of type `Opt`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Opt::Some(ref _x) => {}
+LL + None => todo!()
+ |
error[E0005]: refutable pattern in local binding: `None` not covered
- --> $DIR/non-exhaustive-defined-here.rs:69:9
- |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | | Some(u8),
-LL | | None,
- | | ---- not covered
-LL | |
-LL | | }
- | |_- `Opt` defined here
-...
-LL | let Opt::Some(ref _x) = e;
- | ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:98:9
+ |
+LL | let Opt::Some(ref _x) = e;
+ | ^^^^^^^^^^^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:84:5
+ |
+LL | enum Opt {
+ | ---
+...
+LL | None,
+ | ^^^^ not covered
= note: the matched value is of type `Opt`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Opt::Some(ref _x) = e { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
+ | +++++++++++ +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ |
+LL | let Opt::Some(ref _x) = e else { todo!() };
+ | ++++++++++++++++
error: aborting due to 8 previous errors
LL | match (l1, l2) {
| ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
+LL + (Some(&[]), Err(_)) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `A(C)` not covered
--> $DIR/non-exhaustive-match-nested.rs:15:11
|
-LL | enum T { A(U), B }
- | ------------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match x {
| ^ pattern `A(C)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match-nested.rs:1:10
+ |
+LL | enum T { A(U), B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::B => { panic!("goodbye"); }
+LL + A(C) => todo!()
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `A` not covered
--> $DIR/non-exhaustive-match.rs:7:11
|
-LL | enum T { A, B }
- | ---------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match x { T::B => { } }
| ^ pattern `A` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:10
+ |
+LL | enum T { A, B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match x { T::B => { } A => todo!() }
+ | ++++++++++++
error[E0004]: non-exhaustive patterns: `false` not covered
--> $DIR/non-exhaustive-match.rs:8:11
LL | match true {
| ^^^^ pattern `false` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `bool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ true => {}
+LL + false => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/non-exhaustive-match.rs:11:11
LL | match Some(10) {
| ^^^^^^^^ pattern `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
+LL ~ None => {}
+LL + Some(_) => todo!()
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Option<i32>`
error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
--> $DIR/non-exhaustive-match.rs:14:11
LL | match (2, 3, 4) {
| ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(i32, i32, i32)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (_, _, 4) => {}
+LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
--> $DIR/non-exhaustive-match.rs:18:11
LL | match (T::A, T::A) {
| ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(T, T)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::B, T::A) => {}
+LL + (A, A) | (B, B) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/non-exhaustive-match.rs:22:11
|
-LL | enum T { A, B }
- | ---------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match T::A {
| ^^^^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:13
+ |
+LL | enum T { A, B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::A => {}
+LL + B => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[]` not covered
--> $DIR/non-exhaustive-match.rs:33:11
LL | match *vec {
| ^^^^ pattern `[]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Option<isize>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [None] => {}
+LL + [] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
--> $DIR/non-exhaustive-match.rs:46:11
LL | match *vec {
| ^^^^ pattern `[_, _, _, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[f32]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => (),
+LL + [_, _, _, _, ..] => todo!()
+ |
error: aborting due to 8 previous errors
error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:7:11
|
-LL | / struct Foo {
-LL | | first: bool,
-LL | | second: Option<[usize; 4]>
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match (Foo { first: true, second: None }) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+LL | match (Foo { first: true, second: None }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:1:8
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
+LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Red` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:23:11
|
-LL | / enum Color {
-LL | | Red,
- | | --- not covered
-LL | | Green,
-LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-LL | | }
- | |_- `Color` defined here
-...
-LL | match Color::Red {
- | ^^^^^^^^^^ pattern `Red` not covered
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `Red` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:17:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+ | -----
+LL | Red,
+ | ^^^ not covered
= note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::Green => (),
+LL + Red => todo!()
+ |
error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:35:11
|
-LL | / enum Direction {
-LL | | North, East, South, West
- | | ---- ----- ---- not covered
- | | | |
- | | | not covered
- | | not covered
-LL | | }
- | |_- `Direction` defined here
-...
-LL | match Direction::North {
- | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+LL | match Direction::North {
+ | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+ |
+note: `Direction` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:31:12
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Direction {
+ | ---------
+LL | North, East, South, West
+ | ^^^^ ^^^^^ ^^^^ not covered
+ | | |
+ | | not covered
+ | not covered
= note: the matched value is of type `Direction`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Direction::North => (),
+LL + East | South | West => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered
--> $DIR/non-exhaustive-pattern-witness.rs:46:11
|
-LL | / enum ExcessiveEnum {
-LL | | First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
-LL | | }
- | |_- `ExcessiveEnum` defined here
-...
-LL | match ExcessiveEnum::First {
- | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
+LL | match ExcessiveEnum::First {
+ | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `ExcessiveEnum` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+ |
+LL | enum ExcessiveEnum {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `ExcessiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ExcessiveEnum::First => (),
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:54:11
|
-LL | / enum Color {
-LL | | Red,
-LL | | Green,
-LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
- | | ---------- not covered
-LL | | }
- | |_- `Color` defined here
-...
-LL | match Color::Red {
- | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:19:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+ | -----
+...
+LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+ | ^^^^^^^^^^ not covered
= note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
+LL + CustomRGBA { a: true, .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:70:11
LL | match *x {
| ^^ pattern `[Second(true), Second(false)]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Enum]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_, _, ref tail @ .., _] => (),
+LL + [Second(true), Second(false)] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((), false)` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:83:11
LL | match ((), false) {
| ^^^^^^^^^^^ pattern `((), false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((), bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((), true) => (),
+LL + ((), false) => todo!()
+ |
error: aborting due to 7 previous errors
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `(i32, (Option<i32>, i32))`
-help: you might want to use `if let` to ignore the variant that isn't matched
- |
-LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ }
+help: you might want to use `if let` to ignore the variants that aren't matched
|
+LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }
+ | ++ ~~~~~~~~~~~
error: aborting due to 2 previous errors
LL | match s2 {
| ^^ pattern `&[false, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:12:11
LL | match s3 {
| ^^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:16:11
LL | match s10 {
| ^^^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 10]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:25:11
LL | match s2 {
| ^^ pattern `&[false, true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:30:11
LL | match s3 {
| ^^ pattern `&[false, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:35:11
LL | match s {
| ^ pattern `&[false, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:42:11
LL | match s {
| ^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => {}
+LL + &[_, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:46:11
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_] => {}
+LL + &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:51:11
LL | match s {
| ^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:56:11
LL | match s {
| ^ pattern `&[false, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:62:11
LL | match s {
| ^ pattern `&[_, .., false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., true] => {}
+LL + &[_, .., false] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:69:11
LL | match s {
| ^ pattern `&[_, _, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[_, _, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:76:11
LL | match s {
| ^ pattern `&[true, _, .., _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [false, .., false] => {}
+LL + &[true, _, .., _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:85:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[true] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:89:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:93:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[false] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:98:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:103:11
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST => {}
+LL + &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:108:11
LL | match s {
| ^ pattern `&[false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[_, _, ..] => {}
+LL + &[false] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:121:11
LL | match s1 {
| ^^ pattern `&[false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST1 => {}
+LL + &[false] => todo!()
+ |
error: aborting due to 20 previous errors
LL | match Foo::Stable {
| ^^^^^^^^^^^ patterns `Stable2` and `_` not covered
|
- ::: $DIR/auxiliary/unstable.rs:9:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:9:5
|
-LL | Stable2,
- | ------- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable2,
+ | | ^^^^^^^ not covered
+LL | | #[unstable(feature = "unstable_test_feature", issue = "none")]
+LL | | Unstable,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::Stable => {}
+LL + Stable2 | _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/stable-gated-patterns.rs:13:11
LL | match Foo::Stable {
| ^^^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:5:1
+ |
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+... |
+LL | | Unstable,
+LL | | }
+ | |_^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::Stable2 => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered
--> $DIR/struct-like-enum-nonexhaustive.rs:8:11
|
-LL | / enum A {
-LL | | B { x: Option<isize> },
- | | - not covered
-LL | | C
-LL | | }
- | |_- `A` defined here
-...
-LL | match x {
- | ^ pattern `B { x: Some(_) }` not covered
+LL | match x {
+ | ^ pattern `B { x: Some(_) }` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+ --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
+ |
+LL | enum A {
+ | -
+LL | B { x: Option<isize> },
+ | ^ not covered
= note: the matched value is of type `A`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ A::B { x: None } => {}
+LL + B { x: Some(_) } => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
--> $DIR/tuple-struct-nonexhaustive.rs:5:11
|
-LL | struct Foo(isize, isize);
- | ------------------------- `Foo` defined here
-...
LL | match x {
| ^ pattern `Foo(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/tuple-struct-nonexhaustive.rs:1:8
+ |
+LL | struct Foo(isize, isize);
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo(2, b) => println!("{}", b)
+LL + Foo(_, _) => todo!()
+ |
error: aborting due to previous error
LL | match data {
| ^^^^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ b"" => 1,
+LL ~ &[_, ..] => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
--> $DIR/type_polymorphic_byte_str_literals.rs:23:11
LL | match data {
| ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ [_, _, _] => 1,
+LL ~ _ => todo!(),
+ |
error: aborting due to 2 previous errors
LL | match Foo::Stable {
| ^^^^^^^^^^^ pattern `Unstable` not covered
|
- ::: $DIR/auxiliary/unstable.rs:11:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:11:5
|
-LL | Unstable,
- | -------- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+... |
+LL | | Unstable,
+ | | ^^^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::Stable2 => {}
+LL + Unstable => todo!()
+ |
error: aborting due to previous error
LL | let Ok(x) = res;
| ^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, &R>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, &R>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Ok(x) = res { /* */ }
+LL | let x = if let Ok(x) = res { x } else { todo!() };
+ | ++++++++++ ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
|
+LL | let Ok(x) = res else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
LL | match sl {
| ^^ pattern `&[]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [first, remainder @ ..] => {}
+LL ~ &[] => todo!(),
+ |
error: aborting due to previous error
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `EmptyNonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:18:1
+ |
+LL | pub enum EmptyNonExhaustiveEnum {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/enum.rs:16:11
LL | match enum_unit {
| ^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:4:1
+ |
+LL | / pub enum NonExhaustiveEnum {
+LL | | Unit,
+LL | | Tuple(u32),
+LL | | Struct { field: u32 },
+LL | | }
+ | |_^
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ NonExhaustiveEnum::Struct { .. } => "third",
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/enum.rs:23:11
LL | match enum_unit {};
| ^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:4:1
+ |
+LL | / pub enum NonExhaustiveEnum {
+LL | | Unit,
+LL | | Tuple(u32),
+LL | | Struct { field: u32 },
+LL | | }
+ | |_^
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match enum_unit {
+LL + _ => todo!(),
+LL ~ };
+ |
error: aborting due to 3 previous errors
error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/enum_same_crate_empty_match.rs:33:11
|
-LL | / pub enum NonExhaustiveEnum {
-LL | | Unit,
- | | ---- not covered
-LL | |
-LL | | Tuple(u32),
- | | ----- not covered
-LL | |
-LL | | Struct { field: u32 }
- | | ------ not covered
-LL | |
-LL | | }
- | |_- `NonExhaustiveEnum` defined here
-...
-LL | match NonExhaustiveEnum::Unit {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match NonExhaustiveEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/enum_same_crate_empty_match.rs:5:5
+ |
+LL | pub enum NonExhaustiveEnum {
+ | -----------------
+LL | Unit,
+ | ^^^^ not covered
+LL |
+LL | Tuple(u32),
+ | ^^^^^ not covered
+LL |
+LL | Struct { field: u32 }
+ | ^^^^^^ not covered
= note: the matched value is of type `NonExhaustiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match NonExhaustiveEnum::Unit {
+LL + Unit | Tuple(_) | Struct { .. } => todo!(),
+LL + }
+ |
error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/enum_same_crate_empty_match.rs:35:11
|
-LL | / pub enum NormalEnum {
-LL | | Unit,
- | | ---- not covered
-LL | |
-LL | | Tuple(u32),
- | | ----- not covered
-LL | |
-LL | | Struct { field: u32 }
- | | ------ not covered
-LL | |
-LL | | }
- | |_- `NormalEnum` defined here
-...
-LL | match NormalEnum::Unit {}
- | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match NormalEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `NormalEnum` defined here
+ --> $DIR/enum_same_crate_empty_match.rs:14:5
+ |
+LL | pub enum NormalEnum {
+ | ----------
+LL | Unit,
+ | ^^^^ not covered
+LL |
+LL | Tuple(u32),
+ | ^^^^^ not covered
+LL |
+LL | Struct { field: u32 }
+ | ^^^^^^ not covered
= note: the matched value is of type `NormalEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match NormalEnum::Unit {
+LL + Unit | Tuple(_) | Struct { .. } => todo!(),
+LL + }
+ |
error: aborting due to 3 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:26:1
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match.rs:23:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:28:1
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:30:1
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match.rs:33:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:32:1
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
--> $DIR/indirect_match_same_crate.rs:34:11
|
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
- | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/indirect_match_same_crate.rs:20:12
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:38:11
|
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
- | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/indirect_match_same_crate.rs:22:12
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:42:11
|
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
- | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/indirect_match_same_crate.rs:24:12
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match_same_crate.rs:48:11
|
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
- | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/indirect_match_same_crate.rs:26:12
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:26:1
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:28:1
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:30:1
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:32:1
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:5:1
+ |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match.rs:23:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:9:1
+ |
+LL | / pub struct UninhabitedStruct {
+LL | | _priv: !,
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:14:1
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match.rs:31:11
LL | match x {}
| ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
- ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:17:23
|
-LL | #[non_exhaustive] Tuple(!),
- | ----- not covered
-LL | #[non_exhaustive] Struct { x: ! }
- | ------ not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | | #[non_exhaustive] Tuple(!),
+ | | ^^^^^ not covered
+LL | | #[non_exhaustive] Struct { x: ! }
+ | | ^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match_same_crate.rs:30:11
|
-LL | / pub struct UninhabitedStruct {
-LL | | _priv: !,
-LL | | }
- | |_- `UninhabitedStruct` defined here
-...
-LL | match x {}
- | ^
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match x {}
+ | ^
+ |
+note: `UninhabitedStruct` defined here
+ --> $DIR/match_same_crate.rs:8:12
+ |
+LL | pub struct UninhabitedStruct {
+ | ^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match_same_crate.rs:34:11
|
-LL | pub struct UninhabitedTupleStruct(!);
- | ------------------------------------- `UninhabitedTupleStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/match_same_crate.rs:13:12
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_same_crate.rs:38:11
|
-LL | / pub enum UninhabitedVariants {
-LL | | #[non_exhaustive] Tuple(!),
- | | ----- not covered
-LL | | #[non_exhaustive] Struct { x: ! }
- | | ------ not covered
-LL | | }
- | |_- `UninhabitedVariants` defined here
-...
-LL | match x {}
- | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match x {}
+ | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `UninhabitedVariants` defined here
+ --> $DIR/match_same_crate.rs:16:23
+ |
+LL | pub enum UninhabitedVariants {
+ | -------------------
+LL | #[non_exhaustive] Tuple(!),
+ | ^^^^^ not covered
+LL | #[non_exhaustive] Struct { x: ! }
+ | ^^^^^^ not covered
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 3 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:5:1
+ |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match_with_exhaustive_patterns.rs:26:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:9:1
+ |
+LL | / pub struct UninhabitedStruct {
+LL | | _priv: !,
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match_with_exhaustive_patterns.rs:30:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:14:1
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_with_exhaustive_patterns.rs:34:11
LL | match x {}
| ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
- ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:17:23
|
-LL | #[non_exhaustive] Tuple(!),
- | ----- not covered
-LL | #[non_exhaustive] Struct { x: ! }
- | ------ not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | | #[non_exhaustive] Tuple(!),
+ | | ^^^^^ not covered
+LL | | #[non_exhaustive] Struct { x: ! }
+ | | ^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
- |
-LL | let ptr: fn() -> L = attributed;
- | ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
- |
-LL | ptr()
- | ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
- |
-LL | let ptr: fn() -> L = attributed;
- | ^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
|
LL | ptr()
| ^^^^^
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
LL | if &let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if !let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if *let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if -let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if (let 0 = 0)? {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:47:13
+ |
+LL | if true || let 0 = 0 {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:48:17
LL | if (true || let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:48:14
+ |
+LL | if (true || let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:49:25
LL | if true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:49:22
+ |
+LL | if true && (true || let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:50:25
LL | if true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:50:13
+ |
+LL | if true || (true && let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:53:12
LL | if x = let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if (let 0 = 0).. {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | if let true = let true = true {}
| ^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while &let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while !let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while *let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while -let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while (let 0 = 0)? {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:111:16
+ |
+LL | while true || let 0 = 0 {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:112:20
LL | while (true || let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:112:17
+ |
+LL | while (true || let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:113:28
LL | while true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:113:25
+ |
+LL | while true && (true || let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:114:28
LL | while true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:114:16
+ |
+LL | while true || (true && let 0 = 0) {}
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:117:15
LL | while x = let 0 = 0 {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while (let 0 = 0).. {}
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | while let true = let true = true {}
| ^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | &let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | !let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | *let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | -let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | (let 0 = 0)?;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true || let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:184:10
+ |
+LL | true || let 0 = 0;
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:185:14
LL | (true || let 0 = 0);
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:185:11
+ |
+LL | (true || let 0 = 0);
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:186:22
LL | true && (true || let 0 = 0);
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+ --> $DIR/disallowed-positions.rs:186:19
+ |
+LL | true && (true || let 0 = 0);
+ | ^^
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:189:9
LL | x = let 0 = 0;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true..(let 0 = 0);
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | ..(let 0 = 0);
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | (let 0 = 0)..;
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | (let true = let true = true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | &let 0 = 0
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true && let 1 = 1
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true && let 1 = 1
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true && let 1 = 1
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
LL | true && let 1 = 1
| ^^^^^^^^^
|
- = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: only supported directly in conditions of `if` and `while` expressions
= note: as well as when nested within `&&` and parentheses in those conditions
error[E0308]: mismatched types
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait MyTrait {
// check-pass
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait MyPartialEq {
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
error[E0277]: can't compare `T` with `T` in const contexts
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^ no implementation for `T == T`
|
note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^
error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^
// check-pass
-#![feature(const_fn_trait_bound)]
-
struct S;
impl PartialEq for S {
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
error[E0277]: can't compare `S` with `S` in const contexts
- --> $DIR/call-generic-method-nonconst.rs:19:34
+ --> $DIR/call-generic-method-nonconst.rs:18:34
|
LL | pub const EQ: bool = equals_self(&S);
| ----------- ^^ no implementation for `S == S`
|
= help: the trait `~const PartialEq` is not implemented for `S`
note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
- --> $DIR/call-generic-method-nonconst.rs:19:34
+ --> $DIR/call-generic-method-nonconst.rs:18:34
|
LL | pub const EQ: bool = equals_self(&S);
| ^^
note: required by a bound in `equals_self`
- --> $DIR/call-generic-method-nonconst.rs:12:25
+ --> $DIR/call-generic-method-nonconst.rs:11:25
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
const fn answer_p1<F>(f: &F) -> u8
where
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)] // FIXME is this needed?
trait ConstDefaultFn: Sized {
fn b(self);
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
|
note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^
error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_precise_live_drops)]
const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Drop {
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:44:5
+ --> $DIR/const-drop-fail.rs:43:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
| ++++
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
|
note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required because it appears within the type `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:17:8
+ --> $DIR/const-drop-fail.rs:16:8
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:48:5
+ --> $DIR/const-drop-fail.rs:47:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
- --> $DIR/const-drop-fail.rs:29:25
+ --> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
// revisions: stock precise
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
-#![feature(const_fn_trait_bound)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
use std::marker::PhantomData;
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:44:5
+ --> $DIR/const-drop-fail.rs:43:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
| ++++
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
|
note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required because it appears within the type `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:17:8
+ --> $DIR/const-drop-fail.rs:16:8
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:48:5
+ --> $DIR/const-drop-fail.rs:47:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
- --> $DIR/const-drop-fail.rs:29:25
+ --> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
// run-pass
// revisions: stock precise
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_mut_refs)]
#![feature(never_type)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait Tr {}
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+ --> $DIR/default-method-body-is-const-body-checking.rs:11:15
|
LL | foo::<()>();
| ^^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
- --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+ --> $DIR/default-method-body-is-const-body-checking.rs:11:15
|
LL | foo::<()>();
| ^^
note: required by a bound in `foo`
- --> $DIR/default-method-body-is-const-body-checking.rs:7:28
+ --> $DIR/default-method-body-is-const-body-checking.rs:6:28
|
LL | const fn foo<T>() where T: ~const Tr {}
| ^^^^^^^^^ required by this bound in `foo`
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait Tr {
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^
error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^
#![feature(staged_api)]
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![stable(since = "1", feature = "foo")]
trait Tr {
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
use std::marker::PhantomData;
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Tr {
fn req(&self);
error: const trait implementations may not use non-const default functions
- --> $DIR/impl-with-default-fn-fail.rs:18:1
+ --> $DIR/impl-with-default-fn-fail.rs:17:1
|
LL | / impl const Tr for S {
LL | | fn req(&self) {}
= note: `prov` not implemented
error: const trait implementations may not use non-const default functions
- --> $DIR/impl-with-default-fn-fail.rs:28:1
+ --> $DIR/impl-with-default-fn-fail.rs:27:1
|
LL | / impl const Tr for u32 {
LL | | fn req(&self) {}
= note: `prov` not implemented
error[E0046]: not all trait items implemented, missing: `req`
- --> $DIR/impl-with-default-fn-fail.rs:22:1
+ --> $DIR/impl-with-default-fn-fail.rs:21:1
|
LL | fn req(&self);
| -------------- `req` from trait
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Tr {
fn req(&self);
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait A {
error[E0277]: the trait bound `T: ~const A` is not satisfied
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
|
note: the trait `A` is implemented for `T`, but that implementation is not `const`
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^
error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
pub trait Tr {}
//
// check-pass
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait Super {}
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Convert<T> {
fn to(self) -> T;
#![feature(staged_api)]
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_t_try)]
#![feature(const_try)]
#![feature(try_trait_v2)]
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Bar {
fn bar() -> u8;
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Foo {
fn bar() where Self: ~const Foo;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait Bar {}
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:14:5
+ --> $DIR/trait-where-clause.rs:13:5
|
LL | T::b();
| ^^^^ the trait `~const Bar` is not implemented for `T`
|
note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
- --> $DIR/trait-where-clause.rs:14:5
+ --> $DIR/trait-where-clause.rs:13:5
|
LL | T::b();
| ^^^^
note: required by a bound in `Foo::b`
- --> $DIR/trait-where-clause.rs:8:24
+ --> $DIR/trait-where-clause.rs:7:24
|
LL | fn b() where Self: ~const Bar;
| ^^^^^^^^^^ required by this bound in `Foo::b`
| ++++++++++++
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:16:5
+ --> $DIR/trait-where-clause.rs:15:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `~const Bar` is not implemented for `T`
|
note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
- --> $DIR/trait-where-clause.rs:16:5
+ --> $DIR/trait-where-clause.rs:15:5
|
LL | T::c::<T>();
| ^^^^^^^^^
note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:13
+ --> $DIR/trait-where-clause.rs:8:13
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^ required by this bound in `Foo::c`
| ++++++++++++
error[E0277]: the trait bound `T: Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:28:5
+ --> $DIR/trait-where-clause.rs:27:5
|
LL | T::b();
| ^^^^ the trait `Bar` is not implemented for `T`
|
note: required by a bound in `Foo::b`
- --> $DIR/trait-where-clause.rs:8:24
+ --> $DIR/trait-where-clause.rs:7:24
|
LL | fn b() where Self: ~const Bar;
| ^^^^^^^^^^ required by this bound in `Foo::b`
| +++++
error[E0277]: the trait bound `T: Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:30:5
+ --> $DIR/trait-where-clause.rs:29:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:13
+ --> $DIR/trait-where-clause.rs:8:13
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^ required by this bound in `Foo::c`
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated() {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_text() {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
pub fn deprecated_future() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_unstable() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub fn deprecated_unstable_text() {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
impl MethodTester {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated(&self) {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_unstable(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
pub fn method_deprecated_unstable_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub trait Trait {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated(&self) {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_unstable(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
fn trait_deprecated_unstable_text(&self) {}
#[unstable(feature = "unstable_test_feature", issue = "none")]
#[unstable(feature = "unstable_test_feature", issue = "none")]
type TypeUnstable = u8;
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
type TypeDeprecated = u8;
}
pub trait UnstableTrait { fn dummy(&self) { } }
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub trait DeprecatedTrait {
#[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
}
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableStruct {
#[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
}
pub enum StableEnum {}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableUnitStruct;
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableUnitStruct;
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub enum Enum {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
- #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ #[deprecated(since = "1.0.0", note = "text")]
DeprecatedUnstableVariant,
#[unstable(feature = "unstable_test_feature", issue = "none")]
UnstableVariant,
}
#[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "unstable_test_feature", issue = "none")]
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
pub field2: B,
}
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub struct Struct4<A = usize> {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub field: A,
}
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E),
}
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub enum Enum4<T = usize> {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
None,
}
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub type Alias3<T = isize, #[unstable(feature = "unstable_default", issue = "none")] E = usize> =
Result<T, E>;
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub type Alias4<T = usize> = Option<T>;
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
#[stable(feature = "stable_test_feature", since = "1.0.0")]
pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option<T>;
#[unstable()] //~ ERROR: stability attributes may not be used
#[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
fn main() {}
LL | #[stable()]
| ^^^^^^^^^^^
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
#[unstable()] //~ ERROR: stability attributes may not be used
#[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
fn main() {}
LL | #[stable()]
| ^^^^^^^^^^^
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/stability-attribute-non-staged.rs:3:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
- --> $DIR/stability-attribute-non-staged.rs:3:1
- |
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
fn f4() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute
- //~^ ERROR missing 'since'
+ #[deprecated] //~ ERROR missing 'since'
fn f5() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute
- //~^ ERROR missing 'since'
+ #[deprecated = "a"] //~ ERROR missing 'since'
fn f6() { }
}
LL | #[stable = "a"]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
-error: malformed `rustc_deprecated` attribute input
- --> $DIR/stability-attribute-sanity-4.rs:21:5
- |
-LL | #[rustc_deprecated]
- | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
-error: malformed `rustc_deprecated` attribute input
- --> $DIR/stability-attribute-sanity-4.rs:26:5
- |
-LL | #[rustc_deprecated = "a"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
error[E0542]: missing 'since'
--> $DIR/stability-attribute-sanity-4.rs:21:5
|
-LL | #[rustc_deprecated]
- | ^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated]
+ | ^^^^^^^^^^^^^
error[E0542]: missing 'since'
- --> $DIR/stability-attribute-sanity-4.rs:26:5
+ --> $DIR/stability-attribute-sanity-4.rs:25:5
|
-LL | #[rustc_deprecated = "a"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated = "a"]
+ | ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0542`.
fn f1() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' [E0542]
+ #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542]
fn f2() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated(since = "a")] //~ ERROR missing 'reason' [E0543]
+ #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543]
fn f3() { }
}
fn multiple3() { }
#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
-#[rustc_deprecated(since = "b", reason = "text")]
-#[rustc_deprecated(since = "b", reason = "text")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "b", note = "text")]
+#[deprecated(since = "b", note = "text")] //~ ERROR multiple deprecated attributes
#[rustc_const_unstable(feature = "c", issue = "none")]
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
pub const fn multiple4() { }
#[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
//~^ ERROR feature `a` is declared stable since 1.0.0
-#[rustc_deprecated(since = "invalid", reason = "text")]
+#[deprecated(since = "invalid", note = "text")]
fn invalid_deprecation_version() {}
-#[rustc_deprecated(since = "a", reason = "text")]
+#[deprecated(since = "a", note = "text")]
fn deprecated_without_unstable_or_stable() { }
-//~^^ ERROR rustc_deprecated attribute must be paired with either stable or unstable attribute
+//~^^ ERROR deprecated attribute must be paired with either stable or unstable attribute
fn main() { }
error[E0542]: missing 'since'
--> $DIR/stability-attribute-sanity.rs:40:5
|
-LL | #[rustc_deprecated(reason = "a")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated(note = "a")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0543]: missing 'reason'
+error[E0543]: missing 'note'
--> $DIR/stability-attribute-sanity.rs:44:5
|
-LL | #[rustc_deprecated(since = "a")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated(since = "a")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0544]: multiple stability levels
--> $DIR/stability-attribute-sanity.rs:49:1
error[E0550]: multiple deprecated attributes
--> $DIR/stability-attribute-sanity.rs:62:1
|
-LL | #[rustc_deprecated(since = "b", reason = "text")]
- | ------------------------------------------------- first deprecation attribute
-LL | #[rustc_deprecated(since = "b", reason = "text")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+ | ----------------------------------------- first deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
error[E0544]: multiple stability levels
--> $DIR/stability-attribute-sanity.rs:64:1
LL | fn invalid_deprecation_version() {}
| ----------------------------------- the stability attribute annotates this item
-error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
+error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
--> $DIR/stability-attribute-sanity.rs:72:1
|
-LL | #[rustc_deprecated(since = "a", reason = "text")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated(since = "a", note = "text")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
--> $DIR/stability-attribute-sanity.rs:67:1
note: required by a bound in `core::str::<impl str>::get`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
-LL | pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
- | ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
+LL | pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> $DIR/str-idx.rs:5:29
note: required by a bound in `core::str::<impl str>::get_unchecked`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
-LL | pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
- | ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
+LL | pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
error[E0277]: the type `str` cannot be indexed by `char`
--> $DIR/str-idx.rs:6:17
note: required by a bound in `core::str::<impl str>::get_mut`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
-LL | pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
- | ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
+LL | pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> $DIR/str-mut-idx.rs:11:25
note: required by a bound in `core::str::<impl str>::get_unchecked_mut`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
-LL | pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
- | ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
+LL | pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+ | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
error[E0277]: the type `str` cannot be indexed by `char`
--> $DIR/str-mut-idx.rs:13:5
| - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
LL | for i in &a {
LL | for j in a {
- | ^
- | |
- | `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
- | help: consider borrowing to avoid moving into the for loop: `&a`
+ | ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
|
note: this function takes ownership of the receiver `self`, which moves `a`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop
+ |
+LL | for j in &a {
+ | +
error: aborting due to 2 previous errors
--> $DIR/for-i-in-vec.rs:11:18
|
LL | for _ in self.v {
- | ^^^^^^ move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
+ | ^^^^^^
+ | |
+ | `self.v` moved due to this implicit call to `.into_iter()`
+ | move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
|
-help: consider iterating over a slice of the `Vec<u32>`'s content
+note: this function takes ownership of the receiver `self`, which moves `self.v`
+ --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ |
+LL | fn into_iter(self) -> Self::IntoIter;
+ | ^^^^
+help: consider iterating over a slice of the `Vec<u32>`'s content to avoid moving into the `for` loop
|
LL | for _ in &self.v {
| +
--> $DIR/for-i-in-vec.rs:13:18
|
LL | for _ in self.h {
- | ^^^^^^ move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
+ | ^^^^^^
+ | |
+ | `self.h` moved due to this implicit call to `.into_iter()`
+ | move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
|
-help: consider iterating over a slice of the `HashMap<i32, i32>`'s content
+help: consider iterating over a slice of the `HashMap<i32, i32>`'s content to avoid moving into the `for` loop
|
LL | for _ in &self.h {
| +
--> $DIR/for-i-in-vec.rs:21:19
|
LL | for loader in *LOADERS {
- | ^^^^^^^^ move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+ | ^^^^^^^^
+ | |
+ | value moved due to this implicit call to `.into_iter()`
+ | move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+ |
+note: this function takes ownership of the receiver `self`, which moves value
+ --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
-help: consider iterating over a slice of the `Vec<&u8>`'s content
+LL | fn into_iter(self) -> Self::IntoIter;
+ | ^^^^
+help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid moving into the `for` loop
|
LL | for loader in &*LOADERS {
| +
LL | | var = Some(NotCopyable);
| | ---
| | |
+ | | variable moved due to use in closure
| | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
LL | | }
LL | | });
| |_____- captured by this `FnMut` closure
--- /dev/null
+struct Wrapper<T>(T);
+
+fn foo<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+ T
+ :
+ ?
+ Sized
+{
+ //
+}
+
+fn bar<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where T: ?Sized
+{
+ //
+}
+
+fn qux<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+ T: ?Sized
+{
+ //
+}
+
+
+fn main() {}
--- /dev/null
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:3:16
+ |
+LL | fn foo<T>(foo: Wrapper<T>)
+ | - ^^^^^^^^^^ doesn't have a size known at compile-time
+ | |
+ | this type parameter needs to be `std::marker::Sized`
+ |
+note: required by a bound in `Wrapper`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+ |
+LL - where
+LL - T
+LL - :
+LL - ?
+LL - Sized
+ |
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:14:16
+ |
+LL | fn bar<T>(foo: Wrapper<T>)
+ | - ^^^^^^^^^^ doesn't have a size known at compile-time
+ | |
+ | this type parameter needs to be `std::marker::Sized`
+ |
+note: required by a bound in `Wrapper`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+ |
+LL - where T: ?Sized
+ |
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:21:16
+ |
+LL | fn qux<T>(foo: Wrapper<T>)
+ | - ^^^^^^^^^^ doesn't have a size known at compile-time
+ | |
+ | this type parameter needs to be `std::marker::Sized`
+ |
+note: required by a bound in `Wrapper`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+ |
+LL | struct Wrapper<T>(T);
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+ |
+LL - where
+LL - T: ?Sized
+ |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+fn main() {
+ (|| {})(|| {
+ //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ let b = 1;
+ });
+}
--- /dev/null
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+ --> $DIR/wrong_argument_ice-4.rs:2:5
+ |
+LL | (|| {})(|| {
+ | _____^^^^^^^_-
+ | | |
+ | | expected 0 arguments
+LL | |
+LL | | let b = 1;
+LL | | });
+ | |_____- supplied 1 argument
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
fn main() {}
type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+//~^ ERROR the trait bound `A: Foo` is not satisfied
//~| ERROR `A` doesn't implement `Debug`
//~| ERROR `B` doesn't implement `Debug`
LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+error[E0277]: the trait bound `A: Foo` is not satisfied
--> $DIR/generic_duplicate_param_use9.rs:7:18
|
LL | type Two<A, B> = impl Debug;
- | ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+ | ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
|
- = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
help: consider restricting type parameter `A`
|
LL | type Two<A: Foo, B> = impl Debug;
LL | type Two<A, B> = impl Debug;
| ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+ = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
help: consider restricting type parameter `A`
|
LL | type Two<A: std::fmt::Debug, B> = impl Debug;
LL | type Two<A, B> = impl Debug;
| ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+ = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
help: consider restricting type parameter `B`
|
LL | type Two<A, B: std::fmt::Debug> = impl Debug;
-#![feature(const_impl_trait, const_fn_fn_ptr_basics, rustc_attrs)]
+#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
type Foo = impl Fn() -> usize;
-#![feature(const_impl_trait, generators, generator_trait, rustc_attrs)]
+#![feature(generators, generator_trait, rustc_attrs)]
#![feature(type_alias_impl_trait)]
use std::ops::Generator;
use std::future::Future;
type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-//~| ERROR: the trait bound `T: Trait` is not satisfied
+//~^ ERROR: the trait bound `T: Trait` is not satisfied
trait Trait {
type F: Future<Output = ()>;
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
- --> $DIR/issue-89686.rs:7:17
- |
-LL | type G<'a, T> = impl Future<Output = ()>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
-...
-LL | async move { self.f().await }
- | ------------------ the found `async` block
- |
- ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
- | ------------------------------- the found opaque type
- |
- = note: expected unit type `()`
- found associated type `<impl Future<Output = [async output]> as Future>::Output`
- = help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/issue-89686.rs:7:17
|
LL | type G<'a, T: Trait> = impl Future<Output = ()>;
| +++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
-#![feature(const_impl_trait)]
#![feature(type_alias_impl_trait)]
type Bar = impl Send;
error: `impl Send` cannot be used in patterns
- --> $DIR/structural-match-no-leak.rs:15:9
+ --> $DIR/structural-match-no-leak.rs:14:9
|
LL | LEAK_FREE => (),
| ^^^^^^^^^
-#![feature(const_impl_trait)]
#![feature(type_alias_impl_trait)]
type Foo = impl Send;
error: `impl Send` cannot be used in patterns
- --> $DIR/structural-match.rs:16:9
+ --> $DIR/structural-match.rs:15:9
|
LL | VALUE => (),
| ^^^^^
+// check-pass
+
#![feature(unboxed_closures)]
trait Lt<'a> {
fn main() {
let v: <() as Lt<'_>>::T = ();
let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
- //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
f(v);
}
+++ /dev/null
-error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
- --> $DIR/issue-53448.rs:12:54
- |
-LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
- | ^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
- = help: unsized fn params are gated as an unstable feature
-help: consider further restricting the associated type
- |
-LL | fn main() where <() as Lt<'_>>::T: Sized {
- | ++++++++++++++++++++++++++++++
-help: function arguments must have a statically known size, borrowed types always have a known size
- |
-LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
- | +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
A(foo::SecretlyEmpty),
B(foo::NotSoSecretlyEmpty),
C(NotSoSecretlyEmpty),
- D(u32),
+ D(u32, u32),
}
fn main() {
- let x: Foo = Foo::D(123);
- let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
+ let x: Foo = Foo::D(123, 456);
+ let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
}
error[E0005]: refutable pattern in local binding: `A(_)` not covered
--> $DIR/uninhabited-irrefutable.rs:27:9
|
-LL | / enum Foo {
-LL | | A(foo::SecretlyEmpty),
- | | - not covered
-LL | | B(foo::NotSoSecretlyEmpty),
-LL | | C(NotSoSecretlyEmpty),
-LL | | D(u32),
-LL | | }
- | |_- `Foo` defined here
-...
-LL | let Foo::D(_y) = x;
- | ^^^^^^^^^^ pattern `A(_)` not covered
+LL | let Foo::D(_y, _z) = x;
+ | ^^^^^^^^^^^^^^ pattern `A(_)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+ --> $DIR/uninhabited-irrefutable.rs:19:5
+ |
+LL | enum Foo {
+ | ---
+LL | A(foo::SecretlyEmpty),
+ | ^ not covered
= note: the matched value is of type `Foo`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Foo::D(_y) = x { /* */ }
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
+ | +++++++++++++++++ +++++++++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ |
+LL | let Foo::D(_y, _z) = x else { todo!() };
+ | ++++++++++++++++
error: aborting due to previous error
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, &Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Result<u32, &Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
+LL ~ Ok(n) => n,
+LL ~ Err(_) => todo!(),
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Result<u32, &Void>`
error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:15:19
|
-LL | enum Void {}
- | ------------ `Void` defined here
-...
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Void` defined here
+ --> $DIR/uninhabited-matches-feature-gated.rs:2:6
+ |
+LL | enum Void {}
+ | ^^^^
= note: the matched value is of type `&Void`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:18:19
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Void,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:21:19
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Void; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:24:19
LL | let _ = match x {
| ^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[Void]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[] => (),
+LL ~ &[_, ..] => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:32:19
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Result<u32, Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
+LL ~ Ok(x) => x,
+LL ~ Err(_) => todo!(),
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Result<u32, Void>`
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:37:9
LL | let Ok(x) = x;
| ^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
-LL | if let Ok(x) = x { /* */ }
+LL | let x = if let Ok(x) = x { x } else { todo!() };
+ | ++++++++++ ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
|
+LL | let Ok(x) = x else { todo!() };
+ | ++++++++++++++++
error: aborting due to 7 previous errors
--- /dev/null
+// check-pass
+// compile-flags: -Aunknown_lints -Atest_unstable_lint
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![allow(unknown_lints, test_unstable_lint)]
+
+fn main() {}
--- /dev/null
+// check-fail
+// compile-flags: -Dunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
--- /dev/null
+error: unknown lint: `test_unstable_lint`
+ |
+ = note: requested on the command line with `-D unknown-lints`
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// check-fail
+
+#![deny(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+
+fn main() {}
--- /dev/null
+error: unknown lint: `test_unstable_lint`
+ --> $DIR/deny-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-unstable-lint-inline.rs:3:9
+ |
+LL | #![deny(unknown_lints)]
+ | ^^^^^^^^^^^^^
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+ --> $DIR/deny-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+ --> $DIR/deny-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// check-pass
+// compile-flags: -Wunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
--- /dev/null
+warning: unknown lint: `test_unstable_lint`
+ |
+ = note: requested on the command line with `-W unknown-lints`
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
--- /dev/null
+// check-pass
+
+#![warn(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
--- /dev/null
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/warn-unknown-unstable-lint-inline.rs:3:9
+ |
+LL | #![warn(unknown_lints)]
+ | ^^^^^^^^^^^^^
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+ --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+ |
+LL | #![allow(test_unstable_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `test_unstable_lint` lint is unstable
+ = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
-Subproject commit 3d6970d50e30e797b8e26b2b9b1bdf92dc381f34
+Subproject commit 65c82664263feddc5fe2d424be0993c28d46377a
clippy_utils = { path = "clippy_utils" }
derive-new = "0.5"
if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["full"] }
bytecount = "0.6"
clap = "2.33"
indoc = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
opener = "0.5"
regex = "1.5"
shell-escape = "0.1"
cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
pulldown-cmark = { version = "0.9", default-features = false }
quine-mc_cluskey = "0.2"
regex-syntax = "0.6"
use clippy_utils::ty::has_drop;
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
use rustc_hir as hir;
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
FnKind::Closure => return,
}
+ // Const fns are not allowed as methods in a trait.
+ {
+ let parent = cx.tcx.hir().get_parent_item(hir_id);
+ if parent != CRATE_DEF_ID {
+ if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
+ if let hir::ItemKind::Trait(..) = &item.kind {
+ return;
+ }
+ }
+ }
+ }
+
let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) {
continue;
}
- let borrowers = self.possible_borrower.reachable_from(&row);
+ let borrowers = self.possible_borrower.reachable_from(row);
if !borrowers.is_empty() {
let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
- for &c in borrowers {
+ for c in borrowers {
if c != mir::Local::from_usize(0) {
bs.insert(c);
}
continue;
}
- let borrowers = self.possible_origin.reachable_from(&row);
+ let borrowers = self.possible_origin.reachable_from(row);
if !borrowers.is_empty() {
let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
- for &c in borrowers {
+ for c in borrowers {
if c != mir::Local::from_usize(0) {
bs.insert(c);
}
if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
then {
- layout.layout.size.bytes() == 0
+ layout.layout.size().bytes() == 0
} else {
false
}
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() {
ty::Ref(_, tam, _) => match tam.kind() {
ty::Str => String::from_utf8(
- data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end)
.to_owned(),
)
.ok()
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() {
ty::Array(sub_type, len) => match sub_type.kind() {
ty::Float(FloatTy::F32) => match miri_to_const(*len) {
- Some(Constant::Int(len)) => alloc
+ Some(Constant::Int(len)) => alloc.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
.chunks(4)
_ => None,
},
ty::Float(FloatTy::F64) => match miri_to_const(*len) {
- Some(Constant::Int(len)) => alloc
+ Some(Constant::Int(len)) => alloc.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
.chunks(8)
fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
tcx.crates(())
.iter()
- .find(|&&num| tcx.crate_name(num).as_str() == name)
+ .copied()
+ .find(|&num| tcx.crate_name(num).as_str() == name)
.map(CrateNum::as_def_id)
}
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Trait(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
- ty::PredicateKind::Trait(pred) => {
- if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
- continue;
- }
- match pred.self_ty().kind() {
- ty::Param(ref p) => {
- let generics = tcx.generics_of(current);
- let def = generics.type_param(p, tcx);
- let span = tcx.def_span(def.def_id);
- return Err((
- span,
- "trait bounds other than `Sized` \
- on const fn parameters are unstable"
- .into(),
- ));
- },
- // other kinds of bounds are either tautologies
- // or cause errors in other passes
- _ => continue,
- }
- },
}
}
match predicates.parent {
unsafe { transmute(&x) }
}
-// NOTE: This is currently not yet allowed to be const
-// Once implemented, Clippy should be able to suggest this as const, too.
fn generic_arr<T: Copy>(t: [T; 1]) -> T {
t[0]
}
| |_^
error: this could be a `const fn`
- --> $DIR/could_be_const.rs:67:9
+ --> $DIR/could_be_const.rs:52:1
+ |
+LL | / fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+LL | | t[0]
+LL | | }
+ | |_^
+
+error: this could be a `const fn`
+ --> $DIR/could_be_const.rs:65:9
|
LL | / pub fn b(self, a: &A) -> B {
LL | | B
| |_________^
error: this could be a `const fn`
- --> $DIR/could_be_const.rs:77:5
+ --> $DIR/could_be_const.rs:75:5
|
LL | / fn const_fn_stabilized_before_msrv(byte: u8) {
LL | | byte.is_ascii_digit();
LL | | }
| |_____^
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
/// If the given HTML file contents is an HTML redirect, this returns the
/// destination path given in the redirect.
fn maybe_redirect(source: &str) -> Option<String> {
- const REDIRECT: &str = "<p>Redirecting to <a href=";
+ const REDIRECT_RUSTDOC: (usize, &str) = (7, "<p>Redirecting to <a href=");
+ const REDIRECT_MDBOOK: (usize, &str) = (8 - 7, "<p>Redirecting to... <a href=");
let mut lines = source.lines();
- let redirect_line = lines.nth(7)?;
- redirect_line.find(REDIRECT).map(|i| {
- let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
- let pos_quote = rest.find('"').unwrap();
- rest[..pos_quote].to_owned()
- })
+ let mut find_redirect = |(line_rel, redirect_pattern): (usize, &str)| {
+ let redirect_line = lines.nth(line_rel)?;
+
+ redirect_line.find(redirect_pattern).map(|i| {
+ let rest = &redirect_line[(i + redirect_pattern.len() + 1)..];
+ let pos_quote = rest.find('"').unwrap();
+ rest[..pos_quote].to_owned()
+ })
+ };
+
+ find_redirect(REDIRECT_RUSTDOC).or_else(|| find_redirect(REDIRECT_MDBOOK))
}
fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
-Subproject commit 54b14b7f0110133477e7459a327a0a5cbd18fd41
+Subproject commit 722475ccc143d2dbf9fad5891207dcb5576e3d17
-Subproject commit 4e72700e38421a12993fe5fa5c33d712652bc6c8
+Subproject commit 5fae65dd28b450a437ebc800a410164c3af1d516
try {
// This is more convenient that setting fields one by one.
let args = [
- "--no-screenshot",
+ "--no-screenshot-comparison",
"--variable", "DOC_PATH", opts["doc_folder"],
];
if (opts["debug"]) {
generic-simd = ["bytecount/generic-simd"]
[dependencies]
-itertools = "0.9"
+itertools = "0.10.1"
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
.stderr(Stdio::null())
.output()
.unwrap_or_else(|e| {
- panic!("could not run git ls-files: {}", e);
+ panic!("could not run git ls-files: {e}");
});
let path_bytes = rel_path.as_os_str().as_bytes();
if output.status.success() && output.stdout.starts_with(path_bytes) {
}
Some(pkg_license) => {
if pkg_license.as_str() != *license {
- println!("dependency exception `{}` license has changed", name);
- println!(" previously `{}` now `{}`", license, pkg_license);
+ println!("dependency exception `{name}` license has changed");
+ println!(" previously `{license}` now `{pkg_license}`");
println!(" update EXCEPTIONS for the new license");
*bad = true;
}
if !unapproved.is_empty() {
tidy_error!(bad, "Dependencies not explicitly permitted:");
for dep in unapproved {
- println!("* {}", dep);
+ println!("* {dep}");
}
}
}
.nodes
.iter()
.find(|n| &n.id == pkg_id)
- .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+ .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
node.deps
.iter()
.map(|dep| {
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
let mut i = metadata.packages.iter().filter(|p| p.name == name);
let result =
- i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name));
- assert!(i.next().is_none(), "more than one package found for `{}`", name);
+ i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list"));
+ assert!(i.next().is_none(), "more than one package found for `{name}`");
result
}
.nodes
.iter()
.find(|n| &n.id == pkg_id)
- .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+ .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
for dep in &node.deps {
normal_deps_of_r(resolve, &dep.pkg, result);
}
for (err_code, error_status) in &error_codes {
if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
- errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+ errors.push(format!("Error code {err_code} needs to have at least one UI test!"));
} else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
errors.push(format!(
"Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
}
errors.sort();
for err in &errors {
- eprintln!("{}", err);
+ eprintln!("{err}");
}
println!("Found {} error(s) in error codes", errors.len());
if !errors.is_empty() {
.collect::<Vec<_>>();
for &(name, _) in gate_untested.iter() {
- println!("Expected a gate test for the feature '{}'.", name);
+ println!("Expected a gate test for the feature '{name}'.");
println!(
"Hint: create a failing test file named 'feature-gate-{}.rs'\
\n in the 'ui' test suite, with its failures due to\
lines.sort();
for line in lines {
- println!("* {}", line);
+ println!("* {line}");
}
} else {
println!("* {} features", features.len());
"issue" => &*ISSUE,
"feature" => &*FEATURE,
"since" => &*SINCE,
- _ => unimplemented!("{} not handled", attr),
+ _ => unimplemented!("{attr} not handled"),
};
r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str())
let prefix = "feature_gate_";
if filen_underscore.starts_with(prefix) {
for (n, f) in features.iter_mut() {
- // Equivalent to filen_underscore == format!("feature_gate_{}", n)
+ // Equivalent to filen_underscore == format!("feature_gate_{n}")
if &filen_underscore[prefix.len()..] == n {
f.has_gate_test = true;
return true;
let std_name = "std/src/primitive_docs.rs";
let core_name = "core/src/primitive_docs.rs";
let std_contents = std::fs::read_to_string(library_path.join(std_name))
- .unwrap_or_else(|e| panic!("failed to read library/{}: {}", std_name, e));
+ .unwrap_or_else(|e| panic!("failed to read library/{std_name}: {e}"));
let core_contents = std::fs::read_to_string(library_path.join(core_name))
- .unwrap_or_else(|e| panic!("failed to read library/{}: {}", core_name, e));
+ .unwrap_or_else(|e| panic!("failed to read library/{core_name}: {e}"));
if std_contents != core_contents {
- tidy_error!(bad, "library/{} and library/{} have different contents", core_name, std_name);
+ tidy_error!(bad, "library/{core_name} and library/{std_name} have different contents");
}
}
return Directive::Deny;
}
// Update `can_contain` when changing this
- if contents.contains(&format!("// ignore-tidy-{}", check))
- || contents.contains(&format!("# ignore-tidy-{}", check))
- || contents.contains(&format!("/* ignore-tidy-{} */", check))
+ if contents.contains(&format!("// ignore-tidy-{check}"))
+ || contents.contains(&format!("# ignore-tidy-{check}"))
+ || contents.contains(&format!("/* ignore-tidy-{check} */"))
{
Directive::Ignore(false)
} else {
suppressible_tidy_err!(
err,
skip_line_length,
- &format!("line longer than {} chars", max_columns)
+ &format!("line longer than {max_columns} chars")
);
}
if !is_style_file && line.contains('\t') {
n => suppressible_tidy_err!(
err,
skip_trailing_newlines,
- &format!("too many trailing newlines ({})", n)
+ &format!("too many trailing newlines ({n})")
),
};
if lines > LINES {
let lncfg = &ln[open_brace + 1..close_brace];
it(Some(lncfg), ln[(close_brace + 1)..].trim_start());
} else {
- panic!("malformed condition directive: expected `//[foo]`, found `{}`", ln)
+ panic!("malformed condition directive: expected `//[foo]`, found `{ln}`")
}
} else if ln.starts_with(COMMENT) {
it(None, ln[COMMENT.len()..].trim_start());
let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
info.target_arch.replace(arch);
} else {
- eprintln!("{}: seems to have a malformed --target value", file);
+ eprintln!("{file}: seems to have a malformed --target value");
*bad = true;
}
}
for (name, contents) in modules {
table_file.push_str("#[rustfmt::skip]\n");
- table_file.push_str(&format!("pub mod {} {{\n", name));
+ table_file.push_str(&format!("pub mod {name} {{\n"));
for line in contents.lines() {
if !line.trim().is_empty() {
table_file.push_str(" ");
std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap();
- println!("Total table sizes: {} bytes", total_bytes);
+ println!("Total table sizes: {total_bytes} bytes");
}
fn version() -> String {
readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
let [major, minor, micro] = [version[0], version[1], version[2]];
- out.push_str(&format!("({}, {}, {});\n", major, minor, micro));
+ out.push_str(&format!("({major}, {minor}, {micro});\n"));
out
}
} else {
out.push_str(line.trim_end());
out.push('\n');
- line = format!(" {}", piece);
+ line = format!(" {piece}");
}
}
out.push_str(line.trim_end());
s.push_str("#![allow(incomplete_features, unused)]\n");
s.push_str("#![feature(const_generics)]\n\n");
s.push_str("\n#[allow(unused)]\nuse std::hint;\n");
- s.push_str(&format!("#[path = \"{}\"]\n", data_path));
+ s.push_str(&format!("#[path = \"{data_path}\"]\n"));
s.push_str("mod unicode_data;\n\n");
s.push_str("\nfn main() {\n");
let directory = Path::new(UNICODE_DIRECTORY);
if directory.exists() {
eprintln!(
- "Not refetching unicode data, already exists, please delete {:?} to regenerate",
- directory
+ "Not refetching unicode data, already exists, please delete {directory:?} to regenerate",
);
return;
}
if let Err(e) = std::fs::create_dir_all(directory) {
- panic!("Failed to create {:?}: {}", UNICODE_DIRECTORY, e);
+ panic!("Failed to create {UNICODE_DIRECTORY:?}: {e}");
}
let output = Command::new("curl").arg(URL_PREFIX.to_owned() + README).output().unwrap();
if !output.status.success() {
t!(fs::create_dir_all(&out));
for feature_name in &unstable_features - &unstable_section_file_names {
let feature_name_underscore = feature_name.replace('-', "_");
- let file_name = format!("{}.md", feature_name);
+ let file_name = format!("{feature_name}.md");
let out_file_path = out.join(&file_name);
let feature = &features[&feature_name_underscore];
let current = match env::current_dir() {
Ok(dir) => dir,
Err(err) => {
- eprintln!("Failed to get current directory: {}", err);
+ eprintln!("Failed to get current directory: {err}");
process::exit(1);
}
};
"""
label = "O-riscv"
+[ping.fuchsia]
+message = """\
+Hey friends of Fuchsia! This issue could use some guidance on how this should be
+resolved/implemented on Fuchsia. Could one of you weigh in?
+"""
+label = "O-fuchsia"
+
[prioritize]
label = "I-prioritize"