[[package]]
name = "compiler_builtins"
-version = "0.1.52"
+version = "0.1.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6591c2442ee984e2b264638a8b5e7ae44fd47b32d28e3a08e2e9c3cdb0c2fb0"
+checksum = "c9ac60765140c97aaf531dae151a287646b0805ec725805da9e2a3ee31cd501c"
dependencies = [
"cc",
"rustc-std-workspace-core",
[[package]]
name = "libc"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
+checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
dependencies = [
"rustc-std-workspace-core",
]
version = "0.1.0"
dependencies = [
"expect-test",
+ "unic-emoji-char",
"unicode-xid",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+[[package]]
+name = "unic-char-property"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
+dependencies = [
+ "unic-char-range",
+]
+
+[[package]]
+name = "unic-char-range"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
+
+[[package]]
+name = "unic-common"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
+
+[[package]]
+name = "unic-emoji-char"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
+dependencies = [
+ "unic-char-property",
+ "unic-char-range",
+ "unic-ucd-version",
+]
+
+[[package]]
+name = "unic-ucd-version"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
+dependencies = [
+ "unic-common",
+]
+
[[package]]
name = "unicase"
version = "2.6.0"
+Version 1.57.0 (2021-12-02)
+==========================
+
+Language
+--------
+
+- [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
+- [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
+- [Allow panicking in constant evaluation.][89508]
+
+Compiler
+--------
+
+- [Create more accurate debuginfo for vtables.][89597]
+- [Add `armv6k-nintendo-3ds` at Tier 3\*.][88529]
+- [Add `armv7-unknown-linux-uclibceabihf` at Tier 3\*.][88952]
+- [Add `m68k-unknown-linux-gnu` at Tier 3\*.][88321]
+- [Add SOLID targets at Tier 3\*:][86191] `aarch64-kmc-solid_asp3`, `armv7a-kmc-solid_asp3-eabi`, `armv7a-kmc-solid_asp3-eabihf`
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Avoid allocations and copying in `Vec::leak`][89337]
+- [Add `#[repr(i8)]` to `Ordering`][89507]
+- [Optimize `File::read_to_end` and `read_to_string`][89582]
+- [Update to Unicode 14.0][89614]
+- [Many more functions are marked `#[must_use]`][89692], producing a warning
+ when ignoring their return value. This helps catch mistakes such as expecting
+ a function to mutate a value in place rather than return a new value.
+
+Stabilised APIs
+---------------
+
+- [`[T; N]::as_mut_slice`][`array::as_mut_slice`]
+- [`[T; N]::as_slice`][`array::as_slice`]
+- [`collections::TryReserveError`]
+- [`HashMap::try_reserve`]
+- [`HashSet::try_reserve`]
+- [`String::try_reserve`]
+- [`String::try_reserve_exact`]
+- [`Vec::try_reserve`]
+- [`Vec::try_reserve_exact`]
+- [`VecDeque::try_reserve`]
+- [`VecDeque::try_reserve_exact`]
+- [`Iterator::map_while`]
+- [`iter::MapWhile`]
+- [`proc_macro::is_available`]
+- [`Command::get_program`]
+- [`Command::get_args`]
+- [`Command::get_envs`]
+- [`Command::get_current_dir`]
+- [`CommandArgs`]
+- [`CommandEnvs`]
+
+These APIs are now usable in const contexts:
+
+- [`hint::unreachable_unchecked`]
+
+Cargo
+-----
+
+- [Stabilize custom profiles][cargo/9943]
+
+Compatibility notes
+-------------------
+
+Internal changes
+----------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Added an experimental backend for codegen with `libgccjit`.][87260]
+
+[86191]: https://github.com/rust-lang/rust/pull/86191/
+[87220]: https://github.com/rust-lang/rust/pull/87220/
+[87260]: https://github.com/rust-lang/rust/pull/87260/
+[88243]: https://github.com/rust-lang/rust/pull/88243/
+[88321]: https://github.com/rust-lang/rust/pull/88321/
+[88529]: https://github.com/rust-lang/rust/pull/88529/
+[88690]: https://github.com/rust-lang/rust/pull/88690/
+[88952]: https://github.com/rust-lang/rust/pull/88952/
+[89337]: https://github.com/rust-lang/rust/pull/89337/
+[89507]: https://github.com/rust-lang/rust/pull/89507/
+[89508]: https://github.com/rust-lang/rust/pull/89508/
+[89582]: https://github.com/rust-lang/rust/pull/89582/
+[89597]: https://github.com/rust-lang/rust/pull/89597/
+[89614]: https://github.com/rust-lang/rust/pull/89614/
+[89692]: https://github.com/rust-lang/rust/issues/89692/
+[cargo/9943]: https://github.com/rust-lang/cargo/pull/9943/
+[`array::as_mut_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_mut_slice
+[`array::as_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_slice
+[`collections::TryReserveError`]: https://doc.rust-lang.org/std/collections/struct.TryReserveError.html
+[`HashMap::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.try_reserve
+[`HashSet::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_set/struct.HashSet.html#method.try_reserve
+[`String::try_reserve`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve
+[`String::try_reserve_exact`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve_exact
+[`Vec::try_reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve
+[`Vec::try_reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact
+[`VecDeque::try_reserve`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve
+[`VecDeque::try_reserve_exact`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve_exact
+[`Iterator::map_while`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map_while
+[`iter::MapWhile`]: https://doc.rust-lang.org/std/iter/struct.MapWhile.html
+[`proc_macro::is_available`]: https://doc.rust-lang.org/proc_macro/fn.is_available.html
+[`Command::get_program`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_program
+[`Command::get_args`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_args
+[`Command::get_envs`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_envs
+[`Command::get_current_dir`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_current_dir
+[`CommandArgs`]: https://doc.rust-lang.org/std/process/struct.CommandArgs.html
+[`CommandEnvs`]: https://doc.rust-lang.org/std/process/struct.CommandEnvs.html
+
Version 1.56.1 (2021-11-01)
===========================
pub kind: GenericParamKind,
}
+impl GenericParam {
+ pub fn span(&self) -> Span {
+ match &self.kind {
+ GenericParamKind::Lifetime | GenericParamKind::Type { default: None } => {
+ self.ident.span
+ }
+ GenericParamKind::Type { default: Some(ty) } => self.ident.span.to(ty.span),
+ GenericParamKind::Const { kw_span, default: Some(default), .. } => {
+ kw_span.to(default.value.span)
+ }
+ GenericParamKind::Const { kw_span, default: None, ty } => kw_span.to(ty.span),
+ }
+ }
+}
+
/// Represents lifetime, type and const parameters attached to a declaration of
/// a function, enum, trait, etc.
#[derive(Clone, Encodable, Decodable, Debug)]
pub attrs: Vec<Attribute>,
pub items: Vec<P<Item>>,
pub span: Span,
+ // Placeholder ID if the crate node is a macro placeholder.
+ pub is_placeholder: Option<NodeId>,
}
/// Possible values inside of compile-time attribute lists.
use super::ptr::P;
use super::token::Nonterminal;
use super::tokenstream::LazyTokenStream;
-use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
+use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use super::{AttrVec, Attribute, Stmt, StmtKind};
// These ast nodes only support inert attributes, so they don't
// store tokens (since nothing can observe them)
derive_has_attrs_no_tokens! {
- FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
+ FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate
}
// These AST nodes don't support attributes, but can
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
/// method. Abort the program if the closure panics.
+///
+/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
+/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
+/// possibly meaningless value and rethrow the panic.
//
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_clobber<T, F>(t: &mut T, f: F)
visit_unsafety(unsafety, vis);
}
-// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
-// or make crate visiting first class if necessary.
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
- visit_clobber(krate, |Crate { attrs, items, span }| {
- let item_vis =
- Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
- let item = P(Item {
- ident: Ident::empty(),
- attrs,
- id: DUMMY_NODE_ID,
- vis: item_vis,
- span,
- kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
- tokens: None,
- });
- let items = vis.flat_map_item(item);
-
- let len = items.len();
- if len == 0 {
- Crate { attrs: vec![], items: vec![], span }
- } else if len == 1 {
- let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
- match kind {
- ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span },
- _ => panic!("visitor converted a module to not a module"),
- }
- } else {
- panic!("a crate cannot expand to more than one item");
- }
- });
+ let Crate { attrs, items, span, is_placeholder: _ } = krate;
+ visit_attrs(attrs, vis);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ vis.visit_span(span);
}
// Mutates one item into possibly many items.
fn visit_pat_field(&mut self, fp: &'ast PatField) {
walk_pat_field(self, fp)
}
+ fn visit_crate(&mut self, krate: &'ast Crate) {
+ walk_crate(self, krate)
+ }
}
#[macro_export]
/// Desugar `<expr>.await` into:
/// ```rust
- /// match <expr> {
+ /// match ::std::future::IntoFuture::into_future(<expr>) {
/// mut pinned => loop {
/// match unsafe { ::std::future::Future::poll(
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
await_span,
self.allow_gen_future.clone(),
);
- let expr = self.lower_expr(expr);
+ let expr = self.lower_expr_mut(expr);
let pinned_ident = Ident::with_dummy_span(sym::pinned);
let (pinned_pat, pinned_pat_hid) =
// mut pinned => loop { ... }
let pinned_arm = self.arm(pinned_pat, loop_expr);
- // match <expr> {
+ // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
+ let into_future_span = self.mark_span_with_reason(
+ DesugaringKind::Await,
+ await_span,
+ self.allow_into_future.clone(),
+ );
+ let into_future_expr = self.expr_call_lang_item_fn(
+ into_future_span,
+ hir::LangItem::IntoFutureIntoFuture,
+ arena_vec![self; expr],
+ );
+
+ // match <into_future_expr> {
// mut pinned => loop { .. }
// }
- hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar)
+ hir::ExprKind::Match(
+ into_future_expr,
+ arena_vec![self; pinned_arm],
+ hir::MatchSource::AwaitDesugar,
+ )
}
fn lower_expr_closure(
);
}
if !self.sess.features_untracked().destructuring_assignment {
- feature_err(
+ let mut err = feature_err(
&self.sess.parse_sess,
sym::destructuring_assignment,
eq_sign_span,
"destructuring assignments are unstable",
- )
- .span_label(lhs.span, "cannot assign to this expression")
- .emit();
+ );
+ err.span_label(lhs.span, "cannot assign to this expression");
+ if self.is_in_loop_condition {
+ err.span_suggestion_verbose(
+ lhs.span.shrink_to_lo(),
+ "you might have meant to use pattern destructuring",
+ "let ".to_string(),
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ err.emit();
}
let mut assignments = vec![];
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
+ fn visit_attribute(&mut self, _: &'a Attribute) {
+ // We do not want to lower expressions that appear in attributes,
+ // as they are not accessible to the rest of the HIR.
+ }
+
fn visit_item(&mut self, item: &'a Item) {
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
+ allow_into_future: Option<Lrc<[Symbol]>>,
}
pub trait ResolverAstLowering {
in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
+ allow_into_future: Some([sym::into_future][..].into()),
}
.lower_crate(krate)
}
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
- name: hir::LifetimeName::Implicit,
+ name: hir::LifetimeName::Implicit(false),
})));
let generic_args = self.arena.alloc_from_iter(generic_args);
});
let param_name = match lt.name {
hir::LifetimeName::Param(param_name) => param_name,
- hir::LifetimeName::Implicit
+ hir::LifetimeName::Implicit(_)
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
- AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
+ AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
}
}
&'s mut self,
span: Span,
count: usize,
+ param_mode: ParamMode,
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
- (0..count).map(move |_| self.elided_path_lifetime(span))
+ (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
}
- fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
+ fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
// We should have emitted E0726 when processing this path above
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.new_implicit_lifetime(span)
+ self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
}
}
}
r
}
- fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
+ fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
- name: hir::LifetimeName::Implicit,
+ name: hir::LifetimeName::Implicit(missing),
}
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
let name = match lifetime.name {
- hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+ hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `type Foo<'_> = impl SomeTrait<'_>;`.
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
-use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
-use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::symbol::Ident;
use rustc_span::{BytePos, Span, DUMMY_SP};
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
// Do not suggest going from `Trait()` to `Trait<>`
if !data.inputs.is_empty() {
- if let Some(split) = snippet.find('(') {
- let trait_name = &snippet[0..split];
- let args = &snippet[split + 1..snippet.len() - 1];
- err.span_suggestion(
- data.span,
- "use angle brackets instead",
- format!("{}<{}>", trait_name, args),
- Applicability::MaybeIncorrect,
- );
+ // Suggest replacing `(` and `)` with `<` and `>`
+ // The snippet may be missing the closing `)`, skip that case
+ if snippet.ends_with(')') {
+ if let Some(split) = snippet.find('(') {
+ let trait_name = &snippet[0..split];
+ let args = &snippet[split + 1..snippet.len() - 1];
+ err.span_suggestion(
+ data.span,
+ "use angle brackets instead",
+ format!("{}<{}>", trait_name, args),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
};
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
- if !generic_args.parenthesized && !has_lifetimes {
+ if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 {
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let elided_lifetime_span = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
- segment.ident.span
+ path_span
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
};
generic_args.args = self
- .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
+ .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
.map(GenericArg::Lifetime)
.chain(generic_args.args.into_iter())
.collect();
- if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
+ // In create-parameter mode we error here because we don't want to support
+ // deprecated impl elision in new features like impl elision and `async fn`,
+ // both of which work using the `CreateParameter` mode:
+ //
+ // impl Foo for std::cell::Ref<u32> // note lack of '_
+ // async fn foo(_: std::cell::Ref<u32>) { ... }
+ if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
+ (param_mode, self.anonymous_lifetime_mode)
+ {
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
let no_bindings = generic_args.bindings.is_empty();
- let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
+ let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
// If there are no generic args, our suggestion can include the angle brackets.
- (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
+ (true, format!("<{}>", anon_lt_suggestion))
} else {
// Otherwise we'll insert a `'_, ` right after the opening bracket.
- let span = generic_args
- .span
- .with_lo(generic_args.span.lo() + BytePos(1))
- .shrink_to_lo();
- (false, span, format!("{}, ", anon_lt_suggestion))
+ (false, format!("{}, ", anon_lt_suggestion))
};
- match self.anonymous_lifetime_mode {
- // In create-parameter mode we error here because we don't want to support
- // deprecated impl elision in new features like impl elision and `async fn`,
- // both of which work using the `CreateParameter` mode:
- //
- // impl Foo for std::cell::Ref<u32> // note lack of '_
- // async fn foo(_: std::cell::Ref<u32>) { ... }
- AnonymousLifetimeMode::CreateParameter => {
- let mut err = struct_span_err!(
- self.sess,
- path_span,
- E0726,
- "implicit elided lifetime not allowed here"
- );
- rustc_errors::add_elided_lifetime_in_path_suggestion(
- &self.sess.source_map(),
- &mut err,
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- );
- err.note("assuming a `'static` lifetime...");
- err.emit();
- }
- AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- ELIDED_LIFETIMES_IN_PATHS,
- CRATE_NODE_ID,
- path_span,
- "hidden lifetime parameters in types are deprecated",
- BuiltinLintDiagnostics::ElidedLifetimesInPaths(
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- ),
- );
- }
- }
+ let insertion_sp = elided_lifetime_span.shrink_to_hi();
+ let mut err = struct_span_err!(
+ self.sess,
+ path_span,
+ E0726,
+ "implicit elided lifetime not allowed here"
+ );
+ rustc_errors::add_elided_lifetime_in_path_suggestion(
+ &self.sess.source_map(),
+ &mut err,
+ expected_lifetimes,
+ path_span,
+ incl_angl_brckt,
+ insertion_sp,
+ suggestion,
+ );
+ err.note("assuming a `'static` lifetime...");
+ err.emit();
}
}
use rustc_span::Span;
use rustc_target::spec::abi;
use std::mem;
-use std::ops::DerefMut;
+use std::ops::{Deref, DerefMut};
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
}
}
}
+ // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
+ if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
+ if let [potential_param, potential_assoc] = &full_path.segments[..] {
+ for param in &generics.params {
+ if param.ident == potential_param.ident {
+ for bound in ¶m.bounds {
+ if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
+ {
+ if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
+ let assoc = pprust::path_to_string(&ast::Path::from_ident(
+ potential_assoc.ident,
+ ));
+ let ty = pprust::ty_to_string(&predicate.rhs_ty);
+ let (args, span) = match &trait_segment.args {
+ Some(args) => match args.deref() {
+ ast::GenericArgs::AngleBracketed(args) => {
+ let Some(arg) = args.args.last() else {
+ continue;
+ };
+ (
+ format!(", {} = {}", assoc, ty),
+ arg.span().shrink_to_hi(),
+ )
+ }
+ _ => continue,
+ },
+ None => (
+ format!("<{} = {}>", assoc, ty),
+ trait_segment.span().shrink_to_hi(),
+ ),
+ };
+ err.multipart_suggestion(
+ &format!(
+ "if `{}::{}` is an associated type you're trying to set, \
+ use the associated type binding syntax",
+ trait_segment.ident, potential_assoc.ident,
+ ),
+ vec![(span, args), (predicate.span, String::new())],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
err.note(
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
);
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![recursion_limit = "256"]
pub mod ast_validation;
pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
State::new().to_string(f)
}
+
+pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
+ State::new().to_string(|s| {
+ s.print_inner_attributes(&krate.attrs);
+ for item in &krate.items {
+ s.print_item(item);
+ }
+ })
+}
[NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
(sym, span)
}
- [NestedMetaItem::Literal(Lit { span, .. })
- | NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
+ [
+ NestedMetaItem::Literal(Lit { span, .. })
+ | NestedMetaItem::MetaItem(MetaItem { span, .. }),
+ ] => {
sess.span_diagnostic
.struct_span_err(*span, "expected a version literal")
.emit();
Some(ref name),
BorrowExplanation::MustBeValidFor {
category:
- category
- @
- (ConstraintCategory::Return(_)
+ category @ (ConstraintCategory::Return(_)
| ConstraintCategory::CallArgument
| ConstraintCategory::OpaqueType),
from_closure: false,
BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
}
}
BorrowedContentSource::DerefMutableRef => {
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
}
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("a dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
}
}
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
- tcx.is_diagnostic_item(sym::Option, def_id)
- || tcx.is_diagnostic_item(sym::Result, def_id)
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
});
PlaceRef {
local: _,
projection:
- [.., ProjectionElem::Index(_)
- | ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::Downcast(..)],
+ [
+ ..,
+ ProjectionElem::Index(_)
+ | ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::Downcast(..),
+ ],
} => bug!("Unexpected immutable place."),
}
PlaceRef {
local,
projection:
- [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
+ [
+ proj_base @ ..,
+ ProjectionElem::Deref,
+ ProjectionElem::Field(field, _),
+ ProjectionElem::Deref,
+ ],
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
// check if the RHS is from desugaring
let opt_assignment_rhs_span =
self.body.find_assignments(local).first().map(|&location| {
- let stmt = &self.body[location.block].statements
- [location.statement_index];
- match stmt.kind {
- mir::StatementKind::Assign(box (
- _,
- mir::Rvalue::Use(mir::Operand::Copy(place)),
- )) => {
- self.body.local_decls[place.local].source_info.span
- }
- _ => self.body.source_info(location).span,
+ if let Some(mir::Statement {
+ source_info: _,
+ kind:
+ mir::StatementKind::Assign(box (
+ _,
+ mir::Rvalue::Use(mir::Operand::Copy(place)),
+ )),
+ }) = self.body[location.block]
+ .statements
+ .get(location.statement_index)
+ {
+ self.body.local_decls[place.local].source_info.span
+ } else {
+ self.body.source_info(location).span
}
});
match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
kind:
Call(
_,
- [Expr {
- kind: MethodCall(path_segment, ..),
- hir_id,
- ..
- }, ..],
+ [
+ Expr {
+ kind: MethodCall(path_segment, ..),
+ hir_id,
+ ..
+ },
+ ..,
+ ],
),
..
},
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+ hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds:
- [hir::GenericBound::LangItemTrait(
- hir::LangItem::Future,
- _,
- _,
- hir::GenericArgs {
- bindings:
- [hir::TypeBinding {
- ident: Ident { name: sym::Output, .. },
- kind: hir::TypeBindingKind::Equality { ty },
- ..
- }],
- ..
- },
- )],
+ [
+ hir::GenericBound::LangItemTrait(
+ hir::LangItem::Future,
+ _,
+ _,
+ hir::GenericArgs {
+ bindings:
+ [
+ hir::TypeBinding {
+ ident: Ident { name: sym::Output, .. },
+ kind: hir::TypeBindingKind::Equality { ty },
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ ],
..
}) = opaque_ty.kind
{
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(let_else)]
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::{Body, Location, PlaceElem, Promoted};
+use rustc_middle::mir::{Body, Location, Promoted};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
debug!(?ty);
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- if let PlaceElem::Field(field, ty) = elem {
- let new_ty = self.renumber_regions(ty);
-
- if new_ty != ty {
- return Some(PlaceElem::Field(field, new_ty));
- }
- }
-
- None
- }
-
#[instrument(skip(self), level = "debug")]
fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
*substs = self.renumber_regions(*substs);
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::DUMMY_SP;
self.add_outlives(r1_vid, r2_vid);
}
- GenericArgKind::Type(t1) => {
+ GenericArgKind::Type(mut t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+ // Placeholder regions need to be converted now because it may
+ // create new region variables, which can't be done later when
+ // verifying these bounds.
+ if t1.has_placeholders() {
+ t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r {
+ ty::RegionKind::RePlaceholder(placeholder) => {
+ self.constraints.placeholder_region(self.infcx, placeholder)
+ }
+ _ => r,
+ });
+ }
+
TypeOutlives::new(
&mut *self,
tcx,
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty
// See issue #87748
- let constraints_implied_1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied_2 =
- if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
+ let constraints_implied = self.add_implied_bounds(norm_ty);
normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
+ constraints1.into_iter().chain(constraints_implied)
})
.collect();
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
use rustc_feature::Features;
-use rustc_parse::parser::ForceCollect;
+use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::utils::FlattenNonterminals;
use rustc_session::Session;
use rustc_span::symbol::sym;
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
+ Annotatable::Crate(mut krate) => {
+ vis.visit_crate(&mut krate);
+ Some(Annotatable::Crate(krate))
+ }
}
}
Annotatable::Param(param) => finder.visit_param(¶m),
Annotatable::FieldDef(field) => finder.visit_field_def(&field),
Annotatable::Variant(variant) => finder.visit_variant(&variant),
+ Annotatable::Crate(krate) => finder.visit_crate(krate),
};
finder.has_cfg_or_cfg_attr
}
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
- // FIXME - get rid of this clone
- let nt = annotatable.clone().into_nonterminal();
+ let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
+ Annotatable::Item(_) => {
+ |parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
+ }
+ Annotatable::TraitItem(_) => |parser| {
+ Annotatable::TraitItem(
+ parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ImplItem(_) => |parser| {
+ Annotatable::ImplItem(
+ parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ForeignItem(_) => |parser| {
+ Annotatable::ForeignItem(
+ parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::Stmt(_) => |parser| {
+ Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
+ },
+ Annotatable::Expr(_) => {
+ |parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let nt = annotatable.into_nonterminal();
let mut orig_tokens = rustc_parse::nt_to_tokenstream(
&nt,
let mut parser =
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
parser.capture_cfg = true;
- annotatable = match annotatable {
- Annotatable::Item(_) => {
- Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
- }
- Annotatable::TraitItem(_) => Annotatable::TraitItem(
- parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ImplItem(_) => Annotatable::ImplItem(
- parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
- parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::Stmt(_) => {
- Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
- }
- Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
- _ => unreachable!(),
- };
+ annotatable = parse_annotatable_with(&mut parser);
// Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
// our attribute target will correctly the tokens as well.
/// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
/// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
/// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
- /// * `count_args`: `vec![Exact(0), Exact(5), Exact(3)]`
- count_args: Vec<Position>,
+ /// * `count_args`: `vec![0, 5, 3]`
+ count_args: Vec<usize>,
/// Relative slot numbers for count arguments.
count_positions: FxHashMap<usize, usize>,
/// Number of count slots assigned.
if let Entry::Vacant(e) = self.count_positions.entry(arg) {
let i = self.count_positions_count;
e.insert(i);
- self.count_args.push(Exact(arg));
+ self.count_args.push(arg);
self.count_positions_count += 1;
}
}
for arg_ty in self.arg_unique_types[i].iter() {
args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
- heads.push(self.ecx.expr_addr_of(e.span, e));
+ // use the arg span for `&arg` so that borrowck errors
+ // point to the specific expression passed to the macro
+ // (the span is otherwise unavailable in MIR)
+ heads.push(self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e));
}
- for pos in self.count_args {
- let index = match pos {
- Exact(i) => i,
- _ => panic!("should never happen"),
- };
+ for index in self.count_args {
let span = spans_pos[index];
args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
tests: Vec<Test>,
}
+impl TestHarnessGenerator<'_> {
+ fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
+ let mut tests = mem::replace(&mut self.tests, prev_tests);
+
+ if !tests.is_empty() {
+ // Create an identifier that will hygienically resolve the test
+ // case name, even in another module.
+ let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
+ span,
+ AstPass::TestHarness,
+ &[],
+ Some(node_id),
+ );
+ for test in &mut tests {
+ // See the comment on `mk_main` for why we're using
+ // `apply_mark` directly.
+ test.ident.span =
+ test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
+ }
+ self.cx.test_cases.extend(tests);
+ }
+ }
+}
+
impl<'a> MutVisitor for TestHarnessGenerator<'a> {
fn visit_crate(&mut self, c: &mut ast::Crate) {
+ let prev_tests = mem::take(&mut self.tests);
noop_visit_crate(c, self);
+ self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
// Create a main function to run our tests
c.items.push(mk_main(&mut self.cx));
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
- if let ast::ItemKind::Mod(..) = item.kind {
- let tests = mem::take(&mut self.tests);
+ if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
+ let prev_tests = mem::take(&mut self.tests);
noop_visit_item_kind(&mut item.kind, self);
- let mut tests = mem::replace(&mut self.tests, tests);
-
- if !tests.is_empty() {
- let parent =
- if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
- // Create an identifier that will hygienically resolve the test
- // case name, even in another module.
- let inner_span = match item.kind {
- ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
- _ => unreachable!(),
- };
- let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
- inner_span,
- AstPass::TestHarness,
- &[],
- Some(parent),
- );
- for test in &mut tests {
- // See the comment on `mk_main` for why we're using
- // `apply_mark` directly.
- test.ident.span =
- test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
- }
- self.cx.test_cases.extend(tests);
- }
+ self.add_test_cases(item.id, span, prev_tests);
}
smallvec![P(item)]
}
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
- if depth == 1 {
+ if depth == 0 {
// This is a top-level function so can be 'main'
EntryPointType::MainNamed
} else {
.prefix
.iter()
.flatten()
- .map(|&kind| reg_to_abi_param(Reg { kind, size: cast.prefix_chunk_size }))
+ .map(|®| reg_to_abi_param(reg))
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
.collect::<SmallVec<_>>();
// TODO(antoyo)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
self.cx.current_func.borrow().expect("current func")
.get_param(index as i32)
.to_rvalue()
let mut args: Vec<_> = self
.prefix
.iter()
- .flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
+ .flat_map(|option_reg| {
+ option_reg.map(|reg| reg.gcc_type(cx))
})
.chain((0..rest_count).map(|_| rest_gcc_unit))
.collect();
let mut args: Vec<_> = self
.prefix
.iter()
- .flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
- })
+ .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
);
}
}
+ PassMode::Cast(cast) => {
+ cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
+ }
_ => {}
}
for arg in &self.args {
apply(a);
apply(b);
}
- PassMode::Cast(_) => {
- apply(&ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(&cast.attrs);
}
}
}
);
}
}
+ PassMode::Cast(cast) => {
+ cast.attrs.apply_attrs_to_callsite(
+ llvm::AttributePlace::ReturnValue,
+ &bx.cx,
+ callsite,
+ );
+ }
_ => {}
}
if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
apply(bx.cx, a);
apply(bx.cx, b);
}
- PassMode::Cast(_) => {
- apply(bx.cx, &ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(bx.cx, &cast.attrs);
}
}
}
fn_abi.apply_attrs_callsite(self, callsite)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
llvm::get_param(self.llfn(), index as c_uint)
}
}
pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
llcx: &'a llvm::Context,
+ old_handler: Option<&'a llvm::DiagnosticHandler>,
}
impl<'a> DiagnosticHandlers<'a> {
handler: &'a Handler,
llcx: &'a llvm::Context,
) -> Self {
+ let remark_passes_all: bool;
+ let remark_passes: Vec<CString>;
+ match &cgcx.remark {
+ Passes::All => {
+ remark_passes_all = true;
+ remark_passes = Vec::new();
+ }
+ Passes::Some(passes) => {
+ remark_passes_all = false;
+ remark_passes =
+ passes.iter().map(|name| CString::new(name.as_str()).unwrap()).collect();
+ }
+ };
+ let remark_passes: Vec<*const c_char> =
+ remark_passes.iter().map(|name: &CString| name.as_ptr()).collect();
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
+ let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
+ llvm::LLVMRustContextConfigureDiagnosticHandler(
+ llcx,
+ diagnostic_handler,
+ data.cast(),
+ remark_passes_all,
+ remark_passes.as_ptr(),
+ remark_passes.len(),
+ );
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
- llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
+ DiagnosticHandlers { data, llcx, old_handler }
}
- DiagnosticHandlers { data, llcx }
}
}
use std::ptr::null_mut;
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
- llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
+ llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler);
drop(Box::from_raw(self.data));
}
}
if enabled {
diag_handler.note_without_error(&format!(
- "optimization {} for {} at {}:{}:{}: {}",
- opt.kind.describe(),
- opt.pass_name,
- opt.filename,
- opt.line,
- opt.column,
- opt.message
+ "{}:{}:{}: {}: {}",
+ opt.filename, opt.line, opt.column, opt.pass_name, opt.message,
));
}
}
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_llvm::RustString;
use rustc_middle::mir::coverage::CodeRegion;
+use rustc_middle::ty::TyCtxt;
use rustc_span::Symbol;
use std::ffi::CString;
/// Generates and exports the Coverage Map.
///
-/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3),
-/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
-/// and published in Rust's November 2020 fork of LLVM. This version is supported by the LLVM
-/// coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
+/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
+/// bundled with Rust's fork of LLVM.
///
/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
/// the same version. Clang's implementation of Coverage Map generation was referenced when
pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
let tcx = cx.tcx;
- // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3).
- // If not, the LLVM Version must be less than 11.
+ // Ensure the installed version of LLVM supports at least Coverage Map
+ // Version 5 (encoded as a zero-based value: 4), which was introduced with
+ // LLVM 12.
let version = coverageinfo::mapping_version();
- if version != 3 {
- tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
+ if version < 4 {
+ tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
}
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
return;
}
- let mut mapgen = CoverageMapGenerator::new();
+ let mut mapgen = CoverageMapGenerator::new(tcx, version);
// Encode coverage mappings and generate function records
let mut function_data = Vec::new();
}
impl CoverageMapGenerator {
- fn new() -> Self {
- Self { filenames: FxIndexSet::default() }
+ fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
+ let mut filenames = FxIndexSet::default();
+ if version >= 5 {
+ // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
+ // requires setting the first filename to the compilation directory.
+ // Since rustc generates coverage maps with relative paths, the
+ // compilation directory can be combined with the the relative paths
+ // to get absolute paths, if needed.
+ let working_dir = tcx
+ .sess
+ .opts
+ .working_dir
+ .remapped_path_if_available()
+ .to_string_lossy()
+ .to_string();
+ let c_filename =
+ CString::new(working_dir).expect("null error converting filename to C string");
+ filenames.insert(c_filename);
+ }
+ Self { filenames }
}
/// Using the `expressions` and `counter_regions` collected for the current function, generate
// Deref of the `Pin<&mut Self>` state argument.
mir::ProjectionElem::Field(..),
mir::ProjectionElem::Deref,
-
// Field of a variant of the state.
mir::ProjectionElem::Downcast(_, variant),
mir::ProjectionElem::Field(field, _),
] => {
- let name = &mut generator_saved_local_names[
- generator_layout.variant_fields[variant][field]
- ];
+ let name = &mut generator_saved_local_names
+ [generator_layout.variant_fields[variant][field]];
if name.is_none() {
name.replace(var.name);
}
#[repr(C)]
pub struct Linker<'a>(InvariantOpaque<'a>);
-pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
-pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
+extern "C" {
+ pub type DiagnosticHandler;
+}
+
+pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
+pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
pub mod coverageinfo {
use super::coverage_map;
- /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+ /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum RegionKind {
/// A GapRegion is like a CodeRegion, but its count is only set as the
/// line execution count when its the only region in the line.
GapRegion = 3,
+
+ /// A BranchRegion represents leaf-level boolean expressions and is
+ /// associated with two counters, each representing the number of times the
+ /// expression evaluates to true or false.
+ BranchRegion = 4,
}
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
/// coverage map, in accordance with the
- /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+ /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
/// array", encoded separately), and source location (start and end positions of the represented
/// The counter type and type-dependent counter data, if any.
counter: coverage_map::Counter,
+ /// If the `RegionKind` is a `BranchRegion`, this represents the counter
+ /// for the false branch of the region.
+ false_counter: coverage_map::Counter,
+
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
/// that, in turn, are used to look up the filename for this region.
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
}
}
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ crate fn branch_region(
+ counter: coverage_map::Counter,
+ false_counter: coverage_map::Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter,
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::BranchRegion,
+ }
+ }
+
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id,
start_line,
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
- pub fn LLVMContextSetDiagnosticHandler(
- C: &Context,
- Handler: DiagnosticHandler,
- DiagnosticContext: *mut c_void,
- );
-
#[allow(improper_ctypes)]
pub fn LLVMRustUnpackOptimizationDiagnostic(
DI: &'a DiagnosticInfo,
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
- H: InlineAsmDiagHandler,
+ H: InlineAsmDiagHandlerTy,
CX: *mut c_void,
);
mod_id: *const c_char,
data: &ThinLTOData,
);
+
+ pub fn LLVMRustContextGetDiagnosticHandler(Context: &Context) -> Option<&DiagnosticHandler>;
+ pub fn LLVMRustContextSetDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler: Option<&DiagnosticHandler>,
+ );
+ pub fn LLVMRustContextConfigureDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler_callback: DiagnosticHandlerTy,
+ diagnostic_handler_context: *mut c_void,
+ remark_all_passes: bool,
+ remark_passes: *const *const c_char,
+ remark_passes_len: usize,
+ );
+
}
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
-/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum CounterKind {
/// `instrprof.increment()`)
/// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
/// counter expressions.
-/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100)
+/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103)
/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
}
}
-/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147)
+/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ExprKind {
Add = 1,
}
-/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149)
+/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152)
/// Important: The Rust struct layout (order and types of fields) must match its C++
/// counterpart.
#[derive(Copy, Clone, Debug)]
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value);
- fn get_param(&self, index: usize) -> Self::Value;
+ fn get_param(&mut self, index: usize) -> Self::Value;
}
sym::transmute => {
self.copy_op_transmute(&args[0], dest)?;
}
- sym::assert_inhabited => {
+ sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let ty = instance.substs.type_at(0);
let layout = self.layout_of(ty)?;
+ // For *all* intrinsics we first check `is_uninhabited` to give a more specific
+ // error message.
if layout.abi.is_uninhabited() {
// The run-time intrinsic panics just to get a good backtrace; here we abort
// since there is no problem showing a backtrace even for aborts.
),
)?;
}
+ if intrinsic_name == sym::assert_zero_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ true)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to zero-initialize type `{}`, which is invalid",
+ ty
+ ),
+ )?;
+ }
+ if intrinsic_name == sym::assert_uninit_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ false)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
+ ty
+ ),
+ )?;
+ }
}
sym::simd_insert => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
let signed = left_layout.abi.is_signed();
let size = u128::from(left_layout.size.bits());
let overflow = r >= size;
- let r = r % size; // mask to type 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>
+ // 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 l = self.sign_extend(l, left_layout) as i128;
let elem_size = first.layout.size;
let first_ptr = first.ptr;
let rest_ptr = first_ptr.offset(elem_size, self)?;
+ // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as
+ // that place might be more aligned than its type mandates (a `u8` array could
+ // be 4-aligned if it sits at the right spot in a struct). Instead we use
+ // `first.layout.align`, i.e., the alignment given by the type.
self.memory.copy_repeatedly(
first_ptr,
first.align,
rest_ptr,
- first.align,
+ first.layout.align.abi,
elem_size,
length - 1,
/*nonoverlapping:*/ true,
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
use rustc_errors::{Applicability, Diagnostic, ErrorReported};
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId, LangItem};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
+use rustc_trait_selection::traits::SelectionContext;
use std::mem;
use std::ops::Deref;
self.visit_body(&body);
}
- // Ensure that the end result is `Sync` in a non-thread local `static`.
- let should_check_for_sync = self.const_kind()
- == hir::ConstContext::Static(hir::Mutability::Not)
- && !tcx.is_thread_local_static(def_id.to_def_id());
-
- if should_check_for_sync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- check_return_ty_is_sync(tcx, &body, hir_id);
- }
-
// If we got through const-checking without emitting any "primary" errors, emit any
// "secondary" errors if they occurred.
let secondary_errors = mem::take(&mut self.secondary_errors);
}
let mut err_span = self.span;
+ let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
- let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty(
- self.ccx,
- dropped_place.ty(self.body, self.tcx).ty,
- );
+ let ty_needs_non_const_drop =
+ qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
+
+ debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
if !ty_needs_non_const_drop {
return;
}
}
-fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
- let ty = body.return_ty();
- tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
- fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- let errors = fulfillment_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- });
-}
-
fn place_as_reborrow(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
- mir::TerminatorKind::Drop { place: dropped_place, .. } => {
+ mir::TerminatorKind::Drop { place: dropped_place, .. }
+ | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
// Instead of throwing a bug, we just return here. This is because we have to
}
}
- mir::TerminatorKind::DropAndReplace { .. } => span_bug!(
- terminator.source_info.span,
- "`DropAndReplace` should be removed by drop elaboration",
- ),
-
mir::TerminatorKind::Abort
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
pub mod check_consts;
pub mod promote_consts;
pub mod validate;
-
-pub use rustc_middle::mir::MirPass;
use std::{cmp, iter, mem};
use crate::transform::check_consts::{qualifs, ConstCx};
-use crate::transform::MirPass;
/// A `MirPass` for promotion.
///
//! Validates the MIR to ensure that invariants are upheld.
-use super::MirPass;
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
- PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand,
+ PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_index::vec::{Idx, IndexVec};
use std::mem;
-use std::ptr;
-pub trait IdFunctor {
+pub trait IdFunctor: Sized {
type Inner;
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner;
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}
impl<T> IdFunctor for Box<T> {
type Inner = T;
#[inline]
- fn map_id<F>(self, mut f: F) -> Self
+ fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
let raw = Box::into_raw(self);
- unsafe {
+ Ok(unsafe {
// SAFETY: The raw pointer points to a valid value of type `T`.
- let value = ptr::read(raw);
+ let value = raw.read();
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
// inverse of `Box::assume_init()` and should be safe.
- let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
+ let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
- raw.write(f(value));
- // SAFETY: We just initialized `raw`.
- raw.assume_init()
- }
+ Box::write(raw, f(value)?)
+ })
}
}
type Inner = T;
#[inline]
- fn map_id<F>(mut self, mut f: F) -> Self
+ fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
// FIXME: We don't really care about panics here and leak
// far more than we should, but that should be fine for now.
let start = self.as_mut_ptr();
for i in 0..len {
let p = start.add(i);
- ptr::write(p, f(ptr::read(p)));
+ match f(p.read()) {
+ Ok(val) => p.write(val),
+ Err(err) => {
+ // drop all other elements in self
+ // (current element was "moved" into the call to f)
+ for j in (0..i).chain(i + 1..len) {
+ start.add(j).drop_in_place();
+ }
+
+ // returning will drop self, releasing the allocation
+ // (len is 0 so elements will not be re-dropped)
+ return Err(err);
+ }
+ }
}
+ // Even if we encountered an error, set the len back
+ // so we don't leak memory.
self.set_len(len);
}
- self
+ Ok(self)
}
}
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- Vec::from(self).map_id(f).into()
+ Vec::from(self).try_map_id(f).map(Into::into)
}
}
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- IndexVec::from_raw(self.raw.map_id(f))
+ self.raw.try_map_id(f).map(IndexVec::from_raw)
}
}
-Trait objects like `Box<Trait>` can only be constructed when certain
-requirements are satisfied by the trait in question.
-
-Trait objects are a form of dynamic dispatch and use a dynamically sized type
-for the inner type. So, for a given trait `Trait`, when `Trait` is treated as a
-type, as in `Box<Trait>`, the inner type is 'unsized'. In such cases the boxed
-pointer is a 'fat pointer' that contains an extra pointer to a table of methods
-(among other things) for dynamic dispatch. This design mandates some
-restrictions on the types of traits that are allowed to be used in trait
-objects, which are collectively termed as 'object safety' rules.
-
-Attempting to create a trait object for a non object-safe trait will trigger
-this error.
-
-There are various rules:
-
-### The trait cannot require `Self: Sized`
-
-When `Trait` is treated as a type, the type does not implement the special
-`Sized` trait, because the type does not have a known size at compile time and
-can only be accessed behind a pointer. Thus, if we have a trait like the
-following:
+For any given trait `Trait` there may be a related _type_ called the _trait
+object type_ which is typically written as `dyn Trait`. In earlier editions of
+Rust, trait object types were written as plain `Trait` (just the name of the
+trait, written in type positions) but this was a bit too confusing, so we now
+write `dyn Trait`.
+
+Some traits are not allowed to be used as trait object types. The traits that
+are allowed to be used as trait object types are called "object-safe" traits.
+Attempting to use a trait object type for a trait that is not object-safe will
+trigger error E0038.
+
+Two general aspects of trait object types give rise to the restrictions:
+
+ 1. Trait object types are dynamically sized types (DSTs), and trait objects of
+ these types can only be accessed through pointers, such as `&dyn Trait` or
+ `Box<dyn Trait>`. The size of such a pointer is known, but the size of the
+ `dyn Trait` object pointed-to by the pointer is _opaque_ to code working
+ with it, and different tait objects with the same trait object type may
+ have different sizes.
+
+ 2. The pointer used to access a trait object is paired with an extra pointer
+ to a "virtual method table" or "vtable", which is used to implement dynamic
+ dispatch to the object's implementations of the trait's methods. There is a
+ single such vtable for each trait implementation, but different trait
+ objects with the same trait object type may point to vtables from different
+ implementations.
+
+The specific conditions that violate object-safety follow, most of which relate
+to missing size information and vtable polymorphism arising from these aspects.
+
+### The trait requires `Self: Sized`
+
+Traits that are declared as `Trait: Sized` or which otherwise inherit a
+constraint of `Self:Sized` are not object-safe.
+
+The reasoning behind this is somewhat subtle. It derives from the fact that Rust
+requires (and defines) that every trait object type `dyn Trait` automatically
+implements `Trait`. Rust does this to simplify error reporting and ease
+interoperation between static and dynamic polymorphism. For example, this code
+works:
```
-trait Foo where Self: Sized {
+trait Trait {
+}
+
+fn static_foo<T:Trait + ?Sized>(b: &T) {
+}
+fn dynamic_bar(a: &dyn Trait) {
+ static_foo(a)
}
```
-We cannot create an object of type `Box<Foo>` or `&Foo` since in this case
-`Self` would not be `Sized`.
+This code works because `dyn Trait`, if it exists, always implements `Trait`.
+
+However as we know, any `dyn Trait` is also unsized, and so it can never
+implement a sized trait like `Trait:Sized`. So, rather than allow an exception
+to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit
+such a `dyn Trait` from existing at all.
+
+Only unsized traits are considered object-safe.
Generally, `Self: Sized` is used to indicate that the trait should not be used
as a trait object. If the trait comes from your own crate, consider removing
fn foo(&self) -> Self;
}
-fn call_foo(x: Box<Trait>) {
+fn call_foo(x: Box<dyn Trait>) {
let y = x.foo(); // What type is y?
// ...
}
If only some methods aren't object-safe, you can add a `where Self: Sized` bound
on them to mark them as explicitly unavailable to trait objects. The
functionality will still be available to all other implementers, including
-`Box<Trait>` which is itself sized (assuming you `impl Trait for Box<Trait>`).
+`Box<dyn Trait>` which is itself sized (assuming you `impl Trait for Box<dyn
+Trait>`).
```
trait Trait {
```
At compile time each implementation of `Trait` will produce a table containing
-the various methods (and other items) related to the implementation.
+the various methods (and other items) related to the implementation, which will
+be used as the virtual method table for a `dyn Trait` object derived from that
+implementation.
This works fine, but when the method gains generic parameters, we can have a
problem.
# impl Trait for u8 { fn foo<T>(&self, on: T) {} }
# impl Trait for bool { fn foo<T>(&self, on: T) {} }
# // etc.
-fn call_foo(thing: Box<Trait>) {
+fn call_foo(thing: Box<dyn Trait>) {
thing.foo(true); // this could be any one of the 8 types above
thing.foo(1);
thing.foo("hello");
```
If this is not an option, consider replacing the type parameter with another
-trait object (e.g., if `T: OtherTrait`, use `on: Box<OtherTrait>`). If the
+trait object (e.g., if `T: OtherTrait`, use `on: Box<dyn OtherTrait>`). If the
number of types you intend to feed to this method is limited, consider manually
listing out the methods of different types.
}
```
-### The trait cannot contain associated constants
+### Trait contains associated constants
Just like static functions, associated constants aren't stored on the method
table. If the trait or any subtrait contain an associated constant, they cannot
}
```
-### The trait cannot use `Self` as a type parameter in the supertrait listing
+### Trait uses `Self` as a type parameter in the supertrait listing
This is similar to the second sub-error, but subtler. It happens in situations
like the following:
/// Formats the substitutions of the primary_span
///
- /// The are a lot of conditions to this method, but in short:
+ /// There are a lot of conditions to this method, but in short:
///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// we format the `help` suggestion depending on the content of the
}
let source_string = match file.get_line(line.line_index - 1) {
- Some(s) => replace_tabs(&*s),
+ Some(s) => normalize_whitespace(&*s),
None => return Vec::new(),
};
let line_offset = buffer.num_lines();
- let left = margin.left(source_string.len()); // Left trim
+ // Left trim
+ let left = margin.left(source_string.len());
+
// Account for unicode characters of width !=0 that were removed.
let left = source_string
.chars()
}
for &(ref text, _) in msg.iter() {
// Account for newlines to align output to its label.
- for (line, text) in replace_tabs(text).lines().enumerate() {
+ for (line, text) in normalize_whitespace(text).lines().enumerate() {
buffer.append(
0 + line,
&format!(
self.draw_line(
&mut buffer,
- &replace_tabs(&unannotated_line),
+ &normalize_whitespace(&unannotated_line),
annotated_file.lines[line_idx + 1].line_index - 1,
last_buffer_line_num,
width_offset,
suggestions.iter().take(MAX_SUGGESTIONS)
{
notice_capitalization |= only_capitalization;
- // Only show underline if the suggestion spans a single line and doesn't cover the
- // entirety of the code output. If you have multiple replacements in the same line
- // of code, show the underline.
- let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
- && complete.lines().count() == 1;
let has_deletion = parts.iter().any(|p| p.is_deletion());
let is_multiline = complete.lines().count() > 1;
- let show_diff = has_deletion && !is_multiline;
+ enum DisplaySuggestion {
+ Underline,
+ Diff,
+ None,
+ }
+
+ let show_code_change = if has_deletion && !is_multiline {
+ DisplaySuggestion::Diff
+ } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
+ && !is_multiline
+ {
+ DisplaySuggestion::Underline
+ } else {
+ DisplaySuggestion::None
+ };
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
row_num += 1;
}
&self.maybe_anonymized(line_start + line_pos),
Style::LineNumber,
);
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Add the line number for both addition and removal to drive the point home.
//
// N - fn foo<A: T>(bar: A) {
buffer.puts(
row_num - 1,
max_line_num_len + 3,
- &replace_tabs(
+ &normalize_whitespace(
&*file_lines
.file
.get_line(file_lines.lines[line_pos].line_index)
}
// print the suggestion
- buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
+ buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle);
// Colorize addition/replacements with green.
for &SubstitutionHighlight { start, end } in highlight_parts {
let mut offsets: Vec<(usize, isize)> = Vec::new();
// Only show an underline in the suggestions if the suggestion is not the
// entirety of the code being shown and the displayed code is not multiline.
- if show_underline {
+ if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
for part in parts {
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
assert!(underline_start >= 0 && underline_end >= 0);
let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
- if !show_diff {
+ if let DisplaySuggestion::Underline = show_code_change {
// If this is a replacement, underline with `^`, if this is an addition
// underline with `+`.
buffer.putc(
);
}
}
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Colorize removal with red in diff format.
buffer.set_style_range(
row_num - 2,
// if we elided some lines, add an ellipsis
if lines.next().is_some() {
buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
- } else if !show_underline {
+ } else if let DisplaySuggestion::None = show_code_change {
draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
row_num += 1;
}
// We replace some characters so the CLI output is always consistent and underlines aligned.
const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
('\t', " "), // We do our own tab replacement
+ ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
- ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+ ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk
('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
('\u{202E}', ""),
('\u{2066}', ""),
('\u{2069}', ""),
];
-fn replace_tabs(str: &str) -> String {
+fn normalize_whitespace(str: &str) -> String {
let mut s = str.to_string();
for (c, replacement) in OUTPUT_REPLACEMENTS {
s = s.replace(*c, replacement);
#![feature(crate_visibility_modifier)]
#![feature(backtrace)]
#![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(nll)]
}
fn treat_err_as_bug(&self) -> bool {
- self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
+ self.flags
+ .treat_err_as_bug
+ .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
}
fn print_error_count(&mut self, registry: &Registry) {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
- match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
+ match (
+ self.err_count() + self.lint_err_count,
+ self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
+ ) {
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, _) | (1, _) => {}
(count, as_bug) => panic!(
Param(ast::Param),
FieldDef(ast::FieldDef),
Variant(ast::Variant),
+ Crate(ast::Crate),
}
impl Annotatable {
Annotatable::Param(ref p) => p.span,
Annotatable::FieldDef(ref sf) => sf.span,
Annotatable::Variant(ref v) => v.span,
+ Annotatable::Crate(ref c) => c.span,
}
}
Annotatable::Param(p) => p.visit_attrs(f),
Annotatable::FieldDef(sf) => sf.visit_attrs(f),
Annotatable::Variant(v) => v.visit_attrs(f),
+ Annotatable::Crate(c) => c.visit_attrs(f),
}
}
Annotatable::Param(p) => visitor.visit_param(p),
Annotatable::FieldDef(sf) => visitor.visit_field_def(sf),
Annotatable::Variant(v) => visitor.visit_variant(v),
+ Annotatable::Crate(c) => visitor.visit_crate(c),
}
}
| Annotatable::GenericParam(..)
| Annotatable::Param(..)
| Annotatable::FieldDef(..)
- | Annotatable::Variant(..) => panic!("unexpected annotatable"),
+ | Annotatable::Variant(..)
+ | Annotatable::Crate(..) => panic!("unexpected annotatable"),
}
}
_ => panic!("expected variant"),
}
}
+
+ pub fn expect_crate(self) -> ast::Crate {
+ match self {
+ Annotatable::Crate(krate) => krate,
+ _ => panic!("expected krate"),
+ }
+ }
}
/// Result of an expansion that may need to be retried.
fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
None
}
+
+ fn make_crate(self: Box<Self>) -> Option<ast::Crate> {
+ // Fn-like macros cannot produce a crate.
+ unreachable!()
+ }
}
macro_rules! make_MacEager {
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
-use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
+use rustc_ast::{NodeId, PatKind, Path, StmtKind};
use rustc_ast_pretty::pprust;
use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, FatalError, PResult};
+use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
use rustc_parse::parser::{
AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
use rustc_span::symbol::{sym, Ident};
use rustc_span::{FileName, LocalExpnId, Span};
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::rc::Rc;
Variants(SmallVec<[ast::Variant; 1]>) {
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
}
+ Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
}
pub enum SupportsMacroExpansion {
AstFragmentKind::Items
| AstFragmentKind::TraitItems
| AstFragmentKind::ImplItems
- | AstFragmentKind::ForeignItems => {
- SupportsMacroExpansion::Yes { supports_inner_attrs: true }
- }
+ | AstFragmentKind::ForeignItems
+ | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
AstFragmentKind::OptExpr => {
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
}
+ AstFragmentKind::Crate => {
+ AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate())
+ }
AstFragmentKind::Pat | AstFragmentKind::Ty => {
panic!("patterns and types aren't annotatable")
}
MacroExpander { cx, monotonic }
}
- // FIXME: Avoid visiting the crate as a `Mod` item,
- // make crate a first class expansion target instead.
- pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+ pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
let file_path = match self.cx.source_map().span_to_filename(krate.span) {
FileName::Real(name) => name
.into_local_path()
file_path_stack: vec![file_path],
dir_path,
});
-
- let krate_item = AstFragment::Items(smallvec![P(ast::Item {
- attrs: krate.attrs,
- span: krate.span,
- kind: ast::ItemKind::Mod(
- Unsafe::No,
- ModKind::Loaded(krate.items, Inline::Yes, krate.span)
- ),
- ident: Ident::empty(),
- id: ast::DUMMY_NODE_ID,
- vis: ast::Visibility {
- span: krate.span.shrink_to_lo(),
- kind: ast::VisibilityKind::Public,
- tokens: None,
- },
- tokens: None,
- })]);
-
- match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
- Some(ast::Item {
- attrs,
- kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
- ..
- }) => {
- krate.attrs = attrs;
- krate.items = items;
- }
- None => {
- // Resolution failed so we return an empty expansion
- krate.attrs = vec![];
- krate.items = vec![];
- }
- Some(ast::Item { span, kind, .. }) => {
- krate.attrs = vec![];
- krate.items = vec![];
- self.cx.span_err(
- span,
- &format!(
- "expected crate top-level item to be a module after macro expansion, found {} {}",
- kind.article(), kind.descr()
- ),
- );
- // FIXME: this workaround issue #84569
- FatalError.raise();
- }
- };
+ let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
self.cx.trace_macros_diag();
krate
}
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
- let mut fake_tokens = false;
- if let Annotatable::Item(item_inner) = &item {
- if let ItemKind::Mod(_, mod_kind) = &item_inner.kind {
- // FIXME: Collect tokens and use them instead of generating
- // fake ones. These are unstable, so it needs to be
- // fixed prior to stabilization
- // Fake tokens when we are invoking an inner attribute, and:
- fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) &&
- // We are invoking an attribute on the crate root, or an outline
- // module
- (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _)));
- }
- }
- let tokens = if fake_tokens {
- rustc_parse::fake_token_stream(
+ let tokens = match &item {
+ // FIXME: Collect tokens and use them instead of generating
+ // fake ones. These are unstable, so it needs to be
+ // fixed prior to stabilization
+ // Fake tokens when we are invoking an inner attribute, and
+ // we are invoking it on an out-of-line module or crate.
+ Annotatable::Crate(krate) => rustc_parse::fake_token_stream_for_crate(
&self.cx.sess.parse_sess,
- &item.into_nonterminal(),
- )
- } else {
- item.into_tokens(&self.cx.sess.parse_sess)
+ krate,
+ ),
+ Annotatable::Item(item_inner)
+ if matches!(attr.style, ast::AttrStyle::Inner)
+ && matches!(
+ item_inner.kind,
+ ItemKind::Mod(
+ _,
+ ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
+ )
+ ) =>
+ {
+ rustc_parse::fake_token_stream(
+ &self.cx.sess.parse_sess,
+ &item.into_nonterminal(),
+ )
+ }
+ _ => item.into_tokens(&self.cx.sess.parse_sess),
};
let attr_item = attr.unwrap_normal_item();
if let MacArgs::Eq(..) = attr_item.args {
Annotatable::Item(_)
| Annotatable::TraitItem(_)
| Annotatable::ImplItem(_)
- | Annotatable::ForeignItem(_) => return,
+ | Annotatable::ForeignItem(_)
+ | Annotatable::Crate(..) => return,
Annotatable::Stmt(stmt) => {
// Attributes are stable on item statements,
// but unstable on all other kinds of statements
RecoverComma::No,
RecoverColon::Yes,
)?),
+ AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
}
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
+ fn visit_crate(&mut self, krate: &mut ast::Crate) {
+ let span = krate.span;
+ let empty_crate =
+ || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
+ let mut fold_crate = |krate: ast::Crate| {
+ let mut krate = match self.configure(krate) {
+ Some(krate) => krate,
+ None => return empty_crate(),
+ };
+
+ if let Some(attr) = self.take_first_attr(&mut krate) {
+ return self
+ .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
+ .make_crate();
+ }
+
+ noop_visit_crate(&mut krate, self);
+ krate
+ };
+
+ // Cannot use `visit_clobber` here, see the FIXME on it.
+ *krate = fold_crate(mem::replace(krate, empty_crate()));
+ }
+
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
self.cfg.configure_expr(expr);
visit_clobber(expr.deref_mut(), |mut expr| {
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(if_let_guard)]
#![feature(iter_zip)]
#![feature(let_else)]
//
// At the beginning of the loop, if we reach the end of the delimited submatcher,
// we pop the stack to backtrack out of the descent.
- seq
- @
- (TokenTree::Delimited(..)
+ seq @ (TokenTree::Delimited(..)
| TokenTree::Token(Token { kind: DocComment(..), .. })) => {
let lower_elts = mem::replace(&mut item.top_elts, Tt(seq));
let idx = item.idx;
let tts: &[TokenTree] = &tts[..];
match tts {
- [TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts)]
- if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" =>
- {
+ [
+ TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }),
+ TokenTree::Token(Token { kind: token::Not, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }),
+ TokenTree::Delimited(_, macro_delim, macro_tts),
+ ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
let tts = ¯o_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Delimited(_, first_delim, first_tts), TokenTree::Token(Token { kind: token::FatArrow, .. }), TokenTree::Delimited(_, second_delim, second_tts)]
- if macro_delim == &token::Paren =>
- {
+ [
+ TokenTree::Delimited(_, first_delim, first_tts),
+ TokenTree::Token(Token { kind: token::FatArrow, .. }),
+ TokenTree::Delimited(_, second_delim, second_tts),
+ ] if macro_delim == &token::Paren => {
let tts = &first_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
- if first_delim == &token::Paren && name.as_str() == "a" => {}
+ [
+ TokenTree::Token(Token { kind: token::Dollar, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
+ ] if first_delim == &token::Paren && name.as_str() == "a" => {}
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
}
let tts = &second_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
- if second_delim == &token::Paren && name.as_str() == "a" => {}
+ [
+ TokenTree::Token(Token { kind: token::Dollar, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
+ ] if second_delim == &token::Paren && name.as_str() == "a" => {}
_ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
}
}
|| P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
match kind {
+ AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
+ attrs: Default::default(),
+ items: Default::default(),
+ span,
+ is_placeholder: Some(id),
+ }),
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
_ => noop_visit_ty(ty, self),
}
}
+
+ fn visit_crate(&mut self, krate: &mut ast::Crate) {
+ if let Some(id) = krate.is_placeholder {
+ *krate = self.remove(id).make_crate();
+ } else {
+ noop_visit_crate(krate, self)
+ }
+ }
}
Param(ParamName),
/// User wrote nothing (e.g., the lifetime in `&u32`).
- Implicit,
+ ///
+ /// The bool indicates whether the user should have written something.
+ Implicit(bool),
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
pub fn ident(&self) -> Ident {
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
pub fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::Underscore => true,
// It might seem surprising that `Fresh(_)` counts as
rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
- rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
+ rustc_data_structures::static_assert_size!(super::Ty<'static>, 80);
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
| LifetimeName::Param(ParamName::Error)
| LifetimeName::Static
| LifetimeName::Error
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Underscore => {}
}
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None;
Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
+ GeneratorReturn, sym::generator_return, generator_return, Target::AssocTy, GenericRequirement::None;
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None;
+ IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
};
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
- };
+ let (in_definition_scope, origin) = match tcx.hir().expect_item(def_id).kind
+ {
+ // Anonymous `impl Trait`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: Some(parent),
+ origin,
+ ..
+ }) => (parent == parent_def_id.to_def_id(), origin),
+ // Named `type Foo = impl Bar;`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: None,
+ origin,
+ ..
+ }) => {
+ (may_define_opaque_type(tcx, parent_def_id, opaque_hir_id), origin)
+ }
+ _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ };
if in_definition_scope {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span};
use rustc_middle::mir;
-use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
use std::ops::ControlFlow;
where
T: TypeFoldable<'tcx>,
{
- let mut full_resolver = FullTypeResolver { infcx, err: None };
- let result = value.fold_with(&mut full_resolver);
- match full_resolver.err {
- None => Ok(result),
- Some(e) => Err(e),
- }
+ value.try_fold_with(&mut FullTypeResolver { infcx })
}
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
- err: Option<FixupError<'tcx>>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+ type Error = FixupError<'tcx>;
+
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
+}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() {
- t // micro-optimize -- if there is nothing in this type that this fold affects...
+ Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
- self.err = Some(FixupError::UnresolvedTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::IntVar(vid)) => {
- self.err = Some(FixupError::UnresolvedIntTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::FloatVar(vid)) => {
- self.err = Some(FixupError::UnresolvedFloatTy(vid));
- self.tcx().ty_error()
- }
+ ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
+ ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
+ ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}
- _ => t.super_fold_with(self),
+ _ => t.try_super_fold_with(self),
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
- ty::ReVar(rid) => self
+ ty::ReVar(rid) => Ok(self
.infcx
.lexical_region_resolutions
.borrow()
.as_ref()
.expect("region resolution not performed")
- .resolve_var(rid),
- _ => r,
+ .resolve_var(rid)),
+ _ => Ok(r),
}
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !c.needs_infer() {
- c // micro-optimize -- if there is nothing in this const that this fold affects...
+ Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
- self.err = Some(FixupError::UnresolvedConst(vid));
- return self.tcx().const_error(c.ty);
+ return Err(FixupError::UnresolvedConst(vid));
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
}
_ => {}
}
- c.super_fold_with(self)
+ c.try_super_fold_with(self)
}
}
}
use crate::traits;
use crate::traits::project::Normalized;
use rustc_middle::ty;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use std::fmt;
use std::ops::ControlFlow;
// TypeFoldable implementations.
impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- traits::Obligation {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(traits::Obligation {
cause: self.cause,
recursion_depth: self.recursion_depth,
- predicate: self.predicate.fold_with(folder),
- param_env: self.param_env.fold_with(folder),
- }
+ predicate: self.predicate.try_fold_with(folder)?,
+ param_env: self.param_env.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.predicate.visit_with(visitor)
+ self.predicate.visit_with(visitor)?;
+ self.param_env.visit_with(visitor)
}
}
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::FileName;
+use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tempfile::Builder as TempFileBuilder;
let crate_attrs = krate.attrs.clone();
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
- let krate = ast::Crate { attrs, items, span };
+ let krate = ast::Crate { attrs, items, span, is_placeholder: None };
pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
(krate.attrs, krate.items)
};
});
}
+ // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
+ sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| {
+ let mut identifiers: Vec<_> = identifiers.drain().collect();
+ identifiers.sort_by_key(|&(key, _)| key);
+ for (ident, mut spans) in identifiers.into_iter() {
+ spans.sort();
+ sess.diagnostic().span_err(
+ MultiSpan::from(spans),
+ &format!("identifiers cannot contain emoji: `{}`", ident),
+ );
+ }
+ });
+
Ok(krate)
}
tracked!(dep_info_omit_d_target, true);
tracked!(dual_proc_macros, true);
tracked!(fewer_names, Some(true));
- tracked!(force_overflow_checks, Some(true));
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
unicode-xid = "0.2.0"
+unic-emoji-char = "0.9.0"
[dev-dependencies]
expect-test = "1.0"
/// Peekable iterator over a char sequence.
///
-/// Next characters can be peeked via `nth_char` method,
+/// Next characters can be peeked via `first` method,
/// and position can be shifted forward via `bump` method.
pub(crate) struct Cursor<'a> {
initial_len: usize,
+ /// Iterator over chars. Slightly faster than a &str.
chars: Chars<'a>,
#[cfg(debug_assertions)]
prev: char,
}
}
- /// Returns nth character relative to the current cursor position.
+ /// Peeks the next symbol from the input stream without consuming it.
/// If requested position doesn't exist, `EOF_CHAR` is returned.
/// However, getting `EOF_CHAR` doesn't always mean actual end of file,
/// it should be checked with `is_eof` method.
- fn nth_char(&self, n: usize) -> char {
- self.chars().nth(n).unwrap_or(EOF_CHAR)
- }
-
- /// Peeks the next symbol from the input stream without consuming it.
pub(crate) fn first(&self) -> char {
- self.nth_char(0)
+ // `.next()` optimizes better than `.nth(0)`
+ self.chars.clone().next().unwrap_or(EOF_CHAR)
}
/// Peeks the second symbol from the input stream without consuming it.
pub(crate) fn second(&self) -> char {
- self.nth_char(1)
+ // `.next()` optimizes better than `.nth(1)`
+ let mut iter = self.chars.clone();
+ iter.next();
+ iter.next().unwrap_or(EOF_CHAR)
}
/// Checks if there is nothing more to consume.
self.initial_len - self.chars.as_str().len()
}
- /// Returns a `Chars` iterator over the remaining characters.
- fn chars(&self) -> Chars<'a> {
- self.chars.clone()
+ /// Resets the number of bytes consumed to 0.
+ pub(crate) fn reset_len_consumed(&mut self) {
+ self.initial_len = self.chars.as_str().len();
}
/// Moves to the next character.
Some(c)
}
+
+ /// Eats symbols while predicate returns true or until the end of file is reached.
+ pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
+ // It was tried making optimized version of this for eg. line comments, but
+ // LLVM can inline all of this and compile it down to fast iteration over bytes.
+ while predicate(self.first()) && !self.is_eof() {
+ self.bump();
+ }
+ }
}
/// "ident" or "continue"
/// At this step keywords are also considered identifiers.
Ident,
+ /// Like the above, but containing invalid unicode codepoints.
+ InvalidIdent,
/// "r#ident"
RawIdent,
/// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the
}
/// Creates an iterator that produces tokens from the input string.
-pub fn tokenize(mut input: &str) -> impl Iterator<Item = Token> + '_ {
+pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
+ let mut cursor = Cursor::new(input);
std::iter::from_fn(move || {
- if input.is_empty() {
- return None;
+ if cursor.is_eof() {
+ None
+ } else {
+ cursor.reset_len_consumed();
+ Some(cursor.advance_token())
}
- let token = first_token(input);
- input = &input[token.len..];
- Some(token)
})
}
let kind = Str { terminated };
Literal { kind, suffix_start }
}
+ // Identifier starting with an emoji. Only lexed for graceful error recovery.
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Unknown,
};
Token::new(token_kind, self.len_consumed())
// we see a prefix here, it is definitely an unknown prefix.
match self.first() {
'#' | '"' | '\'' => UnknownPrefix,
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Ident,
}
}
+ fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind {
+ // Start is already eaten, eat the rest of identifier.
+ self.eat_while(|c| {
+ unicode_xid::UnicodeXID::is_xid_continue(c)
+ || (!c.is_ascii() && unic_emoji_char::is_emoji(c))
+ || c == '\u{200d}'
+ });
+ // Known prefixes must have been handled earlier. So if
+ // we see a prefix here, it is definitely an unknown prefix.
+ match self.first() {
+ '#' | '"' | '\'' => UnknownPrefix,
+ _ => InvalidIdent,
+ }
+ }
+
fn number(&mut self, first_digit: char) -> LiteralKind {
debug_assert!('0' <= self.prev() && self.prev() <= '9');
let mut base = Base::Decimal;
self.eat_while(is_id_continue);
}
-
- /// Eats symbols while predicate returns true or until the end of file is reached.
- fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
- while predicate(self.first()) && !self.is_eof() {
- self.bump();
- }
- }
}
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
}
+
+ fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
+ warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs);
+ }
}
declare_lint! {
this_decl_ty,
CItemKind::Declaration,
) {
- let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
+ let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
let orig = Self::name_of_extern_decl(tcx, orig_fi);
// We want to ensure that we use spans for both decls that include where the
impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
- if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
- if let hir::ExprKind::Path(ref qpath) = func.kind {
- if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
- if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
- enforce_mem_discriminant(cx, func, expr.span, args[0].span);
- } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
- enforce_mem_variant_count(cx, func, expr.span);
- }
- }
- }
+ let hir::ExprKind::Call(func, args) = &expr.kind else { return };
+ let hir::ExprKind::Path(qpath) = &func.kind else { return };
+ let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() else { return };
+ let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return };
+ match name {
+ sym::mem_discriminant => enforce_mem_discriminant(cx, func, expr.span, args[0].span),
+ sym::mem_variant_count => enforce_mem_variant_count(cx, func, expr.span),
+ _ => {}
}
}
}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_order_by)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![feature(control_flow_enum)]
// Unwrap more levels of macro expansion, as panic_2015!()
// was likely expanded from panic!() and possibly from
// [debug_]assert!().
- for &i in
- &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
- {
+ loop {
let parent = expn.call_site.ctxt().outer_expn_data();
- if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
- expn = parent;
- panic_macro = i;
+ let Some(id) = parent.macro_def_id else { break };
+ let Some(name) = cx.tcx.get_diagnostic_name(id) else { break };
+ if !matches!(
+ name,
+ sym::core_panic_macro
+ | sym::std_panic_macro
+ | sym::assert_macro
+ | sym::debug_assert_macro
+ ) {
+ break;
}
+ expn = parent;
+ panic_macro = name;
}
let macro_symbol =
_ => return,
};
// (Re)check that it implements the noop diagnostic.
- for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() {
- if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
- let method = &call.ident.name;
- let receiver = &elements[0];
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
- if receiver_ty != expr_ty {
- // This lint will only trigger if the receiver type and resulting expression \
- // type are the same, implying that the method call is unnecessary.
- return;
- }
- let expr_span = expr.span;
- let note = format!(
- "the type `{:?}` which `{}` is being called on is the same as \
- the type returned from `{}`, so the method call does not do \
- anything and can be removed",
- receiver_ty, method, method,
- );
-
- let span = expr_span.with_lo(receiver.span.hi());
- cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
- let method = &call.ident.name;
- let message = format!(
- "call to `.{}()` on a reference in this situation does nothing",
- &method,
- );
- lint.build(&message)
- .span_label(span, "unnecessary method call")
- .note(¬e)
- .emit()
- });
- }
+ let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
+ if !matches!(
+ name,
+ sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
+ ) {
+ return;
}
+ let method = &call.ident.name;
+ let receiver = &elements[0];
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
+ if receiver_ty != expr_ty {
+ // This lint will only trigger if the receiver type and resulting expression \
+ // type are the same, implying that the method call is unnecessary.
+ return;
+ }
+ let expr_span = expr.span;
+ let note = format!(
+ "the type `{:?}` which `{}` is being called on is the same as \
+ the type returned from `{}`, so the method call does not do \
+ anything and can be removed",
+ receiver_ty, method, method,
+ );
+
+ let span = expr_span.with_lo(receiver.span.hi());
+ cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
+ let method = &call.ident.name;
+ let message =
+ format!("call to `.{}()` on a reference in this situation does nothing", &method,);
+ lint.build(&message).span_label(span, "unnecessary method call").note(¬e).emit()
+ });
}
}
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(
- ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_),
+ ty::layout::LayoutError::Unknown(_)
+ | ty::layout::LayoutError::SizeOverflow(_)
+ | ty::layout::LayoutError::NormalizationFailure(_, _),
) => return,
};
let (variants, tag) = match layout.variants {
struct LLVMRustCounterMappingRegion {
coverage::Counter Count;
+ coverage::Counter FalseCount;
uint32_t FileID;
uint32_t ExpandedFileID;
uint32_t LineStart;
MappingRegions.reserve(NumMappingRegions);
for (const auto &Region : makeArrayRef(RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back(
- Region.Count, Region.FileID, Region.ExpandedFileID,
+ Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID,
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
Region.Kind);
}
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
- return coverage::CovMapVersion::Version4;
+#if LLVM_VERSION_GE(13, 0)
+ return coverage::CovMapVersion::Version6;
+#else
+ return coverage::CovMapVersion::Version5;
+#endif
}
#include "LLVMWrapper.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/GlobalVariable.h"
case DK_SampleProfile:
return LLVMRustDiagnosticKind::SampleProfile;
case DK_OptimizationRemark:
+ case DK_MachineOptimizationRemark:
return LLVMRustDiagnosticKind::OptimizationRemark;
case DK_OptimizationRemarkMissed:
+ case DK_MachineOptimizationRemarkMissed:
return LLVMRustDiagnosticKind::OptimizationRemarkMissed;
case DK_OptimizationRemarkAnalysis:
+ case DK_MachineOptimizationRemarkAnalysis:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis;
case DK_OptimizationRemarkAnalysisFPCommute:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute;
return LLVMRustResult::Success;
}
}
+
+// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
+extern "C" DiagnosticHandler *
+LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
+ std::unique_ptr<DiagnosticHandler> DH = unwrap(C)->getDiagnosticHandler();
+ return DH.release();
+}
+
+// Sets unique_ptr to object of DiagnosticHandler to provide custom diagnostic
+// handling. Ownership of the handler is moved to the LLVMContext.
+extern "C" void LLVMRustContextSetDiagnosticHandler(LLVMContextRef C,
+ DiagnosticHandler *DH) {
+ unwrap(C)->setDiagnosticHandler(std::unique_ptr<DiagnosticHandler>(DH));
+}
+
+using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
+
+// Configures a diagnostic handler that invokes provided callback when a
+// backend needs to emit a diagnostic.
+//
+// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
+// the RemarkPasses array specifies individual passes for which remarks will be
+// enabled.
+extern "C" void LLVMRustContextConfigureDiagnosticHandler(
+ LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext, bool RemarkAllPasses,
+ const char * const * RemarkPasses, size_t RemarkPassesLen) {
+
+ class RustDiagnosticHandler final : public DiagnosticHandler {
+ public:
+ RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext,
+ bool RemarkAllPasses,
+ std::vector<std::string> RemarkPasses)
+ : DiagnosticHandlerCallback(DiagnosticHandlerCallback),
+ DiagnosticHandlerContext(DiagnosticHandlerContext),
+ RemarkAllPasses(RemarkAllPasses),
+ RemarkPasses(RemarkPasses) {}
+
+ virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
+ if (DiagnosticHandlerCallback) {
+ DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
+ return true;
+ }
+ return false;
+ }
+
+ bool isAnalysisRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isMissedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isPassedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isAnyRemarkEnabled() const override {
+ return RemarkAllPasses || !RemarkPasses.empty();
+ }
+
+ private:
+ bool isRemarkEnabled(StringRef PassName) const {
+ if (RemarkAllPasses)
+ return true;
+
+ for (auto &Pass : RemarkPasses)
+ if (Pass == PassName)
+ return true;
+
+ return false;
+ }
+
+ LLVMDiagnosticHandlerTy DiagnosticHandlerCallback = nullptr;
+ void *DiagnosticHandlerContext = nullptr;
+
+ bool RemarkAllPasses = false;
+ std::vector<std::string> RemarkPasses;
+ };
+
+ std::vector<std::string> Passes;
+ for (size_t I = 0; I != RemarkPassesLen; ++I)
+ Passes.push_back(RemarkPasses[I]);
+
+ unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
+ DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
+}
vi.construct(|_, index| {
let bind = &bindings[index];
quote! {
- ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)
+ ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
}
})
});
s.bound_impl(
quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>),
quote! {
- fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
+ fn try_super_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>(
self,
__folder: &mut __F
- ) -> Self {
- match self { #body_fold }
+ ) -> Result<Self, __F::Error> {
+ Ok(match self { #body_fold })
}
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
name: Symbol,
span: Span,
dep_kind: CrateDepKind,
- ) -> CrateNum {
+ ) -> Option<CrateNum> {
self.used_extern_options.insert(name);
- self.maybe_resolve_crate(name, dep_kind, None).unwrap_or_else(|err| {
- let missing_core =
- self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
- err.report(&self.sess, span, missing_core)
- })
+ match self.maybe_resolve_crate(name, dep_kind, None) {
+ Ok(cnum) => Some(cnum),
+ Err(err) => {
+ let missing_core =
+ self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
+ err.report(&self.sess, span, missing_core);
+ None
+ }
+ }
}
fn maybe_resolve_crate<'b>(
};
info!("panic runtime not found -- loading {}", name);
- let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
+ let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
let data = self.cstore.get_crate_data(cnum);
// Sanity check the loaded crate to ensure it is indeed a panic runtime
);
}
- let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
+ let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
let data = self.cstore.get_crate_data(cnum);
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
item: &ast::Item,
definitions: &Definitions,
def_id: LocalDefId,
- ) -> CrateNum {
+ ) -> Option<CrateNum> {
match item.kind {
ast::ItemKind::ExternCrate(orig_name) => {
debug!(
CrateDepKind::Explicit
};
- let cnum = self.resolve_crate(name, item.span, dep_kind);
+ let cnum = self.resolve_crate(name, item.span, dep_kind)?;
let path_len = definitions.def_path(def_id).data.len();
self.update_extern_crate(
dependency_of: LOCAL_CRATE,
},
);
- cnum
+ Some(cnum)
}
_ => bug!(),
}
}
- pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
- let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit);
+ pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
+ let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
self.update_extern_crate(
cnum,
},
);
- cnum
+ Some(cnum)
}
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, FatalError};
use rustc_session::config::{self, CrateType};
use rustc_session::cstore::{CrateSource, MetadataLoader};
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
span: Span,
name: Symbol,
) -> PathBuf {
- match find_plugin_registrar_impl(sess, metadata_loader, name) {
- Ok(res) => res,
+ find_plugin_registrar_impl(sess, metadata_loader, name).unwrap_or_else(|err| {
// `core` is always available if we got as far as loading plugins.
- Err(err) => err.report(sess, span, false),
- }
+ err.report(sess, span, false);
+ FatalError.raise()
+ })
}
fn find_plugin_registrar_impl<'a>(
}
impl CrateError {
- crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
- let mut err = match self {
+ crate fn report(self, sess: &Session, span: Span, missing_core: bool) {
+ let mut diag = match self {
CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
span,
&format!("cannot load a crate with a non-ascii name `{}`", crate_name),
),
};
- err.emit();
- sess.abort_if_errors();
- unreachable!();
+ diag.emit();
}
}
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = tcx.hir().expect_trait_item(hir_id);
+ let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
let trait_item = tcx.associated_item(def_id);
let container = match trait_item.defaultness {
debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = self.tcx.hir().expect_impl_item(hir_id);
+ let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
let impl_item = self.tcx.associated_item(def_id);
let container = match impl_item.defaultness {
fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option<Symbol>)]> {
empty_proc_macro!(self);
let tcx = self.tcx;
- let lib_features = tcx.lib_features();
+ let lib_features = tcx.lib_features(());
self.lazy(lib_features.to_vec())
}
bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
}
- pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
- _ => bug!("expected item, found {}", self.node_to_string(id)),
+ _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_impl_item(&self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
- _ => bug!("expected impl item, found {}", self.node_to_string(id)),
+ _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_trait_item(&self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
- _ => bug!("expected trait item, found {}", self.node_to_string(id)),
+ _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
}
}
- pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
- _ => bug!("expected foreign item, found {}", self.node_to_string(id)),
+ _ => {
+ bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+ }
}
}
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#[macro_use]
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
$(
impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
- fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
+ fn try_super_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
self,
_: &mut F
- ) -> $ty {
- self
+ ) -> ::std::result::Result<$ty, F::Error> {
+ Ok(self)
}
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
- fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
+ fn try_super_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
self,
folder: &mut V,
- ) -> Self {
+ ) -> ::std::result::Result<Self, V::Error> {
EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
}
};
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
- match $this {
+ Ok(match $this {
$($output)*
- }
+ })
};
(@FoldVariants($this:expr, $folder:expr)
output(
$variant ( $($variant_arg),* ) => {
$variant (
- $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
+ $($crate::ty::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
)
}
$($output)*
$variant {
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
$variant_arg, $folder
- )),* }
+ )?),* }
}
$($output)*
)
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use crate::ty::TyCtxt;
-use rustc_hir as hir;
-use rustc_hir::Node;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
-
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir as hir;
+use rustc_hir::Node;
use rustc_macros::HashStable;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_span::{Span, DUMMY_SP};
use std::fmt;
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
- /// The parent of the root body owner, if the latter is an
- /// an associated const or method, as impls/traits can also
- /// have lifetime parameters free in this body.
- pub root_parent: Option<hir::HirId>,
-
/// Maps from a scope ID to the enclosing scope id;
/// this is usually corresponding to the lexical nesting, though
/// in the case of closures the parent scope is the innermost
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ScopeTree {
root_body,
- root_parent,
ref body_expr_count,
ref parent_map,
ref var_map,
} = *self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- root_body.hash_stable(hcx, hasher);
- root_parent.hash_stable(hcx, hasher);
+ root_body.hash_stable(hcx, hasher)
});
body_expr_count.hash_stable(hcx, hasher);
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
}
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(InterpError<'_>, 64);
-
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, List, Ty, TyCtxt};
| Self::Downcast(_, _) => false,
}
}
+
+ /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
+ pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
+ matches!(*self, Self::Downcast(_, x) if x == v)
+ }
+
+ /// Returns `true` if this is a `Field` projection with the given index.
+ pub fn is_field_to(&self, f: Field) -> bool {
+ matches!(*self, Self::Field(x, _) if x == f)
+ }
}
/// Alias for projections as they appear in places, where the base is a place
/// The `*` operator (multiplication)
Mul,
/// The `/` operator (division)
+ ///
+ /// Division by zero is UB.
Div,
/// The `%` operator (modulus)
+ ///
+ /// Using zero as the modulus (second operand) is UB.
Rem,
/// The `^` operator (bitwise xor)
BitXor,
/// The `|` operator (bitwise or)
BitOr,
/// The `<<` operator (shift left)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shl,
/// The `>>` operator (shift right)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shr,
/// The `==` operator (equality)
Eq,
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- UserTypeProjection {
- base: self.base.fold_with(folder),
- projs: self.projs.fold_with(folder),
- }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(UserTypeProjection {
+ base: self.base.try_fold_with(folder)?,
+ projs: self.projs.try_fold_with(folder)?,
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::TerminatorKind::*;
let kind = match self.kind {
Goto { target } => Goto { target },
SwitchInt { discr, switch_ty, targets } => SwitchInt {
- discr: discr.fold_with(folder),
- switch_ty: switch_ty.fold_with(folder),
+ discr: discr.try_fold_with(folder)?,
+ switch_ty: switch_ty.try_fold_with(folder)?,
targets,
},
Drop { place, target, unwind } => {
- Drop { place: place.fold_with(folder), target, unwind }
+ Drop { place: place.try_fold_with(folder)?, target, unwind }
}
DropAndReplace { place, value, target, unwind } => DropAndReplace {
- place: place.fold_with(folder),
- value: value.fold_with(folder),
+ place: place.try_fold_with(folder)?,
+ value: value.try_fold_with(folder)?,
target,
unwind,
},
Yield { value, resume, resume_arg, drop } => Yield {
- value: value.fold_with(folder),
+ value: value.try_fold_with(folder)?,
resume,
- resume_arg: resume_arg.fold_with(folder),
+ resume_arg: resume_arg.try_fold_with(folder)?,
drop,
},
Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
- let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest));
+ let dest = destination
+ .map(|(loc, dest)| (loc.try_fold_with(folder).map(|loc| (loc, dest))))
+ .transpose()?;
Call {
- func: func.fold_with(folder),
- args: args.fold_with(folder),
+ func: func.try_fold_with(folder)?,
+ args: args.try_fold_with(folder)?,
destination: dest,
cleanup,
from_hir_call,
Assert { cond, expected, msg, target, cleanup } => {
use AssertKind::*;
let msg = match msg {
- BoundsCheck { len, index } => {
- BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
+ BoundsCheck { len, index } => BoundsCheck {
+ len: len.try_fold_with(folder)?,
+ index: index.try_fold_with(folder)?,
+ },
+ Overflow(op, l, r) => {
+ Overflow(op, l.try_fold_with(folder)?, r.try_fold_with(folder)?)
}
- Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)),
- OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
- DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
- RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+ OverflowNeg(op) => OverflowNeg(op.try_fold_with(folder)?),
+ DivisionByZero(op) => DivisionByZero(op.try_fold_with(folder)?),
+ RemainderByZero(op) => RemainderByZero(op.try_fold_with(folder)?),
ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
};
- Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
+ Assert { cond: cond.try_fold_with(folder)?, expected, msg, target, cleanup }
}
GeneratorDrop => GeneratorDrop,
Resume => Resume,
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
template,
- operands: operands.fold_with(folder),
+ operands: operands.try_fold_with(folder)?,
options,
line_spans,
destination,
},
};
- Terminator { source_info: self.source_info, kind }
+ Ok(Terminator { source_info: self.source_info, kind })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Place {
+ local: self.local.try_fold_with(folder)?,
+ projection: self.projection.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::Rvalue::*;
- match self {
- Use(op) => Use(op.fold_with(folder)),
- Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
- ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
- Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)),
- AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)),
- Len(place) => Len(place.fold_with(folder)),
- Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
- BinaryOp(op, box (rhs, lhs)) => {
- BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ Ok(match self {
+ Use(op) => Use(op.try_fold_with(folder)?),
+ Repeat(op, len) => Repeat(op.try_fold_with(folder)?, len.try_fold_with(folder)?),
+ ThreadLocalRef(did) => ThreadLocalRef(did.try_fold_with(folder)?),
+ Ref(region, bk, place) => {
+ Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
}
- CheckedBinaryOp(op, box (rhs, lhs)) => {
- CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
+ Len(place) => Len(place.try_fold_with(folder)?),
+ Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
+ BinaryOp(op, box (rhs, lhs)) => {
+ BinaryOp(op, Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)))
}
- UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
- Discriminant(place) => Discriminant(place.fold_with(folder)),
- NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
+ CheckedBinaryOp(op, box (rhs, lhs)) => CheckedBinaryOp(
+ op,
+ Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)),
+ ),
+ UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?),
+ Discriminant(place) => Discriminant(place.try_fold_with(folder)?),
+ NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?),
Aggregate(kind, fields) => {
- let kind = kind.map_id(|kind| match kind {
- AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
- AggregateKind::Tuple => AggregateKind::Tuple,
- AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
- def,
- v,
- substs.fold_with(folder),
- user_ty.fold_with(folder),
- n,
- ),
- AggregateKind::Closure(id, substs) => {
- AggregateKind::Closure(id, substs.fold_with(folder))
- }
- AggregateKind::Generator(id, substs, movablity) => {
- AggregateKind::Generator(id, substs.fold_with(folder), movablity)
- }
- });
- Aggregate(kind, fields.fold_with(folder))
+ let kind = kind.try_map_id(|kind| {
+ Ok(match kind {
+ AggregateKind::Array(ty) => AggregateKind::Array(ty.try_fold_with(folder)?),
+ AggregateKind::Tuple => AggregateKind::Tuple,
+ AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+ def,
+ v,
+ substs.try_fold_with(folder)?,
+ user_ty.try_fold_with(folder)?,
+ n,
+ ),
+ AggregateKind::Closure(id, substs) => {
+ AggregateKind::Closure(id, substs.try_fold_with(folder)?)
+ }
+ AggregateKind::Generator(id, substs, movablity) => {
+ AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity)
+ }
+ })
+ })?;
+ Aggregate(kind, fields.try_fold_with(folder)?)
}
- ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
- }
+ ShallowInitBox(op, ty) => {
+ ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- Operand::Copy(place) => Operand::Copy(place.fold_with(folder)),
- Operand::Move(place) => Operand::Move(place.fold_with(folder)),
- Operand::Constant(c) => Operand::Constant(c.fold_with(folder)),
- }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(match self {
+ Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?),
+ Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?),
+ Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?),
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::ProjectionElem::*;
- match self {
+ Ok(match self {
Deref => Deref,
- Field(f, ty) => Field(f, ty.fold_with(folder)),
- Index(v) => Index(v.fold_with(folder)),
+ Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
+ Index(v) => Index(v.try_fold_with(folder)?),
Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
ConstantIndex { offset, min_length, from_end } => {
ConstantIndex { offset, min_length, from_end }
}
Subslice { from, to, from_end } => Subslice { from, to, from_end },
- }
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
}
impl<'tcx> TypeFoldable<'tcx> for Field {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Constant {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Constant {
span: self.span,
- user_ty: self.user_ty.fold_with(folder),
- literal: self.literal.fold_with(folder),
- }
+ user_ty: self.user_ty.try_fold_with(folder)?,
+ literal: self.literal.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.literal.visit_with(visitor)?;
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_mir_const(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_mir_const(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
match self {
- ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),
- ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)),
+ ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
+ ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
}
}
if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
}
+ PlaceElem::Field(field, ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
PlaceElem::Deref
- | PlaceElem::Field(..)
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
| PlaceElem::Downcast(..) => None,
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
- query get_lib_features(_: ()) -> LibFeatures {
+ query lib_features(_: ()) -> LibFeatures {
storage(ArenaCacheSelector<'tcx>)
- eval_always
desc { "calculating the lib features map" }
}
query defined_lib_features(_: CrateNum)
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
- eval_always
}
query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
desc { "normalizing `{:?}`", goal }
}
+ // FIXME: Implement `normalize_generic_arg_after_erasing_regions` and
+ // `normalize_mir_const_after_erasing_regions` in terms of
+ // `try_normalize_generic_arg_after_erasing_regions` and
+ // `try_normalize_mir_const_after_erasing_regions`, respectively.
+
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_generic_arg_after_erasing_regions(
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
desc { "normalizing `{}`", goal.value }
}
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_generic_arg_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+ ) -> Result<GenericArg<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_mir_const_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx>
) -> Result<
pub mod select;
pub mod specialization_graph;
mod structural_impls;
+pub mod util;
use crate::infer::canonical::Canonical;
use crate::thir::abstract_const::NotConstEvaluatable;
--- /dev/null
+use rustc_data_structures::stable_set::FxHashSet;
+
+use crate::ty::{PolyTraitRef, TyCtxt};
+
+/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+///
+/// A simplfied version of the same function at `rustc_infer::traits::util::supertraits`.
+pub fn supertraits<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
+ Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+}
+
+struct Elaborator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ visited: FxHashSet<PolyTraitRef<'tcx>>,
+ stack: Vec<PolyTraitRef<'tcx>>,
+}
+
+impl<'tcx> Elaborator<'tcx> {
+ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
+ let supertrait_refs = self
+ .tcx
+ .super_predicates_of(trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .flat_map(|(pred, _)| {
+ pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_ref()
+ })
+ .map(|t| t.value)
+ .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
+
+ self.stack.extend(supertrait_refs);
+ }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+ type Item = PolyTraitRef<'tcx>;
+
+ fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
+ if let Some(trait_ref) = self.stack.pop() {
+ self.elaborate(trait_ref);
+ Some(trait_ref)
+ } else {
+ None
+ }
+ }
+}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
/// Moreover, Rust only allows recursive data types through indirection.
///
/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
+///
+/// # Recursive types
+///
+/// It may seem impossible to represent recursive types using [`Ty`],
+/// since [`TyKind::Adt`] includes [`AdtDef`], which includes its fields,
+/// creating a cycle. However, `AdtDef` does not actually include the *types*
+/// of its fields; it includes just their [`DefId`]s.
+///
+/// [`TyKind::Adt`]: ty::TyKind::Adt
+///
+/// For example, the following type:
+///
+/// ```
+/// struct S { x: Box<S> }
+/// ```
+///
+/// is essentially represented with [`Ty`] as the following pseudocode:
+///
+/// ```
+/// struct S { x }
+/// ```
+///
+/// where `x` here represents the `DefId` of `S.x`. Then, the `DefId`
+/// can be used with [`TyCtxt::type_of()`] to get the type of the field.
pub struct AdtDef {
/// The `DefId` of the struct, enum or union item.
pub did: DefId,
/// Whether the ADT lacks fields. Note that this includes uninhabited enums,
/// e.g., `enum Void {}` is considered payload free as well.
pub fn is_payloadfree(&self) -> bool {
+ // Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621).
+ // This would disallow the following kind of enum from being casted into integer.
+ // ```
+ // enum Enum {
+ // Foo() = 1,
+ // Bar{} = 2,
+ // Baz = 3,
+ // }
+ // ```
+ if self
+ .variants
+ .iter()
+ .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
+ {
+ return false;
+ }
self.variants.iter().all(|v| v.fields.is_empty())
}
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
-use crate::middle;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
};
debug!("layout_scalar_valid_range: attr={:?}", attr);
if let Some(
- &[ast::NestedMetaItem::Literal(ast::Lit { kind: ast::LitKind::Int(a, _), .. })],
+ &[
+ ast::NestedMetaItem::Literal(ast::Lit {
+ kind: ast::LitKind::Int(a, _), ..
+ }),
+ ],
) = attr.meta_item_list().as_deref()
{
Bound::Included(a)
self.sess.consider_optimizing(&cname, msg)
}
- pub fn lib_features(self) -> &'tcx middle::lib_features::LibFeatures {
- self.get_lib_features(())
- }
-
/// Obtain all lang items of this crate and all dependencies (recursively)
pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
self.get_lang_items(())
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
- let hir = self.hir();
- let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
- match &hir.expect_item(opaque_hir_id).kind {
+ match &self.hir().expect_item(opaque_local_def_id).kind {
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
_ => bug!("The HirId comes from a `ty::Opaque`"),
}
///
/// To implement this conveniently, use the derive macro located in `rustc_macros`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.super_fold_with(folder)
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
+ /// provided default definition delegates. Implementors **should not** override
+ /// this provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_super_fold_with` instead).
+ fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_super_fold_with(folder).into_ok()
+ }
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
+ /// default definition delegates. Implementors **should not** override this
+ /// provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_fold_with` instead).
+ fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_fold_with(folder).into_ok()
+ }
+
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error>;
+
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_super_fold_with(folder)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
}
impl TypeFoldable<'tcx> for hir::Constness {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
/// default implementation that does an "identity" fold. Within each
/// identity fold, it should invoke `foo.fold_with(self)` to fold each
/// sub-item.
+///
+/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
+/// associated type is something other than the default, never),
+/// [`FallibleTypeFolder`] should be implemented manually; otherwise,
+/// a blanket implementation of [`FallibleTypeFolder`] will defer to
+/// the infallible methods of this trait to ensure that the two APIs
+/// are coherent.
pub trait TypeFolder<'tcx>: Sized {
+ type Error = !;
+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
where
T: TypeFoldable<'tcx>,
+ Self: TypeFolder<'tcx, Error = !>,
{
t.super_fold_with(self)
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
r.super_fold_with(self)
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
c.super_fold_with(self)
}
- fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
p.super_fold_with(self)
}
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
}
+/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
+/// method defined for every foldable type. Each of these has a
+/// default implementation that does an "identity" fold. Within each
+/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
+/// sub-item.
+///
+/// A blanket implementation of this trait (that defers to the relevant
+/// method of [`TypeFolder`]) is provided for all infallible folders in
+/// order to ensure the two APIs are coherent.
+pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ r.try_super_fold_with(self)
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ c.try_super_fold_with(self)
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ p.try_super_fold_with(self)
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ bug!("most type folders should not be folding MIR datastructures: {:?}", c)
+ }
+}
+
+// Blanket implementation of fallible trait for infallible folders
+// delegates to infallible methods to prevent incoherence
+impl<'tcx, F> FallibleTypeFolder<'tcx> for F
+where
+ F: TypeFolder<'tcx, Error = !>,
+{
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ Ok(self.fold_binder(t))
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ Ok(self.fold_ty(t))
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok(self.fold_region(r))
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(self.fold_const(c))
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ Ok(self.fold_predicate(p))
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ Ok(self.fold_mir_const(c))
+ }
+}
+
pub trait TypeVisitor<'tcx>: Sized {
type BreakTy = !;
/// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
+use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::subst::Subst;
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
+ NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
}
impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{}` are too big for the current architecture", ty)
}
+ LayoutError::NormalizationFailure(t, e) => write!(
+ f,
+ "unable to determine layout for `{}` because `{}` cannot be normalized",
+ t,
+ e.get_type_for_failure()
+ ),
}
}
}
+#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts();
+ debug!(?ty);
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
ty::tls::enter_context(&icx, |_| {
let param_env = param_env.with_reveal_all_normalized(tcx);
let unnormalized_ty = ty;
- let ty = tcx.normalize_erasing_regions(param_env, ty);
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
if ty != unnormalized_ty {
// Ensure this layout is also cached for the normalized type.
return tcx.layout_of(param_env.and(ty));
}
}
- if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
+ if fields.iter().any(|f| f.abi.is_uninhabited()) {
abi = Abi::Uninhabited;
}
//!
//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
-pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
pub use self::IntVarValue::*;
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
- fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
+ fn try_super_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ParamEnv::new(
+ self.caller_bounds().try_fold_with(folder)?,
+ self.reveal().try_fold_with(folder)?,
+ ))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
impl<'tcx> FieldDef {
/// Returns the type of this field. The resulting type is not normalized. The `subst` is
- /// typically obtained via the second field of `TyKind::AdtDef`.
+ /// typically obtained via the second field of [`TyKind::Adt`].
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).subst(tcx, subst)
}
//! or constant found within. (This underlying query is what is cached.)
use crate::mir;
-use crate::ty::fold::{TypeFoldable, TypeFolder};
+use crate::traits::query::NoSolution;
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
+#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
+pub enum NormalizationError<'tcx> {
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+ ConstantKind(mir::ConstantKind<'tcx>),
+}
+
+impl<'tcx> NormalizationError<'tcx> {
+ pub fn get_type_for_failure(&self) -> String {
+ match self {
+ NormalizationError::Type(t) => format!("{}", t),
+ NormalizationError::Const(c) => format!("{}", c),
+ NormalizationError::ConstantKind(ck) => format!("{}", ck),
+ }
+ }
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
// Erase first before we do the real query -- this keeps the
// cache from being too polluted.
let value = self.erase_regions(value);
+ debug!(?value);
+
if !value.has_projections() {
value
} else {
}
}
+ /// Tries to erase the regions in `value` and then fully normalize all the
+ /// types found within. The result will also have regions erased.
+ ///
+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
+ /// succeeds.
+ pub fn try_normalize_erasing_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+ std::any::type_name::<T>(),
+ value,
+ param_env,
+ );
+
+ // Erase first before we do the real query -- this keeps the
+ // cache from being too polluted.
+ let value = self.erase_regions(value);
+ debug!(?value);
+
+ if !value.has_projections() {
+ Ok(value)
+ } else {
+ let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+ value.try_fold_with(&mut folder)
+ }
+ }
+
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
/// late-bound regions and then normalize the result, yielding up
/// a `T` (with regions erased). This is appropriate when the
}
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
+ #[instrument(skip(self), level = "debug")]
fn normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let arg = self.param_env.and(arg);
+ debug!(?arg);
+
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
}
}
self.tcx.normalize_mir_const_after_erasing_regions(arg)
}
}
+
+struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn try_normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+ }
+}
+
+impl TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ type Error = NormalizationError<'tcx>;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
+ Ok(t) => Ok(t.expect_ty()),
+ Err(_) => Err(NormalizationError::Type(ty)),
+ }
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(*c)),
+ }
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
+ }
+}
}
return Ok(self);
}
- // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
- // by looking up the projections associated with the def_id.
- let bounds = self.tcx().explicit_item_bounds(def_id);
-
- let mut first = true;
- let mut is_sized = false;
- let mut is_future = false;
- let mut future_output_ty = None;
-
- p!("impl");
- for (predicate, _) in bounds {
- let predicate = predicate.subst(self.tcx(), substs);
- let bound_predicate = predicate.kind();
-
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(projection_predicate) => {
- let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue };
- let future_output_def_id =
- self.tcx().associated_item_def_ids(future_trait)[0];
-
- if projection_predicate.projection_ty.item_def_id
- == future_output_def_id
- {
- // We don't account for multiple `Future::Output = Ty` contraints.
- is_future = true;
- future_output_ty = Some(projection_predicate.ty);
- }
- }
- ty::PredicateKind::Trait(pred) => {
- let trait_ref = bound_predicate.rebind(pred.trait_ref);
- // Don't print +Sized, but rather +?Sized if absent.
- if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait()
- {
- is_sized = true;
- continue;
- }
-
- if Some(trait_ref.def_id())
- == self.tcx().lang_items().future_trait()
- {
- is_future = true;
- continue;
- }
-
- p!(
- write("{}", if first { " " } else { " + " }),
- print(trait_ref.print_only_trait_path())
- );
-
- first = false;
- }
- _ => {}
- }
- }
-
- if is_future {
- p!(write("{}Future", if first { " " } else { " + " }));
- first = false;
- if let Some(future_output_ty) = future_output_ty {
- // Don't print projection types, which we (unfortunately) see often
- // in the error outputs involving async blocks.
- if !matches!(future_output_ty.kind(), ty::Projection(_)) {
- p!("<Output = ", print(future_output_ty), ">");
- }
- }
- }
-
- if !is_sized {
- p!(write("{}?Sized", if first { " " } else { " + " }));
- } else if first {
- p!(" Sized");
- }
-
- Ok(self)
+ self.pretty_print_opaque_impl_type(def_id, substs)
});
}
ty::Str => p!("str"),
Ok(self)
}
+ fn pretty_print_opaque_impl_type(
+ mut self,
+ def_id: DefId,
+ substs: &'tcx ty::List<ty::GenericArg<'tcx>>,
+ ) -> Result<Self::Type, Self::Error> {
+ define_scoped_cx!(self);
+
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let bounds = self.tcx().explicit_item_bounds(def_id);
+
+ let mut traits = BTreeMap::new();
+ let mut fn_traits = BTreeMap::new();
+ let mut is_sized = false;
+
+ for (predicate, _) in bounds {
+ let predicate = predicate.subst(self.tcx(), substs);
+ let bound_predicate = predicate.kind();
+
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ let trait_ref = bound_predicate.rebind(pred.trait_ref);
+
+ // Don't print + Sized, but rather + ?Sized if absent.
+ if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
+ is_sized = true;
+ continue;
+ }
+
+ self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
+ }
+ ty::PredicateKind::Projection(pred) => {
+ let proj_ref = bound_predicate.rebind(pred);
+ let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
+
+ // Projection type entry -- the def-id for naming, and the ty.
+ let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+
+ self.insert_trait_and_projection(
+ trait_ref,
+ Some(proj_ty),
+ &mut traits,
+ &mut fn_traits,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ let mut first = true;
+ // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
+ let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
+
+ p!("impl");
+
+ for (fn_once_trait_ref, entry) in fn_traits {
+ // Get the (single) generic ty (the args) of this FnOnce trait ref.
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(fn_once_trait_ref.def_id()),
+ fn_once_trait_ref.skip_binder().substs,
+ );
+
+ match (entry.return_ty, generics[0].expect_ty()) {
+ // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
+ // a return type.
+ (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
+ let name = if entry.fn_trait_ref.is_some() {
+ "Fn"
+ } else if entry.fn_mut_trait_ref.is_some() {
+ "FnMut"
+ } else {
+ "FnOnce"
+ };
+
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ write("{}{}(", if paren_needed { "(" } else { "" }, name)
+ );
+
+ for (idx, ty) in arg_tys.tuple_fields().enumerate() {
+ if idx > 0 {
+ p!(", ");
+ }
+ p!(print(ty));
+ }
+
+ p!(")");
+ if !return_ty.skip_binder().is_unit() {
+ p!("-> ", print(return_ty));
+ }
+ p!(write("{}", if paren_needed { ")" } else { "" }));
+
+ first = false;
+ }
+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
+ _ => {
+ if entry.has_fn_once {
+ traits.entry(fn_once_trait_ref).or_default().extend(
+ // Group the return ty with its def id, if we had one.
+ entry
+ .return_ty
+ .map(|ty| (self.tcx().lang_items().fn_once_output().unwrap(), ty)),
+ );
+ }
+ if let Some(trait_ref) = entry.fn_mut_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ if let Some(trait_ref) = entry.fn_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ }
+ }
+ }
+
+ // Print the rest of the trait types (that aren't Fn* family of traits)
+ for (trait_ref, assoc_items) in traits {
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ print(trait_ref.skip_binder().print_only_trait_name())
+ );
+
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(trait_ref.def_id()),
+ trait_ref.skip_binder().substs,
+ );
+
+ if !generics.is_empty() || !assoc_items.is_empty() {
+ p!("<");
+ let mut first = true;
+
+ for ty in generics {
+ if !first {
+ p!(", ");
+ }
+ p!(print(trait_ref.rebind(*ty)));
+ first = false;
+ }
+
+ for (assoc_item_def_id, ty) in assoc_items {
+ if !first {
+ p!(", ");
+ }
+ p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
+
+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+ match ty.skip_binder().kind() {
+ ty::Projection(ty::ProjectionTy { item_def_id, .. })
+ if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
+ {
+ p!("[async output]")
+ }
+ _ => {
+ p!(print(ty))
+ }
+ }
+
+ first = false;
+ }
+
+ p!(">");
+ }
+
+ first = false;
+ }
+
+ if !is_sized {
+ p!(write("{}?Sized", if first { " " } else { " + " }));
+ } else if first {
+ p!(" Sized");
+ }
+
+ Ok(self)
+ }
+
+ /// Insert the trait ref and optionally a projection type associated with it into either the
+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
+ fn insert_trait_and_projection(
+ &mut self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
+ traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+ fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+ ) {
+ let trait_def_id = trait_ref.def_id();
+
+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
+ // super-trait ref and record it there.
+ if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
+ // If we have a FnOnce, then insert it into
+ if trait_def_id == fn_once_trait {
+ let entry = fn_traits.entry(trait_ref).or_default();
+ // Optionally insert the return_ty as well.
+ if let Some((_, ty)) = proj_ty {
+ entry.return_ty = Some(ty);
+ }
+ entry.has_fn_once = true;
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
+ return;
+ }
+ }
+
+ // Otherwise, just group our traits and projection types.
+ traits.entry(trait_ref).or_default().extend(proj_ty);
+ }
+
fn pretty_print_bound_var(
&mut self,
debruijn: ty::DebruijnIndex,
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { trimmed_def_paths, ..*providers };
}
+
+#[derive(Default)]
+pub struct OpaqueFnEntry<'tcx> {
+ // The trait ref is already stored as a key, so just track if we have it as a real predicate
+ has_fn_once: bool,
+ fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+}
use crate::mir::interpret;
use crate::mir::ProjectionKind;
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
/// AdtDefs are basically the same as a DefId.
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
- (self.0.fold_with(folder), self.1.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(T, U), F::Error> {
+ Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
for (A, B, C)
{
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) {
- (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(A, B, C), F::Error> {
+ Ok((
+ self.0.try_fold_with(folder)?,
+ self.1.try_fold_with(folder)?,
+ self.2.try_fold_with(folder)?,
+ ))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// FIXME: Reuse the `Rc` here.
- Rc::new((*self).clone().fold_with(folder))
+ (*self).clone().try_fold_with(folder).map(Rc::new)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// FIXME: Reuse the `Arc` here.
- Arc::new((*self).clone().fold_with(folder))
+ (*self).clone().try_fold_with(folder).map(Arc::new)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|value| value.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_bound(|ty| ty.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_bound(|ty| ty.try_fold_with(folder))
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_binder(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_binder(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::ty::InstanceDef::*;
- Self {
- substs: self.substs.fold_with(folder),
+ Ok(Self {
+ substs: self.substs.try_fold_with(folder)?,
def: match self.def {
- Item(def) => Item(def.fold_with(folder)),
- VtableShim(did) => VtableShim(did.fold_with(folder)),
- ReifyShim(did) => ReifyShim(did.fold_with(folder)),
- Intrinsic(did) => Intrinsic(did.fold_with(folder)),
- FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)),
- Virtual(did, i) => Virtual(did.fold_with(folder), i),
+ Item(def) => Item(def.try_fold_with(folder)?),
+ VtableShim(did) => VtableShim(did.try_fold_with(folder)?),
+ ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?),
+ Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?),
+ FnPtrShim(did, ty) => {
+ FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i),
ClosureOnceShim { call_once, track_caller } => {
- ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller }
+ ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller }
+ }
+ DropGlue(did, ty) => {
+ DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ CloneShim(did, ty) => {
+ CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
}
- DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
- CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
},
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
let kind = match *self.kind() {
- ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
- ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
- ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
- ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
+ ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?),
+ ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
+ ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
+ ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?),
ty::Dynamic(trait_ty, region) => {
- ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
+ ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
+ }
+ ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
+ ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?),
+ ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?),
+ ty::Ref(r, ty, mutbl) => {
+ ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
}
- ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
- ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)),
- ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
- ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
ty::Generator(did, substs, movability) => {
- ty::Generator(did, substs.fold_with(folder), movability)
+ ty::Generator(did, substs.try_fold_with(folder)?, movability)
}
- ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
- ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
- ty::Projection(data) => ty::Projection(data.fold_with(folder)),
- ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
+ ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
+ ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?),
+ ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?),
+ ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?),
ty::Bool
| ty::Char
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Never
- | ty::Foreign(..) => return self,
+ | ty::Foreign(..) => return Ok(self),
};
- if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }
+ Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_ty(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_ty(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_region(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_region(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_predicate(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_predicate(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let new = self.inner.kind.fold_with(folder);
- folder.tcx().reuse_or_mk_predicate(self, new)
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let new = self.inner.kind.try_fold_with(folder)?;
+ Ok(folder.tcx().reuse_or_mk_predicate(self, new))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
}
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|x| x.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|x| x.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let ty = self.ty.fold_with(folder);
- let val = self.val.fold_with(folder);
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let ty = self.ty.try_fold_with(folder)?;
+ let val = self.val.try_fold_with(folder)?;
if ty != self.ty || val != self.val {
- folder.tcx().mk_const(ty::Const { ty, val })
+ Ok(folder.tcx().mk_const(ty::Const { ty, val }))
} else {
- self
+ Ok(self)
}
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_const(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_const(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
- ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
- ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(match self {
+ ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
+ ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
+ ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Error(_) => self,
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> {
match self.substs[..] {
- [ref parent_substs @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
- ClosureSubstsParts {
- parent_substs,
- closure_kind_ty,
- closure_sig_as_fn_ptr_ty,
- tupled_upvars_ty,
- }
- }
+ [
+ ref parent_substs @ ..,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ ] => ClosureSubstsParts {
+ parent_substs,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ },
_ => bug!("closure substs missing synthetics"),
}
}
///
/// Trait references also appear in object types like `Foo<U>`, but in
/// that case the `Self` parameter is absent from the substitutions.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct TraitRef<'tcx> {
pub def_id: DefId,
Binder(value, self.1)
}
+ pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Ok(Binder(value, self.1))
+ }
+
/// Wraps a `value` in a binder, using the same bound variables as the
/// current `Binder`. This should not be used if the new value *changes*
/// the bound variables. Note: the (old or new) value itself does not
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
}
impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
match self.unpack() {
- GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
- GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
- GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
+ GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// The match arms are in order of frequency. The 1, 2, and 0 cases are
// calling `intern_substs`.
match self.len() {
1 => {
- let param0 = self[0].fold_with(folder);
- if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) }
+ let param0 = self[0].try_fold_with(folder)?;
+ if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
}
2 => {
- let param0 = self[0].fold_with(folder);
- let param1 = self[1].fold_with(folder);
+ let param0 = self[0].try_fold_with(folder)?;
+ let param1 = self[1].try_fold_with(folder)?;
if param0 == self[0] && param1 == self[1] {
- self
+ Ok(self)
} else {
- folder.tcx().intern_substs(&[param0, param1])
+ Ok(folder.tcx().intern_substs(&[param0, param1]))
}
}
- 0 => self,
+ 0 => Ok(self),
_ => {
- let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
- if params[..] == self[..] { self } else { folder.tcx().intern_substs(¶ms) }
+ let params: SmallVec<[_; 8]> =
+ self.iter().map(|k| k.try_fold_with(folder)).collect::<Result<_, _>>()?;
+ if params[..] == self[..] {
+ Ok(self)
+ } else {
+ Ok(folder.tcx().intern_substs(¶ms))
+ }
}
}
}
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::ty::fold::TypeFolder;
+use crate::ty::fold::{FallibleTypeFolder, TypeFolder};
use crate::ty::layout::IntegerExt;
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
[component_ty] => component_ty,
_ => self,
};
+
// This doesn't depend on regions, so try to minimize distinct
// query keys used.
- let erased = tcx.normalize_erasing_regions(param_env, query_ty);
- tcx.needs_drop_raw(param_env.and(erased))
+ // If normalization fails, we just use `query_ty`.
+ let query_ty =
+ tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
+
+ tcx.needs_drop_raw(param_env.and(query_ty))
}
}
}
list: &'tcx ty::List<T>,
folder: &mut F,
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
-) -> &'tcx ty::List<T>
+) -> Result<&'tcx ty::List<T>, F::Error>
where
- F: TypeFolder<'tcx>,
+ F: FallibleTypeFolder<'tcx>,
T: TypeFoldable<'tcx> + PartialEq + Copy,
{
let mut iter = list.iter();
// Look for the first element that changed
- if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
- let new_t = t.fold_with(folder);
- if new_t == t { None } else { Some((i, new_t)) }
+ match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) {
+ Ok(new_t) if new_t == t => None,
+ new_t => Some((i, new_t)),
}) {
- // An element changed, prepare to intern the resulting list
- let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
- new_list.extend_from_slice(&list[..i]);
- new_list.push(new_t);
- new_list.extend(iter.map(|t| t.fold_with(folder)));
- intern(folder.tcx(), &new_list)
- } else {
- list
+ Some((i, Ok(new_t))) => {
+ // An element changed, prepare to intern the resulting list
+ let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
+ new_list.extend_from_slice(&list[..i]);
+ new_list.push(new_t);
+ for t in iter {
+ new_list.push(t.try_fold_with(folder)?)
+ }
+ Ok(intern(folder.tcx(), &new_list))
+ }
+ Some((_, Err(err))) => {
+ return Err(err);
+ }
+ None => Ok(list),
}
}
use rustc_data_structures::captures::Captures;
use rustc_arena::TypedArena;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty, TyCtxt};
// We try each or-pattern branch in turn.
let mut matrix = matrix.clone();
for v in v.expand_or_pat() {
- let usefulness =
- is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
ret.extend(usefulness);
// If pattern has a guard don't add it to the matrix.
if !is_under_guard {
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
let v = v.pop_head_constructor(cx, &ctor);
- let usefulness =
- is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
// When all the conditions are met we have a match with a `non_exhaustive` enum
}
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Index(local) => {
- if let Some(replacement) = self.replacements.for_src(local) {
- bug!(
- "cannot replace {:?} with {:?} in index projection {:?}",
- local,
- replacement,
- elem,
- );
- } else {
- None
- }
- }
- _ => None,
- }
- }
-
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
if let Some(replacement) = self.replacements.for_src(place.local) {
// Rebase `place`s projections onto `replacement`'s.
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
+mod remove_false_edges;
mod remove_noop_landing_pads;
mod remove_storage_markers;
+mod remove_uninit_drops;
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
mod uninhabited_enum_branching;
mod unreachable_prop;
-use rustc_const_eval::transform::check_consts;
+use rustc_const_eval::transform::check_consts::{self, ConstCx};
use rustc_const_eval::transform::promote_consts;
use rustc_const_eval::transform::validate;
-pub use rustc_const_eval::transform::MirPass;
use rustc_mir_dataflow::rustc_peek;
pub fn provide(providers: &mut Providers) {
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
+ // IMPORTANT
+ remove_false_edges::RemoveFalseEdges.run_pass(tcx, &mut body);
+
+ // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
+ //
+ // FIXME: Can't use `run_passes` for these, since `run_passes` SILENTLY DOES NOTHING IF THE MIR
+ // PHASE DOESN'T CHANGE.
+ if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
+ simplify::SimplifyCfg::new("remove-false-edges").run_pass(tcx, &mut body);
+ remove_uninit_drops::RemoveUninitDrops.run_pass(tcx, &mut body);
+ check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
+ }
+
run_post_borrowck_cleanup_passes(tcx, &mut body);
- check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
tcx.alloc_steal_mir(body)
}
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
- &simplify_branches::SimplifyBranches::new("initial"),
+ &simplify_branches::SimplifyConstCondition::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements,
&simplify::SimplifyCfg::new("early-opt"),
&instcombine::InstCombine,
&separate_const_switch::SeparateConstSwitch,
&const_prop::ConstProp,
- &simplify_branches::SimplifyBranches::new("after-const-prop"),
+ &simplify_branches::SimplifyConstCondition::new("after-const-prop"),
&early_otherwise_branch::EarlyOtherwiseBranch,
&simplify_comparison_integral::SimplifyComparisonIntegral,
&simplify_try::SimplifyArmIdentity,
&simplify_try::SimplifyBranchSame,
&dest_prop::DestinationPropagation,
- &simplify_branches::SimplifyBranches::new("final"),
+ &simplify_branches::SimplifyConstCondition::new("final"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("final"),
&nrvo::RenameReturnPlace,
--- /dev/null
+use rustc_middle::mir::{Body, TerminatorKind};
+use rustc_middle::ty::TyCtxt;
+
+use crate::MirPass;
+
+/// Removes `FalseEdge` and `FalseUnwind` terminators from the MIR.
+///
+/// These are only needed for borrow checking, and can be removed afterwards.
+///
+/// FIXME: This should probably have its own MIR phase.
+pub struct RemoveFalseEdges;
+
+impl<'tcx> MirPass<'tcx> for RemoveFalseEdges {
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ for block in body.basic_blocks_mut() {
+ let terminator = block.terminator_mut();
+ terminator.kind = match terminator.kind {
+ TerminatorKind::FalseEdge { real_target, .. } => {
+ TerminatorKind::Goto { target: real_target }
+ }
+ TerminatorKind::FalseUnwind { real_target, .. } => {
+ TerminatorKind::Goto { target: real_target }
+ }
+
+ _ => continue,
+ }
+ }
+ }
+}
--- /dev/null
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::{Body, Field, Rvalue, Statement, StatementKind, TerminatorKind};
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
+use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataParamEnv};
+
+use crate::MirPass;
+
+/// Removes `Drop` and `DropAndReplace` terminators whose target is known to be uninitialized at
+/// that point.
+///
+/// This is redundant with drop elaboration, but we need to do it prior to const-checking, and
+/// running const-checking after drop elaboration makes it opimization dependent, causing issues
+/// like [#90770].
+///
+/// [#90770]: https://github.com/rust-lang/rust/issues/90770
+pub struct RemoveUninitDrops;
+
+impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let param_env = tcx.param_env(body.source.def_id());
+ let Ok(move_data) = MoveData::gather_moves(body, tcx, param_env) else {
+ // We could continue if there are move errors, but there's not much point since our
+ // init data isn't complete.
+ return;
+ };
+
+ let mdpe = MoveDataParamEnv { move_data, param_env };
+ let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+ .into_engine(tcx, body)
+ .pass_name("remove_uninit_drops")
+ .iterate_to_fixpoint()
+ .into_results_cursor(body);
+
+ let mut to_remove = vec![];
+ for (bb, block) in body.basic_blocks().iter_enumerated() {
+ let terminator = block.terminator();
+ let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
+ = &terminator.kind
+ else { continue };
+
+ maybe_inits.seek_before_primary_effect(body.terminator_loc(bb));
+
+ // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone.
+ let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else {
+ continue;
+ };
+
+ let should_keep = is_needs_drop_and_init(
+ tcx,
+ param_env,
+ maybe_inits.get(),
+ &mdpe.move_data,
+ place.ty(body, tcx).ty,
+ mpi,
+ );
+ if !should_keep {
+ to_remove.push(bb)
+ }
+ }
+
+ for bb in to_remove {
+ let block = &mut body.basic_blocks_mut()[bb];
+
+ let (TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. })
+ = &block.terminator().kind
+ else { unreachable!() };
+
+ // Replace block terminator with `Goto`.
+ let target = *target;
+ let old_terminator_kind = std::mem::replace(
+ &mut block.terminator_mut().kind,
+ TerminatorKind::Goto { target },
+ );
+
+ // If this is a `DropAndReplace`, we need to emulate the assignment to the return place.
+ if let TerminatorKind::DropAndReplace { place, value, .. } = old_terminator_kind {
+ block.statements.push(Statement {
+ source_info: block.terminator().source_info,
+ kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value)))),
+ });
+ }
+ }
+ }
+}
+
+fn is_needs_drop_and_init(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ maybe_inits: &BitSet<MovePathIndex>,
+ move_data: &MoveData<'tcx>,
+ ty: Ty<'tcx>,
+ mpi: MovePathIndex,
+) -> bool {
+ // No need to look deeper if the root is definitely uninit or if it has no `Drop` impl.
+ if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, param_env) {
+ return false;
+ }
+
+ let field_needs_drop_and_init = |(f, f_ty, mpi)| {
+ let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f));
+ let Some(mpi) = child else {
+ return f_ty.needs_drop(tcx, param_env);
+ };
+
+ is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)
+ };
+
+ // This pass is only needed for const-checking, so it doesn't handle as many cases as
+ // `DropCtxt::open_drop`, since they aren't relevant in a const-context.
+ match ty.kind() {
+ ty::Adt(adt, substs) => {
+ let dont_elaborate = adt.is_union() || adt.is_manually_drop() || adt.has_dtor(tcx);
+ if dont_elaborate {
+ return true;
+ }
+
+ // Look at all our fields, or if we are an enum all our variants and their fields.
+ //
+ // If a field's projection *is not* present in `MoveData`, it has the same
+ // initializedness as its parent (maybe init).
+ //
+ // If its projection *is* present in `MoveData`, then the field may have been moved
+ // from separate from its parent. Recurse.
+ adt.variants.iter_enumerated().any(|(vid, variant)| {
+ // Enums have multiple variants, which are discriminated with a `Downcast` projection.
+ // Structs have a single variant, and don't use a `Downcast` projection.
+ let mpi = if adt.is_enum() {
+ let downcast =
+ move_path_children_matching(move_data, mpi, |x| x.is_downcast_to(vid));
+ let Some(dc_mpi) = downcast else {
+ return variant_needs_drop(tcx, param_env, substs, variant);
+ };
+
+ dc_mpi
+ } else {
+ mpi
+ };
+
+ variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(f, field)| (Field::from_usize(f), field.ty(tcx, substs), mpi))
+ .any(field_needs_drop_and_init)
+ })
+ }
+
+ ty::Tuple(_) => ty
+ .tuple_fields()
+ .enumerate()
+ .map(|(f, f_ty)| (Field::from_usize(f), f_ty, mpi))
+ .any(field_needs_drop_and_init),
+
+ _ => true,
+ }
+}
+
+fn variant_needs_drop(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ substs: SubstsRef<'tcx>,
+ variant: &VariantDef,
+) -> bool {
+ variant.fields.iter().any(|field| {
+ let f_ty = field.ty(tcx, substs);
+ f_ty.needs_drop(tcx, param_env)
+ })
+}
-//! This pass replaces a drop of a type that does not need dropping, with a goto
+//! This pass replaces a drop of a type that does not need dropping, with a goto.
+//!
+//! When the MIR is built, we check `needs_drop` before emitting a `Drop` for a place. This pass is
+//! useful because (unlike MIR building) it runs after type checking, so it can make use of
+//! `Reveal::All` to provide more precies type information.
use crate::MirPass;
use rustc_middle::mir::*;
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
*ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
}
-
- #[inline]
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Field(field, ty) => {
- let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
- }
- // None of those contain a Ty.
- PlaceElem::Index(..)
- | PlaceElem::Deref
- | PlaceElem::ConstantIndex { .. }
- | PlaceElem::Subslice { .. }
- | PlaceElem::Downcast(..) => None,
- }
- }
}
-//! A pass that simplifies branches when their condition is known.
-
use crate::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use std::borrow::Cow;
-pub struct SimplifyBranches {
+/// A pass that replaces a branch with a goto when its condition is known.
+pub struct SimplifyConstCondition {
label: String,
}
-impl SimplifyBranches {
+impl SimplifyConstCondition {
pub fn new(label: &str) -> Self {
- SimplifyBranches { label: format!("SimplifyBranches-{}", label) }
+ SimplifyConstCondition { label: format!("SimplifyConstCondition-{}", label) }
}
}
-impl<'tcx> MirPass<'tcx> for SimplifyBranches {
+impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
fn name(&self) -> Cow<'_, str> {
Cow::Borrowed(&self.label)
}
Some(v) if v == expected => TerminatorKind::Goto { target },
_ => continue,
},
- TerminatorKind::FalseEdge { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
- TerminatorKind::FalseUnwind { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
_ => continue,
};
}
+use crate::lexer::unicode_chars::UNICODE_ARRAY;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream};
}
token::Ident(sym, is_raw_ident)
}
+ rustc_lexer::TokenKind::InvalidIdent
+ // Do not recover an identifier with emoji if the codepoint is a confusable
+ // with a recoverable substitution token, like `➖`.
+ if UNICODE_ARRAY
+ .iter()
+ .find(|&&(c, _, _)| {
+ let sym = self.str_from(start);
+ sym.chars().count() == 1 && c == sym.chars().next().unwrap()
+ })
+ .is_none() =>
+ {
+ let sym = nfc_normalize(self.str_from(start));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span);
+ token::Ident(sym, false)
+ }
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start as u32);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
- rustc_lexer::TokenKind::Unknown => {
+ rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap();
let mut err =
self.struct_fatal_span_char(start, self.pos, "unknown start of token", c);
use rustc_span::{symbol::kw, BytePos, Pos, Span};
#[rustfmt::skip] // for line breaks
-const UNICODE_ARRAY: &[(char, &str, char)] = &[
+pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[
('
', "Line Separator", ' '),
('
', "Paragraph Separator", ' '),
(' ', "Ogham Space mark", ' '),
parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
}
+pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream {
+ let source = pprust::crate_to_string_for_macros(krate);
+ let filename = FileName::macro_expansion_source_code(&source);
+ parse_stream_from_source_str(filename, source, sess, Some(krate.span))
+}
+
pub fn parse_cfg_attr(
attr: &Attribute,
parse_sess: &ParseSess,
+use super::pat::Expected;
use super::ty::AllowPlus;
-use super::TokenType;
-use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
+use super::{
+ BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
+ TokenExpectType, TokenType,
+};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
-use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
-use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
+use rustc_ast::{
+ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
+ BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
+ PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
use rustc_span::symbol::{kw, Ident};
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
+use std::mem::take;
+
use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
let snapshot = self.clone();
self.bump();
let lo = self.token.span;
- match self.parse_angle_args() {
+ match self.parse_angle_args(None) {
Ok(args) => {
let span = lo.to(self.prev_token.span);
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
let x = self.parse_seq_to_before_end(
&token::Gt,
SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_generic_arg(),
+ |p| p.parse_generic_arg(None),
);
match x {
Ok((_, _, false)) => {
self.expect(&token::ModSep)?;
let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None };
- self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
+ self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
path.span = ty_span.to(self.prev_token.span);
let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
Ok(expr)
}
+ fn recover_const_param_decl(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ let snapshot = self.clone();
+ let param = match self.parse_const_param(vec![]) {
+ Ok(param) => param,
+ Err(mut err) => {
+ err.cancel();
+ *self = snapshot;
+ return Err(err);
+ }
+ };
+ let mut err =
+ self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
+ err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
+ if let (Some(generics), Ok(snippet)) =
+ (ty_generics, self.sess.source_map().span_to_snippet(param.span()))
+ {
+ let (span, sugg) = match &generics.params[..] {
+ [] => (generics.span, format!("<{}>", snippet)),
+ [.., generic] => (generic.span().shrink_to_hi(), format!(", {}", snippet)),
+ };
+ err.multipart_suggestion(
+ "`const` parameters must be declared for the `impl`",
+ vec![(span, sugg), (param.span(), param.ident.to_string())],
+ Applicability::MachineApplicable,
+ );
+ }
+ let value = self.mk_expr_err(param.span());
+ err.emit();
+ return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })));
+ }
+
+ pub fn recover_const_param_declaration(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ // We have to check for a few different cases.
+ if let Ok(arg) = self.recover_const_param_decl(ty_generics) {
+ return Ok(arg);
+ }
+
+ // We haven't consumed `const` yet.
+ let start = self.token.span;
+ self.bump(); // `const`
+
+ // Detect and recover from the old, pre-RFC2000 syntax for const generics.
+ let mut err = self
+ .struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
+ if self.check_const_arg() {
+ err.span_suggestion_verbose(
+ start.until(self.token.span),
+ "the `const` keyword is only needed in the definition of the type",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
+ } else {
+ let after_kw_const = self.token.span;
+ self.recover_const_arg(after_kw_const, err).map(Some)
+ }
+ }
+
/// Try to recover from possible generic const argument without `{` and `}`.
///
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
);
err
}
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_colon_colon_in_pat_typo(
+ &mut self,
+ mut first_pat: P<Pat>,
+ ra: RecoverColon,
+ expected: Expected,
+ ) -> P<Pat> {
+ if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+ return first_pat;
+ }
+ if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
+ || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ return first_pat;
+ }
+ // The pattern looks like it might be a path with a `::` -> `:` typo:
+ // `match foo { bar:baz => {} }`
+ let span = self.token.span;
+ // We only emit "unexpected `:`" error here if we can successfully parse the
+ // whole pattern correctly in that case.
+ let snapshot = self.clone();
+
+ // Create error for "unexpected `:`".
+ match self.expected_one_of_not_found(&[], &[]) {
+ Err(mut err) => {
+ self.bump(); // Skip the `:`.
+ match self.parse_pat_no_top_alt(expected) {
+ Err(mut inner_err) => {
+ // Carry on as if we had not done anything, callers will emit a
+ // reasonable error.
+ inner_err.cancel();
+ err.cancel();
+ *self = snapshot;
+ }
+ Ok(mut pat) => {
+ // We've parsed the rest of the pattern.
+ let new_span = first_pat.span.to(pat.span);
+ let mut show_sugg = false;
+ // Try to construct a recovered pattern.
+ match &mut pat.kind {
+ PatKind::Struct(qself @ None, path, ..)
+ | PatKind::TupleStruct(qself @ None, path, _)
+ | PatKind::Path(qself @ None, path) => match &first_pat.kind {
+ PatKind::Ident(_, ident, _) => {
+ path.segments.insert(0, PathSegment::from_ident(ident.clone()));
+ path.span = new_span;
+ show_sugg = true;
+ first_pat = pat;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ path.segments = old_path
+ .segments
+ .iter()
+ .cloned()
+ .chain(take(&mut path.segments))
+ .collect();
+ path.span = new_span;
+ *qself = old_qself.clone();
+ first_pat = pat;
+ show_sugg = true;
+ }
+ _ => {}
+ },
+ PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ match &first_pat.kind {
+ PatKind::Ident(_, old_ident, _) => {
+ let path = PatKind::Path(
+ None,
+ Path {
+ span: new_span,
+ segments: vec![
+ PathSegment::from_ident(old_ident.clone()),
+ PathSegment::from_ident(ident.clone()),
+ ],
+ tokens: None,
+ },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ let mut segments = old_path.segments.clone();
+ segments.push(PathSegment::from_ident(ident.clone()));
+ let path = PatKind::Path(
+ old_qself.clone(),
+ Path { span: new_span, segments, tokens: None },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ if show_sugg {
+ err.span_suggestion(
+ span,
+ "maybe write a path separator here",
+ "::".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ first_pat = self.mk_pat(new_span, PatKind::Wild);
+ }
+ err.emit();
+ }
+ }
+ }
+ _ => {
+ // Carry on as if we had not done anything. This should be unreachable.
+ *self = snapshot;
+ }
+ };
+ first_pat
+ }
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_unexpected_comma(
+ &mut self,
+ lo: Span,
+ rc: RecoverComma,
+ ) -> PResult<'a, ()> {
+ if rc == RecoverComma::No || self.token != token::Comma {
+ return Ok(());
+ }
+
+ // An unexpected comma after a top-level pattern is a clue that the
+ // user (perhaps more accustomed to some other language) forgot the
+ // parentheses in what should have been a tuple pattern; return a
+ // suggestion-enhanced error here rather than choking on the comma later.
+ let comma_span = self.token.span;
+ self.bump();
+ if let Err(mut err) = self.skip_pat_list() {
+ // We didn't expect this to work anyway; we just wanted to advance to the
+ // end of the comma-sequence so we know the span to suggest parenthesizing.
+ err.cancel();
+ }
+ let seq_span = lo.to(self.prev_token.span);
+ let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
+ if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
+ const MSG: &str = "try adding parentheses to match on a tuple...";
+
+ err.span_suggestion(
+ seq_span,
+ MSG,
+ format!("({})", seq_snippet),
+ Applicability::MachineApplicable,
+ );
+ err.span_suggestion(
+ seq_span,
+ "...or a vertical bar to match on multiple alternatives",
+ seq_snippet.replace(",", " |"),
+ Applicability::MachineApplicable,
+ );
+ }
+ Err(err)
+ }
+
+ /// Parse and throw away a parenthesized comma separated
+ /// sequence of patterns until `)` is reached.
+ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
+ while !self.check(&token::CloseDelim(token::Paren)) {
+ self.parse_pat_no_top_alt(None)?;
+ if !self.eat(&token::Comma) {
+ return Ok(());
+ }
+ }
+ Ok(())
+ }
}
}
let fn_span_lo = self.token.span;
- let mut segment = self.parse_path_segment(PathStyle::Expr)?;
+ let mut segment = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
self.check_turbofish_missing_angle_brackets(&mut segment);
let lo = self.prev_token.span;
let cond = self.parse_cond_expr()?;
+ let missing_then_block_binop_span = || {
+ match cond.kind {
+ ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
+ if let ExprKind::Block(..) = right.kind => Some(binop_span),
+ _ => None
+ }
+ };
+
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
// return. This won't catch blocks with an explicit `return`, but that would be caught by
// the dead code lint.
- let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
- self.error_missing_if_cond(lo, cond.span)
+ let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
+ if let Some(binop_span) = missing_then_block_binop_span() {
+ self.error_missing_if_then_block(lo, None, Some(binop_span)).emit();
+ self.mk_block_err(cond.span)
+ } else {
+ self.error_missing_if_cond(lo, cond.span)
+ }
} else {
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
let not_block = self.token != token::OpenDelim(token::Brace);
- let block = self.parse_block().map_err(|mut err| {
+ let block = self.parse_block().map_err(|err| {
if not_block {
- err.span_label(lo, "this `if` expression has a condition, but no block");
- if let ExprKind::Binary(_, _, ref right) = cond.kind {
- if let ExprKind::Block(_, _) = right.kind {
- err.help("maybe you forgot the right operand of the condition?");
- }
- }
+ self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
+ } else {
+ err
}
- err
})?;
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
block
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
}
+ fn error_missing_if_then_block(
+ &self,
+ if_span: Span,
+ err: Option<DiagnosticBuilder<'a>>,
+ binop_span: Option<Span>,
+ ) -> DiagnosticBuilder<'a> {
+ let msg = "this `if` expression has a condition, but no block";
+
+ let mut err = if let Some(mut err) = err {
+ err.span_label(if_span, msg);
+ err
+ } else {
+ self.struct_span_err(if_span, msg)
+ };
+
+ if let Some(binop_span) = binop_span {
+ err.span_help(binop_span, "maybe you forgot the right operand of the condition?");
+ }
+
+ err
+ }
+
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
let sp = self.sess.source_map().next_point(lo);
self.struct_span_err(sp, "missing condition for `if` expression")
})
}
- fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+ crate fn parse_const_param(
+ &mut self,
+ preceding_attrs: Vec<Attribute>,
+ ) -> PResult<'a, GenericParam> {
let const_span = self.token.span;
self.expect_keyword(kw::Const)?;
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
let (attrs, items, span) = self.parse_mod(&token::Eof)?;
- Ok(ast::Crate { attrs, items, span })
+ Ok(ast::Crate { attrs, items, span, is_placeholder: None })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
tokens: None,
})
} else {
- self.parse_ty()?
+ self.parse_ty_with_generics_recovery(&generics)?
};
// If `for` is missing we try to recover.
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token;
-use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd};
-use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax};
+use rustc_ast::{
+ self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
+ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
+};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
-type Expected = Option<&'static str>;
+pub(super) type Expected = Option<&'static str>;
/// `Expected` for function and lambda parameter patterns.
pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
// If we parsed a leading `|` which should be gated,
// then we should really gate the leading `|`.
// This complicated procedure is done purely for diagnostics UX.
- let mut first_pat = first_pat;
-
- if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) {
- if matches!(
- first_pat.kind,
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None)
- | PatKind::Path(..)
- ) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
- {
- // The pattern looks like it might be a path with a `::` -> `:` typo:
- // `match foo { bar:baz => {} }`
- let span = self.token.span;
- // We only emit "unexpected `:`" error here if we can successfully parse the
- // whole pattern correctly in that case.
- let snapshot = self.clone();
-
- // Create error for "unexpected `:`".
- match self.expected_one_of_not_found(&[], &[]) {
- Err(mut err) => {
- self.bump(); // Skip the `:`.
- match self.parse_pat_no_top_alt(expected) {
- Err(mut inner_err) => {
- // Carry on as if we had not done anything, callers will emit a
- // reasonable error.
- inner_err.cancel();
- err.cancel();
- *self = snapshot;
- }
- Ok(pat) => {
- // We've parsed the rest of the pattern.
- err.span_suggestion(
- span,
- "maybe write a path separator here",
- "::".to_string(),
- Applicability::MachineApplicable,
- );
- err.emit();
- first_pat =
- self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild);
- }
- }
- }
- _ => {
- // Carry on as if we had not done anything. This should be unreachable.
- *self = snapshot;
- }
- };
- }
- }
+
+ // Check if the user wrote `foo:bar` instead of `foo::bar`.
+ let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
if let Some(leading_vert_span) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
err.emit();
}
- /// Some special error handling for the "top-level" patterns in a match arm,
- /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
- fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> {
- if rc == RecoverComma::No || self.token != token::Comma {
- return Ok(());
- }
-
- // An unexpected comma after a top-level pattern is a clue that the
- // user (perhaps more accustomed to some other language) forgot the
- // parentheses in what should have been a tuple pattern; return a
- // suggestion-enhanced error here rather than choking on the comma later.
- let comma_span = self.token.span;
- self.bump();
- if let Err(mut err) = self.skip_pat_list() {
- // We didn't expect this to work anyway; we just wanted to advance to the
- // end of the comma-sequence so we know the span to suggest parenthesizing.
- err.cancel();
- }
- let seq_span = lo.to(self.prev_token.span);
- let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
- if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
- const MSG: &str = "try adding parentheses to match on a tuple...";
-
- err.span_suggestion(
- seq_span,
- MSG,
- format!("({})", seq_snippet),
- Applicability::MachineApplicable,
- );
- err.span_suggestion(
- seq_span,
- "...or a vertical bar to match on multiple alternatives",
- seq_snippet.replace(",", " |"),
- Applicability::MachineApplicable,
- );
- }
- Err(err)
- }
-
- /// Parse and throw away a parenthesized comma separated
- /// sequence of patterns until `)` is reached.
- fn skip_pat_list(&mut self) -> PResult<'a, ()> {
- while !self.check(&token::CloseDelim(token::Paren)) {
- self.parse_pat_no_top_alt(None)?;
- if !self.eat(&token::Comma) {
- return Ok(());
- }
- }
- Ok(())
- }
-
/// A `|` or possibly `||` token shouldn't be here. Ban it.
fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
let span = self.token.span;
self.mk_pat(span, PatKind::Ident(bm, ident, None))
}
- fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
+ pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
}
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
-use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
-use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
-use rustc_ast::{GenericArg, GenericArgs};
-use rustc_ast::{Path, PathSegment, QSelf};
+use rustc_ast::{
+ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
+ AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+ Path, PathSegment, QSelf,
+};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
}
let qself = QSelf { ty, path_span, position: path.segments.len() };
- self.parse_path_segments(&mut path.segments, style)?;
+ self.parse_path_segments(&mut path.segments, style, None)?;
Ok((
qself,
true
}
+ pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ self.parse_path_inner(style, None)
+ }
+
/// Parses simple paths.
///
/// `path = [::] segment+`
/// `a::b::C::<D>` (with disambiguator)
/// `Fn(Args)` (without disambiguator)
/// `Fn::(Args)` (with disambiguator)
- pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ pub(super) fn parse_path_inner(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Path> {
maybe_whole!(self, NtPath, |path| {
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
if self.eat(&token::ModSep) {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
- self.parse_path_segments(&mut segments, style)?;
+ self.parse_path_segments(&mut segments, style, ty_generics)?;
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
&mut self,
segments: &mut Vec<PathSegment>,
style: PathStyle,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, ()> {
loop {
- let segment = self.parse_path_segment(style)?;
+ let segment = self.parse_path_segment(style, ty_generics)?;
if style == PathStyle::Expr {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
}
}
- pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
+ pub(super) fn parse_path_segment(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &Token| {
matches!(
let lo = self.token.span;
let args = if self.eat_lt() {
// `<'a, T, A = U>`
- let args =
- self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
+ let args = self.parse_angle_args_with_leading_angle_bracket_recovery(
+ style,
+ lo,
+ ty_generics,
+ )?;
self.expect_gt()?;
let span = lo.to(self.prev_token.span);
AngleBracketedArgs { args, span }.into()
// `(T, U) -> R`
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let inputs_span = lo.to(self.prev_token.span);
- let span = ident.span.to(self.prev_token.span);
let output =
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+ let span = ident.span.to(self.prev_token.span);
ParenthesizedArgs { span, inputs, inputs_span, output }.into()
};
&mut self,
style: PathStyle,
lo: Span,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, Vec<AngleBracketedArg>> {
// We need to detect whether there are extra leading left angle brackets and produce an
// appropriate error and suggestion. This cannot be implemented by looking ahead at
let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
- match self.parse_angle_args() {
+ match self.parse_angle_args(ty_generics) {
Ok(args) => Ok(args),
Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
// Swap `self` with our backup of the parser state before attempting to parse
.emit();
// Try again without unmatched angle bracket characters.
- self.parse_angle_args()
+ self.parse_angle_args(ty_generics)
}
}
Err(e) => Err(e),
/// Parses (possibly empty) list of generic arguments / associated item constraints,
/// possibly including trailing comma.
- pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
+ pub(super) fn parse_angle_args(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Vec<AngleBracketedArg>> {
let mut args = Vec::new();
- while let Some(arg) = self.parse_angle_arg()? {
+ while let Some(arg) = self.parse_angle_arg(ty_generics)? {
args.push(arg);
if !self.eat(&token::Comma) {
if !self.token.kind.should_end_const_arg() {
}
/// Parses a single argument in the angle arguments `<...>` of a path segment.
- fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
+ fn parse_angle_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<AngleBracketedArg>> {
let lo = self.token.span;
- let arg = self.parse_generic_arg()?;
+ let arg = self.parse_generic_arg(ty_generics)?;
match arg {
Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) {
/// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`.
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
- let arg = self.parse_generic_arg()?;
+ let arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span);
match arg {
Some(GenericArg::Type(ty)) => return Ok(ty),
/// Parse a generic argument in a path segment.
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
- pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
+ pub(super) fn parse_generic_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
let start = self.token.span;
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
// Parse lifetime argument.
return self.recover_const_arg(start, err).map(Some);
}
}
- } else if self.eat_keyword_noexpect(kw::Const) {
- // Detect and recover from the old, pre-RFC2000 syntax for const generics.
- let mut err = self.struct_span_err(
- start,
- "expected lifetime, type, or constant, found keyword `const`",
- );
- if self.check_const_arg() {
- err.span_suggestion_verbose(
- start.until(self.token.span),
- "the `const` keyword is only needed in the definition of the type",
- String::new(),
- Applicability::MaybeIncorrect,
- );
- err.emit();
- GenericArg::Const(self.parse_const_arg()?)
- } else {
- let after_kw_const = self.token.span;
- return self.recover_const_arg(after_kw_const, err).map(Some);
- }
+ } else if self.token.is_keyword(kw::Const) {
+ return self.recover_const_param_declaration(ty_generics);
} else {
return Ok(None);
};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::{self as ast, BareFnTy, FnRetTy, GenericParam, Lifetime, MutTy, Ty, TyKind};
-use rustc_ast::{GenericBound, GenericBounds, MacCall, Mutability};
-use rustc_ast::{PolyTraitRef, TraitBoundModifier, TraitObjectSyntax};
+use rustc_ast::{
+ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
+ MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
+};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
+ )
+ }
+
+ pub(super) fn parse_ty_with_generics_recovery(
+ &mut self,
+ ty_params: &Generics,
+ ) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ Some(ty_params),
)
}
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
+ None,
)
}
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else {
allow_c_variadic: AllowCVariadic,
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
TyKind::Path(Some(qself), path)
} else if self.check_path() {
- self.parse_path_start_ty(lo, allow_plus)?
+ self.parse_path_start_ty(lo, allow_plus, ty_generics)?
} else if self.can_begin_bound() {
self.parse_bare_trait_object(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
/// 1. a type macro, `mac!(...)`,
/// 2. a bare trait object, `B0 + ... + Bn`,
/// 3. or a path, `path::to::MyType`.
- fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
+ fn parse_path_start_ty(
+ &mut self,
+ lo: Span,
+ allow_plus: AllowPlus,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, TyKind> {
// Simple path
- let path = self.parse_path(PathStyle::Type)?;
+ let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
Ok(TyKind::MacCall(MacCall {
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
- let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()).expect_owner();
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
Target::Impl => Some("implementation block"),
Target::ForeignMod => Some("extern block"),
Target::AssocTy => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
if Target::from_item(containing_item) == Target::Impl {
Some("type alias in implementation block")
}
}
Target::AssocConst => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
None => return true,
};
+ // If the function belongs to a trait, then it must enable the const_trait_impl
+ // feature to use that trait function (with a const default body).
+ if tcx.trait_of_item(def_id).is_some() {
+ return true;
+ }
+
// If this crate is not using stability attributes, or this function is not claiming to be a
// stable `const fn`, that is all that is required.
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
}
}
-fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
+fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
let mut collector = LibFeatureCollector::new(tcx);
tcx.hir().walk_attributes(&mut collector);
collector.lib_features
}
pub fn provide(providers: &mut Providers) {
- providers.get_lib_features = get_lib_features;
+ providers.lib_features = lib_features;
}
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
- let impl_hir_id = self.tcx.hir().local_def_id_to_hir_id(impl_did);
- match self.tcx.hir().expect_item(impl_hir_id).kind {
+ match self.tcx.hir().expect_item(impl_did).kind {
hir::ItemKind::Impl { .. } => {
let generics = self.tcx.generics_of(impl_did);
generics.requires_monomorphization(self.tcx)
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Expr, Local, Node, Pat, PatKind, Stmt};
+use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
use rustc_index::vec::Idx;
use rustc_middle::middle::region::*;
use rustc_middle::ty::query::Providers;
let body = tcx.hir().body(body_id);
visitor.scope_tree.root_body = Some(body.value.hir_id);
-
- // If the item is an associated const or a method,
- // record its impl/trait parent, as it can also have
- // lifetime parameters free in this body.
- match tcx.hir().get(id) {
- Node::ImplItem(_) | Node::TraitItem(_) => {
- visitor.scope_tree.root_parent = Some(tcx.hir().get_parent_item(id));
- }
- _ => {}
- }
-
visitor.visit_body(body);
-
visitor.scope_tree
} else {
ScopeTree::default()
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
- let local_defined_features = tcx.lib_features().to_vec();
+ let local_defined_features = tcx.lib_features(()).to_vec();
if !remaining_lib_features.is_empty() {
check_features(&mut remaining_lib_features, &local_defined_features);
// have normal hygine, so we can treat them like other items without type
// privacy and mark them reachable.
DefKind::Macro(_) => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let item = self.tcx.hir().expect_item(hir_id);
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind {
if vis.is_accessible_from(module.to_def_id(), self.tcx) {
self.update(def_id, level);
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
if vis.is_public() {
- let item =
- self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
// If the module is `self`, i.e. the current crate,
// there will be no corresponding item.
.filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
- .and_then(|def_id| {
- def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
- })
+ .and_then(|def_id| def_id.as_local())
.map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
{
if let hir::ItemKind::Mod(m) = &item.kind {
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
- if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
- // Fake crate root item from expand.
- return;
- }
-
let parent_scope = &self.parent_scope;
let parent = parent_scope.module;
let expansion = parent_scope.expansion;
}
ItemKind::ExternCrate(orig_name) => {
- let module = if orig_name.is_none() && ident.name == kw::SelfLower {
- self.r
- .session
- .struct_span_err(item.span, "`extern crate self;` requires renaming")
- .span_suggestion(
- item.span,
- "try",
- "extern crate self as name;".into(),
- Applicability::HasPlaceholders,
- )
- .emit();
- return;
- } else if orig_name == Some(kw::SelfLower) {
- self.r.graph_root
- } else {
- let crate_id = self.r.crate_loader.process_extern_crate(
- item,
- &self.r.definitions,
- local_def_id,
- );
- self.r.extern_crate_map.insert(local_def_id, crate_id);
- self.r.expect_module(crate_id.as_def_id())
- };
-
- let used = self.process_macro_use_imports(item, module);
- let binding =
- (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
- let import = self.r.arenas.alloc_import(Import {
- kind: ImportKind::ExternCrate { source: orig_name, target: ident },
- root_id: item.id,
- id: item.id,
- parent_scope: self.parent_scope,
- imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
- has_attributes: !item.attrs.is_empty(),
- use_span_with_attributes: item.span_with_attributes(),
- use_span: item.span,
- root_span: item.span,
- span: item.span,
- module_path: Vec::new(),
- vis: Cell::new(vis),
- used: Cell::new(used),
- });
- self.r.potentially_unused_imports.push(import);
- let imported_binding = self.r.import(binding, import);
- if ptr::eq(parent, self.r.graph_root) {
- if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0())
- {
- if expansion != LocalExpnId::ROOT
- && orig_name.is_some()
- && entry.extern_crate_item.is_none()
- {
- let msg = "macro-expanded `extern crate` items cannot \
- shadow names passed with `--extern`";
- self.r.session.span_err(item.span, msg);
- }
- }
- let entry =
- self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
- ExternPreludeEntry {
- extern_crate_item: None,
- introduced_by_item: true,
- },
- );
- entry.extern_crate_item = Some(imported_binding);
- if orig_name.is_some() {
- entry.introduced_by_item = true;
- }
- }
- self.r.define(parent, ident, TypeNS, imported_binding);
+ self.build_reduced_graph_for_extern_crate(
+ orig_name,
+ item,
+ local_def_id,
+ vis,
+ parent,
+ );
}
ItemKind::Mod(..) => {
}
}
+ fn build_reduced_graph_for_extern_crate(
+ &mut self,
+ orig_name: Option<Symbol>,
+ item: &Item,
+ local_def_id: LocalDefId,
+ vis: ty::Visibility,
+ parent: Module<'a>,
+ ) {
+ let ident = item.ident;
+ let sp = item.span;
+ let parent_scope = self.parent_scope;
+ let expansion = parent_scope.expansion;
+
+ let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
+ self.r
+ .session
+ .struct_span_err(item.span, "`extern crate self;` requires renaming")
+ .span_suggestion(
+ item.span,
+ "rename the `self` crate to be able to import it",
+ "extern crate self as name;".into(),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+ return;
+ } else if orig_name == Some(kw::SelfLower) {
+ Some(self.r.graph_root)
+ } else {
+ self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id).map(
+ |crate_id| {
+ self.r.extern_crate_map.insert(local_def_id, crate_id);
+ self.r.expect_module(crate_id.as_def_id())
+ },
+ )
+ }
+ .map(|module| {
+ let used = self.process_macro_use_imports(item, module);
+ let binding =
+ (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+ (used, Some(ModuleOrUniformRoot::Module(module)), binding)
+ })
+ .unwrap_or((true, None, self.r.dummy_binding));
+ let import = self.r.arenas.alloc_import(Import {
+ kind: ImportKind::ExternCrate { source: orig_name, target: ident },
+ root_id: item.id,
+ id: item.id,
+ parent_scope: self.parent_scope,
+ imported_module: Cell::new(module),
+ has_attributes: !item.attrs.is_empty(),
+ use_span_with_attributes: item.span_with_attributes(),
+ use_span: item.span,
+ root_span: item.span,
+ span: item.span,
+ module_path: Vec::new(),
+ vis: Cell::new(vis),
+ used: Cell::new(used),
+ });
+ self.r.potentially_unused_imports.push(import);
+ let imported_binding = self.r.import(binding, import);
+ if ptr::eq(parent, self.r.graph_root) {
+ if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
+ if expansion != LocalExpnId::ROOT
+ && orig_name.is_some()
+ && entry.extern_crate_item.is_none()
+ {
+ let msg = "macro-expanded `extern crate` items cannot \
+ shadow names passed with `--extern`";
+ self.r.session.span_err(item.span, msg);
+ }
+ }
+ let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
+ ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true },
+ );
+ entry.extern_crate_item = Some(imported_binding);
+ if orig_name.is_some() {
+ entry.introduced_by_item = true;
+ }
+ }
+ self.r.define(parent, ident, TypeNS, imported_binding);
+ }
+
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
let local_def_id = self.r.local_def_id(item.id);
visit::walk_variant(self, variant);
}
+
+ fn visit_crate(&mut self, krate: &'b ast::Crate) {
+ if let Some(id) = krate.is_placeholder {
+ self.visit_invoc_in_module(id);
+ } else {
+ visit::walk_crate(self, krate);
+ self.contains_macro_use(&krate.attrs);
+ }
+ }
}
use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions::*;
use rustc_span::hygiene::LocalExpnId;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::sym;
use rustc_span::Span;
use tracing::debug;
// information we encapsulate into, the better
let def_data = match &i.kind {
ItemKind::Impl { .. } => DefPathData::Impl,
- ItemKind::Mod(..) if i.ident.name == kw::Empty => {
- // Fake crate root item from expand.
- return visit::walk_item(self, i);
- }
ItemKind::Mod(..)
| ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
fn visit_field_def(&mut self, field: &'a FieldDef) {
self.collect_field(field, None);
}
+
+ fn visit_crate(&mut self, krate: &'a Crate) {
+ if let Some(id) = krate.is_placeholder {
+ self.visit_macro_invoc(id)
+ } else {
+ visit::walk_crate(self, krate)
+ }
+ }
}
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
let res = b.res();
- if b.span.is_dummy() {
+ if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() {
// These already contain the "built-in" prefix or look bad with it.
let add_built_in =
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
+ fn visit_attribute(&mut self, _: &'ast Attribute) {
+ // We do not want to resolve expressions that appear in attributes,
+ // as they do not correspond to actual code.
+ }
fn visit_item(&mut self, item: &'ast Item) {
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
// Always report errors in items we just entered.
err.emit();
}
+ /// Returns whether to add `'static` lifetime to the suggested lifetime list.
+ crate fn report_elision_failure(
+ &mut self,
+ db: &mut DiagnosticBuilder<'_>,
+ params: &[ElisionFailureInfo],
+ ) -> bool {
+ let mut m = String::new();
+ let len = params.len();
+
+ let elided_params: Vec<_> =
+ params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
+
+ let elided_len = elided_params.len();
+
+ for (i, info) in elided_params.into_iter().enumerate() {
+ let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
+ info;
+
+ db.span_label(span, "");
+ let help_name = if let Some(ident) =
+ parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
+ {
+ format!("`{}`", ident)
+ } else {
+ format!("argument {}", index + 1)
+ };
+
+ m.push_str(
+ &(if n == 1 {
+ help_name
+ } else {
+ format!(
+ "one of {}'s {} {}lifetimes",
+ help_name,
+ n,
+ if have_bound_regions { "free " } else { "" }
+ )
+ })[..],
+ );
+
+ if elided_len == 2 && i == 0 {
+ m.push_str(" or ");
+ } else if i + 2 == elided_len {
+ m.push_str(", or ");
+ } else if i != elided_len - 1 {
+ m.push_str(", ");
+ }
+ }
+
+ if len == 0 {
+ db.help(
+ "this function's return type contains a borrowed value, \
+ but there is no value for it to be borrowed from",
+ );
+ true
+ } else if elided_len == 0 {
+ db.help(
+ "this function's return type contains a borrowed value with \
+ an elided lifetime, but the lifetime cannot be derived from \
+ the arguments",
+ );
+ true
+ } else if elided_len == 1 {
+ db.help(&format!(
+ "this function's return type contains a borrowed value, \
+ but the signature does not say which {} it is borrowed from",
+ m
+ ));
+ false
+ } else {
+ db.help(&format!(
+ "this function's return type contains a borrowed value, \
+ but the signature does not say whether it is borrowed from {}",
+ m
+ ));
+ false
+ }
+ }
+
+ crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
+ let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
+ lt.name == hir::LifetimeName::Implicit(true)
+ }) else { return };
+
+ let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+ spans.sort();
+ let mut spans_dedup = spans.clone();
+ spans_dedup.dedup();
+ let spans_with_counts: Vec<_> = spans_dedup
+ .into_iter()
+ .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
+ .collect();
+
+ self.tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+ missing_lifetime.hir_id,
+ spans,
+ |lint| {
+ let mut db = lint.build("hidden lifetime parameters in types are deprecated");
+ self.add_missing_lifetime_specifiers_label(
+ &mut db,
+ spans_with_counts,
+ &FxHashSet::from_iter([kw::UnderscoreLifetime]),
+ Vec::new(),
+ &[],
+ );
+ db.emit()
+ },
+ );
+ }
+
// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
// generics. We are disallowing this until we can decide on how we want to handle non-'static
// lifetimes in const generics. See issue #74052 for discussion.
);
let is_allowed_lifetime = matches!(
lifetime_ref.name,
- hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
+ hir::LifetimeName::Implicit(_)
+ | hir::LifetimeName::Static
+ | hir::LifetimeName::Underscore
);
if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
#[derive(Clone, Debug)]
crate struct ElisionFailureInfo {
/// Where we can find the argument pattern.
- parent: Option<hir::BodyId>,
+ crate parent: Option<hir::BodyId>,
/// The index of the argument in the original definition.
- index: usize,
- lifetime_count: usize,
- have_bound_regions: bool,
+ crate index: usize,
+ crate lifetime_count: usize,
+ crate have_bound_regions: bool,
crate span: Span,
}
trait_definition_only: bool,
with_scope_for_path: bool,
) -> NamedRegionMap {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id));
+ let item = tcx.hir().expect_item(local_def_id);
let mut named_region_map = NamedRegionMap {
defs: Default::default(),
late_bound: Default::default(),
}
});
match lifetime.name {
- LifetimeName::Implicit => {
+ LifetimeName::Implicit(_) => {
// For types like `dyn Foo`, we should
// generate a special form of elided.
span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(trait_item.hir_id())),
+ Some(tcx.hir().get_parent_did(trait_item.hir_id())),
trait_item.hir_id(),
&sig.decl,
&trait_item.generics,
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(impl_item.hir_id())),
+ Some(tcx.hir().get_parent_did(impl_item.hir_id())),
impl_item.hir_id(),
&sig.decl,
&impl_item.generics,
/// ordering is not important there.
fn visit_early_late<F>(
&mut self,
- parent_id: Option<hir::HirId>,
+ parent_id: Option<LocalDefId>,
hir_id: hir::HirId,
decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>,
Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
if let hir::ItemKind::Trait(.., ref trait_items) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
assoc_item_kind =
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
impl_self = Some(self_ty);
assoc_item_kind =
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
- Scope::Body { .. } => return,
+ Scope::Body { .. } => break Ok(()),
- Scope::Root => break None,
+ Scope::Root => break Err(None),
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
scope = s;
}
- Scope::Elision { ref elide, ref s, .. } => {
- let lifetime = match *elide {
- Elide::FreshLateAnon(named_late_bound_vars, ref counter) => {
- for lifetime_ref in lifetime_refs {
- let lifetime = Region::late_anon(named_late_bound_vars, counter)
- .shifted(late_depth);
+ Scope::Elision {
+ elide: Elide::FreshLateAnon(named_late_bound_vars, ref counter),
+ ..
+ } => {
+ for lifetime_ref in lifetime_refs {
+ let lifetime =
+ Region::late_anon(named_late_bound_vars, counter).shifted(late_depth);
- self.insert_lifetime(lifetime_ref, lifetime);
- }
- return;
- }
- Elide::Exact(l) => l.shifted(late_depth),
- Elide::Error(ref e) => {
- let mut scope = s;
- loop {
- match scope {
- Scope::Binder { ref lifetimes, s, .. } => {
- // Collect named lifetimes for suggestions.
- for name in lifetimes.keys() {
- if let hir::ParamName::Plain(name) = name {
- lifetime_names.insert(name.name);
- lifetime_spans.push(name.span);
- }
- }
- scope = s;
- }
- Scope::ObjectLifetimeDefault { ref s, .. }
- | Scope::Elision { ref s, .. }
- | Scope::TraitRefBoundary { ref s, .. } => {
- scope = s;
+ self.insert_lifetime(lifetime_ref, lifetime);
+ }
+ break Ok(());
+ }
+
+ Scope::Elision { elide: Elide::Exact(l), .. } => {
+ let lifetime = l.shifted(late_depth);
+ for lifetime_ref in lifetime_refs {
+ self.insert_lifetime(lifetime_ref, lifetime);
+ }
+ break Ok(());
+ }
+
+ Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
+ let mut scope = s;
+ loop {
+ match scope {
+ Scope::Binder { ref lifetimes, s, .. } => {
+ // Collect named lifetimes for suggestions.
+ for name in lifetimes.keys() {
+ if let hir::ParamName::Plain(name) = name {
+ lifetime_names.insert(name.name);
+ lifetime_spans.push(name.span);
}
- _ => break,
}
+ scope = s;
+ }
+ Scope::ObjectLifetimeDefault { ref s, .. }
+ | Scope::Elision { ref s, .. }
+ | Scope::TraitRefBoundary { ref s, .. } => {
+ scope = s;
}
- break Some(&e[..]);
+ _ => break,
}
- Elide::Forbid => break None,
- };
- for lifetime_ref in lifetime_refs {
- self.insert_lifetime(lifetime_ref, lifetime);
}
- return;
+ break Err(Some(&e[..]));
}
+ Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
+
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
}
};
+ let error = match error {
+ Ok(()) => {
+ self.report_elided_lifetime_in_ty(lifetime_refs);
+ return;
+ }
+ Err(error) => error,
+ };
+
// If we specifically need the `scope_for_path` map, then we're in the
// diagnostic pass and we don't want to emit more errors.
if self.map.scope_for_path.is_some() {
err.emit();
}
- fn report_elision_failure(
- &mut self,
- db: &mut DiagnosticBuilder<'_>,
- params: &[ElisionFailureInfo],
- ) -> bool /* add `'static` lifetime to lifetime list */ {
- let mut m = String::new();
- let len = params.len();
-
- let elided_params: Vec<_> =
- params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
-
- let elided_len = elided_params.len();
-
- for (i, info) in elided_params.into_iter().enumerate() {
- let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
- info;
-
- db.span_label(span, "");
- let help_name = if let Some(ident) =
- parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
- {
- format!("`{}`", ident)
- } else {
- format!("argument {}", index + 1)
- };
-
- m.push_str(
- &(if n == 1 {
- help_name
- } else {
- format!(
- "one of {}'s {} {}lifetimes",
- help_name,
- n,
- if have_bound_regions { "free " } else { "" }
- )
- })[..],
- );
-
- if elided_len == 2 && i == 0 {
- m.push_str(" or ");
- } else if i + 2 == elided_len {
- m.push_str(", or ");
- } else if i != elided_len - 1 {
- m.push_str(", ");
- }
- }
-
- if len == 0 {
- db.help(
- "this function's return type contains a borrowed value, \
- but there is no value for it to be borrowed from",
- );
- true
- } else if elided_len == 0 {
- db.help(
- "this function's return type contains a borrowed value with \
- an elided lifetime, but the lifetime cannot be derived from \
- the arguments",
- );
- true
- } else if elided_len == 1 {
- db.help(&format!(
- "this function's return type contains a borrowed value, \
- but the signature does not say which {} it is borrowed from",
- m
- ));
- false
- } else {
- db.help(&format!(
- "this function's return type contains a borrowed value, \
- but the signature does not say whether it is borrowed from {}",
- m
- ));
- false
- }
- }
-
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
let mut late_depth = 0;
))
.emit();
}
- hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
+ hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
self.resolve_lifetime_ref(lt);
}
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(never_type)]
}
pub fn next_node_id(&mut self) -> NodeId {
- let next = self
- .next_node_id
- .as_usize()
- .checked_add(1)
- .expect("input too large; ran out of NodeIds");
- self.next_node_id = ast::NodeId::from_usize(next);
+ let next =
+ self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+ self.next_node_id = ast::NodeId::from_u32(next);
self.next_node_id
}
Some(binding)
} else {
let crate_id = if !speculative {
- self.crate_loader.process_path_extern(ident.name, ident.span)
+ let Some(crate_id) =
+ self.crate_loader.process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); };
+ crate_id
} else {
self.crate_loader.maybe_process_path_extern(ident.name)?
};
Passes::All => false,
}
}
+
+ pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
+ match *self {
+ Passes::Some(ref mut v) => v.extend(passes),
+ Passes::All => {}
+ }
+ }
}
pub const fn default_lib_output() -> CrateType {
v => {
let mut passes = vec![];
if parse_list(&mut passes, v) {
- *slot = Passes::Some(passes);
+ slot.extend(passes);
true
} else {
false
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
- force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "force overflow checks on or off"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
pub config: CrateConfig,
pub edition: Edition,
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
- /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
+ /// Places where raw identifiers were used. This is used to avoid complaining about idents
+ /// clashing with keywords in new editions.
pub raw_identifier_spans: Lock<Vec<Span>>,
+ /// Places where identifiers that contain invalid Unicode codepoints but that look like they
+ /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
+ /// provide a single error per unique incorrect identifier.
+ pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>,
source_map: Lrc<SourceMap>,
pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
/// Contains the spans of block expressions that could have been incomplete based on the
edition: ExpnId::root().expn_data().edition,
missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
+ bad_unicode_identifiers: Lock::new(Default::default()),
source_map,
buffered_lints: Lock::new(vec![]),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
}
pub fn overflow_checks(&self) -> bool {
- self.opts
- .cg
- .overflow_checks
- .or(self.opts.debugging_opts.force_overflow_checks)
- .unwrap_or(self.opts.debug_assertions)
+ self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions)
}
/// Check whether this compile session and crate type use static crt.
HygieneData::with(|data| data.expn_data(self).clone())
}
+ #[inline]
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
+ // a few "fast path" cases to avoid locking HygieneData
+ if ancestor == ExpnId::root() || ancestor == self {
+ return true;
+ }
+ if ancestor.krate != self.krate {
+ return false;
+ }
HygieneData::with(|data| data.is_descendant_of(self, ancestor))
}
}
fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
- while expn_id != ancestor {
+ // a couple "fast path" cases to avoid traversing parents in the loop below
+ if ancestor == ExpnId::root() {
+ return true;
+ }
+ if expn_id.krate != ancestor.krate {
+ return false;
+ }
+ loop {
+ if expn_id == ancestor {
+ return true;
+ }
if expn_id == ExpnId::root() {
return false;
}
expn_id = self.expn_data(expn_id).parent;
}
- true
}
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
data: ExpnData,
hash: ExpnHash,
) -> ExpnId {
+ debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
let expn_id = ExpnId { krate, local_id };
HygieneData::with(|hygiene_data| {
let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
Implied,
Input,
Into,
+ IntoFuture,
IntoIterator,
IoRead,
IoWrite,
gen_future,
gen_kill,
generator,
+ generator_return,
generator_state,
generators,
generic_arg_infer,
inout,
instruction_set,
intel,
+ into_future,
into_iter,
intra_doc_pointers,
intrinsics,
// found that to regress performance up to 2% in some cases. This might be
// revisited after further improvements to `indexmap`.
//
-// This type is private to prevent accidentally constructing more than one `Interner` on the same
-// thread, which makes it easy to mixup `Symbol`s between `Interner`s.
+// This type is private to prevent accidentally constructing more than one
+// `Interner` on the same thread, which makes it easy to mixup `Symbol`s
+// between `Interner`s.
#[derive(Default)]
struct InternerInner {
arena: DroplessArena,
let name = Symbol::new(inner.strings.len() as u32);
- // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
- // UTF-8.
+ // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena,
+ // and immediately convert the clone back to `&[u8], all because there
+ // is no `inner.arena.alloc_str()` method. This is clearly safe.
let string: &str =
unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) };
- // It is safe to extend the arena allocation to `'static` because we only access
- // these while the arena is still alive.
+
+ // SAFETY: we can extend the arena allocation to `'static` because we
+ // only access these while the arena is still alive.
let string: &'static str = unsafe { &*(string as *const str) };
inner.strings.push(string);
+
+ // This second hash table lookup can be avoided by using `RawEntryMut`,
+ // but this code path isn't hot enough for it to be worth it. See
+ // #91445 for details.
inner.names.insert(string, name);
name
}
-use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Reg, Uniform,
+};
use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
for _ in 0..((offset - last_offset).bits() / 64)
.min((prefix.len() - prefix_index) as u64)
{
- prefix[prefix_index] = Some(RegKind::Integer);
+ prefix[prefix_index] = Some(Reg::i64());
prefix_index += 1;
}
break;
}
- prefix[prefix_index] = Some(RegKind::Float);
+ prefix[prefix_index] = Some(Reg::f64());
prefix_index += 1;
last_offset = offset + Reg::f64().size;
}
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
arg.cast_to(CastTarget {
prefix,
- prefix_chunk_size: Size::from_bytes(8),
rest: Uniform { unit: Reg::i64(), total: rest_size },
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
});
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget {
- pub prefix: [Option<RegKind>; 8],
- pub prefix_chunk_size: Size,
+ pub prefix: [Option<Reg>; 8],
pub rest: Uniform,
+ pub attrs: ArgAttributes,
}
impl From<Reg> for CastTarget {
impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
- CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
+ CastTarget {
+ prefix: [None; 8],
+ rest: uniform,
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
+ }
}
}
impl CastTarget {
pub fn pair(a: Reg, b: Reg) -> CastTarget {
CastTarget {
- prefix: [Some(a.kind), None, None, None, None, None, None, None],
- prefix_chunk_size: a.size,
+ prefix: [Some(a), None, None, None, None, None, None, None],
rest: Uniform::from(b),
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
}
}
- pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
- (self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
- .align_to(self.rest.align(cx))
- + self.rest.total
+ pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
+ let mut size = self.rest.total;
+ for i in 0..self.prefix.iter().count() {
+ match self.prefix[i] {
+ Some(v) => size += Size { raw: v.size.bytes() },
+ None => {}
+ }
+ }
+ return size;
}
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
self.prefix
.iter()
- .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
+ .filter_map(|x| x.map(|reg| reg.align(cx)))
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
acc.max(align)
})
// FIXME: This needs an audit for correctness and completeness.
-use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, RegKind, Uniform,
+};
+use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
let valid_unit = match unit.kind {
RegKind::Integer => false,
- RegKind::Float => true,
+ RegKind::Float => false,
RegKind::Vector => arg.layout.size.bits() == 128,
};
})
}
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
-where
- Ty: TyAbiInterface<'a, C> + Copy,
- C: HasDataLayout,
-{
- if !ret.layout.is_aggregate() {
- ret.extend_integer_width_to(64);
- return;
- }
-
- if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
- ret.cast_to(uniform);
- return;
- }
- let size = ret.layout.size;
- let bits = size.bits();
- if bits <= 256 {
- let unit = Reg::i64();
- ret.cast_to(Uniform { unit, total: size });
- return;
- }
-
- // don't return aggregates in registers
- ret.make_indirect();
-}
-
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
+fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
return;
}
+ // This doesn't intentionally handle structures with floats which needs
+ // special care below.
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
arg.cast_to(uniform);
return;
}
+ if let abi::FieldsShape::Arbitrary { .. } = arg.layout.fields {
+ let dl = cx.data_layout();
+ let size = arg.layout.size;
+ let mut prefix = [None; 8];
+ let mut prefix_index = 0;
+ let mut last_offset = Size::ZERO;
+ let mut has_float = false;
+ let mut arg_attribute = ArgAttribute::default();
+
+ for i in 0..arg.layout.fields.count() {
+ let field = arg.layout.field(cx, i);
+ let offset = arg.layout.fields.offset(i);
+
+ if let abi::Abi::Scalar(scalar) = &field.abi {
+ if scalar.value == abi::F32 || scalar.value == abi::F64 {
+ has_float = true;
+
+ if !last_offset.is_aligned(dl.f64_align.abi) && last_offset < offset {
+ if prefix_index == prefix.len() {
+ break;
+ }
+ prefix[prefix_index] = Some(Reg::i32());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i32().size;
+ }
+
+ for _ in 0..((offset - last_offset).bits() / 64)
+ .min((prefix.len() - prefix_index) as u64)
+ {
+ prefix[prefix_index] = Some(Reg::i64());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i64().size;
+ }
+
+ if last_offset < offset {
+ if prefix_index == prefix.len() {
+ break;
+ }
+ prefix[prefix_index] = Some(Reg::i32());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i32().size;
+ }
+
+ if prefix_index == prefix.len() {
+ break;
+ }
+
+ if scalar.value == abi::F32 {
+ arg_attribute = ArgAttribute::InReg;
+ prefix[prefix_index] = Some(Reg::f32());
+ last_offset = offset + Reg::f32().size;
+ } else {
+ prefix[prefix_index] = Some(Reg::f64());
+ last_offset = offset + Reg::f64().size;
+ }
+ prefix_index += 1;
+ }
+ }
+ }
+
+ if has_float && arg.layout.size <= in_registers_max {
+ let mut rest_size = size - last_offset;
+
+ if (rest_size.raw % 8) != 0 && prefix_index < prefix.len() {
+ prefix[prefix_index] = Some(Reg::i32());
+ rest_size = rest_size - Reg::i32().size;
+ }
+
+ arg.cast_to(CastTarget {
+ prefix,
+ rest: Uniform { unit: Reg::i64(), total: rest_size },
+ attrs: ArgAttributes {
+ regular: arg_attribute,
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
+ });
+ return;
+ }
+ }
+
let total = arg.layout.size;
- if total.bits() > 128 {
+ if total > in_registers_max {
arg.make_indirect();
return;
}
C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
- classify_ret(cx, &mut fn_abi.ret);
+ classify_arg(cx, &mut fn_abi.ret, Size { raw: 32 });
}
for arg in &mut fn_abi.args {
if arg.is_ignore() {
continue;
}
- classify_arg(cx, arg);
+ classify_arg(cx, arg, Size { raw: 16 });
}
}
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
+ base.link_env.extend(super::apple_base::macos_link_env("arm64"));
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
- let arch = "aarch64";
- let llvm_target = super::apple_base::macos_llvm_target(&arch);
+ let llvm_target = super::apple_base::macos_llvm_target("arm64");
Target {
llvm_target,
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
- arch: arch.to_string(),
+ arch: "aarch64".to_string(),
options: TargetOptions {
mcount: "\u{1}mcount".to_string(),
frame_pointer: FramePointer::NonLeaf,
// warnings about the usage of ELF TLS.
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
- // TLS is flagged as enabled if it looks to be supported.
- let version = macos_deployment_target();
+ // TLS is flagged as enabled if it looks to be supported. The architecture
+ // only matters for default deployment target which is 11.0 for ARM64 and
+ // 10.7 for everything else.
+ let has_elf_tls = macos_deployment_target("x86_64") >= (10, 7);
TargetOptions {
os: os.to_string(),
has_rpath: true,
dll_suffix: ".dylib".to_string(),
archive_format: "darwin".to_string(),
- has_elf_tls: version >= (10, 7),
+ has_elf_tls,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
eh_frame_header: false,
.and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}
-fn macos_deployment_target() -> (u32, u32) {
- deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
+fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
+ if arch == "arm64" { (11, 0) } else { (10, 7) }
+}
+
+fn macos_deployment_target(arch: &str) -> (u32, u32) {
+ deployment_target("MACOSX_DEPLOYMENT_TARGET")
+ .unwrap_or_else(|| macos_default_deployment_target(arch))
}
pub fn macos_llvm_target(arch: &str) -> String {
- let (major, minor) = macos_deployment_target();
+ let (major, minor) = macos_deployment_target(arch);
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}
+pub fn macos_link_env(arch: &str) -> Vec<(String, String)> {
+ // Use the default deployment target for linking just as with the LLVM target if not
+ // specified via MACOSX_DEPLOYMENT_TARGET, otherwise the system linker would use its
+ // default which varies with Xcode version.
+ if env::var("MACOSX_DEPLOYMENT_TARGET").is_err() {
+ let default = macos_default_deployment_target(arch);
+ vec![("MACOSX_DEPLOYMENT_TARGET".to_string(), format!("{}.{}", default.0, default.1))]
+ } else {
+ vec![]
+ }
+}
+
pub fn macos_link_env_remove() -> Vec<String> {
let mut env_remove = Vec::with_capacity(2);
// Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
base.cpu = "yonah".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
+ base.link_env.extend(super::apple_base::macos_link_env("i686"));
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
LinkerFlavor::Gcc,
vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
);
+ base.link_env.extend(super::apple_base::macos_link_env("x86_64"));
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
// is otherwise overwhelming and unhelpful (see #85844 for an
// example).
- let trait_is_debug =
- self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id());
- let trait_is_display =
- self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id());
-
let in_std_macro =
match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
Some(macro_def_id) => {
None => false,
};
- if in_std_macro && (trait_is_debug || trait_is_display) {
+ if in_std_macro
+ && matches!(
+ self.tcx.get_diagnostic_name(trait_ref.def_id()),
+ Some(sym::Debug | sym::Display)
+ )
+ {
err.emit();
return;
}
debug!("maybe_suggest_unsized_generics: param={:?}", param);
match node {
hir::Node::Item(
- item
- @
- hir::Item {
+ item @ hir::Item {
// Only suggest indirection for uses of type parameters in ADTs.
kind:
hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
use rustc_middle::mir;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
cause: self.cause,
param_env: self.param_env,
obligations: vec![],
- error: false,
cache: SsoHashMap::new(),
anon_depth: 0,
universes: vec![],
normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
}
}
- let result = value.fold_with(&mut normalizer);
+ let result = value.try_fold_with(&mut normalizer);
info!(
"normalize::<{}>: result={:?} with {} obligations",
std::any::type_name::<T>(),
std::any::type_name::<T>(),
normalizer.obligations,
);
- if normalizer.error {
- Err(NoSolution)
- } else {
- Ok(Normalized { value: result, obligations: normalizer.obligations })
- }
+ result.map(|value| Normalized { value, obligations: normalizer.obligations })
}
}
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
- error: bool,
anon_depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
}
impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ type Error = NoSolution;
+
fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
+}
- fn fold_binder<T: TypeFoldable<'tcx>>(
+impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ fn try_fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
- let t = t.super_fold_with(self);
+ let t = t.try_super_fold_with(self);
self.universes.pop();
t
}
#[instrument(level = "debug", skip(self))]
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
- return ty;
+ return Ok(ty);
}
if let Some(ty) = self.cache.get(&ty) {
- return ty;
+ return Ok(ty);
}
// See note in `rustc_trait_selection::traits::project` about why we
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
- Reveal::UserFacing => ty.super_fold_with(self),
+ Reveal::UserFacing => ty.try_super_fold_with(self),
Reveal::All => {
- let substs = substs.super_fold_with(self);
+ let substs = substs.try_super_fold_with(self)?;
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth(
ty
);
}
- let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty));
+ let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));
self.anon_depth -= 1;
folded_ty
}
// we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx;
- let data = data.super_fold_with(self);
+ let data = data.try_super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
-
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- result.normalized_ty
- }
-
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
-
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(result.normalized_ty)
}
ty::Projection(data) => {
&mut self.universes,
data,
);
- let data = data.super_fold_with(self);
+ let data = data.try_super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- crate::traits::project::PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- result.normalized_ty,
- )
- }
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ ))
}
- _ => ty.super_fold_with(self),
- })();
+ _ => ty.try_super_fold_with(self),
+ })()?;
self.cache.insert(ty, res);
- res
+ Ok(res)
}
- fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- let constant = constant.super_fold_with(self);
- constant.eval(self.infcx.tcx, self.param_env)
+ fn try_fold_const(
+ &mut self,
+ constant: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ let constant = constant.try_super_fold_with(self)?;
+ Ok(constant.eval(self.infcx.tcx, self.param_env))
}
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- constant.super_fold_with(self)
+ fn try_fold_mir_const(
+ &mut self,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ constant.try_super_fold_with(self)
}
}
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
{
if self.is_in_const_context {
- self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+ self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
} else {
debug!("passing ~const Drop bound; in non-const context");
// `~const Drop` when we are not in a const context has no effect.
// This helps us avoid overflow: see issue #72839
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
- if obligation.references_error() {
+ // We don't check for errors in the `ParamEnv` - in practice,
+ // it seems to cause us to be overly aggressive in deciding
+ // to give up searching for candidates, leading to spurious errors.
+ if obligation.predicate.references_error() {
return;
}
}
}
- fn assemble_const_drop_candidates(
+ fn assemble_const_drop_candidates<'a>(
&mut self,
obligation: &TraitObligation<'tcx>,
+ obligation_stack: &TraitObligationStack<'a, 'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) -> Result<(), SelectionError<'tcx>> {
let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
let mut noreturn = false;
self.check_recursion_depth(depth, obligation)?;
- let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+ let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
let mut copy_obligation =
obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef {
polarity: ty::ImplPolarity::Positive,
}));
copy_obligation.recursion_depth = depth + 1;
- self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
+ self.assemble_candidates_from_impls(©_obligation, &mut new_candidates);
let copy_conditions = self.copy_clone_conditions(©_obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
- if !copy_candidates.vec.is_empty() {
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates);
+ let copy_stack = self.push_stack(obligation_stack.list(), ©_obligation);
+ self.assemble_candidates_from_caller_bounds(©_stack, &mut new_candidates)?;
+
+ let const_drop_obligation =
+ obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None),
+ substs: self.tcx().mk_substs_trait(ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ }));
+
+ let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation);
+ self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?;
+
+ if !new_candidates.vec.is_empty() {
noreturn = true;
}
- debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy");
+ debug!(?new_candidates.vec, "assemble_const_drop_candidates");
match ty.kind() {
ty::Int(_)
},
ty::PredicateKind::TypeOutlives(pred) => {
- if pred.0.is_known_global() {
+ // A global type with no late-bound regions can only
+ // contain the "'static" lifetime (any other lifetime
+ // would either be late-bound or local), so it is guaranteed
+ // to outlive any other lifetime
+ if pred.0.is_global(self.infcx.tcx) && !pred.0.has_late_bound_regions() {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToOkModuloRegions)
normalize_mir_const_after_erasing_regions: |tcx, goal| {
normalize_after_erasing_regions(tcx, goal)
},
+ try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
+ debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
+
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
+ try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
..*p
};
}
})
}
+#[instrument(level = "debug", skip(tcx))]
+fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
+ tcx: TyCtxt<'tcx>,
+ goal: ParamEnvAnd<'tcx, T>,
+) -> Result<T, NoSolution> {
+ let ParamEnvAnd { param_env, value } = goal;
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::dummy();
+ match infcx.at(&cause, param_env).normalize(value) {
+ Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
+ // We don't care about the `obligations`; they are
+ // always only region relations, and we are about to
+ // erase those anyway:
+ debug_assert_eq!(
+ normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
+ None,
+ );
+
+ let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
+ // It's unclear when `resolve_vars` would have an effect in a
+ // fresh `InferCtxt`. If this assert does trigger, it will give
+ // us a test case.
+ debug_assert_eq!(normalized_value, resolved_value);
+ let erased = infcx.tcx.erase_regions(resolved_value);
+ debug_assert!(!erased.needs_infer(), "{:?}", erased);
+ Ok(erased)
+ }
+ Err(NoSolution) => Err(NoSolution),
+ }
+ })
+}
+
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
match p.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
Ok(tys) => tys,
};
for required_ty in tys {
- let required =
- tcx.normalize_erasing_regions(self.param_env, required_ty);
+ let required = tcx
+ .try_normalize_erasing_regions(self.param_env, required_ty)
+ .unwrap_or(required_ty);
+
queue_type(self, required);
}
}
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_def_id);
match parent_item.kind {
hir::ItemKind::Impl(ref impl_) => {
if let Some(impl_item_ref) =
}
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.defaultness
} else {
}
fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.constness
} else {
}
fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
def_id: LocalDefId,
span: Span,
) {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);
struct FoundParentLifetime;
for expr in exprs {
let expr = expr.as_coercion_site();
let noop = match self.typeck_results.borrow().expr_adjustments(expr) {
- &[Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }] =>
- {
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. },
+ ] => {
match *self.node_ty(expr.hir_id).kind() {
ty::Ref(_, _, mt_orig) => {
let mutbl_adj: hir::Mutability = mutbl_adj.into();
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
parent_id,
expression.map(|expr| (expr, blk_id)),
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
id,
None,
}
}
_ => {
- err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
+ err = fcx.report_mismatched_types(
+ cause,
+ expected,
+ found,
+ coercion_error.clone(),
+ );
}
}
}
if let Some(expr) = expression {
- fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
+ fcx.emit_coerce_suggestions(
+ &mut err,
+ expr,
+ found,
+ expected,
+ None,
+ coercion_error,
+ );
}
err.emit_unless(unsized_return);
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
// Get the `impl Trait`'s `DefId`.
if let ty::Opaque(def_id, _) = ty.kind() {
- let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
// get the `Trait`'s `DefId`.
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
- fcx.tcx.hir().expect_item(hir_id).kind
+ fcx.tcx.hir().expect_item(def_id.expect_local()).kind
{
// Are of this `impl Trait`'s traits object safe?
is_object_safe = bounds.iter().all(|bound| {
// First liberate late bound regions and subst placeholders
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_sig =
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
- // Also add the resulting inputs and output as well-formed.
- // This probably isn't strictly necessary.
+ // Add the resulting inputs and output as well-formed.
wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
// span points only at the type `Box<Self`>, but we want to cover the whole
// argument pattern and type.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, body) => tcx
.hir()
.body_param_names(body)
if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _)
if sig.header.asyncness == hir::IsAsync::NotAsync =>
{
trait_m: &ty::AssocItem,
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a method", impl_m),
};
- let trait_args = trait_m.def_id.as_local().map(|def_id| {
- let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
+ let trait_args =
+ trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
TraitItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- }
- });
+ });
match *terr {
TypeError::ArgumentMutability(i) => {
err_occurred = true;
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
- let trait_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
if trait_item.generics.params.is_empty() {
(Some(vec![trait_item.generics.span]), vec![])
} else {
(trait_span.map(|s| vec![s]), vec![])
};
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_.def_id.expect_local());
- let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
+ let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
let impl_item_impl_trait_spans: Vec<Span> = impl_item
.generics
.params
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
if trait_number_args != impl_number_args {
let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
- let trait_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_id).kind {
+ match tcx.hir().expect_trait_item(def_id).kind {
TraitItemKind::Fn(ref trait_m_sig, _) => {
let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
} else {
trait_item_span
};
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref impl_m_sig, _) => {
let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
);
// Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_c_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span,
_ => bug!("{:?} is not a impl const", impl_c),
}
trait_c.ident
);
- let trait_c_hir_id =
- trait_c.def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
- let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
+ let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
// Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_hir_id).kind {
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
}
use rustc_hir::{is_range_literal, Node};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
expr_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+ error: TypeError<'tcx>,
) {
- self.annotate_expected_due_to_let_ty(err, expr);
+ self.annotate_expected_due_to_let_ty(err, expr, error);
self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+ let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
- self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, e);
(expected, Some(err))
}
&self,
err: &mut DiagnosticBuilder<'_>,
expr: &hir::Expr<'_>,
+ error: TypeError<'_>,
) {
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
- if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
- self.tcx.hir().find(parent)
- {
- if init.hir_id == expr.hir_id {
+ match (self.tcx.hir().find(parent), error) {
+ (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
+ if init.hir_id == expr.hir_id =>
+ {
// Point at `let` assignment type.
err.span_label(ty.span, "expected due to this");
}
+ (
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+ })),
+ TypeError::Sorts(ExpectedFound { expected, .. }),
+ ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
+ // We ignore closures explicitly because we already point at them elsewhere.
+ // Point at the assigned-to binding.
+ let mut primary_span = lhs.span;
+ let mut secondary_span = lhs.span;
+ let mut post_message = "";
+ match lhs.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ res:
+ hir::def::Res::Def(
+ hir::def::DefKind::Static | hir::def::DefKind::Const,
+ def_id,
+ ),
+ ..
+ },
+ )) => {
+ if let Some(hir::Node::Item(hir::Item {
+ ident,
+ kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
+ ..
+ })) = self.tcx.hir().get_if_local(*def_id)
+ {
+ primary_span = ty.span;
+ secondary_span = ident.span;
+ post_message = " type";
+ }
+ }
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) => {
+ if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
+ let parent = self.tcx.hir().get_parent_node(pat.hir_id);
+ primary_span = pat.span;
+ secondary_span = pat.span;
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
+ primary_span = ty.span;
+ post_message = " type";
+ }
+ Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
+ primary_span = init.span;
+ post_message = " value";
+ }
+ Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
+ primary_span = *ty_span;
+ post_message = " parameter type";
+ }
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+
+ if primary_span != secondary_span
+ && self
+ .tcx
+ .sess
+ .source_map()
+ .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
+ {
+ // We are pointing at the binding's type or initializer value, but it's pattern
+ // is in a different line, so we point at both.
+ err.span_label(secondary_span, "expected due to the type of this binding");
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ } else if post_message == "" {
+ // We are pointing at either the assignment lhs or the binding def pattern.
+ err.span_label(primary_span, "expected due to the type of this binding");
+ } else {
+ // We are pointing at the binding's type or initializer value.
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ }
+
+ if !lhs.is_syntactic_place_expr() {
+ // We already emitted E0070 "invalid left-hand side of assignment", so we
+ // silence this.
+ err.delay_as_bug();
+ }
+ }
+ _ => {}
}
}
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Pos};
use rustc_trait_selection::traits::{self, ObligationCauseCode};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
lhs: &'tcx hir::Expr<'tcx>,
err_code: &'static str,
- expr_span: &Span,
+ op_span: Span,
) {
if lhs.is_syntactic_place_expr() {
return;
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
let mut err = self.tcx.sess.struct_span_err_with_code(
- *expr_span,
+ op_span,
"invalid left-hand side of assignment",
DiagnosticId::Error(err_code.into()),
);
err.span_label(lhs.span, "cannot assign to this expression");
+
+ let mut parent = self.tcx.hir().get_parent_node(lhs.hir_id);
+ while let Some(node) = self.tcx.hir().find(parent) {
+ match node {
+ hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::Loop(
+ hir::Block {
+ expr:
+ Some(hir::Expr {
+ kind:
+ hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..),
+ ..
+ }),
+ ..
+ },
+ _,
+ hir::LoopSource::While,
+ _,
+ ),
+ ..
+ }) => {
+ // We have a situation like `while Some(0) = value.get(0) {`, where `while let`
+ // was more likely intended.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "you might have meant to use pattern destructuring",
+ "let ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ if !self.sess().features_untracked().destructuring_assignment {
+ // We already emit an E0658 with a suggestion for `while let`, this is
+ // redundant output.
+ err.delay_as_bug();
+ }
+ break;
+ }
+ hir::Node::Item(_)
+ | hir::Node::ImplItem(_)
+ | hir::Node::TraitItem(_)
+ | hir::Node::Crate(_) => break,
+ _ => {
+ parent = self.tcx.hir().get_parent_node(parent);
+ }
+ }
+ }
+
err.emit();
}
} else {
(Applicability::MaybeIncorrect, false)
};
- if !lhs.is_syntactic_place_expr() {
+ if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
let hir = self.tcx.hir();
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
"let ".to_string(),
applicability,
);
- }
+ };
}
if eq {
err.span_suggestion_verbose(
return self.tcx.ty_error();
}
- self.check_lhs_assignable(lhs, "E0070", span);
+ self.check_lhs_assignable(lhs, "E0070", *span);
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
Some(span),
);
} else {
- err.help("methods are immutable and cannot be assigned to");
+ let mut found = false;
+
+ if let ty::RawPtr(ty_and_mut) = expr_t.kind() {
+ if let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() {
+ if adt_def.variants.len() == 1
+ && adt_def
+ .variants
+ .iter()
+ .next()
+ .unwrap()
+ .fields
+ .iter()
+ .any(|f| f.ident == field)
+ {
+ if let Some(dot_loc) = expr_snippet.rfind('.') {
+ found = true;
+ err.span_suggestion(
+ expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
+ "to access the field, dereference first",
+ format!("(*{})", &expr_snippet[0..dot_loc]),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+
+ if !found {
+ err.help("methods are immutable and cannot be assigned to");
+ }
}
err.emit();
// is a valid NeverToAny adjustment, because it can't
// be reached.
(&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
- (&[
- Adjustment { kind: Adjust::Deref(_), .. },
- Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
- ], &[
- Adjustment { kind: Adjust::Deref(_), .. },
- .. // Any following adjustments are allowed.
- ]) => {
+ (
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+ ],
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ .., // Any following adjustments are allowed.
+ ],
+ ) => {
// A reborrow has no effect before a dereference.
}
// FIXME: currently we never try to compose autoderefs
// and ReifyFnPointer/UnsafeFnPointer, but we could.
- _ =>
- bug!("while adjusting {:?}, can't compose {:?} and {:?}",
- expr, entry.get(), adj)
+ _ => bug!(
+ "while adjusting {:?}, can't compose {:?} and {:?}",
+ expr,
+ entry.get(),
+ adj
+ ),
};
*entry.get_mut() = adj;
}
(_, _) => return None,
};
- let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
- let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
-
match (
- &self.tcx.hir().expect_item(last_hir_id).kind,
- &self.tcx.hir().expect_item(exp_hir_id).kind,
+ &self.tcx.hir().expect_item(last_local_id).kind,
+ &self.tcx.hir().expect_item(exp_local_id).kind,
) {
(
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+ if expected_ty == self.tcx.types.bool {
+ // If this is caused by a missing `let` in a `while let`,
+ // silence this redundant error, as we already emit E0070.
+ let parent = self.tcx.hir().get_parent_node(blk.hir_id);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
+ ..
+ })) => {
+ err.delay_as_bug();
+ }
+ _ => {}
+ }
+ }
}
if let Some(fn_span) = fn_span {
err.span_label(
let import_items: Vec<_> = applicable_trait
.import_ids
.iter()
- .map(|&import_id| {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
- self.tcx.hir().expect_item(hir_id)
- })
+ .map(|&import_id| self.tcx.hir().expect_item(import_id))
.collect();
// Find an identifier with which this trait was imported (note that `_` doesn't count).
let mut wf_tys = FxHashSet::default();
// Compute the fty from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- wf_tys.extend(fn_sig.inputs_and_output.iter());
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
return_ty
};
- self.check_lhs_assignable(lhs, "E0067", &op.span);
+ self.check_lhs_assignable(lhs, "E0067", op.span);
ty
}
}
// If we have an autoref followed by unsizing at the end, fix the unsize target.
- if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
- adjustments[..]
+ if let [
+ ..,
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+ Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target },
+ ] = adjustments[..]
{
*target = method.sig.inputs()[0];
}
r
),
(
- l
- @
- (ProjectionKind::Index
+ l @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::Field(..)),
- r
- @
- (ProjectionKind::Index
+ r @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::Field(..)),
/// the types first.
#[instrument(skip(tcx), level = "debug")]
pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id);
debug!(
?item.def_id,
pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, trait_item.def_id, span, method_sig);
- let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
- let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+ let encl_trait_def_id = tcx.hir().get_parent_did(hir_id);
+ let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
let encl_trait_def_id = encl_trait.def_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
}
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let impl_item = tcx.hir().expect_impl_item(hir_id);
+ let impl_item = tcx.hir().expect_impl_item(def_id);
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
);
}
+ // Ensure that the end result is `Sync` in a non-thread local `static`.
+ let should_check_for_sync = tcx.static_mutability(item_id.to_def_id())
+ == Some(hir::Mutability::Not)
+ && !tcx.is_foreign_item(item_id.to_def_id())
+ && !tcx.is_thread_local_static(item_id.to_def_id());
+
+ if should_check_for_sync {
+ fcx.register_bound(
+ item_ty,
+ tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
+ traits::ObligationCause::new(ty_span, fcx.body_id, traits::SharedStatic),
+ );
+ }
+
// No implied bounds in a const, etc.
FxHashSet::default()
});
) {
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
- // Unnormalized types in signature are WF too
- implied_bounds.extend(sig.inputs());
- // FIXME(#27579) return types should not be implied bounds
- implied_bounds.insert(sig.output());
-
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
for extern_crate in &crates_to_lint {
let def_id = extern_crate.def_id.expect_local();
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id);
// If the crate is fully unused, we suggest removing it altogether.
// We do this in any edition.
if extern_crate.warn_if_unused {
if let Some(&span) = unused_extern_crates.get(&def_id) {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, span, |lint| {
// Removal suggestion span needs to include attributes (Issue #54400)
let span_with_attrs = tcx
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
continue;
}
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
// Otherwise, we can convert it into a `use` of some kind.
let base_replacement = match extern_crate.orig_name {
return;
}
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let sp = match tcx.hir().expect_item(impl_hir_id).kind {
+ let sp = match tcx.hir().expect_item(impl_did).kind {
ItemKind::Impl(ref impl_) => impl_.self_ty.span,
_ => bug!("expected Drop impl item"),
};
match can_type_implement_copy(tcx, param_env, self_type) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
tr.path.span
} else {
err.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span =
if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
// this provider should only get invoked for local def-ids
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did.expect_local());
- let span = tcx.hir().span(impl_hir_id);
+ let impl_did = impl_did.expect_local();
+ let span = tcx.def_span(impl_did);
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
tcx.infer_ctxt().enter(|infcx| {
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
let cause = ObligationCause::misc(span, impl_hir_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
.emit();
return err_info;
} else if diff_fields.len() > 1 {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
item.kind
{
t.path.span
} else {
- tcx.hir().span(impl_hir_id)
+ tcx.def_span(impl_did)
};
struct_span_err!(
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default());
+ infcx.resolve_regions_and_report_errors(
+ impl_did.to_def_id(),
+ &outlives_env,
+ RegionckMode::default(),
+ );
CoerceUnsizedInfo { custom_kind: kind }
})
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(self.hir_id()));
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .flat_map(|b| predicates_from_bound(self, ty, b));
+ .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty()));
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
let from_where_clauses = ast_generics
} else {
None
};
+ let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
+
bp.bounds
.iter()
.filter(|b| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .filter_map(move |b| bt.map(|bt| (bt, b)))
+ .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
})
- .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
+ .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
from_ty_params.chain(from_where_clauses).collect()
}
}
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
let (is_auto, unsafety) = match item.kind {
hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().expect_item(hir_id).kind {
+ match tcx.hir().expect_item(def_id.expect_local()).kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
<dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
}
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match &item.kind {
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Negative(span),
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
- astconv.add_bounds(
- param_ty,
- std::array::IntoIter::new([bound]),
- &mut bounds,
- ty::List::empty(),
- );
+ astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
bounds.predicates(astconv.tcx(), param_ty)
}
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_id = tcx.hir().get_parent_did(hir_id);
let parent_item = tcx.hir().expect_item(parent_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(if_let_guard)]
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
let (raw, alloc) = Box::into_raw_with_allocator(self);
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
}
+
+ /// Writes the value and converts to `Box<T, A>`.
+ ///
+ /// This method converts the box similarly to [`Box::assume_init`] but
+ /// writes `value` into it before conversion thus guaranteeing safety.
+ /// In some scenarios use of this method may improve performance because
+ /// the compiler may be able to optimize copying from stack.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(new_uninit)]
+ ///
+ /// let big_box = Box::<[usize; 1024]>::new_uninit();
+ ///
+ /// let mut array = [0; 1024];
+ /// for (i, place) in array.iter_mut().enumerate() {
+ /// *place = i;
+ /// }
+ ///
+ /// // The optimizer may be able to elide this copy, so previous code writes
+ /// // to heap directly.
+ /// let big_box = Box::write(big_box, array);
+ ///
+ /// for (i, x) in big_box.iter().enumerate() {
+ /// assert_eq!(*x, i);
+ /// }
+ /// ```
+ #[unstable(feature = "new_uninit", issue = "63291")]
+ #[inline]
+ pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+ unsafe {
+ (*boxed).write(value);
+ boxed.assume_init()
+ }
+ }
}
impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {
}
impl<A: Allocator> Box<dyn Any, A> {
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
impl<A: Allocator> Box<dyn Any + Send, A> {
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
- #[inline]
- #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
- Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
+ Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
}
}
+ // Double the buffer size. This method is inline(never), so we expect it to only
+ // be called in cold paths.
// This may panic or abort
#[inline(never)]
fn grow(&mut self) {
- if self.is_full() {
- let old_cap = self.cap();
- // Double the buffer size.
- self.buf.reserve_exact(old_cap, old_cap);
- assert!(self.cap() == old_cap * 2);
- unsafe {
- self.handle_capacity_increase(old_cap);
- }
- debug_assert!(!self.is_full());
+ // Extend or possibly remove this assertion when valid use-cases for growing the
+ // buffer without it being full emerge
+ debug_assert!(self.is_full());
+ let old_cap = self.cap();
+ self.buf.reserve_exact(old_cap, old_cap);
+ assert!(self.cap() == old_cap * 2);
+ unsafe {
+ self.handle_capacity_increase(old_cap);
}
+ debug_assert!(!self.is_full());
}
/// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`,
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(inherent_ascii_escape)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
#![feature(iter_zip)]
}
}
+ /// A specialized version of `reserve()` used only by the hot and
+ /// oft-instantiated `Vec::push()`, which does its own capacity check.
+ #[cfg(not(no_global_oom_handling))]
+ #[inline(never)]
+ pub fn reserve_for_push(&mut self, len: usize) {
+ handle_reserve(self.grow_amortized(len, 1));
+ }
+
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
if self.needs_to_grow(len, additional) {
assert!(v.capacity() >= 12 + 12 / 2);
}
}
+
+struct ZST;
+
+// A `RawVec` holding zero-sized elements should always look like this.
+fn zst_sanity<T>(v: &RawVec<T>) {
+ assert_eq!(v.capacity(), usize::MAX);
+ assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
+ assert_eq!(v.current_memory(), None);
+}
+
+#[test]
+fn zst() {
+ let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into());
+
+ assert_eq!(std::mem::size_of::<ZST>(), 0);
+
+ // All these different ways of creating the RawVec produce the same thing.
+
+ let v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ // Check all these operations work as expected with zero-sized elements.
+
+ assert!(!v.needs_to_grow(100, usize::MAX - 100));
+ assert!(v.needs_to_grow(101, usize::MAX - 100));
+ zst_sanity(&v);
+
+ v.reserve(100, usize::MAX - 100);
+ //v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below
+ zst_sanity(&v);
+
+ v.reserve_exact(100, usize::MAX - 100);
+ //v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve(101, usize::MAX - 100);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_exact_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve_exact(101, usize::MAX - 100);
+}
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
- let (first_valid, first_broken) = if let Some(chunk) = iter.next() {
+ let first_valid = if let Some(chunk) = iter.next() {
let lossy::Utf8LossyChunk { valid, broken } = chunk;
- if valid.len() == v.len() {
- debug_assert!(broken.is_empty());
+ if broken.is_empty() {
+ debug_assert_eq!(valid.len(), v.len());
return Cow::Borrowed(valid);
}
- (valid, broken)
+ valid
} else {
return Cow::Borrowed("");
};
let mut res = String::with_capacity(v.len());
res.push_str(first_valid);
- if !first_broken.is_empty() {
- res.push_str(REPLACEMENT);
- }
+ res.push_str(REPLACEMENT);
for lossy::Utf8LossyChunk { valid, broken } in iter {
res.push_str(valid);
// This will panic or abort if we would allocate > isize::MAX bytes
// or if the length increment would overflow for zero-sized types.
if self.len == self.buf.capacity() {
- self.reserve(1);
+ self.buf.reserve_for_push(self.len);
}
unsafe {
let end = self.as_mut_ptr().add(self.len);
assert_eq!(i.advance_by(usize::MAX), Err(0));
+ i.advance_by(0).unwrap();
+ i.advance_back_by(0).unwrap();
+
assert_eq!(i.len(), 0);
}
// > `usize::MAX`)
let new_size = self.size() + pad;
- Layout::from_size_align(new_size, self.align()).unwrap()
+ // SAFETY: self.align is already known to be valid and new_size has been
+ // padded already.
+ unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
}
/// Creates a layout describing the record for `n` instances of
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
- let (layout, offset) = Layout::new::<T>().repeat(n)?;
- debug_assert_eq!(offset, mem::size_of::<T>());
- Ok(layout.pad_to_align())
+ let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
+
+ // SAFETY:
+ // - Size: `array_size` cannot be too big because `size_of::<T>()` must
+ // be a multiple of `align_of::<T>()`. Therefore, `array_size`
+ // rounded up to the nearest multiple of `align_of::<T>()` is just
+ // `array_size`. And `array_size` cannot be too big because it was
+ // just checked by the `checked_mul()`.
+ // - Alignment: `align_of::<T>()` will always give an acceptable
+ // (non-zero, power of two) alignment.
+ Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
}
}
}
impl dyn Any {
- /// Returns `true` if the boxed type is the same as `T`.
+ /// Returns `true` if the inner type is the same as `T`.
///
/// # Examples
///
t == concrete
}
- /// Returns some reference to the boxed value if it is of type `T`, or
+ /// Returns some reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
///
/// # Examples
// SAFETY: just checked whether we are pointing to the correct type, and we can rely on
// that check for memory safety because we have implemented Any for all types; no other
// impls can exist as they would conflict with our impl.
- unsafe { Some(&*(self as *const dyn Any as *const T)) }
+ unsafe { Some(self.downcast_ref_unchecked()) }
} else {
None
}
}
- /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// Returns some mutable reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
///
/// # Examples
// SAFETY: just checked whether we are pointing to the correct type, and we can rely on
// that check for memory safety because we have implemented Any for all types; no other
// impls can exist as they would conflict with our impl.
- unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) }
+ unsafe { Some(self.downcast_mut_unchecked()) }
} else {
None
}
}
+
+ /// Returns a reference to the inner value as type `dyn T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ debug_assert!(self.is::<T>());
+ // SAFETY: caller guarantees that T is the correct type
+ unsafe { &*(self as *const dyn Any as *const T) }
+ }
+
+ /// Returns a mutable reference to the inner value as type `dyn T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ debug_assert!(self.is::<T>());
+ // SAFETY: caller guarantees that T is the correct type
+ unsafe { &mut *(self as *mut dyn Any as *mut T) }
+ }
}
impl dyn Any + Send {
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
<dyn Any>::is::<T>(self)
}
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
<dyn Any>::downcast_ref::<T>(self)
}
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
<dyn Any>::downcast_mut::<T>(self)
}
+
+ /// Forwards to the method defined on the type `dyn Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// Same as the method on the type `dyn Any`.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+ }
+
+ /// Forwards to the method defined on the type `dyn Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// Same as the method on the type `dyn Any`.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+ }
}
impl dyn Any + Send + Sync {
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
<dyn Any>::downcast_mut::<T>(self)
}
+
+ /// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+ }
}
///////////////////////////////////////////////////////////////////////////////
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
use crate::mem::{self, MaybeUninit};
-use crate::ops::{Index, IndexMut};
+use crate::ops::{
+ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
+};
use crate::slice::{Iter, IterMut};
mod equality;
}
/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
-/// Unlike `core::array::from_fn`, where the element creation can't fail, this version will return an error
+/// Unlike [`from_fn`], where the element creation can't fail, this version will return an error
/// if any element creation was unsuccessful.
///
+/// The return type of this function depends on the return type of the closure.
+/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+///
/// # Arguments
///
/// * `cb`: Callback where the passed argument is the current array index.
///
/// ```rust
/// #![feature(array_from_fn)]
+/// # // Apparently these doc tests are still on edition2018
+/// # use std::convert::TryInto;
///
-/// #[derive(Debug, PartialEq)]
-/// enum SomeError {
-/// Foo,
-/// }
-///
-/// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
+/// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
///
-/// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
-/// assert_eq!(another_array, Err(SomeError::Foo));
+/// let array: Result<[i8; 200], _> = std::array::try_from_fn(|i| i.try_into());
+/// assert!(array.is_err());
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_add(100));
+/// assert_eq!(array, Some([100, 101, 102, 103]));
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_sub(100));
+/// assert_eq!(array, None);
/// ```
#[inline]
#[unstable(feature = "array_from_fn", issue = "89379")]
-pub fn try_from_fn<E, F, T, const N: usize>(cb: F) -> Result<[T; N], E>
+pub fn try_from_fn<F, R, const N: usize>(cb: F) -> ChangeOutputType<R, [R::Output; N]>
where
- F: FnMut(usize) -> Result<T, E>,
+ F: FnMut(usize) -> R,
+ R: Try,
+ R::Residual: Residual<[R::Output; N]>,
{
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
- unsafe { collect_into_array_rslt_unchecked(&mut (0..N).map(cb)) }
+ unsafe { try_collect_into_array_unchecked(&mut (0..N).map(cb)) }
}
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
}
}
-#[cfg(not(bootstrap))]
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
impl<T: Copy, const N: usize> Copy for [T; N] {}
-#[cfg(not(bootstrap))]
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
impl<T: Clone, const N: usize> Clone for [T; N] {
#[inline]
}
}
-#[cfg(not(bootstrap))]
trait SpecArrayClone: Clone {
fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
}
-#[cfg(not(bootstrap))]
impl<T: Clone> SpecArrayClone for T {
#[inline]
default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
}
}
-#[cfg(not(bootstrap))]
impl<T: Copy> SpecArrayClone for T {
#[inline]
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
}
+ /// A fallible function `f` applied to each element on array `self` in order to
+ /// return an array the same size as `self` or the first error encountered.
+ ///
+ /// The return type of this function depends on the return type of the closure.
+ /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+ /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_try_map)]
+ /// let a = ["1", "2", "3"];
+ /// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
+ /// assert_eq!(b, [2, 3, 4]);
+ ///
+ /// let a = ["1", "2a", "3"];
+ /// let b = a.try_map(|v| v.parse::<u32>());
+ /// assert!(b.is_err());
+ ///
+ /// use std::num::NonZeroU32;
+ /// let z = [1, 2, 0, 3, 4];
+ /// assert_eq!(z.try_map(NonZeroU32::new), None);
+ /// let a = [1, 2, 3];
+ /// let b = a.try_map(NonZeroU32::new);
+ /// let c = b.map(|x| x.map(NonZeroU32::get));
+ /// assert_eq!(c, Some(a));
+ /// ```
+ #[unstable(feature = "array_try_map", issue = "79711")]
+ pub fn try_map<F, R>(self, f: F) -> ChangeOutputType<R, [R::Output; N]>
+ where
+ F: FnMut(T) -> R,
+ R: Try,
+ R::Residual: Residual<[R::Output; N]>,
+ {
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
+ // items.
+ unsafe { try_collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
+ }
+
/// 'Zips up' two arrays into a single array of pairs.
///
/// `zip()` returns a new array where every element is a tuple where the
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, this function exhibits undefined behavior.
///
-/// See [`collect_into_array`] for more information.
+/// See [`try_collect_into_array`] for more information.
///
///
/// # Safety
///
/// It is up to the caller to guarantee that `iter` yields at least `N` items.
/// Violating this condition causes undefined behavior.
-unsafe fn collect_into_array_rslt_unchecked<E, I, T, const N: usize>(
- iter: &mut I,
-) -> Result<[T; N], E>
+unsafe fn try_collect_into_array_unchecked<I, T, R, const N: usize>(iter: &mut I) -> R::TryType
where
// Note: `TrustedLen` here is somewhat of an experiment. This is just an
// internal function, so feel free to remove if this bound turns out to be a
// bad idea. In that case, remember to also remove the lower bound
// `debug_assert!` below!
- I: Iterator<Item = Result<T, E>> + TrustedLen,
+ I: Iterator + TrustedLen,
+ I::Item: Try<Output = T, Residual = R>,
+ R: Residual<[T; N]>,
{
debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
debug_assert!(N <= iter.size_hint().0);
// SAFETY: covered by the function contract.
- unsafe { collect_into_array(iter).unwrap_unchecked() }
+ unsafe { try_collect_into_array(iter).unwrap_unchecked() }
}
-// Infallible version of `collect_into_array_rslt_unchecked`.
+// Infallible version of `try_collect_into_array_unchecked`.
unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
where
I: Iterator + TrustedLen,
{
- let mut map = iter.map(Ok::<_, Infallible>);
+ let mut map = iter.map(NeverShortCircuit);
// SAFETY: The same safety considerations w.r.t. the iterator length
- // apply for `collect_into_array_rslt_unchecked` as for
+ // apply for `try_collect_into_array_unchecked` as for
// `collect_into_array_unchecked`
- match unsafe { collect_into_array_rslt_unchecked(&mut map) } {
- Ok(array) => array,
+ match unsafe { try_collect_into_array_unchecked(&mut map) } {
+ NeverShortCircuit(array) => array,
}
}
///
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
-fn collect_into_array<E, I, T, const N: usize>(iter: &mut I) -> Option<Result<[T; N], E>>
+fn try_collect_into_array<I, T, R, const N: usize>(iter: &mut I) -> Option<R::TryType>
where
- I: Iterator<Item = Result<T, E>>,
+ I: Iterator,
+ I::Item: Try<Output = T, Residual = R>,
+ R: Residual<[T; N]>,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
- return unsafe { Some(Ok(mem::zeroed())) };
+ return unsafe { Some(Try::from_output(mem::zeroed())) };
}
struct Guard<'a, T, const N: usize> {
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
while let Some(item_rslt) = iter.next() {
- let item = match item_rslt {
- Err(err) => {
- return Some(Err(err));
+ let item = match item_rslt.branch() {
+ ControlFlow::Break(r) => {
+ return Some(FromResidual::from_residual(r));
}
- Ok(elem) => elem,
+ ControlFlow::Continue(elem) => elem,
};
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
// SAFETY: the condition above asserts that all elements are
// initialized.
let out = unsafe { MaybeUninit::array_assume_init(array) };
- return Some(Ok(out));
+ return Some(Try::from_output(out));
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Pointer for *const T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- let old_width = f.width;
- let old_flags = f.flags;
-
- // The alternate flag is already treated by LowerHex as being special-
- // it denotes whether to prefix with 0x. We use it to work out whether
- // or not to zero extend, and then unconditionally set it to get the
- // prefix.
- if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
-
- if f.width.is_none() {
- f.width = Some((usize::BITS / 4) as usize + 2);
+ /// Since the formatting will be identical for all pointer types, use a non-monomorphized
+ /// implementation for the actual formatting to reduce the amount of codegen work needed
+ fn inner(ptr: *const (), f: &mut Formatter<'_>) -> Result {
+ let old_width = f.width;
+ let old_flags = f.flags;
+
+ // The alternate flag is already treated by LowerHex as being special-
+ // it denotes whether to prefix with 0x. We use it to work out whether
+ // or not to zero extend, and then unconditionally set it to get the
+ // prefix.
+ if f.alternate() {
+ f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
+
+ if f.width.is_none() {
+ f.width = Some((usize::BITS / 4) as usize + 2);
+ }
}
- }
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ f.flags |= 1 << (FlagV1::Alternate as u32);
+
+ let ret = LowerHex::fmt(&(ptr as usize), f);
- let ret = LowerHex::fmt(&(*self as *const () as usize), f);
+ f.width = old_width;
+ f.flags = old_flags;
- f.width = old_width;
- f.flags = old_flags;
+ ret
+ }
- ret
+ inner(*self as *const (), f)
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
#[lang = "future_trait"]
-#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
+#[rustc_on_unimplemented(
+ label = "`{Self}` is not a future",
+ message = "`{Self}` is not a future",
+ note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
+)]
pub trait Future {
/// The type of value produced on completion.
#[stable(feature = "futures_api", since = "1.36.0")]
/// Creates a future from a value.
#[unstable(feature = "into_future", issue = "67644")]
+ #[cfg_attr(not(bootstrap), lang = "into_future")]
fn into_future(self) -> Self::Future;
}
/// `0xFF` byte to the `Hasher` so that the values `("ab", "c")` and `("a",
/// "bc")` hash differently.
///
+/// ## Portability
+///
+/// Due to differences in endianness and type sizes, data fed by `Hash` to a `Hasher`
+/// should not be considered portable across platforms. Additionally the data passed by most
+/// standard library types should not be considered stable between compiler versions.
+///
+/// This means tests shouldn't probe hard-coded hash values or data fed to a `Hasher` and
+/// instead should check consistency with `Eq`.
+///
+/// Serialization formats intended to be portable between platforms or compiler versions should
+/// either avoid encoding hashes or only rely on `Hash` and `Hasher` implementations that
+/// provide additional guarantees.
+///
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`hash`]: Hash::hash
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_unstable(feature = "const_assert_type", issue = "none")]
+ #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
pub fn assert_inhabited<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` does not permit
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_zero_valid<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` has invalid
/// bit patterns: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_uninit_valid<T>();
/// Gets a reference to a static `Location` indicating where it was called.
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
-
let step_one = self.n.saturating_add(rem);
+
match self.iter.advance_by(step_one) {
Ok(_) => {
rem -= step_one - self.n;
Err(advanced) => {
let advanced_without_skip = advanced.saturating_sub(self.n);
self.n = self.n.saturating_sub(advanced);
- return Err(advanced_without_skip);
+ return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
}
}
}
#[inline]
+ #[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let inner_len = self.iter.len();
- let len = self.n;
- let remainder = len.saturating_sub(n);
- let to_advance = inner_len - remainder;
- match self.iter.advance_back_by(to_advance) {
- Ok(_) => {
- self.n = remainder;
- if n > len {
- return Err(len);
- }
- return Ok(());
- }
- _ => panic!("ExactSizeIterator contract violation"),
- }
+ // The amount by which the inner iterator needs to be shortened for it to be
+ // at most as long as the take() amount.
+ let trim_inner = self.iter.len().saturating_sub(self.n);
+ // The amount we need to advance inner to fulfill the caller's request.
+ // take(), advance_by() and len() all can be at most usize, so we don't have to worry
+ // about having to advance more than usize::MAX here.
+ let advance_by = trim_inner.saturating_add(n);
+
+ let advanced = match self.iter.advance_back_by(advance_by) {
+ Ok(_) => advance_by - trim_inner,
+ Err(advanced) => advanced - trim_inner,
+ };
+ self.n -= advanced;
+ return if advanced < n { Err(advanced) } else { Ok(()) };
}
}
/// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
/// outer iterator until it finds an inner iterator that is not empty, which then often
/// allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_back_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next_back`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`advance_by`]: Iterator::advance_by
/// [`Flatten`]: crate::iter::Flatten
use crate::cmp::{self, Ordering};
-use crate::ops::{ControlFlow, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
use super::super::TrustedRandomAccessNoCoerce;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
/// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
/// can advance its outer iterator until it finds an inner iterator that is not empty, which
/// then often allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`Flatten`]: crate::iter::Flatten
/// [`next`]: Iterator::next
/// In other words, it zips two iterators together, into a single one.
///
/// If either iterator returns [`None`], [`next`] from the zipped iterator
- /// will return [`None`]. If the first iterator returns [`None`], `zip` will
- /// short-circuit and `next` will not be called on the second iterator.
+ /// will return [`None`].
+ /// If the zipped iterator has no more elements to return then each further attempt to advance
+ /// it will first try to advance the first iterator at most one time and if it still yielded an item
+ /// try to advance the second iterator at most one time.
///
/// # Examples
///
/// assert_eq!(iter.next(), None);
/// ```
#[inline]
+ #[doc(alias = "drop_while")]
#[stable(feature = "rust1", since = "1.0.0")]
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where
/// Applies function to the elements of iterator and returns
/// the first true result or the first error.
///
+ /// The return type of this method depends on the return type of the closure.
+ /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>; E>`.
+ /// If you return `Option<bool>` from the closure, you'll get an `Option<Option<Self::Item>>`.
+ ///
/// # Examples
///
/// ```
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
/// assert!(result.is_err());
/// ```
+ ///
+ /// This also supports other types which implement `Try`, not just `Result`.
+ /// ```
+ /// #![feature(try_find)]
+ ///
+ /// use std::num::NonZeroU32;
+ /// let a = [3, 5, 7, 4, 9, 0, 11];
+ /// let result = a.iter().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, Some(Some(&4)));
+ /// let result = a.iter().take(3).try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, Some(None));
+ /// let result = a.iter().rev().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, None);
+ /// ```
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
- fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
+ fn try_find<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<Self::Item>>
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
R: Try<Output = bool>,
- // FIXME: This bound is rather strange, but means minimal breakage on nightly.
- // See #85115 for the issue tracking a holistic solution for this and try_map.
- R: Try<Residual = Result<crate::convert::Infallible, E>>,
+ R::Residual: Residual<Option<Self::Item>>,
{
#[inline]
- fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
+ fn check<I, V, R>(
+ mut f: impl FnMut(&I) -> V,
+ ) -> impl FnMut((), I) -> ControlFlow<R::TryType>
where
- F: FnMut(&T) -> R,
- R: Try<Output = bool>,
- R: Try<Residual = Result<crate::convert::Infallible, E>>,
+ V: Try<Output = bool, Residual = R>,
+ R: Residual<Option<I>>,
{
move |(), x| match f(&x).branch() {
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
- ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
- ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
+ ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))),
+ ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)),
}
}
- self.try_fold((), check(f)).break_value().transpose()
+ match self.try_fold((), check(f)) {
+ ControlFlow::Break(x) => x,
+ ControlFlow::Continue(()) => Try::from_output(None),
+ }
}
/// Searches for an element in an iterator, returning its index.
#![feature(const_align_of_val)]
#![feature(const_alloc_layout)]
#![feature(const_arguments_as_str)]
-#![feature(const_assert_type)]
#![feature(const_bigint_helper_methods)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_intrinsic_copy)]
#![feature(const_intrinsic_forget)]
#![feature(const_likely)]
-#![feature(const_maybe_uninit_as_ptr)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_num_from_num)]
#![feature(const_ops)]
#![feature(const_impl_trait)]
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
#![feature(const_refs_to_cell)]
#![feature(decl_macro)]
#![feature(derive_default_enum)]
#![feature(doc_cfg)]
#![feature(doc_notable_trait)]
-#![cfg_attr(bootstrap, feature(doc_primitive))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![feature(rustdoc_internals)]
#![feature(exhaustive_patterns)]
#![feature(doc_cfg_hide)]
#![feature(extern_types)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
-#![cfg_attr(not(bootstrap), feature(asm_const))]
+#![feature(asm_const)]
//
// Target features:
#![feature(aarch64_target_feature)]
#[allow(rustdoc::bare_urls)]
#[unstable(feature = "portable_simd", issue = "86656")]
#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
-#[cfg(not(bootstrap))]
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)))] // Miri does not support all SIMD intrinsics
-#[cfg(not(bootstrap))]
pub mod simd {
#[unstable(feature = "portable_simd", issue = "86656")]
pub use crate::core_simd::simd::*;
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_as_mut_ptr", issue = "75251")]
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
#[inline(always)]
#[rustc_diagnostic_item = "assume_init"]
#[track_caller]
/// }
/// ```
#[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
#[inline(always)]
pub const unsafe fn assume_init_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` is initialized.
///
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
// SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
/// Basic usage:
///
/// ```
- /// #![feature(nonzero_is_power_of_two)]
- ///
#[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
/// assert!(eight.is_power_of_two());
#[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
/// assert!(!ten.is_power_of_two());
/// ```
#[must_use]
- #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
+ #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
#[inline]
pub const fn is_power_of_two(self) -> bool {
// LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
}
}
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+ type TryType = ControlFlow<B, C>;
+}
+
impl<B, C> ControlFlow<B, C> {
/// Returns `true` if this is a `Break` variant.
///
/// `return` statement or implicitly as the last expression of a generator
/// literal. For example futures would use this as `Result<T, E>` as it
/// represents a completed future.
+ #[lang = "generator_return"]
type Return;
/// Resumes the execution of this generator.
#[stable(feature = "inclusive_range", since = "1.26.0")]
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
+#[unstable(feature = "one_sided_range", issue = "69780")]
+pub use self::range::OneSidedRange;
+
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub use self::try_trait::{FromResidual, Try};
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub use self::try_trait::Residual;
+
+pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
+
#[unstable(feature = "generator_trait", issue = "43122")]
pub use self::generator::{Generator, GeneratorState};
Included(self.end)
}
}
+
+/// `OneSidedRange` is implemented for built-in range types that are unbounded
+/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`,
+/// but `..`, `d..e`, and `f..=g` do not.
+///
+/// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
+/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
+#[unstable(feature = "one_sided_range", issue = "69780")]
+pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}
#[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_residual(residual: R) -> Self;
}
+
+/// Allows retrieving the canonical type implementing [`Try`] that has this type
+/// as its residual and allows it to hold an `O` as its output.
+///
+/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
+/// and [`Try::Residual`] components, this allows putting them back together.
+///
+/// For example,
+/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
+/// and in the other direction,
+/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub trait Residual<O> {
+ /// The "return" type of this meta-function.
+ #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+ type TryType: Try<Output = O, Residual = Self>;
+}
+
+#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
+pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::TryType;
+
+/// An adapter for implementing non-try methods via the `Try` implementation.
+///
+/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
+/// solving and inhabited-ness checking and such, by being an obvious newtype
+/// and not having `From` bounds lying around.
+///
+/// Not currently planned to be exposed publicly, so just `pub(crate)`.
+#[repr(transparent)]
+pub(crate) struct NeverShortCircuit<T>(pub T);
+
+pub(crate) enum NeverShortCircuitResidual {}
+
+impl<T> Try for NeverShortCircuit<T> {
+ type Output = T;
+ type Residual = NeverShortCircuitResidual;
+
+ #[inline]
+ fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
+ ControlFlow::Continue(self.0)
+ }
+
+ #[inline]
+ fn from_output(x: T) -> Self {
+ NeverShortCircuit(x)
+ }
+}
+
+impl<T> FromResidual for NeverShortCircuit<T> {
+ #[inline]
+ fn from_residual(never: NeverShortCircuitResidual) -> Self {
+ match never {}
+ }
+}
+
+impl<T> Residual<T> for NeverShortCircuitResidual {
+ type TryType = NeverShortCircuit<T>;
+}
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn expect(self, msg: &str) -> T {
+ #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+ pub const fn expect(self, msg: &str) -> T {
match self {
Some(val) => val,
None => expect_failed(msg),
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Some`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let v = vec![1, 2, 3, 4, 5];
+ ///
+ /// // prints "got: 4"
+ /// 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));
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+ if let Some(ref x) = self {
+ f(x);
+ }
+
+ self
+ }
+
/// Returns the provided default result (if none),
/// or applies a function to the contained value (if any).
///
#[inline(never)]
#[cold]
#[track_caller]
-fn expect_failed(msg: &str) -> ! {
+const fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}
}
}
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T> ops::Residual<T> for Option<convert::Infallible> {
+ type TryType = Option<T>;
+}
+
impl<T> Option<Option<T>> {
/// Converts from `Option<Option<T>>` to `Option<T>`.
///
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Ok`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let x: u8 = "4"
+ /// .parse::<u8>()
+ /// .inspect(|x| println!("original: {}", x))
+ /// .map(|x| x.pow(3))
+ /// .expect("failed to parse number");
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+ if let Ok(ref t) = self {
+ f(t);
+ }
+
+ self
+ }
+
+ /// Calls the provided closure with a reference to the contained error (if [`Err`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// use std::{fs, io};
+ ///
+ /// fn read() -> io::Result<String> {
+ /// fs::read_to_string("address.txt")
+ /// .inspect_err(|e| eprintln!("failed to read file: {}", e))
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self {
+ if let Err(ref e) = self {
+ f(e);
+ }
+
+ self
+ }
+
/////////////////////////////////////////////////////////////////////////
// Iterator constructors
/////////////////////////////////////////////////////////////////////////
}
}
}
+
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
+ type TryType = Result<T, E>;
+}
use crate::marker::Copy;
use crate::mem;
use crate::num::NonZeroUsize;
-use crate::ops::{FnMut, Range, RangeBounds};
+use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
use crate::option::Option;
use crate::option::Option::{None, Some};
use crate::ptr;
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
pub use ascii::EscapeAscii;
+/// Calculates the direction and split point of a one-sided range.
+///
+/// This is a helper function for `take` and `take_mut` that returns
+/// the direction of the split (front or back) as well as the index at
+/// which to split. Returns `None` if the split index would overflow.
+#[inline]
+fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> {
+ use Bound::*;
+
+ Some(match (range.start_bound(), range.end_bound()) {
+ (Unbounded, Excluded(i)) => (Direction::Front, *i),
+ (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?),
+ (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?),
+ (Included(i), Unbounded) => (Direction::Back, *i),
+ _ => unreachable!(),
+ })
+}
+
+enum Direction {
+ Front,
+ Back,
+}
+
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
{
self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
}
+
+ /// Removes the subslice corresponding to the given range
+ /// and returns a reference to it.
+ ///
+ /// Returns `None` and does not modify the slice if the given
+ /// range is out of bounds.
+ ///
+ /// Note that this method only accepts one-sided ranges such as
+ /// `2..` or `..6`, but not `2..6`.
+ ///
+ /// # Examples
+ ///
+ /// Taking the first three elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ /// let mut first_three = slice.take(..3).unwrap();
+ ///
+ /// assert_eq!(slice, &['d']);
+ /// assert_eq!(first_three, &['a', 'b', 'c']);
+ /// ```
+ ///
+ /// Taking the last two elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ /// let mut tail = slice.take(2..).unwrap();
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(tail, &['c', 'd']);
+ /// ```
+ ///
+ /// Getting `None` when `range` is out of bounds:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ ///
+ /// assert_eq!(None, slice.take(5..));
+ /// assert_eq!(None, slice.take(..5));
+ /// assert_eq!(None, slice.take(..=4));
+ /// let expected: &[char] = &['a', 'b', 'c', 'd'];
+ /// assert_eq!(Some(expected), slice.take(..4));
+ /// ```
+ #[inline]
+ #[must_use = "method does not modify the slice if the range is out of bounds"]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
+ let (direction, split_index) = split_point_of(range)?;
+ if split_index > self.len() {
+ return None;
+ }
+ let (front, back) = self.split_at(split_index);
+ match direction {
+ Direction::Front => {
+ *self = back;
+ Some(front)
+ }
+ Direction::Back => {
+ *self = front;
+ Some(back)
+ }
+ }
+ }
+
+ /// Removes the subslice corresponding to the given range
+ /// and returns a mutable reference to it.
+ ///
+ /// Returns `None` and does not modify the slice if the given
+ /// range is out of bounds.
+ ///
+ /// Note that this method only accepts one-sided ranges such as
+ /// `2..` or `..6`, but not `2..6`.
+ ///
+ /// # Examples
+ ///
+ /// Taking the first three elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// let mut first_three = slice.take_mut(..3).unwrap();
+ ///
+ /// assert_eq!(slice, &mut ['d']);
+ /// assert_eq!(first_three, &mut ['a', 'b', 'c']);
+ /// ```
+ ///
+ /// Taking the last two elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// let mut tail = slice.take_mut(2..).unwrap();
+ ///
+ /// assert_eq!(slice, &mut ['a', 'b']);
+ /// assert_eq!(tail, &mut ['c', 'd']);
+ /// ```
+ ///
+ /// Getting `None` when `range` is out of bounds:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ ///
+ /// assert_eq!(None, slice.take_mut(5..));
+ /// assert_eq!(None, slice.take_mut(..5));
+ /// assert_eq!(None, slice.take_mut(..=4));
+ /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// assert_eq!(Some(expected), slice.take_mut(..4));
+ /// ```
+ #[inline]
+ #[must_use = "method does not modify the slice if the range is out of bounds"]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_mut<'a, R: OneSidedRange<usize>>(
+ self: &mut &'a mut Self,
+ range: R,
+ ) -> Option<&'a mut Self> {
+ let (direction, split_index) = split_point_of(range)?;
+ if split_index > self.len() {
+ return None;
+ }
+ let (front, back) = mem::take(self).split_at_mut(split_index);
+ match direction {
+ Direction::Front => {
+ *self = back;
+ Some(front)
+ }
+ Direction::Back => {
+ *self = front;
+ Some(back)
+ }
+ }
+ }
+
+ /// Removes the first element of the slice and returns a reference
+ /// to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c'];
+ /// let first = slice.take_first().unwrap();
+ ///
+ /// assert_eq!(slice, &['b', 'c']);
+ /// assert_eq!(first, &'a');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
+ let (first, rem) = self.split_first()?;
+ *self = rem;
+ Some(first)
+ }
+
+ /// Removes the first element of the slice and returns a mutable
+ /// reference to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+ /// let first = slice.take_first_mut().unwrap();
+ /// *first = 'd';
+ ///
+ /// assert_eq!(slice, &['b', 'c']);
+ /// assert_eq!(first, &'d');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
+ let (first, rem) = mem::take(self).split_first_mut()?;
+ *self = rem;
+ Some(first)
+ }
+
+ /// Removes the last element of the slice and returns a reference
+ /// to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c'];
+ /// let last = slice.take_last().unwrap();
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(last, &'c');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
+ let (last, rem) = self.split_last()?;
+ *self = rem;
+ Some(last)
+ }
+
+ /// Removes the last element of the slice and returns a mutable
+ /// reference to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+ /// let last = slice.take_last_mut().unwrap();
+ /// *last = 'd';
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(last, &'d');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
+ let (last, rem) = mem::take(self).split_last_mut()?;
+ *self = rem;
+ Some(last)
+ }
}
trait CloneFromSpec<T> {
}
// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
-#[cfg(all(not(bootstrap), debug_assertions))]
+#[cfg(debug_assertions)]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
);
}
-#[cfg(not(all(not(bootstrap), debug_assertions)))]
+#[cfg(not(debug_assertions))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
/// Converts a reference to T into a slice of length 1 (without copying).
}
let mut i = 0;
+ let mut valid_up_to = 0;
while i < self.source.len() {
- let i_ = i;
-
- // SAFETY: `i` starts at `0`, is less than `self.source.len()`, and
- // only increases, so `0 <= i < self.source.len()`.
+ // SAFETY: `i < self.source.len()` per previous line.
+ // For some reason the following are both significantly slower:
+ // while let Some(&byte) = self.source.get(i) {
+ // while let Some(byte) = self.source.get(i).copied() {
let byte = unsafe { *self.source.get_unchecked(i) };
i += 1;
if byte < 128 {
+ // This could be a `1 => ...` case in the match below, but for
+ // the common case of all-ASCII inputs, we bypass loading the
+ // sizeable UTF8_CHAR_WIDTH table into cache.
} else {
let w = utf8_char_width(byte);
- macro_rules! error {
- () => {{
- // SAFETY: We have checked up to `i` that source is valid UTF-8.
- unsafe {
- let r = Utf8LossyChunk {
- valid: from_utf8_unchecked(&self.source[0..i_]),
- broken: &self.source[i_..i],
- };
- self.source = &self.source[i..];
- return Some(r);
- }
- }};
- }
-
match w {
2 => {
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
(0xE1..=0xEC, 0x80..=0xBF) => (),
(0xED, 0x80..=0x9F) => (),
(0xEE..=0xEF, 0x80..=0xBF) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
(0xF0, 0x90..=0xBF) => (),
(0xF1..=0xF3, 0x80..=0xBF) => (),
(0xF4, 0x80..=0x8F) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
- _ => {
- error!();
- }
+ _ => break,
}
}
+
+ valid_up_to = i;
}
- let r = Utf8LossyChunk {
- // SAFETY: We have checked that the entire source is valid UTF-8.
- valid: unsafe { from_utf8_unchecked(self.source) },
- broken: &[],
- };
- self.source = &[];
- Some(r)
+ // SAFETY: `i <= self.source.len()` because it is only ever incremented
+ // via `i += 1` and in between every single one of those increments, `i`
+ // is compared against `self.source.len()`. That happens either
+ // literally by `i < self.source.len()` in the while-loop's condition,
+ // or indirectly by `safe_get(self.source, i) & 192 != TAG_CONT_U8`. The
+ // loop is terminated as soon as the latest `i += 1` has made `i` no
+ // longer less than `self.source.len()`, which means it'll be at most
+ // equal to `self.source.len()`.
+ let (inspected, remaining) = unsafe { self.source.split_at_unchecked(i) };
+ self.source = remaining;
+
+ // SAFETY: `valid_up_to <= i` because it is only ever assigned via
+ // `valid_up_to = i` and `i` only increases.
+ let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) };
+
+ Some(Utf8LossyChunk {
+ // SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
+ valid: unsafe { from_utf8_unchecked(valid) },
+ broken,
+ })
}
}
// https://tools.ietf.org/html/rfc3629
const UTF8_CHAR_WIDTH: &[u8; 256] = &[
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x1F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x3F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x5F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x7F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0x9F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0xBF
- 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, // 0xDF
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
- 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
+ // 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E
+ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
];
/// Given a first byte, determines how many bytes are in this UTF-8 character.
#[inline]
#[must_use]
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_panic))]
pub const fn new(secs: u64, nanos: u32) -> Duration {
let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(secs) => secs,
without modifying the original"]
#[inline]
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_panic))]
pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
let mut nanos = self.nanos + rhs.nanos;
without modifying the original"]
#[inline]
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_panic))]
pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
let nanos = if self.nanos >= rhs.nanos {
without modifying the original"]
#[inline]
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_panic))]
pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
// Multiply nanoseconds as u64, because it cannot overflow that way.
let total_nanos = self.nanos as u64 * rhs as u64;
without modifying the original"]
#[inline]
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_panic))]
pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
if rhs != 0 {
let secs = self.secs / (rhs as u64);
let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
assert_eq!(array, Ok([0, 1, 2, 3, 4]));
- let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
+ let another_array = core::array::try_from_fn::<_, Result<(), _>, 2>(|_| Err(SomeError::Foo));
assert_eq!(another_array, Err(SomeError::Foo));
}
iter.advance_by(i).unwrap();
assert_eq!(iter.next(), Some(&xs[i]));
assert_eq!(iter.advance_by(100), Err(len - i - 1));
+ iter.advance_by(0).unwrap();
}
for i in 0..ys.len() {
iter.advance_by(xs.len() + i).unwrap();
assert_eq!(iter.next(), Some(&ys[i]));
assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+ iter.advance_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_by(len).unwrap();
assert_eq!(iter.next(), None);
+ iter.advance_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_by(len + 1), Err(len));
+ iter.advance_by(0).unwrap();
}
test_chain(&[], &[]);
iter.advance_back_by(i).unwrap();
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+ iter.advance_back_by(0).unwrap();
}
for i in 0..xs.len() {
iter.advance_back_by(ys.len() + i).unwrap();
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+ iter.advance_back_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_back_by(len).unwrap();
assert_eq!(iter.next_back(), None);
+ iter.advance_back_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_back_by(len + 1), Err(len));
+ iter.advance_back_by(0).unwrap();
}
test_chain(&[], &[]);
#[test]
fn test_flatten_advance_by() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
+
it.advance_by(5).unwrap();
assert_eq!(it.next(), Some(5));
it.advance_by(9).unwrap();
assert_eq!(it.advance_by(usize::MAX), Err(9));
assert_eq!(it.advance_back_by(usize::MAX), Err(0));
+ it.advance_by(0).unwrap();
+ it.advance_back_by(0).unwrap();
assert_eq!(it.size_hint(), (0, Some(0)));
}
assert_eq!(it.nth(0), None);
}
+#[test]
+fn test_skip_advance_by() {
+ assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).skip(10).advance_by(1), Err(0));
+ assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
+ assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
+
+ assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
+}
+
#[test]
fn test_iterator_skip_count() {
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
assert_eq!(it.nth_back(1), None);
}
+#[test]
+fn test_take_advance_by() {
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_by(2), Ok(()));
+ assert_eq!(take.next(), Some(2));
+ assert_eq!(take.advance_by(1), Err(0));
+
+ assert_eq!((0..0).take(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).take(10).advance_by(1), Err(0));
+ assert_eq!((0..10).take(4).advance_by(5), Err(4));
+
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_back_by(2), Ok(()));
+ assert_eq!(take.next(), Some(0));
+ assert_eq!(take.advance_back_by(1), Err(0));
+
+ assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
+ assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
+ assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
+}
+
#[test]
fn test_iterator_take_short() {
let xs = [0, 1, 2, 3];
assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
+ r.advance_by(0).unwrap();
+ r.advance_back_by(0).unwrap();
+
let mut r = 0u128..u128::MAX;
r.advance_by(usize::MAX).unwrap();
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(pattern)]
#![feature(sort_internals)]
#![feature(slice_partition_at_index)]
+#![feature(slice_take)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_extra)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
#![feature(const_slice_from_raw_parts)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(result_into_ok_or_err)]
-#![cfg_attr(not(bootstrap), feature(portable_simd))]
+#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
#![feature(unsized_tuple_coercion)]
mod pin;
mod ptr;
mod result;
-#[cfg(not(bootstrap))]
mod simd;
mod slice;
mod str;
const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
assert_eq!(FOO, 42);
}
+
+#[test]
+fn const_maybe_uninit() {
+ use std::ptr;
+
+ #[derive(Debug, PartialEq)]
+ struct Foo {
+ x: u8,
+ y: u8,
+ }
+
+ const FIELD_BY_FIELD: Foo = unsafe {
+ let mut val = MaybeUninit::uninit();
+ init_y(&mut val); // order shouldn't matter
+ init_x(&mut val);
+ val.assume_init()
+ };
+
+ const fn init_x(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1;
+ }
+ }
+
+ const fn init_y(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2;
+ }
+ }
+
+ assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
+}
assert_eq!(iter.as_slice(), &v[3..]);
iter.advance_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_by(0).unwrap();
}
#[test]
assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
iter.advance_back_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_back_by(0).unwrap();
}
#[test]
v.split_array_mut::<7>();
}
+
+macro_rules! take_tests {
+ (slice: &[], $($tts:tt)*) => {
+ take_tests!(ty: &[()], slice: &[], $($tts)*);
+ };
+ (slice: &mut [], $($tts:tt)*) => {
+ take_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
+ };
+ (slice: &$slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &[_], slice: &$slice, $($tts)*);
+ };
+ (slice: &mut $slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
+ };
+ (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => {
+ $(
+ #[test]
+ fn $test_name() {
+ let mut slice: $ty = $slice;
+ assert_eq!($output, slice.$method($($args)*));
+ let remaining: $ty = $remaining;
+ assert_eq!(remaining, slice);
+ }
+ )*
+ };
+}
+
+take_tests! {
+ slice: &[0, 1, 2, 3], method: take,
+ (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
+ (take_oob_range_to, (..5), None, &[0, 1, 2, 3]),
+ (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
+ (take_oob_range_from, (5..), None, &[0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &mut [0, 1, 2, 3], method: take_mut,
+ (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
+ (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_first,
+ (take_first_nonempty, (), Some(&1), &[2]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_first_mut,
+ (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_last,
+ (take_last_nonempty, (), Some(&2), &[1]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_last_mut,
+ (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
+}
+
+take_tests! {
+ slice: &[], method: take_first,
+ (take_first_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_first_mut,
+ (take_first_mut_empty, (), None, &mut []),
+}
+
+take_tests! {
+ slice: &[], method: take_last,
+ (take_last_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_last_mut,
+ (take_last_mut_empty, (), None, &mut []),
+}
+
+const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
+
+// can't be a constant due to const mutability rules
+macro_rules! empty_max_mut {
+ () => {
+ &mut [(); usize::MAX] as _
+ };
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &[(); usize::MAX], method: take,
+ (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
+ (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
+ (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &mut [(); usize::MAX], method: take_mut,
+ (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
+ (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+ (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+}
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.52" }
+libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.55" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
/// `GetLastError` on Windows) and will return a corresponding instance of
/// [`Error`] for the error code.
///
+ /// This should be called immediately after a call to a platform function,
+ /// otherwise the state of the error value is indeterminate. In particular,
+ /// other standard library functions may call platform functions that may
+ /// (or may not) reset the error value even if they succeed.
+ ///
/// # Examples
///
/// ```
/// use std::io::Error;
///
- /// println!("last OS error: {:?}", Error::last_os_error());
+ /// let os_error = Error::last_os_error();
+ /// println!("last OS error: {:?}", os_error);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#![feature(const_ipv4)]
#![feature(const_ipv6)]
#![feature(const_option)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
-#![cfg_attr(not(bootstrap), feature(const_mut_refs))]
+#![feature(const_mut_refs)]
#![feature(const_socketaddr)]
#![feature(const_trait_impl)]
#![feature(container_error_extra)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
-#![cfg_attr(bootstrap, feature(doc_primitive))]
-#![cfg_attr(bootstrap, feature(doc_keyword))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![feature(rustdoc_internals)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
-#![cfg_attr(not(bootstrap), feature(portable_simd))]
+#![feature(portable_simd)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(bootstrap))]
pub use core::simd;
#[unstable(feature = "async_stream", issue = "79024")]
pub use core::stream;
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
//! [`PathBuf`]; note that the paths may differ syntactically by the
//! normalization described in the documentation for the [`components`] method.
//!
+//! ## Case sensitivity
+//!
+//! Unless otherwise indicated path methods that do not access the filesystem,
+//! such as [`Path::starts_with`] and [`Path::ends_with`], are case sensitive no
+//! matter the platform or filesystem. An exception to this is made for Windows
+//! drive letters.
+//!
//! ## Simple usage
//!
//! Path manipulation includes both parsing components from slices and building
#[inline]
fn obtain_lock(&self) {
let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
+ let mut counter: u16 = 0;
while self.dequeue.load(Ordering::SeqCst) != ticket {
- hint::spin_loop();
+ counter += 1;
+ if counter < 100 {
+ hint::spin_loop();
+ } else {
+ counter = 0;
+ unsafe {
+ abi::yield_now();
+ }
+ }
}
}
#![cfg(target_os = "android")]
-use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
-use libc::{ftruncate, pread, pwrite};
+use libc::{c_int, sighandler_t};
-use super::{cvt, cvt_r, weak::weak};
-use crate::io;
+use super::weak::weak;
// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
f(signum, handler)
}
-
-// The `ftruncate64` symbol apparently appeared in android-12, so we do some
-// dynamic detection to see if we can figure out whether `ftruncate64` exists.
-//
-// If it doesn't we just fall back to `ftruncate`, generating an error for
-// too-large values.
-#[cfg(target_pointer_width = "32")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- weak!(fn ftruncate64(c_int, i64) -> c_int);
-
- unsafe {
- match ftruncate64.get() {
- Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
- None => {
- if size > i32::MAX as u64 {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot truncate >2GB"))
- } else {
- cvt_r(|| ftruncate(fd, size as i32)).map(drop)
- }
- }
- }
- }
-}
-
-#[cfg(target_pointer_width = "64")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- unsafe { cvt_r(|| ftruncate(fd, size as i64)).map(drop) }
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
- pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pread(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pread >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
- pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pwrite(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pwrite >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pread(fd, buf, count, offset))
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pwrite(fd, buf, count, offset))
-}
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pread64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pread as pread64;
- #[cfg(target_os = "linux")]
- use libc::pread64;
- cvt(pread64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pread as pread64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pread64;
unsafe {
- cvt_pread64(
+ cvt(pread64(
self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pwrite64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pwrite as pwrite64;
- #[cfg(target_os = "linux")]
- use libc::pwrite64;
- cvt(pwrite64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pwrite as pwrite64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pwrite64;
unsafe {
- cvt_pwrite64(
+ cvt(pwrite64(
self.as_raw_fd(),
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
use libc::{
- dirent as dirent64, fstat as fstat64, fstatat as fstatat64, lseek64, lstat as lstat64,
- open as open64, stat as stat64,
+ dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
+ lstat as lstat64, off64_t, open as open64, stat as stat64,
};
#[cfg(not(any(
target_os = "linux",
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
- #[cfg(target_os = "android")]
- return crate::sys::android::ftruncate64(self.as_raw_fd(), size);
-
- #[cfg(not(target_os = "android"))]
- {
- use crate::convert::TryInto;
- let size: off64_t =
- size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
- cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
- }
+ use crate::convert::TryInto;
+ let size: off64_t =
+ size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+ cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
} else if #[cfg(target_os = "macos")] {
// On MacOS, older versions (<=10.9) lack support for linkat while newer
// versions have it. We want to use linkat if it is available, so we use weak!
- // to check. `linkat` is preferable to `link` ecause it gives us a flag to
+ // to check. `linkat` is preferable to `link` because it gives us a flag to
// specify how symlinks should be handled. We pass 0 as the flags argument,
// meaning it shouldn't follow symlinks.
weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int);
static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
+ // Android builds use feature level 14, but the libc wrapper for splice is
+ // gated on feature level 21+, so we have to invoke the syscall directly.
+ #[cfg(target_os = "android")]
syscall! {
fn splice(
srcfd: libc::c_int,
) -> libc::ssize_t
}
+ #[cfg(target_os = "linux")]
+ use libc::splice;
+
match mode {
SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => {
return CopyResult::Fallback(0);
// res_init unconditionally, we call it only when we detect we're linking
// against glibc version < 2.26. (That is, when we both know its needed and
// believe it's thread-safe).
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn on_resolver_failure() {
use crate::sys;
}
}
-#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))]
+#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
fn on_resolver_failure() {}
#![allow(unused_imports)] // lots of cfg code here
-#[cfg(all(test, target_env = "gnu"))]
+#[cfg(test)]
mod tests;
use crate::os::unix::prelude::*;
}
#[cfg(target_os = "dragonfly")]
+#[allow(dead_code)]
pub fn set_errno(e: i32) {
extern "C" {
#[thread_local]
unsafe { libc::getppid() as u32 }
}
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn glibc_version() -> Option<(usize, usize)> {
- if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
- parse_glibc_version(version_str)
- } else {
- None
- }
-}
-
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
-fn glibc_version_cstr() -> Option<&'static CStr> {
- weak! {
- fn gnu_get_libc_version() -> *const libc::c_char
+ extern "C" {
+ fn gnu_get_libc_version() -> *const libc::c_char;
}
- if let Some(f) = gnu_get_libc_version.get() {
- unsafe { Some(CStr::from_ptr(f())) }
+ let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
+ if let Ok(version_str) = version_cstr.to_str() {
+ parse_glibc_version(version_str)
} else {
None
}
// Returns Some((major, minor)) if the string is a valid "x.y" version,
// ignoring any extra dot-separated parts. Otherwise return None.
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
-use super::*;
-
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_glibc_version() {
// This mostly just tests that the weak linkage doesn't panic wildly...
- glibc_version();
+ super::glibc_version();
}
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
- assert_eq!(parsed, parse_glibc_version(version_str));
+ assert_eq!(parsed, super::parse_glibc_version(version_str));
}
}
use crate::os::linux::process::PidFd;
#[cfg(target_os = "linux")]
-use crate::sys::weak::syscall;
+use crate::sys::weak::raw_syscall;
#[cfg(any(
target_os = "macos",
cgroup: u64,
}
- syscall! {
+ raw_syscall! {
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
}
use crate::sys::{os, stack_overflow};
use crate::time::Duration;
-#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
+use crate::sys::weak::dlsym;
+#[cfg(any(target_os = "solaris", target_os = "illumos"))]
use crate::sys::weak::weak;
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
// We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
-#[cfg(target_os = "linux")]
-#[allow(deprecated)]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
- weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+ // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
+ // We shouldn't really be using such an internal symbol, but there's currently
+ // no other way to account for the TLS size.
+ dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
match __pthread_get_minstack.get() {
None => libc::PTHREAD_STACK_MIN,
}
}
-// No point in looking up __pthread_get_minstack() on non-glibc
-// platforms.
-#[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))]
+// No point in looking up __pthread_get_minstack() on non-glibc platforms.
+#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
libc::PTHREAD_STACK_MIN
}
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! really workable with ELF. Otherwise, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
+//! dependency on libc6 (#23628) because it is GLIBC_PRIVATE. We now use `dlsym`
+//! for a runtime lookup of that symbol to avoid the ELF versioned dependency.
// There are a variety of `#[cfg]`s controlling which targets are involved in
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
#![allow(dead_code, unused_macros)]
use crate::ffi::CStr;
-use crate::marker;
+use crate::marker::PhantomData;
use crate::mem;
use crate::sync::atomic::{self, AtomicUsize, Ordering};
+// We can use true weak linkage on ELF targets.
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
- #[allow(non_upper_case_globals)]
- static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> $ret> =
- crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+ let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+ extern "C" {
+ #[linkage = "extern_weak"]
+ static $name: *const libc::c_void;
+ }
+ #[allow(unused_unsafe)]
+ ExternWeak::new(unsafe { $name })
+ };
)
}
-pub struct Weak<F> {
+// On non-ELF targets, use the dlsym approximation of weak linkage.
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub(crate) use self::dlsym as weak;
+
+pub(crate) struct ExternWeak<F> {
+ weak_ptr: *const libc::c_void,
+ _marker: PhantomData<F>,
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
+ ExternWeak { weak_ptr, _marker: PhantomData }
+ }
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
+ unsafe {
+ if self.weak_ptr.is_null() {
+ None
+ } else {
+ Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
+ }
+ }
+ }
+}
+
+pub(crate) macro dlsym {
+ (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+ static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
+ DlsymWeak::new(concat!(stringify!($name), '\0'));
+ let $name = &DLSYM;
+ )
+}
+
+pub(crate) struct DlsymWeak<F> {
name: &'static str,
addr: AtomicUsize,
- _marker: marker::PhantomData<F>,
+ _marker: PhantomData<F>,
}
-impl<F> Weak<F> {
- pub const fn new(name: &'static str) -> Weak<F> {
- Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
+impl<F> DlsymWeak<F> {
+ pub(crate) const fn new(name: &'static str) -> Self {
+ DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
}
- pub fn get(&self) -> Option<F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
// Cold because it should only happen during first-time initalization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+
let val = fetch(self.name);
// This synchronizes with the acquire fence in `get`.
self.addr.store(val, Ordering::Release);
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name: $t),*) -> $ret {
- use super::os;
-
weak! { fn $name($($t),*) -> $ret }
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
- os::set_errno(libc::ENOSYS);
+ super::os::set_errno(libc::ENOSYS);
-1
}
}
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name:$t),*) -> $ret {
- use weak;
- // This looks like a hack, but concat_idents only accepts idents
- // (not paths).
- use libc::*;
-
weak! { fn $name($($t),*) -> $ret }
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
syscall(
concat_idents!(SYS_, $name),
$($arg_name),*
}
)
}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub(crate) macro raw_syscall {
+ (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+ unsafe fn $name($($arg_name:$t),*) -> $ret {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
+ syscall(
+ concat_idents!(SYS_, $name),
+ $($arg_name),*
+ ) as $ret
+ }
+ )
+}
/// destroyed, but not all platforms have this guard. Those platforms that do
/// not guard typically have a synthetic limit after which point no more
/// destructors are run.
+/// 3. When the process exits on Windows systems, TLS destructors may only be
+/// run on the thread that causes the process to exit. This is because the
+/// other threads may be forcibly terminated.
///
+/// ## Synchronization in thread-local destructors
+///
+/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
+/// thread local destructors are prone to deadlocks and so should be avoided.
+/// This is because the [loader lock] is held while a destructor is run. The
+/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
+/// or unloaded. Therefore these events are blocked for as long as a thread
+/// local destructor is running.
+///
+/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
+/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
/// [`with`]: LocalKey::with
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LocalKey<T: 'static> {
/// The purpose of this API is to provide an easy and portable way to query
/// the default amount of parallelism the program should use. Among other things it
/// does not expose information on NUMA regions, does not account for
-/// differences in (co)processor capabilities, and will not modify the program's
-/// global state in order to more accurately query the amount of available
-/// parallelism.
+/// differences in (co)processor capabilities or current system load,
+/// and will not modify the program's global state in order to more accurately
+/// query the amount of available parallelism.
+///
+/// Where both fixed steady-state and burst limits are available the steady-state
+/// capacity will be used to ensure more predictable latencies.
///
/// Resource limits can be changed during the runtime of a program, therefore the value is
/// not cached and instead recomputed every time this function is called. It should not be
} else {
println!("cargo:rustc-link-lib=gcc");
}
+
+ // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+ println!("cargo:rustc-link-lib=dl");
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("netbsd") {
// NOTE: The check for the empty directory is here because when running x.py the first time,
// the submodule won't be checked out. Check it out now so we can build it.
- if !channel::GitInfo::new(false, relative_path).is_git() && !dir_is_empty(&absolute_path) {
+ if !channel::GitInfo::new(false, &absolute_path).is_git() && !dir_is_empty(&absolute_path) {
return;
}
# 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.4.5 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.5.0 --unsafe-perm=true
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
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:
specially cache them. This flag will rename all these files in the output to include the suffix in
the filename. For example, `light.css` would become `light-suf.css` with the above command.
-### `--display-doctest-warnings`: display warnings when documenting or running documentation tests
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --display-doctest-warnings
-$ rustdoc --test src/lib.rs -Z unstable-options --display-doctest-warnings
-```
-
-The intent behind this flag is to allow the user to see warnings that occur within their library or
-their documentation tests, which are usually suppressed. However, [due to a
-bug][issue-display-warnings], this flag doesn't 100% work as intended. See the linked issue for
-details.
-
-[issue-display-warnings]: https://github.com/rust-lang/rust/issues/41574
-
### `--extern-html-root-url`: control how rustdoc links to non-local crates
Using this flag looks like this:
When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
- Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
-- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
+- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted.
When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
## Installing LLVM coverage tools
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
- The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
- If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
}
let impl_item = match did.as_local() {
- Some(did) => {
- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
- match &tcx.hir().expect_item(hir_id).kind {
- hir::ItemKind::Impl(impl_) => Some(impl_),
- _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
- }
- }
+ Some(did) => match &tcx.hir().expect_item(did).kind {
+ hir::ItemKind::Impl(impl_) => Some(impl_),
+ _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
+ },
None => None,
};
use utils::*;
-crate use utils::{get_auto_trait_and_blanket_impls, krate, register_res};
-
-crate use self::types::FnRetTy::*;
-crate use self::types::ItemKind::*;
-crate use self::types::SelfTy::*;
-crate use self::types::Type::*;
-crate use self::types::Visibility::{Inherited, Public};
crate use self::types::*;
+crate use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
crate trait Clean<T> {
fn clean(&self, cx: &mut DocContext<'_>) -> T;
} else {
hir::Constness::NotConst
};
+ clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
}
}
}
+/// This is needed to make it more "readable" when documenting functions using
+/// `rustc_legacy_const_generics`. More information in
+/// <https://github.com/rust-lang/rust/issues/83167>.
+fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) {
+ for meta_item_list in attrs
+ .iter()
+ .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
+ .filter_map(|a| a.meta_item_list())
+ {
+ for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() {
+ match literal.kind {
+ ast::LitKind::Int(a, _) => {
+ let gen = func.generics.params.remove(0);
+ if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
+ gen
+ {
+ func.decl
+ .inputs
+ .values
+ .insert(a as _, Argument { name, type_: *ty, is_const: true });
+ } else {
+ panic!("unexpected non const in position {}", pos);
+ }
+ }
+ _ => panic!("invalid arg index"),
+ }
+ }
+ }
+}
+
impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
fn clean(&self, cx: &mut DocContext<'_>) -> Function {
let (generics, decl) = enter_impl_trait(cx, |cx| {
if name.is_empty() {
name = kw::Underscore;
}
- Argument { name, type_: ty.clean(cx) }
+ Argument { name, type_: ty.clean(cx), is_const: false }
})
.collect(),
}
.map(|(i, ty)| Argument {
name: name_from_pat(body.params[i].pat),
type_: ty.clean(cx),
+ is_const: false,
})
.collect(),
}
.map(|t| Argument {
type_: t.clean(cx),
name: names.next().map_or(kw::Empty, |i| i.name),
+ is_const: false,
})
.collect(),
},
let what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
- let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id()));
+ let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_did(self.hir_id()));
if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
if impl_.of_trait.is_some() {
// Trait impl items always inherit the impl's visibility --
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
let Some(def_id) = def_id.as_local() else { return None };
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- &cx.tcx.hir().expect_item(hir_id).kind
+ &cx.tcx.hir().expect_item(def_id).kind
} else {
return None;
};
return None;
}
- use crate::rustc_trait_selection::infer::TyCtxtInferExt;
- use crate::rustc_trait_selection::traits::query::normalize::AtExt;
- use rustc_middle::traits::ObligationCause;
-
// Try to normalize `<X as Y>::T` to a type
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
- let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
- infcx
- .at(&ObligationCause::dummy(), cx.param_env)
- .normalize(lifted)
- .map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
- });
- match normalized {
+ match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) {
Ok(normalized_value) => {
- debug!("normalized {:?} to {:?}", ty, normalized_value);
+ trace!("normalized {:?} to {:?}", ty, normalized_value);
Some(normalized_value)
}
Err(err) => {
- debug!("failed to normalize {:?}: {:?}", ty, err);
+ info!("failed to normalize {:?}: {:?}", ty, err);
None
}
}
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, did, false, vec![], substs);
- ResolvedPath { path, did }
+ Type::Path { path }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
- ResolvedPath { path, did }
+ Type::Path { path }
}
ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
-use crate::clean::types::Type::{QPath, ResolvedPath};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
use crate::clean::Clean;
use crate::core::DocContext;
use crate::html::render::cache::ExternalLocation;
use crate::html::render::Context;
-use self::FnRetTy::*;
-use self::ItemKind::*;
-use self::SelfTy::*;
-use self::Type::*;
+crate use self::FnRetTy::*;
+crate use self::ItemKind::*;
+crate use self::SelfTy::*;
+crate use self::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
+ RawPointer, Slice, Tuple,
+};
+crate use self::Visibility::{Inherited, Public};
crate type ItemIdSet = FxHashSet<ItemId>;
self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
}
- crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
- self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
+ crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
+ self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did)).map(|cs| *cs)
}
crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
})
}
- crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
match self.stability(tcx)?.level {
- StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+ StabilityLevel::Stable { since, .. } => Some(since),
StabilityLevel::Unstable { .. } => None,
}
}
- crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
match self.const_stability(tcx)?.level {
- StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+ StabilityLevel::Stable { since, .. } => Some(since),
StabilityLevel::Unstable { .. } => None,
}
}
crate struct Argument {
crate type_: Type,
crate name: Symbol,
+ /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
+ /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
+ crate is_const: bool,
}
#[derive(Clone, PartialEq, Debug)]
crate enum Type {
/// A named type, which could be a trait.
///
- /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
- ResolvedPath { path: Path, did: DefId },
+ /// This is mostly Rustdoc's version of [`hir::Path`].
+ /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
+ Path { path: Path },
/// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter.
rustc_data_structures::static_assert_size!(Type, 72);
impl Type {
+ /// When comparing types for equality, it can help to ignore `&` wrapping.
+ crate fn without_borrowed_ref(&self) -> &Type {
+ let mut result = self;
+ while let Type::BorrowedRef { type_, .. } = result {
+ result = &*type_;
+ }
+ result
+ }
+
+ /// Check if two types are "potentially the same".
+ /// This is different from `Eq`, because it knows that things like
+ /// `Placeholder` are possible matches for everything.
+ crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
+ match (self, other) {
+ // Recursive cases.
+ (Type::Tuple(a), Type::Tuple(b)) => {
+ a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
+ }
+ (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
+ (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
+ (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
+ mutability == b_mutability && type_.is_same(&b_type_, cache)
+ }
+ (
+ Type::BorrowedRef { mutability, type_, .. },
+ Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
+ ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
+ // Placeholders and generics are equal to all other types.
+ (Type::Infer, _) | (_, Type::Infer) => true,
+ (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+ // Other cases, such as primitives, just use recursion.
+ (a, b) => a
+ .def_id(cache)
+ .and_then(|a| Some((a, b.def_id(cache)?)))
+ .map(|(a, b)| a == b)
+ .unwrap_or(false),
+ }
+ }
+
crate fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
/// Checks if this is a `T::Name` path for an associated type.
crate fn is_assoc_ty(&self) -> bool {
match self {
- ResolvedPath { path, .. } => path.is_assoc_ty(),
+ Type::Path { path, .. } => path.is_assoc_ty(),
_ => false,
}
}
crate fn generics(&self) -> Option<Vec<&Type>> {
match self {
- ResolvedPath { path, .. } => path.generics(),
+ Type::Path { path, .. } => path.generics(),
_ => None,
}
}
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
- ResolvedPath { did, .. } => return Some(did),
+ Type::Path { ref path } => return Some(path.def_id()),
DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
- ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type,
- TypeBinding, Visibility,
+ ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
inline::build_impl(cx, None, did, None, ret);
}
- } else if let ResolvedPath { did, .. } = *target {
+ } else if let Type::Path { path } = target {
+ let did = path.def_id();
if !did.is_local() {
inline::build_impls(cx, None, did, None, ret);
}
Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper),
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => {
- let did = register_res(cx, path.res);
- ResolvedPath { path, did }
+ let _ = register_res(cx, path.res);
+ Type::Path { path }
}
}
}
debug!("register_res({:?})", res);
let (did, kind) = match res {
- Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
- // associated items are documented, but on the page of their parent
- (cx.tcx.parent(i).unwrap(), ItemType::Trait)
- }
- Res::Def(DefKind::Variant, i) => {
- // variant items are documented, but on the page of their parent
- (cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
- }
- // Each of these have their own page.
+ // These should be added to the cache using `record_extern_fqn`.
Res::Def(
- kind
- @
- (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
- | Macro(..) | TraitAlias),
+ kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
+ | Union | Mod | ForeignTy | Const | Static | Macro(..) | TraitAlias),
i,
) => (i, kind.into()),
// This is part of a trait definition; document the trait.
///
/// Be aware: This option can come both from the CLI and from crate attributes!
crate manual_passes: Vec<String>,
- /// Whether to display warnings during doc generation or while gathering doctests. By default,
- /// all non-rustdoc-specific lints are allowed when generating docs.
- crate display_doctest_warnings: bool,
/// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items
/// with and without documentation.
crate show_coverage: bool,
.field("persist_doctests", &self.persist_doctests)
.field("default_passes", &self.default_passes)
.field("manual_passes", &self.manual_passes)
- .field("display_doctest_warnings", &self.display_doctest_warnings)
.field("show_coverage", &self.show_coverage)
.field("crate_version", &self.crate_version)
.field("render_options", &self.render_options)
))
.emit();
}
- themes.push(StylePath { path: theme_file, disabled: true });
+ themes.push(StylePath { path: theme_file });
}
}
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
let playground_url = matches.opt_str("playground-url");
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let display_doctest_warnings = matches.opt_present("display-doctest-warnings");
let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
let enable_minification = !matches.opt_present("disable-minification");
test_args,
default_passes,
manual_passes,
- display_doctest_warnings,
show_coverage,
crate_version,
test_run_directory,
crate struct TestOptions {
/// Whether to disable the default `extern crate my_crate;` when creating doctests.
crate no_crate_inject: bool,
- /// Whether to emit compilation warnings when compiling doctests. Setting this will suppress
- /// the default `#![allow(unused)]`.
- crate display_doctest_warnings: bool,
/// Additional crate-level attributes to add to doctests.
crate attrs: Vec<String>,
}
}
});
+ debug!(?lint_opts);
+
let crate_types =
if options.proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
maybe_sysroot: options.maybe_sysroot.clone(),
search_paths: options.libs.clone(),
crate_types,
- lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
+ lint_opts,
lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
};
let test_args = options.test_args.clone();
- let display_doctest_warnings = options.display_doctest_warnings;
let nocapture = options.nocapture;
let externs = options.externs.clone();
let json_unused_externs = options.json_unused_externs;
let collector = global_ctxt.enter(|tcx| {
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
- let mut opts = scrape_test_config(crate_attrs);
- opts.display_doctest_warnings |= options.display_doctest_warnings;
+ let opts = scrape_test_config(crate_attrs);
let enable_per_target_ignores = options.enable_per_target_ignores;
let mut collector = Collector::new(
tcx.crate_name(LOCAL_CRATE),
Err(ErrorReported) => return Err(ErrorReported),
};
- run_tests(test_args, nocapture, display_doctest_warnings, tests);
+ run_tests(test_args, nocapture, tests);
// Collect and warn about unused externs, but only if we've gotten
// reports for each doctest
Ok(())
}
-crate fn run_tests(
- mut test_args: Vec<String>,
- nocapture: bool,
- display_doctest_warnings: bool,
- tests: Vec<test::TestDescAndFn>,
-) {
+crate fn run_tests(mut test_args: Vec<String>, nocapture: bool, tests: Vec<test::TestDescAndFn>) {
test_args.insert(0, "rustdoctest".to_string());
if nocapture {
test_args.push("--nocapture".to_string());
}
- test::test_main(
- &test_args,
- tests,
- Some(test::Options::new().display_output(display_doctest_warnings)),
- );
+ test::test_main(&test_args, tests, None);
}
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config(attrs: &[ast::Attribute]) -> TestOptions {
use rustc_ast_pretty::pprust;
- let mut opts =
- TestOptions { no_crate_inject: false, display_doctest_warnings: false, attrs: Vec::new() };
+ let mut opts = TestOptions { no_crate_inject: false, attrs: Vec::new() };
let test_attrs: Vec<_> = attrs
.iter()
let mut prog = String::new();
let mut supports_color = false;
- if opts.attrs.is_empty() && !opts.display_doctest_warnings {
+ if opts.attrs.is_empty() {
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
// lints that are commonly triggered in doctests. The crate-level test attributes are
// commonly used to make tests fail in case they trigger warnings, so having this there in
fn make_test_no_crate_inject() {
// Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
// adding it anyway.
- let opts =
- TestOptions { no_crate_inject: true, display_doctest_warnings: false, attrs: vec![] };
+ let opts = TestOptions { no_crate_inject: true, attrs: vec![] };
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
assert_eq!((output, len), (expected, 1));
}
-#[test]
-fn make_test_display_doctest_warnings() {
- // If the user is asking to display doctest warnings, suppress the default `allow(unused)`.
- let mut opts = TestOptions::default();
- opts.display_doctest_warnings = true;
- let input = "assert_eq!(2+2, 4);";
- let expected = "fn main() {
-assert_eq!(2+2, 4);
-}"
- .to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
- assert_eq!((output, len), (expected, 1));
-}
-
#[test]
fn make_test_issues_21299_33731() {
let opts = TestOptions::default();
match $e {
Some(e) => e,
None => {
- return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file));
+ return Err(<crate::error::Error as crate::docfs::PathError>::new(
+ io::Error::new(io::ErrorKind::Other, "not found"),
+ $file,
+ ));
}
}
}};
#[derive(Default)]
crate struct Cache {
/// Maps a type ID to all known implementations for that type. This is only
- /// recognized for intra-crate `ResolvedPath` types, and is used to print
+ /// recognized for intra-crate [`clean::Type::Path`]s, and is used to print
/// out extra documentation on the page of an enum/struct.
///
/// The values of the map are a list of implementations and documentation
clean::ImplItem(ref i) => {
self.cache.parent_is_trait_impl = i.trait_.is_some();
match i.for_ {
- clean::ResolvedPath { did, .. } => {
- self.cache.parent_stack.push(did);
+ clean::Type::Path { ref path } => {
+ self.cache.parent_stack.push(path.def_id());
true
}
clean::DynTrait(ref bounds, _)
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
match i.for_ {
- clean::ResolvedPath { did, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
- dids.insert(did);
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
+ dids.insert(path.def_id());
}
clean::DynTrait(ref bounds, _)
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty;
+use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi;
cx: &Context<'_>,
root_path: Option<&str>,
) -> Result<(String, ItemType, Vec<String>), HrefError> {
- let cache = &cx.cache();
+ let tcx = cx.tcx();
+ let def_kind = tcx.def_kind(did);
+ let did = match def_kind {
+ DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
+ // documented on their parent's page
+ tcx.parent(did).unwrap()
+ }
+ _ => did,
+ };
+ let cache = cx.cache();
let relative_to = &cx.current;
fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
}
}
-/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
-/// rendering function with the necessary arguments for linking to a local path.
+/// Used to render a [`clean::Path`].
fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
did: DefId,
match *t {
clean::Generic(name) => write!(f, "{}", name),
- clean::ResolvedPath { did, ref path } => {
+ clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
+ let did = path.def_id();
resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
}
clean::DynTrait(ref bounds, ref lt) => {
args.push_str(" <br>");
args_plain.push(' ');
}
+ 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));
}
}
-crate fn print_constness_with_space(
- c: &hir::Constness,
- s: Option<&ConstStability>,
-) -> &'static str {
+crate fn print_constness_with_space(c: &hir::Constness, s: Option<ConstStability>) -> &'static str {
match (c, s) {
// const stable or when feature(staged_api) is not set
(
},
Some(c) => c,
},
- TokenKind::RawIdent | TokenKind::UnknownPrefix => {
+ TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
Class::Ident(self.new_span(before, text))
}
TokenKind::Lifetime { .. } => Class::Lifetime,
use rustc_data_structures::fx::FxHashMap;
+use crate::error::Error;
use crate::externalfiles::ExternalHtml;
-use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};
static_root_path: &'a str,
page: &'a Page<'a>,
layout: &'a Layout,
- style_files: String,
+ themes: Vec<String>,
sidebar: String,
content: String,
krate_with_trailing_slash: String,
+ crate rustdoc_version: &'a str,
}
crate fn render<T: Print, S: Print>(
) -> String {
let static_root_path = page.get_static_root_path();
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
- let style_files = style_files
+ let mut themes: Vec<String> = style_files
.iter()
- .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
- .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
- .map(|t| {
- format!(
- r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
- Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
- if t.1 { "disabled" } else { "" },
- if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
- )
- })
- .collect::<String>();
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()
+ .unwrap_or_default();
+ themes.sort();
+ let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
let sidebar = Buffer::html().to_display(sidebar);
let teractx = tera::Context::from_serialize(PageLayout {
static_root_path,
page,
layout,
- style_files,
+ themes,
sidebar,
content,
krate_with_trailing_slash,
+ rustdoc_version,
})
.unwrap();
templates.render("page.html", &teractx).unwrap()
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
match *clean_type {
- clean::ResolvedPath { ref path, .. } => {
+ clean::Type::Path { ref path, .. } => {
let path_segment = path.segments.last().unwrap();
Some(path_segment.name)
}
let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
- let ty = Type::ResolvedPath { did: path.def_id(), path };
+ let ty = Type::Path { path };
get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
}
}
// by the browser as the theme stylesheet. The theme system (hackily) works by
// changing the href to this stylesheet. All other themes are disabled to
// prevent rule conflicts
- scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false });
- scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true });
- scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true });
+ scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
let dst = output;
scx.ensure_dir(&dst)?;
page.description = "Settings of Rustdoc";
page.root_path = "./";
- let mut style_files = self.shared.style_files.clone();
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
- style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
+ let theme_names: Vec<String> = self
+ .shared
+ .style_files
+ .iter()
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()?;
let v = layout::render(
&self.shared.templates,
&self.shared.layout,
settings(
self.shared.static_root_path.as_deref().unwrap_or("./"),
&self.shared.resource_suffix,
- &self.shared.style_files,
+ theme_names,
)?,
- &style_files,
+ &self.shared.style_files,
);
self.shared.fs.write(settings_file, v)?;
if let Some(ref redirections) = self.shared.redirections {
use serde::{Serialize, Serializer};
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
-use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
crate struct StylePath {
/// The path to the theme
crate path: PathBuf,
- /// What the `disabled` attribute should be set to in the HTML tag
- crate disabled: bool,
+}
+
+impl StylePath {
+ pub fn basename(&self) -> Result<String, Error> {
+ Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
+ }
}
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
js_data_name: &'static str,
description: &'static str,
default_value: &'static str,
- options: Vec<(String, String)>,
+ options: Vec<String>,
},
}
options
.iter()
.map(|opt| format!(
- "<option value=\"{}\" {}>{}</option>",
- opt.0,
- if opt.0 == default_value { "selected" } else { "" },
- opt.1,
+ "<option value=\"{name}\" {}>{name}</option>",
+ if opt == default_value { "selected" } else { "" },
+ name = opt,
))
.collect::<String>(),
root_path,
}
}
-fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
- let theme_names: Vec<(String, String)> = themes
- .iter()
- .map(|entry| {
- let theme =
- try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
- .to_string();
-
- Ok((theme.clone(), theme))
- })
- .collect::<Result<_, Error>>()?;
-
+fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
// (id, explanation, default value)
let settings: &[Setting] = &[
(
<span class=\"in-band\">Rustdoc settings</span>\
</h1>\
<div class=\"settings\">{}</div>\
- <script src=\"{}settings{}.js\"></script>",
+ <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
+ <script src=\"{root_path}settings{suffix}.js\"></script>",
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
- root_path,
- suffix
+ root_path = root_path,
+ suffix = suffix
))
}
fn render_stability_since_raw(
w: &mut Buffer,
- ver: Option<&str>,
- const_stability: Option<&ConstStability>,
- containing_ver: Option<&str>,
- containing_const_ver: Option<&str>,
+ ver: Option<Symbol>,
+ const_stability: Option<ConstStability>,
+ containing_ver: Option<Symbol>,
+ containing_const_ver: Option<Symbol>,
) {
let ver = ver.filter(|inner| !inner.is_empty());
match (ver, const_stability) {
// stable and const stable
(Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
- if Some(since.as_str()).as_deref() != containing_const_ver =>
+ if Some(since) != containing_const_ver =>
{
write!(
w,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
+ render_mode: RenderMode,
) {
fn method(
w: &mut Buffer,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
+ render_mode: RenderMode,
) {
let name = meth.name.as_ref().unwrap();
let href = match link {
}
};
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
- let constness =
- print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
+ // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+ // this condition.
+ let constness = match render_mode {
+ RenderMode::Normal => {
+ print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()))
+ }
+ RenderMode::ForDeref { .. } => "",
+ };
let asyncness = header.asyncness.print_with_space();
let unsafety = header.unsafety.print_with_space();
let defaultness = print_default_space(meth.is_default());
match *item.kind {
clean::StrippedItem(..) => {}
clean::TyMethodItem(ref m) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::MethodItem(ref m, _) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::AssocConstItem(ref ty, ref default) => assoc_const(
w,
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
(mutability == Mutability::Mut, false, false)
}
- SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
- (false, Some(did) == tcx.lang_items().owned_box(), false)
+ SelfTy::SelfExplicit(clean::Type::Path { path }) => {
+ (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
}
SelfTy::SelfValue => (false, false, true),
_ => (false, false, false),
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
- if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
+ if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
+ {
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
+ if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
+ {
+ // Two different types might have the same did,
+ // without actually being the same.
+ continue;
+ }
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();
"<div id=\"{}\" class=\"{}{} has-srclink\">",
id, item_type, in_trait_class,
);
- render_rightside(w, cx, item, containing_item);
+ render_rightside(w, cx, item, containing_item, render_mode);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
w.write_str("<h4 class=\"code-header\">");
render_assoc_item(
link.anchor(source_id.as_ref().unwrap_or(&id)),
ItemType::Impl,
cx,
+ render_mode,
);
w.write_str("</h4>");
w.write_str("</div>");
"<div id=\"{}\" class=\"{}{} has-srclink\">",
id, item_type, in_trait_class
);
- render_rightside(w, cx, item, containing_item);
+ render_rightside(w, cx, item, containing_item, render_mode);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
w.write_str("<h4 class=\"code-header\">");
assoc_const(
cx: &Context<'_>,
item: &clean::Item,
containing_item: &clean::Item,
+ render_mode: RenderMode,
) {
let tcx = cx.tcx();
+ // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+ // this condition.
+ let (const_stability, const_stable_since) = match render_mode {
+ RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
+ RenderMode::ForDeref { .. } => (None, None),
+ };
+
write!(w, "<div class=\"rightside\">");
render_stability_since_raw(
w,
- item.stable_since(tcx).as_deref(),
- item.const_stability(tcx),
- containing_item.stable_since(tcx).as_deref(),
- containing_item.const_stable_since(tcx).as_deref(),
+ item.stable_since(tcx),
+ const_stability,
+ containing_item.stable_since(tcx),
+ const_stable_since,
);
write_srclink(cx, item, w);
format!(" data-aliases=\"{}\"", aliases.join(","))
};
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
- render_rightside(w, cx, &i.impl_item, containing_item);
+ render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write!(w, "<h3 class=\"code-header in-band\">");
}
match ty {
- clean::Type::ResolvedPath { did, .. } => process_path(did),
+ clean::Type::Path { path } => process_path(path.def_id()),
clean::Type::Tuple(tys) => {
work.extend(tys.into_iter());
}
let mut stability_since_raw = Buffer::new();
render_stability_since_raw(
&mut stability_since_raw,
- item.stable_since(cx.tcx()).as_deref(),
+ item.stable_since(cx.tcx()),
item.const_stability(cx.tcx()),
None,
None,
);
}
for t in &types {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ t,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
}
// If there are too many associated constants, hide everything after them
w.write_str("\n");
}
for t in &consts {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ t,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
}
if !toggle && should_hide_fields(count_methods) {
w.write_str("\n");
}
for (pos, m) in required.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
if pos < required.len() - 1 {
w.write_str("\n");
}
for (pos, m) in provided.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
match *m.kind {
clean::MethodItem(ref inner, _)
if !inner.generics.where_predicates.is_empty() =>
write_srclink(cx, m, w);
write!(w, "</div>");
write!(w, "<h4 class=\"code-header\">");
- render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(Some(&id)),
+ ItemType::Impl,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str("</h4>");
w.write_str("</div>");
if toggled {
let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
for implementor in implementors {
match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, did, .. }
- | clean::BorrowedRef {
- type_: box clean::ResolvedPath { ref path, did, .. }, ..
- } if !path.is_assoc_ty() => {
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. }
+ if !path.is_assoc_ty() =>
+ {
+ let did = path.def_id();
let &mut (prev_did, ref mut has_duplicates) =
implementor_dups.entry(path.last()).or_insert((did, false));
if prev_did != did {
) {
render_stability_since_raw(
w,
- item.stable_since(tcx).as_deref(),
+ item.stable_since(tcx),
item.const_stability(tcx),
- containing_item.stable_since(tcx).as_deref(),
- containing_item.const_stable_since(tcx).as_deref(),
+ containing_item.stable_since(tcx),
+ containing_item.const_stable_since(tcx),
)
}
// If there's already another implementor that has the same abridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. }
+ clean::Type::Path { ref path, .. }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path, .. }, .. }
if !path.is_assoc_ty() =>
{
implementor_dups[&path.last()].1
the type was too big.</p>"
);
}
+ Err(LayoutError::NormalizationFailure(_, _)) => {
+ writeln!(
+ w,
+ "<p><strong>Note:</strong> Encountered an error during type layout; \
+ the type failed to be normalized.</p>"
+ )
+ }
}
writeln!(w, "</div>");
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
};
- fn add_background_image_to_css(
- cx: &Context<'_>,
- css: &mut String,
- rule: &str,
- file: &'static str,
- ) {
- css.push_str(&format!(
- "{} {{ background-image: url({}); }}",
- rule,
- SharedResource::ToolchainSpecific { basename: file }
+ // Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
+ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
+ format!(
+ "url(\"{}\")",
+ SharedResource::ToolchainSpecific { basename }
.path(cx)
.file_name()
.unwrap()
.to_str()
.unwrap()
- ))
+ )
}
- // Add all the static files. These may already exist, but we just
- // overwrite them anyway to make sure that they're fresh and up-to-date.
- let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
- add_background_image_to_css(
- cx,
- &mut rustdoc_css,
- "details.undocumented[open] > summary::before, \
- details.rustdoc-toggle[open] > summary::before, \
- details.rustdoc-toggle[open] > summary.hideme::before",
- "toggle-minus.svg",
- );
- add_background_image_to_css(
+ // We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
+ // values that are only known at doc build time. Since this mechanism is somewhat
+ // surprising when reading the code, please limit it to rustdoc.css.
+ write_minify(
+ "rustdoc.css",
+ static_files::RUSTDOC_CSS
+ .replace(
+ "/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
+ &ver_url(cx, "toggle-minus.svg"),
+ )
+ .replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
+ .replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
cx,
- &mut rustdoc_css,
- "details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
- "toggle-plus.svg",
- );
- write_minify("rustdoc.css", rustdoc_css, cx, options)?;
+ options,
+ )?;
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
let mut themes: FxHashSet<String> = FxHashSet::default();
for entry in &cx.shared.style_files {
- let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path);
+ let theme = entry.basename()?;
let extension =
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
// Handle the official themes
- match theme {
+ match theme.as_str() {
"light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
"dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
"ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
let mut themes: Vec<&String> = themes.iter().collect();
themes.sort();
- // FIXME: this should probably not be a toolchain file since it depends on `--theme`.
- // But it seems a shame to copy it over and over when it's almost always the same.
- // Maybe we can change the representation to move this out of main.js?
- write_minify(
- "main.js",
- static_files::MAIN_JS
- .replace(
- "/* INSERT THEMES HERE */",
- &format!(" = {}", serde_json::to_string(&themes).unwrap()),
- )
- .replace(
- "/* INSERT RUSTDOC_VERSION HERE */",
- &format!(
- "rustdoc {}",
- rustc_interface::util::version_str().unwrap_or("unknown version")
- ),
- ),
- cx,
- options,
- )?;
+ write_minify("main.js", static_files::MAIN_JS, cx, options)?;
write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
}
- {
- write_minify(
- "storage.js",
- format!(
- "var resourcesSuffix = \"{}\";{}",
- cx.shared.resource_suffix,
- static_files::STORAGE_JS
- ),
- cx,
- options,
- )?;
- }
+ write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
if cx.shared.layout.scrape_examples_extension {
cx.write_minify(
overflow-y: scroll;
}
+.rustdoc.source .sidebar {
+ overflow-y: auto;
+}
+
/* Improve the scrollbar display on firefox */
* {
scrollbar-width: initial;
background-color: transparent;
background-size: 20px;
background-position: calc(100% - 1px) 56%;
+ background-image: /* AUTOREPLACE: */url("down-arrow.svg");
}
.search-container > .top-button {
position: absolute;
margin-top: 3px;
}
-.docblock > .section-header:first-child {
+.top-doc .docblock > .section-header:first-child {
margin-left: 15px;
- margin-top: 0;
}
-
-.docblock > .section-header:first-child:hover > a:before {
+.top-doc .docblock > .section-header:first-child:hover > a:before {
left: -10px;
}
+.docblock > .section-header:first-child {
+ margin-top: 0;
+}
+
:target > code, :target > .code-header {
opacity: 1;
}
display: none;
}
+details.undocumented[open] > summary::before,
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+ background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
+}
+
+details.undocumented > summary::before, details.rustdoc-toggle > summary::before {
+ background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
+}
+
details.rustdoc-toggle[open] > summary::before,
details.rustdoc-toggle[open] > summary.hideme::before {
width: 17px;
};
}
-(function () {
- var rustdocVars = document.getElementById("rustdoc-vars");
- if (rustdocVars) {
- window.rootPath = rustdocVars.attributes["data-root-path"].value;
- window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
- window.searchJS = rustdocVars.attributes["data-search-js"].value;
- window.searchIndexJS = rustdocVars.attributes["data-search-index-js"].value;
+// Get a value from the rustdoc-vars div, which is used to convey data from
+// Rust to the JS. If there is no such element, return null.
+function getVar(name) {
+ var el = document.getElementById("rustdoc-vars");
+ if (el) {
+ return el.attributes["data-" + name].value;
+ } else {
+ return null;
}
+}
+
+// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
+// for a resource under the root-path, with the resource-suffix.
+function resourcePath(basename, extension) {
+ return getVar("root-path") + basename + getVar("resource-suffix") + extension;
+}
+
+
+(function () {
+ window.rootPath = getVar("root-path");
+ window.currentCrate = getVar("current-crate");
+ window.searchJS = resourcePath("search", ".js");
+ window.searchIndexJS = resourcePath("search-index", ".js");
var sidebarVars = document.getElementById("sidebar-vars");
if (sidebarVars) {
window.sidebarCurrent = {
(function () {
var themeChoices = getThemesElement();
var themePicker = getThemePickerElement();
- var availableThemes/* INSERT THEMES HERE */;
+ var availableThemes = getVar("themes").split(",");
function switchThemeButtonState() {
if (themeChoices.style.display === "block") {
var rustdoc_version = document.createElement("span");
rustdoc_version.className = "bottom";
var rustdoc_version_code = document.createElement("code");
- rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */";
+ rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
rustdoc_version.appendChild(rustdoc_version_code);
container.appendChild(rustdoc_version);
-// From rust:
-/* global resourcesSuffix */
var darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle");
}
function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
- var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
- var fullNewTheme = newTheme + resourcesSuffix + ".css";
- var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);
+ var newHref = mainStyleElem.href.replace(
+ /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
// If this new value comes from a system setting or from the previously
// saved theme, no need to save it.
<meta name="description" content="{{page.description}}"> {#- -#}
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
id="mainThemeStyle"> {#- -#}
- {{- style_files | safe -}}
+ {%- for theme in themes -%}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {#- -#}
+ {%- if theme == "light" -%}
+ id="themeStyle"
+ {%- else -%}
+ disabled
+ {%- endif -%}
+ >
+ {%- endfor -%}
<script id="default-settings" {# -#}
{% for k, v in layout.default_settings %}
data-{{k}}="{{v}}"
href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
{%- endif -%}
{{- layout.external_html.in_header | safe -}}
- <style type="text/css"> {#- -#}
- #crate-search{ {#- -#}
- background-image:url("{{static_root_path | safe}}down-arrow{{page.resource_suffix}}.svg"); {#- -#}
- } {#- -#}
- </style> {#- -#}
</head> {#- -#}
<body class="rustdoc {{page.css_class}}"> {#- -#}
<!--[if lte IE 11]> {#- -#}
<div id="rustdoc-vars" {# -#}
data-root-path="{{page.root_path | safe}}" {# -#}
data-current-crate="{{layout.krate}}" {# -#}
- data-search-index-js="{{page.root_path | safe}}search-index{{page.resource_suffix}}.js" {# -#}
- data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
+ data-themes="{{themes | join(sep=",") }}" {# -#}
+ data-resource-suffix="{{page.resource_suffix}}" {# -#}
+ data-rustdoc-version="{{rustdoc_version}}" {# -#}
+ > {#- -#}
</div>
</body> {#- -#}
</html> {#- -#}
match bound {
TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ =
- clean::ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
- use clean::Type::*;
+ use clean::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
+ QPath, RawPointer, Slice, Tuple,
+ };
+
match ty {
- ResolvedPath { path, did } => Type::ResolvedPath {
+ clean::Type::Path { path } => Type::ResolvedPath {
name: path.whole_name(),
- id: from_item_id(did.into()),
+ id: from_item_id(path.def_id().into()),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
},
QPath { name, self_type, trait_, .. } => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
Type::QualifiedPath {
name: name.to_string(),
self_type: Box::new((*self_type).into_tcx(tcx)),
let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = trait_.map(|path| {
- let did = path.def_id();
- clean::ResolvedPath { path, did }.into_tcx(tcx)
- });
+ let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
let (synthetic, blanket_impl) = match kind {
clean::ImplKind::Normal => (false, None),
.map_err(|err| format!("{}: {}", options.input.display(), err))?;
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
- opts.display_doctest_warnings = options.display_doctest_warnings;
let mut collector = Collector::new(
Symbol::intern(&options.input.display().to_string()),
options.clone(),
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
- crate::doctest::run_tests(
- options.test_args,
- options.nocapture,
- options.display_doctest_warnings,
- collector.tests,
- );
+ crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
Ok(())
}
hir::ExprKind::Call(f, _) => {
let types = tcx.typeck(ex.hir_id.owner);
- match types.node_type_opt(f.hir_id) {
- Some(ty) => (ty, ex.span),
- None => {
- return;
- }
+ if let Some(ty) = types.node_type_opt(f.hir_id) {
+ (ty, ex.span)
+ } else {
+ trace!("node_type_opt({}) = None", f.hir_id);
+ return;
}
}
hir::ExprKind::MethodCall(_, _, _, span) => {
let types = tcx.typeck(ex.hir_id.owner);
- let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+ let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) {
+ def_id
+ } else {
+ trace!("type_dependent_def_id({}) = None", ex.hir_id);
+ return;
+ };
(tcx.type_of(def_id), span)
}
_ => {
if let Some(local_def_id) = def_id.as_local() {
if self.cx.tcx.has_attr(def_id, sym::macro_export) {
if inserted.insert(def_id) {
- let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- let item = self.cx.tcx.hir().expect_item(hir_id);
+ let item = self.cx.tcx.hir().expect_item(local_def_id);
top_level_module.items.push((item, None));
}
}
-Subproject commit f9b03d0e2d7378f8dd5697ceb72b310060f7598f
+Subproject commit 01c8b654f9a01371414d1fd69cba38b289510a9e
"__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
"dist_server": "https://static.rust-lang.org",
"compiler": {
- "date": "2021-10-22",
+ "date": "2021-11-30",
"version": "beta"
},
"rustfmt": {
- "date": "2021-10-23",
+ "date": "2021-11-30",
"version": "nightly"
},
"checksums_sha256": {
- "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.gz": "b81ef641492ff2f03a93c8fbfbcfa78db2f6574d1998569d68dd2ba0e08ee186",
- "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.xz": "925090782ad982202ca554a84e9d4a7b190f94b0b220c23e73235383d6ca367d",
- "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "eba42edfebc85c744f4c6874337847748df65e430915f47238a93b1b7e96840a",
- "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "fd04a8c4058ff287ea0256fd9f33a4b04b4f098d6911e8d827525cdeda6f169e",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c7abbf1f265435cc9f6f0773d30321fc99353e0ddbf0004d00f47433eb3aaab1",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "3363dfdcd7106841edbd9029676ac339ff54c142921d71d92e308bee2ee33066",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fbc5d5f70a36fc73f4d34d101aef4be78e38b5009ebf690fe46ba32eff6c1fce",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "220f23f50645532df4e5a4b1d6d894ce66a6ee2e5576fdf552081644a74a1c8f",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "94b42b8639ce541c1a355991f20d9934c72e766b6200d742d2d5b3b2f499f782",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e32e9df3ab261fe20c363406d655fdaeeefc9dbb3d69da4551cdf9c22c418eb2",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "301c303ec0db0e342ecce4e259e79810e082766bac8f9907c353bdf490177863",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6f9409076ab4e2dac5ac5c07bac6be30e83e281df9efe2fa68386928e2e6faf",
- "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a4a82d48b2b1e6a49c0a765f9ee4d01e7ce4b0543128745d13cf4684c56eca8c",
- "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c9ca524ba0e76d9fe38f0e4af337d14b97fd97dcd83d80ebf4725b5b03bea3ac",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "973eabda91963d58a9cdd1491bcea15834874fbca018287fb7f5c8bdcdf323d1",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "cbbc14d1ef0e4579167fce4a5fac43b22c87882049a3d0edfbace9fc5c103ad3",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "ef090943f6c90bb3327225e0256e73762ca2f73ae5d0d07b2c828709077e1132",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "42708683ba5ad855880ec69d92192bd9f99ebf102beaf6c53680cb8733fba9e7",
- "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6c260ba19734482439bf6d12b8e87e82f269f1bec447ec85e59372ef6489eec",
- "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "fb6036ff910d075fb5e483000af641328e6d7d01c33255c099ed1b0302239918",
- "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.gz": "71e4e5fcf055251089ac0d37b5ad873eaee6aa0380438cd68f140a16d3a37cd1",
- "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.xz": "b89acabf106b10c5c3421574bea83d8baf1f29d040c40d5522f85e2e6afa6373",
- "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "f544ea08d2f6086dc49c4d635116f3b4b804e5b68251e5fad433d538ae5e8226",
- "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "54b0cbb4292cc4733a704017775e5cd4a9be34d53a4c666d6fc556472b508e1c",
- "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5e81253ec483f096e23ed98f939220b029814c041b4b72b93e994cead3dc4f4c",
- "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1a66beee5ccfd8b0fb4de52bccd11a0057248ac7fe8daf4f4d6fe0c0088044ea",
- "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "2a6cc2e98ed575df64661595b6e1ec2814ed79fb63fe697c0201193eb52d70e0",
- "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ab3f70ea6977306c26c9cc368d64a116716f9ac6ad1a55eed23ddac894e7717b",
- "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "ddd840c0c19077b4b45dc85920a2b2a37f176795b3d9390f1faccd44aa3d55e5",
- "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f5c9f1df082a7c48a63e786e5104d31e616c31d47514e9233b4a86d24700159c",
- "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "4d39fac4d45dd73221b93b1d1351988ab4bf07ab04187a815467ab9b992f9490",
- "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3b6b0d38a3644028ca76347d5b82da6bac6e761a235516bf5b321d12ba909519",
- "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d5992a6e66207e4ead98d5bd627c181a052775f03ebdd2a0313574092a12abc",
- "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "217940928d5c22553f910f3abf7b56bc832ddcd36282cb85c4b8142f9411147f",
- "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "67ce7cb12cbd06e114a2f5dedd1d94c844f091ab05a764579dccf30e6158ea46",
- "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2cb17c66bdfcfeb567bb021c25c33a8c2b8df1366601d09fd9332278517a2f4c",
- "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "e25a7fa310019a3457b317c9e3fe052602c82a25939c2ea8c012ff6016c622d9",
- "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "1722ef69ea949c365f6b64735ee31dc92082db1177b94f0086b8aca790378398",
- "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.gz": "f171fb45017640db15d437198b25758c49649b64338118501905f48ce957b93f",
- "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.xz": "59c5f8ce9fa9dbf3e96dd8a38a52b8bff0ff0d97c081b1d343a654257df1e500",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "4f219f3661a03330b33d33cebadd5eac759968e1c4c3449f0f27433e715ab55e",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "5aed2d9631a2aa3fe016ae5e2ee312aa5357ce470c26c01171d14a159af7750c",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c9dfb9c486cedac794cab6ac524805c10d2853c15416f3037ff4a5098514427a",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "a1e0aca8a32700e62fbc73b17dbb0be711db4e9caf535440b08bb1465d6a9c9c",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "61c041ba51632c029d916f274ed8ff92f1f7b23b5e9641591828e6251e205f6b",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b61464e9e1c2e820a237f1f3d91cae8b0e62cda16dea51b32a8cf695b7a5707c",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "1f9b7e500b22c34fa3080e4a15397a3a3827797c237d21459841055b5cb6cbaa",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "97aba07cede4a9228ff1b937b8e884b23e9e246afe39b9d68896e6b4a346d972",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c82bf6a11f468ba1d865a3cdc036b03f01e63a23272512583afa9dd9bbf95824",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "2efde3ef57e877f7a0aaba264ec14bc94d0cf3e4451b072c004c37e3f86288a9",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "17df9a194a8cd80871981fbde5fc333794e36a4ab219aafa7849ffeaf07d95c1",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "54fd84ff5bdf3221b151945ceacd71f51e71898927fe4b57887a0eba5d3e3676",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0bd987dd970f98b297afbb7cf4906b1d2045ad09df929e8ebd291125e3c36126",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "054af5ef3148902a8fe07c2c445ea98a526f63203c13b849ba464d17145afe07",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "2228315b5b7280a7ea9b3acfdfa1a8f0921391f67d792f32f53c1b303565a20b",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "777d4c1c6bd3430771280dad79aaa16a6903901875529391e4779f0c2fadb0d8",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "1d2a74d8ff44feae6551613c182a87d078c0d4cc8f5117c6a3763f28d0af306e",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "67ab7519c7182a582fbd3e477b8bbbcba143a76e442cef94a47f0a03fa36ed05",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.gz": "2c2a8ca955cc99e86823bf7ede5492b04ea28c182a94d0f59b0d542f10128e88",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.xz": "bfd421654ad72aaff2610a104d0ea2afec579803ed16ac70ab594067cac292aa",
- "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.gz": "b06020ac4aa9b5236d1888a59e2dc3519ac63c760ed0ef47b706466df437d5ba",
- "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.xz": "92ffbe22d8fe9474aef42cd3bbe4808c4afa212a3f65f07828b39848dc03a1f9",
- "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.gz": "55aa7b2b3b79aba674bfc496efba37400086e192e6c7fa8483f5501ba31e68a8",
- "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.xz": "6219a156e46b7056a9046ab5a58af1a5386024b2961528a54fe6b1c3ec09a91f",
- "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f43fecdf75ac81f8b18ba5ec59625ce93b0debd27c0016edd76d5058e8182118",
- "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a032b56685b2b8431068565d652e5a174dbc9febe6de96945c037b96359d5cfe",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "bdb7d197cc36c774fe4d59a1c86b46325e93d82462c1cbe87e8ab415aba78e4c",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "061cb27b6d5b8e416457137334969733cd0727afe75d63d7954ccf547b7edc51",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "895d936a579c9642efcfdca400662264b8ba84ab9130f88e4dcd11c968a81e4d",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "29f3aa4005c64fa28f99af20221956ad21aff4a37c5cab9723959ddebb3c2b9d",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1e326b0ab30a2f9172a55272926cfa62dca9fbc2c590579f6c7685b8b4ad789",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "616fa68272334400c9110cf5a2cbd7d5c6e462cef8d2c5bc443c3ef6e9843e3b",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.gz": "ec7d513787434a3cf2d523dcff7e37c28cff4b09b13be93c024729cbbbb5aa83",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.xz": "5a396cc0499690193879d10da333f5a3acc6586f1c216f751a1e62bf1a8b6618",
- "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.gz": "f9baf9d74b094cabdab59c1eaaf5238caa175e7865c3497c34eba68be5b2d756",
- "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.xz": "0c5f14f311e29233057ea466123ef9c33e3fffdc798358f0f339ce3869ffe9e4",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "e3c2ffd3d69ba9035048fad22103989ec97b892de955a94015e16578e42481e9",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "3e716d6aab270f764233f50a25a33d37a6d34c2dea23b3cd1aa5733c72c13958",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "65b74540b47fcf7fc8a88cbc5cfe54ad67c1060722c37af7e31bebe2b3c204ed",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4bf4f75f7c4ed171ef7705764f71eb899763205a9a4727343b96cb209691a97c",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "be073a69a1e9de0f87511a5a8b3454b3a2d24319571c25f347f7213c872a54bf",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "57be5edb2c00745235dc486b4e6e6f0e6b40edf16481405abe3ac360190040e1",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "53c39c89d7b19e45e1a4f32b07eac8214a7d5d277a83e4a88d7ab8820bf2de86",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b9f058907117e3f1921fb5ee73e04c6114154870067dc8791382f3099aeb5c0a",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "bc3d93dd7381749a7d24eb904c7fa74aa6e2a575ad1af5ef7e34ffa07e91105e",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "b605ced5cb597a2973417f4de55fb39cfe12b1209c4249ced9232091395d8e91",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "315432af4541ceabb14891da9ab6af6717bba88f1caaf216053f75405ff8997f",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "aa643ea7978ea7911e50ab65ba0af7bf018a4bf9ded1da8e161ee7ab13decbfa",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "3f780d36c780b1379fde18fbcd6a1f75efa766b56a4aa6933c9bb88dcd4f4ba8",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d0c87b4127f10c85368254377013053747c10d2d7dafae2f5643a3526f938f48",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fb4a610676f9102dd206a1762be6bf7838b3eb0fa08629df8199573246bfc38e",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "192d9bf1354737dc576bfdcc310c936e065039f39303370008dd0fe3d3e8ec65",
- "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "5dd746bb8db14ca9f968a651f3ae7e3c3c5a505800c0c3da8f6469809a81230a",
- "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "2cd651fad1f2820a2bb9b828faf292d3029ce633d24283d9a5363a726a024044",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "06f337db74903b607d09151f8a5178ce48e8b5905af407ae9b37445fe78aeed0",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8851247487823bbee990937a1f83578d910985ed4055fe3bf339871a7aa28bce",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5696a2c0fc2c3141d43f2d97d8e4959310032756cbdf0140dde28a5843b431e8",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d8f9a3669d550f1c6f338d99ea74f4e48771620d4125bbd408cc750a70ee4686",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "326e4ac48ef1e1a60c434699b5fb09b9d0581e020bb745196011f2f61af41a13",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "cbd10db975412fe275d12b81cdfd5e97c0b464194639dcc439cd72a65790d601",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "977c9e94e25fa9a1db5f93ec800d529d80d874ceb2ed3a10bff63639fd24da59",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0729470e2138e90d9140e30779d7397e58ebfc1ec243e55caf90ab12ef904da4",
- "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3115e3b7f0981dba799902b212f350608042a2beff3bc3b32e930e9c9c3cca17",
- "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.xz": "75b3d8eba51877916129d8dec07bc86ec6e88076af79cc221e8543695e64da63",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.gz": "9787d23a7078c94b4ac33d34cdfb68da586d777f020a6284bb1540b54069f476",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.xz": "c8f9b933b2e9c955e6bbcb141082f6b5833f89f34de16e14f54e8d4aac02c473",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "ce9ea3ade0886bf7ea40a1066981d172d915aff4c54ca325d72ed823c7e17787",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "2d2442ed2ac017777d3fab1a3f69a578a9db1139fa1aa63dc87113071f08a6f8",
- "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "98258ea791d398c6a29e1ebe28557aceb59ac228a0bb1332bdbd9f702c61a4bd",
- "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "a4172c8c2b719d0391654968377fdba932343e444bc78482f19f731ca45806ca",
- "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2221360e32bdbbdbf073a4bc1fbbb98b86bd0a1df526cb8dd05dd521ea402c7a",
- "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "03c53e31762e5ccc58d1296a8fcee123592dc6d3b88d0c81ed1f8305545faca1",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "612eb9bc2a06779ec05f6033f44b18f283d6cc8dccac0d5c81a6d09f515fc077",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "70ad4e52227ae069a9e99cf53e07470267abf1f2ae0398192ac854cfd31d50d9",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "8a5dd3dd62cb31c77aec2e00847812ba53e951fb284c74671cf3875b18a015eb",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "10650efcfda713c2a3053a9c505847dd021bed19b1e3af12d58742deb76cb421",
- "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.gz": "6fb4f4ac2b448bebade72ba2080bdcf579b6a40041b311301452ee41ea267ea1",
- "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.xz": "6e0e8feb477ad35bab1ef599f51f64b4720dc37194dd6354a7a4bfdbacbf2c82",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0b0c0e86be0fb63dd56b419f0b8d05eb59841649120e16a8216bbe490a76db1c",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "c54a116404d31591d6a6a1a332e4bb8ee177ea7a0367b11eef6a8cae6c1c0325",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "14313eb7b20a3a3739a28406b1544cfe421c593a3198b081956a1a54387cd0b8",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "54fb4abc77fb6c97929641095ef86e559a4cb116cdac7dc4bf34a81aafa03681",
- "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "9a2a5b2d3d5cd98cb3f9a43fc34d3dd0dcdf9bd104798380f70373440edaefa4",
- "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "d0165b16890da11196a1e4cd6b48d545f44ddb996ba9515a919ecad85cddaceb",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a42e125c252eed17664a50713d5e2f0c43f0f9ffe54e471500db75352d1e2147",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "705185a2b4b98f6ac16a9106af60f30618c24d6d93ffb0283a41cd31f992750e",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1a01712d4b8b470548c22a24e7e9524c0ddacfcf15459b490531e68e62b8a400",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "a86f8080ea25267f7e127f23bb75538cc3032091061b1fc3ce95c917d2a1cc92",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d6d06becfaa6a4b0cb7131fbadd6cc6ff58edfa11fc6d98e69d2cf5388e8bdef",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "65bafaa34e506e8bab15d2442742fc075dab2ea8687c69f6090acf0204b6fb06",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "53a48c17c4ed3740049d0c88b14d2a1189e7ef5fa08a926c8ca26ec5b2b298b8",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "14525b83b69fc54d4c808ffb69e06f015850ea9186837c670dcc23b5bc66d4bd",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1b8f11cb2ab076f00cd601c1465ff3a2e3857cdec255c8ecc1697efa713f5626",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "31e824a6243a6e15ea96a2984c69711e312eefa5214ba349ef6d6a4c42fffffa",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "89178cf43cfbffea696390c317230d39108e529803e28ca60d37b6167e589dbd",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "8b9fc0f9a2297d15abc86db95ac8768e872ec1acd21461e599a1aacb80f4b182",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "13ec0039303d3df358ccfa4fc19924df0ce17b31e8f57b13e7367db68bb9dfe8",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1266340a228c8cd657d0ee7ef257d80a33b193c4ecb742cdb82d469772311499",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "b100adc79e776116a267bc918ded30c4c8d27d83ed21f65f9428ed8831d101b6",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "6966af76ccf83f37657efc4aff88887de81642dddc3f2ef59dcaa91219d4f674",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "0b7a859f952741a740458609cd207d5f7291c054fc6d9a0191d3acf0f216bd17",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "2e6e61f68fc3772a6c3b3f0b3be6d99bca1a57b5f568e87397765cf6fe867dd1",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "881946b261399e50992beb3cc613ca2141736a7480103fa1fb117c1e7df2b1db",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "223a78a4c5055ca00a7d5b40491aef9498a204759cb388e734408e305999713b",
- "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "76d81922eb6f61d33c10f2754ccc9b1394ae09feee5818b23b62f768f0e6a370",
- "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "be57410669ba5a516dc935fd1eaa73b2d0d3d237a2eb184a8dadce919bf1975f",
- "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cebf48de57e57285c91092abc01ab1fd9bc7eb660eaad3db2ce71877bd6b9352",
- "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "30a8fc47441c4f7b34f540f5132b3d7ff9756e8906ac6e2b9df5ea8fb622ad65",
- "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "7deb058683792cd3fcab92b950f653a4ba0d2a2997bef508c6d1d04be319f057",
- "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c5d26bbe5b6c64ce9cae78465d22faa98ef956dc4d8bacc91a127a7f439f7b11",
- "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bf06959a991270e9e15d538e70d078a5241b6e87d62a55a655e4c2f9e8ea2964",
- "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d85b330532cb6743071ffa117fbe8bc26b9c6167a0ff76c0ba32fb17c0247c70",
- "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "7dda5e010ddb4afd6e6efeb9f43ef17cb30af7ed9f172b59e6c737b2f9d66ef8",
- "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "35d8feb28897bead99c17d952b711888f2f6f613fef767f28e3593fb4aa2dc36",
- "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "2e7067692c10447d50df8e9871f95b4ea925a88c5792f973b3c51325afaa8457",
- "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "4b2d3bc61727c87f7c2ba129e9147621c3e3efd542feba3acb6596ea91d10d71",
- "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "093aa10e425beef7d66e9986b045543b3dc04c296fa3b3fdd9071fd6d61b269b",
- "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "8f3512c368b7c44c7d8ec9e1dbdbaed344859ebe2d0dcee22118397d41b841b3",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "adab0b58b93d37949eb35d4a6f3ba9e6b43630e4a82f1d9047116f1462cd1809",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "6a0410d1194ec0c471e384c5d02aba555efbd47b36a3544c56674fc2080c51e7",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "19c8be8430ab59b92006e0bccf186687569ca172b54f934ff4763da20cebdb58",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "6cb9647a504683fa5c67e5ab2e737bf1d6004dd4a7ffbaf593dea0f9844ced6f",
- "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "cc2d94e753035ff0b49490173b042d21f1ea58711f7c6ce5cfdfd79a76e539b1",
- "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "de398391e577f2fa09f369fbea4114c6cc0f1412884c6f52c97d71c74920462b",
- "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "feefd67b9c9dceee7ef7947753ebd990a914d7a54562b718e6704d35a1f5c75f",
- "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1b550a911a51514f8d69b9b763cc3379cd674615090652a253eeb7b585d2d97d",
- "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "4d7d78589d6d72e5ce60d6997394c4d7ff03fd2bae471ef3334f1d5bff9f18d7",
- "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "ec499330b2f63047eb43bf98b1e66d301d7ea7015447c83307ab528421387502",
- "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "7e48f11954d44dade640c86cc87d5841ebd708643cd5220ae7d07127f71ff333",
- "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5038770dbb2dda71d32c4270653fd3ece96062b24ad55dc8def6475e464210df",
- "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b8b9a59bf1a9127b26aff54dde3a1da9992a99fd3d601be7cc1daa6ce3c7b6e4",
- "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "e0a96a8b105466a3279da3d9bf589724def7326448bc6f51ae6f8e8aee2ac880",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc3a8d935ae2101cff8af86fb066c09672f9fd0297cd9d6b960c9f4877618e98",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9bafbfbcb01e23f58b1adc7fab26e8ebd135c5c20589887278065f75cb5b5350",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8dd7c2cbc2c24e5220ff6a7f5caffcca6605f3d76ff66f766af00ba4bb316067",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "963a698d49c8742ec5c7520fdefa1668db573eb01bd7774f80133496122b0517",
- "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "3a01a35a10f0efe48cef64d45e80fccab31df8287f500bf280b5d9bd5784ea3a",
- "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "84a5b9d9cc21a13cf1e2e1c29e7af63c75690cbb2293c63fe95e075ebf59815d",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "946e96f404b8a9f4c8139e90172ea26f3a6c509effc6e1ff16a49dc9ff6cc1e4",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "787cd874aeb33e4a4fed2726a571d39f6687da20625aa9a485a95d7167b321b5",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "70fd17c069fe4b6a318d887794c54a142275cc65f088a7bcbda5bbbd7c9d6aa7",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "15ce829bd9ea0a1ee918e7887392ce1e74e00b23509b802f5f45550176d78768",
- "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2edc66ee89c319ef7c9520c5203185a5b5203ca4ea9996e0142075273ccf84b6",
- "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c129a2557639fad501c7f1474f45535a55c33813a889f08521f4a7d527010ab",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "354e644c51ad5863bb0eea09e0c5d1aa32858e7025c039d693e2e433e1c18c04",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "6996a329a81624537d45b2401b8dba81911e5c61d2fff6bcd63c5fb15b2fbec3",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "97d6aa47e209650860e97d442f7ec5c5da385399aa5f06bca4c7f9a08767026d",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "dac5cadd67e5d162e00861ec5d2c96166fe1a80954237068aed6072afe0f728e",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e0161120cb6cefb23514c839eb2be13a54139d4f408563bd9dc1d6b9d665496a",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "94bcd63f3712cb3b09948ed62c8db889e2bc78b97d868c89386f912d0daa1b4d",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "00a37ebbf36bd66ab6e0b957e93c7a2e5c2d8567583c65873abc1c79b37bbabf",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "75589caa1835ee12362a2ad581828c9faf0d527f48d5a07c1d7f0b810e035def",
- "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.gz": "2276b9ef2ff2faa665f15d3572abe0d13a5bb9ec0ad08a6a0c00d9e143464993",
- "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.xz": "fa132a08849d7c583dbf37db97f3702c263b17de595823d87fa14e56ff21ef3c",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "47454a419e6a87b057047c002932cd2f0f52a77ed4c3b4e4d9b65cc4f4ddaaf4",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "f9040fa310d122651461d026f43873aa18d5f2c63a9f3bdd47f9a034e4153348",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.gz": "e143c4c8d394810c7734824476dbbfb2a73b3b62cb8a708f796e0c0332deede9",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.xz": "53c660ef68e1898574f62725c2f50fc2f26539143c0be0675327a33511142f8f",
- "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "e419db2f8f12467335c8571902f1ed163a5407394914f55416fe948525140ec5",
- "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "efd2b6df7dd439b0ae0312831afd4517cf19adf619916eeda1f571daf1dae723",
- "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.gz": "e669378ed5da5948dbe232323ef3926f37ad430feb8c398259229fd18675de20",
- "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.xz": "5a26a35164ae44467d256e6fab0e8f45731e8840204635ac9b1dd1d7d8f96810",
- "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.gz": "0d922ff7d7658c296246c22f4440a8975c8036f7159508e2fa964d1f2ad3aebb",
- "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.xz": "d775ecb6054216f0f48dbd0acb7710fc097ef6d61df9c1f59139721ada7bef8a",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1e830dc490e9b00b86c9d55c974feefdd87efc06c1bb90088b41737151987dce",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "cb37a89a871d61849f9aa262bee7248813a8c7a422872aa3926f20c1adf4ec63",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d83a17c374e937b9a06a364d0be980f4dc953df01efccdb3a0bf853ffd889718",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "94fb51d1db6482adf683b9953fcc942923fa5c85cbb63f7b05ad19c24272a21e",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4b7cc0a0a6b07054bb1da0b75d5f687fb38653a7b31f7610f5a90a402839e481",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "267f634ec4e08d0a76a75ec0f4ae037aaba44db3ac2969ed3f34d74db43bea1a",
- "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "3648f1129895e89467a569219570061a6c50937d87bbb407e6b3b6b1f488bac3",
- "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "3a7d686102d9f2469e180a80679db52b6c8dc8ca35adf3e50a25b7bd35f4c6a5",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cb296c0d9e07e00b8561c2f39a7dad9c9d74e224658fa9a7039e34d4b5f3aa7",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9e951fec5ee4a4a655693d1c9e205413aeb3120a7b2c0bb6673f4392cdf9fa6d",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "35b6775e13b79b946398a65d6cd4f15d26e160dbf44718cf177679964b2f3cec",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "84d127ce90d62f1698a948ffb247cba400bd162b9864d2ca7c0240a46b23c88b",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53a627ff89fbfd2abe9b4354e25e02d2ae8d05fcf6f6cefe99b84aec9775acd0",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "7692b0b44eea139874fb8c6cbaca46b8f156ce392454ee4891daad532a5c6baa",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "853db076a2c469e37003fc8e52af2d0a2e31cd7f74c51147f00b04532df5721e",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6925429b5f25d0454abbd68ee333623ccec9d706fe0ec528fb619b2688528770",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "13e920a779485d04952e4c402b42fac9b7570098e5e32394996cd985889682fc",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "158062a56de043afc4acefc8eafaa536c3018cbdc7696b6d909c757050062b42",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1701a13827b3ab22fe78569704d39a2f699f463b2f6f159407a39eaf4c7fd6d8",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f10ff1def90cb101179f11b4b07ceeec0ae26ee15c7a85f80e4e31c61baf846c",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "20c6c718322cc341f0e1f69a9dc42f3146d10f32075d32376a241a90a2e40f48",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "d0429de3b0391f063836c765ad17e2fd1940f737b69961f501eb9d2573cba6e5",
- "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.gz": "31d16857f6fec033e6f79121040eb025c28a1d049014c6047fbf1057450f86d6",
- "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.xz": "997a9aa6db5e23f476aefd3f4799f986a51fda3e31e2b293309fb65fa92b0370",
- "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "73fb943292d50a372f2df490e47235f395ff7eceac353be74fde3adcf45d363f",
- "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "30a4a4cbe3fb683b8e846052a83a3185d1b8d714251bd6ad0bfc251b49a72121",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b238cffde0b9ae2305e501970cb9cff1782331f1cccbf8dff84979d1ffdf0625",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "5d01b8e471419036703886fc7dcceb89ffc88fa62994727109865339fbe0c92c",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8b8b48fc67a2093502baf21c372870bad42840377548e250023c9f83884322b5",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "a9e73e67a7120968474040dbde7b12668bd6e3a6b4f9d91b8c9a66474f68e40b",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "4e83419922b4f02b1c1c62ca14db65863f4226cbaa61674ac792e860c026a948",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "20d7369422ebb89f8e1064616a9842cbc98d9056910a2d0ba46f8bcf144cb794",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "05ab3071cdb3ea4e39f53e179c754d2cf64800ca1c38ff887e45f60294d6e222",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "e8509c60955ecf4938575a7a40091ba5d7aff77c9c3e24208623882d1bb45e6f",
- "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "185a3e399dcc67d8fb43a0174ef8e15c36a068b82aa33db8b42c948c2ee15689",
- "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "69be7881ba1b2d4348ea06fc2d31a62fe484843e660f399349c49a17852cfaa7",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "74c3a25a67b10abbefadf63bc09f6069242267a9ca8a9177e2f46e2b29869b75",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "9f0d3ce0a00b33bb591d6b615f9cc80a714f3ea0d787f410da7d643ac5e1144a",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "feac518beb813b2d553d6ee1ce03daf890c956918f0de69d5f59d4067f2f60d3",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "aad640ae5e48f489148e1edf5e815a78b19288d916615e2af8805f0023e15686",
- "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "c5996c458e6e1a3f3dbcb70debe562bb5d0f4a6eadd97932d8935209fbbe6809",
- "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d5ed640d08bcf3770b80386282c442d79af38e4c7e73be9617d0ac72d553c507",
- "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.gz": "aa0dd3e77f92c1cc21f550c59761a437d3a8ddf31b23040e8849dd116e209835",
- "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.xz": "3c7bfcd663507730ad3d07024e1d884dee6adb49343bef0cfb8fd07b8a56c6e4",
- "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0370337cce565e6e363e6de59aaa8c2e17db49d79496086c20f00d80198635c8",
- "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "30413f65a4fcafbbb6a5302cc65bc35edc549cded8ce6a32277ae9a499adfe59",
- "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "0e6ee26e237a185a26068c2c69ef095ff37f24af7984bad91196ad253dae196b",
- "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f0185e074bb0c6811d244502ce93384cd7256840fbf64025e074d97e4ccb03a9",
- "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a2c1f733c16d62300adef3ed41f9c5926f704e6b3d47e98cc615665496aa4f17",
- "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "3945ad08c0b296a700bfca778994fd93bd3cbe643517ba20a60aa1f9a88eb2cf",
- "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "e3871e21ac938b4bf3a1ed44fed2f05fa3a27d3eb000d98876f9f220a5fe9175",
- "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bdc7cddaf0031af1b737fd0c2510ef018d68ebed914200ae8acbfd31ad38ad06",
- "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9ea42f7e50864bb514293461d3622096fd7a73e8f487578ba1425a3e8d26a970",
- "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "c39cf38c563b16d303bc2cde8c67527e7d2a74e8c5375af73744d9a9e3dc5e1e",
- "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "dee289bd99b3b573493160446f923fb2f2b66926a5a69c0a7704eb2aaaac3ea8",
- "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e3c89f1baa358b6a28ae567981d5efd457d2df61f2eeee19bceeac715793510b",
- "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "748df03717e997a01a6d222bdb6d6c0b1e206d9be55b74c14c3374a333ad8d55",
- "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5cbef13c038d0fe822920eabf91c152a7130e50824fd203e3fffff4a44b10bcc",
- "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "dd0ec4dba66712a10c3ee5e5ef1835210d8632766c17a4afa1ba0594b6fdd35c",
- "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "30d736ad6f32019435613fec04b4474795c8915e878a528c46de453a25df1bd9",
- "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.gz": "14c1ba057a56a0c34f129ebae29c6a9453faa03125f1fe88b564355c186d42bb",
- "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.xz": "67d1c23c910e038c6238d286af0141f0a954799dc12a6b935d47239f4d2e8bd9",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "7685e5b408bf70aa4c8af5ce7b5e5d5a6ac7125c75e7b10a9b3dc0e2dbd4cca1",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a52b846d34cfaeddb57d00d0209b1829fb129049ef61212937c0f19fff5efc91",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a5c2dce3211ec671959abb8b2f7fc34b572e3bd44362c61b98e0850c0530d1bb",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "ba948c4a665c349732de9f8faddc2f7e0f7be5995ad88af44f8f4f5ffd4b9387",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "edf7d1c9c9288cca973a0bc3a90bf005d25df324c592b0b8d051f0de98b85f78",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "0c01b34ed39016866e945e0f01de830a68c54f7eef2ac83c3ab85318b01debb0",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "6ddf6e92653ab0c00ec524e1274be3e644868cfa867933bc383e8e3e7674945f",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "14353a439a306d0803d89a3ce3da5e5c91b9236ed84759fecf8b38ebe1d8a8b1",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "4d7feace1b414919ba2e682c748e24b31d811d7b54d710a7cf70e0b3c9c1a591",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "35593657a752a66f3052752c67c380e7ebace191a0be78c5def2cc3c1fb3a18a",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "04e752df5371b5d3879c8514b7dab27bcb35a7b8c7eaec0ec6e3ec5f51ff84a2",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b0ef02ff310386b80a9b6113a6e44a437ab78b42480b4d0a86e828d97d92a3dc",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "387040cfbb92e6b2acc52067ab2184313de2588a6af65c0af003432bc9e69c75",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "a617e0ee647908038bd1b3f233b99db1a82b0f32875c9093cb66387f3b2bf430",
- "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "5ef7d34a33925b7af081f2e135a0fd20ebb18f711372d432a570f8983243c93b",
- "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "6003e9f8fb4b2a581e359e2e4f1bad83b9055d5a0c60fa0b752ef1aa15957f28",
- "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "838f7773a9aaec82c4323d8412a441eb3db94da8384bc1a4a50969c5beea9aa8",
- "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "403a2141367854a281302f9cdcc2d1b37a2415e8aca4cd5e5308af5fa254601d",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "6a3b69c8352c8262a37ba0104043a66bc579fb033166434a1b9eeaf115d8d1c2",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f272195798b40df211b1d2e817e91bba68a1083026159cab4414ecc88ddb06f3",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "5ec04606fc7196f9a5cd130dc4c98e8df58994278ab50f7ea6baf2cdca957b07",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "a24513ffce8f76fa3334932268aed073958f904b1988d337df7bd4277d3a139b",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "8f078b404db9fabd8b0a45deb5110fab32e2ffe5f604f74ef787d9baf3f857ad",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "3569e3ed42cd9b4dd6f8b2838329c7864c6d3f7a5242cbdbcd9a756e6f2ca5ea",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "afa42b42631320a68d6a99902fd48b1e72d2daeb07a5be34b833f22ba6dcb67a",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "839a8576012332bb2ad01d5b4ab24d46af8644e38b3019b36c0ba5a9417bfd07",
- "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "aa59c2ebf3bbff46b6c09aa1e7784ebf83dccd6df60e1295935ff3cc954fa755",
- "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e7f479891368cebb99f41b59508a3904321d600e20cc2507954f78386a448601",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "a971a861cc76d0a2a4c5fecfc4537c8e1c14f4d43013bceeed395722e8620cbd",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5879a7a9af9c6ef6397f75e4b062527fee5006d655fac5b7538915b176d9faa8",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "dc66ac568c709f4b580b46d567bf2d79481566688e0ae55df1edd2a5f07fe0a9",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a2ea4554d52b1181c589eefdf67c60bc0831f2e26430bd6e5e7bb4094db5dfc5",
- "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8d9ef4755d32e8dc480db1b130943f47b45cc2ba69b1e9fa3dfa128d63780b70",
- "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "3cac0853da192779f4edc5bc3c913e4b93a02ae98b883cfe2717cc58329d7469",
- "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "14c5197f4884f418a392bccce9ac3c9a09dcd0a710a337bba5959f5570c41e98",
- "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f9b14921e3a6bd006479a01579e6601787082ecc0ec8e631b8cea6a4f1c0b967",
- "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "9f4efc8229a5a8561bea614a3df0da49349dc4118d72905ecd6feb6b6e1eba9f",
- "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02d829ac6d9013f7268e505aa2b0aa99db7e25ddc3d6555ca8f9a4c5ed3f01e7",
- "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8192413e5e376bf957a2caffe8ab15b3c235c714f8214a0f3a46711a79fe33c5",
- "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "be155309daae3cb39dbbc874b2ddaebd1ad303b09f40e130ea8429cc7c9c366f",
- "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "318c3e8235913f64c9e90b0e7c1fb50229caf59c02f0ddc702cf0728d54dc41c",
- "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "50bf71e32ae2228142ad88d67e794ab00b632147fb554ebbfcda7ec79304ae2f",
- "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80f5b76c38d7300c5aa6a71a8b3325b28290b1bb936dd59287fa87d6dee044da",
- "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "30a71791c6ed0cf3e0fb955fa697549dcd13d2c0f3e357d9723fa729c3a03698",
- "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7e5dc3dc89cb21638b452eb9b5c9f008803ee5845c973f2547f59db01b7a0100",
- "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e1a949b29d249361b306af38bba7118aa1931c14061b6fa7621027e9994b519f",
- "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "ae4186e4faebc9ad8a13f06a97f96c48cbb35353ad649e25f2e80e519a9d272a",
- "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "ca4466d872bb050cabce20ae04eb915ac3e39e4788899db7bec5b51ed7d5b579",
- "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0f39f27e2ee437df69975578c6e32b6e293bf3129f7e63bde83091330aaa496c",
- "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "55700dff4b4f3f7d9dfee3317d984afe2b44681deb7b074441b41cfd59e497ed",
- "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6273db29aa2715ffe38593802c520adafcbb2300ed2595121bff628686eae675",
- "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a4ce848a1083c16bc17bd22345427ba4c920cb887e90d612a8c3d1ddcf802ed",
- "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "12a715fca796c192514157b43b0296d688cc46e9d81416a67a0019184c1703d4",
- "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9a651e94a0cdddef7c7a56e356e25d0f35d0c592b6a54f2cbeeb3364fc5d457c",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2ea52a8413a43a10165322135064692faee0d03a453c4b28ddea480b153de5c8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "843b06b9b21c56fe1749e8a5bda908dcc2b6d8206faabd04d050ce83f8c32b73",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "69210991cca5a07c0421254a2e18a29de28ab5019b490a576f7bb94496ca10b8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3f5a59ba68e004c06cb07ce83d4a567b77179e11071a8b5b8ab6fe3a70bdb872",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "7225fde4655ed5b4479ff9f4e61237a16280541f44aa751c5a06d5916e8fde3f",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e844e80d99418bea9e7cf96cd389056d17f3be60e9412983d91c64e107a28b92",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "6c1b031bc408349c5d15bf494881dd75aa68df8e7417e6c72c061c7d3270cdf8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "d24b970a15dfd41cb1b0027a4a5822e8c2b0217dd1984503d60a85fc6acf7414",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "5b5aec4bfde07863d2d5bb71f38d3459db0659df75f53567be6fbaacec33c7b3",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "851b9582bd2518a3e050127c46e59f7bb6b24d354c6e89a9b0fe4d3e09cfbbb9",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "758a05277e99d00e21ff9d8abf96a6da71350664a1eb85adbb1ad4cfa1934255",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "6431dabc8ef72ca252b257683fd2f5ce3c1347b18ff1d4b7ee7758c6906ba2af",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "51bdea94714c0892ca7020ddcc7c55bb20ac69eaf5152a38f83925d793b90eb1",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "660a23d1430164b01b3e1e8b50233be07fa0988d90e9880bb9044fe661537cde"
+ "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.gz": "f7dadcadc22aab3ed9ddd737a9c2af05f42ffe48b431bbad5d43128130480279",
+ "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.xz": "0ee7c052bb1fd3f3655d9ff74b3f38ebb256d3f523750dbde1be9bceb207cda9",
+ "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68d914f773b122bd1ceae13a55d3c8365753d09d4371e3962401b9a48945cf20",
+ "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "b0204e516f0c22b956f227555be5665df96c4e0f60281592b00678b4ea8ad4e9",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "77b771198aaf78c039df9c08493a9af5d1eb02e6b88bd4fc3b42269cdbf582d0",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6f6465db2c726cc3d2db73150377ed17cbe164297f8cbffc51c8194494cb0384",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "76a8001adffd5d7a607459f1726f3d68c95e6eb4925eac9ccb77b213c37d2385",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "07dac7cfe68cb6b0a1872728c1dfb3fde0f9fa27a08933494faaf58a5e35865a",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d2d6d2b56cbcc8bb5b2139818770fc155146d6b4469678de8a1e8249f15137d7",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "5f97d1449b9c4461be47615ab49ec408d8f1981b7a1bc0d7b7cce606c14cd5ed",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "097d346e828a37ae5be077f0896796ab6238194846f8ae279cd9e2f510645625",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "71a7906aea42e1048fc43828ece3da720eea4f9d4ff59e970e273f0fe9191e12",
+ "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "20e49a6995503dd8215dc9f56ffb87dc9f07fe85a1b0d2f409313836dc0dda3f",
+ "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "b9388524cec65e789bb5eaf22cfd63ce837b9a98d1b769901597c6f061f1b93d",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.gz": "7b0bf29bc67904a64560402891d60506a29b7cd64007d7c1f4e168a574009a9c",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.xz": "c580c17566e36cbb91945e0fb9e592ac7578d32da948c70aabb90de80000f5c8",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.gz": "e34436449fb69b8ca696b4bcba8e18a612fee189ad8069d765813d39c708ad58",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.xz": "322836c74da2b221426782e4b5e174571d1da1935d478b4b8b948608a28a20e8",
+ "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab2361cb4cbe44331e34a50728dd56a3db220e08f1b29452f781ee075b236c33",
+ "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6375ef38e8e6270d6d932d176a7e62014daf153e873667f6d4a5335fa15f8bf3",
+ "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.gz": "3e80c94aef4511090e6a83f64b304b835ae2a8e769d3beec96e3f08c0faca01c",
+ "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.xz": "af954c96c823d711b372c94a2f2bab32536a4e39bcdd0351674252837096f8b4",
+ "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "92464fb6d0691a591637cf342842b42b940f8a84525f1e1f51493734f2ad7b1b",
+ "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5ddeb87b53749bc532322ee8435fd442adbfaa5e80f3b614b7153c40f46d63d1",
+ "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "1c60eccc658664853232131fb48dc5d2c66340bb95d242084c211c59407fa667",
+ "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "257aab89cd0d5d9af408fc346aeccb8d51e1eba5dc0db074db1f4b57a8d4aab2",
+ "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "20b1fa2138a547f5f6644acfbca9e73f8d228578a600c7710cb2fc34a20eb058",
+ "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "134dde13eb7dedb8fc608acae62d715937c168a9fe5a449262e9ac9b3f042396",
+ "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "4ffca03462b91b9cbb02a022546aa0e16118eb1950a8f040929e5bfceee2b9f7",
+ "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "14bfd567241f969de712240f78d83d21dab0bd11ac42da38a2b02da7a59a9dc9",
+ "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "f44113175429958961148bef66d0ec1b52850c19c035ac83b0d20139e1116d97",
+ "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3e5f05f0f5aa2fb8b2e63eed7b29ce67831158648f64c2892b477b318a86e300",
+ "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "76258605464ea434a2c28c2fd05f1947b2165fa10a2810958397d8352e20215d",
+ "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c4f2e0756f8571ed7b1bd82702d91b32cc40af58e0697c2f307feeb5755f93ae",
+ "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c466a280084c164ca4a120b184eab6403c80db962c0d2d1f2cb5b662746ec4da",
+ "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "b6f97111eeab0403c67965d57f9bee2ecdf5f39eb44941070d3cd06745f235a3",
+ "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "2ab5f013205446852a06f27b326f6454a5b3fb958413a7e00e1d8402413155b5",
+ "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "49dd5e7e3b8091546ef932f359fc4260e3f0b7ec851f43dd10f471c6fe50a5cd",
+ "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.gz": "ac20e50e745914c8431a5c6993b9dbb6bf7b745e4b45283b230207e7be1bb167",
+ "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.xz": "dec91c3f6eda827d3976b96da8def71ad3cc0b71fbe1b4e5387a464a8bbd85c3",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e11e26ad4fde6109808f4cd752c2a810c8ca81b890b0c09902be981a72c43723",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fb49db7bce2376335f4fda11cc454b3d762bd7f95c5dba85596100bd0c1e148a",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7703eb725703aeffb57d6a2c0c95c44b6e4eed09b4a99b37346ea895a1d51088",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "65e0f34d9b4af3b270d8d4752c94b58e54895d180fddc3f4b535406e16b8a356",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.gz": "4624bd8e93bc1c36bccd15b44f484059f485df1c0cd1b8bcf21c4855c85b7ea4",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.xz": "a277a3fccfba30db2942c8303db16e5112d72c7721fe7a777cf24a301b68ad2c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.gz": "37e034e5c83bab47ac5cd502d4f6385af270040fb7eb59221bc02cdbcf949d0b",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.xz": "d26eda6fd5533defbf3983f2bb9c07c0cba00abf4c346443080059c4810ef1b6",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "909f8bc8dce0276695f1e88994bd21ba2ad4a3ff66b8172e566b7907d9f2531c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "52807fac650c03c9d398ce6e5987ecfd5e8e30b5c4e94c320ebc2a6fd665740c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "3158dcde7e05e9871572dd7044b3c8466687d8afadbbffa4021a443f4973a4ac",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "551ef92e71c001fe48804587e8532b5032d419bd139b2f59cbd8c2e308e3c2ae",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.gz": "9dd630b19f6c9ce26d2ed6a1f46c383d6bc3eecf1efb80f15a651ef4408197c0",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.xz": "1f128e4e8f9e98839caf64e68fbd163de1d5323abf40f718643a815081f898ac",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.gz": "3aecc61fe4e056326182db5942cd472039f95788d165940df8b53742f70fb051",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.xz": "db3cdaf50925184df6a79914cd1c0df0c9782f96829d23428b1a0ebc814fb468",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "61df5ab32d3e11243bc2b8506c65af9d8a84a2bc93fc1315d046e20eb048c62e",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "42603c786c02ce754b4c756ac0fe4d88574231f5a8d31b6f9a1192680f8eb180",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.gz": "49e5d2df9b1019e21c14a1b7f8e69515c16d810dc354ddbe2429857214b3c33e",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.xz": "5323762166729cc7c3c5045b484ea2f50ec0dbdca15d8c7e82f0c29e1247f8e2",
+ "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.gz": "7510b5b538c735362ec6b12beaa9d3c8720c4ea1f686c643fcc40c5dabca5435",
+ "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.xz": "19b4d188923a820bc8424fed062bab64a56d33f8f00d9ba6792331f06eb0cbc0",
+ "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.gz": "77a5e84c97f83ea8263fd147e5f5781a61bb5bdbf1cc40a3a8a72becc8dd486d",
+ "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.xz": "c17f843d951d9fa72760e3a071557635da83c0dc279887648979277bcef66aff",
+ "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6e86b78826f5e3d18b2f2aa4f274a5d7bacadbde8d7cfc72cc89dbcb0455fec3",
+ "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e1b1e9eb09e851c8125319432b9fb52a6aa815b7f5bc82efbba7e375aab44764",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "a6589e628f03fc7c39345cfa23827be6cf26391848bc576a66c7701f18a01669",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a0cb9706216575748a953b6e36b59875c6bf9b9410d4a8085974e324c0cbb7e0",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "c803cfd7c803de2b210d5e9800d44f3365a0b4ae581d987b415fdfb990de1a30",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "a93310d2102699602c348901186992c1305a1a20fd0a2e5d8985a4f32e61eb28",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "2ce3460b436c8c44e074ce1cb8c81bb2cd37ec8ea8fde1b766f113b39412d71c",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e65f8409d2a8eb366f29fe994469f257b18e70ad0707be2ca9c144a0b6f9a78",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.gz": "a4b73dfbf9df497883b2f5ea3053c256838e1e706f312ee02e1b018b9a7f6099",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.xz": "a70bd19ae1fa41a3413f0a0b6b2beff569c1b16829cd675967a6d1cd92d8dd54",
+ "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.gz": "46eabf68836f62fe8dfb39c54ee63e9fe211ab84443ff17c46b5240e0d08e723",
+ "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.xz": "9a4e53e3e867e9e18959cba32078c4f7d588247b74e156cc68345808d7b7ecc4",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "66d9e4de284d7a221f66a2c615d6ec0805dc8f1a91a184cc96701cf98116be60",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1af2fd7a16d51e2f4bd6e1840b935e2cdc7a8f3b3b1144d22b42cea52b9bd185",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "cb479e676240ef682d3ad27390bc2498f80a421d321e9423cb923b972ea86675",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0011ba4db5a8310199011d37818818867703bf6fbbcd7e1a7bead621eda1e5f2",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8b192e6f0263d925aac1436887f67b24fa02f31c0fc708c30827f0363f032ceb",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "688755d433c1227db1125ee52e7aa643f27f922b21fbe3a5fcaf70467d159a79",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "b336cef0e11136ccf5c41669869426a376d570042d3c99eed6c448cfe165818e",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1be7d7f0de2ae63b9dd282efc24531f1146fbc7831b84d9c0cd2c8cbdff32fe3",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.gz": "33d49bd069b9fdbae8a6868e2cce6fcea26cfd0248372d3d3c977828b3fc51cd",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.xz": "e204295b8b17388d8b4cfc04de5690b4b6a377da12df7c24f930c064da787200",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.gz": "07584d1a4f4979ff86aa8b8be820810366c4fdbda4e5dec93c0a5883804a2103",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.xz": "4f73d8af677409960ac480c254f25547752ffe08b80785dceb6b6f1fdc0b6646",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "fb998ae84f383f1ee93fb946f396545a60d4a58f1f0107653f3dcf97e2cfb4f7",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "8d8fdc9404422d0519328d6a622262833c5465b1cba62a59951a05f59d6cb15a",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c8abc1c472326419065caed5567bffc4bcfac2af45fafb7f1327b468f26a0112",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "d905b6339363b2538bc39607c0fc58dae2b8023b1c3c1f745654a839ec178988",
+ "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.gz": "69dbb3e17dcdfa9e6acc465fae4427a2596e8bfc024cc18d30201f41bcdd1be2",
+ "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.xz": "f012832da820d59a791bf39c25e282c2b92bee75377e4fca7e9520162be62b83",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "bb742536d0d7b664ac7277bc5e45f40d64001da0ff1f9e088edc5240e1b35dcf",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "6d4c050229400ef1f2e384a4a360569309d1a0828ff07f97c73ca294ef114ca1",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c7c354d1bd4071ef69e8d91ee5c020c9aac613ddb2565c9a3a01fa41903e3715",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "1bfe9acf4bc7f1e58f1e5a721172df69be65e049894046561bc94ed6ed67c24c",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "96fe9952332d7aee42e61445226793af32995d0f21fde7ebfe751ef2f9acfd90",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "2f85ea745f03f779306f78ddff9389f4417d826258a90740a76b37bd14b8fca6",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "434b6eaffa2a4c798b4a6f00997d65c55d9fad24d176bbc54dc045339e654432",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "955fd83cc57de91fea9aea3f563c4cb5a2611e6dd24406845f7e8be5b7f25f3c",
+ "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.gz": "45a4818cc22f80252264309263994270b2e15ec8db7ced500cef838f09260fa5",
+ "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.xz": "8748379556a312b31788b5458b74d5d7fb2fa61f29e5528e449d216c21f4e9ed",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.gz": "928a6b77d3e6e8030c6ee454d648c5f6eb0b79a8beda3d11fc3578cc4556ac45",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.xz": "428526e30a28a9dba01943800a179b7ba144866f36dd69171a4fd1804345b75f",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.gz": "e1e43b61b7826fe4f8063d89896e7b86a13e41ed3a17ef2684d1bded5252b7b6",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.xz": "5f6478a196f1eabd6d4b58ebacf89c3635a9488f4b2f145283e9352cff5da7b8",
+ "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "65b23ab952ed313cc9de94eae473a28eb9b7d9ca8aa432f4d3a08c30484e30c7",
+ "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "949e3b832f70c3effa2b78363b42caf0720ede57722c360b710773bd7f3e1502",
+ "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.gz": "06667714b168e2e0d6e0f3e81cc3fb68940f77aa3cd3495d91ce9ff15502ab9f",
+ "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9794592856633299de53e697579c75bcf6009c6f05c7bfcadf8c63dfa383b3f9",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "ffb8b8ec98f9732602edcf3e4e628327f8ef80712c59ebaab5392503ed04460c",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "7f60c2798023bdf3993b443783d3d6dd350abfa3bbdce58ada3e9b3d3c4391f0",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.gz": "f086f349faf5f44b0fbd060f3c40b553aa5a6309a02c08e8a45d27cb3a820926",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.xz": "05ebd51df4b17c22569d69a65d9542b5010beea023e545859a23bb244162b537",
+ "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.gz": "0f2a192b970209d10f2ffb4f88dcb6637e1ed822e47fef8e0d3daf4ca8b250d9",
+ "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.xz": "3aee7e88fbcc0290219a8d980efb1c6d8a1642a1576393fe3b5d400a68b17f8b",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.gz": "251780731ee8c996dc1adb59148d7a0307642e11f3bf767c0caaf5f37b70b395",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.xz": "76c8cd535a4ab4f9c0ccca19986f483de63e7c6c0708e37de653acb80621bce0",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.gz": "ce1b7c98f381f207a26ca3fa5937f5e276eb8f91ef6ae2e0e082370e9ca1c21e",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.xz": "106f655c10d182b6581e87cff881bf081efe9404b52885b6efed4eb0f09a3a04",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.gz": "2cac777f7178954e5c19e266d57927ddf68b74aa5a0161e35e096569d0a6946c",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.xz": "abd915c242fdd2e8f7d53291b2d84d269f9c6f4c4059c725770c3e47e50c4758",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "f680956e937e421c7868a22ec3ac2a6de7bc8203fae17937793914f4a9fd1657",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "15c71b8a2e8604a49240f5d6d0da65c40c8c207f1ebec943cb8c50cd7a51d879",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.gz": "71c15bbabb5bcadb603513c73e40a96026fc8f6d5c82e9ea9b6569fcc22d5af2",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4a9af011d4a2b63a0357c6367210fbf4b6e116b5388ed3a62b758a4bad1fa77f",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "c44531c5467c1e01739f3796db1f59c4b6d6483f4bb8c398c751dbc30ed550ed",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "0ec54d445e3c24bf7aa8ecdca45f49abfc2e4013c7af682d7134a5e52e752d23",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.gz": "3ea1a25b04112d83771e7b713ff8d33418bd18a7adcaaf6cce68f537cb27fefb",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c904834d0fa015d24ba0e929e900ad06bfe773bc4a439f9bbcd8862a5065171c",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "498cda7a23e81ed7563650deb320361c8cffdc10de13ce143175e77f720600ed",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bb0e95d7fad089cc84e826adffc416757df4480ffdfd09547625950b13b9e934",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "87ae1f563963370eeaa3f46d568339d5589e4fd509d21087db43ca2f1d6a1daf",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "da6268585d69c9c71c92dadb658bc7c055b5ce4c87abc52b5451d1111c1675dd",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "93c67427050266f49dc367a1f8e694989424664f740ae3911f78f1cc53faf35c",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "03f9a6e921555954b33fd7f446e9093ad4b631c86d001303e4c47078d0e1d385",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "6c96a53e86f71965f1922585469501504b79c3347d09409033f871b1c9cdc856",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "000e43f7e40abecd402242455f8a3d60692043ddb80bd15dd6f52acd1c5af096",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "7ee55e1f5a63b52d7b87882fa4131fe848d18dba819d46e16ea2435889d84722",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "b8fc28ffd7d97e76913755bedc2f9e7cec7150e036d13fcf7e50dc5a2422d1dd",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "af81aaa9bd624f57168762dfbae39853ada92043809bff953e108e97169e5732",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "37357e40af421ca5b4d2b95f19eca41ce016404ffcce8abea45e08721664f0e3",
+ "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "cbbd98fd3ee6bdd3c01e590c2f10367ec38d799e02ddbc1b0e31027684a356f6",
+ "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "defda4e2ef2f3baf8c7d2a9159d17ca439004687f0b6714826408b94d4f0aed0",
+ "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "201c5bdc1dba11e039bea9257e17ddd2f50b29448b070fc0edb4a7a9f4e45f45",
+ "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0319b07244f443e254e10a04e75633b293faffc5896ade44c05dde0739356f38",
+ "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "54e7cb5a1534ecdbd484ef304f608eb48464ae2c2330958b65b8101f81291319",
+ "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "aecedf5ca4d91e98ba3c4faba64699d79b3fd4877f880840d492b4872ccb924a",
+ "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a4cf3bde61d46484e36fd41386840250e0c031414ee422bbb3d37f7ac7489ca3",
+ "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d93e2a290aea3075cd61b950ded4c3756611acc6a59ba7efb9ce2e4dbac76c59",
+ "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "69c9f09416b788d93f54734a953ed8dead2a31e1dacd6e67a6550529385b338f",
+ "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "808a02952a31ae3a171849dc217763f5cd142622e92ae2b383014bbe37e9b551",
+ "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "67e6b61d822cfc9f95a2808917601cf3d2560d636b12a19ee29a790cc06e8235",
+ "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "7310493bc6f184b401650fb399015be29a8df009e55fa1cbfbcf9d9608fe61e2",
+ "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "fd4db925d7eb598f210ab2d96f692cbdb627acbd6a8976259411a4d2356b8728",
+ "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "b5b0394ef612188fd094e355892aafe4530758fe38dc8859ba917cb2febe028e",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "3b7c3ad97393bc702dbd71bc819c0e5f6164cf471171c7c48cfffdf5477b35b6",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "21e6f247a6663918c6e38782e43211224d50d4de22a9162be0c5f6d6d0a9afea",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "d0c9bd56dcac12d7174e11f2acdb16fba41ffb3aba71b6b1b4b49ce7fa115f6e",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "c89adc1cbdb7bfa27f5bfdac38b5ff084eafe081b27548dc243bbff378ec7118",
+ "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3e6f8a86901c1350c54bd89e156af029978f4a25f578ea26f49a1f3332da2187",
+ "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "43e74dbeb89547be1b3ad1b532bef97b577530a8b19b825342efb72d91d4b0bd",
+ "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "c8c7a22e63353e7c7766e254c3fc0b0277bc8265f1123a38705bf319a7d99a19",
+ "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1759ca2de0ff890918a0f634782557ae2b3181e543790878093f303ede45e215",
+ "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "a9ac36f2b4e88ce2f2789e9df46ae679879c111594cfe82b538e4067adad2b5e",
+ "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "6260f0616828d79898165bf42875881dc5253143d940ac951b7f295553afb8c9",
+ "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.gz": "42d3e5acf2475d732ce5afe3c2ebea6d332c137d061aa256df75b7ce54c16b16",
+ "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.xz": "7f84ff29dc36a224961e87d40cd6e531c9309bdafaec5de2b043aa89af511552",
+ "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.gz": "6bfdf4e59ac3f9dbde2fa46797bd9bb9cbda232c0d507f04bafd937e88945cb7",
+ "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d12901a4efc8395df3c1ac137f86c3da07477277fad138edb49d5c4382a3a114",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.gz": "38718b50fa2acacc0fac98931a5714df38feb8370fccf8d7a955de3b2c117dd0",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9753c00de1117a5fb9bff4ce2a4434ac6d3d06a1b4b3d0cc44ddb590739b9a0b",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "c1eb35c914ad1a762cf550d54b7ec80cb3a8ab6ab39f5c89709f88e04eeba46f",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3c092ac130633f327a0afc8bdf8ba252f05d9b0050383122d7ba31cc3f5ddfc5",
+ "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.gz": "fb391d1199eab0854228323d08dd8b27709175697532e4b47e9dab6f26f24a8f",
+ "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.xz": "82347d3a0a123c430a526486dbd8c424732181eede038e2f91f1504d510a755b",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "0cb559fff7f8dc35e5279217ef6fe7c2b5fa3d68f5ca82f258b6885f42e8d144",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "ee1fe1dc9fe620743022939cdeac3ab34135e61897f0707c3b1a0a1b7d730360",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "bb8de6fe10aa624fdd63484403e228a5c592b94d4aac95e2b2401cd8b9472f0a",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "1bb7f7ac88e250534d89f0b0dc74f13ca563bad53956be74418d2aef28d250a5",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "0aea9f5cddb136591d105ebd3607a2e1f402f1c707cf33f21fb5cf1d30101ee0",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "f547622b8f052c6290c530d506d8ee314f90c81ace562a0a533b6ad2ba00b987",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "80f8f7c613c7ff2097f5c346b3ac4a5cf750167277f28655e0263b05a231668d",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "a57b4489a1d46ad3fc303a3b2dd478df66407a3e2dfeb9c12860a543ae5210eb",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6c4264b2bcecc951c39626fc1cf8de36f1eadbda31a552e14274f728978e16a5",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ec72f8e861eed6b5e2518b46cd8008d3bd2b6f2a7a42784a2dc8a6184d3ecc62",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "0fc209babd43546d04b3fdd27ce77c96d75aa5eb6595f00586a19a17e4530b59",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "ecdb8152992b4a9779aeda2b4cc638163ac24faf45c484f27316a6b3ff0eb297",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.gz": "52bbea99f2405f35f58d5448c353c605c2a87e7546e95b86d8baa39b4fc7a9a2",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.xz": "47ea301d79eada8898907af226b39b4c73ac1fe974963139aee78c3567ee53e4",
+ "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.gz": "dc9ccfa3e46e4f3b0e11de8a83885695ab154a2211fa89a20670db116d63a4c2",
+ "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.xz": "52d890b402c7e7bb7c0f9b34f2e216f0937453ab42e7c4ce205739bd64ba7dc7",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.gz": "0ccbff8a582047cd6d2a6b30387ea73cfce7e0c61eddf516126836b9f9ca86ff",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.xz": "cab55f71575d58aa7213a7dc4cfb0704ca7faec7203c545aeaff178eebe40436",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.gz": "6863523669b65464bd52e1a47f6decf868cc93d2111ffc222bb4a032a0095e3f",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.xz": "d5c6e65a656621891f387861c8259116dd9a8ab14e13ea10e93b78834e1d334a",
+ "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "ec7130bfff74b7226fb5d0f311dd399f7628cb59ce06b4bc9a9f394067855eda",
+ "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "0f52f00f03126aed0260cbfdd9790a62f9f4ceb24e2a3a6d80e8a15a1b4a09c2",
+ "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.gz": "1a3f4c6c1528050820b85e07aa96af6588c7d61935108cb5110d1e0c964142e8",
+ "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.xz": "fe9488c3476e931440ad487a4cf265fdd3c01e18c9e43b33f51b9eb078821282",
+ "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.gz": "c7205b1cdcdff00d91a3991b1f40674b075c34dc0877de4786da5ab85e3b6cfa",
+ "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.xz": "87a3cfe8992ad615d5522d97ace91dcc86057d060d82b581df206f2802225a0e",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.gz": "cd9eeb26fe909e38d8d8129829d19b4d04d96014496cc7f2f4ae077b94f2aae3",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.xz": "b6e59180ff89f7e460fcbc246802e6441c71600774ae5cb2d9af464365a642cb",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "45e07be14211ec7c9f3c1ad0eb9f7a9b422b10c842d5d0e8b0b498751ab7ae0f",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "593f70209f3b5b4e126d57ece0b1adefb4bc1055cfd168779d854369985b2b2e",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "6e14f3431da08f63d82e5b1e2c56fdf13f93ea7b6660dc64b1c855d00c008257",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6e6355686d22213d27f5dbec0b7ded38532e79ac904bae978a8eb5fc880916cf",
+ "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.gz": "39bdaa250d8f17914602a2185c51014f7fbfb1e30991816a432c3897338b52a1",
+ "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.xz": "ebab0e4b13e0b3bdbe0ac858d5a4ca28bb813854aea1d8ec86d8e220c68b3442",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "a700f1736b96c4e7237305dc98a79163b07127f0aac1f436415c233b8495a5af",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "e94ecf7d1c9a5144577fdb14b7232b11dff0ebbfa8aae8cb4884d4ed9c5bae77",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.gz": "209dc9917790c2be8777c597e19a9f43301aaaaac3c9731e9d0512e6918334b9",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.xz": "6e4810c7484c231f0edb15ae5acea822ed5d868eaf041438afea4b6ba38be35e",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "df952ee1385da9457c4e95dc08ab59ca915f5f211738982f8db3684cf80967fc",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "62d7383ee21b0a7d072b15a9877a922f8dbcea42d910c2cb3c4129152b26ea9a",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "be28225516fa38edd34e1af5f051d7c8ab5f433cc5814df199bc451285d95e0c",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1a6fdfac24feb34744daced6c6545c844ff13d5e5f14620520d5ed4b85be8742",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "c0f098faa0c9de6a8e82b80dfe44bfa9d4482e118259c33452ef025885ceab6e",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1d1ed7cf8fc16efab3faab9ef5abadac9ab98d3b60522fde0612ac0b256de528",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1ed41e8019480cd151a9ddd0f080afc56ed0afe47cfb7c6b5a6a2473ff6e7e81",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "849c04115660abdf1d4460aef2d87021c6ad52423c83dfed3c2cec8e380ae6fe",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3a35d33b3282fd156482c85e19817f78dcd964de8b712a6e46b965dc60d5204",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.xz": "d5bfbb1415a62547b9e2a24b770a3c6e4d531101cfb2360b7a7de34d0bf18974",
+ "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.gz": "28beba0ff958b93f85618e49f13f4062cefacc82f6b5911d42f00515f99c5abe",
+ "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.xz": "07c6a43130112c93745e729c91669243cd28b73fafc7d9b32b4f22650db7bcad",
+ "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "9e70dc74c4428438716d14861797380ce7f6617bc93b83c74fc1a6f8aca99392",
+ "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "8f61ec8129b7b0bcc6b329337e5e0323054a438e999615687a18fdc42a8d0692",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "bba3cbfdd2842cdf8f2698b709401db6a641227d1742595e3959f1f0ace37c5f",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fe74ad76a2cffdff0a2fb953f31b73d80a0bce75402bf65f01d250fcae6ff779",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "cde952fb3c38a969c0743d2f9d90e256db8613c463a4b23d6119656570978eb5",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f2dd88f1b4ec97aaaebb601d20751d50536e85b2cac36740abbc03fa8a4d0d06",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "1a4414987e4da2c8086590fe4ad531f78862443eede3bc9069efb424900746d2",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1682f8bde2562d4b9183fa512bc1e54d2a821fd9f63208a51489f21deeb7fcfd",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ca40f3c5e8fd8bd6d89d3c0a3ad4d767353c1b4138e2720371a275c9c52c9117",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "c7afe4eba5cdb02a2e8ae224a0970c8aa36ef429ac298b0f98ff41a0d911aad1",
+ "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6acd677fda38aea2b960f2af6438b30c3b6bd759bb3e56228a1096445ddd100f",
+ "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "451a2e139771f39ec09a7cefd48885ec30f732668d50c750d42e6c58c250f8fe",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.gz": "a1df7d105231d4941a55a9f850d39acc201a99dd408d523935799b70fec30c6a",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.xz": "3005718736a2a0fa3a4f1be10239cfb467e9cabe6ce366f9909826bd3c06a990",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.gz": "695039c6737fb3bfd325fbebdab61aeef80ec427ae3d40d8b82e8b317e147fc8",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.xz": "7a5038b7299de71d3677042647fca501984d1f2a52c1d84052956ff7854622b3",
+ "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d21dd4c98d38186544aee9b22b439d67d77c0a740357dfad7fea3c4a9b8d1332",
+ "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.xz": "e62a7c9809de668343323eb9fa1a1f6cc302a6e161e64826e9d31bd202f2f472",
+ "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.gz": "b85eb1bff16384b4f6ad268a01bdcec539b9ea412abb6d64618521cb0e63985d",
+ "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.xz": "ce79b36723a65419e03ec77ea14680791d683e5e04332eebdf59550bdaaa164d",
+ "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e778edd911e09c5c3b46aeccbabcd8ead78dd38086206d03406fc8dce52806e7",
+ "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "10afe035ca7d3a967b467875b1345dde8bdcd3f8c4af1e917bfa2c676e0fec70",
+ "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6b6c3386ebec138ff07a21d3f5631263219c226ca146bf97fe0a7bb9fee9d0c5",
+ "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5ff6430623d0f3aa14748f371e34072aba126a16429928f8f99172190f369fee",
+ "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "369ad16e85e4f2956e400105e6d8374ff64c473c3c3b61ae4d916214d5f922da",
+ "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1c8adfb22f724fa98f30f23378a28729e144f6ab9bba54adf13111ca4648ed78",
+ "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "b3e270c6272420c31ee7bed8ed36c113c879a384fa5b85af0deb7d43a355ca2c",
+ "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "a21cdd8d182cc64ceaa83e522299860c2710dee780e8f49ff107a73fbd73c3ca",
+ "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "1a81076b8e49647b61761a38ed283a9a71b326dc321920f7be453e0e15ae2465",
+ "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "3f8ce23f81623a00de63ce7e82e448eec0901a92f908e6aff362807bae14ff84",
+ "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "eaa3b365bd91a5770db85e8541ee28c99988635521c0f2dfea05218172f11a55",
+ "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3f856ae24c4737bf1928025a10712b6d856788d988fb5018631c525d13b68e29",
+ "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c672cbf2caef81f7ab923ff7c6a05f1865057278180a686f810ddc71dacc49d0",
+ "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bda5d2234aebdc175c87da3b77d050c56bced21a794c416bb9090c0ae3374be2",
+ "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "59e01371664f8d39c7a06c205af0f5ab9aabdb3942be4f493d05ab71047619e8",
+ "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "de956b5275e38e0b4223819973e85f5f65c409addd786f7ac2d525a79c3f0c92",
+ "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.gz": "4f78d90362488a866ea7b1cccbc61f925d94034b46dfa775dea75223e67d755a",
+ "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.xz": "3520d028e9370087cfa57eb7225dd76c008cb08ffb01c8101aaa86104f427f12",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f954349daa7dfd819ec0a7335a47b1d3b2ed0138eae31c56288d9c523cdf56b2",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "ca046d8fca5fa48117c61c70a21176d9220a3c62af9fdc9b899c157bb196a5b5",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "61ae4421bdf798a5ca1a8bc8c8521dfb29a707e40d382dbd2e155f134956ac33",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "495076dfc2fa0b8d96613e34f867de9d43483984a8bd6839bf273c2be38039b6",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.gz": "828526bc23ad8802071bf4f2984faf3549139eb4ce8ebb9ba8711c196d2bf437",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.xz": "fa2464350b2ac29bec6751c551cc45b7af92c25d2cf1109397e724802d4859cf",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.gz": "a1d9719668ea1887d6202c25b9dd2b7d40bdd240f3f753af77ac93f126c84c38",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.xz": "4b36f5d448bf022f90e284c22a44e0b87ef8518ec93a297ceb703eb612ef80d8",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "63e654f5e8707a0536381025bdbb43d498c70a29a5ada0ecdb12e23844cc9a9f",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "6b5b74abdcb1cae42620cabc142a119b58823e9f2ac0c3151e087a76323c5cae",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f3aa2d52ce5da066c59de609ebd5df60ac908c7e0db23ac4afe69b927ef2a974",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "6e8858dbaf50a8211516e5afa83e4133d878e0d4b19ba4a3e4c3e51cb80210b7",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.gz": "9028dd44728092ccaec86f415abdb3733f3ea58ab7c3d736e96e27540cc66a2d",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.xz": "c6720fd231b54a04e1ba3ed3fe333b1d8ef5b771ce341b4c112169a293bf713a",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d987783ba5117529b325bcf6f5e7abd9eee42b5ea86ce5109a4fd3f450af8062",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5d5838733dc64e302991465c1f371fde855ee410d42d1713ddc1c471b469e1a8",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "8593ab35bb800312d6fe4c4a4d151feb26187c6db0d0d5ca5e3e98a007f8a4ff",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "a2ded0420cc1d98df255c7ef93247b9a6d3d9ec22e42c477305dc15ef35fd329",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "652275e77d73f122c12eb952338661562a48fc76164d6549158abc14fb4e4a4a",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "fbb49b56bb11348e07124d8216b8f8b6e26d8697abb05afec0ddb07a456b29e5",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "817c7ed90ab8cdec1dcfc8571391a714002b49fd20da0ae32135f57d233ffbfb",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "cbd8674c65babce944bab6a6f013d44a2c7d6829434a6b97edb1f1e1df1c076f",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "66b13ffad073bc624ebdef219e61f8972fc6be354aaf1f8ede58a3acc01314c3",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "11ecfef218376fd2232ad552526b39173c5269130f02e408a7492762cde87a6a",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "07ad99e019141843f5d6f8c302b9d20c7453ebead79e9711af33c9c8081b9e22",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "6656be84a9b5a63083d63e3a87bc928b424109efff48e3a6770e026c6ea7c2e8",
+ "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "155422628d41ce9730f4503bffa12e396b58692c906828acf15f0dd39b3d491e",
+ "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fc75c3836489bda30d340132d0d5ab8ee7f7c67617e4dc66a9eae559bbdb0421",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "181d557c8f73c8f22ed63a8f98e53f6d88871fd694173aea70c53d42c0c55ae2",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5defc562a2f0ced4539006692cc969cf89756637f5f5c62be0276dfedd6f3db6",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "f28b3fdf5425e7b782d0f78ca95613efd87b2b0d14d44c4490f17d4eb452f183",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b6cebd5a23bcc504d05c8dd79654baf2ab45b162c59b7b843e24efb7e2344011",
+ "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "c59850b28fcfb1608c7e91890b8628ac201b87b4d9af7e9fd019e3e4a137c033",
+ "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "ad808569083691ba31b0e10222f9dd01822ade91689bcb060544f28b99f2a299",
+ "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "8fca357226b91cc712b888c0a62f9e52b121ab6d9815ea5f53bbfd243b895b69",
+ "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f5451fe6946c16a7ba404c8bab33816d58d478b1dc0ea1ce6b85befe26ddf77",
+ "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "7cc76ce31cf59f1cbeca87a46c996e905f048acfc70d438eae2a32bb67fc60c1",
+ "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "429bacebe2a9f1478a00b1573fe4e1b071c6348d800182993c8b5d8ba54d9615",
+ "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "701a12b5a4a689e6b2ef260e35ed2d22c00452cde5e18ce0d886ace37e81964f",
+ "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "0ef78c91a3220226619f20b28bf67947a56ff31f369d5ea7bfc2aef356060e42",
+ "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "0765a3b65315bbb1381927eaf6f65f16fd09dddab41d7398e483bf001ee7bc3e",
+ "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "c74b0833f995ffad5c812ba130f423485bd8297eca0c4eae227852a88ece8521",
+ "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "3c9d5a35ef1e459ded4dcdcad40bc5e3bcd5b2821cf4f46dbaf2c2c3259fa3ff",
+ "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "0aa8975a6dbd103a4764ad643de6094bd6911bd3a90d46e24ad1eafcea2870e7",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0ee2ec59ed07ba9c9e48076c954f5c6e4d39809d9e4923337db2627ea279c6f",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e712fa72a41dedcd50c6531433220904b9627fa78bfa15cdd96d97161981cb77",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "fc7809520a4a41ccb0ffb303c7bbc96443308387890ebdb65a25c3697a5c3eb4",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "84a8fa7468b9e59465f85607f84960e11faf0f37bd766d55b6be985db89d0d17",
+ "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2703dff8cb1c0ca08787f1c7715885c5b09919c040783ba98bd74f8fe3af704d",
+ "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a3e25cc857e990b467c804f41e23bfbe8ef02630b48703fc1c7fae692e16eb80",
+ "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "659a9ca0e1296f817cd9f90fed9ccd7d3c7c3e7eea7e9c437bbeb2d951a2669c",
+ "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "21e83ac3b148f0f690cb9a39b385fb0d5a82d6eea9ec46d4d4445b5a660c6d7c",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "c8e3300a426cc4a80ba4f1cf0c6822d9b883f24c486b991f2056938be778d43f",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "55f1f7d84828b3cc5d13b10e549a74f2f1df11057ed48e75fbafc0d3538daf03",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "99bf70cee39b2ce73dbe5827fe3d93e45241faea284acb3f8004cf7e700e1704",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "dfc569d57211eae74a2cde5db180d2f2f44bca04f811655ef1f8d8c2154b97ef",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "679d69ba6a4b460f9672f1ec1c2939ac41ee7f911a2a74eaf6db477aa088e6e3",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3b9a899fcf40db84be8bd14e7c767c572c7d8c7c85f90997b8278fe8726413ae",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "19be469ab711dcee7a7243e865efc5addf8b2cdbdf15150a2c367692c45b9f94",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "789c7129e235b65860a514fdb38f01ac195af610d4ac6a296d272a6f36d72344",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "18657363783d0967d871ee1ed8905b3db0c3b761910fb06ea10980ec6b5ca082",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8b272546a9eb8b23724fbec5577fc0c917a23e994befc38ebfa797957df03b9d",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "4e1de312f07fb98845a881b44c2a76ec9abf61e5aba46e8e384de1cd297957a3",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "a13ad29e2d06c9df233882d009ba8354d92d2fb29239cadaf858b9abc8b477d9",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "aae38bbf1eb7e0da50eb7f226897dc85e88b5e008ef901a93dadb0550f4055ac",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "757564eaa1a339d37b59da304bbc7a846bb883a73c62b78df39dacd947606ec9",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "5f3a83079cb1fd7d8b9be44d0df7b57c6dc79da8e1762eace67c122cffc2d4ca",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "e47ee14a1e679ee5f23936ba7d7de13dcba082c7f32e366be7a990503c91f6ad"
}
}
--- /dev/null
+// Test SPARC64 ABI
+// - float structure members are passes in floating point registers
+// (#86163)
+
+// assembly-output: emit-asm
+// needs-llvm-components: sparc
+// compile-flags: --target=sparcv9-sun-solaris -Copt-level=3
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[repr(C)]
+pub struct Franta {
+ a: f32,
+ b: f32,
+ c: f32,
+ d: f32,
+}
+
+// NB: due to delay slots the `ld` following the call is actually executed before the call.
+#[no_mangle]
+pub unsafe extern "C" fn callee(arg: Franta) {
+ // CHECK-LABEL: callee:
+ // CHECK: st %f3, [[PLACE_D:.*]]
+ // CHECK: st %f2, [[PLACE_C:.*]]
+ // CHECK: st %f1, [[PLACE_B:.*]]
+ // CHECK: st %f0, [[PLACE_A:.*]]
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_A]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_B]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_C]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_D]], %f1
+ clobber();
+ tst_use(arg.a);
+ tst_use(arg.b);
+ tst_use(arg.c);
+ tst_use(arg.d);
+}
+
+extern "C" {
+ fn opaque_callee(arg: Franta, intarg: i32);
+ fn tst_use(arg: f32);
+ fn clobber();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn caller() {
+ // CHECK-LABEL: caller:
+ // CHECK: ld [{{.*}}], %f0
+ // CHECK: ld [{{.*}}], %f1
+ // CHECK: ld [{{.*}}], %f2
+ // CHECK: ld [{{.*}}], %f3
+ // CHECK: call opaque_callee
+ // CHECK: mov 3, %o2
+ opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3);
+}
// Checks that we correctly codegen extern "C" functions returning structs.
-// See issue #52638.
+// See issues #52638 and #86163.
// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
// needs-llvm-components: sparc
pub extern "C" fn structbool() -> Bool {
Bool { b: true }
}
+
+
+#[repr(C)]
+pub struct BoolFloat {
+ b: bool,
+ f: f32,
+}
+
+// CHECK: define inreg { i32, float } @structboolfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i32, float } { i32 16777216, float 0x40091EB860000000 }
+#[no_mangle]
+pub extern "C" fn structboolfloat() -> BoolFloat {
+ BoolFloat { b: true, f: 3.14 }
+}
+
+// CHECK: define void @structboolfloat_input({ i32, float } inreg %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structboolfloat_input(a: BoolFloat) { }
+
+
+#[repr(C)]
+pub struct ShortDouble {
+ s: i16,
+ d: f64,
+}
+
+// CHECK: define { i64, double } @structshortdouble()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i64, double } { i64 34621422135410688, double 3.140000e+00 }
+#[no_mangle]
+pub extern "C" fn structshortdouble() -> ShortDouble {
+ ShortDouble { s: 123, d: 3.14 }
+}
+
+// CHECK: define void @structshortdouble_input({ i64, double } %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structshortdouble_input(a: ShortDouble) { }
+
+
+#[repr(C)]
+pub struct FloatLongFloat {
+ f: f32,
+ i: i64,
+ g: f32,
+}
+
+// CHECK: define inreg { float, i32, i64, float, i32 } @structfloatlongfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { float, i32, i64, float, i32 } { float 0x3FB99999A0000000, i32 undef, i64 123, float 0x40091EB860000000, i32 undef }
+#[no_mangle]
+pub extern "C" fn structfloatlongfloat() -> FloatLongFloat {
+ FloatLongFloat { f: 0.1, i: 123, g: 3.14 }
+}
-// pretty-printers are not loaded
+// ignore-windows-gnu: pretty-printers are not loaded
// compile-flags:-g
// min-gdb-version: 8.1
+++ /dev/null
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11
- let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:7:11: 7:12
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12
- _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
-- switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:7:5: 7:12
-+ goto -> bb2; // scope 0 at $DIR/switch_int.rs:7:5: 7:12
- }
-
- bb1: {
- _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
- // mir::Constant
- // + span: $DIR/switch_int.rs:9:14: 9:17
- // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
- }
-
- bb2: {
- _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
- // mir::Constant
- // + span: $DIR/switch_int.rs:8:14: 8:17
- // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
- }
-
- bb3: {
- StorageDead(_1); // scope 0 at $DIR/switch_int.rs:11:1: 11:2
- return; // scope 0 at $DIR/switch_int.rs:11:2: 11:2
- }
- }
-
--- /dev/null
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11
+ let mut _1: i32; // in scope 0 at $DIR/switch_int.rs:7:11: 7:12
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+ _1 = const 1_i32; // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+- switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:7:5: 7:12
++ goto -> bb2; // scope 0 at $DIR/switch_int.rs:7:5: 7:12
+ }
+
+ bb1: {
+ _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+ // mir::Constant
+ // + span: $DIR/switch_int.rs:9:14: 9:17
+ // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+ // mir::Constant
+ // + span: $DIR/switch_int.rs:8:14: 8:17
+ // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb3: {
+ StorageDead(_1); // scope 0 at $DIR/switch_int.rs:11:1: 11:2
+ return; // scope 0 at $DIR/switch_int.rs:11:2: 11:2
+ }
+ }
+
fn foo(_: i32) { }
// EMIT_MIR switch_int.main.ConstProp.diff
-// EMIT_MIR switch_int.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR switch_int.main.SimplifyConstCondition-after-const-prop.diff
fn main() {
match 1 {
1 => foo(0),
}
// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-final.after
+// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after
#[no_mangle]
pub extern "C" fn try_sum(
x: &ViewportPercentageLength,
+++ /dev/null
-- // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyBranches-final
-
- fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
- debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6
- debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:10
- let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:6: 19:42
- let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
- let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
- let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
- let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
- let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
- let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
- let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:23: 24:34
- let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
- let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:11: 22:18
- let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
- let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
- let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
- let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
- let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
- let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
- let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
- let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
- let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
- let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
- let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
- let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
- let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
- let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
- let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
- let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
- let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
- let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
- let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
- let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
- let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
- let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
- scope 1 {
-- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
- }
- scope 2 {
-- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
- }
- scope 3 {
-- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
- }
- scope 4 {
-- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
- }
-
- bb0: {
-- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
-- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
-- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
-+ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
-- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
-- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
- _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
- }
-
- bb1: {
-- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-- }
--
-- bb2: {
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
- StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
- discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
- StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
-- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
-- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
- }
-
-+ bb2: {
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ }
-+
- bb3: {
-- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
- }
-
- bb4: {
-- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
- }
-
- bb5: {
-- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
-- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
- }
-
- bb6: {
-- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
-- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
-- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
-- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
-- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
-- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
-- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
-- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
-+ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
-+ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
- }
-
- bb7: {
-- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-- }
--
-- bb8: {
-- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
-- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
-- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
-- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
-- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
-- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
-- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
-- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
-- }
--
-- bb9: {
-- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-- }
--
-- bb10: {
-- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
-- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
-- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
-- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
-- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
- }
- }
-
--- /dev/null
+- // MIR for `try_sum` before EarlyOtherwiseBranch
++ // MIR for `try_sum` after SimplifyConstCondition-final
+
+ fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
+ debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6
+ debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:10
+ let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:6: 19:42
+ let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
+ let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
+ let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
+ let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
+ let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+ let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:23: 24:34
+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:11: 22:18
+ let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+ let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
+ let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
+ let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
+ let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+ let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+ let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+ let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+ let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+ let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
+ let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
+ let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
+ let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+ let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+ let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+ let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+ let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
+ let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
+ scope 1 {
+- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+ }
+ scope 2 {
+- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+ }
+ scope 3 {
+- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+ }
+ scope 4 {
+- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+ }
+
+ bb0: {
+- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
+- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
+- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 27:6
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
++ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
+ StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
+ _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
+- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+ StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
+- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
+ _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+ }
+
+ bb1: {
+- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
+- }
+-
+- bb2: {
++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+ StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+ discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
+ StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
+- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
+- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
+ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
+ }
+
++ bb2: {
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ }
++
+ bb3: {
+- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+ }
+
+ bb4: {
+- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+ }
+
+ bb5: {
+- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
+- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+ }
+
+ bb6: {
+- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
+- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
+- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
+- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
+- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:41
+- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
+- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:44: 22:49
+- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
+- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
+- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
+- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
+- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
+- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
+- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
++ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
++ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
+ }
+
+ bb7: {
+- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
+- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
+- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+- }
+-
+- bb8: {
+- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19
+- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33
+- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
+- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
+- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:47
+- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
+- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:50: 24:55
+- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
+- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
+- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
+- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
+- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
+- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
+- }
+-
+- bb9: {
+- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
+- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
+- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+- }
+-
+- bb10: {
+- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
+- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
+- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
+- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
+- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
+ }
+ }
+
+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:13
- // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
}
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 = <impl Fn() 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 std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17
}
debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-- let mut _3: &impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
-- let _4: impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let _4: impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
_4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:13
- // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
}
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
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
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:15
- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
}
bb2: {
+++ /dev/null
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify_if.rs:5:11: 5:11
- let mut _1: bool; // in scope 0 at $DIR/simplify_if.rs:6:8: 6:13
- let _2: (); // in scope 0 at $DIR/simplify_if.rs:7:9: 7:15
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
- _1 = const false; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
-- switchInt(const false) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
-+ goto -> bb3; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
- }
-
- bb1: {
- StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:7:9: 7:15
- _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15
- // mir::Constant
- // + span: $DIR/simplify_if.rs:7:9: 7:13
- // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) }
- }
-
- bb2: {
- StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:7:15: 7:16
- nop; // scope 0 at $DIR/simplify_if.rs:6:14: 8:6
- goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6
- }
-
- bb3: {
- nop; // scope 0 at $DIR/simplify_if.rs:8:6: 8:6
- goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6
- }
-
- bb4: {
- StorageDead(_1); // scope 0 at $DIR/simplify_if.rs:8:5: 8:6
- return; // scope 0 at $DIR/simplify_if.rs:9:2: 9:2
- }
- }
-
--- /dev/null
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_if.rs:5:11: 5:11
+ let mut _1: bool; // in scope 0 at $DIR/simplify_if.rs:6:8: 6:13
+ let _2: (); // in scope 0 at $DIR/simplify_if.rs:7:9: 7:15
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
+ _1 = const false; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
+- switchInt(const false) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
++ goto -> bb3; // scope 0 at $DIR/simplify_if.rs:6:8: 6:13
+ }
+
+ bb1: {
+ StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:7:9: 7:15
+ _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15
+ // mir::Constant
+ // + span: $DIR/simplify_if.rs:7:9: 7:13
+ // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:7:15: 7:16
+ nop; // scope 0 at $DIR/simplify_if.rs:6:14: 8:6
+ goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6
+ }
+
+ bb3: {
+ nop; // scope 0 at $DIR/simplify_if.rs:8:6: 8:6
+ goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6
+ }
+
+ bb4: {
+ StorageDead(_1); // scope 0 at $DIR/simplify_if.rs:8:5: 8:6
+ return; // scope 0 at $DIR/simplify_if.rs:9:2: 9:2
+ }
+ }
+
#[inline(never)]
fn noop() {}
-// EMIT_MIR simplify_if.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff
fn main() {
if false {
noop();
# needs-profiler-support
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
-include ../coverage/coverage_tools.mk
BASEDIR=../coverage-llvmir
# needs-profiler-support
# ignore-windows-gnu
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
# properly. Since we only have GCC on the CI ignore the test for now.
"$(LLVM_BIN_DIR)"/llvm-cov show \
$(DEBUG_FLAG) \
$(LLVM_COV_IGNORE_FILES) \
+ --compilation-dir=. \
--Xdemangler="$(RUST_DEMANGLER)" \
--show-line-counts-or-regions \
--instr-profile="$(TMPDIR)"/$@.profdata \
-// This test is to ensure that the anchors (`§`) have the expected color.
+// This test is to ensure that the anchors (`§`) have the expected color and position.
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+show-text: true
// This is needed to ensure that the text color is computed.
show-text: true
// Same thing with the impl block title.
move-cursor-to: "#impl"
assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"})
+
+// Now we check the positions: only the first heading of the top doc comment should
+// have a different position.
+move-cursor-to: ".top-doc .docblock .section-header:first-child"
+assert-css: (
+ ".top-doc .docblock .section-header:first-child > a::before",
+ {"left": "-10px", "padding-right": "10px"}
+)
+// We also check that the heading itself has a different indent.
+assert-css: (".top-doc .docblock .section-header:first-child", {"margin-left": "15px"})
+
+move-cursor-to: ".top-doc .docblock .section-header:not(:first-child)"
+assert-css: (
+ ".top-doc .docblock .section-header:not(:first-child) > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: (".top-doc .docblock .section-header:not(:first-child)", {"margin-left": "0px"})
+
+// Now let's check some other docblock headings...
+// First the impl block docs.
+move-cursor-to: "#title-for-struct-impl-doc"
+assert-css: (
+ "#title-for-struct-impl-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: ("#title-for-struct-impl-doc", {"margin-left": "0px"})
+// Now a method docs.
+move-cursor-to: "#title-for-struct-impl-item-doc"
+assert-css: (
+ "#title-for-struct-impl-item-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
+
+// Finally, we want to ensure that if the first element of the doc block isn't a heading,
+// if there is a heading afterwards, it won't have the indent.
+goto: file://|DOC_PATH|/test_docs/enum.WhoLetTheDogOut.html
+
+move-cursor-to: ".top-doc .docblock .section-header"
+assert-css: (
+ ".top-doc .docblock .section-header > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: (".top-doc .docblock .section-header", {"margin-left": "0px"})
goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
write: (".search-input", "test")
// Waiting for the search results to appear...
wait-for: "#titles"
assert-text: ("#results .externcrate", "test_docs")
-text: (".search-input", "")
+
+goto: file://|DOC_PATH|/test_docs/index.html
// We now want to change the crate filter.
click: "#crate-search"
// We select "lib2" option then press enter to change the filter.
}
/// Just a normal enum.
+///
+/// # title!
#[doc(alias = "ThisIsAnAlias")]
pub enum WhoLetTheDogOut {
/// Woof!
#![crate_type = "lib"]
#![crate_name = "summaries"]
+#![allow(rustdoc::broken_intra_doc_links)]
+
//! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc.
//!
//! This is the second paragraph. It should not be rendered.
--- /dev/null
+pub struct B0;
+pub struct B1;
+use std::ops::Shl;
+use std::ops::Sub;
+pub type Shleft<A, B> = <A as Shl<B>>::Output;
+pub type Sub1<A> = <A as Sub<B1>>::Output;
+pub struct UInt<U, B> {
+ pub(crate) msb: U,
+ pub(crate) lsb: B,
+}
+impl<U, B, Ur, Br> Shl<UInt<Ur, Br>> for UInt<U, B>
+where
+ UInt<Ur, Br>: Sub<B1>,
+ UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>,
+{
+ type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>;
+ fn shl(self, rhs: UInt<Ur, Br>) -> Self::Output {
+ unimplemented!()
+ }
+}
+// Test that `--show-output` has an effect and `allow(unused)` can be overriden.
+
// check-pass
-// compile-flags:-Zunstable-options --display-doctest-warnings --test
+// edition:2018
+// compile-flags:--test --test-args=--show-output
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
/// ```
+/// #![warn(unused)]
/// let x = 12;
+///
+/// fn foo(x: &std::fmt::Display) {}
/// ```
pub fn foo() {}
running 1 test
-test $DIR/display-output.rs - foo (line 6) ... ok
+test $DIR/display-output.rs - foo (line 9) ... ok
successes:
----- $DIR/display-output.rs - foo (line 6) stdout ----
+---- $DIR/display-output.rs - foo (line 9) stdout ----
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/display-output.rs:13:12
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::fmt::Display`
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
warning: unused variable: `x`
- --> $DIR/display-output.rs:7:5
+ --> $DIR/display-output.rs:11:5
|
LL | let x = 12;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
- = note: `#[warn(unused_variables)]` on by default
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `x`
+ --> $DIR/display-output.rs:13:8
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+warning: function is never used: `foo`
+ --> $DIR/display-output.rs:13:4
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(dead_code)]` implied by `#[warn(unused)]`
-warning: 1 warning emitted
+warning: 4 warnings emitted
successes:
- $DIR/display-output.rs - foo (line 6)
+ $DIR/display-output.rs - foo (line 9)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
--- /dev/null
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![crate_name="some_macros"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ item // This doesn't erase the spans.
+}
+
+#[proc_macro_attribute]
+pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ // Make a new `TokenStream` to erase the spans:
+ let mut out: TokenStream = TokenStream::new();
+ out.extend(item);
+ out
+}
--- /dev/null
+// check-pass
+// aux-build:through-proc-macro-aux.rs
+// build-aux-docs
+
+// Ensure rustdoc doesn't panic on this code.
+
+#![warn(rustdoc::broken_intra_doc_links)]
+
+extern crate some_macros;
+
+#[some_macros::second]
+pub enum Boom {
+ /// [Oooops]
+ //~^ WARNING unresolved link to `Oooops`
+ Bam,
+}
+
+fn main() {}
--- /dev/null
+warning: unresolved link to `Oooops`
+ --> $DIR/through-proc-macro.rs:13:10
+ |
+LL | /// [Oooops]
+ | ^^^^^^ no item named `Oooops` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/through-proc-macro.rs:7:9
+ |
+LL | #![warn(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+// Regresion test for <https://github.com/rust-lang/rust/issues/79459>.
+pub trait Query {}
+
+pub trait AsQuery {
+ type Query;
+}
+
+impl<T: Query> AsQuery for T {
+ type Query = T;
+}
+
+pub trait SelectDsl<Selection> {
+ type Output;
+}
+
+impl<T, Selection> SelectDsl<Selection> for T
+where
+ T: AsQuery,
+ T::Query: SelectDsl<Selection>,
+{
+ type Output = <T::Query as SelectDsl<Selection>>::Output;
+}
+
+pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output;
--- /dev/null
+// aux-crate:overflow=overflow.rs
+// check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/79506>.
--- /dev/null
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+// check-pass
+#![no_std]
+use core as _;
+#![feature(rustdoc_internals)]
+
#![crate_name = "foo"]
+
pub use std::fs::File;
// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
// @has bad_codeblock_syntax/fn.foo.html
// @has - '//*[@class="docblock"]' '\_'
/// ```
// aux-build:source_code.rs
// build-aux-docs
+#![feature(rustdoc_internals)]
+
#![crate_name = "foo"]
extern crate source_code;
// @has - '//a/@href' '/struct.String.html'
// @has - '//a/@href' '/primitive.u32.html'
// @has - '//a/@href' '/primitive.str.html'
-// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5
+// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5
// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
let x = 12;
let y: Foo = Foo;
let z: Bar = bar::Bar { field: Foo };
babar();
- // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#24"]' 'hello'
+ // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello'
y.hello();
}
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
-pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {
-}
+pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool'
#[doc(primitive = "bool")]
+#![allow(incomplete_features)]
+
#![feature(adt_const_params)]
#![crate_name = "foo"]
inner: Vec<T>,
}
-// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Sorted}>'
-impl <T> VSet<T, {Order::Sorted}> {
+// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+impl<T> VSet<T, { Order::Sorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
-// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Unsorted}>'
-impl <T> VSet<T, {Order::Unsorted}> {
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+impl<T> VSet<T, { Order::Unsorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
pub struct Escape<const S: &'static str>;
-// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
-impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
+// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+impl Escape<r#"<script>alert("Escape");</script>"#> {
pub fn f() {}
}
-#![feature(specialization)]
+#![feature(min_specialization)]
// @has default_trait_method/trait.Item.html
// @has - '//*[@id="tymethod.foo"]' 'fn foo()'
--- /dev/null
+// This test ensures that the const methods from Deref aren't shown as const.
+// For more information, see https://github.com/rust-lang/rust/issues/90855.
+
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// @has 'foo/struct.Bar.html'
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+ // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize'
+ // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+ pub const fn len(&self) -> usize { 0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Foo {
+ value: Bar,
+}
+
+// @has 'foo/struct.Foo.html'
+// @has - '//*[@id="method.len"]' 'pub fn len(&self) -> usize'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '(const: 1.0.0)'
+#[stable(feature = "rust1", since = "1.0.0")]
+impl std::ops::Deref for Foo {
+ type Target = Bar;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
// @has doc_cfg/fn.multiple_attrs.html \
// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on x and y and z only.'
-#[doc(inline, cfg(x))]
+#[doc(cfg(x))]
#[doc(cfg(y), cfg(z))]
pub fn multiple_attrs() {}
--- /dev/null
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+pub struct OtherStruct;
+impl SomeTrait for &[SomeStruct] {}
+
+// @has doc_notable_trait_slice/fn.bare_fn_matches.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_matches() -> &'static [SomeStruct] {
+ &[]
+}
+
+// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
+// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
+ &[]
+}
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(associated_type_defaults)]
pub trait TraitWithDefault {
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl
-#![feature(no_core, lang_items)]
+#![feature(no_core, lang_items, rustdoc_internals)]
#![no_core]
#![crate_type="rlib"]
+++ /dev/null
-// force-host
-// no-prefer-dynamic
-#![crate_type = "proc-macro"]
-#![crate_name="some_macros"]
-
-extern crate proc_macro;
-use proc_macro::TokenStream;
-
-#[proc_macro_attribute]
-pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
- item // This doesn't erase the spans.
-}
-
-#[proc_macro_attribute]
-pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream {
- // Make a new `TokenStream` to erase the spans:
- let mut out: TokenStream = TokenStream::new();
- out.extend(item);
- out
-}
// aux-build:additional_doc.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate my_rand;
#![crate_name = "my_rand"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub trait RngCore {}
/// Rng extends [`RngCore`].
#![crate_name = "hidden_dep"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#[doc(hidden)]
pub mod __reexport {
#![crate_name = "a"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub struct Foo;
#![crate_name = "macro_inner"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub struct Foo;
#![crate_name = "module_inner"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// [SomeType] links to [bar]
pub struct SomeType;
pub trait SomeTrait {}
#![crate_name = "a"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod bar {
pub struct Bar;
#![crate_name = "bar"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub trait Foo {
/// [`Bar`] [`Baz`]
// aux-build:intra-doc-basic.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// from https://github.com/rust-lang/rust/issues/65983
extern crate a;
// aux-build:hidden.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// tests https://github.com/rust-lang/rust/issues/73363
// aux-build:macro_inner.rs
// aux-build:proc_macro.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate macro_inner;
extern crate proc_macro_inner;
// outer.rs
// aux-build: module.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate module_inner;
// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
// aux-build:submodule-inner.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate a;
// aux-build:submodule-outer.rs
// edition:2018
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate bar as bar_;
// aux-build:traits.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate inner;
use inner::SomeTrait;
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
// first try backticks
/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
// @has disambiguators_removed/struct.AtDisambiguator.html
+#![allow(rustdoc::broken_intra_doc_links)]
+
//! Email me at <hello@example.com>.
//! Email me at <hello-world@example.com>.
//! Email me at <hello@localhost> (this warns but will still become a link).
// though they would never actually get displayed. This tripped intra-doc-link resolution failures,
// for items that aren't under our control, and not actually getting documented!
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate inner;
// ignore-cross-compile
#![crate_name = "outer"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// using a trait that has intra-doc links on it from another crate (whether re-exporting or just
// implementing it) used to give spurious resolution failure warnings
// we need to make sure that intra-doc links on trait impls get resolved in the right scope
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod inner {
pub struct SomethingOutOfScope;
#![crate_name = "foo"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub enum Foo {
Bar {
abc: i32,
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(intra_doc_pointers)]
pub use std::*;
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub fn foo() {
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
//! [i32::MAX]
// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
// ignore-cross-compile
// only-linux
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(no_core, lang_items)]
#![no_core]
#![crate_type = "rlib"]
-#![deny(broken_intra_doc_links)]
-#![feature(no_core, lang_items)]
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items, rustdoc_internals)]
#![no_core]
#![crate_type = "rlib"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// @has prim_methods/index.html
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod char {
/// [char]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// @has primitive_disambiguators/index.html
// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
//! [str::trim()]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// @has primitive_non_default_impl/fn.str_methods.html
// These failures were legitimate, but not truly relevant - the docs in question couldn't be
// checked for accuracy anyway.
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// ooh, i'm a [rebel] just for kicks
struct SomeStruct;
-#![crate_name = "private"]
// compile-flags: --document-private-items
// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
+#![allow(rustdoc::private_intra_doc_links)]
+
+#![crate_name = "private"]
+
/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe'
// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
// aux-build:proc-macro-macro.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate proc_macro_macro;
// aux-build: intra-link-pub-use.rs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "outer"]
extern crate inner;
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod r#impl {
pub struct S;
+++ /dev/null
-// aux-build:through-proc-macro-aux.rs
-// build-aux-docs
-#![warn(broken_intra_doc_links)]
-extern crate some_macros;
-
-#[some_macros::second]
-pub enum Boom {
- /// [Oooops]
- Bam,
-}
-
-fn main() {}
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "foo"]
// Regression test for issue #86120.
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "foo"]
pub struct Foo;
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(lang_items)]
#![feature(no_core)]
+#![feature(rustdoc_internals)]
#![no_core]
#[lang = "usize"]
// Tests that failing to syntax highlight a rust code-block doesn't cause
// rustdoc to fail, while still rendering the code-block (without highlighting).
+#![allow(rustdoc::invalid_rust_codeblocks)]
// @has issue_12834/fn.foo.html
// @has - //pre 'a + b '
+#![feature(rustdoc_internals)]
+
// @has issue_15318_3/primitive.pointer.html
/// dox
#![feature(lang_items)]
+#![feature(rustdoc_internals)]
#![no_std]
pub mod str {
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
// @has issue_42760/struct.NonGen.html
// @has - '//h2' 'Example'
Some(1u8).into_iter()
}
+#[allow(unused_parens)]
pub fn h() -> (impl Iterator<Item=u8>) {
Some(1u8).into_iter()
}
--- /dev/null
+#![crate_name = "foo"]
+#![feature(rustc_attrs)]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+
+// @has 'foo/fn.bar.html'
+// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1, 2)]
+pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+#![allow(rustdoc::broken_intra_doc_links)]
+
#![crate_name = "foo"]
//! hello [foo]
+++ /dev/null
-#![crate_name = "foo"]
-
-include!("primitive/primitive-generic-impl.rs");
-
-// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+#![feature(rustdoc_internals)]
+
+#![crate_name = "foo"]
+
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+
#[doc(primitive = "i32")]
/// Some useless docs, wouhou!
mod i32 {}
// @has some_macros/index.html
// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
-//! include a link to [some_proc_macro] to make sure it works.
+//! include a link to [some_proc_macro!] to make sure it works.
extern crate proc_macro;
// @has foo/fn.f.html
// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)'
-pub fn f(0u8...255: u8) {}
+pub fn f(0u8..=255: u8) {}
pub mod internal {
// @has 'raw_ident_eliminate_r_hashtag/internal/struct.mod.html'
+ #[allow(non_camel_case_types)]
pub struct r#mod;
/// See [name], [other name]
// @has foo/enum.En.html
// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
-// @has - '//*[@class="sidebar-links"]/a' 'foo'
-// @has - '//*[@class="sidebar-links"]/a' 'bar'
+// @has - '//*[@class="sidebar-links"]/a' 'Foo'
+// @has - '//*[@class="sidebar-links"]/a' 'Bar'
pub enum En {
- foo,
- bar,
+ Foo,
+ Bar,
}
// @has foo/union.MyUnion.html
// @has static_root_path/struct.SomeStruct.html
// @matches - '"/cache/main\.js"'
// @!matches - '"\.\./main\.js"'
-// @matches - '"\.\./search-index\.js"'
+// @matches - 'data-root-path="\.\./"'
// @!matches - '"/cache/search-index\.js"'
pub struct SomeStruct;
#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
// @matches 'foo/index.html' '//h1' 'Crate foo'
// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
extern crate rustc_lint;
#[macro_use]
extern crate rustc_session;
-extern crate rustc_span;
extern crate rustc_ast;
+extern crate rustc_span;
use rustc_ast_pretty::pprust;
use rustc_driver::plugin::Registry;
) {
let item = match cx.tcx.hir().get(id) {
Node::Item(item) => item,
- _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
+ _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).expect_owner()),
};
let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr");
--- /dev/null
+trait NotFoo {}
+
+pub trait Foo: NotFoo {
+ type OnlyFoo;
+}
+
+pub trait Service {
+ type AssocType;
+}
+
+pub trait ThriftService<Bug: NotFoo>:
+//~^ ERROR the trait bound `Bug: Foo` is not satisfied
+//~| ERROR the trait bound `Bug: Foo` is not satisfied
+ Service<AssocType = <Bug as Foo>::OnlyFoo>
+{
+ fn get_service(
+ //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+ //~| ERROR the trait bound `Bug: Foo` is not satisfied
+ &self,
+ ) -> Self::AssocType;
+}
+
+fn with_factory<H>(factory: dyn ThriftService<()>) {}
+//~^ ERROR the trait bound `(): Foo` is not satisfied
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:5
+ |
+LL | / fn get_service(
+LL | |
+LL | |
+LL | | &self,
+LL | | ) -> Self::AssocType;
+ | |_________________________^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:8
+ |
+LL | fn get_service(
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/issue-59324.rs:23:29
+ |
+LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+#![allow(dead_code)]
+
+trait ParseError {
+ type StreamError;
+}
+
+impl<T> ParseError for T {
+ type StreamError = ();
+}
+
+trait Stream {
+ type Item;
+ type Error: ParseError;
+}
+
+trait Parser
+where
+ <Self as Parser>::PartialState: Default,
+{
+ type PartialState;
+ fn parse_mode(_: &Self, _: Self::PartialState) {
+ loop {}
+ }
+}
+
+impl Stream for () {
+ type Item = ();
+ type Error = ();
+}
+
+impl Parser for () {
+ type PartialState = ();
+}
+
+struct AndThen<A, B>(core::marker::PhantomData<(A, B)>);
+
+impl<A, B> Parser for AndThen<A, B>
+where
+ A: Stream,
+ B: Into<<A::Error as ParseError>::StreamError>,
+{
+ type PartialState = ();
+}
+
+fn expr<A>() -> impl Parser
+where
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ AndThen::<A, ()>(core::marker::PhantomData)
+}
+
+fn parse_mode_impl<A>()
+where
+ <A as Stream>::Error: ParseError,
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ Parser::parse_mode(&expr::<A>(), Default::default())
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub trait Foo {
+ type Bar;
+}
+
+pub trait Broken {
+ type Assoc;
+ fn broken(&self) where Self::Assoc: Foo;
+}
+
+impl<T> Broken for T {
+ type Assoc = ();
+ fn broken(&self) where Self::Assoc: Foo {
+ let _x: <Self::Assoc as Foo>::Bar;
+ }
+}
+
+fn main() {
+ let _m: &dyn Broken<Assoc=()> = &();
+}
--- /dev/null
+// check-pass
+
+use std::borrow::Cow;
+
+enum _Recursive<'a>
+where
+ Self: ToOwned<Owned=Box<Self>>
+{
+ Variant(MyCow<'a, _Recursive<'a>>),
+}
+
+pub struct Wrapper<T>(T);
+
+pub struct MyCow<'a, T: ToOwned<Owned=Box<T>> + 'a>(Wrapper<Cow<'a, T>>);
+
+fn main() {}
--- /dev/null
+// check-pass
+
+mod convenience_operators {
+ use crate::{Op, Relation};
+ use std::ops::AddAssign;
+ use std::ops::Mul;
+
+ impl<C: Op> Relation<C> {
+ pub fn map<F: Fn(C::D) -> D2 + 'static, D2: 'static>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = C::R>> {
+ self.map_dr(move |x, r| (f(x), r))
+ }
+ }
+
+ impl<K: 'static, V: 'static, C: Op<D = (K, V)>> Relation<C> {
+ pub fn semijoin<C2: Op<D = K, R = R2>, R2, R3: AddAssign<R3>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = C::D, R = R3>>
+ where
+ C::R: Mul<R2, Output = R3>,
+ {
+ self.join(other.map(|x| (x, ()))).map(|(k, x, ())| (k, x))
+ }
+ }
+}
+
+mod core {
+ mod operator {
+ mod join {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::{AddAssign, Mul};
+ struct Join<LC, RC> {
+ _left: LC,
+ _right: RC,
+ }
+ impl<
+ LC: Op<D = (K, LD), R = LR>,
+ RC: Op<D = (K, RD), R = RR>,
+ K: 'static,
+ LD: 'static,
+ LR: AddAssign<LR> + Mul<RR, Output = OR>,
+ RD: 'static,
+ RR: AddAssign<RR>,
+ OR: AddAssign<OR>,
+ > Op for Join<LC, RC>
+ {
+ type D = (K, LD, RD);
+ type R = OR;
+ }
+ impl<K: 'static, D: 'static, C: Op<D = (K, D)>> Relation<C> {
+ pub fn join<C2: Op<D = (K, D2)>, D2: 'static, OR: AddAssign<OR>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = (K, D, D2), R = OR>>
+ where
+ C::R: Mul<C2::R, Output = OR>,
+ {
+ Relation {
+ inner: Join {
+ _left: self.inner,
+ _right: other.inner,
+ },
+ }
+ }
+ }
+ }
+ mod map {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::AddAssign;
+ struct Map<C, MF> {
+ _inner: C,
+ _op: MF,
+ }
+ impl<
+ D1,
+ R1,
+ D2: 'static,
+ R2: AddAssign<R2>,
+ C: Op<D = D1, R = R1>,
+ MF: Fn(D1, R1) -> (D2, R2),
+ > Op for Map<C, MF>
+ {
+ type D = D2;
+ type R = R2;
+ }
+ impl<C: Op> Relation<C> {
+ pub fn map_dr<F: Fn(C::D, C::R) -> (D2, R2), D2: 'static, R2: AddAssign<R2>>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = R2>> {
+ Relation {
+ inner: Map {
+ _inner: self.inner,
+ _op: f,
+ },
+ }
+ }
+ }
+ }
+ use std::ops::AddAssign;
+ pub trait Op {
+ type D: 'static;
+ type R: AddAssign<Self::R>;
+ }
+ }
+ pub use self::operator::Op;
+ #[derive(Clone)]
+ pub struct Relation<C> {
+ inner: C,
+ }
+}
+
+use self::core::Op;
+pub use self::core::Relation;
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ ERROR layout error: NormalizationFailure
+
+fn main() {}
--- /dev/null
+error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
+ --> $DIR/issue-85103.rs:6:1
+ |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
//~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
accepts_trait(returns_opaque_foo());
- //~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
accepts_trait(returns_opaque_derived_foo());
- //~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
accepts_generic_trait(returns_opaque_generic());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_foo());
- //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_duplicate());
- //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
}
LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:85:5
|
LL | fn returns_opaque_foo() -> impl Trait + Foo {
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl Trait + Foo as Trait>::Associated`
+ found associated type `<impl Foo + Trait as Trait>::Associated`
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl Trait + Foo as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl Foo + Trait as Trait>::Associated` to `()`
|
LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:88:5
|
LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl DerivedTrait + Foo as Trait>::Associated`
- = help: consider constraining the associated type `<impl DerivedTrait + Foo as Trait>::Associated` to `()`
+ found associated type `<impl Foo + DerivedTrait as Trait>::Associated`
+ = help: consider constraining the associated type `<impl Foo + DerivedTrait as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:94:5
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated`
+ found associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated`
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
-help: consider constraining the associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated` to `()`
+help: consider constraining the associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:97:5
|
LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated`
- = help: consider constraining the associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+ found associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated`
+ = help: consider constraining the associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
--- /dev/null
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Trait{
+ type R;
+ fn func(self)->Self::R;
+}
+
+pub struct TraitImpl<const N:usize>(pub i32);
+
+impl<const N:usize> Trait for TraitImpl<N>
+where [();N/2]:,
+{
+ type R = Self;
+ fn func(self)->Self::R {
+ self
+ }
+}
+
+fn sample<P,Convert>(p:P,f:Convert) -> i32
+where
+ P:Trait,Convert:Fn(P::R)->i32
+{
+ f(p.func())
+}
+
+fn main() {
+ let t = TraitImpl::<10>(4);
+ sample(t,|x|x.0);
+}
--- /dev/null
+// check-pass
+
+#![feature(extern_types)]
+#![allow(dead_code)]
+
+extern {
+ type Extern;
+}
+
+trait Trait {
+ type Type;
+}
+
+#[inline]
+fn f<'a>(_: <&'a Extern as Trait>::Type) where &'a Extern: Trait {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+struct Struct;
+
+trait Trait {
+ type Type;
+}
+
+enum Enum<'a> where &'a Struct: Trait {
+ Variant(<&'a Struct as Trait>::Type)
+}
+
+fn main() {}
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
return 0u8;
};
let _: &dyn Future<Output = ()> = █
- //~^ ERROR type mismatch resolving `<impl Future as Future>::Output == ()`
+ //~^ ERROR type mismatch
}
async fn return_targets_async_block_not_async_fn() -> u8 {
- //~^ ERROR mismatched types
+ //~^ ERROR mismatched types [E0308]
let block = async {
return 0u8;
};
let _: &dyn Future<Output = ()> = █
- //~^ ERROR type mismatch resolving `<impl Future as Future>::Output == ()`
+ //~^ ERROR type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
}
fn no_break_in_async_block() {
LL | | }
| |_^ expected `u8`, found `()`
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = █
| |
| implicitly returns `()` as its body has no tail or `return` expression
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = █
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/async-error-span.rs:13:9
fn main() {
assert_eq!(1025, std::mem::size_of_val(&single()));
assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
- assert_eq!(3078, std::mem::size_of_val(&joined()));
- assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
- assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
+ assert_eq!(3076, std::mem::size_of_val(&joined()));
+ assert_eq!(3076, std::mem::size_of_val(&joined_with_noop()));
+ assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
}
--- /dev/null
+// run-pass
+// aux-build: issue-72470-lib.rs
+// edition:2021
+#![feature(into_future)]
+
+extern crate issue_72470_lib;
+use std::{future::{Future, IntoFuture}, pin::Pin};
+
+struct AwaitMe;
+
+impl IntoFuture for AwaitMe {
+ type Output = i32;
+ type Future = Pin<Box<dyn Future<Output = i32>>>;
+
+ fn into_future(self) -> Self::Future {
+ Box::pin(me())
+ }
+}
+
+async fn me() -> i32 {
+ 41
+}
+
+async fn run() {
+ assert_eq!(AwaitMe.await, 41);
+}
+
+fn main() {
+ issue_72470_lib::run(run());
+}
| the expected opaque type
| the found opaque type
|
- = note: expected opaque type `impl Future` (`async` closure body)
- found opaque type `impl Future` (`async` closure body)
+ = note: expected opaque type `impl Future<Output = [async output]>` (`async` closure body)
+ found opaque type `impl Future<Output = [async output]>` (`async` closure body)
error: aborting due to 3 previous errors
LL | spawn(async {
| ^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()`
+ = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*mut ()`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-67252-unnamed-future.rs:20:9
|
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
- = note: required because it appears within the type `impl Future`
+ = note: required because it appears within the type `impl Future<Output = [async output]>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
- = note: required because it appears within the type `impl Future`
+ = note: required because it appears within the type `impl Future<Output = [async output]>`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
| ^^^^^^^^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
error: aborting due to 4 previous errors
| ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
|
= help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+ = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
error: aborting due to 4 previous errors
LL | assert_send(async {
| ^^^^^^^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future`, the trait `Send` is not implemented for `*const u8`
+ = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:9
|
//~^ ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
+ //~| ERROR type inside `async fn` body must be known in this context
+ //~| ERROR type inside `async fn` body must be known in this context
+ //~| NOTE cannot infer type for type parameter `T`
+ //~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE in this expansion of desugaring of `await`
+ //~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
LL | bar().await;
| ^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error[E0698]: type inside `async fn` body must be known in this context
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+ |
+note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^^^^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+ |
+note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0698`.
--- /dev/null
+#![u=||{static d=||1;}]
+//~^ unexpected token
+//~| cannot find attribute `u` in this scope
+//~| `main` function not found in crate `issue_90873`
+//~| missing type for `static` item
+
+#![a={impl std::ops::Neg for i8 {}}]
+//~^ ERROR unexpected token
+//~| ERROR cannot find attribute `a` in this scope
--- /dev/null
+error: unexpected token: `||
+ {
+ static d: _ = || 1;
+ }`
+ --> $DIR/issue-90873.rs:1:6
+ |
+LL | #![u=||{static d=||1;}]
+ | ^^^^^^^^^^^^^^^^^
+
+error: unexpected token: `{
+ impl std::ops::Neg for i8 { }
+ }`
+ --> $DIR/issue-90873.rs:7:6
+ |
+LL | #![a={impl std::ops::Neg for i8 {}}]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `u` in this scope
+ --> $DIR/issue-90873.rs:1:4
+ |
+LL | #![u=||{static d=||1;}]
+ | ^
+
+error: cannot find attribute `a` in this scope
+ --> $DIR/issue-90873.rs:7:4
+ |
+LL | #![a={impl std::ops::Neg for i8 {}}]
+ | ^
+
+error[E0601]: `main` function not found in crate `issue_90873`
+ --> $DIR/issue-90873.rs:1:1
+ |
+LL | / #![u=||{static d=||1;}]
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | #![a={impl std::ops::Neg for i8 {}}]
+ | |____________________________________^ consider adding a `main` function to `$DIR/issue-90873.rs`
+
+error: missing type for `static` item
+ --> $DIR/issue-90873.rs:1:16
+ |
+LL | #![u=||{static d=||1;}]
+ | ^ help: provide a type for the item: `d: <type>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", v);
| ^ use of possibly-uninitialized `v`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0381]: borrow of possibly-uninitialized variable: `x`
--> $DIR/issue-24267-flow-exit.rs:18:20
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
// looks at some parent.
// 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]compile-flags: -Z borrowck=mir
-
-
// transcribed from borrowck-closures-unique.rs
mod borrowck_closures_unique {
pub fn e(x: &'static mut isize) {
+++ /dev/null
-error[E0506]: cannot assign to `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:11:5
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-LL |
-LL | greeting = "DEALLOCATED".to_string();
- | ^^^^^^^^ assignment to borrowed `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error[E0505]: cannot move out of `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:14:10
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-...
-LL | drop(greeting);
- | ^^^^^^^^ move out of `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0505, E0506.
-For more information about an error, try `rustc --explain E0505`.
--- /dev/null
+struct TestClient;
+
+impl TestClient {
+ fn get_inner_ref(&self) -> &Vec<usize> {
+ todo!()
+ }
+}
+
+fn main() {
+ let client = TestClient;
+ let inner = client.get_inner_ref();
+ //~^ HELP consider changing this to be a mutable reference
+ inner.clear();
+ //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596]
+}
--- /dev/null
+error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference
+ --> $DIR/issue-91206.rs:13:5
+ |
+LL | let inner = client.get_inner_ref();
+ | ----- help: consider changing this to be a mutable reference: `&mut Vec<usize>`
+LL |
+LL | inner.clear();
+ | ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+#![feature(arbitrary_enum_discriminant)]
+
+#[repr(u8)]
+enum Kind2 {
+ Foo() = 1,
+ Bar{} = 2,
+ Baz = 3,
+}
+
+fn main() {
+ let _ = Kind2::Foo() as u8;
+ //~^ ERROR non-primitive cast
+}
--- /dev/null
+error[E0605]: non-primitive cast: `Kind2` as `u8`
+ --> $DIR/issue-88621.rs:11:13
+ |
+LL | let _ = Kind2::Foo() as u8;
+ | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0605`.
...
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
--> $DIR/arrays.rs:73:24
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
--> $DIR/box.rs:55:5
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 1 warning emitted
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--- /dev/null
+// error-pattern: any use of this value will cause an error
+
+#![feature(never_type)]
+#![feature(const_maybe_uninit_assume_init, const_assert_type2)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+#[allow(invalid_value)]
+fn main() {
+ use std::mem::MaybeUninit;
+
+ const _BAD1: () = unsafe {
+ MaybeUninit::<!>::uninit().assume_init();
+ };
+ const _BAD2: () = unsafe {
+ intrinsics::assert_uninit_valid::<bool>();
+ };
+ const _BAD3: () = unsafe {
+ intrinsics::assert_zero_valid::<&'static i32>();
+ };
+}
--- /dev/null
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:14:9
+ |
+LL | / const _BAD1: () = unsafe {
+LL | | MaybeUninit::<!>::uninit().assume_init();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL | | };
+ | |______-
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:17:9
+ |
+LL | / const _BAD2: () = unsafe {
+LL | | intrinsics::assert_uninit_valid::<bool>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:20:9
+ |
+LL | / const _BAD3: () = unsafe {
+LL | | intrinsics::assert_zero_valid::<&'static i32>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to 3 previous errors
+
+++ /dev/null
-// error-pattern: any use of this value will cause an error
-
-#![feature(never_type)]
-#![feature(const_maybe_uninit_assume_init)]
-
-#[allow(invalid_value)]
-fn main() {
- use std::mem::MaybeUninit;
-
- const _BAD: () = unsafe {
- MaybeUninit::<!>::uninit().assume_init();
- };
-}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/assume-type-intrinsics.rs:11:9
- |
-LL | / const _BAD: () = unsafe {
-LL | | MaybeUninit::<!>::uninit().assume_init();
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
-LL | | };
- | |______-
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to previous error
-
-static a: &'static str = "foo";
-static b: *const u8 = a as *const u8; //~ ERROR casting
-static c: *const u8 = &a as *const u8; //~ ERROR casting
+const a: &str = "foo";
+const b: *const u8 = a as *const u8; //~ ERROR casting
+const c: *const u8 = &a as *const u8; //~ ERROR casting
fn main() {
}
error[E0606]: casting `&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:2:23
+ --> $DIR/const-cast-different-types.rs:2:22
|
-LL | static b: *const u8 = a as *const u8;
- | ^^^^^^^^^^^^^^
+LL | const b: *const u8 = a as *const u8;
+ | ^^^^^^^^^^^^^^
error[E0606]: casting `&&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:3:23
+ --> $DIR/const-cast-different-types.rs:3:22
|
-LL | static c: *const u8 = &a as *const u8;
- | ^^^^^^^^^^^^^^^
+LL | const c: *const u8 = &a as *const u8;
+ | ^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-static a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
-static b: *const i8 = &a as *const i8; //~ ERROR mismatched types
+const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
+const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
fn main() {
}
error[E0308]: mismatched types
- --> $DIR/const-cast-wrong-type.rs:2:23
+ --> $DIR/const-cast-wrong-type.rs:2:22
|
-LL | static b: *const i8 = &a as *const i8;
- | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
+LL | const b: *const i8 = &a as *const i8;
+ | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
error: aborting due to previous error
// build-fail
-// compile-flags: -Zforce-overflow-checks=on
+// compile-flags: -C overflow-checks=on
#![allow(arithmetic_overflow)]
#![warn(const_err)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 2 warnings emitted
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation of constant value failed
--> $DIR/issue-43197.rs:16:26
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors; 4 warnings emitted
--- /dev/null
+// check-fail
+
+#![feature(const_precise_live_drops)]
+
+struct S;
+
+impl Drop for S {
+ fn drop(&mut self) {
+ println!("Hello!");
+ }
+}
+
+const fn foo() {
+ let s = S; //~ destructor
+}
+
+fn main() {}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop_zst.rs:14:9
+ |
+LL | let s = S;
+ | ^ constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
#![l=|x|[b;x ]] //~ ERROR unexpected token: `|x| [b; x]`
//~^ ERROR cannot find attribute `l` in this scope
-//~^^ ERROR attempt to use a non-constant value in a constant [E0435]
-//~^^^ ERROR cannot find value `b` in this scope [E0425]
// notice the space at the start,
// we can't attach any attributes to this file because it needs to be at the start
LL | #![l=|x|[b;x ]]
| ^
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/issue-90878-2.rs:1:13
- |
-LL | #![l=|x|[b;x ]]
- | - ^
- | |
- | this would need to be a `const`
-
-error[E0425]: cannot find value `b` in this scope
- --> $DIR/issue-90878-2.rs:1:11
- |
-LL | #![l=|x|[b;x ]]
- | ^ help: a local variable with a similar name exists: `x`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0425, E0435.
-For more information about an error, try `rustc --explain E0425`.
#![no_std]
use ::foo; //~ ERROR invalid metadata files for crate `foo`
//~| NOTE failed to mmap file
+//~^^ ERROR invalid metadata files for crate `foo`
+//~| NOTE failed to mmap file
|
= note: failed to mmap file 'auxiliary/libfoo.rlib'
-error: aborting due to previous error
+error[E0786]: found invalid metadata files for crate `foo`
+ --> $DIR/invalid-rlib.rs:7:7
+ |
+LL | use ::foo;
+ | ^^^
+ |
+ = note: failed to mmap file 'auxiliary/libfoo.rlib'
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0786`.
// compile-flags: --target x86_64-unknown-uefi
// needs-llvm-components: x86
// rustc-env:CARGO=/usr/bin/cargo
+#![feature(no_core)]
#![no_core]
extern crate core;
//~^ ERROR can't find crate for `core`
error[E0463]: can't find crate for `core`
- --> $DIR/missing-std.rs:5:1
+ --> $DIR/missing-std.rs:6:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ can't find crate
= help: consider downloading the target with `rustup target add x86_64-unknown-uefi`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error: requires `sized` lang_item
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0463`.
--> $DIR/dst-bad-assign-3.rs:33:12
|
LL | f5.2 = Bar1 {f: 36};
- | ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | ---- ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | |
+ | expected due to the type of this binding
|
= note: expected trait object `dyn ToBar`
found struct `Bar1`
--> $DIR/dst-bad-assign.rs:35:14
|
LL | f5.ptr = Bar1 {f: 36};
- | ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | ------ ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | |
+ | expected due to the type of this binding
|
= note: expected trait object `dyn ToBar`
found struct `Bar1`
LL | pub const BAR: MainFn = bar;
| ^^^ expected opaque type, found fn item
|
- = note: expected opaque type `impl Fn<()>`
+ = note: expected opaque type `impl Fn()`
found fn item `fn() {bar}`
error: could not find defining uses
}
}
-#[allow(dead_code)]
-#[repr(u8)]
-enum FieldlessEnum {
- Unit = 3,
- Tuple() = 2,
- Struct {} = 1,
-}
-
fn main() {
const UNIT: Enum = Enum::Unit;
const TUPLE: Enum = Enum::Tuple(5);
assert_eq!(3, UNIT_TAG);
assert_eq!(2, TUPLE_TAG);
assert_eq!(1, STRUCT_TAG);
-
- // Ensure `as` conversions are correct
- assert_eq!(3, FieldlessEnum::Unit as u8);
- assert_eq!(2, FieldlessEnum::Tuple() as u8);
- assert_eq!(1, FieldlessEnum::Struct{} as u8);
}
SOME_CONST = 14; //~ ERROR E0070
1 = 3; //~ ERROR E0070
some_other_func() = 4; //~ ERROR E0070
- //~^ ERROR E0308
}
fn main() {
| |
| cannot assign to this expression
-error[E0308]: mismatched types
- --> $DIR/E0070.rs:8:25
- |
-LL | some_other_func() = 4;
- | ^ expected `()`, found integer
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0070, E0308.
-For more information about an error, try `rustc --explain E0070`.
+For more information about this error, try `rustc --explain E0070`.
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
-// ignore-compare-mode-nll
-
// Check that E0161 is a hard error in all possible configurations that might
// affect it.
//[zflagsul] check-pass
//[editionul] check-pass
+// 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
+
#![allow(incomplete_features)]
#![cfg_attr(nll, feature(nll))]
#![cfg_attr(nllul, feature(nll))]
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
LL | }
| ^ expected `{`
|
- = help: maybe you forgot the right operand of the condition?
+help: maybe you forgot the right operand of the condition?
+ --> $DIR/if-without-block.rs:3:10
+ |
+LL | if 5 == {
+ | ^^
error: aborting due to previous error
// compile-flags: --extern std=
// error-pattern: extern location for std does not exist
+// needs-unwind since it affects the error output
+// ignore-emscripten compiled with panic=abort, personality not required
fn main() {}
error: extern location for std does not exist:
-error: aborting due to previous error
+error: language item required, but not found: `eh_personality`
+
+error: `#[panic_handler]` function required, but not found
+
+error: aborting due to 3 previous errors
--- /dev/null
+// If multiple `extern crate` resolutions fail each of them should produce an error
+extern crate bar; //~ ERROR can't find crate for `bar`
+extern crate foo; //~ ERROR can't find crate for `foo`
+
+fn main() {
+ // If the crate name introduced by `extern crate` failed to resolve then subsequent
+ // derived paths do not emit additional errors
+ foo::something();
+ bar::something();
+}
--- /dev/null
+error[E0463]: can't find crate for `bar`
+ --> $DIR/extern-crate-multiple-missing.rs:2:1
+ |
+LL | extern crate bar;
+ | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error[E0463]: can't find crate for `foo`
+ --> $DIR/extern-crate-multiple-missing.rs:3:1
+ |
+LL | extern crate foo;
+ | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
--- /dev/null
+// check-pass
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(_: <&'a &'b () as Trait>::Type)
+where
+ 'a: 'a,
+ 'b: 'b,
+{
+}
+
+fn g<'a, 'b>() {
+ f::<'a, 'b>(());
+}
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | s
+ | ^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-fail
+// See issue #91068. Types in the substs of an associated type can't be implied
+// to be WF, since they don't actually have to be constructed.
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ s //~ ERROR lifetime mismatch [E0623]
+}
+
+fn main() {
+ let x = String::from("Hello World!");
+ let y = f(&x, ());
+ drop(x);
+ println!("{}", y);
+}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | ------- ----------
+ | |
+ | these two types are declared with different lifetimes...
+LL | s
+ | ^ ...but data from `s` flows here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
// Test that we use fully-qualified type names in error messages.
fn main() {
- let x: Option<usize>;
+ let x: //~ NOTE expected due to the type of this binding
+ Option<usize>; //~ NOTE expected due to this type
x = 5;
//~^ ERROR mismatched types
- //~| expected enum `Option<usize>`
- //~| found type `{integer}`
- //~| expected enum `Option`, found integer
+ //~| NOTE expected enum `Option<usize>`
+ //~| NOTE expected enum `Option`, found integer
}
error[E0308]: mismatched types
- --> $DIR/fully-qualified-type-name1.rs:5:9
+ --> $DIR/fully-qualified-type-name1.rs:6:9
|
+LL | let x:
+ | - expected due to the type of this binding
+LL | Option<usize>;
+ | ------------- expected due to this type
LL | x = 5;
| ^ expected enum `Option`, found integer
|
--> $DIR/issue-68112.rs:31:9
|
LL | let _non_send_gen = make_non_send_generator();
- | ------------- has type `impl Generator` which is not `Send`
+ | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
LL | };
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]`
- = note: required because it appears within the type `impl Generator`
- = note: required because it appears within the type `impl Generator`
- = note: required because it appears within the type `{impl Generator, ()}`
+ = note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ = note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ = note: required because it appears within the type `{impl Generator<Return = Arc<RefCell<i32>>>, ()}`
= note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:22:25
| ^ second borrow occurs here
LL | Pin::new(&mut b).resume(());
| ------ first borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--- /dev/null
+fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+//~| ERROR failed to resolve: use of undeclared type `I`
+ panic!()
+}
+
+fn main() {}
--- /dev/null
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:1:51
+ |
+LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:5:41
+ |
+LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+error[E0433]: failed to resolve: use of undeclared type `I`
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^ use of undeclared type `I`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
+++ /dev/null
-// Checks that we properly add implied bounds from unnormalized projections in
-// inputs when typechecking functions.
-
-// check-pass
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
- type Assoc<'a, 'b> where 'b: 'a;
- fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct A;
-struct B;
-struct C;
-
-impl MyTrait for A {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: u32) {}
-}
-impl MyTrait for B {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-impl MyTrait for C {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'static, 'static>) {}
-}
-
-fn main () {}
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/missing-bounds.rs:37:33
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | ^^^^^^^^^^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
+ | ~~~~~~~~~~~~~~~~~~
+
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
|
LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| +++++++++++++++++++++++++++
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/missing-bounds.rs:42:14
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | - this type parameter
+...
+LL | Self(self.0 + rhs.0)
+ | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
+ |
+ = note: expected type parameter `B`
+ found associated type `<B as Add>::Output`
+help: consider further restricting type parameter `B`
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
+ | ++++++++++++++++++++
+
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for #88586: a higher-ranked outlives bound on Self in a trait
+// definition caused an ICE when debug_assertions were enabled.
+//
+// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved.
+
+trait A where for<'a> Self: 'a
+//~^ ERROR the parameter type `Self` may not live long enough
+{
+}
+
+fn main() {}
--- /dev/null
+error[E0311]: the parameter type `Self` may not live long enough
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:1
+ |
+LL | / trait A where for<'a> Self: 'a
+LL | |
+LL | | {
+LL | | }
+ | |_^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:29
+ |
+LL | trait A where for<'a> Self: 'a
+ | ^^
+
+error: aborting due to previous error
+
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57: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:52:5
+ --> $DIR/issue-71955.rs:57: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:52:5
+ --> $DIR/issue-71955.rs:57: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:52:5
+ --> $DIR/issue-71955.rs:57: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:52:5
+ --> $DIR/issue-71955.rs:57: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:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.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:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.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:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.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:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.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:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
error: fatal error triggered by #[rustc_error]
- --> $DIR/issue-71955.rs:42:1
+ --> $DIR/issue-71955.rs:47:1
|
LL | fn main() {
| ^^^^^^^^^
// [nll]compile-flags: -Zborrowck=mir
// check-fail
+// 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
+
#![feature(rustc_attrs)]
trait Parser<'s> {
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
// through again.
// 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
// ignore-compare-mode-polonius
-//[nll]compile-flags: -Z borrowck=mir
-
pub trait Stream {
type Item;
fn next(self) -> Option<Self::Item>;
--> $DIR/auto-trait-leak2.rs:13:10
|
LL | fn before() -> impl Fn(i32) {
- | ------------ within this `impl Fn<(i32,)>`
+ | ------------ within this `impl Fn(i32)`
...
LL | send(before());
| ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
- = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
+ = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
- = note: required because it appears within the type `impl Fn<(i32,)>`
+ = note: required because it appears within the type `impl Fn(i32)`
note: required by a bound in `send`
--> $DIR/auto-trait-leak2.rs:10:12
|
| required by a bound introduced by this call
...
LL | fn after() -> impl Fn(i32) {
- | ------------ within this `impl Fn<(i32,)>`
+ | ------------ within this `impl Fn(i32)`
|
- = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
+ = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]`
- = note: required because it appears within the type `impl Fn<(i32,)>`
+ = note: required because it appears within the type `impl Fn(i32)`
note: required by a bound in `send`
--> $DIR/auto-trait-leak2.rs:10:12
|
| expected type parameter
| found type parameter
...
+LL | let mut a = x;
+ | - expected due to this value
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
type E = impl std::marker::Copy;
fn foo<T>() -> Self::E {
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- //~| ERROR the trait bound `impl Future: Copy` is not satisfied [E0277]
+ //~| ERROR the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
async {}
}
}
-error[E0277]: the trait bound `impl Future: Copy` is not satisfied
+error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
--> $DIR/issue-55872-2.rs:14:20
|
LL | fn foo<T>() -> Self::E {
- | ^^^^^^^ the trait `Copy` is not implemented for `impl Future`
+ | ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-2.rs:14:28
LL | lint_files().flat_map(|f| gather_from_file(&f))
| -----------------------------------------------
| |
- | returning here with type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
- | returning here with type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
...
LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
- | -------------------------- returning this opaque type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | -------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
...
LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
- | -------------------------------------- returning this opaque type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | -------------------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
error: aborting due to 3 previous errors
| ^^^^^^^^^ recursive opaque type
...
LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
- | ----------------------------------------------- returning here with type `impl Fn<()>`
+ | ----------------------------------------------- returning here with type `impl Fn()`
...
LL | fn wrap(f: impl Fn()) -> impl Fn() {
- | --------- returning this opaque type `impl Fn<()>`
+ | --------- returning this opaque type `impl Fn()`
error: aborting due to previous error; 1 warning emitted
| ------------------------------- the found opaque type
|
= note: expected opaque type `impl Future<Output = u8>`
- found opaque type `impl Future`
+ found opaque type `impl Future<Output = [async output]>`
= note: distinct uses of `impl Trait` result in different opaque types
error: aborting due to previous error
#![feature(type_alias_impl_trait)]
type FunType = impl Fn<()>;
-//~^ could not find defining uses
+//~^ ERROR could not find defining uses
static STATIC_FN: FunType = some_fn;
-//~^ mismatched types
+//~^ ERROR mismatched types
fn some_fn() {}
| |
| expected type parameter
LL | let mut a = x;
+ | - expected due to this value
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
--> $DIR/extern-crate-self-fail.rs:1:1
|
LL | extern crate self;
- | ^^^^^^^^^^^^^^^^^^ help: try: `extern crate self as name;`
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: rename the `self` crate to be able to import it
+ |
+LL | extern crate self as name;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: `#[macro_use]` is not supported on `extern crate self`
--> $DIR/extern-crate-self-fail.rs:3:1
#![deny(elided_lifetimes_in_paths)]
//~^ NOTE the lint level is defined here
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+ x: &'a u32,
+}
fn foo(x: &Foo<'_>) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
fn bar(x: &Foo<'_>) {}
-
struct Wrapped<'a>(&'a str);
struct WrappedWithBow<'a> {
- gift: &'a str
+ gift: &'a str,
}
struct MatchedSet<'a, 'b> {
fn wrap_gift(gift: &str) -> Wrapped<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
Wrapped(gift)
}
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
WrappedWithBow { gift }
}
fn inspect_matched_set(set: MatchedSet<'_, '_>) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP consider using the `'_` lifetime
println!("{} {}", set.one, set.another);
}
+// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly.
+fn match_sets() -> MatchedSet<'static, 'static> {
+ //~^ ERROR missing lifetime specifiers
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP this function's return type contains a borrowed value
+ //~| HELP consider using the `'static` lifetime
+ MatchedSet { one: "one", another: "another" }
+}
+
macro_rules! autowrapper {
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
struct $type_name<$lt> {
fn $fn_name(gift: &str) -> $type_name<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
+ //~| ERROR hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
$type_name { gift }
}
}
//~^ NOTE in this expansion of autowrapper!
//~| NOTE in this expansion of autowrapper!
+// Verify that rustfix does not try to apply the fix twice.
+autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+//~^ NOTE in this expansion of autowrapper!
+//~| NOTE in this expansion of autowrapper!
+
macro_rules! anytuple_ref_ty {
($($types:ty),*) => {
Ref<'_, ($($types),*)>
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
}
+#[allow(elided_lifetimes_in_paths)]
+mod blah {
+ struct Thing<'a>(&'a i32);
+ struct Bar<T>(T);
+
+ fn foo(b: Bar<Thing>) {}
+}
+
fn main() {
let honesty = RefCell::new((4, 'e'));
let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
let generosity = Ref::map(loyalty, |t| &t.0);
let laughter = RefCell::new((true, "magic"));
#![deny(elided_lifetimes_in_paths)]
//~^ NOTE the lint level is defined here
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+ x: &'a u32,
+}
fn foo(x: &Foo) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
fn bar(x: &Foo<'_>) {}
-
struct Wrapped<'a>(&'a str);
struct WrappedWithBow<'a> {
- gift: &'a str
+ gift: &'a str,
}
struct MatchedSet<'a, 'b> {
fn wrap_gift(gift: &str) -> Wrapped {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
Wrapped(gift)
}
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
WrappedWithBow { gift }
}
fn inspect_matched_set(set: MatchedSet) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP consider using the `'_` lifetime
println!("{} {}", set.one, set.another);
}
+// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly.
+fn match_sets() -> MatchedSet {
+ //~^ ERROR missing lifetime specifiers
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP this function's return type contains a borrowed value
+ //~| HELP consider using the `'static` lifetime
+ MatchedSet { one: "one", another: "another" }
+}
+
macro_rules! autowrapper {
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
struct $type_name<$lt> {
fn $fn_name(gift: &str) -> $type_name {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
+ //~| ERROR hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
$type_name { gift }
}
}
//~^ NOTE in this expansion of autowrapper!
//~| NOTE in this expansion of autowrapper!
+// Verify that rustfix does not try to apply the fix twice.
+autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+//~^ NOTE in this expansion of autowrapper!
+//~| NOTE in this expansion of autowrapper!
+
macro_rules! anytuple_ref_ty {
($($types:ty),*) => {
Ref<($($types),*)>
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
}
+#[allow(elided_lifetimes_in_paths)]
+mod blah {
+ struct Thing<'a>(&'a i32);
+ struct Bar<T>(T);
+
+ fn foo(b: Bar<Thing>) {}
+}
+
fn main() {
let honesty = RefCell::new((4, 'e'));
let loyalty: Ref<(u32, char)> = honesty.borrow();
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
let generosity = Ref::map(loyalty, |t| &t.0);
let laughter = RefCell::new((true, "magic"));
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:13:12
+ --> $DIR/elided-lifetimes.rs:14:12
|
LL | fn foo(x: &Foo) {
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected named lifetime parameter
|
note: the lint level is defined here
--> $DIR/elided-lifetimes.rs:5:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+ |
+LL | fn foo(x: &Foo<'_>) {
+ | ~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:32:29
+ --> $DIR/elided-lifetimes.rs:33:29
|
LL | fn wrap_gift(gift: &str) -> Wrapped {
- | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn wrap_gift(gift: &str) -> Wrapped<'_> {
+ | ~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:38:38
+ --> $DIR/elided-lifetimes.rs:40:38
|
LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
- | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^^^^^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
+ | ~~~~~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:44:29
+ --> $DIR/elided-lifetimes.rs:47:29
|
LL | fn inspect_matched_set(set: MatchedSet) {
- | ^^^^^^^^^^- help: indicate the anonymous lifetimes: `<'_, '_>`
+ | ^^^^^^^^^^ expected 2 lifetime parameters
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) {
+ | ~~~~~~~~~~~~~~~~~~
+
+error[E0106]: missing lifetime specifiers
+ --> $DIR/elided-lifetimes.rs:55:20
+ |
+LL | fn match_sets() -> MatchedSet {
+ | ^^^^^^^^^^ expected 2 lifetime parameters
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | fn match_sets() -> MatchedSet<'static, 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:56:36
+ --> $DIR/elided-lifetimes.rs:69:36
|
LL | fn $fn_name(gift: &str) -> $type_name {
- | ^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^ expected named lifetime parameter
...
LL | autowrapper!(Autowrapped, autowrap_gift, 'a);
| -------------------------------------------- in this macro invocation
|
= note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | fn $fn_name(gift: &str) -> $type_name<'_> {
+ | ~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:78:18
+ --> $DIR/elided-lifetimes.rs:69:36
+ |
+LL | fn $fn_name(gift: &str) -> $type_name {
+ | ^^^^^^^^^^ expected named lifetime parameter
+...
+LL | autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+ | ------------------------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | fn $fn_name(gift: &str) -> $type_name<'_> {
+ | ~~~~~~~~~~~~~~
+
+error: hidden lifetime parameters in types are deprecated
+ --> $DIR/elided-lifetimes.rs:109:22
|
LL | let loyalty: Ref<(u32, char)> = honesty.borrow();
- | ^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, (u32, char)>`
+ | ^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
+ | +++
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:70:9
+ --> $DIR/elided-lifetimes.rs:92:13
|
LL | Ref<($($types),*)>
- | ^^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, ($($types),*)>`
+ | ^ expected named lifetime parameter
...
LL | let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow();
| ---------------------------- in this macro invocation
|
= note: this error originates in the macro `anytuple_ref_ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | Ref<'_, ($($types),*)>
+ | +++
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
+For more information about this error, try `rustc --explain E0106`.
fn main() {
- let mut x = 2;
+ let mut x //~ NOTE expected due to the type of this binding
+ =
+ 2; //~ NOTE expected due to this value
x = 5.0;
//~^ ERROR mismatched types
- //~| expected integer, found floating-point number
+ //~| NOTE expected integer, found floating-point number
}
error[E0308]: mismatched types
- --> $DIR/integral-variable-unification-error.rs:3:9
+ --> $DIR/integral-variable-unification-error.rs:5:9
|
+LL | let mut x
+ | ----- expected due to the type of this binding
+LL | =
+LL | 2;
+ | - expected due to this value
LL | x = 5.0;
| ^^^ expected integer, found floating-point number
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
|
= help: the trait `Future` is not implemented for `u32`
+ = note: u32 must be a future or must implement `IntoFuture` to be awaited
error: aborting due to 2 previous errors
fn main() {
A::C = 1;
//~^ ERROR: invalid left-hand side of assignment
- //~| ERROR: mismatched types
//~| ERROR: struct `C` is private
}
| |
| cannot assign to this expression
-error[E0308]: mismatched types
- --> $DIR/issue-13407.rs:6:12
- |
-LL | A::C = 1;
- | ^ expected struct `C`, found integer
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0070, E0308, E0603.
+Some errors have detailed explanations: E0070, E0603.
For more information about an error, try `rustc --explain E0070`.
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
+ --> $DIR/issue-16538.rs:15:23
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:21
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
+#![feature(const_raw_ptr_deref)]
mod Y {
pub type X = usize;
extern "C" {
}
}
-static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
-//~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
+static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+//~^ ERROR dereference of raw pointer
//~| ERROR E0015
//~| ERROR use of extern static is unsafe and requires
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:22
+ |
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+ --> $DIR/issue-16538.rs:15:23
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
error[E0277]: `Foo` cannot be shared between threads safely
- --> $DIR/issue-17718-static-sync.rs:9:1
+ --> $DIR/issue-17718-static-sync.rs:9:13
|
LL | static BAR: Foo = Foo;
- | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be shared between threads safely
+ | ^^^ `Foo` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Foo`
= note: shared static variables must have a type that implements `Sync`
fn main() {
static foo: dyn Fn() -> u32 = || -> u32 {
//~^ ERROR the size for values of type
+ //~| ERROR cannot be shared between threads safely
0
};
}
|
= help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
-error: aborting due to previous error
+error[E0277]: `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ --> $DIR/issue-24446.rs:2:17
+ |
+LL | static foo: dyn Fn() -> u32 = || -> u32 {
+ | ^^^^^^^^^^^^^^^ `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `(dyn Fn() -> u32 + 'static)`
+ = note: shared static variables must have a type that implements `Sync`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
| |
| expected type parameter
LL | let mut xx = x;
+ | - expected due to this value
LL | xx = y;
| ^ expected type parameter `T`, found type parameter `U`
|
= help: consider downloading the target with `rustup target add thumbv6m-none-eabi`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error: requires `sized` lang_item
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0463`.
...
LL | println!("{}", s);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
...
LL | };
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
-//~ ERROR 1:1: 1:1: can't find crate for `core` [E0463]
+//~ ERROR can't find crate for `core`
+//~^ ERROR can't find crate for `compiler_builtins`
// compile-flags: --target thumbv7em-none-eabihf
// needs-llvm-components: arm
#![no_std]
extern crate cortex_m;
+//~^ ERROR can't find crate for `cortex_m`
+
+fn main() {}
= help: consider downloading the target with `rustup target add thumbv7em-none-eabihf`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error[E0463]: can't find crate for `compiler_builtins`
+
+error[E0463]: can't find crate for `cortex_m`
+ --> $DIR/compiler-builtins-error.rs:10:1
+ |
+LL | extern crate cortex_m;
+ | ^^^^^^^^^^^^^^^^^^^^^^ can't find crate
+
+error: requires `sized` lang_item
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0463`.
fn f() { }
-struct S(Box<dyn FnMut()>);
+struct S(Box<dyn FnMut() + Sync>);
pub static C: S = S(f); //~ ERROR mismatched types
fn g() { }
-type T = Box<dyn FnMut()>;
+type T = Box<dyn FnMut() + Sync>;
pub static D: T = g; //~ ERROR mismatched types
fn main() {}
LL | pub static C: S = S(f);
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {f}`
error[E0308]: mismatched types
LL | pub static D: T = g;
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {g}`
error: aborting due to 2 previous errors
v.into_iter().map(|s|s.to_owned()).collect::<Vec<_>>();
- let mut a = String::new();
+ let mut a = String::new(); //~ NOTE expected due to this value
for i in v {
a = *i.to_string();
//~^ ERROR mismatched types
error[E0308]: mismatched types
--> $DIR/issue-53348.rs:10:13
|
+LL | let mut a = String::new();
+ | ------------- expected due to this value
+LL | for i in v {
LL | a = *i.to_string();
| ^^^^^^^^^^^^^^ expected struct `String`, found `str`
let g = |(a, _)| a;
let t7 = |env| |a| |b| t7p(f, g)(((env, a), b));
let t8 = t8n(t7, t7p(f, g));
- //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>
+ //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))` [E0277]
}
-error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))`
--> $DIR/issue-59494.rs:21:22
|
LL | let t8 = t8n(t7, t7p(f, g));
- | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+ | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn(((_, _), _))`
| |
| required by a bound introduced by this call
|
- = help: the trait `Fn<(_,)>` is not implemented for `impl Fn<(((_, _), _),)>`
+ = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))`
note: required by a bound in `t8n`
--> $DIR/issue-59494.rs:5:45
|
// Regression test for issue 7364
static boxed: Box<RefCell<isize>> = box RefCell::new(0);
-//~^ ERROR allocations are not allowed in statics
-//~| ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
+//~^ ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
fn main() { }
-error[E0010]: allocations are not allowed in statics
- --> $DIR/issue-7364.rs:6:37
- |
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics
-
error[E0277]: `RefCell<isize>` cannot be shared between threads safely
- --> $DIR/issue-7364.rs:6:1
+ --> $DIR/issue-7364.rs:6:15
|
LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
+ | ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `RefCell<isize>`
= note: required because of the requirements on the impl of `Sync` for `Unique<RefCell<isize>>`
= note: required because it appears within the type `Box<RefCell<isize>>`
= note: shared static variables must have a type that implements `Sync`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0010, E0277.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-fn main() {
- let value = [7u8];
- while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
- //~| ERROR invalid left-hand side of assignment
- //~| ERROR mismatched types
- //~| ERROR mismatched types
-
- // FIXME The following diagnostic should also be emitted
- // HELP you might have meant to use pattern matching
- }
-}
+++ /dev/null
-error[E0658]: destructuring assignments are unstable
- --> $DIR/issue-77218.rs:3:19
- |
-LL | while Some(0) = value.get(0) {
- | ------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0070]: invalid left-hand side of assignment
- --> $DIR/issue-77218.rs:3:19
- |
-LL | while Some(0) = value.get(0) {
- | - ^
- | |
- | cannot assign to this expression
-
-error[E0308]: mismatched types
- --> $DIR/issue-77218.rs:3:16
- |
-LL | while Some(0) = value.get(0) {
- | ^ expected integer, found `&u8`
- |
-help: consider dereferencing the borrow
- |
-LL | while Some(*0) = value.get(0) {
- | +
-
-error[E0308]: mismatched types
- --> $DIR/issue-77218.rs:3:11
- |
-LL | while Some(0) = value.get(0) {
- | ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0070, E0308, E0658.
-For more information about an error, try `rustc --explain E0070`.
--- /dev/null
+// run-rustfix
+#![feature(destructuring_assignment)]
+fn main() {
+ let value = [7u8];
+ while let Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+ }
+}
--- /dev/null
+// run-rustfix
+#![feature(destructuring_assignment)]
+fn main() {
+ let value = [7u8];
+ while Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+ }
+}
--- /dev/null
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/issue-77218-2.rs:5:19
+ |
+LL | while Some(0) = value.get(0) {
+ | - ^
+ | |
+ | cannot assign to this expression
+ |
+help: you might have meant to use pattern destructuring
+ |
+LL | while let Some(0) = value.get(0) {
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
--- /dev/null
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while let Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
+ }
+}
--- /dev/null
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
+ }
+}
--- /dev/null
+error[E0658]: destructuring assignments are unstable
+ --> $DIR/issue-77218.rs:4:19
+ |
+LL | while Some(0) = value.get(0) {
+ | ------- ^
+ | |
+ | cannot assign to this expression
+ |
+ = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+ = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+help: you might have meant to use pattern destructuring
+ |
+LL | while let Some(0) = value.get(0) {
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-pass
+// compile-flags:-C debuginfo=2
+// edition:2018
+
+use core::marker::PhantomData;
+
+pub struct Foo<T: ?Sized, A>(
+ PhantomData<(A, T)>,
+);
+
+enum Never {}
+
+impl<T: ?Sized> Foo<T, Never> {
+ fn new_foo() -> Foo<T, Never> {
+ Foo(PhantomData)
+ }
+}
+
+fn main() {
+ let _ = Foo::<[()], Never>::new_foo();
+}
--- /dev/null
+fn main() {
+ 0b121; //~ ERROR invalid digit for a base 2 literal
+ 0b10_10301; //~ ERROR invalid digit for a base 2 literal
+ 0b30; //~ ERROR invalid digit for a base 2 literal
+ 0b41; //~ ERROR invalid digit for a base 2 literal
+ 0b5; //~ ERROR invalid digit for a base 2 literal
+ 0b6; //~ ERROR invalid digit for a base 2 literal
+ 0b7; //~ ERROR invalid digit for a base 2 literal
+ 0b8; //~ ERROR invalid digit for a base 2 literal
+ 0b9; //~ ERROR invalid digit for a base 2 literal
+}
--- /dev/null
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:2:8
+ |
+LL | 0b121;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:3:12
+ |
+LL | 0b10_10301;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:4:7
+ |
+LL | 0b30;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:5:7
+ |
+LL | 0b41;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:6:7
+ |
+LL | 0b5;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:7:7
+ |
+LL | 0b6;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:8:7
+ |
+LL | 0b7;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:9:7
+ |
+LL | 0b8;
+ | ^
+
+error: invalid digit for a base 2 literal
+ --> $DIR/lex-bad-binary-literal.rs:10:7
+ |
+LL | 0b9;
+ | ^
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+static c3: char =
+ '\x1' //~ ERROR: numeric character escape is too short
+;
+
+static s3: &'static str =
+ "\x1" //~ ERROR: numeric character escape is too short
+;
+
+static c: char =
+ '\●' //~ ERROR: unknown character escape
+;
+
+static s: &'static str =
+ "\●" //~ ERROR: unknown character escape
+;
+
+fn main() {}
--- /dev/null
+error: numeric character escape is too short
+ --> $DIR/lex-bad-char-literals-1.rs:2:6
+ |
+LL | '\x1'
+ | ^^^
+
+error: numeric character escape is too short
+ --> $DIR/lex-bad-char-literals-1.rs:6:6
+ |
+LL | "\x1"
+ | ^^^
+
+error: unknown character escape: `\u{25cf}`
+ --> $DIR/lex-bad-char-literals-1.rs:10:7
+ |
+LL | '\●'
+ | ^ unknown character escape
+ |
+ = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+
+error: unknown character escape: `\u{25cf}`
+ --> $DIR/lex-bad-char-literals-1.rs:14:7
+ |
+LL | "\●"
+ | ^ unknown character escape
+ |
+ = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+ 'nope' //~ ERROR: character literal may only contain one codepoint
+;
+
+fn main() {}
--- /dev/null
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-2.rs:3:5
+ |
+LL | 'nope'
+ | ^^^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | "nope"
+ | ~~~~~~
+
+error: aborting due to previous error
+
--- /dev/null
+static c: char = '●●';
+//~^ ERROR: character literal may only contain one codepoint
+
+fn main() {
+ let ch: &str = '●●';
+ //~^ ERROR: character literal may only contain one codepoint
+}
--- /dev/null
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-3.rs:1:18
+ |
+LL | static c: char = '●●';
+ | ^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | static c: char = "●●";
+ | ~~~~
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-3.rs:5:20
+ |
+LL | let ch: &str = '●●';
+ | ^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let ch: &str = "●●";
+ | ~~~~
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+//
+// This test needs to the last one appearing in this file as it kills the parser
+static c: char =
+ '● //~ ERROR: unterminated character literal
+;
--- /dev/null
+error[E0762]: unterminated character literal
+ --> $DIR/lex-bad-char-literals-4.rs:4:5
+ |
+LL | '●
+ | ^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0762`.
--- /dev/null
+static c: char = '\x10\x10';
+//~^ ERROR: character literal may only contain one codepoint
+
+fn main() {
+ let ch: &str = '\x10\x10';
+ //~^ ERROR: character literal may only contain one codepoint
+}
--- /dev/null
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-5.rs:1:18
+ |
+LL | static c: char = '\x10\x10';
+ | ^^^^^^^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | static c: char = "\x10\x10";
+ | ~~~~~~~~~~
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-5.rs:5:20
+ |
+LL | let ch: &str = '\x10\x10';
+ | ^^^^^^^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let ch: &str = "\x10\x10";
+ | ~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+fn main() {
+ let x: &str = 'ab';
+ //~^ ERROR: character literal may only contain one codepoint
+ let y: char = 'cd';
+ //~^ ERROR: character literal may only contain one codepoint
+ let z = 'ef';
+ //~^ ERROR: character literal may only contain one codepoint
+
+ if x == y {}
+ //~^ ERROR: can't compare `&str` with `char`
+ if y == z {} // no error here
+ if x == z {}
+ //~^ ERROR: can't compare `&str` with `char`
+
+ let a: usize = "";
+ //~^ ERROR: mismatched types
+}
--- /dev/null
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:2:19
+ |
+LL | let x: &str = 'ab';
+ | ^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let x: &str = "ab";
+ | ~~~~
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:4:19
+ |
+LL | let y: char = 'cd';
+ | ^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let y: char = "cd";
+ | ~~~~
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:6:13
+ |
+LL | let z = 'ef';
+ | ^^^^
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let z = "ef";
+ | ~~~~
+
+error[E0277]: can't compare `&str` with `char`
+ --> $DIR/lex-bad-char-literals-6.rs:9:10
+ |
+LL | if x == y {}
+ | ^^ no implementation for `&str == char`
+ |
+ = help: the trait `PartialEq<char>` is not implemented for `&str`
+
+error[E0308]: mismatched types
+ --> $DIR/lex-bad-char-literals-6.rs:15:20
+ |
+LL | let a: usize = "";
+ | ----- ^^ expected `usize`, found `&str`
+ | |
+ | expected due to this
+
+error[E0277]: can't compare `&str` with `char`
+ --> $DIR/lex-bad-char-literals-6.rs:12:10
+ |
+LL | if x == z {}
+ | ^^ no implementation for `&str == char`
+ |
+ = help: the trait `PartialEq<char>` is not implemented for `&str`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+fn main() {
+ let _: char = '';
+ //~^ ERROR: empty character literal
+ let _: char = '\u{}';
+ //~^ ERROR: empty unicode escape
+
+ // Next two are OK, but may befool error recovery
+ let _ = '/';
+ let _ = b'/';
+
+ let _ = ' hello // here's a comment
+ //~^ ERROR: unterminated character literal
+}
--- /dev/null
+error: empty character literal
+ --> $DIR/lex-bad-char-literals-7.rs:2:20
+ |
+LL | let _: char = '';
+ | ^ empty character literal
+
+error: empty unicode escape
+ --> $DIR/lex-bad-char-literals-7.rs:4:20
+ |
+LL | let _: char = '\u{}';
+ | ^^^^ this escape must have at least 1 hex digit
+
+error[E0762]: unterminated character literal
+ --> $DIR/lex-bad-char-literals-7.rs:11:13
+ |
+LL | let _ = ' hello // here's a comment
+ | ^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0762`.
--- /dev/null
+fn main() {
+ 0o1.0; //~ ERROR: octal float literal is not supported
+ 0o2f32; //~ ERROR: octal float literal is not supported
+ 0o3.0f32; //~ ERROR: octal float literal is not supported
+ 0o4e4; //~ ERROR: octal float literal is not supported
+ 0o5.0e5; //~ ERROR: octal float literal is not supported
+ 0o6e6f32; //~ ERROR: octal float literal is not supported
+ 0o7.0e7f64; //~ ERROR: octal float literal is not supported
+ 0x8.0e+9; //~ ERROR: hexadecimal float literal is not supported
+ 0x9.0e-9; //~ ERROR: hexadecimal float literal is not supported
+ 0o; //~ ERROR: no valid digits
+ 1e+; //~ ERROR: expected at least one digit in exponent
+ 0x539.0; //~ ERROR: hexadecimal float literal is not supported
+ 9900000000000000000000000000999999999999999999999999999999;
+ //~^ ERROR: integer literal is too large
+ 9900000000000000000000000000999999999999999999999999999999;
+ //~^ ERROR: integer literal is too large
+ 0x; //~ ERROR: no valid digits
+ 0xu32; //~ ERROR: no valid digits
+ 0ou32; //~ ERROR: no valid digits
+ 0bu32; //~ ERROR: no valid digits
+ 0b; //~ ERROR: no valid digits
+ 0o123f64; //~ ERROR: octal float literal is not supported
+ 0o123.456; //~ ERROR: octal float literal is not supported
+ 0b101f64; //~ ERROR: binary float literal is not supported
+ 0b111.101; //~ ERROR: binary float literal is not supported
+}
--- /dev/null
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:2:5
+ |
+LL | 0o1.0;
+ | ^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:4:5
+ |
+LL | 0o3.0f32;
+ | ^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:5:5
+ |
+LL | 0o4e4;
+ | ^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:6:5
+ |
+LL | 0o5.0e5;
+ | ^^^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:7:5
+ |
+LL | 0o6e6f32;
+ | ^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:8:5
+ |
+LL | 0o7.0e7f64;
+ | ^^^^^^^
+
+error: hexadecimal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:9:5
+ |
+LL | 0x8.0e+9;
+ | ^^^^^^^^
+
+error: hexadecimal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:10:5
+ |
+LL | 0x9.0e-9;
+ | ^^^^^^^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:11:5
+ |
+LL | 0o;
+ | ^^
+
+error: expected at least one digit in exponent
+ --> $DIR/lex-bad-numeric-literals.rs:12:5
+ |
+LL | 1e+;
+ | ^^^
+
+error: hexadecimal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:13:5
+ |
+LL | 0x539.0;
+ | ^^^^^^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:18:5
+ |
+LL | 0x;
+ | ^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:19:5
+ |
+LL | 0xu32;
+ | ^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:20:5
+ |
+LL | 0ou32;
+ | ^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:21:5
+ |
+LL | 0bu32;
+ | ^^
+
+error[E0768]: no valid digits found for number
+ --> $DIR/lex-bad-numeric-literals.rs:22:5
+ |
+LL | 0b;
+ | ^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:24:5
+ |
+LL | 0o123.456;
+ | ^^^^^^^^^
+
+error: binary float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:26:5
+ |
+LL | 0b111.101;
+ | ^^^^^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:3:5
+ |
+LL | 0o2f32;
+ | ^^^^^^ not supported
+
+error: integer literal is too large
+ --> $DIR/lex-bad-numeric-literals.rs:14:5
+ |
+LL | 9900000000000000000000000000999999999999999999999999999999;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: integer literal is too large
+ --> $DIR/lex-bad-numeric-literals.rs:16:5
+ |
+LL | 9900000000000000000000000000999999999999999999999999999999;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: octal float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:23:5
+ |
+LL | 0o123f64;
+ | ^^^^^^^^ not supported
+
+error: binary float literal is not supported
+ --> $DIR/lex-bad-numeric-literals.rs:25:5
+ |
+LL | 0b101f64;
+ | ^^^^^^^^ not supported
+
+error: aborting due to 23 previous errors
+
+For more information about this error, try `rustc --explain E0768`.
--- /dev/null
+fn main() {
+ 0o18; //~ ERROR invalid digit for a base 8 literal
+ 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
+}
--- /dev/null
+error: invalid digit for a base 8 literal
+ --> $DIR/lex-bad-octal-literal.rs:2:8
+ |
+LL | 0o18;
+ | ^
+
+error: invalid digit for a base 8 literal
+ --> $DIR/lex-bad-octal-literal.rs:3:12
+ |
+LL | 0o1234_9_5670;
+ | ^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+● //~ ERROR: unknown start of token
+
+fn main() {}
--- /dev/null
+error: unknown start of token: \u{25cf}
+ --> $DIR/lex-bad-token.rs:1:1
+ |
+LL | ●
+ | ^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// ignore-tidy-cr
+
+// nondoc comment with bare CR: '\r'
+//// nondoc comment with bare CR: '\r'
+/* block nondoc comment with bare CR: '\r' */
+
+fn main() {
+}
--- /dev/null
+// ignore-tidy-cr
+
+/// doc comment with bare CR: '\r'
+pub fn foo() {}
+//~^^ ERROR: bare CR not allowed in doc-comment
+
+/** block doc comment with bare CR: '\r' */
+pub fn bar() {}
+//~^^ ERROR: bare CR not allowed in block doc-comment
+
+fn main() {
+ //! doc comment with bare CR: '\r'
+ //~^ ERROR: bare CR not allowed in doc-comment
+
+ /*! block doc comment with bare CR: '\r' */
+ //~^ ERROR: bare CR not allowed in block doc-comment
+
+ // the following string literal has a bare CR in it
+ let _s = "foo\rbar"; //~ ERROR: bare CR not allowed in string
+
+ // the following string literal has a bare CR in it
+ let _s = r"bar\rfoo"; //~ ERROR: bare CR not allowed in raw string
+
+ // the following string literal has a bare CR in it
+ let _s = "foo\\rbar"; //~ ERROR: unknown character escape: `\r`
+}
--- /dev/null
+error: bare CR not allowed in doc-comment
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:3:32
+ |
+LL | /// doc comment with bare CR: '\r'
+ | ^
+
+error: bare CR not allowed in block doc-comment
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:7:38
+ |
+LL | /** block doc comment with bare CR: '\r' */
+ | ^
+
+error: bare CR not allowed in doc-comment
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:12:36
+ |
+LL | //! doc comment with bare CR: '\r'
+ | ^
+
+error: bare CR not allowed in block doc-comment
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:15:42
+ |
+LL | /*! block doc comment with bare CR: '\r' */
+ | ^
+
+error: bare CR not allowed in string, use `\r` instead
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18
+ |
+LL | let _s = "foo\rbar";
+ | ^ help: escape the character: `\r`
+
+error: bare CR not allowed in raw string
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19
+ |
+LL | let _s = r"bar\rfoo";
+ | ^
+
+error: unknown character escape: `\r`
+ --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:25:19
+ |
+LL | let _s = "foo\\rbar";
+ | ^ unknown character escape
+ |
+ = help: this is an isolated carriage return; consider checking your editor and version control settings
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+\ //~ ERROR: unknown start of token: \
+
+fn main() {}
--- /dev/null
+error: unknown start of token: \
+ --> $DIR/lex-stray-backslash.rs:1:1
+ |
+LL | \
+ | ^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass\r
+// ignore-tidy-cr\r
+// ignore-tidy-cr (repeated again because of tidy bug)\r
+// license is ignored because tidy can't handle the CRLF here properly.\r
+\r
+// N.B., this file needs CRLF line endings. The .gitattributes file in\r
+// this directory should enforce it.\r
+\r
+// ignore-pretty issue #37195\r
+\r
+/// Doc comment that ends in CRLF\r
+pub fn foo() {}\r
+\r
+/** Block doc comment that\r
+ * contains CRLF characters\r
+ */\r
+pub fn bar() {}\r
+\r
+fn main() {\r
+ let s = "string\r
+literal";\r
+ assert_eq!(s, "string\nliteral");\r
+\r
+ let s = "literal with \\r
+ escaped newline";\r
+ assert_eq!(s, "literal with escaped newline");\r
+\r
+ let s = r"string\r
+literal";\r
+ assert_eq!(s, "string\nliteral");\r
+ let s = br"byte string\r
+literal";\r
+ assert_eq!(s, "byte string\nliteral".as_bytes());\r
+\r
+ // validate that our source file has CRLF endings\r
+ let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs");\r
+ assert!(source.contains("string\r\nliteral"));\r
+}\r
--- /dev/null
+// edition:2018
+// check-pass
+
+#![feature(unboxed_closures)]
+use std::future::Future;
+
+async fn wrapper<F>(f: F)
+where for<'a> F: FnOnce<(&'a mut i32,)>,
+ for<'a> <F as FnOnce<(&'a mut i32,)>>::Output: Future<Output=()> + 'a
+{
+ let mut i = 41;
+ f(&mut i).await;
+}
+
+async fn add_one(i: &mut i32) {
+ *i = *i + 1;
+}
+
+fn main() {}
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
--> $DIR/allowed-by-default-lint.rs:9:12
|
LL | fn foo(x: &Foo) {}
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected named lifetime parameter
|
= note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
+help: consider using the `'_` lifetime
+ |
+LL | fn foo(x: &Foo<'_>) {}
+ | ~~~~~~~
warning: 1 warning emitted
}
extern "C" {
- pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+ pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA<Assoc = u32>`
}
fn main() {}
-error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+error: `extern` block uses type `impl TraitA<Assoc = u32>`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-2.rs:36:25
|
LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
extern "C" {
pub fn a(_: A);
- //~^ ERROR `extern` block uses type `impl Fn<()>`, which is not FFI-safe
+ //~^ ERROR `extern` block uses type `impl Fn()`, which is not FFI-safe [improper_ctypes]
}
fn main() {}
-error: `extern` block uses type `impl Fn<()>`, which is not FFI-safe
+error: `extern` block uses type `impl Fn()`, which is not FFI-safe
--> $DIR/opaque-ty-ffi-unsafe.rs:11:17
|
LL | pub fn a(_: A);
// check-pass
#![feature(lint_reasons)]
-
#![warn(elided_lifetimes_in_paths,
//~^ NOTE the lint level is defined here
reason = "explicit anonymous lifetimes aid reasoning about ownership")]
impl fmt::Debug for CheaterDetectionMechanism {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
//~^ WARN hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
//~| NOTE explicit anonymous lifetimes aid
- //~| HELP indicate the anonymous lifetime
+ //~| HELP consider using the `'_` lifetime
fmt.debug_struct("CheaterDetectionMechanism").finish()
}
}
warning: hidden lifetime parameters in types are deprecated
- --> $DIR/reasons.rs:21:29
+ --> $DIR/reasons.rs:20:29
|
LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^^^^^ expected named lifetime parameter
|
= note: explicit anonymous lifetimes aid reasoning about ownership
note: the lint level is defined here
- --> $DIR/reasons.rs:5:9
+ --> $DIR/reasons.rs:4:9
|
LL | #![warn(elided_lifetimes_in_paths,
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+ |
+LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ | ~~~~~~~~~~~~~~~~~~
warning: variable `Social_exchange_psychology` should have a snake case name
--> $DIR/reasons.rs:30:9
= note: people shouldn't have to change their usual style habits
to contribute to our project
note: the lint level is defined here
- --> $DIR/reasons.rs:9:5
+ --> $DIR/reasons.rs:8:5
|
LL | nonstandard_style,
| ^^^^^^^^^^^^^^^^^
num == 3
}
+fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+//~^ ERROR: unused doc comment
+
fn main() {}
|
= help: use `//` for a plain comment
+error: unused doc comment
+ --> $DIR/unused-doc-comments-edge-cases.rs:29:27
+ |
+LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+ | ^^^^^^^^^^^^ - rustdoc does not generate documentation for generic parameters
+ |
+ = help: use `//` for a plain comment
+
error[E0308]: mismatched types
--> $DIR/unused-doc-comments-edge-cases.rs:14:9
|
LL | return true;
| ++++++ +
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
| ^ value borrowed here after move
LL | while true { while true { while true { x = y; x.clone(); } } }
| - value moved here, in previous iteration of loop
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 3 warnings emitted
LL |
LL | println!("{}", *x);
| ^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
| ------- value moved here
LL | println!("{}", message);
| ^^^^^^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{:?}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
// run-pass
-// compile-flags: -Z force-overflow-checks=off
+// compile-flags: -C overflow-checks=off
// Test that with MIR codegen, overflow checks can be
// turned off, even when they're from core::ops::*.
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:17:14
|
+LL | let mut length = 0;
+ | - expected due to this value
+...
LL | length = foo(&length);
| ^^^^^^^^^^^^ expected `u32`, found `i32`
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:23:20
|
+LL | let mut float_length = 0.0;
+ | --- expected due to this value
+...
LL | float_length = bar(&float_length);
| ^^^^^^^^^^^^^^^^^^ expected `f32`, found `f64`
LL | });
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
// run-pass
-// compile-flags: -Z force-overflow-checks=on
+// compile-flags: -C overflow-checks=on
// ignore-emscripten no threads support
use std::thread;
--- /dev/null
+// build-pass
+// ignore-pass
+// no-system-llvm
+// revisions: all inline merge1 merge2
+// compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
+//
+// Check that remarks can be enabled individually or with "all":
+//
+// [all] compile-flags: -Cremark=all
+// [inline] compile-flags: -Cremark=inline
+//
+// Check that values of -Cremark flag are accumulated:
+//
+// [merge1] compile-flags: -Cremark=all -Cremark=giraffe
+// [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
+//
+// error-pattern: inline: f not inlined into g
+// dont-check-compiler-stderr
+
+#[no_mangle]
+#[inline(never)]
+pub fn f() {
+}
+
+#[no_mangle]
+pub fn g() {
+ f();
+}
--> $DIR/output-type-mismatch.rs:5:31
|
LL | fn main() { let i: isize; i = f(); }
- | ^^^ expected `isize`, found `()`
+ | ----- ^^^ expected `isize`, found `()`
+ | |
+ | expected due to this type
error: aborting due to previous error
--- /dev/null
+struct NInts<const N: usize>([u8; N]);
+impl NInts<const N: usize> {} //~ ERROR unexpected `const` parameter declaration
+
+fn main() {
+ let _: () = 42; //~ ERROR mismatched types
+}
+
+fn banana(a: <T<const N: usize>>::BAR) {}
+//~^ ERROR unexpected `const` parameter declaration
+//~| ERROR cannot find type `T` in this scope
+fn chaenomeles() {
+ path::path::Struct::<const N: usize>()
+ //~^ ERROR unexpected `const` parameter declaration
+ //~| ERROR failed to resolve: use of undeclared crate or module `path`
+}
--- /dev/null
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:2:12
+ |
+LL | impl NInts<const N: usize> {}
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+ |
+help: `const` parameters must be declared for the `impl`
+ |
+LL | impl<const N: usize> NInts<N> {}
+ | ++++++++++++++++ ~
+
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:8:17
+ |
+LL | fn banana(a: <T<const N: usize>>::BAR) {}
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:12:26
+ |
+LL | path::path::Struct::<const N: usize>()
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+
+error[E0433]: failed to resolve: use of undeclared crate or module `path`
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:12:5
+ |
+LL | path::path::Struct::<const N: usize>()
+ | ^^^^ use of undeclared crate or module `path`
+
+error[E0412]: cannot find type `T` in this scope
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:8:15
+ |
+LL | fn banana(a: <T<const N: usize>>::BAR) {}
+ | ^ not found in this scope
+
+error[E0308]: mismatched types
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:5:17
+ |
+LL | let _: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0412, E0433.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+struct ABig👩👩👧👧Family; //~ ERROR identifiers cannot contain emoji
+struct 👀; //~ ERROR identifiers cannot contain emoji
+impl 👀 {
+ fn full_of_✨() -> 👀 { //~ ERROR identifiers cannot contain emoji
+ 👀
+ }
+}
+fn i_like_to_😅_a_lot() -> 👀 { //~ ERROR identifiers cannot contain emoji
+ 👀::full_of✨() //~ ERROR no function or associated item named `full_of✨` found for struct `👀`
+ //~^ ERROR identifiers cannot contain emoji
+}
+fn main() {
+ let _ = i_like_to_😄_a_lot() ➖ 4; //~ ERROR cannot find function `i_like_to_😄_a_lot` in this scope
+ //~^ ERROR identifiers cannot contain emoji
+ //~| ERROR unknown start of token: \u{2796}
+}
--- /dev/null
+error: unknown start of token: \u{2796}
+ --> $DIR/emoji-identifiers.rs:13:33
+ |
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^
+ |
+help: Unicode character '➖' (Heavy Minus Sign) looks like '-' (Minus/Hyphen), but it is not
+ |
+LL | let _ = i_like_to_😄_a_lot() - 4;
+ | ~
+
+error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
+ --> $DIR/emoji-identifiers.rs:13:13
+ |
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ----------------------------- similarly named function `i_like_to_😅_a_lot` defined here
+...
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_😅_a_lot`
+
+error: identifiers cannot contain emoji: `ABig👩👩👧👧Family`
+ --> $DIR/emoji-identifiers.rs:1:8
+ |
+LL | struct ABig👩👩👧👧Family;
+ | ^^^^^^^^^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `👀`
+ --> $DIR/emoji-identifiers.rs:2:8
+ |
+LL | struct 👀;
+ | ^^
+LL | impl 👀 {
+ | ^^
+LL | fn full_of_✨() -> 👀 {
+ | ^^
+LL | 👀
+ | ^^
+...
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ^^
+LL | 👀::full_of✨()
+ | ^^
+
+error: identifiers cannot contain emoji: `full_of_✨`
+ --> $DIR/emoji-identifiers.rs:4:8
+ |
+LL | fn full_of_✨() -> 👀 {
+ | ^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `i_like_to_😅_a_lot`
+ --> $DIR/emoji-identifiers.rs:8:4
+ |
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `full_of✨`
+ --> $DIR/emoji-identifiers.rs:9:8
+ |
+LL | 👀::full_of✨()
+ | ^^^^^^^^^
+
+error: identifiers cannot contain emoji: `i_like_to_😄_a_lot`
+ --> $DIR/emoji-identifiers.rs:13:13
+ |
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no function or associated item named `full_of✨` found for struct `👀` in the current scope
+ --> $DIR/emoji-identifiers.rs:9:8
+ |
+LL | struct 👀;
+ | ---------- function or associated item `full_of✨` not found for this
+...
+LL | 👀::full_of✨()
+ | ^^^^^^^^^
+ | |
+ | function or associated item not found in `👀`
+ | help: there is an associated function with a similar name: `full_of_✨`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
--- /dev/null
+// Regression test for issue #91421.
+
+fn main() {
+ let value = if true && {
+ //~^ ERROR: this `if` expression has a condition, but no block
+ //~| HELP: maybe you forgot the right operand of the condition?
+ 3
+ //~^ ERROR: mismatched types [E0308]
+ } else { 4 };
+}
--- /dev/null
+error: this `if` expression has a condition, but no block
+ --> $DIR/issue-91421.rs:4:17
+ |
+LL | let value = if true && {
+ | ^^
+ |
+help: maybe you forgot the right operand of the condition?
+ --> $DIR/issue-91421.rs:4:25
+ |
+LL | let value = if true && {
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91421.rs:7:9
+ |
+LL | 3
+ | ^ expected `bool`, found integer
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
// Tests that a suggestion is issued if the user wrote a colon instead of
// a path separator in a match arm.
-enum Foo {
- Bar,
- Baz,
+mod qux {
+ pub enum Foo {
+ Bar,
+ Baz,
+ }
}
+use qux::Foo;
+
fn f() -> Foo { Foo::Bar }
fn g1() {
_ => {}
}
match f() {
- Foo::Bar:Baz => {}
+ qux::Foo:Bar => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo:Bar::Baz => {}
+ qux:Foo::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo: Bar::Baz if true => {}
+ qux: Foo::Baz if true => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
- if let Bar:Baz = f() {
+ if let Foo:Bar = f() {
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
}
fn g1_neg() {
match f() {
- ref Foo: Bar::Baz => {}
+ ref qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
fn g2_neg() {
match f() {
- mut Foo: Bar::Baz => {}
+ mut qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
Foo:Bar::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
+ //~| ERROR: failed to resolve: `Bar` is a variant, not a module
+ }
+ match myfoo {
+ Foo::Bar => {}
+ Foo:Bar => {}
+ //~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
}
}
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:13:12
+ --> $DIR/issue-87086-colon-path-sep.rs:17:12
|
LL | Foo:Bar => {}
| ^
| help: maybe write a path separator here: `::`
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:19:17
+ --> $DIR/issue-87086-colon-path-sep.rs:23:17
|
-LL | Foo::Bar:Baz => {}
+LL | qux::Foo:Bar => {}
| ^
| |
| expected one of 8 possible tokens
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:25:12
+ --> $DIR/issue-87086-colon-path-sep.rs:29:12
|
-LL | Foo:Bar::Baz => {}
+LL | qux:Foo::Baz => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:31:12
+ --> $DIR/issue-87086-colon-path-sep.rs:35:12
|
-LL | Foo: Bar::Baz if true => {}
+LL | qux: Foo::Baz if true => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:36:15
+ --> $DIR/issue-87086-colon-path-sep.rs:40:15
|
-LL | if let Bar:Baz = f() {
+LL | if let Foo:Bar = f() {
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:44:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:48:16
|
-LL | ref Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | ref qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:52:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:57:16
|
-LL | mut Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | mut qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:62:12
+ --> $DIR/issue-87086-colon-path-sep.rs:68:12
|
LL | Foo:Bar::Baz => {}
| ^
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: aborting due to 8 previous errors
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:75:12
+ |
+LL | Foo:Bar => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
+
+error[E0433]: failed to resolve: `Bar` is a variant, not a module
+ --> $DIR/issue-87086-colon-path-sep.rs:68:13
+ |
+LL | Foo:Bar::Baz => {}
+ | ^^^ `Bar` is a variant, not a module
+
+error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0433`.
+++ /dev/null
-fn main() {
- 0b121; //~ ERROR invalid digit for a base 2 literal
- 0b10_10301; //~ ERROR invalid digit for a base 2 literal
- 0b30; //~ ERROR invalid digit for a base 2 literal
- 0b41; //~ ERROR invalid digit for a base 2 literal
- 0b5; //~ ERROR invalid digit for a base 2 literal
- 0b6; //~ ERROR invalid digit for a base 2 literal
- 0b7; //~ ERROR invalid digit for a base 2 literal
- 0b8; //~ ERROR invalid digit for a base 2 literal
- 0b9; //~ ERROR invalid digit for a base 2 literal
-}
+++ /dev/null
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:2:8
- |
-LL | 0b121;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:3:12
- |
-LL | 0b10_10301;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:4:7
- |
-LL | 0b30;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:5:7
- |
-LL | 0b41;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:6:7
- |
-LL | 0b5;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:7:7
- |
-LL | 0b6;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:8:7
- |
-LL | 0b7;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:9:7
- |
-LL | 0b8;
- | ^
-
-error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:10:7
- |
-LL | 0b9;
- | ^
-
-error: aborting due to 9 previous errors
-
+++ /dev/null
-static c3: char =
- '\x1' //~ ERROR: numeric character escape is too short
-;
-
-static s3: &'static str =
- "\x1" //~ ERROR: numeric character escape is too short
-;
-
-static c: char =
- '\●' //~ ERROR: unknown character escape
-;
-
-static s: &'static str =
- "\●" //~ ERROR: unknown character escape
-;
-
-fn main() {}
+++ /dev/null
-error: numeric character escape is too short
- --> $DIR/lex-bad-char-literals-1.rs:2:6
- |
-LL | '\x1'
- | ^^^
-
-error: numeric character escape is too short
- --> $DIR/lex-bad-char-literals-1.rs:6:6
- |
-LL | "\x1"
- | ^^^
-
-error: unknown character escape: `\u{25cf}`
- --> $DIR/lex-bad-char-literals-1.rs:10:7
- |
-LL | '\●'
- | ^ unknown character escape
- |
- = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
-
-error: unknown character escape: `\u{25cf}`
- --> $DIR/lex-bad-char-literals-1.rs:14:7
- |
-LL | "\●"
- | ^ unknown character escape
- |
- = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
-
-error: aborting due to 4 previous errors
-
+++ /dev/null
-// This test needs to the last one appearing in this file as it kills the parser
-static c: char =
- 'nope' //~ ERROR: character literal may only contain one codepoint
-;
-
-fn main() {}
+++ /dev/null
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-2.rs:3:5
- |
-LL | 'nope'
- | ^^^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | "nope"
- | ~~~~~~
-
-error: aborting due to previous error
-
+++ /dev/null
-static c: char = '●●';
-//~^ ERROR: character literal may only contain one codepoint
-
-fn main() {
- let ch: &str = '●●';
- //~^ ERROR: character literal may only contain one codepoint
-}
+++ /dev/null
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-3.rs:1:18
- |
-LL | static c: char = '●●';
- | ^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | static c: char = "●●";
- | ~~~~
-
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-3.rs:5:20
- |
-LL | let ch: &str = '●●';
- | ^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | let ch: &str = "●●";
- | ~~~~
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-//
-// This test needs to the last one appearing in this file as it kills the parser
-static c: char =
- '● //~ ERROR: unterminated character literal
-;
+++ /dev/null
-error[E0762]: unterminated character literal
- --> $DIR/lex-bad-char-literals-4.rs:4:5
- |
-LL | '●
- | ^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0762`.
+++ /dev/null
-static c: char = '\x10\x10';
-//~^ ERROR: character literal may only contain one codepoint
-
-fn main() {
- let ch: &str = '\x10\x10';
- //~^ ERROR: character literal may only contain one codepoint
-}
+++ /dev/null
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-5.rs:1:18
- |
-LL | static c: char = '\x10\x10';
- | ^^^^^^^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | static c: char = "\x10\x10";
- | ~~~~~~~~~~
-
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-5.rs:5:20
- |
-LL | let ch: &str = '\x10\x10';
- | ^^^^^^^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | let ch: &str = "\x10\x10";
- | ~~~~~~~~~~
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-fn main() {
- let x: &str = 'ab';
- //~^ ERROR: character literal may only contain one codepoint
- let y: char = 'cd';
- //~^ ERROR: character literal may only contain one codepoint
- let z = 'ef';
- //~^ ERROR: character literal may only contain one codepoint
-
- if x == y {}
- //~^ ERROR: can't compare `&str` with `char`
- if y == z {} // no error here
- if x == z {}
- //~^ ERROR: can't compare `&str` with `char`
-
- let a: usize = "";
- //~^ ERROR: mismatched types
-}
+++ /dev/null
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-6.rs:2:19
- |
-LL | let x: &str = 'ab';
- | ^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | let x: &str = "ab";
- | ~~~~
-
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-6.rs:4:19
- |
-LL | let y: char = 'cd';
- | ^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | let y: char = "cd";
- | ~~~~
-
-error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-6.rs:6:13
- |
-LL | let z = 'ef';
- | ^^^^
- |
-help: if you meant to write a `str` literal, use double quotes
- |
-LL | let z = "ef";
- | ~~~~
-
-error[E0277]: can't compare `&str` with `char`
- --> $DIR/lex-bad-char-literals-6.rs:9:10
- |
-LL | if x == y {}
- | ^^ no implementation for `&str == char`
- |
- = help: the trait `PartialEq<char>` is not implemented for `&str`
-
-error[E0308]: mismatched types
- --> $DIR/lex-bad-char-literals-6.rs:15:20
- |
-LL | let a: usize = "";
- | ----- ^^ expected `usize`, found `&str`
- | |
- | expected due to this
-
-error[E0277]: can't compare `&str` with `char`
- --> $DIR/lex-bad-char-literals-6.rs:12:10
- |
-LL | if x == z {}
- | ^^ no implementation for `&str == char`
- |
- = help: the trait `PartialEq<char>` is not implemented for `&str`
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-fn main() {
- let _: char = '';
- //~^ ERROR: empty character literal
- let _: char = '\u{}';
- //~^ ERROR: empty unicode escape
-
- // Next two are OK, but may befool error recovery
- let _ = '/';
- let _ = b'/';
-
- let _ = ' hello // here's a comment
- //~^ ERROR: unterminated character literal
-}
+++ /dev/null
-error: empty character literal
- --> $DIR/lex-bad-char-literals-7.rs:2:20
- |
-LL | let _: char = '';
- | ^ empty character literal
-
-error: empty unicode escape
- --> $DIR/lex-bad-char-literals-7.rs:4:20
- |
-LL | let _: char = '\u{}';
- | ^^^^ this escape must have at least 1 hex digit
-
-error[E0762]: unterminated character literal
- --> $DIR/lex-bad-char-literals-7.rs:11:13
- |
-LL | let _ = ' hello // here's a comment
- | ^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0762`.
+++ /dev/null
-fn main() {
- 0o1.0; //~ ERROR: octal float literal is not supported
- 0o2f32; //~ ERROR: octal float literal is not supported
- 0o3.0f32; //~ ERROR: octal float literal is not supported
- 0o4e4; //~ ERROR: octal float literal is not supported
- 0o5.0e5; //~ ERROR: octal float literal is not supported
- 0o6e6f32; //~ ERROR: octal float literal is not supported
- 0o7.0e7f64; //~ ERROR: octal float literal is not supported
- 0x8.0e+9; //~ ERROR: hexadecimal float literal is not supported
- 0x9.0e-9; //~ ERROR: hexadecimal float literal is not supported
- 0o; //~ ERROR: no valid digits
- 1e+; //~ ERROR: expected at least one digit in exponent
- 0x539.0; //~ ERROR: hexadecimal float literal is not supported
- 9900000000000000000000000000999999999999999999999999999999;
- //~^ ERROR: integer literal is too large
- 9900000000000000000000000000999999999999999999999999999999;
- //~^ ERROR: integer literal is too large
- 0x; //~ ERROR: no valid digits
- 0xu32; //~ ERROR: no valid digits
- 0ou32; //~ ERROR: no valid digits
- 0bu32; //~ ERROR: no valid digits
- 0b; //~ ERROR: no valid digits
- 0o123f64; //~ ERROR: octal float literal is not supported
- 0o123.456; //~ ERROR: octal float literal is not supported
- 0b101f64; //~ ERROR: binary float literal is not supported
- 0b111.101; //~ ERROR: binary float literal is not supported
-}
+++ /dev/null
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:2:5
- |
-LL | 0o1.0;
- | ^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:4:5
- |
-LL | 0o3.0f32;
- | ^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:5:5
- |
-LL | 0o4e4;
- | ^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:6:5
- |
-LL | 0o5.0e5;
- | ^^^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:7:5
- |
-LL | 0o6e6f32;
- | ^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:8:5
- |
-LL | 0o7.0e7f64;
- | ^^^^^^^
-
-error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:9:5
- |
-LL | 0x8.0e+9;
- | ^^^^^^^^
-
-error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:10:5
- |
-LL | 0x9.0e-9;
- | ^^^^^^^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:11:5
- |
-LL | 0o;
- | ^^
-
-error: expected at least one digit in exponent
- --> $DIR/lex-bad-numeric-literals.rs:12:5
- |
-LL | 1e+;
- | ^^^
-
-error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:13:5
- |
-LL | 0x539.0;
- | ^^^^^^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:18:5
- |
-LL | 0x;
- | ^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:19:5
- |
-LL | 0xu32;
- | ^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:20:5
- |
-LL | 0ou32;
- | ^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:21:5
- |
-LL | 0bu32;
- | ^^
-
-error[E0768]: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:22:5
- |
-LL | 0b;
- | ^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:24:5
- |
-LL | 0o123.456;
- | ^^^^^^^^^
-
-error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:26:5
- |
-LL | 0b111.101;
- | ^^^^^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:3:5
- |
-LL | 0o2f32;
- | ^^^^^^ not supported
-
-error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:14:5
- |
-LL | 9900000000000000000000000000999999999999999999999999999999;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:16:5
- |
-LL | 9900000000000000000000000000999999999999999999999999999999;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:23:5
- |
-LL | 0o123f64;
- | ^^^^^^^^ not supported
-
-error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:25:5
- |
-LL | 0b101f64;
- | ^^^^^^^^ not supported
-
-error: aborting due to 23 previous errors
-
-For more information about this error, try `rustc --explain E0768`.
+++ /dev/null
-fn main() {
- 0o18; //~ ERROR invalid digit for a base 8 literal
- 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
-}
+++ /dev/null
-error: invalid digit for a base 8 literal
- --> $DIR/lex-bad-octal-literal.rs:2:8
- |
-LL | 0o18;
- | ^
-
-error: invalid digit for a base 8 literal
- --> $DIR/lex-bad-octal-literal.rs:3:12
- |
-LL | 0o1234_9_5670;
- | ^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-● //~ ERROR: unknown start of token
-
-fn main() {}
+++ /dev/null
-error: unknown start of token: \u{25cf}
- --> $DIR/lex-bad-token.rs:1:1
- |
-LL | ●
- | ^
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// ignore-tidy-cr
-
-// nondoc comment with bare CR: '\r'
-//// nondoc comment with bare CR: '\r'
-/* block nondoc comment with bare CR: '\r' */
-
-fn main() {
-}
+++ /dev/null
-// ignore-tidy-cr
-
-/// doc comment with bare CR: '\r'
-pub fn foo() {}
-//~^^ ERROR: bare CR not allowed in doc-comment
-
-/** block doc comment with bare CR: '\r' */
-pub fn bar() {}
-//~^^ ERROR: bare CR not allowed in block doc-comment
-
-fn main() {
- //! doc comment with bare CR: '\r'
- //~^ ERROR: bare CR not allowed in doc-comment
-
- /*! block doc comment with bare CR: '\r' */
- //~^ ERROR: bare CR not allowed in block doc-comment
-
- // the following string literal has a bare CR in it
- let _s = "foo\rbar"; //~ ERROR: bare CR not allowed in string
-
- // the following string literal has a bare CR in it
- let _s = r"bar\rfoo"; //~ ERROR: bare CR not allowed in raw string
-
- // the following string literal has a bare CR in it
- let _s = "foo\\rbar"; //~ ERROR: unknown character escape: `\r`
-}
+++ /dev/null
-error: bare CR not allowed in doc-comment
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:3:32
- |
-LL | /// doc comment with bare CR: '\r'
- | ^
-
-error: bare CR not allowed in block doc-comment
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:7:38
- |
-LL | /** block doc comment with bare CR: '\r' */
- | ^
-
-error: bare CR not allowed in doc-comment
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:12:36
- |
-LL | //! doc comment with bare CR: '\r'
- | ^
-
-error: bare CR not allowed in block doc-comment
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:15:42
- |
-LL | /*! block doc comment with bare CR: '\r' */
- | ^
-
-error: bare CR not allowed in string, use `\r` instead
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18
- |
-LL | let _s = "foo\rbar";
- | ^ help: escape the character: `\r`
-
-error: bare CR not allowed in raw string
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19
- |
-LL | let _s = r"bar\rfoo";
- | ^
-
-error: unknown character escape: `\r`
- --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:25:19
- |
-LL | let _s = "foo\\rbar";
- | ^ unknown character escape
- |
- = help: this is an isolated carriage return; consider checking your editor and version control settings
-
-error: aborting due to 7 previous errors
-
+++ /dev/null
-\ //~ ERROR: unknown start of token: \
-
-fn main() {}
+++ /dev/null
-error: unknown start of token: \
- --> $DIR/lex-stray-backslash.rs:1:1
- |
-LL | \
- | ^
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass\r
-// ignore-tidy-cr\r
-// ignore-tidy-cr (repeated again because of tidy bug)\r
-// license is ignored because tidy can't handle the CRLF here properly.\r
-\r
-// N.B., this file needs CRLF line endings. The .gitattributes file in\r
-// this directory should enforce it.\r
-\r
-// ignore-pretty issue #37195\r
-\r
-/// Doc comment that ends in CRLF\r
-pub fn foo() {}\r
-\r
-/** Block doc comment that\r
- * contains CRLF characters\r
- */\r
-pub fn bar() {}\r
-\r
-fn main() {\r
- let s = "string\r
-literal";\r
- assert_eq!(s, "string\nliteral");\r
-\r
- let s = "literal with \\r
- escaped newline";\r
- assert_eq!(s, "literal with escaped newline");\r
-\r
- let s = r"string\r
-literal";\r
- assert_eq!(s, "string\nliteral");\r
- let s = br"byte string\r
-literal";\r
- assert_eq!(s, "byte string\nliteral".as_bytes());\r
-\r
- // validate that our source file has CRLF endings\r
- let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs");\r
- assert!(source.contains("string\r\nliteral"));\r
-}\r
LL | const { || {} } => {},
| ^^^^^^^^^^^^^^^
-error: `impl Future` cannot be used in patterns
+error: `impl Future<Output = [async output]>` cannot be used in patterns
--> $DIR/non-structural-match-types.rs:12:9
|
LL | const { async {} } => {},
--- /dev/null
+// check-pass: this used to be a stack overflow because of recursion in `usefulness.rs`
+
+macro_rules! long_tuple_arg {
+ ([$($t:tt)*]#$($h:tt)*) => {
+ long_tuple_arg!{[$($t)*$($t)*]$($h)*}
+ };
+ ([$([$t:tt $y:tt])*]) => {
+ pub fn _f(($($t,)*): ($($y,)*)) {}
+ }
+}
+
+long_tuple_arg!{[[_ u8]]########## ###}
+
+fn main() {}
--- /dev/null
+// Multiple custom crate-level attributes, both inert and active.
+
+// check-pass
+// aux-crate:test_macros=test-macros.rs
+
+#![feature(custom_inner_attributes)]
+#![feature(prelude_import)]
+
+#![test_macros::identity_attr]
+#![rustfmt::skip]
+#![test_macros::identity_attr]
+#![rustfmt::skip]
+
+fn main() {}
-// edition:2018
-// aux-crate:issue_59191=issue-59191.rs
// Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely.
// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
+
+// edition:2018
+// aux-crate:issue_59191=issue-59191.rs
+// error-pattern: requires `sized` lang_item
+
#![feature(custom_inner_attributes)]
#![issue_59191::no_main]
-//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
+#![issue_59191::no_main]
-error: expected crate top-level item to be a module after macro expansion, found a function
- --> $DIR/issue-59191-replace-root-with-fn.rs:6:1
- |
-LL | #![issue_59191::no_main]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+error: requires `sized` lang_item
error: aborting due to previous error
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
// 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
+
#![allow(dead_code)]
pub trait TheTrait {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
- |
-LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'b &'a usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
- |
-LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let y: Paramd<'a> = Paramd { x: a };
-LL | let z: Option<&'b Paramd<'a>> = None;
- | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
- |
-LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'a &'b usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 3 previous errors
-
error[E0491]: in type `&'b &'a usize`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | let z: Option<&'b &'a usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:10:14
+ --> $DIR/regions-free-region-ordering-caller.rs:15:14
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:10:10
+ --> $DIR/regions-free-region-ordering-caller.rs:15:10
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error[E0491]: in type `&'b Paramd<'a>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | let z: Option<&'b Paramd<'a>> = None;
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:15:14
+ --> $DIR/regions-free-region-ordering-caller.rs:20:14
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:15:10
+ --> $DIR/regions-free-region-ordering-caller.rs:20:10
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | let z: Option<&'a &'b usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:21:10
+ --> $DIR/regions-free-region-ordering-caller.rs:26:10
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:21:14
+ --> $DIR/regions-free-region-ordering-caller.rs:26:14
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
// 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
+
struct Paramd<'a> { x: &'a usize }
fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
- |
-LL | fn with_assoc_sub<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 2 previous errors
-
error[E0491]: in type `&'a WithHrAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error[E0491]: in type `&'a WithHrAssocSub<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:19
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:22
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | fn with_assoc_sub<'a,'b>() {
| -- -- lifetime `'b` defined here
// 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
+
#![allow(dead_code)]
pub trait TheTrait<'b> {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:15
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:18
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
// 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
+
#![allow(dead_code)]
pub trait TheTrait {
pub enum NonExhaustiveSingleVariant {
A(bool),
}
+
+#[repr(u8)]
+pub enum FieldLessWithNonExhaustiveVariant {
+ A,
+ B,
+ #[non_exhaustive]
+ C,
+}
+
+impl Default for FieldLessWithNonExhaustiveVariant {
+ fn default() -> Self { Self::A }
+}
--- /dev/null
+// aux-build:enums.rs
+// run-pass
+
+extern crate enums;
+
+use enums::FieldLessWithNonExhaustiveVariant;
+
+fn main() {
+ let e = FieldLessWithNonExhaustiveVariant::default();
+ // FIXME: https://github.com/rust-lang/rust/issues/91161
+ // This `as` cast *should* be an error, since it would fail
+ // if the non-exhaustive variant got fields. But today it
+ // doesn't. The fix for that will update this test to
+ // show an error (and not be run-pass any more).
+ let d = e as u8;
+ assert_eq!(d, 0);
+}
--- /dev/null
+// 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 {
+ match res {
+ Ok(t) => Some(t),
+ Err(_e) => None,
+ }
+}
+
+pub struct Foo<T>(T);
+
+const fn baz<T: ~const Drop, E: ~const Drop>(res: Result<Foo<T>, Foo<E>>) -> Option<Foo<T>> {
+ foo(res)
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(staged_api)]
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_t_try)]
+#![feature(const_try)]
+#![feature(try_trait_v2)]
+
+#![stable(feature = "foo", since = "1.0")]
+
+use std::ops::{ControlFlow, FromResidual, Try};
+
+#[stable(feature = "foo", since = "1.0")]
+pub struct T;
+
+#[stable(feature = "foo", since = "1.0")]
+#[rustc_const_unstable(feature = "const_t_try", issue = "none")]
+impl const Try for T {
+ type Output = T;
+ type Residual = T;
+
+ fn from_output(t: T) -> T {
+ t
+ }
+
+ fn branch(self) -> ControlFlow<T, T> {
+ ControlFlow::Continue(self)
+ }
+}
+
+#[stable(feature = "foo", since = "1.0")]
+#[rustc_const_unstable(feature = "const_t_try", issue = "none")]
+impl const FromResidual for T {
+ fn from_residual(t: T) -> T {
+ t
+ }
+}
+
+#[stable(feature = "foo", since = "1.0")]
+pub trait Tr {
+ #[default_method_body_is_const]
+ #[stable(feature = "foo", since = "1.0")]
+ fn bar() -> T {
+ T?
+ // Should be allowed.
+ // Must enable unstable features to call this trait fn in const contexts.
+ }
+}
+
+fn main() {}
-error[E0277]: `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- --> $DIR/rfc1623.rs:21:1
- |
-LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL | | foo: &Foo { bools: &[false, true] },
-LL | | bar: &Bar { bools: &[true, true] },
-LL | | f: &id,
-LL | |
-LL | | };
- | |__^ `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- |
- = help: within `&SomeStruct`, the trait `Sync` is not implemented for `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
- = note: required because it appears within the type `&dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-note: required because it appears within the type `SomeStruct`
- --> $DIR/rfc1623.rs:11:8
- |
-LL | struct SomeStruct<'x, 'y, 'z: 'x> {
- | ^^^^^^^^^^
- = note: required because it appears within the type `&SomeStruct`
- = note: shared static variables must have a type that implements `Sync`
-
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
}
+// Without this, the wf-check will fail early so we'll never see the
+// error in SOME_STRUCT's body.
+unsafe impl<'x, 'y, 'z: 'x> Sync for SomeStruct<'x, 'y, 'z> {}
+
fn id<T>(t: T) -> T {
t
}
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:24:8
+ --> $DIR/rfc1623.rs:28:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
// edition:2018
// compile-flags:--extern foo --extern bar
+use bar::foo; //~ ERROR can't find crate for `bar`
use foo::bar; //~ ERROR can't find crate for `foo`
-use bar::foo;
+//~^^ ERROR unresolved imports `bar::foo`, `foo::bar`
fn main() {}
-error[E0463]: can't find crate for `foo`
+error[E0463]: can't find crate for `bar`
--> $DIR/deadlock.rs:4:5
|
+LL | use bar::foo;
+ | ^^^ can't find crate
+
+error[E0463]: can't find crate for `foo`
+ --> $DIR/deadlock.rs:5:5
+ |
LL | use foo::bar;
| ^^^ can't find crate
-error: aborting due to previous error
+error[E0432]: unresolved imports `bar::foo`, `foo::bar`
+ --> $DIR/deadlock.rs:4:5
+ |
+LL | use bar::foo;
+ | ^^^^^^^^
+LL | use foo::bar;
+ | ^^^^^^^^
+
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0463`.
+Some errors have detailed explanations: E0432, E0463.
+For more information about an error, try `rustc --explain E0432`.
error[E0308]: mismatched types
--> $DIR/static-mut-bad-types.rs:5:13
|
+LL | static mut a: isize = 3;
+ | ----- expected due to this type
+...
LL | a = true;
| ^^^^ expected `isize`, found `bool`
| required by a bound introduced by this call
|
= help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
+ = note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
| required by a bound introduced by this call
|
= help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+ = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
| ------------------------------- the found opaque type
|
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
- found opaque type `impl Future`
+ found opaque type `impl Future<Output = [async output]>`
help: you need to pin and box this expression
|
LL ~ Box::pin(async {
-error[E0277]: the trait bound `fn() -> impl T {foo}: T` is not satisfied
+error[E0277]: the trait bound `fn() -> impl T<O = ()> {foo}: T` is not satisfied
--> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9
|
LL | fn foo() -> impl T<O=()> { S }
| --- consider calling this function
...
LL | bar(foo);
- | --- ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}`
+ | --- ^^^ the trait `T` is not implemented for `fn() -> impl T<O = ()> {foo}`
| |
| required by a bound introduced by this call
|
|
LL | if 3 = foo {}
| ^^^^^^^ expected `bool`, found `()`
- |
-help: you might have meant to use pattern matching
- |
-LL | if let 3 = foo {}
- | +++
error[E0070]: invalid left-hand side of assignment
--> $DIR/if-let-typo.rs:10:16
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:2:11
|
+LL | fn suggestion(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = None;
| ^^^^ expected mutable reference, found enum `Option`
|
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:6:11
|
+LL | fn no_suggestion(opt: &mut Result<String, ()>) {
+ | ----------------------- expected due to this parameter type
LL | opt = None
| ^^^^ expected mutable reference, found enum `Option`
|
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:10:11
|
+LL | fn suggestion2(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = Some(String::new())
| ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `Option`
|
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:14:11
|
+LL | fn no_suggestion2(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = Some(42)
| ^^^^^^^^ expected mutable reference, found enum `Option`
|
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:changing-crates-a1.rs
// aux-build:changing-crates-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/changing-crates.rs:10:1
+ --> $DIR/changing-crates.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-lit.rs:10:1
+ --> $DIR/svh-change-lit.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-significant-cfg.rs:10:1
+ --> $DIR/svh-change-significant-cfg.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-trait-bound.rs:10:1
+ --> $DIR/svh-change-trait-bound.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-arg.rs:10:1
+ --> $DIR/svh-change-type-arg.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-ret.rs:10:1
+ --> $DIR/svh-change-type-ret.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-static.rs:10:1
+ --> $DIR/svh-change-type-static.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-uta-base.rs
// aux-build:svh-utb.rs
error[E0460]: found possibly newer version of crate `uta` which `utb` depends on
- --> $DIR/svh-use-trait.rs:15:1
+ --> $DIR/svh-use-trait.rs:13:1
|
LL | extern crate utb;
| ^^^^^^^^^^^^^^^^^
--- /dev/null
+// revisions: with_clause without_clause
+// Tests that `EvaluatedToOkModuloRegions` from a projection sub-obligation
+// is correctly propagated
+
+#![feature(rustc_attrs)]
+
+trait MyTrait {
+ type Assoc;
+}
+
+struct MyStruct;
+
+impl MyTrait for MyStruct {
+ // Evaluating this projection will result in `EvaluatedToOkModuloRegions`
+ // (when `with_clause` is enabled)
+ type Assoc = <Bar as MyTrait>::Assoc;
+}
+
+struct Bar;
+
+// The `where` clause on this impl will cause us to produce `EvaluatedToOkModuloRegions`
+// when evaluating a projection involving this impl
+#[cfg(with_clause)]
+impl MyTrait for Bar where for<'b> &'b (): 'b {
+ type Assoc = bool;
+}
+
+// This impl tests that the `EvaluatedToOkModuoRegions` result that we get
+// is really due to the `where` clause on the `with_clause` impl
+#[cfg(without_clause)]
+impl MyTrait for Bar {
+ type Assoc = bool;
+}
+
+// The implementation of `#[rustc_evaluate_where_clauses]` doesn't perform
+// normalization, so we need to place the projection predicate behind a normal
+// trait predicate
+struct Helper {}
+trait HelperTrait {}
+impl HelperTrait for Helper where <MyStruct as MyTrait>::Assoc: Sized {}
+
+// Evaluating this 'where' clause will (recursively) end up evaluating
+// `for<'b> &'b (): 'b`, which will produce `EvaluatedToOkModuloRegions`
+#[rustc_evaluate_where_clauses]
+fn test(val: MyStruct) where Helper: HelperTrait {
+ panic!()
+}
+
+fn foo(val: MyStruct) {
+ test(val);
+ //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+}
+
+fn main() {}
--- /dev/null
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ --> $DIR/project-modulo-regions.rs:50:5
+ |
+LL | fn test(val: MyStruct) where Helper: HelperTrait {
+ | ----------- predicate
+...
+LL | test(val);
+ | ^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ --> $DIR/project-modulo-regions.rs:50:5
+ |
+LL | fn test(val: MyStruct) where Helper: HelperTrait {
+ | ----------- predicate
+...
+LL | test(val);
+ | ^^^^
+
+error: aborting due to previous error
+
LL | };
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-maybe-bad-lifetime.rs:40:9
LL | type Foo = impl Debug;
| ---------- the expected opaque type
...
+LL | fn foo1(mut x: Foo) {
+ | --- expected due to this parameter type
LL | x = 22_u32;
| ^^^^^^ expected opaque type, found `u32`
|
use std::future::Future;
type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future as Future>::Output == ()`
+//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
//~| ERROR: the trait bound `T: Trait` is not satisfied
trait Trait {
-error[E0271]: type mismatch resolving `<impl Future as 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 = ()>;
| ------------------------------- the found opaque type
|
= note: expected unit type `()`
- found associated type `<impl Future as Future>::Output`
- = help: consider constraining the associated type `<impl Future as Future>::Output` to `()`
+ 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
use std::fmt::Debug;
-type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
+type Foo = impl Debug; //~ ERROR could not find defining uses
-static FOO1: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
-const FOO2: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
+static FOO1: Foo = 22_u32; //~ ERROR mismatched types
+const FOO2: Foo = 22_u32; //~ ERROR mismatched types
fn main() {}
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:11:20
+ --> $DIR/static-const-types.rs:10:20
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
-...
+LL |
LL | static FOO1: Foo = 22_u32;
| ^^^^^^ expected opaque type, found `u32`
|
found type `u32`
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:13:19
+ --> $DIR/static-const-types.rs:11:19
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: cannot find type `ţ` in this scope
+// error-pattern: parenthesized type parameters may only be used with a `Fn` trait
+// error-pattern: type arguments are not allowed for this type
+// error-pattern: mismatched types
+// ignore-tidy-trailing-newlines
+// `ţ` must be the last character in this file, it cannot be followed by a newline
+fn main() {
+ 0: u8(ţ
\ No newline at end of file
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91268.rs:9:12
+ |
+LL | fn main() {
+ | - unclosed delimiter
+LL | 0: u8(ţ
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91268.rs:9:12
+ |
+LL | fn main() {
+ | - unclosed delimiter
+LL | 0: u8(ţ
+ | - ^
+ | |
+ | unclosed delimiter
+
+error[E0412]: cannot find type `ţ` in this scope
+ --> $DIR/issue-91268.rs:9:11
+ |
+LL | 0: u8(ţ
+ | ^ expecting a type here because of type ascription
+
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/issue-91268.rs:9:8
+ |
+LL | 0: u8(ţ
+ | ^^^^ only `Fn` traits may use parentheses
+
+error[E0109]: type arguments are not allowed for this type
+ --> $DIR/issue-91268.rs:9:11
+ |
+LL | 0: u8(ţ
+ | ^ type argument not allowed
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91268.rs:9:5
+ |
+LL | fn main() {
+ | - expected `()` because of default return type
+LL | 0: u8(ţ
+ | ^^^^^^^ expected `()`, found `u8`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0109, E0214, E0308, E0412.
+For more information about an error, try `rustc --explain E0109`.
LL | if 0 = 0 {}
| ^^^^^ expected `bool`, found `()`
|
-help: you might have meant to use pattern matching
- |
-LL | if let 0 = 0 {}
- | +++
help: you might have meant to compare for equality
|
LL | if 0 == 0 {}
LL | if 3 = x {
| ^^^^^ expected `bool`, found `()`
|
-help: you might have meant to use pattern matching
- |
-LL | if let 3 = x {
- | +++
help: you might have meant to compare for equality
|
LL | if 3 == x {
error[E0308]: mismatched types
--> $DIR/issue-81293.rs:6:9
|
+LL | let a: u16;
+ | --- expected due to this type
+...
LL | a = c + b * 5;
| ^^^^^^^^^ expected `u16`, found `usize`
error[E0308]: mismatched types
--> $DIR/issue-87771-ice-assign-assign-to-bool.rs:3:9
|
+LL | let mut a;
+ | ----- expected due to the type of this binding
LL | a = a = true;
| ^^^^^^^^ expected `bool`, found `()`
--- /dev/null
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+ (*x).read = 4;
+ //~^ ERROR: attempted to take value of method
+ //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
--- /dev/null
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+ x.read = 4;
+ //~^ ERROR: attempted to take value of method
+ //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
--- /dev/null
+error[E0615]: attempted to take value of method `read` on type `*mut Foo`
+ --> $DIR/issue-91210-ptr-method.rs:10:7
+ |
+LL | x.read = 4;
+ | - ^^^^ method, not a field
+ | |
+ | help: to access the field, dereference first: `(*x)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.
--- /dev/null
+#[repr(C)]
+union PtrRepr<T: ?Sized> {
+ const_ptr: *const T,
+ mut_ptr: *mut T,
+ components: PtrComponents<T>,
+ //~^ ERROR the trait bound
+}
+
+#[repr(C)]
+struct PtrComponents<T: Pointee + ?Sized> {
+ data_address: *const (),
+ metadata: <T as Pointee>::Metadata,
+}
+
+
+
+pub trait Pointee {
+ type Metadata;
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `T: Pointee` is not satisfied in `PtrComponents<T>`
+ --> $DIR/issue-81199.rs:5:17
+ |
+LL | components: PtrComponents<T>,
+ | ^^^^^^^^^^^^^^^^ within `PtrComponents<T>`, the trait `Pointee` is not implemented for `T`
+ |
+note: required because it appears within the type `PtrComponents<T>`
+ --> $DIR/issue-81199.rs:10:8
+ |
+LL | struct PtrComponents<T: Pointee + ?Sized> {
+ | ^^^^^^^^^^^^^
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: consider further restricting this bound
+ |
+LL | union PtrRepr<T: ?Sized + Pointee> {
+ | +++++++++
+help: borrowed types always have a statically known size
+ |
+LL | components: &PtrComponents<T>,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | components: Box<PtrComponents<T>>,
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
| - value moved here
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | fn make_string_bar(mut self) -> Mine{
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
-Subproject commit e1fb17631eb1b3665cdbe45b1c186111577ef512
+Subproject commit 294967c53f0c70d598fc54ca189313c86c576ea7
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
use if_chain::if_chain;
-use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
trait_ref: &TraitRef<'_>,
ty: Ty<'tcx>,
) {
- fn item_from_def_id<'tcx>(cx: &LateContext<'tcx>, def_id: DefId) -> &'tcx Item<'tcx> {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- cx.tcx.hir().expect_item(hir_id)
- }
-
fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
walk_item(&mut visitor, item);
if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
if cx.tcx.inherent_impls(def.did)
.iter()
- .map(|imp_did| item_from_def_id(cx, *imp_did))
+ .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp));
then {
span_lint_and_help(
return;
}
let name = impl_item.ident.name.as_str();
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
- let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id());
- let item = cx.tcx.hir().expect_item(item_hir_id);
+ let item_def_id = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let item = cx.tcx.hir().expect_item(item_def_id);
match &item.kind {
ItemKind::Impl(Impl {
_ => return,
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
if impl_item.span.from_expansion() {
return;
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let parent_item = cx.tcx.hir().expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.def_id);
if_chain! {
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:14
|
+LL | for reference in vec![1, 2, 3] {
+ | --------- expected due to the type of this binding
+...
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^ expected integer, found `&i32`
|
.arg(aux_dir)
.arg("-o")
.arg(out_dir)
+ .arg("--deny")
+ .arg("warnings")
.arg(&self.testpaths.file)
.args(&self.props.compile_flags);
-Subproject commit 76a3329f51439ff2cacda4d26d478a9dc1682a06
+Subproject commit 9983e0fc634e11717eb457a73fe84cfc9409ba8f
-Subproject commit 183ef048f61ae36aa389d1d0345cde940fe788e9
+Subproject commit d9b2291f546abc77d24499339a72a89127464b95
jobs:
test:
runs-on: ubuntu-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
target: [
x86_64-unknown-linux-gnu,
]
+ cfg_release_channel: [nightly, stable]
steps:
- name: checkout
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources
# macOS Catalina 10.15
runs-on: macos-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
fail-fast: false
matrix:
target: [
x86_64-apple-darwin,
]
+ cfg_release_channel: [nightly, stable]
steps:
- name: checkout
jobs:
test:
runs-on: windows-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
+ cfg_release_channel: [nightly, stable]
steps:
# The Windows runners have autocrlf enabled by default
- **Default value**: `"Front"`
- **Possible values**: `"Front"`, `"Back"`
-- **Stable**: No (tracking issue: #3368)
+- **Stable**: No (tracking issue: [#3368](https://github.com/rust-lang/rustfmt/issues/3368))
#### `"Front"` (default):
- **Default value**: `0`
- **Possible values**: *unsigned integer*
-- **Stable**: No (tracking issue: #3382)
+- **Stable**: No (tracking issue: [#3382](https://github.com/rust-lang/rustfmt/issues/3382))
### Example
Original Code (rustfmt will not change it with the default value of `0`):
- **Default value**: `1`
- **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3381)
+- **Stable**: No (tracking issue: [#3381](https://github.com/rust-lang/rustfmt/issues/3381))
### Example
Original Code:
- **Default value**: `"SameLineWhere"`
- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"`
-- **Stable**: No (tracking issue: #3376)
+- **Stable**: No (tracking issue: [#3376](https://github.com/rust-lang/rustfmt/issues/3376))
### Functions
- **Default value**: `"Auto"`
- **Possible values**: "Auto", "Always", "Never"
-- **Stable**: No (tracking issue: #3385)
+- **Stable**: No (tracking issue: [#3385](https://github.com/rust-lang/rustfmt/issues/3385))
## `combine_control_expr`
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3369)
+- **Stable**: No (tracking issue: [#3369](https://github.com/rust-lang/rustfmt/issues/3369))
#### `true` (default):
- **Default value**: `80`
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3349)
+- **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349))
**Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3384)
+- **Stable**: No (tracking issue: [#3384](https://github.com/rust-lang/rustfmt/issues/3384))
#### `false` (default):
- **Default value**: `"AlwaysSameLine"`
- **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"`
-- **Stable**: No (tracking issue: #3377)
+- **Stable**: No (tracking issue: [#3377](https://github.com/rust-lang/rustfmt/issues/3377))
#### `"AlwaysSameLine"` (default):
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3356)
+- **Stable**: No (tracking issue: [#3356](https://github.com/rust-lang/rustfmt/issues/3356))
#### `true` (default):
- **Default value** : 0
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3372)
+- **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372))
#### `0` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3391)
+- **Stable**: No (tracking issue: [#3391](https://github.com/rust-lang/rustfmt/issues/3391))
See also [`max_width`](#max_width).
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3392)
+- **Stable**: No (tracking issue: [#3392](https://github.com/rust-lang/rustfmt/issues/3392))
## `fn_args_layout`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3358)
+- **Stable**: No (tracking issue: [#3358](https://github.com/rust-lang/rustfmt/issues/3358))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `false`, `true`
-- **Stable**: No (tracking issue: #3374)
+- **Stable**: No (tracking issue: [#3374](https://github.com/rust-lang/rustfmt/issues/3374))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3348)
+- **Stable**: No (tracking issue: [#3348](https://github.com/rust-lang/rustfmt/issues/3348))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
## `format_macro_matchers`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3354)
+- **Stable**: No (tracking issue: [#3354](https://github.com/rust-lang/rustfmt/issues/3354))
#### `false` (default):
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3355)
+- **Stable**: No (tracking issue: [#3355](https://github.com/rust-lang/rustfmt/issues/3355))
#### `true` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3353)
+- **Stable**: No (tracking issue: [#3353](https://github.com/rust-lang/rustfmt/issues/3353))
#### `false` (default):
- **Default value**: `Preserve`
- **Possible values**: `Upper`, `Lower`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081))
## `hide_parse_errors`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3390)
+- **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
## `ignore`
- **Default value**: format every file
- **Possible values**: See an example below
-- **Stable**: No (tracking issue: #3395)
+- **Stable**: No (tracking issue: [#3395](https://github.com/rust-lang/rustfmt/issues/3395))
### Example
- **Default Value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3360)
+- **Stable**: No (tracking issue: [#3360](https://github.com/rust-lang/rustfmt/issues/3360))
#### `"Block"` (default):
- **Default value**: "Mixed"
- **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical"
-- **Stable**: No (tracking issue: #3361)
+- **Stable**: No (tracking issue: [#3361](https://github.com/rust-lang/rustfmt/issues/3361))
#### `"Mixed"` (default):
- **Default value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3346)
+- **Stable**: No (tracking issue: [#3346](https://github.com/rust-lang/rustfmt/issues/3346))
### Array
- **Default value**: 0
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3343)
+- **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343))
### Example
- **Default value**: `""`
- **Possible values**: path to a license template file
-- **Stable**: No (tracking issue: #3352)
+- **Stable**: No (tracking issue: [#3352](https://github.com/rust-lang/rustfmt/issues/3352))
A license template is a plain text file which is matched literally against the
beginning of each source file, except for `{}`-delimited blocks, which are
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3373)
+- **Stable**: No (tracking issue: [#3373](https://github.com/rust-lang/rustfmt/issues/3373))
#### `true` (default):
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
#### `Preserve` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3350)
+- **Stable**: No (tracking issue: [#3350](https://github.com/rust-lang/rustfmt/issues/3350))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3351)
+- **Stable**: No (tracking issue: [#3351](https://github.com/rust-lang/rustfmt/issues/3351))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3370)
+- **Stable**: No (tracking issue: [#3370](https://github.com/rust-lang/rustfmt/issues/3370))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3363)
+- **Stable**: No (tracking issue: [#3363](https://github.com/rust-lang/rustfmt/issues/3363))
#### `false` (default)
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5083](https://github.com/rust-lang/rustfmt/issues/5083))
#### `Preserve` (default):
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3394)
+- **Stable**: No (tracking issue: [#3394](https://github.com/rust-lang/rustfmt/issues/3394))
Warns about any comments containing `FIXME` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3393)
+- **Stable**: No (tracking issue: [#3393](https://github.com/rust-lang/rustfmt/issues/3393))
Warns about any comments containing `TODO` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
- **Default value**: `CARGO_PKG_VERSION`
- **Possible values**: any published version (e.g. `"0.3.8"`)
-- **Stable**: No (tracking issue: #3386)
+- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))
## `skip_children`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3389)
+- **Stable**: No (tracking issue: [#3389](https://github.com/rust-lang/rustfmt/issues/3386))
## `single_line_if_else_max_width`
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3366)
+- **Stable**: No (tracking issue: [#3366](https://github.com/rust-lang/rustfmt/issues/3366))
#### `true` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3365)
+- **Stable**: No (tracking issue: [#3365](https://github.com/rust-lang/rustfmt/issues/3365))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3367)
+- **Stable**: No (tracking issue: [#3367](https://github.com/rust-lang/rustfmt/issues/3367))
#### `false` (default):
- **Default value** : 0
- **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3371)
+- **Stable**: No (tracking issue: [#3371](https://github.com/rust-lang/rustfmt/issues/3371))
#### `0` (default):
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3357)
+- **Stable**: No (tracking issue: [#3357](https://github.com/rust-lang/rustfmt/issues/3357))
#### `true` (default):
- **Default value**: `"Vertical"`
- **Possible values**: `"Always"`, `"Never"`, `"Vertical"`
-- **Stable**: No (tracking issue: #3379)
+- **Stable**: No (tracking issue: [#3379](https://github.com/rust-lang/rustfmt/issues/3379))
#### `"Vertical"` (default):
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3378)
+- **Stable**: No (tracking issue: [#3378](https://github.com/rust-lang/rustfmt/issues/3378))
#### `true` (default):
```rust
- **Default value**: `"Wide"`
- **Possible values**: `"Compressed"`, `"Wide"`
-- **Stable**: No (tracking issue: #3364)
+- **Stable**: No (tracking issue: [#3364](https://github.com/rust-lang/rustfmt/issues/3364))
#### `"Wide"` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3387)
+- **Stable**: No (tracking issue: [#3387](https://github.com/rust-lang/rustfmt/issues/3387))
## `use_field_init_shorthand`
- **Default value**: `One`
- **Possible values**: `One`, `Two`
-- **Stable**: No (tracking issue: #3383)
+- **Stable**: No (tracking issue: [#3383](https://github.com/rust-lang/rustfmt/issues/3383))
### Example
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3359)
+- **Stable**: No (tracking issue: [#3359](https://github.com/rust-lang/rustfmt/issues/3359))
#### `false` (default):
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3347)
+- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
#### `false` (default):
## Limitations
Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
-doesn't even need to compile! As we approach a 1.0 release we are also looking
-to limit areas of instability; in particular, post-1.0, the formatting of most
-code should not change as Rustfmt improves. However, there are some things that
-Rustfmt can't do or can't do well (and thus where formatting might change
-significantly, even post-1.0). We would like to reduce the list of limitations
-over time.
+doesn't even need to compile! In general, we are looking to limit areas of
+instability; in particular, post-1.0, the formatting of most code should not
+change as Rustfmt improves. However, there are some things that Rustfmt can't
+do or can't do well (and thus where formatting might change significantly,
+even post-1.0). We would like to reduce the list of limitations over time.
The following list enumerates areas where Rustfmt does not work or where the
stability guarantees do not apply (we don't make a distinction between the two
mod item_struct;
mod utils;
+use std::str::FromStr;
+
use proc_macro::TokenStream;
use syn::parse_macro_input;
TokenStream::from(output)
}
+
+/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
+///
+/// ```rust
+/// #[nightly_only_test]
+/// #[test]
+/// fn test_needs_nightly_rustfmt() {
+/// assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+ // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
+ if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
+ input
+ } else {
+ // output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
+ TokenStream::from_str("").unwrap()
+ }
+}
+
+/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
+///
+/// ```rust
+/// #[stable_only_test]
+/// #[test]
+/// fn test_needs_stable_rustfmt() {
+/// assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+ // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
+ if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
+ input
+ } else {
+ // output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
+ TokenStream::from_str("").unwrap()
+ }
+}
use std::{self, borrow::Cow, iter};
use itertools::{multipeek, MultiPeek};
+use lazy_static::lazy_static;
+use regex::Regex;
use rustc_span::Span;
use crate::config::Config;
};
use crate::{ErrorKind, FormattingError};
+lazy_static! {
+ /// A regex matching reference doc links.
+ ///
+ /// ```markdown
+ /// /// An [example].
+ /// ///
+ /// /// [example]: this::is::a::link
+ /// ```
+ static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap();
+}
+
fn is_custom_comment(comment: &str) -> bool {
if !comment.starts_with("//") {
false
opener: String,
closer: String,
line_start: String,
+ style: CommentStyle<'a>,
}
impl<'a> CommentRewrite<'a> {
shape: Shape,
config: &'a Config,
) -> CommentRewrite<'a> {
- let (opener, closer, line_start) = if block_style {
- CommentStyle::SingleBullet.to_str_tuplet()
+ let ((opener, closer, line_start), style) = if block_style {
+ (
+ CommentStyle::SingleBullet.to_str_tuplet(),
+ CommentStyle::SingleBullet,
+ )
} else {
- comment_style(orig, config.normalize_comments()).to_str_tuplet()
+ let style = comment_style(orig, config.normalize_comments());
+ (style.to_str_tuplet(), style)
};
let max_width = shape
opener: opener.to_owned(),
closer: closer.to_owned(),
line_start: line_start.to_owned(),
+ style,
};
cr.result.push_str(opener);
cr
result
}
+ /// Check if any characters were written to the result buffer after the start of the comment.
+ /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening
+ /// characters for the comment.
+ fn buffer_contains_comment(&self) -> bool {
+ // if self.result.len() < self.opener.len() then an empty comment is in the buffer
+ // if self.result.len() > self.opener.len() then a non empty comment is in the buffer
+ self.result.len() != self.opener.len()
+ }
+
fn finish(mut self) -> String {
if !self.code_block_buffer.is_empty() {
// There is a code block that is not properly enclosed by backticks.
// the last few lines are part of an itemized block
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
- self.result.push_str(&self.comment_line_separator);
+
+ // only push a comment_line_separator for ItemizedBlocks if the comment is not empty
+ if self.buffer_contains_comment() {
+ self.result.push_str(&self.comment_line_separator);
+ }
+
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
line: &'a str,
has_leading_whitespace: bool,
) -> bool {
- let is_last = i == count_newlines(orig);
+ let num_newlines = count_newlines(orig);
+ let is_last = i == num_newlines;
+ let needs_new_comment_line = if self.style.is_block_comment() {
+ num_newlines > 0 || self.buffer_contains_comment()
+ } else {
+ self.buffer_contains_comment()
+ };
if let Some(ref mut ib) = self.item_block {
if ib.add_line(line) {
self.is_prev_line_multi_line = false;
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
- self.result.push_str(&self.comment_line_separator);
+
+ // only push a comment_line_separator if we need to start a new comment line
+ if needs_new_comment_line {
+ self.result.push_str(&self.comment_line_separator);
+ }
+
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
/// Returns `true` if the given string MAY include URLs or alike.
fn has_url(s: &str) -> bool {
// This function may return false positive, but should get its job done in most cases.
- s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://")
+ s.contains("https://")
+ || s.contains("http://")
+ || s.contains("ftp://")
+ || s.contains("file://")
+ || REFERENCE_LINK_URL.is_match(s)
}
/// Given the span, rewrite the missing comment inside it if available.
use super::*;
use std::str;
+ use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
+
#[allow(dead_code)]
mod mock {
use super::super::*;
assert!(config.license_template.is_none());
}
+ #[nightly_only_test]
#[test]
fn test_valid_license_template_path() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
}
+ #[nightly_only_test]
#[test]
fn test_override_existing_license_with_no_license() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
assert_eq!(&toml, &default_config);
}
- // FIXME(#2183): these tests cannot be run in parallel because they use env vars.
- // #[test]
- // fn test_as_not_nightly_channel() {
- // let mut config = Config::default();
- // assert_eq!(config.was_set().unstable_features(), false);
- // config.set().unstable_features(true);
- // assert_eq!(config.was_set().unstable_features(), false);
- // }
-
- // #[test]
- // fn test_as_nightly_channel() {
- // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
- // let mut config = Config::default();
- // config.set().unstable_features(true);
- // assert_eq!(config.was_set().unstable_features(), false);
- // config.set().unstable_features(true);
- // assert_eq!(config.unstable_features(), true);
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
- // }
-
- // #[test]
- // fn test_unstable_from_toml() {
- // let mut config = Config::from_toml("unstable_features = true").unwrap();
- // assert_eq!(config.was_set().unstable_features(), false);
- // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
- // config = Config::from_toml("unstable_features = true").unwrap();
- // assert_eq!(config.was_set().unstable_features(), true);
- // assert_eq!(config.unstable_features(), true);
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
- // }
+ #[stable_only_test]
+ #[test]
+ fn test_as_not_nightly_channel() {
+ let mut config = Config::default();
+ assert_eq!(config.was_set().unstable_features(), false);
+ config.set().unstable_features(true);
+ assert_eq!(config.was_set().unstable_features(), false);
+ }
+
+ #[nightly_only_test]
+ #[test]
+ fn test_as_nightly_channel() {
+ let mut config = Config::default();
+ config.set().unstable_features(true);
+ // When we don't set the config from toml or command line options it
+ // doesn't get marked as set by the user.
+ assert_eq!(config.was_set().unstable_features(), false);
+ config.set().unstable_features(true);
+ assert_eq!(config.unstable_features(), true);
+ }
+
+ #[nightly_only_test]
+ #[test]
+ fn test_unstable_from_toml() {
+ let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
+ assert_eq!(config.was_set().unstable_features(), true);
+ assert_eq!(config.unstable_features(), true);
+ }
#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;
+ #[nightly_only_test]
#[test]
fn test_old_option_set() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}
+ #[nightly_only_test]
#[test]
fn test_both_set() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
+ #[nightly_only_test]
#[test]
fn test_new_overridden() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
+ #[nightly_only_test]
#[test]
fn test_old_overridden() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
imports_granularity = "Module"
capture, is_async, movability, fn_decl, body, expr.span, context, shape,
)
}
- ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
- rewrite_chain(expr, context, shape)
- }
+ ast::ExprKind::Try(..)
+ | ast::ExprKind::Field(..)
+ | ast::ExprKind::MethodCall(..)
+ | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
wrap_str(
))
}
}
- ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::Underscore => Some("_".to_owned()),
ast::ExprKind::Err => None,
};
&format!("{}{}{}", matcher, pat_string, self.connector),
expr,
cond_shape,
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
}
+pub(crate) enum RhsAssignKind<'ast> {
+ Expr(&'ast ast::ExprKind, Span),
+ Bounds,
+ Ty,
+}
+
+impl<'ast> RhsAssignKind<'ast> {
+ // TODO(calebcartwright)
+ // Preemptive addition for handling RHS with chains, not yet utilized.
+ // It may make more sense to construct the chain first and then check
+ // whether there are actually chain elements.
+ #[allow(dead_code)]
+ fn is_chain(&self) -> bool {
+ match self {
+ RhsAssignKind::Expr(kind, _) => {
+ matches!(
+ kind,
+ ast::ExprKind::Try(..)
+ | ast::ExprKind::Field(..)
+ | ast::ExprKind::MethodCall(..)
+ | ast::ExprKind::Await(_)
+ )
+ }
+ _ => false,
+ }
+ }
+}
+
fn rewrite_assignment(
context: &RewriteContext<'_>,
lhs: &ast::Expr,
let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
- rewrite_assign_rhs(context, lhs_str, rhs, shape)
+ rewrite_assign_rhs(
+ context,
+ lhs_str,
+ rhs,
+ &RhsAssignKind::Expr(&rhs.kind, rhs.span),
+ shape,
+ )
}
/// Controls where to put the rhs.
context: &RewriteContext<'_>,
lhs: S,
ex: &R,
+ rhs_kind: &RhsAssignKind<'_>,
shape: Shape,
) -> Option<String> {
- rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
+ rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
}
pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
lhs: &str,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
ex,
orig_shape,
ex.rewrite(context, orig_shape),
+ rhs_kind,
rhs_tactics,
has_rhs_comment,
)
lhs: S,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let lhs = lhs.into();
- let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+ let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
Some(lhs + &rhs)
}
lhs: S,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
between_span: Span,
allow_extend: bool,
} else {
shape
};
- let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+ let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
if contains_comment {
let rhs = rhs.trim_start();
expr: &R,
shape: Shape,
orig_rhs: Option<String>,
+ _rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
has_rhs_comment: bool,
) -> Option<String> {
use crate::config::{Config, FileName};
use crate::ignore_path::IgnorePathSet;
+ use rustfmt_config_proc_macro::nightly_only_test;
+
+ #[nightly_only_test]
#[test]
fn test_ignore_path_set() {
- match option_env!("CFG_RELEASE_CHANNEL") {
- // this test requires nightly
- None | Some("nightly") => {
- let config =
- Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
- .unwrap();
- let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
-
- assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
- assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
- assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
- }
- _ => (),
- };
+ let config =
+ Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap();
+ let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
+
+ assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
+ assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
+ assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
}
}
use crate::config::{BraceStyle, Config, IndentStyle, Version};
use crate::expr::{
is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
- rewrite_assign_rhs_with_comments, RhsTactics,
+ rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
};
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
use crate::macros::{rewrite_macro, MacroPosition};
use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
use crate::stmt::Stmt;
+use crate::types::opaque_ty;
use crate::utils::*;
use crate::vertical::rewrite_with_alignment;
use crate::visitor::FmtVisitor;
// 1 = trailing semicolon;
let nested_shape = shape.sub_width(1)?;
- result = rewrite_assign_rhs(context, result, init, nested_shape)?;
+ result = rewrite_assign_rhs(
+ context,
+ result,
+ init,
+ &RhsAssignKind::Expr(&init.kind, init.span),
+ nested_shape,
+ )?;
// todo else
}
let variant_body = if let Some(ref expr) = field.disr_expr {
let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
+ let ex = &*expr.value;
rewrite_assign_rhs_with(
&context,
lhs,
- &*expr.value,
+ ex,
shape,
+ &RhsAssignKind::Expr(&ex.kind, ex.span),
RhsTactics::AllowOverflow,
)?
} else {
fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
if self.get_context().config.reorder_impl_items() {
+ type TyOpt = Option<ptr::P<ast::Ty>>;
+ use crate::ast::AssocItemKind::*;
+ let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
+ let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
+ let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
+ let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
+ let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
+ (TyAlias(lty), TyAlias(rty))
+ if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
+ {
+ false
+ }
+ (Const(..), Const(..)) => false,
+ _ => true,
+ };
+
// Create visitor for each items, then reorder them.
let mut buffer = vec![];
for item in items {
self.buffer.clear();
}
- fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
- if let Some(lty) = ty {
- if let ast::TyKind::ImplTrait(..) = lty.kind {
- return false;
- }
- }
- true
- }
-
- fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
- !is_type(ty)
- }
-
- fn both_type(
- a: &Option<rustc_ast::ptr::P<ast::Ty>>,
- b: &Option<rustc_ast::ptr::P<ast::Ty>>,
- ) -> bool {
- is_type(a) && is_type(b)
- }
-
- fn both_opaque(
- a: &Option<rustc_ast::ptr::P<ast::Ty>>,
- b: &Option<rustc_ast::ptr::P<ast::Ty>>,
- ) -> bool {
- is_opaque(a) && is_opaque(b)
- }
-
- // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
- // we still need to differentiate to maintain sorting order.
-
- // type -> opaque -> const -> macro -> method
- use crate::ast::AssocItemKind::*;
- fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
- match (a, b) {
- (TyAlias(lty), TyAlias(rty))
- if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
- {
- false
- }
- (Const(..), Const(..)) => false,
- _ => true,
- }
- }
-
buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
(TyAlias(lty), TyAlias(rty))
if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
pub(crate) fn format_impl(
context: &RewriteContext<'_>,
item: &ast::Item,
+ iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
- if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::Impl {
- ref generics,
- ref self_ty,
- ref items,
- ..
- } = **impl_kind;
- let mut result = String::with_capacity(128);
- let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
- let sep = offset.to_string_with_newline(context.config);
- result.push_str(&ref_and_type);
+ let ast::Impl {
+ generics,
+ self_ty,
+ items,
+ ..
+ } = iimpl;
+ let mut result = String::with_capacity(128);
+ let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
+ let sep = offset.to_string_with_newline(context.config);
+ result.push_str(&ref_and_type);
- let where_budget = if result.contains('\n') {
- context.config.max_width()
- } else {
- context.budget(last_line_width(&result))
- };
+ let where_budget = if result.contains('\n') {
+ context.config.max_width()
+ } else {
+ context.budget(last_line_width(&result))
+ };
- let mut option = WhereClauseOption::snuggled(&ref_and_type);
- let snippet = context.snippet(item.span);
- let open_pos = snippet.find_uncommented("{")? + 1;
- if !contains_comment(&snippet[open_pos..])
- && items.is_empty()
- && generics.where_clause.predicates.len() == 1
- && !result.contains('\n')
- {
- option.suppress_comma();
- option.snuggle();
- option.allow_single_line();
- }
+ let mut option = WhereClauseOption::snuggled(&ref_and_type);
+ let snippet = context.snippet(item.span);
+ let open_pos = snippet.find_uncommented("{")? + 1;
+ if !contains_comment(&snippet[open_pos..])
+ && items.is_empty()
+ && generics.where_clause.predicates.len() == 1
+ && !result.contains('\n')
+ {
+ option.suppress_comma();
+ option.snuggle();
+ option.allow_single_line();
+ }
- let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
- let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
- let where_clause_str = rewrite_where_clause(
- context,
- &generics.where_clause,
- context.config.brace_style(),
- Shape::legacy(where_budget, offset.block_only()),
- false,
- "{",
- where_span_end,
- self_ty.span.hi(),
- option,
- )?;
+ let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
+ let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
+ let where_clause_str = rewrite_where_clause(
+ context,
+ &generics.where_clause,
+ context.config.brace_style(),
+ Shape::legacy(where_budget, offset.block_only()),
+ false,
+ "{",
+ where_span_end,
+ self_ty.span.hi(),
+ option,
+ )?;
- // If there is no where-clause, we may have missing comments between the trait name and
- // the opening brace.
- if generics.where_clause.predicates.is_empty() {
- if let Some(hi) = where_span_end {
- match recover_missing_comment_in_span(
- mk_sp(self_ty.span.hi(), hi),
- Shape::indented(offset, context.config),
- context,
- last_line_width(&result),
- ) {
- Some(ref missing_comment) if !missing_comment.is_empty() => {
- result.push_str(missing_comment);
- }
- _ => (),
+ // If there is no where-clause, we may have missing comments between the trait name and
+ // the opening brace.
+ if generics.where_clause.predicates.is_empty() {
+ if let Some(hi) = where_span_end {
+ match recover_missing_comment_in_span(
+ mk_sp(self_ty.span.hi(), hi),
+ Shape::indented(offset, context.config),
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
}
+ _ => (),
}
}
+ }
- if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
- result.push_str(&where_clause_str);
- if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
- // if the where_clause contains extra comments AND
- // there is only one where-clause predicate
- // recover the suppressed comma in single line where_clause formatting
- if generics.where_clause.predicates.len() == 1 {
- result.push(',');
- }
- result.push_str(&format!("{}{{{}}}", sep, sep));
- } else {
- result.push_str(" {}");
+ if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
+ result.push_str(&where_clause_str);
+ if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
+ // if the where_clause contains extra comments AND
+ // there is only one where-clause predicate
+ // recover the suppressed comma in single line where_clause formatting
+ if generics.where_clause.predicates.len() == 1 {
+ result.push(',');
}
- return Some(result);
+ result.push_str(&format!("{}{{{}}}", sep, sep));
+ } else {
+ result.push_str(" {}");
}
+ return Some(result);
+ }
- result.push_str(&where_clause_str);
+ result.push_str(&where_clause_str);
- let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
- match context.config.brace_style() {
- _ if need_newline => result.push_str(&sep),
- BraceStyle::AlwaysNextLine => result.push_str(&sep),
- BraceStyle::PreferSameLine => result.push(' '),
- BraceStyle::SameLineWhere => {
- if !where_clause_str.is_empty() {
- result.push_str(&sep);
- } else {
- result.push(' ');
- }
+ let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
+ match context.config.brace_style() {
+ _ if need_newline => result.push_str(&sep),
+ BraceStyle::AlwaysNextLine => result.push_str(&sep),
+ BraceStyle::PreferSameLine => result.push(' '),
+ BraceStyle::SameLineWhere => {
+ if !where_clause_str.is_empty() {
+ result.push_str(&sep);
+ } else {
+ result.push(' ');
}
}
+ }
- result.push('{');
- // this is an impl body snippet(impl SampleImpl { /* here */ })
- let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
- let snippet = context.snippet(mk_sp(lo, item.span.hi()));
- let open_pos = snippet.find_uncommented("{")? + 1;
+ result.push('{');
+ // this is an impl body snippet(impl SampleImpl { /* here */ })
+ let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
+ let snippet = context.snippet(mk_sp(lo, item.span.hi()));
+ let open_pos = snippet.find_uncommented("{")? + 1;
- if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
- let mut visitor = FmtVisitor::from_context(context);
- let item_indent = offset.block_only().block_indent(context.config);
- visitor.block_indent = item_indent;
- visitor.last_pos = lo + BytePos(open_pos as u32);
+ if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
+ let mut visitor = FmtVisitor::from_context(context);
+ let item_indent = offset.block_only().block_indent(context.config);
+ visitor.block_indent = item_indent;
+ visitor.last_pos = lo + BytePos(open_pos as u32);
- visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
- visitor.visit_impl_items(items);
+ visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
+ visitor.visit_impl_items(items);
- visitor.format_missing(item.span.hi() - BytePos(1));
+ visitor.format_missing(item.span.hi() - BytePos(1));
- let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
- let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
+ let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
+ let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
- result.push_str(&inner_indent_str);
- result.push_str(visitor.buffer.trim());
- result.push_str(&outer_indent_str);
- } else if need_newline || !context.config.empty_item_single_line() {
- result.push_str(&sep);
- }
+ result.push_str(&inner_indent_str);
+ result.push_str(visitor.buffer.trim());
+ result.push_str(&outer_indent_str);
+ } else if need_newline || !context.config.empty_item_single_line() {
+ result.push_str(&sep);
+ }
- result.push('}');
+ result.push('}');
- Some(result)
- } else {
- unreachable!();
- }
+ Some(result)
}
fn is_impl_single_line(
fn format_impl_ref_and_type(
context: &RewriteContext<'_>,
item: &ast::Item,
+ iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
- if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- ref generics,
- of_trait: ref trait_ref,
- ref self_ty,
- ..
- } = **impl_kind;
- let mut result = String::with_capacity(128);
+ let ast::Impl {
+ unsafety,
+ polarity,
+ defaultness,
+ constness,
+ ref generics,
+ of_trait: ref trait_ref,
+ ref self_ty,
+ ..
+ } = *iimpl;
+ let mut result = String::with_capacity(128);
- result.push_str(&format_visibility(context, &item.vis));
- result.push_str(format_defaultness(defaultness));
- result.push_str(format_unsafety(unsafety));
+ result.push_str(&format_visibility(context, &item.vis));
+ result.push_str(format_defaultness(defaultness));
+ result.push_str(format_unsafety(unsafety));
- let shape = if context.config.version() == Version::Two {
- Shape::indented(offset + last_line_width(&result), context.config)
- } else {
- generics_shape_from_config(
- context.config,
- Shape::indented(offset + last_line_width(&result), context.config),
- 0,
- )?
- };
- let generics_str = rewrite_generics(context, "impl", generics, shape)?;
- result.push_str(&generics_str);
- result.push_str(format_constness_right(constness));
+ let shape = if context.config.version() == Version::Two {
+ Shape::indented(offset + last_line_width(&result), context.config)
+ } else {
+ generics_shape_from_config(
+ context.config,
+ Shape::indented(offset + last_line_width(&result), context.config),
+ 0,
+ )?
+ };
+ let generics_str = rewrite_generics(context, "impl", generics, shape)?;
+ result.push_str(&generics_str);
+ result.push_str(format_constness_right(constness));
- let polarity_str = match polarity {
- ast::ImplPolarity::Negative(_) => "!",
- ast::ImplPolarity::Positive => "",
- };
+ let polarity_str = match polarity {
+ ast::ImplPolarity::Negative(_) => "!",
+ ast::ImplPolarity::Positive => "",
+ };
- let polarity_overhead;
- let trait_ref_overhead;
- if let Some(ref trait_ref) = *trait_ref {
- let result_len = last_line_width(&result);
- result.push_str(&rewrite_trait_ref(
- context,
- trait_ref,
- offset,
- polarity_str,
- result_len,
- )?);
- polarity_overhead = 0; // already written
- trait_ref_overhead = " for".len();
- } else {
- polarity_overhead = polarity_str.len();
- trait_ref_overhead = 0;
- }
+ let polarity_overhead;
+ let trait_ref_overhead;
+ if let Some(ref trait_ref) = *trait_ref {
+ let result_len = last_line_width(&result);
+ result.push_str(&rewrite_trait_ref(
+ context,
+ trait_ref,
+ offset,
+ polarity_str,
+ result_len,
+ )?);
+ polarity_overhead = 0; // already written
+ trait_ref_overhead = " for".len();
+ } else {
+ polarity_overhead = polarity_str.len();
+ trait_ref_overhead = 0;
+ }
- // Try to put the self type in a single line.
- let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
- // If there is no where-clause adapt budget for type formatting to take space and curly
- // brace into account.
- match context.config.brace_style() {
- BraceStyle::AlwaysNextLine => 0,
- _ => 2,
- }
- } else {
- 0
- };
- let used_space = last_line_width(&result)
- + polarity_overhead
- + trait_ref_overhead
- + curly_brace_overhead;
- // 1 = space before the type.
- let budget = context.budget(used_space + 1);
- if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
- if !self_ty_str.contains('\n') {
- if trait_ref.is_some() {
- result.push_str(" for ");
- } else {
- result.push(' ');
- result.push_str(polarity_str);
- }
- result.push_str(&self_ty_str);
- return Some(result);
+ // Try to put the self type in a single line.
+ let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
+ // If there is no where-clause adapt budget for type formatting to take space and curly
+ // brace into account.
+ match context.config.brace_style() {
+ BraceStyle::AlwaysNextLine => 0,
+ _ => 2,
+ }
+ } else {
+ 0
+ };
+ let used_space =
+ last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
+ // 1 = space before the type.
+ let budget = context.budget(used_space + 1);
+ if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
+ if !self_ty_str.contains('\n') {
+ if trait_ref.is_some() {
+ result.push_str(" for ");
+ } else {
+ result.push(' ');
+ result.push_str(polarity_str);
}
+ result.push_str(&self_ty_str);
+ return Some(result);
}
+ }
- // Couldn't fit the self type on a single line, put it on a new line.
- result.push('\n');
- // Add indentation of one additional tab.
- let new_line_offset = offset.block_indent(context.config);
- result.push_str(&new_line_offset.to_string(context.config));
- if trait_ref.is_some() {
- result.push_str("for ");
- } else {
- result.push_str(polarity_str);
- }
- let budget = context.budget(last_line_width(&result) + polarity_overhead);
- let type_offset = match context.config.indent_style() {
- IndentStyle::Visual => new_line_offset + trait_ref_overhead,
- IndentStyle::Block => new_line_offset,
- };
- result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
- Some(result)
+ // Couldn't fit the self type on a single line, put it on a new line.
+ result.push('\n');
+ // Add indentation of one additional tab.
+ let new_line_offset = offset.block_indent(context.config);
+ result.push_str(&new_line_offset.to_string(context.config));
+ if trait_ref.is_some() {
+ result.push_str("for ");
} else {
- unreachable!();
+ result.push_str(polarity_str);
}
+ let budget = context.budget(last_line_width(&result) + polarity_overhead);
+ let type_offset = match context.config.indent_style() {
+ IndentStyle::Visual => new_line_offset + trait_ref_overhead,
+ IndentStyle::Block => new_line_offset,
+ };
+ result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
+ Some(result)
}
fn rewrite_trait_ref(
result + ":",
bounds,
shape,
+ &RhsAssignKind::Bounds,
RhsTactics::ForceNextLineWithoutIndent,
)?;
}
generic_bounds,
generics,
};
- rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
+ rewrite_assign_rhs(
+ context,
+ lhs,
+ &trait_alias_bounds,
+ &RhsAssignKind::Bounds,
+ shape.sub_width(1)?,
+ )
+ .map(|s| s + ";")
}
fn format_unit_struct(
ref bounds,
ref ty,
} = *ty_alias_kind;
- let ty_opt = ty.as_ref().map(|t| &**t);
+ let ty_opt = ty.as_ref();
let (ident, vis) = match visitor_kind {
Item(i) => (i.ident, &i.vis),
AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
ForeignItem(i) => (i.ident, &i.vis),
};
let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
-
+ let op_ty = opaque_ty(ty);
// Type Aliases are formatted slightly differently depending on the context
// in which they appear, whether they are opaque, and whether they are associated.
// https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
// https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
- match (visitor_kind, ty_opt) {
- (Item(_), None) => {
- let op_ty = OpaqueType { bounds };
- rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
+ match (visitor_kind, &op_ty) {
+ (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => {
+ let op = OpaqueType { bounds: op_bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
+ }
+ (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
+ rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}
- (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
(AssocImplItem(_), _) => {
- let result = if let Some(ast::Ty {
- kind: ast::TyKind::ImplTrait(_, ref bounds),
- ..
- }) = ty_opt
- {
- let op_ty = OpaqueType { bounds };
- rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
+ let result = if let Some(ref op_bounds) = op_ty {
+ let op = OpaqueType { bounds: op_bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
} else {
- rewrite_ty(rw_info, None, ty.as_ref(), vis)
+ rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}?;
match defaultness {
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
_ => Some(result),
}
}
- (AssocTraitItem(_), _) | (ForeignItem(_), _) => {
- rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
- }
}
}
// 1 = `;`
let shape = Shape::indented(indent, context.config).sub_width(1)?;
- rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
+ rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
} else {
Some(format!("{};", result))
}
let is_prefix_empty = prefix.is_empty();
// We must use multiline. We are going to put attributes and a field on different lines.
- let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
+ let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
// Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
let field_str = if is_prefix_empty {
field_str.trim_start()
&lhs,
&**expr,
Shape::legacy(remaining_width, offset.block_only()),
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
Some(format!("{}{};", prefix, ty_str))
}
}
+
+// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
+// This should be removed once that bug is resolved, with the type alias formatting using the
+// defined Ty for the RHS directly.
+// https://github.com/rust-lang/rustfmt/issues/4373
+// https://github.com/rust-lang/rustfmt/issues/5027
struct OpaqueType<'a> {
bounds: &'a ast::GenericBounds,
}
result.push_str(¶m_indent.to_string_with_newline(context.config));
}
- // Skip `pub(crate)`.
- let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span);
- // A conservative estimation, the goal is to be over all parens in generics
- let params_start = fn_sig
- .generics
- .params
- .last()
- .map_or(lo_after_visibility, |param| param.span().hi());
let params_end = if fd.inputs.is_empty() {
context
.snippet_provider
- .span_after(mk_sp(params_start, span.hi()), ")")
+ .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
} else {
let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
context.snippet_provider.span_after(last_span, ")")
let params_span = mk_sp(
context
.snippet_provider
- .span_after(mk_sp(params_start, span.hi()), "("),
+ .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
params_end,
);
let param_str = rewrite_params(
rewrite_ident(context, self.ident)
);
// 1 = ;
- rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
+ rewrite_assign_rhs(
+ context,
+ prefix,
+ &**ty,
+ &RhsAssignKind::Ty,
+ shape.sub_width(1)?,
+ )
+ .map(|s| s + ";")
}
ast::ForeignItemKind::TyAlias(ref ty_alias) => {
let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);
let offset = formatting.shape.indent + overhead;
let comment_shape = Shape::legacy(width, offset);
- // Use block-style only for the last item or multiline comments.
- let block_style = !formatting.ends_with_newline && last
- || comment.trim().contains('\n')
- || comment.trim().len() > width;
+ let block_style = if !formatting.ends_with_newline && last {
+ true
+ } else if starts_with_newline(comment) {
+ false
+ } else if comment.trim().contains('\n') || comment.trim().len() > width {
+ true
+ } else {
+ false
+ };
rewrite_comment(
comment.trim_start(),
contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
};
use crate::config::lists::*;
-use crate::expr::rewrite_array;
+use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
use crate::lists::{itemize_list, write_list, ListFormatting};
use crate::overflow;
use crate::rewrite::{Rewrite, RewriteContext};
id,
ty.rewrite(context, nested_shape)?
));
- result.push_str(&crate::expr::rewrite_assign_rhs(
+ result.push_str(&rewrite_assign_rhs(
context,
stmt,
&*expr,
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
nested_shape.sub_width(1)?,
)?);
result.push(';');
mod tests {
use super::*;
+ use rustfmt_config_proc_macro::nightly_only_test;
+
mod emitter {
use super::*;
use crate::config::IgnoreList;
- use crate::is_nightly_channel;
use crate::utils::mk_sp;
use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP};
use std::path::PathBuf;
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
+ #[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_ignored_file() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
}
+ #[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_non_ignored_file() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
+ #[nightly_only_test]
#[test]
fn handles_mix_of_recoverable_parse_error() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
use crate::source_file;
use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
+use rustfmt_config_proc_macro::nightly_only_test;
+
mod configuration_snippet;
mod mod_resolver;
mod parser;
// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
+#[nightly_only_test]
#[test]
fn idempotence_tests() {
init_log();
run_test_with(&TestSetting::default(), || {
- // these tests require nightly
- if !is_nightly_channel!() {
- return;
- }
// Get all files in the tests/target directory.
let files = get_test_files(Path::new("tests/target"), true);
let (_reports, count, fails) = check_files(files, &None);
// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
+// Issue-3443: these tests require nightly
+#[nightly_only_test]
#[test]
fn self_tests() {
init_log();
- // Issue-3443: these tests require nightly
- if !is_nightly_channel!() {
- return;
- }
let mut files = get_test_files(Path::new("tests"), false);
let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
for dir in bin_directories {
use std::ops::Deref;
use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ptr;
use rustc_span::{symbol::kw, BytePos, Pos, Span};
use crate::comment::{combine_strs_with_missing_comments, contains_comment};
use crate::config::{IndentStyle, TypeDensity, Version};
use crate::expr::{
format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
+ RhsAssignKind,
};
use crate::lists::{
definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
format!("{}{}", type_str, colon)
};
- rewrite_assign_rhs(context, lhs, bounds, shape)?
+ rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
..
}) => {
let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
- rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
+ rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
}
};
}
}
+pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
+ ty.as_ref().and_then(|t| match &t.kind {
+ ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
+ _ => None,
+ })
+}
+
pub(crate) fn can_be_overflowed_type(
context: &RewriteContext<'_>,
ty: &ast::Ty,
if should_visit_node_again {
match item.kind {
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
- ast::ItemKind::Impl { .. } => {
+ ast::ItemKind::Impl(ref iimpl) => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::Trait(..) => {
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-wrap_comments: true
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
--- /dev/null
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
--- /dev/null
+macro_rules! m {
+() => {
+type Type;
+};
+}
--- /dev/null
+// rustfmt-version: Two
+
+pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;
+
+trait FOo {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
+
+impl Bar {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
\ No newline at end of file
--- /dev/null
+#[cfg(any())]
+ type Type : Bound ;
\ No newline at end of file
--- /dev/null
+// rustfmt-format_code_in_doc_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4420
+enum Minimal {
+ Example,
+ //[thisisremoved thatsleft
+ // canbeanything
+}
+
+struct Minimal2 {
+ Example: usize,
+ //[thisisremoved thatsleft
+ // canbeanything
+}
+
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-normalize_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ }
+}
--- /dev/null
+// rustfmt-wrap_comments: false
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
--- /dev/null
+// rustfmt-wrap_comments: true
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa
+ // aaaaaaaaa aaaaaaaaa
+ // bbbbbbbbbb bbbbbbbbb
+ // bbbbbbbbb ccc cccccccccc
+ // ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa
+ // aaaaaaaaa aaaaaaaaa
+ // bbbbbbbbbb bbbbbbbbb
+ // bbbbbbbbb ccc cccccccccc
+ // ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa
+ * aaaaaaaaa aaaaaaaaa
+ * bbbbbbbbbb bbbbbbbbb
+ * bbbbbbbbb ccc cccccccccc
+ * ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa
+ * aaaaaaaaa aaaaaaaaa
+ * bbbbbbbbbb bbbbbbbbb
+ * bbbbbbbbb ccc cccccccccc
+ * ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
--- /dev/null
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
--- /dev/null
+// rustfmt-wrap_comments: false
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
--- /dev/null
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
--- /dev/null
+// rustfmt-wrap_comments: false
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
--- /dev/null
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
--- /dev/null
+// rustfmt-wrap_comments: false
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
--- /dev/null
+// rustfmt-wrap_comments: true
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
--- /dev/null
+// rustfmt-wrap_comments: false
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
--- /dev/null
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
--- /dev/null
+// rustfmt-wrap_comments: true
+
+pub mod a_long_name {
+ pub mod b_long_name {
+ pub mod c_long_name {
+ pub mod d_long_name {
+ pub mod e_long_name {
+ pub struct Bananas;
+ impl Bananas {
+ pub fn fantastic() {}
+ }
+
+ pub mod f_long_name {
+ pub struct Apples;
+ }
+ }
+ }
+ }
+ }
+}
+
+/// Check out [my other struct] ([`Bananas`]) and [the method it has].
+///
+/// [my other struct]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::f_long_name::Apples
+/// [`Bananas`]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+/// [the method it has]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+pub struct A;
--- /dev/null
+macro_rules! m {
+ () => {
+ type Type;
+ };
+}
--- /dev/null
+// rustfmt-version: Two
+
+pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+
+trait FOo {
+ pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+}
+
+impl Bar {
+ type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+}
--- /dev/null
+#[cfg(any())]
+type Type: Bound;
"bitflags",
"block-buffer",
"block-padding",
- "byteorder",
"byte-tools",
+ "byteorder",
"cc",
"cfg-if",
"chalk-derive",
"memmap2",
"memoffset",
"miniz_oxide",
- "num_cpus",
"num-integer",
"num-traits",
+ "num_cpus",
"object",
"odht",
"once_cell",
"serde_json",
"sha-1",
"sha2",
- "smallvec",
"sharded-slab",
+ "smallvec",
"snap",
"stable_deref_trait",
"stacker",
"tracing-subscriber",
"tracing-tree",
"typenum",
+ "unic-char-property",
+ "unic-char-range",
+ "unic-common",
+ "unic-emoji-char",
+ "unic-ucd-version",
"unicode-normalization",
"unicode-script",
"unicode-security",
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 983;
+const ROOT_ENTRY_LIMIT: usize = 982;
const ISSUES_ENTRY_LIMIT: usize = 2310;
-const PARSER_LIMIT: usize = 1012;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
// Use special values for these dirs.
let is_root = path.join("test/ui") == dir_path;
let is_issues_dir = path.join("test/ui/issues") == dir_path;
- let is_parser = path.join("test/ui/parser") == dir_path;
let limit = if is_root {
ROOT_ENTRY_LIMIT
} else if is_issues_dir {
ISSUES_ENTRY_LIMIT
- } else if is_parser {
- PARSER_LIMIT
} else {
ENTRY_LIMIT
};