[[package]]
name = "compiler_builtins"
-version = "0.1.53"
+version = "0.1.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2467ff455350a4df7d02f1ed1449d0279605a763de5d586dcf6aa7d732508bcb"
+checksum = "c9ac60765140c97aaf531dae151a287646b0805ec725805da9e2a3ee31cd501c"
dependencies = [
"cc",
"rustc-std-workspace-core",
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.
bitflags::bitflags! {
#[derive(Encodable, Decodable, HashStable_Generic)]
- pub struct InlineAsmOptions: u8 {
+ pub struct InlineAsmOptions: u16 {
const PURE = 1 << 0;
const NOMEM = 1 << 1;
const READONLY = 1 << 2;
const NOSTACK = 1 << 5;
const ATT_SYNTAX = 1 << 6;
const RAW = 1 << 7;
+ const MAY_UNWIND = 1 << 8;
}
}
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]
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
.emit();
}
+ if asm.options.contains(InlineAsmOptions::MAY_UNWIND)
+ && !self.sess.features_untracked().asm_unwind
+ {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_unwind,
+ sp,
+ "the `may_unwind` option is unstable",
+ )
+ .emit();
+ }
let mut clobber_abis = FxHashMap::default();
if let Some(asm_arch) = asm_arch {
/// 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(
use tracing::{debug, trace};
macro_rules! arena_vec {
- ($this:expr; $($x:expr),*) => ({
- let a = [$($x),*];
- $this.arena.alloc_from_iter(std::array::IntoIter::new(a))
- });
+ ($this:expr; $($x:expr),*) => (
+ $this.arena.alloc_from_iter([$($x),*])
+ );
}
mod asm;
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();
}
}
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);
+ }
+ })
+}
self.strsep(",", false, b, elts, op)
}
- fn maybe_print_comment(&mut self, pos: BytePos) {
+ fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
+ let mut has_comment = false;
while let Some(ref cmnt) = self.next_comment() {
if cmnt.pos < pos {
+ has_comment = true;
self.print_comment(cmnt);
} else {
break;
}
}
+ has_comment
}
fn print_comment(&mut self, cmnt: &Comment) {
self.print_tts(tts, convert_dollar_crate);
self.end();
match delim {
- DelimToken::Brace => self.bclose(span),
+ DelimToken::Brace => {
+ let empty = tts.is_empty();
+ self.bclose(span, empty);
+ }
_ => {
let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
self.word(token_str)
self.end(); // Close the head-box.
}
- fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
- self.maybe_print_comment(span.hi());
- self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+ fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
+ let has_comment = self.maybe_print_comment(span.hi());
+ if !empty || has_comment {
+ self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+ }
self.word("}");
if close_box {
self.end(); // Close the outer-box.
}
}
- fn bclose(&mut self, span: rustc_span::Span) {
- self.bclose_maybe_open(span, true)
+ fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
+ let close_box = true;
+ self.bclose_maybe_open(span, empty, close_box)
}
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
for item in items {
self.print_item(item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ModKind::Unloaded => {
self.s.word(";");
}
self.bopen();
self.print_foreign_mod(nmod, &item.attrs);
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && nmod.items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::GlobalAsm(ref asm) => {
self.head(visibility_qualified(&item.vis, "global_asm!"));
for impl_item in items {
self.print_assoc_item(impl_item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::Trait(box ast::Trait {
is_auto,
for trait_item in items {
self.print_assoc_item(trait_item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
self.head("");
self.end();
self.maybe_print_trailing_comment(v.span, None);
}
- self.bclose(span)
+ let empty = variants.is_empty();
+ self.bclose(span, empty)
}
crate fn print_visibility(&mut self, vis: &ast::Visibility) {
crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.nbsp();
self.bopen();
- self.hardbreak_if_not_bol();
- for field in fields {
+ let empty = fields.is_empty();
+ if !empty {
self.hardbreak_if_not_bol();
- self.maybe_print_comment(field.span.lo());
- self.print_outer_attributes(&field.attrs);
- self.print_visibility(&field.vis);
- self.print_ident(field.ident.unwrap());
- self.word_nbsp(":");
- self.print_type(&field.ty);
- self.s.word(",");
+
+ for field in fields {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(field.span.lo());
+ self.print_outer_attributes(&field.attrs);
+ self.print_visibility(&field.vis);
+ self.print_ident(field.ident.unwrap());
+ self.word_nbsp(":");
+ self.print_type(&field.ty);
+ self.s.word(",");
+ }
}
- self.bclose(span)
+ self.bclose(span, empty);
}
crate fn print_struct(
}
}
- self.bclose_maybe_open(blk.span, close_box);
+ let empty = attrs.is_empty() && blk.stmts.is_empty();
+ self.bclose_maybe_open(blk.span, empty, close_box);
self.ann.post(self, AnnNode::Block(blk))
}
for arm in arms {
self.print_arm(arm);
}
- self.bclose(expr.span);
+ let empty = attrs.is_empty() && arms.is_empty();
+ self.bclose(expr.span, empty);
}
ast::ExprKind::Closure(
capture_clause,
if opts.contains(InlineAsmOptions::RAW) {
options.push("raw");
}
+ if opts.contains(InlineAsmOptions::MAY_UNWIND) {
+ options.push("may_unwind");
+ }
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
[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();
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use std::fmt;
use std::iter;
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
PlaceContext::MutatingUse(MutatingUseContext::Store) |
// This is potentially both a def and a use...
- PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
+ PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
// We let Call define the result in both the success and
// unwind cases. This is not really correct, however it
// the def in call only to the input from the success
// path and not the unwind path. -nmatsakis
PlaceContext::MutatingUse(MutatingUseContext::Call) |
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
PlaceContext::MutatingUse(MutatingUseContext::Yield) |
// Storage live and storage dead aren't proper defines, but we can ignore
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));
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
{
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
#![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)]
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
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();
}
}
- assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
- if let Some(mir_yield_ty) = body.yield_ty() {
- let ur_yield_ty = universal_regions.yield_ty.unwrap();
+ debug!(
+ "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
+ body.yield_ty(),
+ universal_regions.yield_ty
+ );
+
+ // We will not have a universal_regions.yield_ty if we yield (by accident)
+ // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
+ // because we don't want to panic in an assert here if we've already got errors.
+ if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
+ self.tcx().sess.delay_span_bug(
+ body.span,
+ &format!(
+ "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
+ body.yield_ty(),
+ universal_regions.yield_ty,
+ ),
+ );
+ }
+
+ if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
+ (body.yield_ty(), universal_regions.yield_ty)
+ {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
}
self.assert_iscleanup(body, block_data, unwind, true);
}
}
- TerminatorKind::InlineAsm { destination, .. } => {
+ TerminatorKind::InlineAsm { destination, cleanup, .. } => {
if let Some(target) = destination {
self.assert_iscleanup(body, block_data, target, is_cleanup);
}
+ if let Some(cleanup) = cleanup {
+ if is_cleanup {
+ span_mirbug!(self, block_data, "cleanup on cleanup block")
+ }
+ self.assert_iscleanup(body, block_data, cleanup, true);
+ }
}
}
}
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
} else if p.eat_keyword(kw::Raw) {
try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
+ } else if p.eat_keyword(sym::may_unwind) {
+ try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
} else {
return p.unexpected();
}
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.
})
});
- let Generics { mut params, mut where_clause, span } =
+ let Generics { mut params, mut where_clause, .. } =
self.generics.to_generics(cx, self.span, type_ident, generics);
+ where_clause.span = generics.where_clause.span;
+ let ctxt = self.span.ctxt();
+ let span = generics.span.with_ctxt(ctxt);
// Create the generic parameters
params.extend(generics.params.iter().map(|param| match ¶m.kind {
param.bounds.iter().cloned()
).collect();
- cx.typaram(self.span, param.ident, vec![], bounds, None)
+ cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
}
GenericParamKind::Const { ty, kw_span, .. } => {
let const_nodefault_kind = GenericParamKind::Const {
ty: ty.clone(),
- kw_span: *kw_span,
+ kw_span: kw_span.with_ctxt(ctxt),
// We can't have default values inside impl block
default: None,
// and similarly for where clauses
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
- match *clause {
- ast::WherePredicate::BoundPredicate(ref wb) => {
+ match clause {
+ ast::WherePredicate::BoundPredicate(wb) => {
+ let span = wb.span.with_ctxt(ctxt);
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- span: self.span,
- bound_generic_params: wb.bound_generic_params.clone(),
- bounded_ty: wb.bounded_ty.clone(),
- bounds: wb.bounds.to_vec(),
+ span,
+ ..wb.clone()
})
}
- ast::WherePredicate::RegionPredicate(ref rb) => {
+ ast::WherePredicate::RegionPredicate(wr) => {
+ let span = wr.span.with_ctxt(ctxt);
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
- span: self.span,
- lifetime: rb.lifetime,
- bounds: rb.bounds.to_vec(),
+ span,
+ ..wr.clone()
})
}
- ast::WherePredicate::EqPredicate(ref we) => {
+ ast::WherePredicate::EqPredicate(we) => {
+ let span = we.span.with_ctxt(ctxt);
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
id: ast::DUMMY_NODE_ID,
- span: self.span,
- lhs_ty: we.lhs_ty.clone(),
- rhs_ty: we.rhs_ty.clone(),
+ span,
+ ..we.clone()
})
}
}
.iter()
.map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
+ GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
}
GenericParamKind::Type { .. } => {
- GenericArg::Type(cx.ty_ident(self.span, param.ident))
+ GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
GenericParamKind::Const { .. } => {
- GenericArg::Const(cx.const_ident(self.span, param.ident))
+ GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
})
.collect();
nonself_args: &[P<Expr>],
fields: &SubstructureFields<'_>,
) -> P<Expr> {
+ let span = trait_.span;
let substructure = Substructure {
type_ident,
- method_ident: Ident::new(self.name, trait_.span),
+ method_ident: Ident::new(self.name, span),
self_args,
nonself_args,
fields,
};
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
- f(cx, trait_.span, &substructure)
+ f(cx, span, &substructure)
}
fn get_ret_ty(
let mut nonself_args = Vec::new();
let mut arg_tys = Vec::new();
let mut nonstatic = false;
+ let span = trait_.span;
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
- let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
+ let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
self_args.push(self_expr);
nonstatic = true;
});
for (ty, name) in self.args.iter() {
- let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
- let ident = Ident::new(*name, trait_.span);
+ let ast_ty = ty.to_ty(cx, span, type_ident, generics);
+ let ident = Ident::new(*name, span);
arg_tys.push((ident, ast_ty));
- let arg_expr = cx.expr_ident(trait_.span, ident);
+ let arg_expr = cx.expr_ident(span, ident);
match *ty {
// for static methods, just treat any Self
self_args.push(arg_expr);
}
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
- self_args.push(cx.expr_deref(trait_.span, arg_expr))
+ self_args.push(cx.expr_deref(span, arg_expr))
}
_ => {
nonself_args.push(arg_expr);
arg_types: Vec<(Ident, P<ast::Ty>)>,
body: P<Expr>,
) -> P<ast::AssocItem> {
+ let span = trait_.span;
// Create the generics that aren't for `Self`.
- let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
+ let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
let args = {
let self_args = explicit_self.map(|explicit_self| {
- let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
+ let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
});
- let nonself_args =
- arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty));
+ let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
self_args.into_iter().chain(nonself_args).collect()
};
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
- let method_ident = Ident::new(self.name, trait_.span);
+ let method_ident = Ident::new(self.name, span);
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
let body_block = cx.block_expr(body);
- let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
+ let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
- let trait_lo_sp = trait_.span.shrink_to_lo();
+ let trait_lo_sp = span.shrink_to_lo();
let sig = ast::FnSig {
header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
decl: fn_decl,
- span: trait_.span,
+ span,
};
let defaultness = ast::Defaultness::Final;
P(ast::AssocItem {
id: ast::DUMMY_NODE_ID,
attrs: self.attributes.clone(),
- span: trait_.span,
+ span,
vis: ast::Visibility {
span: trait_lo_sp,
kind: ast::VisibilityKind::Inherited,
nonself_args: &[P<Expr>],
use_temporaries: bool,
) -> P<Expr> {
- let mut raw_fields = Vec::new(); // Vec<[fields of self],
- // [fields of next Self arg], [etc]>
+ let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
+ let span = trait_.span;
let mut patterns = Vec::new();
for i in 0..self_args.len() {
- let struct_path = cx.path(trait_.span, vec![type_ident]);
+ let struct_path = cx.path(span, vec![type_ident]);
let (pat, ident_expr) = trait_.create_struct_pattern(
cx,
struct_path,
let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
first_field
.map(|(span, opt_id, field, attrs)| FieldInfo {
- span,
+ span: span.with_ctxt(trait_.span.ctxt()),
name: opt_id,
self_: field,
other: other_fields
})
.collect()
} else {
- cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
+ cx.span_bug(span, "no `self` parameter for method in generic `derive`")
};
// body of the inner most destructuring match
// structs. This is actually right-to-left, but it shouldn't
// matter.
for (arg_expr, pat) in iter::zip(self_args, patterns) {
- body = cx.expr_match(
- trait_.span,
- arg_expr.clone(),
- vec![cx.arm(trait_.span, pat.clone(), body)],
- )
+ body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
}
body
mut self_args: Vec<P<Expr>>,
nonself_args: &[P<Expr>],
) -> P<Expr> {
- let sp = trait_.span;
+ let span = trait_.span;
let variants = &enum_def.variants;
let self_arg_names = iter::once("__self".to_string())
let self_arg_idents = self_arg_names
.iter()
- .map(|name| Ident::from_str_and_span(name, sp))
+ .map(|name| Ident::from_str_and_span(name, span))
.collect::<Vec<Ident>>();
// The `vi_idents` will be bound, solely in the catch-all, to
.iter()
.map(|name| {
let vi_suffix = format!("{}_vi", &name[..]);
- Ident::from_str_and_span(&vi_suffix, trait_.span)
+ Ident::from_str_and_span(&vi_suffix, span)
})
.collect::<Vec<Ident>>();
self_arg_name,
ast::Mutability::Not,
);
- (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), idents)
+ (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
};
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
}
// Here is the pat = `(&VariantK, &VariantK, ...)`
- let single_pat = cx.pat_tuple(sp, subpats);
+ let single_pat = cx.pat_tuple(span, subpats);
// For the BodyK, we need to delegate to our caller,
// passing it an EnumMatching to indicate which case
.into_iter()
.enumerate()
// For each arg field of self, pull out its getter expr ...
- .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
+ .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
// ... but FieldInfo also wants getter expr
// for matching other arguments of Self type;
// so walk across the *other* self_pats_idents
.collect::<Vec<P<Expr>>>();
FieldInfo {
- span: sp,
+ span,
name: opt_ident,
self_: self_getter_expr,
other: others,
&substructure,
);
- cx.arm(sp, single_pat, arm_expr)
+ cx.arm(span, single_pat, arm_expr)
})
.collect();
// Since we know that all the arguments will match if we reach
// the match expression we add the unreachable intrinsics as the
// result of the catch all which should help llvm in optimizing it
- Some(deriving::call_unreachable(cx, sp))
+ Some(deriving::call_unreachable(cx, span))
}
_ => None,
};
if let Some(arm) = default {
- match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
+ match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
}
// We will usually need the catch-all after matching the
// We also build an expression which checks whether all discriminants are equal
// discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
- let mut discriminant_test = cx.expr_bool(sp, true);
+ let mut discriminant_test = cx.expr_bool(span, true);
let mut first_ident = None;
for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
- let self_addr = cx.expr_addr_of(sp, self_arg.clone());
+ let self_addr = cx.expr_addr_of(span, self_arg.clone());
let variant_value =
- deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
- let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
+ deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
+ let let_stmt = cx.stmt_let(span, false, ident, variant_value);
index_let_stmts.push(let_stmt);
match first_ident {
Some(first) => {
- let first_expr = cx.expr_ident(sp, first);
- let id = cx.expr_ident(sp, ident);
- let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
+ let first_expr = cx.expr_ident(span, first);
+ let id = cx.expr_ident(span, ident);
+ let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id);
discriminant_test =
- cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
+ cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
}
None => {
first_ident = Some(ident);
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
- self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
- let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
+ self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+ let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
// Lastly we create an expression which branches on all discriminants being equal
// if discriminant_test {
// else {
// <delegated expression referring to __self0_vi, et al.>
// }
- let all_match = cx.expr_match(sp, match_arg, match_arms);
- let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+ let all_match = cx.expr_match(span, match_arg, match_arms);
+ let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
index_let_stmts.push(cx.stmt_expr(arm_expr));
- cx.expr_block(cx.block(sp, index_let_stmts))
+ cx.expr_block(cx.block(span, index_let_stmts))
} else if variants.is_empty() {
// As an additional wrinkle, For a zero-variant enum A,
// currently the compiler
// derive Debug on such a type could here generate code
// that needs the feature gate enabled.)
- deriving::call_unreachable(cx, sp)
+ deriving::call_unreachable(cx, span)
} else {
// Final wrinkle: the self_args are expressions that deref
// down to desired places, but we cannot actually deref
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
- self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
- let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
- cx.expr_match(sp, match_arg, match_arms)
+ self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+ let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
+ cx.expr_match(span, match_arg, match_arms)
}
}
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
match (just_spans.is_empty(), named_idents.is_empty()) {
- (false, false) => cx.span_bug(
- self.span,
- "a struct with named and unnamed \
- fields in generic `derive`",
- ),
+ (false, false) => {
+ cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
+ }
// named fields
(_, false) => Named(named_idents),
// unnamed fields
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
}
-fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
- Generics {
- params,
- where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
- span,
- }
-}
-
/// Bounds on type parameters.
#[derive(Clone)]
pub struct Bounds {
self_ty: Ident,
self_generics: &Generics,
) -> Generics {
- let generic_params = self
+ let params = self
.bounds
.iter()
.map(|t| {
})
.collect();
- mk_generics(generic_params, span)
+ Generics {
+ params,
+ where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
+ span,
+ }
}
}
/// * 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;
}
}
// (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 {
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
- std::array::IntoIter::new(["rustc".to_string()])
+ IntoIterator::into_iter(["rustc".to_string()])
.chain(env::args().skip(2))
.chain([
"--".to_string(),
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
- std::array::IntoIter::new(["rustc".to_string()])
+ IntoIterator::into_iter(["rustc".to_string()])
.chain(env::args().skip(2))
.chain([
"--".to_string(),
.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<_>>();
//! Codegen of a single function
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
+use rustc_ast::InlineAsmOptions;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiOf;
fx.add_comment(inst, terminator_head);
}
- fx.set_debug_loc(bb_data.terminator().source_info);
+ let source_info = bb_data.terminator().source_info;
+ fx.set_debug_loc(source_info);
match &bb_data.terminator().kind {
TerminatorKind::Goto { target } => {
let len = codegen_operand(fx, len).load_scalar(fx);
let index = codegen_operand(fx, index).load_scalar(fx);
let location = fx
- .get_caller_location(bb_data.terminator().source_info.span)
+ .get_caller_location(source_info.span)
.load_scalar(fx);
codegen_panic_inner(
fx,
rustc_hir::LangItem::PanicBoundsCheck,
&[index, len, location],
- bb_data.terminator().source_info.span,
+ source_info.span,
);
}
_ => {
let msg_str = msg.description();
- codegen_panic(fx, msg_str, bb_data.terminator().source_info.span);
+ codegen_panic(fx, msg_str, source_info.span);
}
}
}
options,
destination,
line_spans: _,
+ cleanup: _,
} => {
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ fx.tcx.sess.span_fatal(
+ source_info.span,
+ "cranelift doesn't support unwinding from inline assembly.",
+ );
+ }
+
crate::inline_asm::codegen_inline_asm(
fx,
- bb_data.terminator().source_info.span,
+ source_info.span,
template,
operands,
*options,
}
TerminatorKind::Drop { place, target, unwind: _ } => {
let drop_place = codegen_place(fx, *place);
- crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
+ crate::abi::codegen_drop(fx, source_info.span, drop_place);
let target_block = fx.get_block(*target);
fx.bcx.ins().jump(target_block, &[]);
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();
true
}
- fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ self.sess()
+ .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm")
+ .emit();
+ return;
+ }
+
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
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);
}
}
}
use crate::builder::Builder;
+use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::llvm;
+use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
ia.alignstack,
ia.dialect,
&[span],
+ false,
+ None,
);
if r.is_none() {
return false;
options: InlineAsmOptions,
line_spans: &[Span],
instance: Instance<'_>,
+ dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
alignstack,
dialect,
line_spans,
+ options.contains(InlineAsmOptions::MAY_UNWIND),
+ dest_catch_funclet,
)
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
alignstack: bool,
dia: LlvmAsmDialect,
line_spans: &[Span],
+ unwind: bool,
+ dest_catch_funclet: Option<(
+ &'ll llvm::BasicBlock,
+ &'ll llvm::BasicBlock,
+ Option<&Funclet<'ll>>,
+ )>,
) -> Option<&'ll Value> {
let volatile = if volatile { llvm::True } else { llvm::False };
let alignstack = if alignstack { llvm::True } else { llvm::False };
+ let can_throw = if unwind { llvm::True } else { llvm::False };
let argtys = inputs
.iter()
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
debug!("constraint verification result: {:?}", constraints_ok);
if constraints_ok {
+ if unwind && llvm_util::get_version() < (13, 0, 0) {
+ bx.cx.sess().span_fatal(
+ line_spans[0],
+ "unwinding from inline assembly is only supported on llvm >= 13.",
+ );
+ }
+
let v = llvm::LLVMRustInlineAsm(
fty,
asm.as_ptr().cast(),
volatile,
alignstack,
llvm::AsmDialect::from_generic(dia),
+ can_throw,
);
- let call = bx.call(fty, v, inputs, None);
+
+ let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
+ bx.invoke(fty, v, inputs, dest, catch, funclet)
+ } else {
+ bx.call(fty, v, inputs, None)
+ };
// Store mark in a metadata node so we can map LLVM errors
// back to source locations. See #17552.
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);
}
false,
ast::LlvmAsmDialect::Att,
&[span],
+ false,
+ None,
)
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
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,
SideEffects: Bool,
AlignStack: Bool,
Dialect: AsmDialect,
+ CanThrow: Bool,
) -> &Value;
pub fn LLVMRustInlineAsmVerify(
Ty: &Type,
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)]
PlaceContext::MutatingUse(
MutatingUseContext::Store
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::AddressOf
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::FalseEdge { .. }
- | TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
+ | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
TerminatorKind::Call { cleanup: unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. }
| TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::Drop { unwind, .. } => {
use crate::MemFlags;
use rustc_ast as ast;
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
use rustc_middle::mir::AssertKind;
}
}
}
+
+ /// Generates inline assembly with optional `destination` and `cleanup`.
+ fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
+ &self,
+ fx: &mut FunctionCx<'a, 'tcx, Bx>,
+ bx: &mut Bx,
+ template: &[InlineAsmTemplatePiece],
+ operands: &[InlineAsmOperandRef<'tcx, Bx>],
+ options: InlineAsmOptions,
+ line_spans: &[Span],
+ destination: Option<mir::BasicBlock>,
+ cleanup: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
+ ) {
+ if let Some(cleanup) = cleanup {
+ let ret_llbb = if let Some(target) = destination {
+ fx.llbb(target)
+ } else {
+ fx.unreachable_block()
+ };
+
+ bx.codegen_inline_asm(
+ template,
+ &operands,
+ options,
+ line_spans,
+ instance,
+ Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
+ );
+ } else {
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
+
+ if let Some(target) = destination {
+ self.funclet_br(fx, bx, target);
+ } else {
+ bx.unreachable();
+ }
+ }
+ }
}
/// Codegen implementations for some terminator variants.
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ cleanup: Option<mir::BasicBlock>,
instance: Instance<'_>,
) {
let span = terminator.source_info.span;
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
-
- if let Some(target) = destination {
- helper.funclet_br(self, &mut bx, target);
- } else {
- bx.unreachable();
- }
+ helper.do_inlineasm(
+ self,
+ &mut bx,
+ template,
+ &operands,
+ options,
+ line_spans,
+ destination,
+ cleanup,
+ instance,
+ );
}
}
options,
line_spans,
destination,
+ cleanup,
} => {
self.codegen_asm_terminator(
helper,
options,
line_spans,
destination,
+ cleanup,
self.instance,
);
}
options: InlineAsmOptions,
line_spans: &[Span],
instance: Instance<'_>,
+ dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
);
}
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()?);
#![feature(trusted_len)]
#![feature(trusted_step)]
#![feature(try_blocks)]
-#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
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 { .. }
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
use rustc_span::DUMMY_SP;
use std::fmt;
fn apply_call_return_effect(
&mut self,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // We cannot reason about another function's internals, so use conservative type-based
- // qualification for the result of a function call.
- let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty;
- let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
+ return_places.for_each(|place| {
+ // We cannot reason about another function's internals, so use conservative type-based
+ // qualification for the result of a function call.
+ let return_ty = place.ty(self.ccx.body, self.ccx.tcx).ty;
+ let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
- if !return_place.is_indirect() {
- self.assign_qualif_direct(&return_place, qualif);
- }
+ if !place.is_indirect() {
+ self.assign_qualif_direct(&place, qualif);
+ }
+ });
}
fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
}
}
-impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
}
}
-impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
&self,
state: &mut Self::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
+ self.transfer_function(state).apply_call_return_effect(block, return_places)
}
}
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.
///
}
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::ConstPromotion)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
//! 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;
// Leave consts and types unchanged.
ct_op: |ct| ct,
ty_op: |ty| ty,
- })
- .into_ok(),
+ }),
)
};
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
}
- TerminatorKind::InlineAsm { destination, .. } => {
+ TerminatorKind::InlineAsm { destination, cleanup, .. } => {
if let Some(destination) = destination {
self.check_edge(location, *destination, EdgeKind::Normal);
}
+ if let Some(cleanup) = cleanup {
+ self.check_edge(location, *cleanup, EdgeKind::Unwind);
+ }
}
// Nothing to validate for these.
TerminatorKind::Resume
pub trait IdFunctor: Sized {
type Inner;
- #[inline]
- fn map_id<F>(self, mut f: F) -> Self
- where
- F: FnMut(Self::Inner) -> Self::Inner,
- {
- self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
- }
-
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
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)?)
})
}
}
#![feature(once_cell)]
#![feature(test)]
#![feature(thread_id_value)]
-#![feature(unwrap_infallible)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
-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 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()
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) {
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;
}
('\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}', ""),
#![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;
),
);
err.span_label(sp, format!("not allowed after `{}` fragments", kind));
+
+ if kind == NonterminalKind::PatWithOr
+ && sess.edition == Edition::Edition2021
+ && next_token.is_token(&BinOp(token::BinOpToken::Or))
+ {
+ let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
+ span,
+ name,
+ Some(NonterminalKind::PatParam { inferred: false }),
+ ));
+ err.span_suggestion(
+ span,
+ &format!("try a `pat_param` fragment specifier instead"),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
let msg = "allowed there are: ";
match possible {
&[] => {}
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)
+ }
+ }
}
ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
ast::ExprKind::Lit(l) => match l.token {
token::Lit { kind: token::Integer | token::Float, .. } => {
- Ok(std::array::IntoIter::new([
+ Ok(Self::TokenStream::from_iter([
// FIXME: The span of the `-` token is lost when
// parsing, so we cannot faithfully recover it here.
tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
tokenstream::TokenTree::token(token::Literal(l.token), l.span),
- ])
- .collect())
+ ]))
}
_ => Err(()),
},
(active, asm_experimental_arch, "1.58.0", Some(72016), None),
/// Allows using `sym` operands in inline assembly.
(active, asm_sym, "1.58.0", Some(72016), None),
+ /// Allows the `may_unwind` option in inline assembly.
+ (active, asm_unwind, "1.58.0", Some(72016), None),
/// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults.
}
pub fn into_iter(self) -> IntoIter<T, 3> {
- IntoIter::new([self.value_ns, self.type_ns, self.macro_ns])
+ [self.value_ns, self.type_ns, self.macro_ns].into_iter()
}
pub fn iter(&self) -> IntoIter<&T, 3> {
- IntoIter::new([&self.value_ns, &self.type_ns, &self.macro_ns])
+ [&self.value_ns, &self.type_ns, &self.macro_ns].into_iter()
}
}
/// Returns an iterator over the items which are `Some`.
pub fn present_items(self) -> impl Iterator<Item = T> {
- IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).flatten()
+ [self.type_ns, self.value_ns, self.macro_ns].into_iter().flatten()
}
}
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{def_id::LocalDefId, BytePos};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::asm::InlineAsmRegOrRegClass;
use rustc_target::spec::abi::Abi;
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
}
impl GenericParam<'hir> {
- pub fn bounds_span(&self) -> Option<Span> {
- self.bounds.iter().fold(None, |span, bound| {
- let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
-
- Some(span)
- })
+ pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
+ self.bounds
+ .iter()
+ .fold(None, |span: Option<Span>, bound| {
+ // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+ // as we use this method to get a span appropriate for suggestions.
+ if !bound.span().can_be_used_for_suggestions() {
+ None
+ } else {
+ let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
+ Some(span)
+ }
+ })
+ .map(|sp| sp.shrink_to_hi())
}
}
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 => {}
}
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;
if opts.contains(ast::InlineAsmOptions::RAW) {
options.push("raw");
}
+ if opts.contains(ast::InlineAsmOptions::MAY_UNWIND) {
+ options.push("may_unwind");
+ }
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
match decl.output {
hir::FnRetTy::Return(ref ty) => {
self.print_type(&ty);
- self.maybe_print_comment(ty.span.lo())
+ self.maybe_print_comment(ty.span.lo());
}
hir::FnRetTy::DefaultReturn(..) => unreachable!(),
}
self.end();
if let hir::FnRetTy::Return(ref output) = decl.output {
- self.maybe_print_comment(output.span.lo())
+ self.maybe_print_comment(output.span.lo());
}
}
self.tcx
}
- fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(index, ..) => {
if index >= self.binder_index {
bug!("escaping late-bound region during canonicalization");
} else {
- Ok(r)
+ r
}
}
vid, r
);
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
- Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r))
+ self.canonicalize_region_mode.canonicalize_free_region(self, r)
}
ty::ReStatic
| ty::ReFree(_)
| ty::ReEmpty(_)
| ty::RePlaceholder(..)
- | ty::ReErased => Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r)),
+ | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
debug!("canonical: type var found with vid {:?}", vid);
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
- Ok(self.canonicalize_ty_var(
+ self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
},
t,
- ))
+ )
}
}
}
- ty::Infer(ty::IntVar(_)) => Ok(self.canonicalize_ty_var(
+ ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
- )),
+ ),
- ty::Infer(ty::FloatVar(_)) => Ok(self.canonicalize_ty_var(
+ ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
- )),
+ ),
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
}
- ty::Placeholder(placeholder) => Ok(self.canonicalize_ty_var(
+ ty::Placeholder(placeholder) => self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
t,
- )),
+ ),
ty::Bound(debruijn, _) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
- Ok(t)
+ t
}
}
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
- Ok(t)
+ t
}
}
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match ct.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
- return Ok(self.canonicalize_const_var(
+ return self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
ct,
- ));
+ );
}
}
}
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
- return Ok(ct);
+ return ct;
}
}
ty::ConstKind::Placeholder(placeholder) => {
- return Ok(self.canonicalize_const_var(
+ return self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
ct,
- ));
+ );
}
_ => {}
}
let flags = FlagComputation::for_const(ct);
- if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { Ok(ct) }
+ if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
}
}
indices: FxHashMap::default(),
binder_index: ty::INNERMOST,
};
- let out_value = value.fold_with(&mut canonicalizer).into_ok();
+ let out_value = value.fold_with(&mut canonicalizer);
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(ty_var);
if bound_to != ty_var {
- self.fold_ty(bound_to).into_ok()
+ self.fold_ty(bound_to)
} else {
let var = self.canonical_var(info, ty_var.into());
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(const_var);
if bound_to != const_var {
- self.fold_const(bound_to).into_ok()
+ self.fold_const(bound_to)
} else {
let var = self.canonical_var(info, const_var.into());
self.tcx().mk_const(ty::Const {
val: ty::ConstKind::Bound(self.binder_index, var),
- ty: self.fold_ty(const_var.ty).into_ok(),
+ ty: self.fold_ty(const_var.ty),
})
}
}
use crate::infer::type_variable::TypeVariableOriginKind;
use crate::infer::InferCtxt;
+use crate::rustc_middle::ty::TypeFoldable;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
}
}
GenericArgKind::Const(ct) => {
- if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
- let origin =
- self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
- if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
- origin.kind
- {
- return InferenceDiagnosticsData {
- name: name.to_string(),
+ match ct.val {
+ ty::ConstKind::Infer(InferConst::Var(vid)) => {
+ let origin = self
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .probe_value(vid)
+ .origin;
+ if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+ origin.kind
+ {
+ return InferenceDiagnosticsData {
+ name: name.to_string(),
+ span: Some(origin.span),
+ kind: UnderspecifiedArgKind::Const { is_parameter: true },
+ parent: InferenceDiagnosticsParentData::for_def_id(
+ self.tcx, def_id,
+ ),
+ };
+ }
+
+ debug_assert!(!origin.span.is_dummy());
+ let mut s = String::new();
+ let mut printer =
+ ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
+ if let Some(highlight) = highlight {
+ printer.region_highlight_mode = highlight;
+ }
+ let _ = ct.print(printer);
+ InferenceDiagnosticsData {
+ name: s,
span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: true },
- parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
- };
+ kind: UnderspecifiedArgKind::Const { is_parameter: false },
+ parent: None,
+ }
}
-
- debug_assert!(!origin.span.is_dummy());
- let mut s = String::new();
- let mut printer =
- ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
- if let Some(highlight) = highlight {
- printer.region_highlight_mode = highlight;
+ ty::ConstKind::Unevaluated(ty::Unevaluated {
+ substs_: Some(substs), ..
+ }) => {
+ assert!(substs.has_infer_types_or_consts());
+
+ // FIXME: We only use the first inference variable we encounter in
+ // `substs` here, this gives insufficiently informative diagnostics
+ // in case there are multiple inference variables
+ for s in substs.iter() {
+ match s.unpack() {
+ GenericArgKind::Type(t) => match t.kind() {
+ ty::Infer(_) => {
+ return self.extract_inference_diagnostics_data(s, None);
+ }
+ _ => {}
+ },
+ GenericArgKind::Const(c) => match c.val {
+ ty::ConstKind::Infer(InferConst::Var(_)) => {
+ return self.extract_inference_diagnostics_data(s, None);
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ }
+ bug!(
+ "expected an inference variable in substs of unevaluated const {:?}",
+ ct
+ );
}
- let _ = ct.print(printer);
- InferenceDiagnosticsData {
- name: s,
- span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: false },
- parent: None,
+ _ => {
+ bug!("unexpect const: {:?}", ct);
}
- } else {
- bug!("unexpect const: {:?}", ct);
}
}
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
F: FnOnce(u32) -> ty::InferTy,
{
if let Some(ty) = opt_ty {
- return ty.fold_with(self).into_ok();
+ return ty.fold_with(self);
}
match self.ty_freshen_map.entry(key) {
F: FnOnce(u32) -> ty::InferConst<'tcx>,
{
if let Some(ct) = opt_ct {
- return ct.fold_with(self).into_ok();
+ return ct.fold_with(self);
}
match self.const_freshen_map.entry(key) {
self.infcx.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(..) => {
// leave bound regions alone
- Ok(r)
+ r
}
ty::ReEarlyBound(..)
| ty::ReEmpty(_)
| ty::ReErased => {
// replace all free regions with 'erased
- Ok(self.tcx().lifetimes.re_erased)
+ self.tcx().lifetimes.re_erased
}
ty::ReStatic => {
if self.keep_static {
- Ok(r)
+ r
} else {
- Ok(self.tcx().lifetimes.re_erased)
+ self.tcx().lifetimes.re_erased
}
}
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
- return Ok(t);
+ return t;
}
let tcx = self.infcx.tcx;
match *t.kind() {
ty::Infer(ty::TyVar(v)) => {
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
- Ok(self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy))
+ self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
}
- ty::Infer(ty::IntVar(v)) => Ok(self.freshen_ty(
+ ty::Infer(ty::IntVar(v)) => self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.map(|v| v.to_type(tcx)),
ty::IntVar(v),
ty::FreshIntTy,
- )),
+ ),
- ty::Infer(ty::FloatVar(v)) => Ok(self.freshen_ty(
+ ty::Infer(ty::FloatVar(v)) => self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.map(|v| v.to_type(tcx)),
ty::FloatVar(v),
ty::FreshFloatTy,
- )),
+ ),
ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => {
if ct >= self.ty_freshen_count {
self.ty_freshen_count
);
}
- Ok(t)
+ t
}
ty::Generator(..)
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match ct.val {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct = self
.probe_value(v)
.val
.known();
- return Ok(self.freshen_const(
+ return self.freshen_const(
opt_ct,
ty::InferConst::Var(v),
ty::InferConst::Fresh,
ct.ty,
- ));
+ );
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
self.const_freshen_count,
);
}
- return Ok(ct);
+ return ct;
}
ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
{
Ok(value)
} else {
- Ok(value.fold_with(&mut fudger).into_ok())
+ Ok(value.fold_with(&mut fudger))
}
}
}
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Infer(ty::InferTy::TyVar(vid)) => {
if self.type_vars.0.contains(&vid) {
// Recreate it with a fresh variable here.
let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize;
let origin = self.type_vars.1[idx];
- Ok(self.infcx.next_ty_var(origin))
+ self.infcx.next_ty_var(origin)
} else {
// This variable was created before the
// "fudging". Since we refresh all type
debug_assert!(
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
);
- Ok(ty)
+ ty
}
}
ty::Infer(ty::InferTy::IntVar(vid)) => {
- Ok(if self.int_vars.contains(&vid) { self.infcx.next_int_var() } else { ty })
+ if self.int_vars.contains(&vid) {
+ self.infcx.next_int_var()
+ } else {
+ ty
+ }
}
ty::Infer(ty::InferTy::FloatVar(vid)) => {
- Ok(if self.float_vars.contains(&vid) { self.infcx.next_float_var() } else { ty })
+ if self.float_vars.contains(&vid) {
+ self.infcx.next_float_var()
+ } else {
+ ty
+ }
}
_ => ty.super_fold_with(self),
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReVar(vid) = *r {
if self.region_vars.0.contains(&vid) {
let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx];
- return Ok(self.infcx.next_region_var(origin));
+ return self.infcx.next_region_var(origin);
}
}
- Ok(r)
+ r
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize;
let origin = self.const_vars.1[idx];
- Ok(self.infcx.next_const_var(ty, origin))
+ self.infcx.next_const_var(ty, origin)
} else {
- Ok(ct)
+ ct
}
} else {
ct.super_fold_with(self)
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
}
pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
- t.fold_with(&mut self.freshener()).into_ok()
+ t.fold_with(&mut self.freshener())
}
/// Returns the origin of the type variable identified by `vid`, or `None`
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut ShallowResolver { infcx: self }).into_ok()
+ value.fold_with(&mut ShallowResolver { infcx: self })
}
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
return value; // Avoid duplicated subst-folding.
}
let mut r = resolve::OpportunisticVarResolver::new(self);
- value.fold_with(&mut r).into_ok()
+ value.fold_with(&mut r)
}
/// Returns the first unresolved variable contained in `T`. In the
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
- let mut original_values = OriginalQueryValues::default();
- let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
+ let mut substs = unevaluated.substs(self.tcx);
+ substs = self.resolve_vars_if_possible(substs);
+
+ // Postpone the evaluation of constants whose substs depend on inference
+ // variables
+ if substs.has_infer_types_or_consts() {
+ return Err(ErrorHandled::TooGeneric);
+ }
+
+ let param_env_erased = self.tcx.erase_regions(param_env);
+ let substs_erased = self.tcx.erase_regions(substs);
+
+ let unevaluated = ty::Unevaluated {
+ def: unevaluated.def,
+ substs_: Some(substs_erased),
+ promoted: unevaluated.promoted,
+ };
- let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
- self.tcx.const_eval_resolve(param_env, unevaluated, span)
+ self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
}
/// If `typ` is a type variable of some kind, resolve it one level
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- Ok(self.infcx.shallow_resolve_ty(ty))
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.infcx.shallow_resolve_ty(ty)
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- Ok(if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
self.infcx
.inner
.borrow_mut()
.unwrap_or(ct)
} else {
ct
- })
+ }
}
}
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
let tcx = self.infcx.tcx;
- value
- .fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- if let Some(def_id) = def_id.as_local() {
- let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.infcx.defining_use_anchor;
- let def_scope_default = || {
- 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),
- };
- if in_definition_scope {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ value.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| {
+ if ty.references_error() {
+ return tcx.ty_error();
+ } else if let ty::Opaque(def_id, substs) = ty.kind() {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ if let Some(def_id) = def_id.as_local() {
+ let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let parent_def_id = self.infcx.defining_use_anchor;
+ let def_scope_default = || {
+ 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(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 };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ }
- debug!(
- "instantiate_opaque_types_in_map: \
+ debug!(
+ "instantiate_opaque_types_in_map: \
encountered opaque outside its definition scope \
def_id={:?}",
- def_id,
- );
- }
+ def_id,
+ );
}
+ }
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- .into_ok()
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
}
#[instrument(skip(self), level = "debug")]
debug!(?predicate);
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
- let predicate = predicate
- .fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| match ty.kind() {
- ty::Projection(projection_ty) => infcx.infer_projection(
- self.param_env,
- *projection_ty,
- traits::ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- .into_ok();
+ let predicate = predicate.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| match ty.kind() {
+ ty::Projection(projection_ty) => infcx.infer_projection(
+ self.param_env,
+ *projection_ty,
+ traits::ObligationCause::misc(self.value_span, self.body_id),
+ 0,
+ &mut self.obligations,
+ ),
+ _ => ty,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ });
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
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;
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.has_infer_types_or_consts() {
- Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
+ t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
t.super_fold_with(self)
}
}
- fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> Result<&'tcx Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
if !ct.has_infer_types_or_consts() {
- Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
+ ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
- fn fold_mir_const(
- &mut self,
- constant: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
constant.super_fold_with(self)
}
}
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.has_infer_regions() {
- Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
+ t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
t.super_fold_with(self)
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- Ok(match *r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
ty::ReVar(rid) => {
let resolved = self
.infcx
self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
}
_ => r,
- })
+ }
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if !ct.has_infer_regions() {
- Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
+ ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
ct.super_fold_with(self)
}
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut FullTypeResolver { infcx })
+ value.try_fold_with(&mut FullTypeResolver { infcx })
}
// N.B. This type is not public because the protocol around checking the
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
+}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+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() {
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
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>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReVar(rid) => Ok(self
.infcx
}
}
- fn fold_const(
+ fn try_fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
}
_ => {}
}
- c.super_fold_with(self)
+ c.try_super_fold_with(self)
}
}
}
#![feature(control_flow_enum)]
#![feature(min_specialization)]
#![feature(label_break_value)]
-#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
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) -> Result<Self, F::Error> {
+ 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)?,
})
}
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)
};
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true);
- untracked!(emit_future_incompat_report, true);
untracked!(emit_stack_sizes, true);
untracked!(future_incompat_test, true);
untracked!(hir_stats, true);
/// 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();
+ }
+ }
}
}
/// 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)
})
}
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();
- }
- }
}
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
- let target = match adjustments.last() {
- Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
- _ => return,
+ let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
+ return
};
let types =
// If the trait is private, add the impl items to `private_traits` so they don't get
// reported for missing docs.
let real_trait = trait_ref.path.res.def_id();
- if let Some(def_id) = real_trait.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
- if let hir::VisibilityKind::Inherited = item.vis.node {
- for impl_item_ref in items {
- self.private_traits.insert(impl_item_ref.id.hir_id());
- }
- }
+ let Some(def_id) = real_trait.as_local() else { return };
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) else { return };
+ if let hir::VisibilityKind::Inherited = item.vis.node {
+ for impl_item_ref in items {
+ self.private_traits.insert(impl_item_ref.id.hir_id());
}
}
return;
_ => return,
}
- let debug = match cx.tcx.get_diagnostic_item(sym::Debug) {
- Some(debug) => debug,
- None => return,
+ let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
+ return
};
if self.impling_types.is_none() {
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! {
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- let (ty, type_alias_generics) = match item.kind {
- hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics),
- _ => return,
+ let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
+ return
};
if let hir::TyKind::OpaqueDef(..) = ty.kind {
// Bounds are respected for `type X = impl Trait`
// and should check for them here.
match predicate.bounded_ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
- if let Res::Def(DefKind::TyParam, def_id) = path.res {
- let index = ty_generics.param_def_id_to_index[&def_id];
- (
- Self::lifetimes_outliving_type(inferred_outlives, index),
- &predicate.bounds,
- predicate.span,
- )
- } else {
- continue;
- }
+ let Res::Def(DefKind::TyParam, def_id) = path.res else {
+ continue
+ };
+ let index = ty_generics.param_def_id_to_index[&def_id];
+ (
+ Self::lifetimes_outliving_type(inferred_outlives, index),
+ &predicate.bounds,
+ predicate.span,
+ )
}
_ => {
continue;
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
for (idx, _) in statement.match_indices(':') {
let possible_label = statement[start_idx..idx].trim();
let mut chars = possible_label.chars();
- if let Some(c) = chars.next() {
- // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
- if (c.is_alphabetic() || matches!(c, '.' | '_'))
- && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
- {
- found_labels.push(possible_label);
- } else {
- // If we encounter a non-label, there cannot be any further labels, so stop checking
- break;
- }
- } else {
+ let Some(c) = chars.next() else {
// Empty string means a leading ':' in this section, which is not a label
+ break
+ };
+ // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
+ if (c.is_alphabetic() || matches!(c, '.' | '_'))
+ && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
+ {
+ found_labels.push(possible_label);
+ } else {
+ // If we encounter a non-label, there cannot be any further labels, so stop checking
break;
}
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),
+ _ => {}
}
}
}
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
for attr in attrs {
- let level = match Level::from_symbol(attr.name_or_empty()) {
- None => continue,
- Some(lvl) => lvl,
+ let Some(level) = Level::from_symbol(attr.name_or_empty()) else {
+ continue
};
- let mut metas = match attr.meta_item_list() {
- Some(x) => x,
- None => continue,
+ let Some(mut metas) = attr.meta_item_list() else {
+ continue
};
if metas.is_empty() {
continue;
}
- let (lint_attr_name, lint_attr_span) = match *src {
- LintLevelSource::Node(name, span, _) => (name, span),
- _ => continue,
+ let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else {
+ continue
};
let lint = builtin::UNUSED_ATTRIBUTES;
#![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 =
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let (call, elements) = match expr.kind {
- ExprKind::MethodCall(call, _, elements, _) => (call, elements),
- _ => return,
+ let ExprKind::MethodCall(call, _, elements, _) = &expr.kind else {
+ return
};
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
}
let param_env = cx.tcx.param_env(trait_id);
// Resolve the trait method instance.
- let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
- Ok(Some(i)) => i,
- _ => return,
+ let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) else {
+ 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 predicates = cx.tcx.explicit_predicates_of(item.def_id);
for &(predicate, span) in predicates.predicates {
- let trait_predicate = match predicate.kind().skip_binder() {
- Trait(trait_predicate) => trait_predicate,
- _ => continue,
+ let Trait(trait_predicate) = predicate.kind().skip_binder() else {
+ continue
};
if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
// `~const Drop` definitely have meanings so avoid linting here.
continue;
}
cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
- let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
- Some(needs_drop) => needs_drop,
- None => return,
+ let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+ return
};
let msg = format!(
"bounds on `{}` are most likely incorrect, consider instead \
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
- let bounds = match &ty.kind {
- hir::TyKind::TraitObject(bounds, _lifetime, _syntax) => bounds,
- _ => return,
+ let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else {
+ return
};
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if cx.tcx.lang_items().drop_trait() == def_id {
cx.struct_span_lint(DYN_DROP, bound.span, |lint| {
- let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
- Some(needs_drop) => needs_drop,
- None => return,
+ let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+ return
};
let msg = format!(
"types that do not implement `Drop` can still have drop glue, consider \
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 {
- Variants::Multiple {
+ let Variants::Multiple {
tag_encoding: TagEncoding::Direct, tag, ref variants, ..
- } => (variants, tag),
- _ => return,
+ } = &layout.variants else {
+ return
};
let tag_size = tag.value.size(&cx.tcx).bytes();
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
}
LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
char *Constraints, size_t ConstraintsLen,
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
- LLVMRustAsmDialect Dialect) {
+ LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
+#if LLVM_VERSION_GE(13, 0)
+ return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
+ StringRef(AsmString, AsmStringLen),
+ StringRef(Constraints, ConstraintsLen),
+ HasSideEffects, IsAlignStack,
+ fromRust(Dialect), CanThrow));
+#else
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
StringRef(AsmString, AsmStringLen),
StringRef(Constraints, ConstraintsLen),
- HasSideEffects, IsAlignStack, fromRust(Dialect)));
+ HasSideEffects, IsAlignStack,
+ fromRust(Dialect)));
+#endif
}
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
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
) -> Result<Self, __F::Error> {
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(control_flow_enum)]
#![feature(associated_type_defaults)]
#![feature(iter_zip)]
-#![feature(thread_local_const_init)]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
(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
) -> ::std::result::Result<$ty, F::Error> {
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,
) -> ::std::result::Result<Self, V::Error> {
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)*
//! [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};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId};
+use rustc_session::Session;
use rustc_target::abi::{Size, VariantIdx};
use polonius_engine::Atom;
}
}
+ /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+ /// If this pass causes the MIR to enter a new phase, return that phase.
+ fn phase_change(&self) -> Option<MirPhase> {
+ None
+ }
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ true
+ }
}
/// The various "big phases" that MIR goes through.
| 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
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
Ok(UserTypeProjection {
- base: self.base.fold_with(folder)?,
- projs: self.projs.fold_with(folder)?,
+ base: self.base.try_fold_with(folder)?,
+ projs: self.projs.try_fold_with(folder)?,
})
}
/// Destination block after the inline assembly returns, unless it is
/// diverging (InlineAsmOptions::NORETURN).
destination: Option<BasicBlock>,
+
+ /// Cleanup to be done if the inline assembly unwinds. This is present
+ /// if and only if InlineAsmOptions::MAY_UNWIND is set.
+ cleanup: Option<BasicBlock>,
},
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
| Return
| Unreachable
| Call { destination: None, cleanup: None, .. }
- | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
+ | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]),
Goto { target: ref t }
| Call { destination: None, cleanup: Some(ref t), .. }
| Call { destination: Some((_, ref t)), cleanup: None, .. }
| Drop { target: ref t, unwind: None, .. }
| Assert { target: ref t, cleanup: None, .. }
| FalseUnwind { real_target: ref t, unwind: None }
- | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
+ | InlineAsm { destination: Some(ref t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(ref t), .. } => {
+ Some(t).into_iter().chain(&[])
+ }
Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
| Yield { resume: ref t, drop: Some(ref u), .. }
| DropAndReplace { target: ref t, unwind: Some(ref u), .. }
| Drop { target: ref t, unwind: Some(ref u), .. }
| Assert { target: ref t, cleanup: Some(ref u), .. }
- | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
+ | FalseUnwind { real_target: ref t, unwind: Some(ref u) }
+ | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => {
Some(t).into_iter().chain(slice::from_ref(u))
}
SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]),
| Return
| Unreachable
| Call { destination: None, cleanup: None, .. }
- | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
+ | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
Goto { target: ref mut t }
| Call { destination: None, cleanup: Some(ref mut t), .. }
| Call { destination: Some((_, ref mut t)), cleanup: None, .. }
| Drop { target: ref mut t, unwind: None, .. }
| Assert { target: ref mut t, cleanup: None, .. }
| FalseUnwind { real_target: ref mut t, unwind: None }
- | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
+ | InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
+ Some(t).into_iter().chain(&mut [])
+ }
Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
- | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
+ | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
+ | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
Some(t).into_iter().chain(slice::from_mut(u))
}
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]),
| TerminatorKind::GeneratorDrop
| TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. }
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => None,
+ | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref unwind, .. }
| TerminatorKind::Assert { cleanup: ref unwind, .. }
| TerminatorKind::DropAndReplace { ref unwind, .. }
| TerminatorKind::Drop { ref unwind, .. }
- | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
+ | TerminatorKind::FalseUnwind { ref unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
}
}
| TerminatorKind::GeneratorDrop
| TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. }
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => None,
+ | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref mut unwind, .. }
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
| TerminatorKind::DropAndReplace { ref mut unwind, .. }
| TerminatorKind::Drop { ref mut unwind, .. }
- | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
+ | TerminatorKind::FalseUnwind { ref mut unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
}
}
FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
FalseUnwind { unwind: None, .. } => vec!["real".into()],
- InlineAsm { destination: Some(_), .. } => vec!["".into()],
- InlineAsm { destination: None, .. } => vec![],
+ InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+ InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+ InlineAsm { destination: None, cleanup: None, .. } => vec![],
}
}
}
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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).map(|loc| (loc, dest))))
+ .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,
FalseEdge { real_target, imaginary_target }
}
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
- InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
- template,
- operands: operands.fold_with(folder)?,
- options,
- line_spans,
- destination,
- },
+ InlineAsm { template, operands, options, line_spans, destination, cleanup } => {
+ InlineAsm {
+ template,
+ operands: operands.try_fold_with(folder)?,
+ options,
+ line_spans,
+ destination,
+ cleanup,
+ }
+ }
};
Ok(Terminator { source_info: self.source_info, kind })
}
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
Ok(Place {
- local: self.local.fold_with(folder)?,
- projection: self.projection.fold_with(folder)?,
+ local: self.local.try_fold_with(folder)?,
+ projection: self.projection.try_fold_with(folder)?,
})
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::Rvalue::*;
Ok(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)?)))
+ 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.try_map_id(|kind| {
Ok(match kind {
- AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)?),
+ 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.fold_with(folder)?,
- user_ty.fold_with(folder)?,
+ substs.try_fold_with(folder)?,
+ user_ty.try_fold_with(folder)?,
n,
),
AggregateKind::Closure(id, substs) => {
- AggregateKind::Closure(id, substs.fold_with(folder)?)
+ AggregateKind::Closure(id, substs.try_fold_with(folder)?)
}
AggregateKind::Generator(id, substs, movablity) => {
- AggregateKind::Generator(id, substs.fold_with(folder)?, movablity)
+ AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity)
}
})
})?;
- Aggregate(kind, fields.fold_with(folder)?)
+ Aggregate(kind, fields.try_fold_with(folder)?)
+ }
+ ShallowInitBox(op, ty) => {
+ ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?)
}
- ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder)?, ty.fold_with(folder)?),
})
}
}
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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.fold_with(folder)?),
- Operand::Move(place) => Operand::Move(place.fold_with(folder)?),
- Operand::Constant(c) => Operand::Constant(c.fold_with(folder)?),
+ 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)?),
})
}
}
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::ProjectionElem::*;
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 }
}
impl<'tcx> TypeFoldable<'tcx> for Field {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ 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 GeneratorSavedLocal {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ 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, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ 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 Constant<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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> {
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
match self {
- ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.fold_with(folder)?)),
- ConstantKind::Val(v, t) => Ok(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)?)),
}
}
for output in & $($mutability)? asm.outputs[..] {
self.visit_place(
output,
- PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
+ PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
location
);
}
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match op {
InlineAsmOperand::Out { place: Some(place), .. } => {
self.visit_place(
place,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
location,
);
}
if let Some(out_place) = out_place {
self.visit_place(
out_place,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
location,
);
}
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,
/// Appears as LHS of an assignment.
Store,
/// Can often be treated as a `Store`, but needs to be separate because
- /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
+ /// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
/// cannot be simplified the way a `Store`-`Store` can be.
+ LlvmAsmOutput,
+ /// Output operand of an inline assembly block.
AsmOutput,
/// Destination of a call.
Call,
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput,
)
)
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)
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<
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(())
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
{
- if let Some(bounds_span) = param.bounds_span() {
+ if let Some(span) = param.bounds_span_for_suggestions() {
// If user has provided some bounds, suggest restricting them:
//
// fn foo<T: Foo>(t: T) { ... }
// --
// |
// replace with: `T: Bar +`
- suggest_restrict(bounds_span.shrink_to_hi());
+ suggest_restrict(span);
} else {
// If user hasn't provided any bounds, suggest adding a new one:
//
fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
// N.B., use `super_fold_with` here. If we used `fold_with`, it
// could invoke the `erase_regions_ty` query recursively.
- ty.super_fold_with(&mut RegionEraserVisitor { tcx }).into_ok()
+ ty.super_fold_with(&mut RegionEraserVisitor { tcx })
}
impl<'tcx> TyCtxt<'tcx> {
return value;
}
debug!("erase_regions({:?})", value);
- let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }).into_ok();
+ let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
debug!("erase_regions = {:?}", value1);
value1
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- if ty.needs_infer() { ty.super_fold_with(self) } else { Ok(self.tcx.erase_regions_ty(ty)) }
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
}
- fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
u.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'erased.
// away. In codegen, they will always be erased to 'erased
// whenever a substitution occurs.
match *r {
- ty::ReLateBound(..) => Ok(r),
- _ => Ok(self.tcx.lifetimes.re_erased),
+ ty::ReLateBound(..) => r,
+ _ => self.tcx.lifetimes.re_erased,
}
}
- fn fold_mir_const(
- &mut self,
- c: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
}
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) -> Result<Self, F::Error>;
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
+ 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> {
/// 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>) -> Result<Binder<'tcx, T>, Self::Error>
+ 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>) -> Result<Ty<'tcx>, Self::Error> {
+ 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>) -> Result<ty::Region<'tcx>, Self::Error> {
+ 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(
+ 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>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
+ p.super_fold_with(self)
+ }
+
+ 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.super_fold_with(self)
+ c.try_super_fold_with(self)
}
- fn fold_predicate(
+ fn try_fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
- p.super_fold_with(self)
+ p.try_super_fold_with(self)
}
- fn fold_mir_const(
+ fn try_fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
}
}
+// 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
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- let t = ty.super_fold_with(self)?;
- Ok((self.ty_op)(t))
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let t = ty.super_fold_with(self);
+ (self.ty_op)(t)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- let r = r.super_fold_with(self)?;
- Ok((self.lt_op)(r))
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let r = r.super_fold_with(self);
+ (self.lt_op)(r)
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- let ct = ct.super_fold_with(self)?;
- Ok((self.ct_op)(ct))
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ let ct = ct.super_fold_with(self);
+ (self.ct_op)(ct)
}
}
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)).into_ok()
+ value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
}
/// Invoke `callback` on every region appearing free in `value`.
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
}
#[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
debug!(?self.current_index, "skipped bound region");
*self.skipped_regions = true;
- Ok(r)
+ r
}
_ => {
debug!(?self.current_index, "folding free region");
- Ok((self.fold_region_fn)(r, self.current_index))
+ (self.fold_region_fn)(r, self.current_index)
}
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
if let Some(fld_t) = self.fld_t.as_mut() {
let ty = fld_t(bound_ty);
- return Ok(ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()));
+ return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
}
}
_ if t.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- Ok(t)
+ t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
if let Some(fld_r) = self.fld_r.as_mut() {
// debruijn index. Then we adjust it to the
// correct depth.
assert_eq!(debruijn1, ty::INNERMOST);
- Ok(self.tcx.mk_region(ty::ReLateBound(debruijn, br)))
+ self.tcx.mk_region(ty::ReLateBound(debruijn, br))
} else {
- Ok(region)
+ region
};
}
}
_ => {}
}
- Ok(r)
+ r
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
if debruijn == self.current_index =>
{
if let Some(fld_c) = self.fld_c.as_mut() {
let ct = fld_c(bound_const, ty);
- return Ok(ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()));
+ return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
}
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- Ok(ct)
+ ct
}
}
value
} else {
let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
- value.fold_with(&mut replacer).into_ok()
+ value.fold_with(&mut replacer)
};
(value, region_map)
}
} else {
let mut replacer =
BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
- value.fold_with(&mut replacer).into_ok()
+ value.fold_with(&mut replacer)
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, br) => {
if self.amount == 0 || debruijn < self.current_index {
- Ok(r)
+ r
} else {
let debruijn = debruijn.shifted_in(self.amount);
let shifted = ty::ReLateBound(debruijn, br);
- Ok(self.tcx.mk_region(shifted))
+ self.tcx.mk_region(shifted)
}
}
- _ => Ok(r),
+ _ => r,
}
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Bound(debruijn, bound_ty) => {
if self.amount == 0 || debruijn < self.current_index {
- Ok(ty)
+ ty
} else {
let debruijn = debruijn.shifted_in(self.amount);
- Ok(self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)))
+ self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
}
}
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
if self.amount == 0 || debruijn < self.current_index {
- Ok(ct)
+ ct
} else {
let debruijn = debruijn.shifted_in(self.amount);
- Ok(self
- .tcx
- .mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }))
+ self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
}
} else {
ct.super_fold_with(self)
{
debug!("shift_vars(value={:?}, amount={})", value, amount);
- value.fold_with(&mut Shifter::new(tcx, amount)).into_ok()
+ value.fold_with(&mut Shifter::new(tcx, amount))
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
///
/// FIXME(@lcnr): explain this function a bit more
pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
- v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }).into_ok()
+ v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
ty.super_fold_with(self)
} else {
- Ok(ty)
+ ty
}
}
- fn fold_predicate(
- &mut self,
- pred: ty::Predicate<'tcx>,
- ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
pred.super_fold_with(self)
} else {
- Ok(pred)
+ pred
}
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
debug!("fold_ty: ty={:?}", ty);
match ty.kind {
ty::Closure(def_id, substs) => {
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
- Ok(if substs == polymorphized_substs {
+ if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_closure(def_id, polymorphized_substs)
- })
+ }
}
ty::Generator(def_id, substs, movability) => {
let polymorphized_substs = polymorphize(
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
- Ok(if substs == polymorphized_substs {
+ if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_generator(def_id, polymorphized_substs, movability)
- })
+ }
}
_ => ty.super_fold_with(self),
}
// ..and polymorphize any closures/generators captured as upvars.
let upvars_ty = upvars_ty.unwrap();
let polymorphized_upvars_ty = upvars_ty.fold_with(
- &mut PolymorphizationFolder { tcx }).into_ok();
+ &mut PolymorphizationFolder { tcx });
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
ty::GenericArg::from(polymorphized_upvars_ty)
},
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>>(
+ fn try_super_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
- Ok(ParamEnv::new(self.caller_bounds().fold_with(folder)?, self.reveal().fold_with(folder)?))
+ 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 {
- value
- .fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
- .into_ok()
+ value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+ }
+ }
+
+ /// 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)
}
}
}
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
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- Ok(self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty())
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
}
- fn fold_const(
+ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
+ }
+
+ #[inline]
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ 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> {
- Ok(self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const())
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(*c)),
+ }
}
- #[inline]
- fn fold_mir_const(
+ 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);
- Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
_ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
return t.super_fold_with(self);
}
_ => {}
}
- Ok(t)
+ t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let name = &mut self.name;
let region = match *r {
ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
}
}
}
- _ => return Ok(r),
+ _ => return r,
};
if let ty::ReLateBound(debruijn1, br) = *region {
assert_eq!(debruijn1, ty::INNERMOST);
- Ok(self.tcx.mk_region(ty::ReLateBound(self.current_index, br)))
+ self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
} else {
- Ok(region)
+ region
}
}
}
name: &mut name,
region_map: BTreeMap::new(),
};
- let new_value = value.clone().skip_binder().fold_with(&mut folder).into_ok();
+ let new_value = value.clone().skip_binder().fold_with(&mut folder);
let region_map = folder.region_map;
start_or_continue(&mut self, "", "> ");
(new_value, region_map)
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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
Ok(self)
}
}
impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
- Ok((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) -> Result<(A, B, C), F::Error> {
- Ok((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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// FIXME: Reuse the `Rc` here.
- Ok(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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// FIXME: Reuse the `Arc` here.
- Ok(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) -> Result<Self, F::Error> {
- self.try_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) -> Result<Self, F::Error> {
- self.try_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) -> Result<Self, F::Error> {
- self.try_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) -> Result<Self, F::Error> {
- self.try_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) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::ty::InstanceDef::*;
Ok(Self {
- substs: self.substs.fold_with(folder)?,
+ 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)?),
},
})
}
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- Ok(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) -> Result<Self, F::Error> {
+ 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
Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
- let new = self.inner.kind.fold_with(folder)?;
+ 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))
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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) -> Result<Self, F::Error> {
- self.try_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) -> Result<Self, F::Error> {
- 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 {
Ok(folder.tcx().mk_const(ty::Const { ty, val }))
} else {
}
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- 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) -> Result<Self, F::Error> {
+ 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.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)?),
+ 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(..)
}
impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
Ok(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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,
})
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ 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,
})
}
/// 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"),
}
}
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) -> Result<Self, F::Error> {
+ 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).map(Into::into),
- GenericArgKind::Type(ty) => ty.fold_with(folder).map(Into::into),
- GenericArgKind::Const(ct) => ct.fold_with(folder).map(Into::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) -> Result<Self, F::Error> {
+ 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)?;
+ 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] {
Ok(self)
} else {
0 => Ok(self),
_ => {
let params: SmallVec<[_; 8]> =
- self.iter().map(|k| k.fold_with(folder)).collect::<Result<_, _>>()?;
+ self.iter().map(|k| k.try_fold_with(folder)).collect::<Result<_, _>>()?;
if params[..] == self[..] {
Ok(self)
} else {
span: Option<Span>,
) -> T {
let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
- self.fold_with(&mut folder).into_ok()
+ self.fold_with(&mut folder)
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.binders_passed += 1;
- let t = t.super_fold_with(self)?;
+ let t = t.super_fold_with(self);
self.binders_passed -= 1;
- Ok(t)
+ t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
ty::ReEarlyBound(data) => {
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
- Some(GenericArgKind::Lifetime(lt)) => Ok(self.shift_region_through_binders(lt)),
+ Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
let msg = format!(
}
}
}
- _ => Ok(r),
+ _ => r,
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.potentially_needs_subst() {
- return Ok(t);
+ return t;
}
match *t.kind() {
- ty::Param(p) => Ok(self.ty_for_param(p, t)),
+ ty::Param(p) => self.ty_for_param(p, t),
_ => t.super_fold_with(self),
}
}
- fn fold_const(
- &mut self,
- c: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::ConstKind::Param(p) = c.val {
- Ok(self.const_for_param(p, c))
+ self.const_for_param(p, c)
} else {
c.super_fold_with(self)
}
}
#[inline]
- fn fold_mir_const(
- &mut self,
- c: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
}
//! 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};
if self.found_any_recursion {
return None;
}
- let substs = substs.fold_with(self).into_ok();
+ let substs = substs.fold_with(self);
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
Some(expanded_ty) => expanded_ty,
None => {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
- let expanded_ty = self.fold_ty(concrete_ty).into_ok();
+ let expanded_ty = self.fold_ty(concrete_ty);
self.expanded_cache.insert((def_id, substs), expanded_ty);
expanded_ty
}
self.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Opaque(def_id, substs) = t.kind {
- Ok(self.expand_opaque_ty(def_id, substs).unwrap_or(t))
+ self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else if t.has_opaque_types() {
t.super_fold_with(self)
} else {
- Ok(t)
+ t
}
}
}
[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))
}
}
}
intern: impl FnOnce(TyCtxt<'tcx>, &[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
- match iter.by_ref().enumerate().find_map(|(i, t)| match t.fold_with(folder) {
+ 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)),
}) {
new_list.extend_from_slice(&list[..i]);
new_list.push(new_t);
for t in iter {
- new_list.push(t.fold_with(folder)?)
+ new_list.push(t.try_fold_with(folder)?)
}
Ok(intern(folder.tcx(), &new_list))
}
check_recursion: false,
tcx,
};
- val.fold_with(&mut visitor).into_ok()
+ val.fold_with(&mut visitor)
}
pub fn provide(providers: &mut ty::query::Providers) {
} else {
Some(destination_block)
},
+ cleanup: None,
},
);
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ this.diverge_from(block);
+ }
destination_block.unit()
}
| TerminatorKind::Call { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::InlineAsm { .. }
),
"diverge_from called on block with terminator that cannot unwind."
);
| TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::FalseUnwind { unwind, .. }
| TerminatorKind::Call { cleanup: unwind, .. }
- | TerminatorKind::Assert { cleanup: unwind, .. } => {
+ | TerminatorKind::Assert { cleanup: unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
*unwind = Some(to);
}
TerminatorKind::Goto { .. }
| TerminatorKind::Unreachable
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => {
+ | TerminatorKind::FalseEdge { .. } => {
span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
}
}
use std::ops::RangeInclusive;
use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
+use super::{
+ Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget,
+};
pub trait Direction {
fn is_forward() -> bool;
// Apply terminator-specific edge effects.
//
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
- mir::TerminatorKind::Call {
- destination: Some((return_place, dest)),
- ref func,
- ref args,
- ..
+ mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. }
+ if dest == bb =>
+ {
+ let mut tmp = exit_state.clone();
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::Call(return_place),
+ );
+ propagate(pred, &tmp);
+ }
+ mir::TerminatorKind::InlineAsm {
+ destination: Some(dest), ref operands, ..
} if dest == bb => {
let mut tmp = exit_state.clone();
- analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place);
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::InlineAsm(operands),
+ );
propagate(pred, &tmp);
}
| mir::TerminatorKind::Drop { unwind: Some(unwind), .. }
| mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. }
| mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. }
+ | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
if unwind == bb =>
{
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
propagate(target, exit_state);
}
- Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => {
+ Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => {
if let Some(unwind) = cleanup {
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
propagate(unwind, exit_state);
if let Some((dest_place, target)) = destination {
// N.B.: This must be done *last*, otherwise the unwind path will see the call
// return effect.
- analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place);
+ analysis.apply_call_return_effect(
+ exit_state,
+ bb,
+ CallReturnPlaces::Call(dest_place),
+ );
propagate(target, exit_state);
}
}
- InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => {
+ InlineAsm {
+ template: _,
+ ref operands,
+ options: _,
+ line_spans: _,
+ destination,
+ cleanup,
+ } => {
+ if let Some(unwind) = cleanup {
+ if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
+ propagate(unwind, exit_state);
+ }
+ }
+
if let Some(target) = destination {
+ // N.B.: This must be done *last*, otherwise the unwind path will see the call
+ // return effect.
+ analysis.apply_call_return_effect(
+ exit_state,
+ bb,
+ CallReturnPlaces::InlineAsm(operands),
+ );
propagate(target, exit_state);
}
}
use rustc_middle::mir::{self, BasicBlock, Body, Location};
use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
-use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor};
+use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OutputStyle {
// for the basic block itself. That way, we could display terminator-specific effects for
// backward dataflow analyses as well as effects for `SwitchInt` terminators.
match terminator.kind {
- mir::TerminatorKind::Call {
- destination: Some((return_place, _)),
- ref func,
- ref args,
- ..
- } => {
+ mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => {
self.write_row(w, "", "(on successful return)", |this, w, fmt| {
let state_on_unwind = this.results.get().clone();
this.results.apply_custom_effect(|analysis, state| {
- analysis.apply_call_return_effect(state, block, func, args, return_place);
+ analysis.apply_call_return_effect(
+ state,
+ block,
+ CallReturnPlaces::Call(return_place),
+ );
});
write!(
})?;
}
+ mir::TerminatorKind::InlineAsm { destination: Some(_), ref operands, .. } => {
+ self.write_row(w, "", "(on successful return)", |this, w, fmt| {
+ let state_on_unwind = this.results.get().clone();
+ this.results.apply_custom_effect(|analysis, state| {
+ analysis.apply_call_return_effect(
+ state,
+ block,
+ CallReturnPlaces::InlineAsm(operands),
+ );
+ });
+
+ write!(
+ w,
+ r#"<td balign="left" colspan="{colspan}" {fmt} align="left">{diff}</td>"#,
+ colspan = this.style.num_state_columns(),
+ fmt = fmt,
+ diff = diff_pretty(
+ this.results.get(),
+ &state_on_unwind,
+ this.results.analysis()
+ ),
+ )
+ })?;
+ }
+
_ => {}
};
&self,
state: &mut Self::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
);
/// Updates the current dataflow state with the effect of resuming from a `Yield` terminator.
&self,
trans: &mut impl GenKill<Self::Idx>,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
);
/// See `Analysis::apply_yield_resume_effect`.
&self,
state: &mut A::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- self.call_return_effect(state, block, func, args, return_place);
+ self.call_return_effect(state, block, return_places);
}
fn apply_yield_resume_effect(
fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
}
+/// List of places that are written to after a successful (non-unwind) return
+/// from a `Call` or `InlineAsm`.
+pub enum CallReturnPlaces<'a, 'tcx> {
+ Call(mir::Place<'tcx>),
+ InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]),
+}
+
+impl<'tcx> CallReturnPlaces<'_, 'tcx> {
+ pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) {
+ match *self {
+ Self::Call(place) => f(place),
+ Self::InlineAsm(operands) => {
+ for op in operands {
+ match *op {
+ mir::InlineAsmOperand::Out { place: Some(place), .. }
+ | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests;
&self,
_state: &mut Self::Domain,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
use super::*;
-use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
//!
//! A local will be maybe initialized if *any* projections of that local might be initialized.
-use crate::GenKill;
+use crate::{CallReturnPlaces, GenKill};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- trans.gen(return_place.local)
+ return_places.for_each(|place| trans.gen(place.local));
}
/// See `Analysis::apply_yield_resume_effect`.
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
match context {
// These are handled specially in `call_return_effect` and `yield_resume_effect`.
- PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
+ PlaceContext::MutatingUse(
+ MutatingUseContext::Call
+ | MutatingUseContext::AsmOutput
+ | MutatingUseContext::Yield,
+ ) => {}
// Otherwise, when a place is mutated, we must consider it possibly initialized.
PlaceContext::MutatingUse(_) => self.trans.gen(local),
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Local, Location};
-use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
/// A [live-variable dataflow analysis][liveness].
///
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- if let Some(local) = dest_place.as_local() {
- trans.kill(local);
- }
+ return_places.for_each(|place| {
+ if let Some(local) = place.as_local() {
+ trans.kill(local);
+ }
+ });
}
fn yield_resume_effect(
// destination place for a `Call` return or `Yield` resume respectively. Since this is
// only a `Def` when the function returns successfully, we handle this case separately
// in `call_return_effect` above.
- PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
+ PlaceContext::MutatingUse(
+ MutatingUseContext::Call
+ | MutatingUseContext::AsmOutput
+ | MutatingUseContext::Yield,
+ ) => None,
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
- | MutatingUseContext::AsmOutput
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,
use crate::drop_flag_effects_for_function_entry;
use crate::drop_flag_effects_for_location;
use crate::elaborate_drops::DropFlagState;
-use crate::framework::SwitchIntEdgeEffects;
+use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects};
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::on_lookup_result_bits;
use crate::MoveDataParamEnv;
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 1 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.gen(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 1 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.gen(mpi);
+ },
+ );
+ });
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 0 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.kill(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 0 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.kill(mpi);
+ },
+ );
+ });
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 1 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.gen(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 1 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.gen(mpi);
+ },
+ );
+ });
}
}
&self,
trans: &mut impl GenKill<Self::Idx>,
block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
let move_data = self.move_data();
let init_loc_map = &move_data.init_loc_map;
pub use super::*;
use crate::storage::AlwaysLiveLocals;
-use crate::{GenKill, Results, ResultsRefCursor};
+use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use std::cell::RefCell;
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
terminator: &mir::Terminator<'tcx>,
loc: Location,
) {
- match &terminator.kind {
+ match terminator.kind {
// For call terminators the destination requires storage for the call
// and after the call returns successfully, but not after a panic.
// Since `propagate_call_unwind` doesn't exist, we have to kill the
trans.kill(place.local);
}
+ // The same applies to InlineAsm outputs.
+ TerminatorKind::InlineAsm { ref operands, .. } => {
+ CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
+ }
+
// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.
TerminatorKind::Call { destination: None, .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::Goto { .. }
- | TerminatorKind::InlineAsm { .. }
| TerminatorKind::Resume
| TerminatorKind::Return
| TerminatorKind::SwitchInt { .. }
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- trans.gen(return_place.local);
+ return_places.for_each(|place| trans.gen(place.local));
}
fn yield_resume_effect(
on_lookup_result_bits,
};
pub use self::framework::{
- fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine,
- Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor,
- ResultsVisitable, ResultsVisitor,
+ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
+ Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
+ ResultsRefCursor, ResultsVisitable, ResultsVisitor,
};
use self::move_paths::MoveData;
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
pub struct SanityCheck;
+// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
impl<'tcx> MirPass<'tcx> for SanityCheck {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
use crate::has_rustc_mir_with;
}
impl<'tcx> MirPass<'tcx> for AddRetag {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !tcx.sess.opts.debugging_opts.mir_emit_retag {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.debugging_opts.mir_emit_retag
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// We need an `AllCallEdges` pass before we can do any work.
super::add_call_guards::AllCallEdges.run_pass(tcx, body);
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;
-use crate::MirPass;
+use crate::MirLint;
pub struct CheckConstItemMutation;
-impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
checker.visit_body(&body);
}
use rustc_span::symbol::sym;
use crate::util;
-use crate::MirPass;
+use crate::MirLint;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
pub struct CheckPackedRef;
-impl<'tcx> MirPass<'tcx> for CheckPackedRef {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckPackedRef {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let source_info = SourceInfo::outermost(body.span);
let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
MutatingUseContext::Store
| MutatingUseContext::Drop
| MutatingUseContext::AsmOutput
+ | MutatingUseContext::LlvmAsmOutput
)
);
// If this is just an assignment, determine if the assigned type needs dropping.
pub struct ConstDebugInfo;
impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
+ }
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running ConstDebugInfo on {:?}", body.source);
for (local, constant) in find_optimization_oportunities(body) {
pub struct ConstGoto;
impl<'tcx> MirPass<'tcx> for ConstGoto {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
trace!("Running ConstGoto on {:?}", body.source);
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let mut opt_finder =
pub struct ConstProp;
impl<'tcx> MirPass<'tcx> for ConstProp {
+ fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
+ // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
+ // runs even when MIR optimizations are disabled. We should separate the lint out from the
+ // transform and move the lint as early in the pipeline as possible.
+ true
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// will be evaluated by miri and produce its errors there
if body.source.promoted.is_some() {
// These are just stores, where the storing is not propagatable, but there may be later
// mutations of the same local via `Store`
| MutatingUse(MutatingUseContext::Call)
+ | MutatingUse(MutatingUseContext::AsmOutput)
// Actual store that can possibly even propagate a value
| MutatingUse(MutatingUseContext::Store) => {
if !self.found_assignment.insert(local) {
// These could be propagated with a smarter analysis or just some careful thinking about
// whether they'd be fine right now.
- MutatingUse(MutatingUseContext::AsmOutput)
+ MutatingUse(MutatingUseContext::LlvmAsmOutput)
| MutatingUse(MutatingUseContext::Yield)
| MutatingUse(MutatingUseContext::Drop)
| MutatingUse(MutatingUseContext::Retag)
pub struct InstrumentCoverage;
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.instrument_coverage()
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
let mir_source = mir_body.source;
pub struct DeduplicateBlocks;
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
debug!("Running DeduplicateBlocks on `{:?}`", body.source);
let duplicates = find_duplicates(body);
let has_opts_to_apply = !duplicates.is_empty();
pub struct DestinationPropagation;
impl<'tcx> MirPass<'tcx> for DestinationPropagation {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // FIXME(#79191, #82678)
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
-
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ // FIXME(#79191, #82678): This is unsound.
+ //
// Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove
// storage statements at the moment).
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
let candidates = find_candidates(tcx, body);
}
}
- 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.
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
// The intended semantics here aren't documented, we just assume that nothing that
// could be written to by the assembly may overlap with any other operands.
pub struct EarlyOtherwiseBranch;
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// FIXME(#78496)
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+ }
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running EarlyOtherwiseBranch on {:?}", body.source);
+
// we are only interested in this bb if the terminator is a switchInt
let bbs_with_switch =
body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::DropLowering)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
use rustc_span::{symbol::sym, Span};
use rustc_target::spec::abi::Abi;
-use crate::MirPass;
+use crate::MirLint;
pub struct FunctionItemReferences;
-impl<'tcx> MirPass<'tcx> for FunctionItemReferences {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = FunctionItemRefChecker { tcx, body };
checker.visit_body(&body);
}
}
impl<'tcx> MirPass<'tcx> for StateTransform {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::GeneratorLowering)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let yield_ty = if let Some(yield_ty) = body.yield_ty() {
yield_ty
source_info: SourceInfo,
}
-/// Returns true if MIR inlining is enabled in the current compilation session.
-crate fn is_enabled(tcx: TyCtxt<'_>) -> bool {
- if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir {
- return enabled;
- }
-
- tcx.sess.mir_opt_level() >= 3
-}
-
impl<'tcx> MirPass<'tcx> for Inline {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !is_enabled(tcx) {
- return;
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ if let Some(enabled) = sess.opts.debugging_opts.inline_mir {
+ return enabled;
}
+ sess.opts.mir_opt_level() >= 3
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
let _guard = span.enter();
if inline(tcx, body) {
}
}
TerminatorKind::Resume => cost += RESUME_PENALTY,
+ TerminatorKind::InlineAsm { cleanup, .. } => {
+ cost += INSTR_COST;
+
+ if cleanup.is_some() {
+ cost += LANDINGPAD_PENALTY;
+ }
+ }
_ => cost += INSTR_COST,
}
{
bug!("False unwinds should have been removed before inlining")
}
- TerminatorKind::InlineAsm { ref mut destination, .. } => {
+ TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => {
if let Some(ref mut tgt) = *destination {
*tgt = self.map_block(*tgt);
+ } else if !self.in_cleanup_block {
+ // Unless this inline asm is in a cleanup block, add an unwind edge to
+ // the original call's cleanup block
+ *cleanup = self.cleanup_block;
}
}
}
pub struct InstCombine;
impl<'tcx> MirPass<'tcx> for InstCombine {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
let ctx = InstCombineContext { tcx, local_decls };
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::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
+#[macro_use]
+mod pass_manager;
+
+use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+
mod abort_unwinding_calls;
mod add_call_guards;
mod add_moves_for_packed_drops;
mod instcombine;
mod lower_intrinsics;
mod lower_slice_len;
+mod marker;
mod match_branches;
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) {
set
}
-fn run_passes(
- tcx: TyCtxt<'tcx>,
- body: &mut Body<'tcx>,
- mir_phase: MirPhase,
- passes: &[&[&dyn MirPass<'tcx>]],
-) {
- let phase_index = mir_phase.phase_index();
- let validate = tcx.sess.opts.debugging_opts.validate_mir;
-
- if body.phase >= mir_phase {
- return;
- }
-
- if validate {
- validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase }
- .run_pass(tcx, body);
- }
-
- let mut index = 0;
- let mut run_pass = |pass: &dyn MirPass<'tcx>| {
- let run_hooks = |body: &_, index, is_after| {
- let disambiguator = if is_after { "after" } else { "before" };
- dump_mir(
- tcx,
- Some(&format_args!("{:03}-{:03}", phase_index, index)),
- &pass.name(),
- &disambiguator,
- body,
- |_, _| Ok(()),
- );
- };
- run_hooks(body, index, false);
- pass.run_pass(tcx, body);
- run_hooks(body, index, true);
-
- if validate {
- validate::Validator {
- when: format!("after {} in phase {:?}", pass.name(), mir_phase),
- mir_phase,
- }
- .run_pass(tcx, body);
- }
-
- index += 1;
- };
-
- for pass_group in passes {
- for pass in *pass_group {
- run_pass(*pass);
- }
- }
-
- body.phase = mir_phase;
-
- if mir_phase == MirPhase::Optimization {
- validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
- .run_pass(tcx, body);
- }
-}
-
fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
let const_kind = tcx.hir().body_const_context(def.did);
rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
- run_passes(
+ pm::run_passes(
tcx,
&mut body,
- MirPhase::Const,
- &[&[
+ &[
// MIR-level lints.
- &check_packed_ref::CheckPackedRef,
- &check_const_item_mutation::CheckConstItemMutation,
- &function_item_references::FunctionItemReferences,
+ &Lint(check_packed_ref::CheckPackedRef),
+ &Lint(check_const_item_mutation::CheckConstItemMutation),
+ &Lint(function_item_references::FunctionItemReferences),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::new("initial"),
- &rustc_peek::SanityCheck,
- ]],
+ &rustc_peek::SanityCheck, // Just a lint
+ &marker::PhaseChange(MirPhase::Const),
+ ],
);
tcx.alloc_steal_mir(body)
}
}
body.required_consts = required_consts;
+ // What we need to run borrowck etc.
let promote_pass = promote_consts::PromoteTemps::default();
- let promote: &[&dyn MirPass<'tcx>] = &[
- // What we need to run borrowck etc.
- &promote_pass,
- &simplify::SimplifyCfg::new("promote-consts"),
- ];
-
- let opt_coverage: &[&dyn MirPass<'tcx>] =
- if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] };
-
- run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
+ pm::run_passes(
+ tcx,
+ &mut body,
+ &[
+ &promote_pass,
+ &simplify::SimplifyCfg::new("promote-consts"),
+ &coverage::InstrumentCoverage,
+ ],
+ );
let promoted = promote_pass.promoted_fragments.into_inner();
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
// Technically we want to not run on regular const items, but oli-obk doesn't know how to
// conveniently detect that at this point without looking at the HIR.
hir::ConstContext::Const => {
- #[rustfmt::skip]
- let optimizations: &[&dyn MirPass<'_>] = &[
- &const_prop::ConstProp,
- ];
-
- #[rustfmt::skip]
- run_passes(
+ pm::run_passes(
tcx,
&mut body,
- MirPhase::Optimization,
- &[
- optimizations,
- ],
+ &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimization)],
);
}
}
let def = ty::WithOptConstParam::unknown(did);
// Do not compute the mir call graph without said call graph actually being used.
- if inline::is_enabled(tcx) {
+ if inline::Inline.is_enabled(&tcx.sess) {
let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
}
}
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
+ // IMPORTANT
+ pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
+
+ // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
+ if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
+ pm::run_passes(
+ tcx,
+ &mut body,
+ &[
+ &simplify::SimplifyCfg::new("remove-false-edges"),
+ &remove_uninit_drops::RemoveUninitDrops,
+ ],
+ );
+ check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
+ }
+
run_post_borrowck_cleanup_passes(tcx, &mut body);
- check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
+ assert!(body.phase == MirPhase::DropLowering);
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"),
&deaggregator::Deaggregator,
];
- run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]);
+ pm::run_passes(tcx, body, post_borrowck_cleanup);
}
fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let mir_opt_level = tcx.sess.mir_opt_level();
+ fn o1<T>(x: T) -> WithMinOptLevel<T> {
+ WithMinOptLevel(1, x)
+ }
// Lowering generator control-flow and variables has to happen before we do anything else
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
- let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
- &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
- &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
- &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
- &unreachable_prop::UnreachablePropagation,
- &uninhabited_enum_branching::UninhabitedEnumBranching,
- &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
- &inline::Inline,
- &generator::StateTransform,
- ];
-
- // Even if we don't do optimizations, we still have to lower generators for codegen.
- let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform];
-
- // The main optimizations that we do on MIR.
- let optimizations: &[&dyn MirPass<'tcx>] = &[
- &remove_storage_markers::RemoveStorageMarkers,
- &remove_zsts::RemoveZsts,
- &const_goto::ConstGoto,
- &remove_unneeded_drops::RemoveUnneededDrops,
- &match_branches::MatchBranchSimplification,
- // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
- &multiple_return_terminators::MultipleReturnTerminators,
- &instcombine::InstCombine,
- &separate_const_switch::SeparateConstSwitch,
- &const_prop::ConstProp,
- &simplify_branches::SimplifyBranches::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"),
- &remove_noop_landing_pads::RemoveNoopLandingPads,
- &simplify::SimplifyCfg::new("final"),
- &nrvo::RenameReturnPlace,
- &const_debuginfo::ConstDebugInfo,
- &simplify::SimplifyLocals,
- &multiple_return_terminators::MultipleReturnTerminators,
- &deduplicate_blocks::DeduplicateBlocks,
- ];
-
- // Optimizations to run even if mir optimizations have been disabled.
- let no_optimizations: &[&dyn MirPass<'tcx>] = &[
- // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
- &const_prop::ConstProp,
- ];
-
- // Some cleanup necessary at least for LLVM and potentially other codegen backends.
- let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
- &add_call_guards::CriticalCallEdges,
- // Dump the end result for testing and debugging purposes.
- &dump_mir::Marker("PreCodegen"),
- ];
-
- // End of pass declarations, now actually run the passes.
- // Generator Lowering
- #[rustfmt::skip]
- run_passes(
+ pm::run_passes(
tcx,
body,
- MirPhase::GeneratorLowering,
&[
- if mir_opt_level > 0 {
- optimizations_with_generators
- } else {
- no_optimizations_with_generators
- }
+ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
+ &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
+ &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
+ &unreachable_prop::UnreachablePropagation,
+ &uninhabited_enum_branching::UninhabitedEnumBranching,
+ &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
+ &inline::Inline,
+ &generator::StateTransform,
],
);
- // Main optimization passes
- #[rustfmt::skip]
- run_passes(
+ assert!(body.phase == MirPhase::GeneratorLowering);
+
+ // The main optimizations that we do on MIR.
+ pm::run_passes(
tcx,
body,
- MirPhase::Optimization,
&[
- if mir_opt_level > 0 { optimizations } else { no_optimizations },
- pre_codegen_cleanup,
+ &remove_storage_markers::RemoveStorageMarkers,
+ &remove_zsts::RemoveZsts,
+ &const_goto::ConstGoto,
+ &remove_unneeded_drops::RemoveUnneededDrops,
+ &match_branches::MatchBranchSimplification,
+ // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
+ &multiple_return_terminators::MultipleReturnTerminators,
+ &instcombine::InstCombine,
+ &separate_const_switch::SeparateConstSwitch,
+ //
+ // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
+ &const_prop::ConstProp,
+ //
+ // FIXME: The old pass manager ran this only at mir-opt-level >= 1, but
+ // const-prop runs unconditionally. Should this run unconditionally as well?
+ &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
+ &early_otherwise_branch::EarlyOtherwiseBranch,
+ &simplify_comparison_integral::SimplifyComparisonIntegral,
+ &simplify_try::SimplifyArmIdentity,
+ &simplify_try::SimplifyBranchSame,
+ &dest_prop::DestinationPropagation,
+ &o1(simplify_branches::SimplifyConstCondition::new("final")),
+ &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
+ &o1(simplify::SimplifyCfg::new("final")),
+ &nrvo::RenameReturnPlace,
+ &const_debuginfo::ConstDebugInfo,
+ &simplify::SimplifyLocals,
+ &multiple_return_terminators::MultipleReturnTerminators,
+ &deduplicate_blocks::DeduplicateBlocks,
+ // Some cleanup necessary at least for LLVM and potentially other codegen backends.
+ &add_call_guards::CriticalCallEdges,
+ &marker::PhaseChange(MirPhase::Optimization),
+ // Dump the end result for testing and debugging purposes.
+ &dump_mir::Marker("PreCodegen"),
],
);
}
pub struct LowerSliceLenCalls;
impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
lower_slice_len_calls(tcx, body)
}
--- /dev/null
+use std::borrow::Cow;
+
+use crate::MirPass;
+use rustc_middle::mir::{Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+
+/// Changes the MIR phase without changing the MIR itself.
+pub struct PhaseChange(pub MirPhase);
+
+impl<'tcx> MirPass<'tcx> for PhaseChange {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(self.0)
+ }
+
+ fn name(&self) -> Cow<'_, str> {
+ Cow::from(format!("PhaseChange-{:?}", self.0))
+ }
+
+ fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
+}
/// ```
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 3
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
let param_env = tcx.param_env(def_id);
pub struct MultipleReturnTerminators;
impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// find basic blocks with no statement and a return terminator
let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
let def_id = body.source.def_id();
pub struct NormalizeArrayLen;
impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// early returns for edge cases of highly unrolled functions
if body.basic_blocks().len() > MAX_NUM_BLOCKS {
return;
pub struct RenameReturnPlace;
impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
- if tcx.sess.mir_opt_level() == 0 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
let def_id = body.source.def_id();
let returned_local = match local_eligible_for_nrvo(body) {
Some(l) => l,
--- /dev/null
+use std::borrow::Cow;
+
+use rustc_middle::mir::{self, Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+
+use crate::{validate, MirPass};
+
+/// Just like `MirPass`, except it cannot mutate `Body`.
+pub trait MirLint<'tcx> {
+ fn name(&self) -> Cow<'_, str> {
+ let name = std::any::type_name::<Self>();
+ if let Some(tail) = name.rfind(':') {
+ Cow::from(&name[tail + 1..])
+ } else {
+ Cow::from(name)
+ }
+ }
+
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>);
+}
+
+/// An adapter for `MirLint`s that implements `MirPass`.
+#[derive(Debug, Clone)]
+pub struct Lint<T>(pub T);
+
+impl<T> MirPass<'tcx> for Lint<T>
+where
+ T: MirLint<'tcx>,
+{
+ fn name(&self) -> Cow<'_, str> {
+ self.0.name()
+ }
+
+ fn is_enabled(&self, sess: &Session) -> bool {
+ self.0.is_enabled(sess)
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ self.0.run_lint(tcx, body)
+ }
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ false
+ }
+}
+
+pub struct WithMinOptLevel<T>(pub u32, pub T);
+
+impl<T> MirPass<'tcx> for WithMinOptLevel<T>
+where
+ T: MirPass<'tcx>,
+{
+ fn name(&self) -> Cow<'_, str> {
+ self.1.name()
+ }
+
+ fn is_enabled(&self, sess: &Session) -> bool {
+ sess.mir_opt_level() >= self.0 as usize
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ self.1.run_pass(tcx, body)
+ }
+
+ fn phase_change(&self) -> Option<MirPhase> {
+ self.1.phase_change()
+ }
+}
+
+pub fn run_passes(tcx: TyCtxt<'tcx>, body: &'mir mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
+ let start_phase = body.phase;
+ let mut cnt = 0;
+
+ let validate = tcx.sess.opts.debugging_opts.validate_mir;
+
+ if validate {
+ validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
+ }
+
+ for pass in passes {
+ if !pass.is_enabled(&tcx.sess) {
+ continue;
+ }
+
+ let name = pass.name();
+ let dump_enabled = pass.is_mir_dump_enabled();
+
+ if dump_enabled {
+ dump_mir(tcx, body, start_phase, &name, cnt, false);
+ }
+
+ pass.run_pass(tcx, body);
+
+ if dump_enabled {
+ dump_mir(tcx, body, start_phase, &name, cnt, true);
+ cnt += 1;
+ }
+
+ if let Some(new_phase) = pass.phase_change() {
+ if body.phase >= new_phase {
+ panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
+ }
+
+ body.phase = new_phase;
+ }
+
+ if validate {
+ validate_body(tcx, body, format!("after pass {}", pass.name()));
+ }
+ }
+
+ if validate || body.phase == MirPhase::Optimization {
+ validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
+ }
+}
+
+pub fn validate_body(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+ validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
+}
+
+pub fn dump_mir(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ phase: MirPhase,
+ pass_name: &str,
+ cnt: usize,
+ is_after: bool,
+) {
+ let phase_index = phase as u32;
+
+ mir::dump_mir(
+ tcx,
+ Some(&format_args!("{:03}-{:03}", phase_index, cnt)),
+ pass_name,
+ if is_after { &"after" } else { &"before" },
+ body,
+ |_, _| Ok(()),
+ );
+}
--- /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,
+ }
+ }
+ }
+}
/// code for these.
pub struct RemoveNoopLandingPads;
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.panic_strategy() == PanicStrategy::Abort {
- return;
+impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.panic_strategy() != PanicStrategy::Abort
}
- debug!("remove_noop_landing_pads({:?})", body);
-
- RemoveNoopLandingPads.remove_nop_landing_pads(body)
-}
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- remove_noop_landing_pads(tcx, body);
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ debug!("remove_noop_landing_pads({:?})", body);
+ self.remove_nop_landing_pads(body)
}
}
pub struct RemoveStorageMarkers;
impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if tcx.sess.emit_lifetime_markers() {
return;
--- /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::*;
pub struct RemoveZsts;
impl<'tcx> MirPass<'tcx> for RemoveZsts {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Avoid query cycles (generators require optimized MIR for layout).
if tcx.type_of(body.source.def_id()).is_generator() {
pub struct RevealAll;
impl<'tcx> MirPass<'tcx> for RevealAll {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
// Do not apply this transformation to generators.
- if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
- && body.generator.is_none()
- {
- let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
- RevealAllVisitor { tcx, param_env }.visit_body(body);
+ if body.generator.is_some() {
+ return;
}
+
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ RevealAllVisitor { tcx, param_env }.visit_body(body);
}
}
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,
- }
- }
}
pub struct SeparateConstSwitch;
impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// If execution did something, applying a simplification layer
// helps later passes optimize the copy away.
if separate_const_switch(body) > 0 {
use crate::util::expand_aggregate;
use crate::{
- abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
- run_passes, simplify,
+ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm,
+ remove_noop_landing_pads, simplify,
};
use rustc_middle::mir::patch::MirPatch;
use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
};
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
- run_passes(
+ // In some of the above cases, we seem to be invoking the passes for non-shim MIR bodies.
+ // If that happens, there's no need to run them again.
+ //
+ // FIXME: Is this intentional?
+ if result.phase >= MirPhase::Const {
+ return result;
+ }
+
+ pm::run_passes(
tcx,
&mut result,
- MirPhase::Const,
- &[&[
+ &[
&add_moves_for_packed_drops::AddMovesForPackedDrops,
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
&abort_unwinding_calls::AbortUnwindingCalls,
- ]],
+ &marker::PhaseChange(MirPhase::Const),
+ ],
);
debug!("make_shim({:?}) = {:?}", instance, result);
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running SimplifyLocals on {:?}", body.source);
simplify_locals(body, tcx);
-//! 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,
};
}
pub struct SimplifyComparisonIntegral;
impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
}
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if body.source.promoted.is_some() {
return;
pub struct UnreachablePropagation;
impl MirPass<'_> for UnreachablePropagation {
- fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
- // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
+ // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut unreachable_blocks = FxHashSet::default();
let mut replacements = FxHashMap::default();
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_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 =
);
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 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")
let attrs = self.parse_outer_attributes()?;
let param =
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ if this.eat_keyword_noexpect(kw::SelfUpper) {
+ // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
+ // as if `Self` never existed.
+ this.struct_span_err(
+ this.prev_token.span,
+ "unexpected keyword `Self` in generic parameters",
+ )
+ .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
+ .emit();
+
+ this.eat(&token::Comma);
+ }
+
let param = if this.check_lifetime() {
let lifetime = this.expect_lifetime();
// Parse lifetime parameter.
/// 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.
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 })
}
}
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";
}
}
+// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
+// from this check.
fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+ // Check for builtin attributes at the crate level
+ // which were unsuccessfully resolved due to cannot determine
+ // resolution for the attribute macro error.
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::repr,
sym::automatically_derived,
sym::start,
sym::rustc_main,
+ sym::derive,
+ sym::test,
+ sym::test_case,
+ sym::global_allocator,
+ sym::bench,
];
for attr in attrs {
- for attr_to_check in ATTRS_TO_CHECK {
- if attr.has_name(*attr_to_check) {
- tcx.sess
- .struct_span_err(
+ // This function should only be called with crate attributes
+ // which are inner attributes always but lets check to make sure
+ if attr.style == AttrStyle::Inner {
+ for attr_to_check in ATTRS_TO_CHECK {
+ if attr.has_name(*attr_to_check) {
+ let mut err = tcx.sess.struct_span_err(
attr.span,
&format!(
"`{}` attribute cannot be used at crate level",
attr_to_check.to_ident_string()
),
- )
- .emit();
+ );
+ // Only emit an error with a suggestion if we can create a
+ // string out of the attribute span
+ if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
+ let replacement = src.replace("#!", "#");
+ err.span_suggestion_verbose(
+ attr.span,
+ "perhaps you meant to use an outer attribute",
+ replacement,
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ err.emit()
+ }
}
}
}
#![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 {
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(min_specialization)]
-#![feature(thread_local_const_init)]
#![feature(extern_types)]
#[macro_use]
/// 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);
(generics.span, format!("<{}>", ident))
};
// Do not suggest if this is coming from macro expansion.
- if !span.from_expansion() {
+ if span.can_be_used_for_suggestions() {
return Some((
span.shrink_to_hi(),
msg,
);
err.span_label(lifetime_ref.span, "undeclared lifetime");
let mut suggests_in_band = false;
- let mut suggest_note = true;
+ let mut suggested_spans = vec![];
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
suggests_in_band = true;
(generics.span, format!("<{}>", lifetime_ref))
};
- if !span.from_expansion() {
+ if suggested_spans.contains(&span) {
+ continue;
+ }
+ suggested_spans.push(span);
+ if span.can_be_used_for_suggestions() {
err.span_suggestion(
span,
&format!("consider introducing lifetime `{}` here", lifetime_ref),
sugg,
Applicability::MaybeIncorrect,
);
- } else if suggest_note {
- suggest_note = false; // Avoid displaying the same help multiple times.
- err.span_label(
- span,
- &format!(
- "lifetime `{}` is missing in item created through this procedural \
- macro",
- lifetime_ref,
- ),
- );
}
}
MissingLifetimeSpot::HigherRanked { span, span_type } => {
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)?
};
edition: DEFAULT_EDITION,
json_artifact_notifications: false,
json_unused_externs: false,
+ json_future_incompat: false,
pretty: None,
working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
}
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 {
pub json_rendered: HumanReadableErrorType,
pub json_artifact_notifications: bool,
pub json_unused_externs: bool,
+ pub json_future_incompat: bool,
}
/// Parse the `--json` flag.
let mut json_color = ColorConfig::Never;
let mut json_artifact_notifications = false;
let mut json_unused_externs = false;
+ let mut json_future_incompat = false;
for option in matches.opt_strs("json") {
// For now conservatively forbid `--color` with `--json` since `--json`
// won't actually be emitting any colors and anything colorized is
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
"artifacts" => json_artifact_notifications = true,
"unused-externs" => json_unused_externs = true,
+ "future-incompat" => json_future_incompat = true,
s => early_error(
ErrorOutputType::default(),
&format!("unknown `--json` option `{}`", s),
json_rendered: json_rendered(json_color),
json_artifact_notifications,
json_unused_externs,
+ json_future_incompat,
}
}
let edition = parse_crate_edition(matches);
- let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
- parse_json(matches);
+ let JsonConfig {
+ json_rendered,
+ json_artifact_notifications,
+ json_unused_externs,
+ json_future_incompat,
+ } = parse_json(matches);
let error_format = parse_error_format(matches, color, json_rendered);
edition,
json_artifact_notifications,
json_unused_externs,
+ json_future_incompat,
pretty,
working_dir,
}
use std::env;
use std::fs;
+use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple);
- std::array::IntoIter::new([sysroot, Path::new(&rustlib_path), Path::new("lib")])
- .collect::<PathBuf>()
+ PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
}
/// This function checks if sysroot is found using env::args().next(), and if it
);
}
+impl Options {
+ pub fn mir_opt_level(&self) -> usize {
+ self.debugging_opts
+ .mir_opt_level
+ .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 })
+ }
+
+ pub fn instrument_coverage(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ != InstrumentCoverage::Off
+ }
+
+ pub fn instrument_coverage_except_unused_generics(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ == InstrumentCoverage::ExceptUnusedGenerics
+ }
+
+ pub fn instrument_coverage_except_unused_functions(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ == InstrumentCoverage::ExceptUnusedFunctions
+ }
+}
+
top_level_options!(
/// The top-level command-line options struct.
///
/// `true` if we're emitting a JSON blob containing the unused externs
json_unused_externs: bool [UNTRACKED],
+ /// `true` if we're emitting a JSON job containg a future-incompat report for lints
+ json_future_incompat: bool [TRACKED],
+
pretty: Option<PpMode> [UNTRACKED],
/// The (potentially remapped) working directory
v => {
let mut passes = vec![];
if parse_list(&mut passes, v) {
- *slot = Passes::Some(passes);
+ slot.extend(passes);
true
} else {
false
computed `block` spans (one span encompassing a block's terminator and \
all statements). If `-Z instrument-coverage` is also enabled, create \
an additional `.html` file showing the computed coverage spans."),
- emit_future_incompat_report: bool = (false, parse_bool, [UNTRACKED],
- "emits a future-incompatibility report for lints (RFC 2834)"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
}
fn emit_future_breakage(&self) {
- if !self.opts.debugging_opts.emit_future_incompat_report {
+ if !self.opts.json_future_incompat {
return;
}
self.opts.debugging_opts.binary_dep_depinfo
}
pub fn mir_opt_level(&self) -> usize {
- self.opts
- .debugging_opts
- .mir_opt_level
- .unwrap_or_else(|| if self.opts.optimize != config::OptLevel::No { 2 } else { 1 })
+ self.opts.mir_opt_level()
}
/// Gets the features enabled for the current compilation session.
/// Returns a list of directories where target-specific tool binaries are located.
pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple());
- let p = std::array::IntoIter::new([
+ let p = PathBuf::from_iter([
Path::new(&self.sysroot),
Path::new(&rustlib_path),
Path::new("bin"),
- ])
- .collect::<PathBuf>();
+ ]);
if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
}
}
pub fn instrument_coverage(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- != config::InstrumentCoverage::Off
+ self.opts.instrument_coverage()
}
pub fn instrument_coverage_except_unused_generics(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- == config::InstrumentCoverage::ExceptUnusedGenerics
+ self.opts.instrument_coverage_except_unused_generics()
}
pub fn instrument_coverage_except_unused_functions(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- == config::InstrumentCoverage::ExceptUnusedFunctions
+ self.opts.instrument_coverage_except_unused_functions()
}
pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
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);
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
-#![feature(thread_local_const_init)]
#[macro_use]
extern crate rustc_macros;
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
}
+ /// Gate suggestions that would not be appropriate in a context the user didn't write.
+ pub fn can_be_used_for_suggestions(self) -> bool {
+ !self.from_expansion()
+ // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
+ // the callsite span and the span will be pointing at different places. It also means that
+ // we can safely provide suggestions on this span.
+ || (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
+ && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
+ }
+
#[inline]
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
Span::new(lo, hi, SyntaxContext::root(), None)
Implied,
Input,
Into,
+ IntoFuture,
IntoIterator,
IoRead,
IoWrite,
asm_const,
asm_experimental_arch,
asm_sym,
+ asm_unwind,
assert,
assert_inhabited,
assert_macro,
inout,
instruction_set,
intel,
+ into_future,
into_iter,
intra_doc_pointers,
intrinsics,
maxnumf32,
maxnumf64,
may_dangle,
+ may_unwind,
maybe_uninit,
maybe_uninit_uninit,
maybe_uninit_zeroed,
// 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 });
}
}
#![feature(min_specialization)]
#![feature(step_trait)]
+use std::iter::FromIterator;
use std::path::{Path, PathBuf};
#[macro_use]
/// `"lib*/rustlib/x86_64-unknown-linux-gnu"`.
pub fn target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
let libdir = find_libdir(sysroot);
- std::array::IntoIter::new([
+ PathBuf::from_iter([
Path::new(libdir.as_ref()),
Path::new(RUST_LIB_DIR),
Path::new(target_triple),
])
- .collect::<PathBuf>()
}
/// The name of the directory rustc expects libraries to be located.
use rustc_span::symbol::{sym, Symbol};
use std::collections::BTreeMap;
use std::convert::TryFrom;
+use std::iter::FromIterator;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::str::FromStr;
// Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
// as a fallback.
let rustlib_path = crate::target_rustlib_path(&sysroot, &target_triple);
- let p = std::array::IntoIter::new([
+ let p = PathBuf::from_iter([
Path::new(sysroot),
Path::new(&rustlib_path),
Path::new("target.json"),
- ])
- .collect::<PathBuf>();
+ ]);
if p.is_file() {
return load_file(&p);
}
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
-#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
- let definition_ty = instantiated_ty
- .fold_with(&mut ReverseMapper::new(
- self.tcx,
- self.is_tainted_by_errors(),
- def_id,
- map,
- instantiated_ty,
- span,
- ))
- .into_ok();
+ let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
+ self.tcx,
+ self.is_tainted_by_errors(),
+ def_id,
+ map,
+ instantiated_ty,
+ span,
+ ));
debug!(?definition_ty);
definition_ty
) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
self.map_missing_regions_to_empty = true;
- let kind = kind.fold_with(self).into_ok();
+ let kind = kind.fold_with(self);
self.map_missing_regions_to_empty = false;
kind
}
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
- kind.fold_with(self).into_ok()
+ kind.fold_with(self)
}
}
}
#[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r {
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaraion.
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
- ty::ReLateBound(..) | ty::ReStatic => return Ok(r),
+ ty::ReLateBound(..) | ty::ReStatic => return r,
// If regions have been erased (by writeback), don't try to unerase
// them.
- ty::ReErased => return Ok(r),
+ ty::ReErased => return r,
// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
let generics = self.tcx().generics_of(self.opaque_type_def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
- Some(GenericArgKind::Lifetime(r1)) => Ok(r1),
+ Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
- Ok(self.tcx.lifetimes.re_root_empty)
+ self.tcx.lifetimes.re_root_empty
}
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
)
.emit();
}
- Ok(self.tcx.lifetimes.re_root_empty)
+ self.tcx.lifetimes.re_root_empty
}
None => {
self.tcx
)
.emit();
- Ok(self.tcx().lifetimes.re_static)
+ self.tcx().lifetimes.re_static
}
}
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Closure(def_id, substs) => {
// I am a horrible monster and I pray for death. When
}
}));
- Ok(self.tcx.mk_closure(def_id, substs))
+ self.tcx.mk_closure(def_id, substs)
}
ty::Generator(def_id, substs, movability) => {
}
}));
- Ok(self.tcx.mk_generator(def_id, substs, movability))
+ self.tcx.mk_generator(def_id, substs, movability)
}
ty::Param(param) => {
match self.map.get(&ty.into()).map(|k| k.unpack()) {
// Found it in the substitution list; replace with the parameter from the
// opaque type.
- Some(GenericArgKind::Type(t1)) => Ok(t1),
+ Some(GenericArgKind::Type(t1)) => t1,
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
None => {
debug!(?param, ?self.map);
)
.emit();
- Ok(self.tcx().ty_error())
+ self.tcx().ty_error()
}
}
}
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
trace!("checking const {:?}", ct);
// Find a const parameter
- Ok(match ct.val {
+ match ct.val {
ty::ConstKind::Param(..) => {
// Look it up in the substitution list.
match self.map.get(&ct.into()).map(|k| k.unpack()) {
}
_ => ct,
- })
+ }
}
}
self.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- Ok((match r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ (match r {
ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
_ => None,
})
- .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
+ .unwrap_or_else(|| r.super_fold_with(self))
}
}
let arg = self.recurse_build(source)?;
self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
}
-
+ ExprKind::Borrow{ arg, ..} => {
+ let arg_node = &self.body.exprs[*arg];
+
+ // Skip reborrows for now until we allow Deref/Borrow/AddressOf
+ // expressions.
+ // FIXME(generic_const_exprs): Verify/explain why this is sound
+ if let ExprKind::Deref {arg} = arg_node.kind {
+ self.recurse_build(arg)?
+ } else {
+ self.maybe_supported_error(
+ node.span,
+ "borrowing is not supported in generic constants",
+ )?
+ }
+ }
// FIXME(generic_const_exprs): We may want to support these.
- ExprKind::AddressOf { .. }
- | ExprKind::Borrow { .. }
- | ExprKind::Deref { .. } => self.maybe_supported_error(
+ ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error(
node.span,
- "dereferencing is not supported in generic constants",
+ "dereferencing or taking the address is not supported in generic constants",
)?,
ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error(
node.span,
// 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;
}
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
let infcx = self.infcx;
- Ok(self.var_map.entry(ty).or_insert_with(|| {
+ self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
span: DUMMY_SP,
})
- }))
+ })
} else {
ty.super_fold_with(self)
}
self.probe(|_| {
let mut selcx = SelectionContext::new(self);
- let cleaned_pred = pred
- .fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() })
- .into_ok();
+ let cleaned_pred =
+ pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
let cleaned_pred = super::project::normalize(
&mut selcx,
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(..),
match generics
.params
.iter()
- .map(|p| p.bounds_span().unwrap_or(p.span))
- .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
+ .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
+ .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
.max_by_key(|span| span.hi())
{
// `fn foo(t: impl Trait)`
None => (generics.span, format!("<{}>", type_param)),
// `fn foo<A>(t: impl Trait)`
// ^^^ suggest `<A, T: Trait>` here
- Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
+ Some(span) => (span, format!(", {}", type_param)),
},
// `fn foo(t: impl Trait)`
// ^ suggest `where <T as Trait>::A: Bound`
use rustc_span::{MultiSpan, Span};
use smallvec::SmallVec;
-use std::array;
use std::iter;
use std::ops::ControlFlow;
.to_predicate(tcx)
};
- let caller_bounds: Vec<Predicate<'tcx>> = param_env
- .caller_bounds()
- .iter()
- .chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
- .collect();
+ let caller_bounds: Vec<Predicate<'tcx>> =
+ param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect();
ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
};
if !needs_normalization(&value, self.param_env.reveal()) {
value
} else {
- value.fold_with(self).into_ok()
+ value.fold_with(self)
}
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.universes.push(None);
let t = t.super_fold_with(self);
self.universes.pop();
t
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !needs_normalization(&ty, self.param_env.reveal()) {
- return Ok(ty);
+ return ty;
}
// We try to be a little clever here as a performance optimization in
// replace bound vars if the current type is a `Projection` and we need
// to make sure we don't forget to fold the substs regardless.
- Ok(match *ty.kind() {
+ match *ty.kind() {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
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.super_fold_with(self),
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
self.selcx.infcx().report_overflow_error(&obligation, true);
}
- let substs = substs.super_fold_with(self)?;
+ let substs = substs.super_fold_with(self);
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.depth += 1;
- let folded_ty = self.fold_ty(concrete_ty)?;
+ let folded_ty = self.fold_ty(concrete_ty);
self.depth -= 1;
folded_ty
}
// register an obligation to *later* project, since we know
// there won't be bound vars there.
- let data = data.super_fold_with(self)?;
+ let data = data.super_fold_with(self);
let normalized_ty = normalize_projection_type(
self.selcx,
self.param_env,
let infcx = self.selcx.infcx();
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
- let data = data.super_fold_with(self)?;
+ let data = data.super_fold_with(self);
let normalized_ty = opt_normalize_projection_type(
self.selcx,
self.param_env,
.ok()
.flatten()
.map(|normalized_ty| {
- Ok({
- PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- normalized_ty,
- )
- })
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ normalized_ty,
+ )
})
- .unwrap_or_else(|| ty.super_fold_with(self))?;
+ .unwrap_or_else(|| ty.super_fold_with(self));
debug!(
?self.depth,
normalized_ty
}
- _ => ty.super_fold_with(self)?,
- })
+ _ => ty.super_fold_with(self),
+ }
}
- fn fold_const(
- &mut self,
- constant: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if self.selcx.tcx().lazy_normalization() {
- Ok(constant)
+ constant
} else {
- let constant = constant.super_fold_with(self)?;
- Ok(constant.eval(self.selcx.tcx(), self.param_env))
+ let constant = constant.super_fold_with(self);
+ constant.eval(self.selcx.tcx(), self.param_env)
}
}
}
universe_indices,
};
- let value = value.super_fold_with(&mut replacer).into_ok();
+ let value = value.super_fold_with(&mut replacer);
(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, _)
if debruijn.as_usize() + 1
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderRegion { universe, name: br.kind };
self.mapped_regions.insert(p, br);
- Ok(self.infcx.tcx.mk_region(ty::RePlaceholder(p)))
+ self.infcx.tcx.mk_region(ty::RePlaceholder(p))
}
- _ => Ok(r),
+ _ => r,
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Bound(debruijn, _)
if debruijn.as_usize() + 1
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderType { universe, name: bound_ty.var };
self.mapped_types.insert(p, bound_ty);
- Ok(self.infcx.tcx.mk_ty(ty::Placeholder(p)))
+ self.infcx.tcx.mk_ty(ty::Placeholder(p))
}
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
- _ => Ok(t),
+ _ => t,
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
if debruijn.as_usize() + 1
name: ty::BoundConst { var: bound_const, ty },
};
self.mapped_consts.insert(p, bound_const);
- Ok(self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }))
+ self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
- _ => Ok(ct),
+ _ => ct,
}
}
}
universe_indices,
current_index: ty::INNERMOST,
};
- value.super_fold_with(&mut replacer).into_ok()
+ value.super_fold_with(&mut replacer)
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
if !t.has_placeholders() && !t.has_infer_regions() {
- return Ok(t);
+ return t;
}
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
t
}
- fn fold_region(&mut self, r0: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r1 = match r0 {
ty::ReVar(_) => self
.infcx
debug!(?r0, ?r1, ?r2, "fold_region");
- Ok(r2)
+ r2
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Placeholder(p) => {
let replace_var = self.mapped_types.get(&p);
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- Ok(self.tcx().mk_ty(ty::Bound(db, *replace_var)))
+ self.tcx().mk_ty(ty::Bound(db, *replace_var))
}
- None => Ok(ty),
+ None => ty,
}
}
_ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
- _ => Ok(ty),
+ _ => ty,
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- Ok(self
- .tcx()
- .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty }))
+ self.tcx()
+ .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
}
- None => Ok(ct),
+ None => ct,
}
} else {
ct.super_fold_with(self)
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.ty.has_infer_regions() {
- progress.ty =
- OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty).into_ok();
+ progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
}
progress
}
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};
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>(),
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>,
) -> 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>) -> Result<Ty<'tcx>, Self::Error> {
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
return Ok(ty);
}
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,
&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,
))
}
- _ => ty.super_fold_with(self),
+ _ => ty.try_super_fold_with(self),
})()?;
self.cache.insert(ty, res);
Ok(res)
}
- fn fold_const(
+ fn try_fold_const(
&mut self,
constant: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- let constant = constant.super_fold_with(self)?;
+ let constant = constant.try_super_fold_with(self)?;
Ok(constant.eval(self.infcx.tcx, self.param_env))
}
- fn fold_mir_const(
+ fn try_fold_mir_const(
&mut self,
constant: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
- constant.super_fold_with(self)
+ constant.try_super_fold_with(self)
}
}
},
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)
.predicate
.to_poly_trait_ref()
.fold_with(&mut self.freshener)
- .into_ok()
.with_constness(obligation.predicate.skip_binder().constness);
let dfn = previous_stack.cache.next_dfn();
predicates
.iter()
.map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
- .map(|wc| wc.fold_with(&mut regions_substitutor).into_ok())
+ .map(|wc| wc.fold_with(&mut regions_substitutor))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
}
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let trait_ref = trait_ref.fold_with(&mut regions_substitutor).into_ok();
+ let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
let where_clauses = self.where_clauses_for(def_id, bound_vars);
let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let self_ty = self_ty.fold_with(&mut regions_substitutor).into_ok();
+ let self_ty = self_ty.fold_with(&mut regions_substitutor);
let lowered_ty = self_ty.lower_into(&self.interner);
parameters[0].assert_ty_ref(&self.interner).could_match(
.iter()
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
.map(|bound| {
- bound
- .fold_with(&mut ty::fold::BottomUpFolder {
- tcx: self.interner.tcx,
- ty_op: |ty| {
- if let ty::Opaque(def_id, substs) = *ty.kind() {
- if def_id == opaque_ty_id.0 && substs == identity_substs {
- return self.interner.tcx.mk_ty(ty::Bound(
- ty::INNERMOST,
- ty::BoundTy::from(ty::BoundVar::from_u32(0)),
- ));
- }
+ bound.fold_with(&mut ty::fold::BottomUpFolder {
+ tcx: self.interner.tcx,
+ ty_op: |ty| {
+ if let ty::Opaque(def_id, substs) = *ty.kind() {
+ if def_id == opaque_ty_id.0 && substs == identity_substs {
+ return self.interner.tcx.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy::from(ty::BoundVar::from_u32(0)),
+ ));
}
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- .into_ok()
+ }
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
})
.filter_map(|bound| {
LowerInto::<
.collect();
let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
- let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor).into_ok();
+ let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
for var in named_parameters.values() {
parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
self.tcx
}
- fn fold_binder<T: TypeFoldable<'tcx>>(
- &mut self,
- t: Binder<'tcx, T>,
- ) -> Result<Binder<'tcx, T>, Self::Error> {
+ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
- return Ok(self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)));
+ return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
}
None => panic!("Missing `BrNamed`."),
},
self.tcx
}
- fn fold_binder<T: TypeFoldable<'tcx>>(
- &mut self,
- t: Binder<'tcx, T>,
- ) -> Result<Binder<'tcx, T>, Self::Error> {
+ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
// FIXME(chalk): currently we convert params to placeholders starting at
// index `0`. To support placeholders, we'll actually need to do a
// first pass to collect placeholders. Then we can insert params after.
ty::Placeholder(_) => unimplemented!(),
ty::Param(param) => match self.list.iter().position(|r| r == ¶m) {
- Some(idx) => Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
- }))),
+ })),
None => {
self.list.push(param);
let idx = self.list.len() - 1 + self.next_ty_placeholder;
self.params.insert(idx, param);
- Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
- })))
+ }))
}
},
}
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
match r {
// FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
// This covers any region variables in a goal, right?
var: ty::BoundVar::from_u32(*idx),
kind: ty::BrAnon(*idx),
};
- Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
+ self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
}
None => {
let idx = self.named_regions.len() as u32;
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
self.named_regions.insert(_re.def_id, idx);
- Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
+ self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
}
},
self.tcx
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
match r {
ty::ReEmpty(ui) => {
assert_eq!(ui.as_usize(), 0);
- Ok(self.reempty_placeholder)
+ self.reempty_placeholder
}
_ => r.super_fold_with(self),
let mut params_substitutor =
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
- let obligation = obligation.fold_with(&mut params_substitutor).into_ok();
+ let obligation = obligation.fold_with(&mut params_substitutor);
// FIXME(chalk): we really should be substituting these back in the solution
let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
- let obligation = obligation.fold_with(&mut regions_substitutor).into_ok();
+ let obligation = obligation.fold_with(&mut regions_substitutor);
let max_universe = obligation.max_universe.index();
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
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()),
use rustc_trait_selection::traits::wf::object_region_bounds;
use smallvec::SmallVec;
-use std::array;
use std::collections::BTreeSet;
use std::slice;
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
let is_equality = is_equality();
- let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates);
+ let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
let mut err = if is_equality.is_some() {
// More specific Error Index entry.
struct_span_err!(
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();
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),
}
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
&format!(
- "{}, producing the floating point representation of the integer,
+ "{}, producing the floating point representation of the integer, \
rounded if necessary",
cast_msg,
),
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> {
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, .. }),
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,
let mut eraser = TypeParamEraser(self, expr.span);
let needs_bound = self
.lookup_op_method(
- eraser.fold_ty(lhs_ty).into_ok(),
- &[eraser.fold_ty(rhs_ty).into_ok()],
+ eraser.fold_ty(lhs_ty),
+ &[eraser.fold_ty(rhs_ty)],
Op::Binary(op, is_assign),
)
.is_ok();
self.0.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.kind() {
- ty::Param(_) => Ok(self.0.next_ty_var(TypeVariableOrigin {
+ ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.1,
- })),
+ }),
_ => ty.super_fold_with(self),
}
}
}
// 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),
) {
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`
// Inherent impl: take implied bounds from the `self` type.
let self_ty = self.tcx.type_of(impl_def_id);
let self_ty = self.normalize_associated_types_in(span, self_ty);
- std::array::IntoIter::new([self_ty]).collect()
+ FxHashSet::from_iter([self_ty])
}
}
}
T: TypeFoldable<'tcx>,
{
let mut resolver = Resolver::new(self.fcx, span, self.body);
- let x = x.fold_with(&mut resolver).into_ok();
+ let x = x.fold_with(&mut resolver);
if cfg!(debug_assertions) && x.needs_infer() {
span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
}
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_fold_with(self)
} else {
- Ok(ty)
+ ty
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- Ok(if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased })
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
}
}
self.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match self.infcx.fully_resolve(t) {
Ok(t) => {
// Do not anonymize late-bound regions
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
self.report_type_error(t);
self.replaced_with_error = true;
- Ok(self.tcx().ty_error())
+ self.tcx().ty_error()
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
- Ok(self.tcx.lifetimes.re_erased)
+ self.tcx.lifetimes.re_erased
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- Ok(match self.infcx.fully_resolve(ct) {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ match self.infcx.fully_resolve(ct) {
Ok(ct) => self.infcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
self.replaced_with_error = true;
self.tcx().const_error(ct.ty)
}
- })
+ }
}
}
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 }
})
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable, WithConstness};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
sugg.push((arg.span, (*type_name).to_string()));
} else {
let last = generics.iter().last().unwrap();
- sugg.push((
- // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
- last.bounds_span().unwrap_or(last.span).shrink_to_hi(),
- format!(", {}", type_name),
- ));
+ // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
+ let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
+ sugg.push((span, format!(", {}", type_name)));
}
let mut err = bad_placeholder_type(tcx, placeholder_types, 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)
}
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),
visitor.visit_ty(ty);
let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
let ret_ty = fn_sig.skip_binder().output();
- if ret_ty != tcx.ty_error() {
+ if !ret_ty.references_error() {
if !ret_ty.is_closure() {
let ret_ty_str = match ret_ty.kind() {
// Suggest a function pointer return type instead of a unique function definition
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),
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
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !self.success {
- return Ok(ty);
+ return ty;
}
match ty.kind() {
- ty::FnDef(def_id, _) => Ok(self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id))),
+ ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
// FIXME: non-capturing closures should also suggest a function pointer
ty::Closure(..) | ty::Generator(..) => {
self.success = false;
- Ok(ty)
+ ty
}
_ => ty.super_fold_with(self),
}
// Suggesting unnameable types won't help.
let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty).into_ok();
+ let ty = mk_nameable.fold_ty(ty);
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
err.span_suggestion(
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty).into_ok();
+ let ty = mk_nameable.fold_ty(ty);
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
diag.span_suggestion(
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = traits::FulfillmentContext::new();
- let tcx_ty = self
- .icx
- .to_ty(ty)
- .fold_with(&mut EraseAllBoundRegions { tcx: self.tcx })
- .into_ok();
+ let tcx_ty =
+ self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new(
ty.span,
self.hir_id,
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
- if let ty::ReLateBound(..) = r { Ok(&ty::ReErased) } else { Ok(r) }
+ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+ if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
}
}
#![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)]
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
-#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
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)
}
}
}
/// }
/// ```
fn from(arr: [T; N]) -> Self {
- core::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
pub(crate) fn bulk_build_from_sorted_iter<I>(iter: I) -> Self
where
K: Ord,
- I: Iterator<Item = (K, V)>,
+ I: IntoIterator<Item = (K, V)>,
{
let mut root = Root::new();
let mut length = 0;
- root.bulk_push(DedupSortedIter::new(iter), &mut length);
+ root.bulk_push(DedupSortedIter::new(iter.into_iter()), &mut length);
BTreeMap { root: Some(root), length }
}
}
// use stable sort to preserve the insertion order.
inputs.sort_by(|a, b| a.0.cmp(&b.0));
- BTreeMap::bulk_build_from_sorted_iter(inputs.into_iter())
+ BTreeMap::bulk_build_from_sorted_iter(inputs)
}
}
// use stable sort to preserve the insertion order.
arr.sort_by(|a, b| a.0.cmp(&b.0));
- BTreeMap::bulk_build_from_sorted_iter(core::array::IntoIter::new(arr))
+ BTreeMap::bulk_build_from_sorted_iter(arr)
}
}
// use stable sort to preserve the insertion order.
arr.sort();
- let iter = core::array::IntoIter::new(arr).map(|k| (k, ()));
+ let iter = IntoIterator::into_iter(arr).map(|k| (k, ()));
let map = BTreeMap::bulk_build_from_sorted_iter(iter);
BTreeSet { map }
}
/// assert_eq!(list1, list2);
/// ```
fn from(arr: [T; N]) -> Self {
- core::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
+ {
+ self.retain_mut(|elem| f(elem));
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` such that `f(&e)` returns false.
+ /// This method operates in place, visiting each element exactly once in the
+ /// original order, and preserves the order of the retained elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(vec_retain_mut)]
+ ///
+ /// use std::collections::VecDeque;
+ ///
+ /// let mut buf = VecDeque::new();
+ /// buf.extend(1..5);
+ /// buf.retain_mut(|x| if *x % 2 == 0 {
+ /// *x += 1;
+ /// true
+ /// } else {
+ /// false
+ /// });
+ /// assert_eq!(buf, [3, 5]);
+ /// ```
+ #[unstable(feature = "vec_retain_mut", issue = "90829")]
+ pub fn retain_mut<F>(&mut self, mut f: F)
+ where
+ F: FnMut(&mut T) -> bool,
{
let len = self.len();
let mut idx = 0;
// Stage 1: All values are retained.
while cur < len {
- if !f(&self[cur]) {
+ if !f(&mut self[cur]) {
cur += 1;
break;
}
}
// Stage 2: Swap retained value into current idx.
while cur < len {
- if !f(&self[cur]) {
+ if !f(&mut self[cur]) {
cur += 1;
continue;
}
cur += 1;
idx += 1;
}
- // Stage 3: Trancate all values after idx.
+ // Stage 3: Truncate all values after idx.
if cur != idx {
self.truncate(idx);
}
}
+ // 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) {
// 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);
}
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) }
+ }
}
///////////////////////////////////////////////////////////////////////////////
alive: Range<usize>,
}
-impl<T, const N: usize> IntoIter<T, N> {
- /// Creates a new iterator over the given `array`.
- ///
- /// *Note*: this method might be deprecated in the future,
- /// since [`IntoIterator`] is now implemented for arrays.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::array;
+// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
+impl<T, const N: usize> IntoIterator for [T; N] {
+ type Item = T;
+ type IntoIter = IntoIter<T, N>;
+
+ /// Creates a consuming iterator, that is, one that moves each value out of
+ /// the array (from start to end). The array cannot be used after calling
+ /// this unless `T` implements `Copy`, so the whole array is copied.
///
- /// for value in array::IntoIter::new([1, 2, 3, 4, 5]) {
- /// // The type of `value` is an `i32` here, instead of `&i32`
- /// let _: i32 = value;
- /// }
+ /// Arrays have special behavior when calling `.into_iter()` prior to the
+ /// 2021 edition -- see the [array] Editions section for more information.
///
- /// // Since Rust 1.53, arrays implement IntoIterator directly:
- /// for value in [1, 2, 3, 4, 5] {
- /// // The type of `value` is an `i32` here, instead of `&i32`
- /// let _: i32 = value;
- /// }
- /// ```
- #[stable(feature = "array_value_iter", since = "1.51.0")]
- pub fn new(array: [T; N]) -> Self {
+ /// [array]: prim@array
+ fn into_iter(self) -> Self::IntoIter {
// SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
// promise:
//
// Until then, we can use `mem::transmute_copy` to create a bitwise copy
// as a different type, then forget `array` so that it is not dropped.
unsafe {
- let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
- mem::forget(array);
+ let iter = IntoIter { data: mem::transmute_copy(&self), alive: 0..N };
+ mem::forget(self);
iter
}
}
+}
+
+impl<T, const N: usize> IntoIter<T, N> {
+ /// Creates a new iterator over the given `array`.
+ #[stable(feature = "array_value_iter", since = "1.51.0")]
+ #[rustc_deprecated(since = "1.59.0", reason = "use `IntoIterator::into_iter` instead")]
+ pub fn new(array: [T; N]) -> Self {
+ IntoIterator::into_iter(array)
+ }
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
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).
}
}
-// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
-// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
-// so those calls will still resolve to the slice implementation, by reference.
-#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
-impl<T, const N: usize> IntoIterator for [T; N] {
- type Item = T;
- type IntoIter = IntoIter<T, N>;
-
- /// Creates a consuming iterator, that is, one that moves each value out of
- /// the array (from start to end). The array cannot be used after calling
- /// this unless `T` implements `Copy`, so the whole array is copied.
- ///
- /// Arrays have special behavior when calling `.into_iter()` prior to the
- /// 2021 edition -- see the [array] Editions section for more information.
- ///
- /// [array]: prim@array
- fn into_iter(self) -> Self::IntoIter {
- IntoIter::new(self)
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a [T; N] {
type Item = &'a T;
}
}
-#[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));
}
}
#[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;
}
/// 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.
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};
/// 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
Some(self.fold(first, f))
}
+ /// Reduces the elements to a single one by repeatedly applying a reducing operation. If the
+ /// closure returns a failure, the failure is propagated back to the caller immediately.
+ ///
+ /// The return type of this method depends on the return type of the closure. If the closure
+ /// returns `Result<Self::Item, E>`, then this function will return `Result<Option<Self::Item>,
+ /// E>`. If the closure returns `Option<Self::Item>`, then this function will return
+ /// `Option<Option<Self::Item>>`.
+ ///
+ /// When called on an empty iterator, this function will return either `Some(None)` or
+ /// `Ok(None)` depending on the type of the provided closure.
+ ///
+ /// For iterators with at least one element, this is essentially the same as calling
+ /// [`try_fold()`] with the first element of the iterator as the initial accumulator value.
+ ///
+ /// [`try_fold()`]: Iterator::try_fold
+ ///
+ /// # Examples
+ ///
+ /// Safely calculate the sum of a series of numbers:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers: Vec<usize> = vec![10, 20, 5, 23, 0];
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, Some(Some(58)));
+ /// ```
+ ///
+ /// Determine when a reduction short circuited:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers = vec![1, 2, 3, usize::MAX, 4, 5];
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, None);
+ /// ```
+ ///
+ /// Determine when a reduction was not performed because there are no elements:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers: Vec<usize> = Vec::new();
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, Some(None));
+ /// ```
+ ///
+ /// Use a [`Result`] instead of an [`Option`]:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers = vec!["1", "2", "3", "4", "5"];
+ /// let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+ /// numbers.into_iter().try_reduce(|x, y| {
+ /// if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+ /// });
+ /// assert_eq!(max, Ok(Some("5")));
+ /// ```
+ #[inline]
+ #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")]
+ fn try_reduce<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<R::Output>>
+ where
+ Self: Sized,
+ F: FnMut(Self::Item, Self::Item) -> R,
+ R: Try<Output = Self::Item>,
+ R::Residual: Residual<Option<Self::Item>>,
+ {
+ let first = match self.next() {
+ Some(i) => i,
+ None => return Try::from_output(None),
+ };
+
+ match self.try_fold(first, f).branch() {
+ ControlFlow::Break(r) => FromResidual::from_residual(r),
+ ControlFlow::Continue(i) => Try::from_output(Some(i)),
+ }
+ }
+
/// Tests if every element of the iterator matches a predicate.
///
/// `all()` takes a closure that returns `true` or `false`. It applies
/// 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_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::*;
/// ```
#[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
#[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
- #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_raw_ptr_deref))]
#[inline(always)]
pub const unsafe fn assume_init_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` is initialized.
}
}
+#[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.
- #[cfg_attr(not(bootstrap), lang = "generator_return")]
+ #[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>`.
///
/// println!("array[{}] = {}", i, x);
/// }
///
-/// // You can explicitly iterate an array by value using
-/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
+/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
/// println!("array[{}] = {}", i, x);
}
}
+ /// 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,
+ })
}
}
#[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));
}
use super::*;
-use core::array;
use core::iter::*;
#[test]
#[test]
fn test_trusted_len_flatten() {
fn assert_trusted_len<T: TrustedLen>(_: &T) {}
- let mut iter = array::IntoIter::new([[0; 3]; 4]).flatten();
+ let mut iter = IntoIterator::into_iter([[0; 3]; 4]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (12, Some(12)));
iter.next_back();
assert_eq!(iter.size_hint(), (10, Some(10)));
- let iter = array::IntoIter::new([[(); usize::MAX]; 1]).flatten();
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 1]).flatten();
assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX)));
- let iter = array::IntoIter::new([[(); usize::MAX]; 2]).flatten();
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 2]).flatten();
assert_eq!(iter.size_hint(), (usize::MAX, None));
let mut a = [(); 10];
let mut b = [(); 10];
- let iter = array::IntoIter::new([&mut a, &mut b]).flatten();
+ let iter = IntoIterator::into_iter([&mut a, &mut b]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (20, Some(20)));
core::mem::drop(iter);
- let iter = array::IntoIter::new([&a, &b]).flatten();
+ let iter = IntoIterator::into_iter([&a, &b]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (20, Some(20)));
}
}
+#[test]
+fn test_try_reduce() {
+ let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(Some(15)));
+
+ let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, None);
+
+ let v: Vec<usize> = Vec::new();
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(None));
+
+ let v = vec!["1", "2", "3", "4", "5"];
+ let max = v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
+ });
+ assert_eq!(max, Some(Some("5")));
+
+ let v = vec!["1", "2", "3", "4", "5"];
+ let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+ v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+ });
+ assert_eq!(max, Ok(Some("5")));
+}
+
#[test]
fn test_iterator_len() {
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
#![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(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
+#![feature(iterator_try_reduce)]
#![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;
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_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.53" }
+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'] }
/// assert_eq!(map1, map2);
/// ```
fn from(arr: [(K, V); N]) -> Self {
- crate::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
/// assert_eq!(set1, set2);
/// ```
fn from(arr: [T; N]) -> Self {
- crate::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
/// `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]
// std may use features in a platform-specific way
#![allow(unused_features)]
#![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(
- test,
- feature(internal_output_capture, print_internals, update_panic_count, thread_local_const_init)
-)]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
feature(slice_index_methods, coerce_unsized, sgx_platform)
#![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
/// println!("array[{}] = {}", i, x);
/// }
///
-/// // You can explicitly iterate an array by value using
-/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
+/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
/// println!("array[{}] = {}", i, x);
}
#[cfg(target_os = "dragonfly")]
+#[allow(dead_code)]
pub fn set_errno(e: i32) {
extern "C" {
#[thread_local]
#[cfg(target_os = "macos")]
pub unsafe fn environ() -> *mut *const *const c_char {
- extern "C" {
- fn _NSGetEnviron() -> *mut *const *const c_char;
- }
- _NSGetEnviron()
+ libc::_NSGetEnviron() as *mut *const *const c_char
}
#[cfg(not(target_os = "macos"))]
/// 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> {
(@key $t:ty, const $init:expr) => {{
#[cfg_attr(not(windows), inline)] // see comments below
unsafe fn __getit() -> $crate::option::Option<&'static $t> {
- const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
const INIT_EXPR: $t = $init;
// wasm without atomics maps directly to `static mut`, and dtors
#[doc(hidden)]
pub use self::local::statik::Key as __StaticLocalKeyInner;
-// This is only used to make thread locals with `const { .. }` initialization
-// expressions unstable. If and/or when that syntax is stabilized with thread
-// locals this will simply be removed.
-#[doc(hidden)]
-#[unstable(feature = "thread_local_const_init", issue = "84223")]
-pub const fn require_unstable_const_init_thread_local() {}
-
////////////////////////////////////////////////////////////////////////////////
// Builder
////////////////////////////////////////////////////////////////////////////////
} 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") {
] {
tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
}
+
+ // We don't build LLD on some platforms, so only add it if it exists
+ let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target));
+ if lld_path.exists() {
+ tarball.add_file(lld_path, "bin", 0o755);
+ }
+
tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
// Copy the include directory as well; needed mostly to build
options[1] = Some(format!("-Clink-arg=-Wl,{}", threads));
}
- std::array::IntoIter::new(options).flatten()
+ IntoIterator::into_iter(options).flatten()
}
/// Returns if this target should statically link the C runtime, if specified
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-*`.
reg_operand := dir_spec "(" reg_spec ")" operand_expr
operand := reg_operand / "const" const_expr / "sym" path
clobber_abi := "clobber_abi(" <abi> *["," <abi>] [","] ")"
-option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
+option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" / "may_unwind"
options := "options(" option *["," option] [","] ")"
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")"
```
- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
+- `may_unwind`: The `asm` block may unwind the stack and be part of the stack unwinding process (This option is only supported by the LLVM backend right now).
- `raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`. This is primarily useful when including raw assembly code from an external file using `include_str!`.
The compiler performs some additional checks on options:
highlights for example. If you want to simply check for the presence of
a given node or attribute, use an empty string (`""`) as a `PATTERN`.
-* `@count PATH XPATH COUNT' checks for the occurrence of the given XPath
+* `@count PATH XPATH COUNT` checks for the occurrence of the given XPath
in the specified file. The number of occurrences must match the given
count.
+* `@snapshot NAME PATH XPATH` creates a snapshot test named NAME.
+ A snapshot test captures a subtree of the DOM, at the location
+ determined by the XPath, and compares it to a pre-recorded value
+ in a file. The file's name is the test's name with the `.rs` extension
+ replaced with `.NAME.html`, where NAME is the snapshot's name.
+
+ htmldocck supports the `--bless` option to accept the current subtree
+ as expected, saving it to the file determined by the snapshot's name.
+ compiletest's `--bless` flag is forwarded to htmldocck.
+
* `@has-dir PATH` checks for the existence of the given directory.
All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+# Initialized in main
+rust_test_path = None
+bless = None
+
class CustomHTMLParser(HTMLParser):
"""simplified HTML parser.
return len(tree.findall(path))
+def check_snapshot(snapshot_name, tree):
+ assert rust_test_path.endswith('.rs')
+ snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
+ try:
+ with open(snapshot_path, 'r') as snapshot_file:
+ expected_str = snapshot_file.read()
+ except FileNotFoundError:
+ if bless:
+ expected_str = None
+ else:
+ raise FailedCheck('No saved snapshot value')
+
+ actual_str = ET.tostring(tree).decode('utf-8')
+
+ if expected_str != actual_str:
+ if bless:
+ with open(snapshot_path, 'w') as snapshot_file:
+ snapshot_file.write(actual_str)
+ else:
+ print('--- expected ---\n')
+ print(expected_str)
+ print('\n\n--- actual ---\n')
+ print(actual_str)
+ print()
+ raise FailedCheck('Actual snapshot value is different than expected')
+
def stderr(*args):
if sys.version_info.major < 3:
file = codecs.getwriter('utf-8')(sys.stderr)
ret = expected == found
else:
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
+ elif c.cmd == 'snapshot': # snapshot test
+ if len(c.args) == 3: # @snapshot <snapshot-name> <html-path> <xpath>
+ [snapshot_name, html_path, pattern] = c.args
+ tree = cache.get_tree(html_path)
+ xpath = normalize_xpath(pattern)
+ subtrees = tree.findall(xpath)
+ if len(subtrees) == 1:
+ [subtree] = subtrees
+ try:
+ check_snapshot(snapshot_name, subtree)
+ ret = True
+ except FailedCheck as err:
+ cerr = str(err)
+ ret = False
+ elif len(subtrees) == 0:
+ raise FailedCheck('XPATH did not match')
+ else:
+ raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees)))
+ else:
+ raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
elif c.cmd == 'has-dir': # has-dir test
if len(c.args) == 1: # @has-dir <path> = has-dir test
try:
ret = False
else:
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
elif c.cmd == 'valid-html':
raise InvalidCheck('Unimplemented @valid-html')
elif c.cmd == 'valid-links':
raise InvalidCheck('Unimplemented @valid-links')
+
else:
raise InvalidCheck('Unrecognized @{}'.format(c.cmd))
if __name__ == '__main__':
- if len(sys.argv) != 3:
- stderr('Usage: {} <doc dir> <template>'.format(sys.argv[0]))
+ if len(sys.argv) not in [3, 4]:
+ stderr('Usage: {} <doc dir> <template> [--bless]'.format(sys.argv[0]))
raise SystemExit(1)
- check(sys.argv[1], get_commands(sys.argv[2]))
+ rust_test_path = sys.argv[2]
+ if len(sys.argv) > 3 and sys.argv[3] == '--bless':
+ bless = True
+ else:
+ # We only support `--bless` at the end of the arguments.
+ # This assert is to prevent silent failures.
+ assert '--bless' not in sys.argv
+ bless = False
+ check(sys.argv[1], get_commands(rust_test_path))
if ERR_COUNT:
stderr("\nEncountered {} errors".format(ERR_COUNT))
raise SystemExit(1)
// Instead, we generate `impl !Send for Foo<T>`, which better
// expresses the fact that `Foo<T>` never implements `Send`,
// regardless of the choice of `T`.
- let params = (tcx.generics_of(item_def_id), ty::GenericPredicates::default())
- .clean(self.cx)
- .params;
+ let raw_generics = clean_ty_generics(
+ self.cx,
+ tcx.generics_of(item_def_id),
+ ty::GenericPredicates::default(),
+ );
+ let params = raw_generics.params;
Generics { params, where_predicates: Vec::new() }
}
_ => false,
}
})
- .map(|p| p.fold_with(&mut replacer).into_ok());
+ .map(|p| p.fold_with(&mut replacer));
- let mut generic_params =
- (tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
- .clean(self.cx)
- .params;
+ let raw_generics = clean_ty_generics(
+ self.cx,
+ tcx.generics_of(item_def_id),
+ tcx.explicit_predicates_of(item_def_id),
+ );
+ let mut generic_params = raw_generics.params;
debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params);
self.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- Ok((match *r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ (match *r {
ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
- .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
+ .unwrap_or_else(|| r.super_fold_with(self))
}
}
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
- generics: (
+ generics: clean_ty_generics(
+ self.cx,
self.cx.tcx.generics_of(impl_def_id),
self.cx.tcx.explicit_predicates_of(impl_def_id),
- )
- .clean(self.cx),
+ ),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx)),
use rustc_span::symbol::{kw, sym, Symbol};
use crate::clean::{
- self, utils, Attributes, AttributesExt, ImplKind, ItemId, NestedAttributesExt, Type,
+ self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt,
+ Clean, ImplKind, ItemId, NestedAttributesExt, Type, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
-use super::{Clean, Visibility};
-
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
/// Attempt to inline a definition into this AST.
.collect();
let predicates = cx.tcx.predicates_of(did);
- let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = filter_non_trait_generics(did, generics);
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
let is_auto = cx.tcx.trait_is_auto(did);
let predicates = cx.tcx.predicates_of(did);
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
// NOTE: generics need to be cleaned before the decl!
- ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+ let decl = clean_fn_decl_from_did_and_sig(cx, did, sig);
+ (generics, decl)
});
clean::Function {
decl,
let predicates = cx.tcx.explicit_predicates_of(did);
clean::Enum {
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
variants_stripped: false,
variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
}
clean::Struct {
struct_type: variant.ctor_kind,
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
fields: variant.fields.iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
- let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let fields = variant.fields.iter().map(|x| x.clean(cx)).collect();
clean::Union { generics, fields, fields_stripped: false }
}
clean::Typedef {
type_,
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
item_type: None,
}
}
}
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,
};
}
})
.collect::<Vec<_>>(),
- clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
+ clean::enter_impl_trait(cx, |cx| {
+ clean_ty_generics(cx, tcx.generics_of(did), predicates)
+ }),
),
};
let polarity = tcx.impl_polarity(did);
use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
+use std::collections::BTreeMap;
use std::default::Default;
use std::hash::Hash;
use std::{mem, vec};
impl Clean<Item> for DocModule<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![];
- items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
+ items.extend(
+ self.foreigns
+ .iter()
+ .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
+ );
items.extend(self.mods.iter().map(|x| x.clean(cx)));
- items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
+ items.extend(
+ self.items
+ .iter()
+ .flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)),
+ );
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
_ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"),
};
+ let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
GenericBound::TraitBound(
- PolyTrait {
- trait_: (trait_ref, &bindings[..]).clean(cx),
- generic_params: vec![],
- },
+ PolyTrait { trait_, generic_params: vec![] },
hir::TraitBoundModifier::None,
)
}
}
}
-impl Clean<Path> for (ty::TraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- let (trait_ref, bounds) = *self;
- let kind = cx.tcx.def_kind(trait_ref.def_id).into();
- if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
- span_bug!(
- cx.tcx.def_span(trait_ref.def_id),
- "`TraitRef` had unexpected kind {:?}",
- kind
- );
- }
- inline::record_extern_fqn(cx, trait_ref.def_id, kind);
- let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
+fn clean_trait_ref_with_bindings(
+ cx: &mut DocContext<'_>,
+ trait_ref: ty::TraitRef<'_>,
+ bindings: &[TypeBinding],
+) -> Path {
+ let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+ if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+ span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
+ }
+ inline::record_extern_fqn(cx, trait_ref.def_id, kind);
+ let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
- debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
+ debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
- path
- }
+ path
}
impl Clean<Path> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- (*self, &[][..]).clean(cx)
+ clean_trait_ref_with_bindings(cx, *self, &[])
}
}
-impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
- let (poly_trait_ref, bounds) = *self;
- let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
-
- // collect any late bound regions
- let late_bound_regions: Vec<_> = cx
- .tcx
- .collect_referenced_late_bound_regions(&poly_trait_ref)
- .into_iter()
- .filter_map(|br| match br {
- ty::BrNamed(_, name) => Some(GenericParamDef {
- name,
- kind: GenericParamDefKind::Lifetime { outlives: vec![] },
- }),
- _ => None,
- })
- .collect();
+fn clean_poly_trait_ref_with_bindings(
+ cx: &mut DocContext<'_>,
+ poly_trait_ref: ty::PolyTraitRef<'_>,
+ bindings: &[TypeBinding],
+) -> GenericBound {
+ let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
+
+ // collect any late bound regions
+ let late_bound_regions: Vec<_> = cx
+ .tcx
+ .collect_referenced_late_bound_regions(&poly_trait_ref)
+ .into_iter()
+ .filter_map(|br| match br {
+ ty::BrNamed(_, name) => Some(GenericParamDef {
+ name,
+ kind: GenericParamDefKind::Lifetime { outlives: vec![] },
+ }),
+ _ => None,
+ })
+ .collect();
- GenericBound::TraitBound(
- PolyTrait {
- trait_: (poly_trait_ref.skip_binder(), bounds).clean(cx),
- generic_params: late_bound_regions,
- },
- hir::TraitBoundModifier::None,
- )
- }
+ let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref.skip_binder(), bindings);
+ GenericBound::TraitBound(
+ PolyTrait { trait_, generic_params: late_bound_regions },
+ hir::TraitBoundModifier::None,
+ )
}
impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
- (*self, &[][..]).clean(cx)
+ clean_poly_trait_ref_with_bindings(cx, *self, &[])
}
}
}
}
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
- use self::WherePredicate as WP;
- use std::collections::BTreeMap;
-
- let (gens, preds) = *self;
-
- // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
- // since `Clean for ty::Predicate` would consume them.
- let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
-
- // Bounds in the type_params and lifetimes fields are repeated in the
- // predicates field (see rustc_typeck::collect::ty_generics), so remove
- // them.
- let stripped_params = gens
- .params
- .iter()
- .filter_map(|param| match param.kind {
- ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
- ty::GenericParamDefKind::Type { synthetic, .. } => {
- if param.name == kw::SelfUpper {
- assert_eq!(param.index, 0);
- return None;
- }
- if synthetic {
- impl_trait.insert(param.index.into(), vec![]);
- return None;
- }
- Some(param.clean(cx))
+fn clean_ty_generics(
+ cx: &mut DocContext<'_>,
+ gens: &ty::Generics,
+ preds: ty::GenericPredicates<'tcx>,
+) -> Generics {
+ // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
+ // since `Clean for ty::Predicate` would consume them.
+ let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
+
+ // Bounds in the type_params and lifetimes fields are repeated in the
+ // predicates field (see rustc_typeck::collect::ty_generics), so remove
+ // them.
+ let stripped_params = gens
+ .params
+ .iter()
+ .filter_map(|param| match param.kind {
+ ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
+ ty::GenericParamDefKind::Type { synthetic, .. } => {
+ if param.name == kw::SelfUpper {
+ assert_eq!(param.index, 0);
+ return None;
}
- ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
- })
- .collect::<Vec<GenericParamDef>>();
-
- // param index -> [(DefId of trait, associated type name, type)]
- let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
-
- let where_predicates = preds
- .predicates
- .iter()
- .flat_map(|(p, _)| {
- let mut projection = None;
- let param_idx = (|| {
- let bound_p = p.kind();
- match bound_p.skip_binder() {
- ty::PredicateKind::Trait(pred) => {
- if let ty::Param(param) = pred.self_ty().kind() {
- return Some(param.index);
- }
- }
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
- if let ty::Param(param) = ty.kind() {
- return Some(param.index);
- }
+ if synthetic {
+ impl_trait.insert(param.index.into(), vec![]);
+ return None;
+ }
+ Some(param.clean(cx))
+ }
+ ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
+ })
+ .collect::<Vec<GenericParamDef>>();
+
+ // param index -> [(DefId of trait, associated type name, type)]
+ let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+
+ let where_predicates = preds
+ .predicates
+ .iter()
+ .flat_map(|(p, _)| {
+ let mut projection = None;
+ let param_idx = (|| {
+ let bound_p = p.kind();
+ match bound_p.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ if let ty::Param(param) = pred.self_ty().kind() {
+ return Some(param.index);
}
- ty::PredicateKind::Projection(p) => {
- if let ty::Param(param) = p.projection_ty.self_ty().kind() {
- projection = Some(bound_p.rebind(p));
- return Some(param.index);
- }
+ }
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+ if let ty::Param(param) = ty.kind() {
+ return Some(param.index);
}
- _ => (),
}
-
- None
- })();
-
- if let Some(param_idx) = param_idx {
- if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
- let p = p.clean(cx)?;
-
- b.extend(
- p.get_bounds()
- .into_iter()
- .flatten()
- .cloned()
- .filter(|b| !b.is_sized_bound(cx)),
- );
-
- let proj = projection
- .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
- if let Some(((_, trait_did, name), rhs)) =
- proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
- {
- impl_trait_proj
- .entry(param_idx)
- .or_default()
- .push((trait_did, name, rhs));
+ ty::PredicateKind::Projection(p) => {
+ if let ty::Param(param) = p.projection_ty.self_ty().kind() {
+ projection = Some(bound_p.rebind(p));
+ return Some(param.index);
}
-
- return None;
}
+ _ => (),
}
- Some(p)
- })
- .collect::<Vec<_>>();
-
- for (param, mut bounds) in impl_trait {
- // Move trait bounds to the front.
- bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
-
- if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
- if let Some(proj) = impl_trait_proj.remove(&idx) {
- for (trait_did, name, rhs) in proj {
- let rhs = rhs.clean(cx);
- simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+ None
+ })();
+
+ if let Some(param_idx) = param_idx {
+ if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
+ let p = p.clean(cx)?;
+
+ b.extend(
+ p.get_bounds()
+ .into_iter()
+ .flatten()
+ .cloned()
+ .filter(|b| !b.is_sized_bound(cx)),
+ );
+
+ let proj = projection
+ .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+ if let Some(((_, trait_did, name), rhs)) =
+ proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
+ {
+ impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
}
+
+ return None;
}
- } else {
- unreachable!();
}
- cx.impl_trait_bounds.insert(param, bounds);
- }
+ Some(p)
+ })
+ .collect::<Vec<_>>();
- // Now that `cx.impl_trait_bounds` is populated, we can process
- // remaining predicates which could contain `impl Trait`.
- let mut where_predicates =
- where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
-
- // Type parameters have a Sized bound by default unless removed with
- // ?Sized. Scan through the predicates and mark any type parameter with
- // a Sized bound, removing the bounds as we find them.
- //
- // Note that associated types also have a sized bound by default, but we
- // don't actually know the set of associated types right here so that's
- // handled in cleaning associated types
- let mut sized_params = FxHashSet::default();
- where_predicates.retain(|pred| match *pred {
- WP::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
- if bounds.iter().any(|b| b.is_sized_bound(cx)) {
- sized_params.insert(*g);
- false
- } else {
- true
+ for (param, mut bounds) in impl_trait {
+ // Move trait bounds to the front.
+ bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
+
+ if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
+ if let Some(proj) = impl_trait_proj.remove(&idx) {
+ for (trait_did, name, rhs) in proj {
+ let rhs = rhs.clean(cx);
+ simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
}
}
- _ => true,
- });
+ } else {
+ unreachable!();
+ }
- // Run through the type parameters again and insert a ?Sized
- // unbound for any we didn't find to be Sized.
- for tp in &stripped_params {
- if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
- && !sized_params.contains(&tp.name)
- {
- where_predicates.push(WP::BoundPredicate {
- ty: Type::Generic(tp.name),
- bounds: vec![GenericBound::maybe_sized(cx)],
- bound_params: Vec::new(),
- })
+ cx.impl_trait_bounds.insert(param, bounds);
+ }
+
+ // Now that `cx.impl_trait_bounds` is populated, we can process
+ // remaining predicates which could contain `impl Trait`.
+ let mut where_predicates =
+ where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+
+ // Type parameters have a Sized bound by default unless removed with
+ // ?Sized. Scan through the predicates and mark any type parameter with
+ // a Sized bound, removing the bounds as we find them.
+ //
+ // Note that associated types also have a sized bound by default, but we
+ // don't actually know the set of associated types right here so that's
+ // handled in cleaning associated types
+ let mut sized_params = FxHashSet::default();
+ where_predicates.retain(|pred| match *pred {
+ WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
+ if bounds.iter().any(|b| b.is_sized_bound(cx)) {
+ sized_params.insert(*g);
+ false
+ } else {
+ true
}
}
+ _ => true,
+ });
- // It would be nice to collect all of the bounds on a type and recombine
- // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
- // and instead see `where T: Foo + Bar + Sized + 'a`
-
- Generics {
- params: stripped_params,
- where_predicates: simplify::where_clauses(cx, where_predicates),
+ // Run through the type parameters again and insert a ?Sized
+ // unbound for any we didn't find to be Sized.
+ for tp in &stripped_params {
+ if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
+ && !sized_params.contains(&tp.name)
+ {
+ where_predicates.push(WherePredicate::BoundPredicate {
+ ty: Type::Generic(tp.name),
+ bounds: vec![GenericBound::maybe_sized(cx)],
+ bound_params: Vec::new(),
+ })
}
}
+
+ // It would be nice to collect all of the bounds on a type and recombine
+ // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
+ // and instead see `where T: Foo + Bar + Sized + 'a`
+
+ Generics {
+ params: stripped_params,
+ where_predicates: simplify::where_clauses(cx, where_predicates),
+ }
}
fn clean_fn_or_proc_macro(
ProcMacroItem(ProcMacro { kind, helpers })
}
None => {
- let mut func = (sig, generics, body_id).clean(cx);
+ let mut func = clean_function(cx, sig, generics, body_id);
let def_id = item.def_id.to_def_id();
func.header.constness =
if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
} else {
hir::Constness::NotConst
};
+ clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
}
}
}
-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| {
- // NOTE: generics must be cleaned before args
- let generics = self.1.clean(cx);
- let args = (self.0.decl.inputs, self.2).clean(cx);
- let decl = clean_fn_decl_with_args(cx, self.0.decl, args);
- (generics, decl)
- });
- Function { decl, generics, header: self.0.header }
+/// 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<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
- Arguments {
- values: self
- .0
- .iter()
- .enumerate()
- .map(|(i, ty)| {
- let mut name = self.1.get(i).map_or(kw::Empty, |ident| ident.name);
- if name.is_empty() {
- name = kw::Underscore;
- }
- Argument { name, type_: ty.clean(cx) }
- })
- .collect(),
- }
+fn clean_function(
+ cx: &mut DocContext<'_>,
+ sig: &hir::FnSig<'_>,
+ generics: &hir::Generics<'_>,
+ body_id: hir::BodyId,
+) -> Function {
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
+ // NOTE: generics must be cleaned before args
+ let generics = generics.clean(cx);
+ let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
+ let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+ (generics, decl)
+ });
+ Function { decl, generics, header: sig.header }
+}
+
+fn clean_args_from_types_and_names(
+ cx: &mut DocContext<'_>,
+ types: &[hir::Ty<'_>],
+ names: &[Ident],
+) -> Arguments {
+ Arguments {
+ values: types
+ .iter()
+ .enumerate()
+ .map(|(i, ty)| {
+ let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
+ if name.is_empty() {
+ name = kw::Underscore;
+ }
+ Argument { name, type_: ty.clean(cx), is_const: false }
+ })
+ .collect(),
}
}
-impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
- let body = cx.tcx.hir().body(self.1);
+fn clean_args_from_types_and_body_id(
+ cx: &mut DocContext<'_>,
+ types: &[hir::Ty<'_>],
+ body_id: hir::BodyId,
+) -> Arguments {
+ let body = cx.tcx.hir().body(body_id);
- Arguments {
- values: self
- .0
- .iter()
- .enumerate()
- .map(|(i, ty)| Argument {
- name: name_from_pat(body.params[i].pat),
- type_: ty.clean(cx),
- })
- .collect(),
- }
+ Arguments {
+ values: types
+ .iter()
+ .enumerate()
+ .map(|(i, ty)| Argument {
+ name: name_from_pat(body.params[i].pat),
+ type_: ty.clean(cx),
+ is_const: false,
+ })
+ .collect(),
}
}
FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
}
-impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
- let (did, sig) = *self;
- let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
-
- FnDecl {
- output: Return(sig.skip_binder().output().clean(cx)),
- c_variadic: sig.skip_binder().c_variadic,
- inputs: Arguments {
- values: sig
- .skip_binder()
- .inputs()
- .iter()
- .map(|t| Argument {
- type_: t.clean(cx),
- name: names.next().map_or(kw::Empty, |i| i.name),
- })
- .collect(),
- },
- }
+fn clean_fn_decl_from_did_and_sig(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ sig: ty::PolyFnSig<'_>,
+) -> FnDecl {
+ let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
+
+ FnDecl {
+ output: Return(sig.skip_binder().output().clean(cx)),
+ c_variadic: sig.skip_binder().c_variadic,
+ inputs: Arguments {
+ values: sig
+ .skip_binder()
+ .inputs()
+ .iter()
+ .map(|t| Argument {
+ type_: t.clean(cx),
+ name: names.next().map_or(kw::Empty, |i| i.name),
+ is_const: false,
+ })
+ .collect(),
+ },
}
}
AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx.tcx, e)))
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let mut m = (sig, &self.generics, body).clean(cx);
+ let mut m = clean_function(cx, sig, &self.generics, body);
if m.header.constness == hir::Constness::Const
&& is_unstable_const_fn(cx.tcx, local_did).is_some()
{
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = self.generics.clean(cx);
- let args = (sig.decl.inputs, names).clean(cx);
+ let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
(generics, decl)
});
AssocConstItem(ty.clean(cx), Some(print_const_expr(cx.tcx, expr)))
}
hir::ImplItemKind::Fn(ref sig, body) => {
- let mut m = (sig, &self.generics, body).clean(cx);
+ let mut m = clean_function(cx, sig, &self.generics, body);
if m.header.constness == hir::Constness::Const
&& is_unstable_const_fn(cx.tcx, local_did).is_some()
{
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 --
AssocConstItem(ty.clean(cx), default)
}
ty::AssocKind::Fn => {
- let generics =
- (tcx.generics_of(self.def_id), tcx.explicit_predicates_of(self.def_id))
- .clean(cx);
+ let generics = clean_ty_generics(
+ cx,
+ tcx.generics_of(self.def_id),
+ tcx.explicit_predicates_of(self.def_id),
+ );
let sig = tcx.fn_sig(self.def_id);
- let mut decl = (self.def_id, sig).clean(cx);
+ let mut decl = clean_fn_decl_from_did_and_sig(cx, self.def_id, sig);
if self.fn_has_self_parameter {
let self_ty = match self.container {
if let ty::TraitContainer(_) = self.container {
let bounds = tcx.explicit_item_bounds(self.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
let mut bounds = generics
.where_predicates
.iter()
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
}
}
let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
let def_id = DefId::local(CRATE_DEF_INDEX);
+ let decl = clean_fn_decl_from_did_and_sig(cx, def_id, sig);
BareFunction(box BareFunctionDecl {
unsafety: sig.unsafety(),
generic_params: Vec::new(),
- decl: (def_id, sig).clean(cx),
+ decl,
abi: sig.abi(),
})
}
}
}
- let bounds: Vec<_> = bounds
+ let bindings: Vec<_> = bounds
.iter()
.filter_map(|bound| {
if let ty::PredicateKind::Projection(proj) =
})
.collect();
- Some((trait_ref, &bounds[..]).clean(cx))
+ Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
})
.collect::<Vec<_>>();
bounds.extend(regions);
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
- let args = (self.decl.inputs, self.param_names).clean(cx);
+ let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
let decl = clean_fn_decl_with_args(cx, self.decl, args);
(generic_params, decl)
});
}
}
-impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
- use hir::ItemKind;
-
- let (item, renamed) = self;
- let def_id = item.def_id.to_def_id();
- let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
- cx.with_param_env(def_id, |cx| {
- let kind = match item.kind {
- ItemKind::Static(ty, mutability, body_id) => {
- StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
- }
- ItemKind::Const(ty, body_id) => ConstantItem(Constant {
- type_: ty.clean(cx),
- kind: ConstantKind::Local { body: body_id, def_id },
- }),
- ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
- bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
- generics: ty.generics.clean(cx),
- }),
- ItemKind::TyAlias(hir_ty, ref generics) => {
- let rustdoc_ty = hir_ty.clean(cx);
- let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
- TypedefItem(
- Typedef {
- type_: rustdoc_ty,
- generics: generics.clean(cx),
- item_type: Some(ty),
- },
- false,
- )
- }
- ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
- variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
- generics: generics.clean(cx),
- variants_stripped: false,
- }),
- ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+fn clean_maybe_renamed_item(
+ cx: &mut DocContext<'_>,
+ item: &hir::Item<'_>,
+ renamed: Option<Symbol>,
+) -> Vec<Item> {
+ use hir::ItemKind;
+
+ let def_id = item.def_id.to_def_id();
+ let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+ cx.with_param_env(def_id, |cx| {
+ let kind = match item.kind {
+ ItemKind::Static(ty, mutability, body_id) => {
+ StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
+ }
+ ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+ type_: ty.clean(cx),
+ kind: ConstantKind::Local { body: body_id, def_id },
+ }),
+ ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
+ bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
+ generics: ty.generics.clean(cx),
+ }),
+ ItemKind::TyAlias(hir_ty, ref generics) => {
+ let rustdoc_ty = hir_ty.clean(cx);
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+ TypedefItem(
+ Typedef {
+ type_: rustdoc_ty,
+ generics: generics.clean(cx),
+ item_type: Some(ty),
+ },
+ false,
+ )
+ }
+ ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+ variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+ generics: generics.clean(cx),
+ variants_stripped: false,
+ }),
+ ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+ generics: generics.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
+ }),
+ ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+ generics: generics.clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+ fields_stripped: false,
+ }),
+ ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+ struct_type: CtorKind::from_hir(variant_data),
+ generics: generics.clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+ fields_stripped: false,
+ }),
+ ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
+ // proc macros can have a name set by attributes
+ ItemKind::Fn(ref sig, ref generics, body_id) => {
+ clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
+ }
+ ItemKind::Macro(ref macro_def) => {
+ let ty_vis = cx.tcx.visibility(def_id).clean(cx);
+ MacroItem(Macro {
+ source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
+ })
+ }
+ ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
+ let items =
+ item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+ TraitItem(Trait {
+ unsafety,
+ items,
generics: generics.clean(cx),
bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
- }),
- ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
- generics: generics.clean(cx),
- fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
- fields_stripped: false,
- }),
- ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
- struct_type: CtorKind::from_hir(variant_data),
- generics: generics.clean(cx),
- fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
- fields_stripped: false,
- }),
- ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
- // proc macros can have a name set by attributes
- ItemKind::Fn(ref sig, ref generics, body_id) => {
- clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
- }
- ItemKind::Macro(ref macro_def) => {
- let ty_vis = cx.tcx.visibility(def_id).clean(cx);
- MacroItem(Macro {
- source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
- })
- }
- ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
- let items = item_ids
- .iter()
- .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
- .collect();
- TraitItem(Trait {
- unsafety,
- items,
- generics: generics.clean(cx),
- bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
- is_auto: is_auto.clean(cx),
- })
- }
- ItemKind::ExternCrate(orig_name) => {
- return clean_extern_crate(item, name, orig_name, cx);
- }
- ItemKind::Use(path, kind) => {
- return clean_use_statement(item, name, path, kind, cx);
- }
- _ => unreachable!("not yet converted"),
- };
+ is_auto: is_auto.clean(cx),
+ })
+ }
+ ItemKind::ExternCrate(orig_name) => {
+ return clean_extern_crate(item, name, orig_name, cx);
+ }
+ ItemKind::Use(path, kind) => {
+ return clean_use_statement(item, name, path, kind, cx);
+ }
+ _ => unreachable!("not yet converted"),
+ };
- vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
- })
- }
+ vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
+ })
}
impl Clean<Item> for hir::Variant<'_> {
vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
}
-impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Item {
- let (item, renamed) = self;
- let def_id = item.def_id.to_def_id();
- cx.with_param_env(def_id, |cx| {
- let kind = match item.kind {
- hir::ForeignItemKind::Fn(decl, names, ref generics) => {
- let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = generics.clean(cx);
- let args = (decl.inputs, names).clean(cx);
- let decl = clean_fn_decl_with_args(cx, decl, args);
- (generics, decl)
- });
- ForeignFunctionItem(Function {
- decl,
- generics,
- header: hir::FnHeader {
- unsafety: if abi == Abi::RustIntrinsic {
- intrinsic_operation_unsafety(item.ident.name)
- } else {
- hir::Unsafety::Unsafe
- },
- abi,
- constness: hir::Constness::NotConst,
- asyncness: hir::IsAsync::NotAsync,
+fn clean_maybe_renamed_foreign_item(
+ cx: &mut DocContext<'_>,
+ item: &hir::ForeignItem<'_>,
+ renamed: Option<Symbol>,
+) -> Item {
+ let def_id = item.def_id.to_def_id();
+ cx.with_param_env(def_id, |cx| {
+ let kind = match item.kind {
+ hir::ForeignItemKind::Fn(decl, names, ref generics) => {
+ let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
+ // NOTE: generics must be cleaned before args
+ let generics = generics.clean(cx);
+ let args = clean_args_from_types_and_names(cx, decl.inputs, names);
+ let decl = clean_fn_decl_with_args(cx, decl, args);
+ (generics, decl)
+ });
+ ForeignFunctionItem(Function {
+ decl,
+ generics,
+ header: hir::FnHeader {
+ unsafety: if abi == Abi::RustIntrinsic {
+ intrinsic_operation_unsafety(item.ident.name)
+ } else {
+ hir::Unsafety::Unsafe
},
- })
- }
- hir::ForeignItemKind::Static(ref ty, mutability) => {
- ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
- }
- hir::ForeignItemKind::Type => ForeignTypeItem,
- };
+ abi,
+ constness: hir::Constness::NotConst,
+ asyncness: hir::IsAsync::NotAsync,
+ },
+ })
+ }
+ hir::ForeignItemKind::Static(ref ty, mutability) => {
+ ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
+ }
+ hir::ForeignItemKind::Type => ForeignTypeItem,
+ };
- Item::from_hir_id_and_parts(
- item.hir_id(),
- Some(renamed.unwrap_or(item.ident.name)),
- kind,
- cx,
- )
- })
- }
+ Item::from_hir_id_and_parts(
+ item.hir_id(),
+ Some(renamed.unwrap_or(item.ident.name)),
+ kind,
+ cx,
+ )
+ })
}
impl Clean<TypeBinding> for hir::TypeBinding<'_> {
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 Lifetime(pub Symbol);
impl Lifetime {
- crate fn get_ref(&self) -> SymbolStr {
- self.0.as_str()
- }
-
crate fn statik() -> Lifetime {
Lifetime(kw::StaticLifetime)
}
crate fn is_type(&self) -> bool {
matches!(self, GenericParamDefKind::Type { .. })
}
-
- // FIXME(eddyb) this either returns the default of a type parameter, or the
- // type of a `const` parameter. It seems that the intention is to *visit*
- // any embedded types, but `get_type` seems to be the wrong name for that.
- crate fn get_type(&self) -> Option<Type> {
- match self {
- GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
- GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
- GenericParamDefKind::Lifetime { .. } => None,
- }
- }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
self.kind.is_type()
}
- crate fn get_type(&self) -> Option<Type> {
- self.kind.get_type()
- }
-
crate fn get_bounds(&self) -> Option<&[GenericBound]> {
match self.kind {
GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
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)]
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),
let (did, kind) = match res {
// These should be added to the cache using `record_extern_fqn`.
Res::Def(
- kind
- @
- (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
+ kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
| Union | Mod | ForeignTy | Const | Static | Macro(..) | TraitAlias),
i,
) => (i, kind.into()),
impl clean::Lifetime {
crate fn print(&self) -> impl fmt::Display + '_ {
- self.get_ref()
+ self.0.as_str()
}
}
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
(
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let GenericBound::TraitBound(poly_trait, _) = bound {
- for x in poly_trait.generic_params.iter() {
- if !x.is_type() {
- continue;
- }
- if let Some(ty) = x.get_type() {
- get_real_types(
- generics,
- &ty,
- tcx,
- recurse + 1,
- &mut ty_generics,
- cache,
- );
+ for param_def in poly_trait.generic_params.iter() {
+ match ¶m_def.kind {
+ clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
+ get_real_types(
+ generics,
+ ty,
+ tcx,
+ recurse + 1,
+ &mut ty_generics,
+ cache,
+ )
+ }
+ _ => {}
}
}
}
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,
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\">");
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 {
) {
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),
)
}
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>");
<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" {# -#}
#![feature(type_ascription)]
#![feature(iter_intersperse)]
#![recursion_limit = "256"]
-#![feature(unwrap_infallible)]
#![warn(rustc::internal)]
#[macro_use]
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 2b9078f4afae82f60c5ac0fdb4af42d269e2f2f3
"__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);
+}
--- /dev/null
+// min-llvm-version: 13.0.0
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm, asm_unwind)]
+
+#[no_mangle]
+pub extern "C" fn panicky() {}
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!();
+ }
+}
+
+// CHECK-LABEL: @may_unwind
+#[no_mangle]
+pub unsafe fn may_unwind() {
+ let _m = Foo;
+ // CHECK: invoke void asm sideeffect alignstack inteldialect unwind ""
+ asm!("", options(may_unwind));
+}
#![crate_type = "lib"]
-#![feature(thread_local_const_init)]
use std::cell::Cell;
// 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 }
+}
// ignore-android does not use #[thread_local]
#![crate_type = "lib"]
-#![feature(thread_local_const_init)]
extern crate thread_local_aux as aux;
-// 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
+ }
+ }
+
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
// must not optimize as it does not follow the pattern of
// left and right hand side being the same variant
+++ /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();
// pp-exact
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
fn syntax() {
let _ = #[attr] foo!(#! [attr]);
let _ = #[attr] foo![];
let _ = #[attr] foo![#! [attr]];
- let _ = #[attr] foo! { };
+ let _ = #[attr] foo! {};
let _ = #[attr] foo! { #! [attr] };
let _ = #[attr] Foo{bar: baz,};
let _ = #[attr] Foo{..foo};
foo!();
#[attr]
- foo! { }
+ foo! {}
#[attr]
foo![];
{
#[attr]
- foo! { }
+ foo! {}
}
}
Qwerty,
}
-fn main() { }
+fn main() {}
// pp-exact
-auto trait MyTrait { }
+auto trait MyTrait {}
-unsafe auto trait UnsafeMyTrait { }
+unsafe auto trait UnsafeMyTrait {}
-pub fn main() { }
+pub fn main() {}
// compile-flags: --crate-type=lib
// pp-exact
-fn f() {
-} /*
- The next line should not be indented.
+fn f() {} /*
+ The next line should not be indented.
- That one. It shouldn't have been indented.
- */
+ That one. It shouldn't have been indented.
+ */
// pp-exact
-fn call_it(f: Box<FnMut(String) -> String>) { }
+fn call_it(f: Box<FnMut(String) -> String>) {}
-fn call_this<F>(f: F) where F: Fn(&str) + Send { }
+fn call_this<F>(f: F) where F: Fn(&str) + Send {}
-fn call_that<F>(f: F) where F: for<'a> Fn(&'a isize, &'a isize) -> isize { }
+fn call_that<F>(f: F) where F: for<'a> Fn(&'a isize, &'a isize) -> isize {}
-fn call_extern(f: fn() -> isize) { }
+fn call_extern(f: fn() -> isize) {}
-fn call_abid_extern(f: extern "C" fn() -> isize) { }
+fn call_abid_extern(f: extern "C" fn() -> isize) {}
-pub fn main() { }
+pub fn main() {}
fn id<F>(f: F) -> isize where F: Fn() -> isize { f() }
fn wsucc(_n: isize) -> isize { id(|| { 1 }) - 0 }
-fn main() { }
+fn main() {}
// Check that the visibility is printed on an enum variant.
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
enum Foo { pub V, }
// pp-exact
-fn main() { }
+fn main() {}
// pp-exact:example2.pp
-fn main() { }
+fn main() {}
// pp-exact:example2.pp
-fn main() { }
+fn main() {}
// pp-exact:expanded-and-path-remap-80832.pp
// compile-flags: --remap-path-prefix {{src-base}}=the/src
-fn main() { }
+fn main() {}
// pp-exact
-// Check that `fn f() -> () { }` does not print as `fn f() { }`.
+// Check that `fn f() -> () {}` does not print as `fn f() {}`.
-fn f() -> () { }
+fn f() -> () {}
-fn main() { }
+fn main() {}
// pp-exact
-fn from_foreign_fn(_x: fn()) { }
-fn from_stack_closure<F>(_x: F) where F: Fn() { }
-fn main() { }
+fn from_foreign_fn(_x: fn()) {}
+fn from_stack_closure<F>(_x: F) where F: Fn() {}
+fn main() {}
ap.arg::<usize>()
}
-fn main() { }
+fn main() {}
fn simple_attr() {
#[attr]
- if true { }
+ if true {}
#[allow_warnings]
- if true { }
+ if true {}
}
#[cfg(FALSE)]
fn if_else_chain() {
#[first_attr]
- if true { } else if false { } else { }
+ if true {} else if false {} else {}
}
#[cfg(FALSE)]
fn if_let() {
#[attr]
- if let Some(_) = Some(true) { }
+ if let Some(_) = Some(true) {}
}
#[cfg(FALSE)]
fn let_attr_if() {
- let _ = #[attr] if let _ = 0 { };
- let _ = #[attr] if true { };
+ let _ = #[attr] if let _ = 0 {};
+ let _ = #[attr] if true {};
- let _ = #[attr] if let _ = 0 { } else { };
- let _ = #[attr] if true { } else { };
+ let _ = #[attr] if let _ = 0 {} else {};
+ let _ = #[attr] if true {} else {};
}
-fn main() { }
+fn main() {}
#[path = "issue-12590-b.rs"]
mod issue_12590_b;
-fn main() { }
+fn main() {}
#[path = "issue-12590-b.rs"]
mod issue_12590_b {
- fn b() { }
- fn main() { }
+ fn b() {}
+ fn main() {}
}
-fn main() { }
+fn main() {}
#[path = "issue-12590-b.rs"]
mod issue_12590_b;
-fn main() { }
+fn main() {}
fn main() {
match true {
true if true => (),
- false if false => unsafe { },
- true => { }
+ false if false => unsafe {},
+ true => {}
false => (),
}
}
// pretty-compare-only
// pp-exact
-fn main() { b! { } c }
+fn main() { b! {} c }
// pp-exact
-fn main() { }
+fn main() {}
struct C {
field: u8,
// pp-exact
-fn f1<'a, 'b, 'c>(_x: &'a u32, _y: &'b u32, _z: &'c u32) where 'c: 'a + 'b { }
+fn f1<'a, 'b, 'c>(_x: &'a u32, _y: &'b u32, _z: &'c u32) where 'c: 'a + 'b {}
-fn main() { }
+fn main() {}
pub(crate) macro mac { ($arg : expr) => { $arg + $arg } }
-fn main() { }
+fn main() {}
// pp-exact
-macro_rules! brace { () => { } ; }
+macro_rules! brace { () => {} ; }
-macro_rules! bracket[() => { } ;];
+macro_rules! bracket[() => {} ;];
-macro_rules! paren(() => { } ;);
+macro_rules! paren(() => {} ;);
macro_rules! matcher_brackets {
- (paren) => { } ; (bracket) => { } ; (brace) => { } ;
+ (paren) => {} ; (bracket) => {} ; (brace) => {} ;
}
macro_rules! all_fragments {
($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit :
literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty,
- $vis : vis) => { } ;
+ $vis : vis) => {} ;
}
-fn main() { }
+fn main() {}
// pp-exact
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
extern "C" {
trait Tr {
- fn dummy(&self) { }
+ fn dummy(&self) {}
}
-impl Tr for isize { }
+impl Tr for isize {}
fn foo<'a>(x: Box<Tr + Sync + 'a>) -> Box<Tr + Sync + 'a> { x }
}
trait Tu {
- fn dummy() { }
+ fn dummy() {}
}
fn foo<T: m::Tr>() { <T as m::Tr>::Ts::dummy(); }
-fn main() { }
+fn main() {}
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
-fn main() { }
+fn main() {}
fn _0() {
fn _3() {
#[rustc_dummy]
- match () { _ => { } }
+ match () { _ => {} }
}
fn _4() {
stmt_mac!();
#[rustc_dummy]
- stmt_mac! { };
+ stmt_mac! {};
#[rustc_dummy]
stmt_mac![];
#[rustc_dummy]
- stmt_mac! { }
+ stmt_mac! {}
let _ = ();
}
fn _10() {
let _ = #[rustc_dummy] expr_mac!();
let _ = #[rustc_dummy] expr_mac![];
- let _ = #[rustc_dummy] expr_mac! { };
+ let _ = #[rustc_dummy] expr_mac! {};
}
fn _11() {
|| #[rustc_dummy] return;
let _ = #[rustc_dummy] expr_mac!();
let _ = #[rustc_dummy] expr_mac![];
- let _ = #[rustc_dummy] expr_mac! { };
+ let _ = #[rustc_dummy] expr_mac! {};
let _ = #[rustc_dummy] Foo{data: (),};
let _ = #[rustc_dummy] Foo{..s};
let _ = #[rustc_dummy] Foo{data: (), ..s};
}
}
-fn foo() { }
-fn foo3(_: i32, _: (), _: ()) { }
-fn qux(_: i32) { }
+fn foo() {}
+fn foo3(_: i32, _: (), _: ()) {}
+fn qux(_: i32) {}
baz,
}
-fn main() { }
+fn main() {}
#![allow(bar)]
}
-fn main() { }
+fn main() {}
struct Test;
-impl !Send for Test { }
+impl !Send for Test {}
-pub fn main() { }
+pub fn main() {}
}
unsafe impl UnsafeTrait for isize {
- fn foo(&self) { }
+ fn foo(&self) {}
}
pub unsafe trait PubUnsafeTrait {
fn foo(&self);
}
-fn main() { }
+fn main() {}
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
-fn main() { }
+fn main() {}
# 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 \
#![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!()
+ }
+}
--- /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>.
+#![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-content"]/*[@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
// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
-#![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"]
// @has foo/index.html
// 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
+<div class="docblock"><p>Hello world!
+Goodbye!
+Hello again!</p>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
+Hello again!</p>
+</div>
\ No newline at end of file
#![crate_name = "foo"]
// @has 'foo/struct.S1.html'
-// @count - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p' \
-// 1
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[1]' \
-// 'Hello world! Goodbye! Hello again!'
+// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
#[doc = "Hello world!\n\n"]
/// Goodbye!
pub struct S1;
// @has 'foo/struct.S2.html'
-// @count - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p' \
-// 2
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[1]' \
-// 'Hello world!'
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[2]' \
-// 'Goodbye! Hello again!'
+// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
/// Hello world!
///
+++ /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
#![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");
| |
| generic outputs
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:28:25
|
LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:30:25
|
LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:32:25
|
LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
--> $DIR/bad-options.rs:34:25
|
LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:36:25
|
LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:38:25
|
LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
--- /dev/null
+// min-llvm-version: 13.0.0
+// only-aarch64
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_sym, asm_unwind)]
+
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+ fn drop(&mut self) {
+ *self.0 = false;
+ }
+}
+
+extern "C" fn panicky() {
+ resume_unwind(Box::new(()));
+}
+
+fn main() {
+ let flag = &mut true;
+ catch_unwind(AssertUnwindSafe(|| {
+ let _foo = Foo(flag);
+ unsafe {
+ asm!(
+ "bl {}",
+ sym panicky,
+ clobber_abi("C"),
+ options(may_unwind)
+ );
+ }
+ }))
+ .expect_err("expected a panic");
+ assert_eq!(*flag, false);
+}
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:31:26
|
LL | asm!("", options(foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: expected one of `)` or `,`, found `foo`
--> $DIR/parse-error.rs:33:32
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:35:33
|
LL | asm!("", options(nomem, foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: arguments are not allowed after options
--> $DIR/parse-error.rs:37:31
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
--> $DIR/parse-error.rs:100:25
|
LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:102:25
|
LL | global_asm!("", options(nomem FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: arguments are not allowed after options
--> $DIR/parse-error.rs:106:30
--- /dev/null
+// min-llvm-version: 13.0.0
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_unwind)]
+
+fn main() {
+ unsafe { asm!("", options(may_unwind)) };
+}
| | clobber_abi
| generic outputs
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:31:25
|
LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:33:25
|
LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:35:25
|
LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
--> $DIR/bad-options.rs:37:25
|
LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:39:25
|
LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:41:25
|
LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
--- /dev/null
+// min-llvm-version: 13.0.0
+// only-x86_64
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_sym, asm_unwind)]
+
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+ fn drop(&mut self) {
+ *self.0 = false;
+ }
+}
+
+extern "C" fn panicky() {
+ resume_unwind(Box::new(()));
+}
+
+fn main() {
+ let flag = &mut true;
+ catch_unwind(AssertUnwindSafe(|| {
+ let _foo = Foo(flag);
+ unsafe {
+ asm!(
+ "call {}",
+ sym panicky,
+ clobber_abi("C"),
+ options(may_unwind)
+ );
+ }
+ }))
+ .expect_err("expected a panic");
+ assert_eq!(*flag, false);
+}
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:31:26
|
LL | asm!("", options(foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: expected one of `)` or `,`, found `foo`
--> $DIR/parse-error.rs:33:32
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:35:33
|
LL | asm!("", options(nomem, foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: arguments are not allowed after options
--> $DIR/parse-error.rs:37:31
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
--> $DIR/parse-error.rs:102:25
|
LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(nomem FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:106:25
|
LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: arguments are not allowed after options
--> $DIR/parse-error.rs:108:30
--- /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
+
--- /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}
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` 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());
+}
| ^^^^^^^^ `()` 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
-async fn f(mut x : u8) { }
-async fn g((mut x, y, mut z) : (u8, u8, u8)) { }
-async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) { }
+async fn f(mut x : u8) {}
+async fn g((mut x, y, mut z) : (u8, u8, u8)) {}
+async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) {}
| ^^^^^^^^^^^^^^^^ `[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
//~^ 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`.
| ^^^^^^^^^^^^^^^^^
error: unexpected token: `{
- impl std::ops::Neg for i8 { }
+ impl std::ops::Neg for i8 {}
}`
--> $DIR/issue-90873.rs:7:6
|
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
+#![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`.
#[macro_use]
extern crate std;
-trait Foo<const KIND : bool = true> { }
+trait Foo<const KIND : bool = true> {}
-fn foo<const SIZE : usize = 5>() { }
+fn foo<const SIZE : usize = 5>() {}
struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize =
FROM>;
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^-------^^
| |
- | dereferencing is not supported in generic constants
+ | borrowing is not supported in generic constants
|
= help: consider moving this anonymous constant into a `const` function
= note: this operation may be supported in the future
-// run-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
}
fn main() {
- // Test that we can correctly infer `T` which requires evaluating
- // `{ N + 1 }` which has substs containing an inference var
+ // FIXME(generic_const_exprs): We can't correctly infer `T` which requires
+ // evaluating `{ N + 1 }` which has substs containing an inference var
let mut _q = Default::default();
+ //~^ ERROR type annotations needed
+
_q = foo::<_, 2>(_q);
+ //~^ ERROR type annotations needed
}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/const_eval_resolve_canonical.rs:26:9
+ |
+LL | let mut _q = Default::default();
+ | ^^^^^^ consider giving `_q` a type
+
+error[E0283]: type annotations needed
+ --> $DIR/const_eval_resolve_canonical.rs:29:10
+ |
+LL | _q = foo::<_, 2>(_q);
+ | ^^^^^^^^^^^ cannot infer type
+ |
+note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
+ --> $DIR/const_eval_resolve_canonical.rs:8:1
+ |
+LL | impl Foo<0> for () {
+ | ^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo<3> for () {
+ | ^^^^^^^^^^^^^^^^^^
+note: required by a bound in `foo`
+ --> $DIR/const_eval_resolve_canonical.rs:18:9
+ |
+LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
+ | --- required by a bound in this
+LL | where
+LL | (): Foo<{ N + 1 }>,
+ | ^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Foo {
+ const N: usize;
+}
+
+impl Foo for u8 {
+ const N: usize = 1;
+}
+
+fn foo<T: Foo>(_: [u8; T::N]) -> T {
+ todo!()
+}
+
+pub fn bar() {
+ let _: u8 = foo([0; 1]);
+
+ let _ = foo([0; 1]);
+ //~^ ERROR type annotations needed
+}
+
+fn main() {}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/issue-83249.rs:19:13
+ |
+LL | let _ = foo([0; 1]);
+ | - ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | |
+ | consider giving this pattern a type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::{marker::PhantomData, ops::Mul};
+
+pub enum Nil {}
+pub struct Cons<T, L> {
+ _phantom: PhantomData<(T, L)>,
+}
+
+pub trait Indices<const N: usize> {
+ const RANK: usize;
+ const NUM_ELEMS: usize;
+}
+
+impl<const N: usize> Indices<N> for Nil {
+ const RANK: usize = 0;
+ const NUM_ELEMS: usize = 1;
+}
+
+impl<T, I: Indices<N>, const N: usize> Indices<N> for Cons<T, I> {
+ const RANK: usize = I::RANK + 1;
+ const NUM_ELEMS: usize = I::NUM_ELEMS * N;
+}
+
+pub trait Concat<J> {
+ type Output;
+}
+
+impl<J> Concat<J> for Nil {
+ type Output = J;
+}
+
+impl<T, I, J> Concat<J> for Cons<T, I>
+where
+ I: Concat<J>,
+{
+ type Output = Cons<T, <I as Concat<J>>::Output>;
+}
+
+pub struct Tensor<I: Indices<N>, const N: usize>
+where
+ [u8; I::NUM_ELEMS]: Sized,
+{
+ pub data: [u8; I::NUM_ELEMS],
+ _phantom: PhantomData<I>,
+}
+
+impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
+where
+ I: Concat<J>,
+ <I as Concat<J>>::Output: Indices<N>,
+ [u8; I::NUM_ELEMS]: Sized,
+ [u8; J::NUM_ELEMS]: Sized,
+ [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
+{
+ type Output = Tensor<<I as Concat<J>>::Output, N>;
+
+ fn mul(self, _rhs: Tensor<J, N>) -> Self::Output {
+ Tensor {
+ data: [0u8; <I as Concat<J>>::Output::NUM_ELEMS],
+ _phantom: PhantomData,
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait TraitWithConst {
+ const SOME_CONST: usize;
+}
+
+pub trait OtherTrait: TraitWithConst {
+ fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST];
+}
+
+impl TraitWithConst for f32 {
+ const SOME_CONST: usize = 32;
+}
+
+impl OtherTrait for f32 {
+ fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST] {
+ [0; 32]
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Target {
+ const LENGTH: usize;
+}
+
+
+pub struct Container<T: Target>
+where
+ [(); T::LENGTH]: Sized,
+{
+ _target: T,
+}
+
+impl<T: Target> Container<T>
+where
+ [(); T::LENGTH]: Sized,
+{
+ pub fn start(
+ _target: T,
+ ) -> Container<T> {
+ Container { _target }
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+ const SIZE: usize;
+
+ fn to_bytes(&self) -> [u8; Self::SIZE];
+}
+
+pub fn bar<G: Foo>(a: &G) -> u8
+where
+ [(); G::SIZE]: Sized,
+{
+ deeper_bar(a)
+}
+
+fn deeper_bar<G: Foo>(a: &G) -> u8
+where
+ [(); G::SIZE]: Sized,
+{
+ a.to_bytes()[0]
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Enumerable {
+ const N: usize;
+}
+
+#[derive(Clone)]
+pub struct SymmetricGroup<S>
+where
+ S: Enumerable,
+ [(); S::N]: Sized,
+{
+ _phantom: std::marker::PhantomData<S>,
+}
+
+fn main() {}
--- /dev/null
+#![feature(generic_const_exprs, adt_const_params)]
+#![allow(incomplete_features)]
+
+struct FieldElement<const N: &'static str> {
+ n: [u64; num_limbs(N)],
+ //~^ ERROR unconstrained generic constant
+}
+const fn num_limbs(_: &str) -> usize {
+ 0
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/issue-90455.rs:5:8
+ |
+LL | n: [u64; num_limbs(N)],
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); num_limbs(N)]:`
+
+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
-
--- /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`.
#![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`.
#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
+//~^ ERROR `derive` attribute cannot be used at crate level
+
+#![test]//~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR `test` attribute cannot be used at crate level
+
+#![test_case]//~ ERROR cannot determine resolution for the attribute macro `test_case`
+//~^ ERROR `test_case` attribute cannot be used at crate level
+
+#![bench]//~ ERROR cannot determine resolution for the attribute macro `bench`
+//~^ ERROR `bench` attribute cannot be used at crate level
+
+#![global_allocator]//~ ERROR cannot determine resolution for the attribute macro `global_allocator`
+//~^ ERROR `global_allocator` attribute cannot be used at crate level
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: cannot determine resolution for the attribute macro `test`
+ --> $DIR/issue-36617.rs:4:4
+ |
+LL | #![test]
+ | ^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `test_case`
+ --> $DIR/issue-36617.rs:7:4
+ |
+LL | #![test_case]
+ | ^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `bench`
+ --> $DIR/issue-36617.rs:10:4
+ |
+LL | #![bench]
+ | ^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `global_allocator`
+ --> $DIR/issue-36617.rs:13:4
+ |
+LL | #![global_allocator]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: `derive` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:1:1
+ |
+LL | #![derive(Copy)]
+ | ^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[derive(Copy)]
+ | ~~~~~~~~~~~~~~~
+
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:4:1
+ |
+LL | #![test]
+ | ^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test]
+ | ~~~~~~~
+
+error: `test_case` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:7:1
+ |
+LL | #![test_case]
+ | ^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test_case]
+ | ~~~~~~~~~~~~
+
+error: `bench` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:10:1
+ |
+LL | #![bench]
+ | ^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[bench]
+ | ~~~~~~~~
+
+error: `global_allocator` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:13:1
+ |
+LL | #![global_allocator]
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[global_allocator]
+ | ~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
}
}
-#[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);
}
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
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(may_unwind));
+ //~^ ERROR the `may_unwind` option is unstable
+ }
+}
--- /dev/null
+error[E0658]: the `may_unwind` option is unstable
+ --> $DIR/feature-gate-asm_unwind.rs:7:9
+ |
+LL | asm!("", options(may_unwind));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_unwind)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
#![bench = "4100"]
//~^ ERROR cannot determine resolution for the attribute macro `bench`
-
+//~^^ ERROR `bench` attribute cannot be used at crate level
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `bench` attribute cannot be used at crate level
+ --> $DIR/issue-43106-gating-of-bench.rs:7:1
+ |
+LL | #![bench = "4100"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[bench = "4100"]
+ |
+
+error: aborting due to 2 previous errors
|
LL | #![macro_export]
| ^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[macro_export]
+ |
error: `rustc_main` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
|
LL | #![rustc_main]
| ^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[rustc_main]
+ | ~~~~~~~~~~~~~
error: `start` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1
|
LL | #![start]
| ^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[start]
+ |
error: `repr` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:1
|
LL | #![repr()]
| ^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[repr()]
+ |
error: `path` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:20:1
|
LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[path = "3800"]
+ |
error: `automatically_derived` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:1
|
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[automatically_derived]
+ |
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17
#![allow(soft_unstable)]
#![test = "4200"]
//~^ ERROR cannot determine resolution for the attribute macro `test`
-
+//~^^ ERROR `test` attribute cannot be used at crate level
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-43106-gating-of-test.rs:4:1
+ |
+LL | #![test = "4200"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test = "4200"]
+ |
+
+error: aborting due to 2 previous errors
+++ /dev/null
-thread_local!(static X: u32 = const { 0 });
-//~^ ERROR: use of unstable library feature 'thread_local_const_init'
-
-fn main() {}
+++ /dev/null
-error[E0658]: use of unstable library feature 'thread_local_const_init'
- --> $DIR/thread-local-const-init.rs:1:1
- |
-LL | thread_local!(static X: u32 = const { 0 });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #84223 <https://github.com/rust-lang/rust/issues/84223> for more information
- = help: add `#![feature(thread_local_const_init)]` to the crate attributes to enable
- = note: this error originates in the macro `$crate::__thread_local_inner` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /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`.
--- /dev/null
+#![feature(generators)]
+
+fn foo() -> impl Sized {
+ yield 1; //~ ERROR E0627
+}
+
+fn main() {}
--- /dev/null
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/issue-91477.rs:4:5
+ |
+LL | yield 1;
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
+++ /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 () {}
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>;
y /* 0#1 */ + x /* 0#0 */
}
-fn y /* 0#0 */() { }
+fn y /* 0#0 */() {}
/*
Expansions:
--> $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
#![allow(soft_unstable)]
#![test] //~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-28134.rs:4:1
+ |
+LL | #![test]
+ | ^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test]
+ | ~~~~~~~
+
+error: aborting due to 2 previous errors
#![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`.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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
= 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 | impl<T: NotNull> IntoNullable for T {
| ^^^^^^^^^^^^ ^
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+ |
+LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+ | +++++++++++++++++++++++++++++++++++++++
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`.
#[derive(Clone, Copy)]
//~^ ERROR the trait `Copy` may not be implemented for this type
-struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
//~^ ERROR cannot find type `NotDefined` in this scope
//~| ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR `i32` is not an iterator
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
//~| ERROR `i32` is not an iterator
fn main() {}
-error[E0412]: cannot find type `NotDefined` in this scope
+error[E0412]: cannot find type `N` in this scope
--> $DIR/issue-50480.rs:3:12
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<N>`
error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:3:15
+ |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `N` in this scope
--> $DIR/issue-50480.rs:3:12
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<N>`
+
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:3:15
+ |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | - ^^^^^^^^^^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<NotDefined>`
+
+error[E0412]: cannot find type `N` in this scope
+ --> $DIR/issue-50480.rs:12:18
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | - ^
+ | |
+ | similarly named type parameter `T` defined here
+ |
+help: a type parameter with a similar name exists
+ |
+LL | struct Bar<T>(T, T, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ~
+help: you might be missing a type parameter
+ |
+LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | +++
+
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:12:21
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
error[E0277]: `i32` is not an iterator
- --> $DIR/issue-50480.rs:3:24
+ --> $DIR/issue-50480.rs:3:27
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
|
= help: the trait `Iterator` is not implemented for `i32`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
LL | #[derive(Clone, Copy)]
| ^^^^
LL |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | -------- ------ this field does not implement `Copy`
- | |
- | this field does not implement `Copy`
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
+ |
+ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `i32` is not an iterator
+ --> $DIR/issue-50480.rs:12:33
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `i32`
+ = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/issue-50480.rs:10:17
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^
+LL |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors
+error: aborting due to 10 previous errors
Some errors have detailed explanations: E0204, E0277, E0412.
For more information about an error, try `rustc --explain E0204`.
--- /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();
+}
// Regression test of #36638.
struct Foo<Self>(Self);
-//~^ ERROR expected identifier, found keyword `Self`
-//~^^ ERROR E0392
+//~^ ERROR unexpected keyword `Self` in generic parameters
+//~| ERROR recursive type `Foo` has infinite size
trait Bar<Self> {}
-//~^ ERROR expected identifier, found keyword `Self`
+//~^ ERROR unexpected keyword `Self` in generic parameters
fn main() {}
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
--> $DIR/keyword-self-as-type-param.rs:3:12
|
LL | struct Foo<Self>(Self);
- | ^^^^ expected identifier, found keyword
+ | ^^^^
+ |
+ = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
--> $DIR/keyword-self-as-type-param.rs:7:11
|
LL | trait Bar<Self> {}
- | ^^^^ expected identifier, found keyword
+ | ^^^^
+ |
+ = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
-error[E0392]: parameter `Self` is never used
- --> $DIR/keyword-self-as-type-param.rs:3:12
+error[E0072]: recursive type `Foo` has infinite size
+ --> $DIR/keyword-self-as-type-param.rs:3:1
|
LL | struct Foo<Self>(Self);
- | ^^^^ unused parameter
+ | ^^^^^^^^^^^^^^^^^----^^
+ | | |
+ | | recursive without indirection
+ | recursive type has infinite size
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
- = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
+LL | struct Foo<Self>(Box<Self>);
+ | ++++ +
error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0392`.
+For more information about this error, try `rustc --explain E0072`.
--- /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() {}
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
|
-LL | #[derive(Eq, PartialEq)]
- | -- lifetime `'b` is missing in item created through this procedural macro
LL | struct Test {
+ | - help: consider introducing lifetime `'b` here: `<'b>`
LL | a: &'b str,
| ^^ undeclared lifetime
|
--> $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
-// compile-flags: -Zfuture-incompat-test -Zemit-future-incompat-report
+// compile-flags: -Zfuture-incompat-test
// check-pass
// The `-Zfuture-incompat-test flag causes any normal warning to be included
macro_rules! foo { () => { break 'x ; } }
-pub fn main() { loop { } }
+pub fn main() { loop {} }
// 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`.
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28
|
LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
|
LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
|
LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
- | ^ not allowed after `pat` fragments
+ | -------- ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
|
LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
|
LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
|
LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
- | ^ not allowed after `pat` fragments
+ | -------- ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
struct S;
}
- n!(a $nt_item b); //~ ERROR no rules expected the token `enum E { }`
+ n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}`
}
simple_nonterminal!(a, 'a, (x, y, z)); // OK
-error: no rules expected the token `enum E { }`
+error: no rules expected the token `enum E {}`
--> $DIR/nonterminal-matching.rs:19:10
|
LL | macro n(a $nt_item b) {
LL | foo::<f64>(x_usize);
| ^^^^^^^ expected `f64`, found `usize`
|
-help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f64>(x_usize as f64);
| ++++++
LL | foo::<f64>(x_u64);
| ^^^^^ expected `f64`, found `u64`
|
-help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f64>(x_u64 as f64);
| ++++++
LL | foo::<f32>(x_usize);
| ^^^^^^^ expected `f32`, found `usize`
|
-help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_usize as f32);
| ++++++
LL | foo::<f32>(x_u64);
| ^^^^^ expected `f32`, found `u64`
|
-help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_u64 as f32);
| ++++++
LL | foo::<f32>(x_u32);
| ^^^^^ expected `f32`, found `u32`
|
-help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_u32 as f32);
| ++++++
// build-pass
// ignore-pass
// no-system-llvm
-// revisions: all inline
-// compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
+// 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
--- /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`.
span: $DIR/allowed-attr-stmt-expr.rs:49:20: 49:21 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/allowed-attr-stmt-expr.rs:61:28: 61:29 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "second_make_stmt",
span: $DIR/allowed-attr-stmt-expr.rs:64:57: 64:58 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
-PRINT-ATTR INPUT (DISPLAY): fn foo < T : MyTrait < MyStruct < { true } >> > () { }
+PRINT-ATTR INPUT (DISPLAY): fn foo < T : MyTrait < MyStruct < { true } >> > () {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/attr-stmt-expr.rs:53:28: 53:29 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "second_make_stmt",
span: $DIR/attr-stmt-expr.rs:56:57: 56:58 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
-PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
+PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
-PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
+PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
let input = input.to_string();
- assert_eq!(input, "fn foo() { }");
+ assert_eq!(input, "fn foo() {}");
r#"
fn foo() -> &'static str { "Hello, world!" }
#[proc_macro_attribute]
pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {
drop(attr);
- assert_eq!(item.to_string(), "fn foo() { }");
+ assert_eq!(item.to_string(), "fn foo() {}");
"fn foo(&self);".parse().unwrap()
}
#![crate_type = "proc-macro"]
extern crate proc_macro;
+use std::iter::FromIterator;
use std::str::FromStr;
use proc_macro::*;
let set_span_method = TokenStream::from_str("ident.set_span").unwrap();
let set_span_arg = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis, quoted_span)));
let suffix = TokenStream::from_str(";proc_macro::TokenStream::from(proc_macro::TokenTree::Ident(ident))").unwrap();
- let full_stream: TokenStream = std::array::IntoIter::new([prefix, set_span_method, set_span_arg, suffix]).collect();
+ let full_stream = TokenStream::from_iter([prefix, set_span_method, set_span_arg, suffix]);
full_stream
}
_ => unreachable!()
{
#! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner
{ field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0
- }] > { #! [rustc_dummy(evaluated_attr)] fn bar() { } }
+ }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "impl",
--- /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() {}
-Derive First: #[derive(Second)] #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
-Derive Second: #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
-Derive Third: #[derive(Fifth)] pub struct Foo { }
-Derive Fourth: #[derive(Fifth)] pub struct Foo { }
-Derive Fifth: pub struct Foo { }
+Derive First: #[derive(Second)] #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo {}
+Derive Second: #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo {}
+Derive Third: #[derive(Fifth)] pub struct Foo {}
+Derive Fourth: #[derive(Fifth)] pub struct Foo {}
+Derive Fifth: pub struct Foo {}
span: #8 bytes(430..483),
},
]
-PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, }
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): fn foo() { }
+PRINT-ATTR INPUT (DISPLAY): fn foo() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
+PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
span: #4 bytes(432..433),
},
]
-PRINT-DERIVE INPUT (DISPLAY): struct A { }
+PRINT-DERIVE INPUT (DISPLAY): struct A {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
-// 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
-PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2! (1 + 1) ; }
+PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | {} ; mul_2! (1 + 1) ; }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
#[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ;
#[cfg(FALSE)] let a = 25 ; match true
{
- #[cfg(FALSE)] true => { },
- #[cfg_attr(not(FALSE), allow(warnings))] false => { }, _ => { }
+ #[cfg(FALSE)] true => {},
+ #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {}
} ; #[print_helper(should_be_removed)] fn removed_fn()
{ #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn
kept_fn() { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
[u8 ;
{
#[cfg(not(FALSE))] struct Inner ; match true
- { #[allow(warnings)] false => { }, _ => { } } ; #[print_helper(c)]
+ { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)]
#[cfg(not(FALSE))] fn kept_fn()
{ #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
{ Foo(#[cfg(not(FALSE))] i32, u8) } struct
-PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/issue-81007-item-attrs.rs:22:16: 22:18 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#6),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct FirstAttrStruct { }
+PRINT-ATTR INPUT (DISPLAY): struct FirstAttrStruct {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#15),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct SecondAttrStruct { }
+PRINT-ATTR INPUT (DISPLAY): struct SecondAttrStruct {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
struct S /* 0#5 */;
// OK, not a duplicate definition of `S`
-fn main /* 0#0 */() { }
+fn main /* 0#0 */() {}
/*
Expansions:
-PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { }
+PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > { }
+PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "impl",
+++ /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 {
// [pretty]compile-flags: -Zunpretty=everybody_loops
// [pretty]check-pass
#[repr("C")]
-struct A {
-}
+struct A {}
-fn main() { loop { } }
+fn main() { loop {} }
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);
+}
// build-pass (FIXME(62277): could be check-pass?)
// compile-flags: -Z unpretty=expanded
-fn main() { if let 0 = 1 { } }
+fn main() { if let 0 = 1 {} }
}
checker!(attr_extern, r#"extern "C" { fn ffi(#[a1] arg1 : i32, #[a2] ...) ; }"#);
-checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) { }"#);
+checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) {}"#);
checker!(attr_alias, "type Alias = fn(#[a1] u8, #[a2] ...) ;");
checker!(attr_free, "fn free(#[a1] arg1 : u8) { let lam = | #[a2] W(x), #[a3] y | () ; }");
-checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) { }");
+checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) {}");
checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1 : u8) ;");
checker!(attr_trait_2, "fn trait2(#[a1] & self, #[a2] arg1 : u8) ;");
checker!(attr_trait_3, "fn trait3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) ;");
checker!(rename_params, r#"impl Foo
{
fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32)
- { } fn
+ {} fn
hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c :
- u32) { } fn
+ u32) {} fn
hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b :
- i32, #[angery(true)] c : u32) { }
+ i32, #[angery(true)] c : u32) {}
}"#);
// 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`.
#![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
//~^ ERROR cannot determine resolution for the attribute macro `derive`
+//~^^ ERROR `derive` attribute cannot be used at crate level
struct DerivedOn;
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `derive` attribute cannot be used at crate level
+ --> $DIR/issue-43927-non-ADT-derive.rs:1:1
+ |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
| 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
|
--- /dev/null
+mod a {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+
+ impl Debug for Inner<()> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR `a::Inner<T>` doesn't implement `Debug`
+}
+
+mod b {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+
+ impl<T: Debug> Debug for Inner<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>);
+}
+
+mod c {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T: Debug + Trait> Debug for Inner<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: c::Trait` is not satisfied
+}
+
+mod d {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: d::Trait` is not satisfied
+}
+
+mod e {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T> Debug for Inner<T> where T: Debug + Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: e::Trait` is not satisfied
+}
+
+mod f {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T: Debug> Debug for Inner<T> where T: Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: f::Trait` is not satisfied
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `a::Inner<T>` doesn't implement `Debug`
+ --> $DIR/derive-macro-missing-bounds.rs:12:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}`
+ |
+ = help: the trait `Debug` is not implemented for `a::Inner<T>`
+ = note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | struct Outer<T>(Inner<T>) where a::Inner<T>: Debug;
+ | ++++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: c::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:41:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `c::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `c::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:34:28
+ |
+LL | impl<T: Debug + Trait> Debug for Inner<T> {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&c::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: c::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: d::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:56:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `d::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `d::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:49:13
+ |
+LL | impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&d::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: d::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: e::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:71:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `e::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `e::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:64:13
+ |
+LL | impl<T> Debug for Inner<T> where T: Debug + Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&e::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: e::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: f::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:86:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `f::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `f::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:79:20
+ |
+LL | impl<T: Debug> Debug for Inner<T> where T: Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&f::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: f::Trait>(Inner<T>);
+ | ++++++++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
-// 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
+
--- /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`.
--- /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
+// Regression test for #91450.
+// This test ensures that the compiler does not suggest `Foo<[type error]>` in diagnostic messages.
+
+fn foo() -> Option<_> {} //~ ERROR: [E0308]
+//~^ ERROR: the type placeholder `_` is not allowed
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-91450-inner-ty-error.rs:4:13
+ |
+LL | fn foo() -> Option<_> {}
+ | --- ^^^^^^^^^ expected enum `Option`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+ = note: expected enum `Option<_>`
+ found unit type `()`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/issue-91450-inner-ty-error.rs:4:20
+ |
+LL | fn foo() -> Option<_> {}
+ | ^ not allowed in type signatures
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0121, E0308.
+For more information about an error, try `rustc --explain E0121`.
--- /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`.
-Subproject commit 7f08ace4f1305de7f3b1b0e2f765911957226bd4
+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(
remove_blocks, strip_pat_refs,
};
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
-use core::array;
use core::iter::{once, ExactSizeIterator};
use if_chain::if_chain;
use rustc_ast::ast::{Attribute, LitKind};
return find_matches_sugg(
cx,
let_expr,
- array::IntoIter::new([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
+ IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
expr,
true,
);
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 {
Mutability,
};
use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::sym;
fn call_return_effect(
&self,
- _in_out: &mut impl GenKill<Self::Idx>,
+ _trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
_ => 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! {
.arg(aux_dir)
.arg("-o")
.arg(out_dir)
+ .arg("--deny")
+ .arg("warnings")
.arg(&self.testpaths.file)
.args(&self.props.compile_flags);
// patterns still match the raw compiler output.
if self.props.error_patterns.is_empty() {
rustc.args(&["--error-format", "json"]);
+ rustc.args(&["--json", "future-incompat"]);
}
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
Ui => {
if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
rustc.args(&["--error-format", "json"]);
+ rustc.args(&["--json", "future-incompat"]);
}
rustc.arg("-Ccodegen-units=1");
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
- rustc.arg("-Zemit-future-incompat-report");
}
MirOpt => {
rustc.args(&[
self.check_rustdoc_test_option(proc_res);
} else {
let root = self.config.find_rust_src_root().unwrap();
- let res = self.cmd2procres(
- Command::new(&self.config.docck_python)
- .arg(root.join("src/etc/htmldocck.py"))
- .arg(&out_dir)
- .arg(&self.testpaths.file),
- );
+ let mut cmd = Command::new(&self.config.docck_python);
+ cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
+ if self.config.bless {
+ cmd.arg("--bless");
+ }
+ let res = self.cmd2procres(&mut cmd);
if !res.status.success() {
self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| {
this.compare_to_default_rustdoc(&out_dir)
-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,
}
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;