"libc",
"num-integer",
"num-traits",
+ "serde",
"time",
"winapi",
]
"rustc-semver",
]
+[[package]]
+name = "collect-license-metadata"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "serde",
+ "serde_json",
+ "spdx-rs",
+]
+
[[package]]
name = "color-eyre"
version = "0.6.2"
"termcolor",
]
+[[package]]
+name = "generate-copyright"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "generic-array"
version = "0.14.4"
[[package]]
name = "libc"
-version = "0.2.135"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
dependencies = [
"rustc-std-workspace-core",
]
"winapi",
]
+[[package]]
+name = "spdx-expression"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77"
+dependencies = [
+ "nom",
+ "serde",
+ "thiserror",
+ "tracing",
+]
+
+[[package]]
+name = "spdx-rs"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3c02f6eb7e7b4100c272f685a9ccaccaab302324e8c7ec3e2ee72340fb29ff3"
+dependencies = [
+ "chrono",
+ "log",
+ "nom",
+ "serde",
+ "spdx-expression",
+ "strum",
+ "strum_macros",
+ "thiserror",
+ "uuid",
+]
+
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+[[package]]
+name = "strum"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
+
+[[package]]
+name = "strum_macros"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
[[package]]
name = "syn"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom 0.2.0",
+]
+
[[package]]
name = "valuable"
version = "0.1.0"
"src/tools/bump-stage0",
"src/tools/replace-version-placeholder",
"src/tools/lld-wrapper",
+ "src/tools/collect-license-metadata",
+ "src/tools/generate-copyright",
]
exclude = [
use std::str::FromStr;
use bitflags::bitflags;
+#[cfg(feature = "nightly")]
+use rustc_data_structures::stable_hasher::StableOrd;
use rustc_index::vec::{Idx, IndexVec};
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic;
raw: u64,
}
+// Safety: Ord is implement as just comparing numerical values and numerical values
+// are not changed by (de-)serialization.
+#[cfg(feature = "nightly")]
+unsafe impl StableOrd for Size {}
+
// This is debug-printed a lot in larger structs, don't waste too much space there
impl fmt::Debug for Size {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
),
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
*capture_clause,
+ None,
*closure_node_id,
None,
e.span,
pub(super) fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
+ outer_hir_id: Option<hir::HirId>,
closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
hir::ExprKind::Closure(c)
};
- let parent_has_track_caller = self
- .attrs
- .values()
- .find(|attrs| attrs.into_iter().find(|attr| attr.has_name(sym::track_caller)).is_some())
- .is_some();
- let unstable_span =
- self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
- let hir_id = if parent_has_track_caller {
- let generator_hir_id = self.lower_node_id(closure_node_id);
+ let track_caller = outer_hir_id
+ .and_then(|id| self.attrs.get(&id.local_id))
+ .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
+
+ let hir_id = self.lower_node_id(closure_node_id);
+ if track_caller {
+ let unstable_span = self.mark_span_with_reason(
+ DesugaringKind::Async,
+ span,
+ self.allow_gen_future.clone(),
+ );
self.lower_attrs(
- generator_hir_id,
+ hir_id,
&[Attribute {
kind: AttrKind::Normal(ptr::P(NormalAttr {
item: AttrItem {
span: unstable_span,
}],
);
- generator_hir_id
- } else {
- self.lower_node_id(closure_node_id)
- };
+ }
let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) };
let async_body = this.make_async_expr(
capture_clause,
+ // FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]`
+ // can be applied on async closures as well.
+ None,
inner_closure_id,
async_ret_ty,
body.span,
// only cares about the input argument patterns in the function
// declaration (decl), not the return types.
let asyncness = header.asyncness;
- let body_id =
- this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
+ let body_id = this.lower_maybe_async_body(
+ span,
+ hir_id,
+ &decl,
+ asyncness,
+ body.as_deref(),
+ );
let mut itctx = ImplTraitContext::Universal;
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
let hir_id = self.lower_node_id(i.id);
+ self.lower_attrs(hir_id, &i.attrs);
let trait_item_def_id = hir_id.expect_owner();
let (generics, kind, has_default) = match &i.kind {
AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => {
let asyncness = sig.header.asyncness;
let body_id =
- self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
+ self.lower_maybe_async_body(i.span, hir_id, &sig.decl, asyncness, Some(&body));
let (generics, sig) = self.lower_method_sig(
generics,
sig,
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
- self.lower_attrs(hir_id, &i.attrs);
let item = hir::TraitItem {
owner_id: trait_item_def_id,
ident: self.lower_ident(i.ident),
// Since `default impl` is not yet implemented, this is always true in impls.
let has_value = true;
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+ let hir_id = self.lower_node_id(i.id);
+ self.lower_attrs(hir_id, &i.attrs);
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
- let body_id =
- self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
+ let body_id = self.lower_maybe_async_body(
+ i.span,
+ hir_id,
+ &sig.decl,
+ asyncness,
+ body.as_deref(),
+ );
let (generics, sig) = self.lower_method_sig(
generics,
sig,
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
- let hir_id = self.lower_node_id(i.id);
- self.lower_attrs(hir_id, &i.attrs);
let item = hir::ImplItem {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(i.ident),
fn lower_maybe_async_body(
&mut self,
span: Span,
+ fn_id: hir::HirId,
decl: &FnDecl,
asyncness: Async,
body: Option<&Block>,
let async_expr = this.make_async_expr(
CaptureBy::Value,
+ Some(fn_id),
closure_id,
None,
body.span,
let align = ImmTy::from_uint(target_align, args[1].layout).into();
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
- // We replace the entire entire function call with a "tail call".
+ // We replace the entire function call with a "tail call".
// Note that this happens before the frame of the original function
// is pushed on the stack.
self.eval_fn_call(
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
trace!("body: {:#?}", body);
+ // Clobber previous return place contents, nobody is supposed to be able to see them any more
+ // This also checks dereferenceable, but not align. We rely on all constructed places being
+ // sufficiently aligned (in particular we rely on `deref_operand` checking alignment).
+ self.write_uninit(return_place)?;
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
}
}
-impl_stable_hash_via_hash!(Fingerprint);
+impl_stable_traits_for_trivial_type!(Fingerprint);
impl<E: Encoder> Encodable<E> for Fingerprint {
#[inline]
-use crate::stable_hasher::{HashStable, StableHasher};
+use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::iter::FromIterator;
}
}
-impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.data.hash_stable(ctx, hasher);
self.items.hash(hasher)
}
}
+
impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V>
where
K: HashStable<C>,
V: HashStable<C>,
{
fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) {
- self.items.hash_stable(ctx, hasher)
+ let SortedIndexMultiMap {
+ items,
+ // We can ignore this field because it is not observable from the outside.
+ idx_sorted_by_item_key: _,
+ } = self;
+
+ items.hash_stable(ctx, hasher)
}
}
fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
}
-/// Implement HashStable by just calling `Hash::hash()`.
+/// Trait for marking a type as having a sort order that is
+/// stable across compilation session boundaries. More formally:
+///
+/// ```txt
+/// Ord::cmp(a1, b1) == Ord:cmp(a2, b2)
+/// where a2 = decode(encode(a1, context1), context2)
+/// b2 = decode(encode(b1, context1), context2)
+/// ```
+///
+/// i.e. the result of `Ord::cmp` is not influenced by encoding
+/// the values in one session and then decoding them in another
+/// session.
+///
+/// This is trivially true for types where encoding and decoding
+/// don't change the bytes of the values that are used during
+/// comparison and comparison only depends on these bytes (as
+/// opposed to some non-local state). Examples are u32, String,
+/// Path, etc.
+///
+/// But it is not true for:
+/// - `*const T` and `*mut T` because the values of these pointers
+/// will change between sessions.
+/// - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete
+/// values depend on state that might be different between
+/// compilation sessions.
+pub unsafe trait StableOrd: Ord {}
+
+/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
+/// that has the same requirements.
///
/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
/// here in this module.
///
/// Use `#[derive(HashStable_Generic)]` instead.
-macro_rules! impl_stable_hash_via_hash {
+macro_rules! impl_stable_traits_for_trivial_type {
($t:ty) => {
impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
#[inline]
::std::hash::Hash::hash(self, hasher);
}
}
+
+ unsafe impl $crate::stable_hasher::StableOrd for $t {}
};
}
-impl_stable_hash_via_hash!(i8);
-impl_stable_hash_via_hash!(i16);
-impl_stable_hash_via_hash!(i32);
-impl_stable_hash_via_hash!(i64);
-impl_stable_hash_via_hash!(isize);
+impl_stable_traits_for_trivial_type!(i8);
+impl_stable_traits_for_trivial_type!(i16);
+impl_stable_traits_for_trivial_type!(i32);
+impl_stable_traits_for_trivial_type!(i64);
+impl_stable_traits_for_trivial_type!(isize);
-impl_stable_hash_via_hash!(u8);
-impl_stable_hash_via_hash!(u16);
-impl_stable_hash_via_hash!(u32);
-impl_stable_hash_via_hash!(u64);
-impl_stable_hash_via_hash!(usize);
+impl_stable_traits_for_trivial_type!(u8);
+impl_stable_traits_for_trivial_type!(u16);
+impl_stable_traits_for_trivial_type!(u32);
+impl_stable_traits_for_trivial_type!(u64);
+impl_stable_traits_for_trivial_type!(usize);
-impl_stable_hash_via_hash!(u128);
-impl_stable_hash_via_hash!(i128);
+impl_stable_traits_for_trivial_type!(u128);
+impl_stable_traits_for_trivial_type!(i128);
-impl_stable_hash_via_hash!(char);
-impl_stable_hash_via_hash!(());
+impl_stable_traits_for_trivial_type!(char);
+impl_stable_traits_for_trivial_type!(());
impl<CTX> HashStable<CTX> for ! {
fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
}
}
+// Safety: String comparison only depends on their contents and the
+// contents are not changed by (de-)serialization.
+unsafe impl StableOrd for String {}
+
impl<HCX> ToStableHashKey<HCX> for String {
type KeyType = String;
#[inline]
}
}
+// Safety: sort order of bools is not changed by (de-)serialization.
+unsafe impl StableOrd for bool {}
+
impl<T, CTX> HashStable<CTX> for Option<T>
where
T: HashStable<CTX>,
}
}
+// Safety: the Option wrapper does not add instability to comparison.
+unsafe impl<T: StableOrd> StableOrd for Option<T> {}
+
impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
where
T1: HashStable<CTX>,
}
}
-impl_stable_hash_via_hash!(::std::path::Path);
-impl_stable_hash_via_hash!(::std::path::PathBuf);
+impl_stable_traits_for_trivial_type!(::std::path::Path);
+impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
where
impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
where
- K: ToStableHashKey<HCX>,
+ K: HashStable<HCX> + StableOrd,
V: HashStable<HCX>,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
- let key = key.to_stable_hash_key(hcx);
- key.hash_stable(hcx, hasher);
- value.hash_stable(hcx, hasher);
- });
+ self.len().hash_stable(hcx, hasher);
+ for entry in self.iter() {
+ entry.hash_stable(hcx, hasher);
+ }
}
}
impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K>
where
- K: ToStableHashKey<HCX>,
+ K: HashStable<HCX> + StableOrd,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
- let key = key.to_stable_hash_key(hcx);
- key.hash_stable(hcx, hasher);
- });
+ self.len().hash_stable(hcx, hasher);
+ for entry in self.iter() {
+ entry.hash_stable(hcx, hasher);
+ }
}
}
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
.generics_label = lifetimes in impl do not match this {$item_kind} in trait
+ .where_label = this `where` clause might not match the one in the trait
+ .bounds_label = this bound might be missing in the impl
hir_analysis_drop_impl_on_wrong_item =
the `Drop` trait may only be implemented for local structs, enums, and unions
use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
use rustc_span::{def_id::DefPathHash, HashStableContext};
use std::fmt;
pub const INVALID: ItemLocalId = ItemLocalId::MAX;
}
+// Safety: Ord is implement as just comparing the LocalItemId's numerical
+// values and these are not changed by (de-)serialization.
+unsafe impl StableOrd for ItemLocalId {}
+
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
pub const CRATE_HIR_ID: HirId =
HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
adt_substs,
);
let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
+ let ty = self.normalize_ty(span, ty);
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
}
}
.get_generics(impl_m.def_id.expect_local())
.expect("expected impl item to have generics or else we can't compare them")
.span;
- let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() {
- Some(
- tcx.hir()
- .get_generics(local_def_id)
- .expect("expected trait item to have generics or else we can't compare them")
- .span,
- )
- } else {
- None
- };
+ let mut generics_span = None;
+ let mut bounds_span = vec![];
+ let mut where_span = None;
+ if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+ && let Some(trait_generics) = trait_node.generics()
+ {
+ generics_span = Some(trait_generics.span);
+ // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+ // *are* present in the impl.
+ for p in trait_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(lt) = b {
+ bounds_span.push(lt.ident.span);
+ }
+ }
+ }
+ }
+ if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+ && let Some(impl_generics) = impl_node.generics()
+ {
+ let mut impl_bounds = 0;
+ for p in impl_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(_) = b {
+ impl_bounds += 1;
+ }
+ }
+ }
+ }
+ if impl_bounds == bounds_span.len() {
+ bounds_span = vec![];
+ } else if impl_generics.has_where_clause_predicates {
+ where_span = Some(impl_generics.where_clause_span);
+ }
+ }
+ }
let reported = tcx
.sess
.create_err(LifetimesOrBoundsMismatchOnTrait {
item_kind: assoc_item_kind_str(impl_m),
ident: impl_m.ident(tcx),
generics_span,
+ bounds_span,
+ where_span,
})
.emit_unless(delay);
-
return Err(reported);
}
pub span: Span,
#[label(generics_label)]
pub generics_span: Option<Span>,
+ #[label(where_label)]
+ pub where_span: Option<Span>,
+ #[label(bounds_label)]
+ pub bounds_span: Vec<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
/// Defines the `TermsContext` basically houses an arena where we can
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
// ```
// we may not use `'c` in the hidden type.
- struct OpaqueTypeLifetimeCollector {
+ struct OpaqueTypeLifetimeCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ root_def_id: DefId,
variances: Vec<ty::Variance>,
}
- impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
+ impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> {
+ #[instrument(level = "trace", skip(self), ret)]
+ fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> {
+ if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) {
+ let child_variances = self.tcx.variances_of(def_id);
+ for (a, v) in substs.iter().zip(child_variances) {
+ if *v != ty::Bivariant {
+ a.visit_with(self)?;
+ }
+ }
+ ControlFlow::CONTINUE
+ } else {
+ substs.visit_with(self)
+ }
+ }
+ }
+
+ impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
#[instrument(level = "trace", skip(self), ret)]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
}
r.super_visit_with(self)
}
+
+ #[instrument(level = "trace", skip(self), ret)]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
+ ty::Projection(proj)
+ if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ {
+ self.visit_opaque(proj.item_def_id, proj.substs)
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
}
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
}
}
- let mut collector = OpaqueTypeLifetimeCollector { variances };
+ let mut collector =
+ OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
}
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
+ // This suggestion is incorrect for
+ // fn foo() -> bool { match () { () => true } || match () { () => true } }
err.span_suggestion_short(
span.shrink_to_hi(),
"consider using a semicolon here",
";",
- Applicability::MachineApplicable,
+ Applicability::MaybeIncorrect,
);
}
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
+use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_errors::{ErrorGuaranteed, PResult};
use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
});
+ let ty::ResolverOutputs {
+ definitions,
+ global_ctxt: untracked_resolutions,
+ ast_lowering: untracked_resolver_for_lowering,
+ } = resolver_outputs;
+
let gcx = sess.time("setup_global_ctxt", || {
global_ctxt.get_or_init(move || {
TyCtxt::create_global_ctxt(
lint_store,
arena,
hir_arena,
- resolver_outputs,
+ definitions,
+ untracked_resolutions,
krate,
dep_graph,
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
})
});
- QueryContext { gcx }
+ let mut qcx = QueryContext { gcx };
+ qcx.enter(|tcx| {
+ tcx.feed_unit_query()
+ .resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering)))
+ });
+ qcx
}
/// Runs the resolution, type-checking, region checking and other
pub fn start_codegen<'tcx>(
codegen_backend: &dyn CodegenBackend,
tcx: TyCtxt<'tcx>,
- outputs: &OutputFilenames,
) -> Box<dyn Any> {
info!("Pre-codegen\n{:?}", tcx.debug_stats());
- let (metadata, need_metadata_module) =
- rustc_metadata::fs::encode_and_write_metadata(tcx, outputs);
+ let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx);
let codegen = tcx.sess.time("codegen_crate", move || {
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
info!("Post-codegen\n{:?}", tcx.debug_stats());
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
- if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) {
+ if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) {
tcx.sess.emit_err(CantEmitMIR { error });
tcx.sess.abort_if_errors();
}
use std::any::Any;
use std::cell::{Ref, RefCell, RefMut};
use std::rc::Rc;
+use std::sync::Arc;
/// Represent the result of a query.
///
pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
self.global_ctxt.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
- let outputs = self.prepare_outputs()?.peek().clone();
+ let outputs = self.prepare_outputs()?.take();
let dep_graph = self.dep_graph()?.peek().clone();
let (krate, resolver, lint_store) = self.expansion()?.take();
Ok(passes::create_global_ctxt(
pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
self.ongoing_codegen.compute(|| {
- let outputs = self.prepare_outputs()?;
self.global_ctxt()?.peek_mut().enter(|tcx| {
tcx.analysis(()).ok();
// Hook for UI tests.
Self::check_for_rustc_errors_attr(tcx);
- Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
+ Ok(passes::start_codegen(&***self.codegen_backend(), tcx))
})
})
}
let codegen_backend = self.codegen_backend().clone();
let dep_graph = self.dep_graph()?.peek().clone();
- let prepare_outputs = self.prepare_outputs()?.take();
- let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
+ let (crate_hash, prepare_outputs) = self
+ .global_ctxt()?
+ .peek_mut()
+ .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone()));
let ongoing_codegen = self.ongoing_codegen()?.take();
Ok(Linker {
// compilation outputs
dep_graph: DepGraph,
- prepare_outputs: OutputFilenames,
+ prepare_outputs: Arc<OutputFilenames>,
crate_hash: Svh,
ongoing_codegen: Box<dyn Any>,
}
modifiers.eval_always.is_none(),
"Query {name} cannot be both `feedable` and `eval_always`."
);
- assert!(
- modifiers.no_hash.is_none(),
- "Query {name} cannot be both `feedable` and `no_hash`."
- );
feedable_queries.extend(quote! {
#(#doc_comments)*
[#attribute_stream] fn #name(#arg) #result,
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{CrateType, OutputFilenames, OutputType};
+use rustc_session::config::{CrateType, OutputType};
use rustc_session::output::filename_for_metadata;
use rustc_session::Session;
use tempfile::Builder as TempFileBuilder;
out_filename
}
-pub fn encode_and_write_metadata(
- tcx: TyCtxt<'_>,
- outputs: &OutputFilenames,
-) -> (EncodedMetadata, bool) {
+pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum MetadataKind {
None,
.unwrap_or(MetadataKind::None);
let crate_name = tcx.crate_name(LOCAL_CRATE);
- let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
+ let out_filename =
+ filename_for_metadata(tcx.sess, crate_name.as_str(), tcx.output_filenames(()));
// To avoid races with another rustc process scanning the output directory,
// we need to write the file somewhere else and atomically move it to its
// final destination, with an `fs::rename` call. In order for the rename to
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
[decode] borrowck_result:
rustc_middle::mir::BorrowCheckResult<'tcx>,
+ [] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>,
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
[] const_allocs: rustc_middle::mir::interpret::Allocation,
}
query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
- eval_always
+ feedable
no_hash
desc { "getting the resolver for lowering" }
}
use std::ops::{Bound, Deref};
use std::sync::Arc;
-use super::{ImplPolarity, ResolverOutputs, RvalueScopes};
+use super::{ImplPolarity, RvalueScopes};
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
/// This struct should only be created by `create_def`.
#[derive(Copy, Clone)]
-pub struct TyCtxtFeed<'tcx> {
+pub struct TyCtxtFeed<'tcx, KEY: Copy> {
pub tcx: TyCtxt<'tcx>,
// Do not allow direct access, as downstream code must not mutate this field.
- def_id: LocalDefId,
+ key: KEY,
}
-impl<'tcx> TyCtxtFeed<'tcx> {
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> {
+ TyCtxtFeed { tcx: self, key: () }
+ }
+}
+
+impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
+ #[inline(always)]
+ pub fn key(&self) -> KEY {
+ self.key
+ }
+}
+
+impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
#[inline(always)]
pub fn def_id(&self) -> LocalDefId {
- self.def_id
+ self.key
}
}
/// Output of the resolver.
pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
- untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
/// The entire crate as AST. This field serves as the input for the hir_crate query,
/// which lowers it from AST to HIR. It must not be read or used by anything else.
pub untracked_crate: Steal<Lrc<ast::Crate>>,
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
- resolver_outputs: ResolverOutputs,
+ definitions: Definitions,
+ untracked_resolutions: ty::ResolverGlobalCtxt,
krate: Lrc<ast::Crate>,
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
crate_name: &str,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
- let ResolverOutputs {
- definitions,
- global_ctxt: untracked_resolutions,
- ast_lowering: untracked_resolver_for_lowering,
- } = resolver_outputs;
let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
s.emit_fatal(err);
});
lifetimes: common_lifetimes,
consts: common_consts,
untracked_resolutions,
- untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering),
untracked_crate: Steal::new(krate),
on_disk_cache,
queries,
self,
parent: LocalDefId,
data: hir::definitions::DefPathData,
- ) -> TyCtxtFeed<'tcx> {
+ ) -> TyCtxtFeed<'tcx, LocalDefId> {
// This function modifies `self.definitions` using a side-effect.
// We need to ensure that these side effects are re-run by the incr. comp. engine.
// Depending on the forever-red node will tell the graph that the calling query
// This is fine because:
// - those queries are `eval_always` so we won't miss their result changing;
// - this write will have happened before these queries are called.
- let def_id = self.definitions.write().create_def(parent, data);
+ let key = self.definitions.write().create_def(parent, data);
- let feed = TyCtxtFeed { tcx: self.tcx, def_id };
+ let feed = TyCtxtFeed { tcx: self.tcx, key };
feed.def_span(self.span);
feed
}
pub fn provide(providers: &mut ty::query::Providers) {
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
- providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering;
providers.module_reexports =
|tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
_ => None,
}
}
+
+ pub fn to_error<'tcx>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ preceding_substs: &[ty::GenericArg<'tcx>],
+ ) -> ty::GenericArg<'tcx> {
+ match &self.kind {
+ ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
+ ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(),
+ ty::GenericParamDefKind::Const { .. } => {
+ tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into()
+ }
+ }
+ }
}
#[derive(Default)]
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
- GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
- UserTypeAnnotationIndex,
+ GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults,
+ UserType, UserTypeAnnotationIndex,
};
pub use self::instance::{Instance, InstanceDef, ShortInstance};
pub use self::list::List;
};
}
+macro_rules! hash_result {
+ ([]) => {{
+ Some(dep_graph::hash_result)
+ }};
+ ([(no_hash) $($rest:tt)*]) => {{
+ None
+ }};
+ ([$other:tt $($modifiers:tt)*]) => {
+ hash_result!([$($modifiers)*])
+ };
+}
+
macro_rules! define_feedable {
($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
- impl<'tcx> TyCtxtFeed<'tcx> {
- $($(#[$attr])*
+ $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
+ $(#[$attr])*
#[inline(always)]
pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
- let key = self.def_id().into_query_param();
+ let key = self.key().into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
let tcx = self.tcx;
tcx,
key,
&value,
- dep_graph::hash_result,
+ hash_result!([$($modifiers)*]),
);
cache.complete(key, value, dep_node_index)
- })*
- }
+ }
+ })*
}
}
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
}
ExistentialPredicate::AutoTrait(did) => {
- let trait_ref = self.rebind(tcx.mk_trait_ref(did, [self_ty]));
- trait_ref.without_const().to_predicate(tcx)
+ let generics = tcx.generics_of(did);
+ let trait_ref = if generics.params.len() == 1 {
+ tcx.mk_trait_ref(did, [self_ty])
+ } else {
+ // If this is an ill-formed auto trait, then synthesize
+ // new error substs for the missing generics.
+ let err_substs =
+ ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]);
+ tcx.mk_trait_ref(did, err_substs)
+ };
+ self.rebind(trait_ref).without_const().to_predicate(tcx)
}
}
}
}
}
+ // Extend an `original_substs` list to the full number of substs expected by `def_id`,
+ // filling in the missing parameters with error ty/ct or 'static regions.
+ pub fn extend_with_error(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ original_substs: &[GenericArg<'tcx>],
+ ) -> SubstsRef<'tcx> {
+ ty::InternalSubsts::for_item(tcx, def_id, |def, substs| {
+ if let Some(subst) = original_substs.get(def.index as usize) {
+ *subst
+ } else {
+ def.to_error(tcx, substs)
+ }
+ })
+ }
+
#[inline]
pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
self.iter()
/// The dataflow state for an instance of [`ValueAnalysis`].
///
/// Every instance specifies a lattice that represents the possible values of a single tracked
-/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an
+/// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an
/// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is
/// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not
/// the bottom element (because joining an unreachable and any other reachable state yields a
use rustc_middle::mir::write_mir_pretty;
use rustc_middle::mir::Body;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{OutputFilenames, OutputType};
+use rustc_session::config::OutputType;
pub struct Marker(pub &'static str);
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
}
-pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
- let path = outputs.path(OutputType::Mir);
+pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
+ let path = tcx.output_filenames(()).path(OutputType::Mir);
let mut f = io::BufWriter::new(File::create(&path)?);
write_mir_pretty(tcx, None, &mut f)?;
Ok(())
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_session::config::OptLevel;
-use rustc_span::def_id::DefId;
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let mut this = Inliner {
- tcx,
- param_env,
- codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
- history: Vec::new(),
- changed: false,
- };
+ let mut this =
+ Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks);
this.changed
param_env: ParamEnv<'tcx>,
/// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs,
- /// Stack of inlined instances.
- /// We only check the `DefId` and not the substs because we want to
- /// avoid inlining cases of polymorphic recursion.
- /// The number of `DefId`s is finite, so checking history is enough
- /// to ensure that we do not loop endlessly while inlining.
- history: Vec<DefId>,
/// Indicates that the caller body has been modified.
changed: bool,
}
debug!("not-inlined {} [{}]", callsite.callee, reason);
continue;
}
- Ok(new_blocks) => {
+ Ok(_) => {
debug!("inlined {}", callsite.callee);
self.changed = true;
- self.history.push(callsite.callee.def_id());
- self.process_blocks(caller_body, new_blocks);
- self.history.pop();
+ // We could process the blocks returned by `try_inlining` here. However, that
+ // leads to exponential compile times due to the top-down nature of this kind
+ // of inlining.
}
}
}
return None;
}
- if self.history.contains(&callee.def_id()) {
- return None;
- }
-
let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
return Some(CallSite {
// want to keep their span info to improve diagnostics in these cases in a later stage.
(true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
(true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
- (true, Some(AssocOp::Add)) // `{ 42 } + 42
- // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
- // `if x { a } else { b } && if y { c } else { d }`
- if !self.look_ahead(1, |t| t.is_used_keyword()) => {
- // These cases are ambiguous and can't be identified in the parser alone.
- let sp = self.sess.source_map().start_point(self.token.span);
- self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
- false
- }
- (true, Some(AssocOp::LAnd)) |
- (true, Some(AssocOp::LOr)) |
- (true, Some(AssocOp::BitOr)) => {
- // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
- // above due to #74233.
+ (true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus)
+ (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+ (true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure)
+ (true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42`
+ => {
// These cases are ambiguous and can't be identified in the parser alone.
//
// Bitwise AND is left out because guessing intent is hard. We can make
Ok((Some(vr), TrailingToken::MaybeComma))
},
- )
+ ).map_err(|mut err|{
+ err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
+ err
+ })
}
/// Parses `struct Foo { ... }`.
Err(e) => {
// Parsing failed, therefore it must be something more serious
// than just a missing separator.
+ for xx in &e.children {
+ // propagate the help message from sub error 'e' to main error 'expect_err;
+ expect_err.children.push(xx.clone());
+ }
expect_err.emit();
e.cancel();
cx: Ctxt,
key: A,
result: &R,
- hash_result: fn(&mut StableHashingContext<'_>, &R) -> Fingerprint,
+ hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
) -> DepNodeIndex {
if let Some(data) = self.data.as_ref() {
// The caller query has more dependencies than the node we are creating. We may
// For sanity, we still check that the loaded stable hash and the new one match.
if let Some(dep_node_index) = self.dep_node_index_of_opt(&node) {
let _current_fingerprint =
- crate::query::incremental_verify_ich(cx, result, &node, Some(hash_result));
+ crate::query::incremental_verify_ich(cx, result, &node, hash_result);
#[cfg(debug_assertions)]
- data.current.record_edge(dep_node_index, node, _current_fingerprint);
+ if hash_result.is_some() {
+ data.current.record_edge(dep_node_index, node, _current_fingerprint);
+ }
return dep_node_index;
}
});
let hashing_timer = cx.profiler().incr_result_hashing();
- let current_fingerprint =
- cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result));
+ let current_fingerprint = hash_result.map(|hash_result| {
+ cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
+ });
let print_status = cfg!(debug_assertions) && cx.sess().opts.unstable_opts.dep_tasks;
&data.previous,
node,
edges,
- Some(current_fingerprint),
+ current_fingerprint,
print_status,
);
// We have a single lifetime => success.
elision_lifetime = Elision::Param(res)
} else {
- // We have have multiple lifetimes => error.
+ // We have multiple lifetimes => error.
elision_lifetime = Elision::Err;
}
}
if let GenericParamKind::Lifetime = param.kind {
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
- continue;
}
+ continue;
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::ToStableHashKey;
+use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
use rustc_target::abi::Align;
use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
DepInfo,
}
+// Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
+unsafe impl StableOrd for OutputType {}
+
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
type KeyType = Self;
&self,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>> {
- self.tcx
+ let mut candidates: Vec<_> = self
+ .tcx
.all_impls(trait_pred.def_id())
.filter_map(|def_id| {
if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
})
- .collect()
+ .collect();
+ if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
+ // If any of the candidates is a perfect match, we don't want to show all of them.
+ // This is particularly relevant for the case of numeric types (as they all have the
+ // same cathegory).
+ candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
+ }
+ candidates
}
fn report_similar_impl_candidates(
nested: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = selcx.tcx();
- for predicate in tcx
+ let own = tcx
.predicates_of(obligation.predicate.item_def_id)
- .instantiate_own(tcx, obligation.predicate.substs)
- .predicates
- {
+ .instantiate_own(tcx, obligation.predicate.substs);
+ for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
let normalized = normalize_with_depth_to(
selcx,
obligation.param_env,
predicate,
nested,
);
+
+ let nested_cause = if matches!(
+ obligation.cause.code(),
+ super::CompareImplItemObligation { .. }
+ | super::CheckAssociatedTypeBounds { .. }
+ | super::AscribeUserTypeProvePredicate(..)
+ ) {
+ obligation.cause.clone()
+ } else if span.is_dummy() {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::ItemObligation(obligation.predicate.item_def_id),
+ )
+ } else {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::BindingObligation(obligation.predicate.item_def_id, span),
+ )
+ };
nested.push(Obligation::with_depth(
tcx,
- obligation.cause.clone(),
+ nested_cause,
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
# Defaults to the Python interpreter used to execute x.py
#python = "python"
+# The path to the REUSE executable to use. Note that REUSE is not required in
+# most cases, as our tooling relies on a cached (and shrinked) copy of the
+# REUSE output present in the git repository and in our source tarballs.
+#
+# REUSE is only needed if your changes caused the overral licensing of the
+# repository to change, and the cached copy has to be regenerated.
+#
+# Defaults to the "reuse" command in the system path.
+#reuse = "reuse"
+
# Force Cargo to check that Cargo.lock describes the precise dependency
# set that all the Cargo.toml files create, instead of updating it.
#locked-deps = false
use self::Ordering::*;
-/// Trait for equality comparisons which are [partial equivalence
-/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
+/// Trait for equality comparisons.
///
/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`.
/// We use the easier-to-read infix notation in the remainder of this documentation.
/// This trait allows for partial equality, for types that do not have a full
/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
/// so floating point types implement `PartialEq` but not [`trait@Eq`].
+/// Formally speaking, when `Rhs == Self`, this trait corresponds to a [partial equivalence
+/// relation](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
///
/// Implementations must ensure that `eq` and `ne` are consistent with each other:
///
/// #![feature(iter_repeat_n)]
/// use std::iter;
///
-/// // four of the the number four:
+/// // four of the number four:
/// let mut four_fours = iter::repeat_n(4, 4);
///
/// assert_eq!(Some(4), four_fours.next());
// Thus, derefencing both `px` and `py` in the loop below is safe.
//
// Moreover, we set `pxend` and `pyend` to be 4 bytes before the actual
- // end of of `px` and `py`. Thus, the final dereference outside of the
+ // end of `px` and `py`. Thus, the final dereference outside of the
// loop is guaranteed to be valid. (The final comparison will overlap with
// the last comparison done in the loop for lengths that aren't multiples
// of four.)
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.82" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
let slot = unsafe { self.buffer.get_unchecked(index) };
let stamp = slot.stamp.load(Ordering::Acquire);
- // If the the stamp is ahead of the head by 1, we may attempt to pop.
+ // If the stamp is ahead of the head by 1, we may attempt to pop.
if head + 1 == stamp {
let new = if index + 1 < self.cap {
// Same lap, incremented index.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Sender<T> {
- fn drop(&mut self) {
- let _ = self.inner;
- }
+ fn drop(&mut self) {}
}
#[stable(feature = "mpsc_debug", since = "1.8.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for SyncSender<T> {
- fn drop(&mut self) {
- let _ = self.inner;
- }
+ fn drop(&mut self) {}
}
#[stable(feature = "mpsc_debug", since = "1.8.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Receiver<T> {
- fn drop(&mut self) {
- let _ = self.inner;
- }
+ fn drop(&mut self) {}
}
#[stable(feature = "mpsc_debug", since = "1.8.0")]
// We check for 'overflow' with usize::MAX / 2, to make sure there's no
// chance it overflows to 0, which would result in unsoundness.
if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
- // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
+ // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles.
self.decrement_num_running_threads(false);
panic!("too many running threads in thread scope");
}
run::BumpStage0,
run::ReplaceVersionPlaceholder,
run::Miri,
+ run::CollectLicenseMetadata,
+ run::GenerateCopyright,
),
// These commands either don't use paths, or they're special-cased in Build::build()
Kind::Clean | Kind::Format | Kind::Setup => vec![],
pub npm: Option<PathBuf>,
pub gdb: Option<PathBuf>,
pub python: Option<PathBuf>,
+ pub reuse: Option<PathBuf>,
pub cargo_native_static: bool,
pub configure_args: Vec<String>,
nodejs: Option<String> = "nodejs",
npm: Option<String> = "npm",
python: Option<String> = "python",
+ reuse: Option<String> = "reuse",
locked_deps: Option<bool> = "locked-deps",
vendor: Option<bool> = "vendor",
full_bootstrap: Option<bool> = "full-bootstrap",
config.npm = build.npm.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
+ config.reuse = build.reuse.map(PathBuf::from);
config.submodules = build.submodules;
set(&mut config.low_priority, build.low_priority);
set(&mut config.compiler_docs, build.compiler_docs);
args: Vec<String>,
},
Setup {
- profile: Profile,
+ profile: Option<Profile>,
},
}
|path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
));
- profile_string.parse().unwrap_or_else(|err| {
+ let profile = profile_string.parse().unwrap_or_else(|err| {
eprintln!("error: {}", err);
eprintln!("help: the available profiles are:");
eprint!("{}", Profile::all_for_help("- "));
crate::detail_exit(1);
- })
+ });
+ Some(profile)
} else {
- t!(crate::setup::interactive_path())
+ None
};
Subcommand::Setup { profile }
}
metrics: metrics::BuildMetrics::init(),
};
- build.verbose("finding compilers");
- cc_detect::find(&mut build);
- // When running `setup`, the profile is about to change, so any requirements we have now may
- // be different on the next invocation. Don't check for them until the next time x.py is
- // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
- if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
- build.verbose("running sanity check");
- sanity::check(&mut build);
- }
-
// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
let local_version_verbose =
build.local_rebuild = true;
}
- // Make sure we update these before gathering metadata so we don't get an error about missing
- // Cargo.toml files.
- let rust_submodules =
- ["src/tools/rust-installer", "src/tools/cargo", "library/backtrace", "library/stdarch"];
- for s in rust_submodules {
- build.update_submodule(Path::new(s));
- }
+ build.verbose("finding compilers");
+ cc_detect::find(&mut build);
+ // When running `setup`, the profile is about to change, so any requirements we have now may
+ // be different on the next invocation. Don't check for them until the next time x.py is
+ // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
+ //
+ // Similarly, for `setup` we don't actually need submodules or cargo metadata.
+ if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
+ build.verbose("running sanity check");
+ sanity::check(&mut build);
+
+ // Make sure we update these before gathering metadata so we don't get an error about missing
+ // Cargo.toml files.
+ let rust_submodules = [
+ "src/tools/rust-installer",
+ "src/tools/cargo",
+ "library/backtrace",
+ "library/stdarch",
+ ];
+ for s in rust_submodules {
+ build.update_submodule(Path::new(s));
+ }
+ // Now, update all existing submodules.
+ build.update_existing_submodules();
- build.verbose("learning about cargo");
- metadata::build(&mut build);
+ build.verbose("learning about cargo");
+ metadata::build(&mut build);
+ }
build
}
/// If any submodule has been initialized already, sync it unconditionally.
/// This avoids contributors checking in a submodule change by accident.
- pub fn maybe_update_submodules(&self) {
+ pub fn update_existing_submodules(&self) {
// Avoid running git when there isn't a git checkout.
if !self.config.submodules(&self.rust_info()) {
return;
job::setup(self);
}
- self.maybe_update_submodules();
-
if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(&builder::Builder::new(&self), *check, &paths);
}
+use std::path::PathBuf;
use std::process::Command;
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
builder.run(&mut miri);
}
}
+
+#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct CollectLicenseMetadata;
+
+impl Step for CollectLicenseMetadata {
+ type Output = PathBuf;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("src/tools/collect-license-metadata")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(CollectLicenseMetadata);
+ }
+
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let Some(reuse) = &builder.config.reuse else {
+ panic!("REUSE is required to collect the license metadata");
+ };
+
+ // Temporary location, it will be moved to src/etc once it's accurate.
+ let dest = builder.out.join("license-metadata.json");
+
+ let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
+ cmd.env("REUSE_EXE", reuse);
+ cmd.env("DEST", &dest);
+ builder.run(&mut cmd);
+
+ dest
+ }
+}
+
+#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct GenerateCopyright;
+
+impl Step for GenerateCopyright {
+ type Output = PathBuf;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("src/tools/generate-copyright")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(GenerateCopyright);
+ }
+
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let license_metadata = builder.ensure(CollectLicenseMetadata);
+
+ // Temporary location, it will be moved to the proper one once it's accurate.
+ let dest = builder.out.join("COPYRIGHT.md");
+
+ let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
+ cmd.env("LICENSE_METADATA", &license_metadata);
+ cmd.env("DEST", &dest);
+ builder.run(&mut cmd);
+
+ dest
+ }
+}
.map(|p| cmd_finder.must_have(p))
.or_else(|| cmd_finder.maybe_have("gdb"));
+ build.config.reuse = build
+ .config
+ .reuse
+ .take()
+ .map(|p| cmd_finder.must_have(p))
+ .or_else(|| cmd_finder.maybe_have("reuse"));
+
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in &build.targets {
+use crate::Config;
use crate::{t, VERSION};
-use crate::{Config, TargetSelection};
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
+use std::io::Write;
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::Command;
use std::str::FromStr;
-use std::{
- env, fmt, fs,
- io::{self, Write},
-};
+use std::{fmt, fs, io};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Profile {
}
}
-pub fn setup(config: &Config, profile: Profile) {
- let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
-
- if path.exists() {
- eprintln!(
- "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
- path.display()
- );
- eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
- eprintln!(
- "note: this will use the configuration in {}",
- profile.include_path(&config.src).display()
- );
- crate::detail_exit(1);
- }
-
- let settings = format!(
- "# Includes one of the default files in src/bootstrap/defaults\n\
- profile = \"{}\"\n\
- changelog-seen = {}\n",
- profile, VERSION
- );
- t!(fs::write(path, settings));
-
- let include_path = profile.include_path(&config.src);
- println!("`x.py` will now use the configuration at {}", include_path.display());
-
- let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+pub fn setup(config: &Config, profile: Option<Profile>) {
+ let profile = profile.unwrap_or_else(|| t!(interactive_path()));
let stage_path =
- ["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
-
- println!();
+ ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
if !rustup_installed() && profile != Profile::User {
eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
Profile::User => &["dist", "build"],
};
- println!();
-
t!(install_git_hook_maybe(&config));
println!();
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
);
}
+
+ let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
+ setup_config_toml(path, profile, config);
+}
+
+fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
+ if path.exists() {
+ eprintln!();
+ eprintln!(
+ "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
+ path.display()
+ );
+ eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
+ eprintln!(
+ "note: this will use the configuration in {}",
+ profile.include_path(&config.src).display()
+ );
+ crate::detail_exit(1);
+ }
+
+ let settings = format!(
+ "# Includes one of the default files in src/bootstrap/defaults\n\
+ profile = \"{}\"\n\
+ changelog-seen = {}\n",
+ profile, VERSION
+ );
+ t!(fs::write(path, settings));
+
+ let include_path = profile.include_path(&config.src);
+ println!("`x.py` will now use the configuration at {}", include_path.display());
}
fn rustup_installed() -> bool {
// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
+ let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
+ assert!(output.status.success(), "failed to run `git`");
+ PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
+ }));
+ let dst = git.join("hooks").join("pre-push");
+ if dst.exists() {
+ // The git hook has already been set up, or the user already has a custom hook.
+ return Ok(());
+ }
+
let mut input = String::new();
+ println!();
println!(
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
if should_install {
let src = config.src.join("src").join("etc").join("pre-push.sh");
- let git =
- t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
- assert!(output.status.success(), "failed to run `git`");
- PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
- }));
- let dst = git.join("hooks").join("pre-push");
match fs::hard_link(src, &dst) {
Err(e) => eprintln!(
"error: could not create hook {}: do you already have the git hook installed?\n{}",
HtmlChecker, "src/tools/html-checker", "html-checker";
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
+ CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
+ GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
gdb \
libssl-dev \
pkg-config \
- xz-utils
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
wget \
xz \
zlib-devel.i686 \
- zlib-devel.x86_64
+ zlib-devel.x86_64 \
+ && yum clean all
RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
xz-utils \
wget \
libssl-dev \
- pkg-config
+ pkg-config \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/freebsd-toolchain.sh /tmp/
RUN /tmp/freebsd-toolchain.sh x86_64
apt-get install -y --no-install-recommends \
libgmp-dev \
libmpfr-dev \
- libmpc-dev
+ libmpc-dev \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/illumos-toolchain.sh /tmp/
wget \
xz \
zlib-devel.i686 \
- zlib-devel.x86_64
+ zlib-devel.x86_64 \
+ && yum clean all
RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
gdb \
patch \
libssl-dev \
- pkg-config
+ pkg-config \
+ && rm -rf /var/lib/apt/lists/*
WORKDIR /build/
gdb \
zlib1g-dev \
lib32z1-dev \
- xz-utils
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
gdb \
zlib1g-dev \
lib32z1-dev \
- xz-utils
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
xz-utils \
libssl-dev \
pkg-config \
- mingw-w64
+ mingw-w64 \
+ && rm -rf /var/lib/apt/lists/*
RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
# Install es-check
# Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@6.1.1 -g
-RUN npm install eslint@8.6.0 -g
+RUN npm install es-check@6.1.1 eslint@8.6.0 -g
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/
-RUN pip3 install --no-deps --require-hashes -r /tmp/reuse-requirements.txt
+RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
ovmf \
qemu-efi-aarch64 \
qemu-system-arm \
- qemu-system-x86
+ qemu-system-x86 \
+ && rm -rf /var/lib/apt/lists/*
RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
tar -xJ
sudo \
gdb \
xz-utils \
- bzip2
+ bzip2 \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/emscripten.sh /scripts/
RUN bash /scripts/emscripten.sh
llvm-dev \
libfreetype6-dev \
libexpat1-dev \
- tidy
+ tidy \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
pkg-config \
xz-utils \
lld \
- clang
+ clang \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
gdb \
xz-utils \
libssl-dev \
- pkg-config
+ pkg-config \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
pkg-config \
zlib1g-dev \
xz-utils \
- nodejs
+ nodejs \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
pkg-config \
zlib1g-dev \
xz-utils \
- nodejs
+ nodejs \
# Install powershell so we can test x.ps1 on Linux
-RUN apt-get update && \
- apt-get install -y apt-transport-https software-properties-common && \
+ apt-transport-https software-properties-common && \
curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \
dpkg -i packages-microsoft-prod.deb && \
apt-get update && \
- apt-get install -y powershell
+ apt-get install -y powershell \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
gdb \
libssl-dev \
pkg-config \
- xz-utils
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
libssl-dev \
sudo \
xz-utils \
- tidy
+ tidy \
# Install dependencies for chromium browser
-RUN apt-get install -y \
gconf-service \
libasound2 \
libatk1.0-0 \
libnss3 \
lsb-release \
xdg-utils \
- wget
+ wget \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
gdb \
libssl-dev \
pkg-config \
- xz-utils
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
for lib in c cxxrt gcc_s m thr util; do
files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm memstat; do
files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
done
-Subproject commit 3f64052c048c6def93b94a2b514ee88bba918744
+Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
-Subproject commit c533348edd69f11a8f4225d633a05d7093fddbf3
+Subproject commit 19f798d448835a4888e3b3eae7fe69f1d61d8681
-Subproject commit 05532356e7a4dbea2330aabb77611f5179493bb8
+Subproject commit ae406aa5287a9e025abb72343aaceec98458c117
-Subproject commit 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19
+Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731
-Subproject commit 2b15c0abf2bada6e00553814336bc3e2d8399097
+Subproject commit a9869b4a3c4cac3bc6099b41f088679e268400b8
-Subproject commit d0dc6c97a6486f68bac782fff135086eae6d77ec
+Subproject commit e269950a57fa6fcda356426545fb5aa3691a7ced
/* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
the sidebar stays visible for screen readers, which is useful for navigation. */
left: -1000px;
- margin: 0;
- padding: 0;
z-index: 11;
/* Reduce height slightly to account for mobile topbar. */
height: calc(100vh - 45px);
}
.scraped-example .code-wrapper .example-wrap {
- flex: 1;
+ display: grid;
+ grid-template-columns: max-content auto;
+ width: 100%;
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 0;
});
});
- example.querySelector("next")
+ example.querySelector(".next")
.addEventListener("click", () => {
onChangeLoc(() => {
locIndex = (locIndex + 1) % locs.length;
nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt",
}
-pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js");
+pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
-+ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++ _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
++ // mir::Constant
++ // + span: $DIR/cycle.rs:6:5: 6:6
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2 (cleanup): {
-+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
-+ bb4: {
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb4 (cleanup): {
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
}
}
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
-+ scope 3 (inlined g) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+ let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12
-+ scope 4 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
-+ debug g => _6; // in scope 4 at $DIR/cycle.rs:5:6: 5:7
-+ let _7: (); // in scope 4 at $DIR/cycle.rs:6:5: 6:8
-+ let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6
-+ scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
-+ }
-+ }
-+ }
-+ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ StorageLive(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12
-+ StorageLive(_7); // scope 4 at $DIR/cycle.rs:6:5: 6:8
-+ StorageLive(_8); // scope 4 at $DIR/cycle.rs:6:5: 6:6
-+ _8 = &_6; // scope 4 at $DIR/cycle.rs:6:5: 6:6
-+ _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++ _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
++ // mir::Constant
++ // + span: $DIR/cycle.rs:6:5: 6:6
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2 (cleanup): {
-+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
-+ bb4: {
-+ StorageDead(_8); // scope 4 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_7); // scope 4 at $DIR/cycle.rs:6:8: 6:9
-+ StorageDead(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb4 (cleanup): {
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
}
}
--- /dev/null
+- // MIR for `main` before Inline
++ // MIR for `main` after Inline
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/exponential_runtime.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++ scope 1 (inlined <() as G>::call) { // at $DIR/exponential_runtime.rs:86:5: 86:22
++ let _2: (); // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++ let _3: (); // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ let _4: (); // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
+- _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++ _2 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ // mir::Constant
+- // + span: $DIR/exponential_runtime.rs:86:5: 86:20
+- // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
++ // + span: $DIR/exponential_runtime.rs:73:9: 73:23
++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ }
+
+ bb1: {
++ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ _3 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++ }
++
++ bb2: {
++ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
++ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ _4 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:75:9: 75:23
++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++ }
++
++ bb3: {
++ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
+ StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
+ _0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
+ return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
+ }
+ }
+
--- /dev/null
+// Checks that code with exponential runtime does not have exponential behavior in inlining.
+
+trait A {
+ fn call();
+}
+
+trait B {
+ fn call();
+}
+impl<T: A> B for T {
+ #[inline]
+ fn call() {
+ <T as A>::call();
+ <T as A>::call();
+ <T as A>::call();
+ }
+}
+
+trait C {
+ fn call();
+}
+impl<T: B> C for T {
+ #[inline]
+ fn call() {
+ <T as B>::call();
+ <T as B>::call();
+ <T as B>::call();
+ }
+}
+
+trait D {
+ fn call();
+}
+impl<T: C> D for T {
+ #[inline]
+ fn call() {
+ <T as C>::call();
+ <T as C>::call();
+ <T as C>::call();
+ }
+}
+
+trait E {
+ fn call();
+}
+impl<T: D> E for T {
+ #[inline]
+ fn call() {
+ <T as D>::call();
+ <T as D>::call();
+ <T as D>::call();
+ }
+}
+
+trait F {
+ fn call();
+}
+impl<T: E> F for T {
+ #[inline]
+ fn call() {
+ <T as E>::call();
+ <T as E>::call();
+ <T as E>::call();
+ }
+}
+
+trait G {
+ fn call();
+}
+impl<T: F> G for T {
+ #[inline]
+ fn call() {
+ <T as F>::call();
+ <T as F>::call();
+ <T as F>::call();
+ }
+}
+
+impl A for () {
+ #[inline(never)]
+ fn call() {}
+}
+
+// EMIT_MIR exponential_runtime.main.Inline.diff
+fn main() {
+ <() as G>::call();
+}
let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
-+ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
-+ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
-+ }
-+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
++ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
// mir::Constant
- // + span: $DIR/inline_cycle.rs:14:5: 14:22
-+ // + span: $DIR/inline_cycle.rs:36:9: 36:26
- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
++ // + span: $DIR/inline_cycle.rs:43:9: 43:21
++ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
+ let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
-+ scope 3 (inlined f) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+ let _5: (); // in scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
-+ }
-+ }
+ }
bb0: {
+ _2 = f; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
// mir::Constant
- // + span: $DIR/inline_cycle.rs:49:5: 49:9
-+ // + span: $DIR/inline_cycle.rs:49:10: 49:11
-+ // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+- // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
+- // mir::Constant
+ // + span: $DIR/inline_cycle.rs:49:10: 49:11
+ // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ StorageLive(_5); // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
-+ _5 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
++ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ // mir::Constant
-+ // + span: $DIR/inline_cycle.rs:59:5: 59:9
- // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
- // mir::Constant
-- // + span: $DIR/inline_cycle.rs:49:10: 49:11
-+ // + span: $DIR/inline_cycle.rs:59:10: 59:11
- // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
++ // + span: $DIR/inline_cycle.rs:54:5: 54:6
++ // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
}
bb1: {
-+ StorageDead(_5); // scope 3 at $DIR/inline_cycle.rs:59:12: 59:13
+ StorageDead(_4); // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8
+ StorageDead(_3); // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9
+ StorageDead(_2); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
-+ scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
-+ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
-+ }
-+ }
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
// mir::Constant
- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
+- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
++ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ scope 3 {
+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
+ }
-+ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:28:13: 28:16
-+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+ }
-+ }
-+ }
-+ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
-+ scope 5 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+ }
+ }
+ }
+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
++ _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++ // mir::Constant
++ // + span: $DIR/inline_diverging.rs:27:13: 27:14
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
+ }
+
+ bb1: {
-+ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
++ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ // mir::Constant
++ // + span: $DIR/inline_diverging.rs:28:13: 28:14
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++ }
++
++ bb2: {
++ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
++ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
++ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++ _8 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++ Deinit(_1); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++ (_1.0: !) = move _8; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++ (_1.1: !) = move _9; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
++ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ drop(_2) -> bb3; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ }
++
++ bb3: {
++ unreachable; // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
++ }
++
++ bb4 (cleanup): {
++ drop(_3) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ }
++
++ bb5 (cleanup): {
++ drop(_2) -> bb6; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ }
++
++ bb6 (cleanup): {
++ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
}
}
let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
scope 9 {
debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
- debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
}
}
}
StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
_18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
+- _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
++ _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/result.rs:LL:COL
+ // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
}
- bb5: {
+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+ switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
}
+
+- bb8: {
++ bb7: {
+ StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
+ }
}
+// This test ensures that the margins on methods are coherent inside an impl block.
goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
+
+store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre", "scrollTop")
+focus: ".scraped-example-list > .scraped-example .next"
+press-key: "Enter"
+assert-property-false: (".scraped-example-list > .scraped-example pre", {
+ "scrollTop": |initialScrollTop|
+})
+focus: ".scraped-example-list > .scraped-example .prev"
+press-key: "Enter"
+assert-property: (".scraped-example-list > .scraped-example pre", {
+ "scrollTop": |initialScrollTop|
+})
+
store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
assert-property-false: (".scraped-example-list > .scraped-example pre", {
"scrollHeight": |smallOffsetHeight|
println!("hello world!");
println!("hello world!");
}
+ scrape_examples::test();
}
--- /dev/null
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct S<T>(T);
+
+impl<T: O> S<T> {
+ type P = <T as O>::P;
+}
+
+trait O {
+ type P;
+}
+
+impl O for i32 {
+ type P = String;
+}
+
+fn main() {
+ let _: S<i32>::P = String::new();
+}
--- /dev/null
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl S {
+ type P<T: O> = <T as O>::P;
+}
+
+trait O {
+ type P;
+}
+
+impl O for i32 {
+ type P = String;
+}
+
+fn main() {
+ let _: S::P<i32> = String::new();
+}
--- /dev/null
+// check-pass
+// edition:2021
+
+#[track_caller]
+fn f() {
+ let _ = async {};
+}
+
+fn main() {
+ f();
+}
bar_track_caller().await
}
+struct Foo;
+
+impl Foo {
+ #[track_caller]
+ async fn bar_assoc() {
+ panic!();
+ }
+}
+
+async fn foo_assoc() {
+ Foo::bar_assoc().await
+}
+
fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
let loc = Arc::new(Mutex::new(None));
fn main() {
assert_eq!(panicked_at(|| block_on(foo())), 41);
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54);
+ assert_eq!(panicked_at(|| block_on(foo_assoc())), 67);
}
--- /dev/null
+#![feature(auto_traits)]
+
+auto trait Trait1<'a> {}
+//~^ ERROR auto traits cannot have generic parameters
+
+fn f<'a>(x: &dyn Trait1<'a>)
+{}
+
+fn main() {
+ f(&1);
+}
--- /dev/null
+error[E0567]: auto traits cannot have generic parameters
+ --> $DIR/bad-generics-on-dyn.rs:3:18
+ |
+LL | auto trait Trait1<'a> {}
+ | ------^^^^ help: remove the parameters
+ | |
+ | auto trait cannot have generic parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0567`.
|
= help: the trait `Mul<f32>` is not implemented for `i32`
= help: the following other types implement trait `Mul<Rhs>`:
- <&'a f32 as Mul<f32>>
- <&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
<&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&i32 as Mul<&i32>>
+ <i32 as Mul<&i32>>
+ <i32 as Mul>
error: aborting due to previous error
LL | 1_u32
| ----- return type was inferred to be `u32` here
|
- = help: the following other types implement trait `Traitor<N, M>`:
- <u32 as Traitor<N, 2>>
- <u64 as Traitor<1, 2>>
+ = help: the trait `Traitor<N, 2>` is implemented for `u32`
error[E0277]: the trait bound `u64: Traitor` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:21:13
LL | 1_u64
| ----- return type was inferred to be `u64` here
|
- = help: the following other types implement trait `Traitor<N, M>`:
- <u32 as Traitor<N, 2>>
- <u64 as Traitor<1, 2>>
+ = help: the trait `Traitor<1, 2>` is implemented for `u64`
error: aborting due to 3 previous errors
--- /dev/null
+trait Foo<const M: u8, const M: u8 = M> {}
+//~^ ERROR the name `M` is already used for a generic parameter in this item's generic parameters
+impl Foo<2> for () {}
+fn main() {}
--- /dev/null
+error[E0403]: the name `M` is already used for a generic parameter in this item's generic parameters
+ --> $DIR/self-referential.rs:1:30
+ |
+LL | trait Foo<const M: u8, const M: u8 = M> {}
+ | - ^ already used
+ | |
+ | first use of `M`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0403`.
|
= help: the trait `~const Add<u8>` is not implemented for `i8`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&i8 as Add<&i8>>
+ <i8 as Add<&i8>>
+ <i8 as Add>
error: aborting due to 2 previous errors
|
= help: the trait `~const Add<u8>` is not implemented for `i8`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&i8 as Add<&i8>>
+ <i8 as Add<&i8>>
+ <i8 as Add>
error[E0604]: only `u8` can be cast as `char`, not `i8`
--> $DIR/const-eval-overflow-4b.rs:22:13
<i8 as Foo<u32>>
<i8 as Foo<u64>>
<i8 as Foo<u8>>
- <u8 as Foo<bool>>
- <u8 as Foo<u16>>
- <u8 as Foo<u32>>
- <u8 as Foo<u64>>
error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied
--> $DIR/issue-39802-show-5-trait-impls.rs:25:21
| required by a bound introduced by this call
|
= help: the following other types implement trait `Foo<B>`:
- <i8 as Foo<bool>>
- <i8 as Foo<u16>>
- <i8 as Foo<u32>>
- <i8 as Foo<u64>>
- <i8 as Foo<u8>>
<u8 as Foo<bool>>
<u8 as Foo<u16>>
<u8 as Foo<u32>>
| first use of `T`
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
- --> $DIR/duplicate-type-parameter.rs:24:6
+ --> $DIR/duplicate-type-parameter.rs:24:8
|
LL | impl<T,T> Qux<T,T> for Option<T> {}
- | ^ unconstrained type parameter
+ | ^ unconstrained type parameter
error: aborting due to 8 previous errors
--- /dev/null
+struct S;
+
+trait D {
+ type P<T: Copy>;
+ //~^ NOTE required by this bound in `D::P`
+ //~| NOTE required by a bound in `D::P`
+}
+
+impl D for S {
+ type P<T: Copy> = ();
+}
+
+fn main() {
+ let _: <S as D>::P<String>;
+ //~^ ERROR the trait bound `String: Copy` is not satisfied
+ //~| NOTE the trait `Copy` is not implemented for `String`
+}
--- /dev/null
+error[E0277]: the trait bound `String: Copy` is not satisfied
+ --> $DIR/own-bound-span.rs:14:12
+ |
+LL | let _: <S as D>::P<String>;
+ | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+ |
+note: required by a bound in `D::P`
+ --> $DIR/own-bound-span.rs:4:15
+ |
+LL | type P<T: Copy>;
+ | ^^^^ required by this bound in `D::P`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
|
= help: the trait `Add<impl Foo>` is not implemented for `u32`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&'a u32 as Add<u32>>
+ <&u32 as Add<&u32>>
+ <u32 as Add<&u32>>
+ <u32 as Add>
error: aborting due to 2 previous errors; 1 warning emitted
--- /dev/null
+// edition: 2021
+
+fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
+ async move { let _s = s; }
+ //~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
+ --> $DIR/nested-return-type4.rs:4:5
+ |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
+ | -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
+LL | async move { let _s = s; }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound
+ |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's {
+ | ++++
+help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound
+ |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
|
= help: the trait `Sub<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
<&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&f64 as Sub<&f64>>
+ <f64 as Sub<&f64>>
+ <f64 as Sub>
help: consider using a floating-point literal by writing it with `.0`
|
LL | 1.0f64 - 1.0
LL | assert_copy::<&'static mut isize>();
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
|
- = help: the following other types implement trait `Copy`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `Copy` is implemented for `isize`
note: required by a bound in `assert_copy`
--> $DIR/kindck-copy.rs:5:18
|
LL | assert_copy::<&'a mut isize>();
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
|
- = help: the following other types implement trait `Copy`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `Copy` is implemented for `isize`
note: required by a bound in `assert_copy`
--> $DIR/kindck-copy.rs:5:18
|
<&'a str as PartialEq<OsString>>
<&'a str as PartialEq<String>>
<&'b str as PartialEq<Cow<'a, str>>>
- <String as PartialEq<&'a str>>
- <String as PartialEq<Cow<'a, str>>>
- <String as PartialEq<str>>
- <String as PartialEq>
<str as PartialEq<Cow<'a, str>>>
- and 4 others
+ <str as PartialEq<OsStr>>
+ <str as PartialEq<OsString>>
+ <str as PartialEq<String>>
+ <str as PartialEq>
error[E0308]: mismatched types
--> $DIR/lex-bad-char-literals-6.rs:15:20
<&'a str as PartialEq<OsString>>
<&'a str as PartialEq<String>>
<&'b str as PartialEq<Cow<'a, str>>>
- <String as PartialEq<&'a str>>
- <String as PartialEq<Cow<'a, str>>>
- <String as PartialEq<str>>
- <String as PartialEq>
<str as PartialEq<Cow<'a, str>>>
- and 4 others
+ <str as PartialEq<OsStr>>
+ <str as PartialEq<OsString>>
+ <str as PartialEq<String>>
+ <str as PartialEq>
error: aborting due to 6 previous errors
LL | values!(STRING(1) as (String) => cfg(test),);
| -------------------------------------------- in this macro invocation
|
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
error: macro expansion ignores token `(String)` and any following
|
= help: the trait `Sub<Option<{integer}>>` is not implemented for `usize`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
- <&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&'a usize as Sub<usize>>
+ <&usize as Sub<&usize>>
+ <usize as Sub<&usize>>
+ <usize as Sub>
error[E0277]: cannot multiply `{integer}` by `()`
--> $DIR/binops.rs:4:7
|
= help: the trait `Add<()>` is not implemented for `usize`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&'a usize as Add<usize>>
+ <&usize as Add<&usize>>
+ <usize as Add<&usize>>
+ <usize as Add>
error: aborting due to previous error
|
= help: the trait `Add<{float}>` is not implemented for `u8`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&'a u8 as Add<u8>>
+ <&u8 as Add<&u8>>
+ <u8 as Add<&u8>>
+ <u8 as Add>
error[E0277]: cannot add `&str` to `f64`
--> $DIR/not-suggest-float-literal.rs:6:7
|
= help: the trait `Add<&str>` is not implemented for `f64`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&f64 as Add<&f64>>
+ <f64 as Add<&f64>>
+ <f64 as Add>
error[E0277]: cannot add `{integer}` to `f64`
--> $DIR/not-suggest-float-literal.rs:11:7
|
= help: the trait `Add<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&f64 as Add<&f64>>
+ <f64 as Add<&f64>>
+ <f64 as Add>
error[E0277]: cannot subtract `{float}` from `u8`
--> $DIR/not-suggest-float-literal.rs:15:7
|
= help: the trait `Sub<{float}>` is not implemented for `u8`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
- <&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&'a u8 as Sub<u8>>
+ <&u8 as Sub<&u8>>
+ <u8 as Sub<&u8>>
+ <u8 as Sub>
error[E0277]: cannot subtract `&str` from `f64`
--> $DIR/not-suggest-float-literal.rs:19:7
|
= help: the trait `Sub<&str>` is not implemented for `f64`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
<&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&f64 as Sub<&f64>>
+ <f64 as Sub<&f64>>
+ <f64 as Sub>
error[E0277]: cannot subtract `{integer}` from `f64`
--> $DIR/not-suggest-float-literal.rs:24:7
|
= help: the trait `Sub<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
<&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&f64 as Sub<&f64>>
+ <f64 as Sub<&f64>>
+ <f64 as Sub>
error[E0277]: cannot multiply `u8` by `{float}`
--> $DIR/not-suggest-float-literal.rs:28:7
|
= help: the trait `Mul<{float}>` is not implemented for `u8`
= help: the following other types implement trait `Mul<Rhs>`:
- <&'a f32 as Mul<f32>>
- <&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
- <&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&'a u8 as Mul<u8>>
+ <&u8 as Mul<&u8>>
+ <u8 as Mul<&u8>>
+ <u8 as Mul>
error[E0277]: cannot multiply `f64` by `&str`
--> $DIR/not-suggest-float-literal.rs:32:7
|
= help: the trait `Mul<&str>` is not implemented for `f64`
= help: the following other types implement trait `Mul<Rhs>`:
- <&'a f32 as Mul<f32>>
<&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
- <&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&f64 as Mul<&f64>>
+ <f64 as Mul<&f64>>
+ <f64 as Mul>
error[E0277]: cannot multiply `f64` by `{integer}`
--> $DIR/not-suggest-float-literal.rs:37:7
|
= help: the trait `Mul<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Mul<Rhs>`:
- <&'a f32 as Mul<f32>>
<&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
- <&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&f64 as Mul<&f64>>
+ <f64 as Mul<&f64>>
+ <f64 as Mul>
error[E0277]: cannot divide `u8` by `{float}`
--> $DIR/not-suggest-float-literal.rs:41:7
|
= help: the trait `Div<{float}>` is not implemented for `u8`
= help: the following other types implement trait `Div<Rhs>`:
- <&'a f32 as Div<f32>>
- <&'a f64 as Div<f64>>
- <&'a i128 as Div<i128>>
- <&'a i16 as Div<i16>>
- <&'a i32 as Div<i32>>
- <&'a i64 as Div<i64>>
- <&'a i8 as Div<i8>>
- <&'a isize as Div<isize>>
- and 54 others
+ <&'a u8 as Div<u8>>
+ <&u8 as Div<&u8>>
+ <u8 as Div<&u8>>
+ <u8 as Div<NonZeroU8>>
+ <u8 as Div>
error[E0277]: cannot divide `f64` by `&str`
--> $DIR/not-suggest-float-literal.rs:45:7
|
= help: the trait `Div<&str>` is not implemented for `f64`
= help: the following other types implement trait `Div<Rhs>`:
- <&'a f32 as Div<f32>>
<&'a f64 as Div<f64>>
- <&'a i128 as Div<i128>>
- <&'a i16 as Div<i16>>
- <&'a i32 as Div<i32>>
- <&'a i64 as Div<i64>>
- <&'a i8 as Div<i8>>
- <&'a isize as Div<isize>>
- and 54 others
+ <&f64 as Div<&f64>>
+ <f64 as Div<&f64>>
+ <f64 as Div>
error[E0277]: cannot divide `f64` by `{integer}`
--> $DIR/not-suggest-float-literal.rs:50:7
|
= help: the trait `Div<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Div<Rhs>`:
- <&'a f32 as Div<f32>>
<&'a f64 as Div<f64>>
- <&'a i128 as Div<i128>>
- <&'a i16 as Div<i16>>
- <&'a i32 as Div<i32>>
- <&'a i64 as Div<i64>>
- <&'a i8 as Div<i8>>
- <&'a isize as Div<isize>>
- and 54 others
+ <&f64 as Div<&f64>>
+ <f64 as Div<&f64>>
+ <f64 as Div>
error: aborting due to 12 previous errors
= help: the trait `Add<{integer}>` is not implemented for `f32`
= help: the following other types implement trait `Add<Rhs>`:
<&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&f32 as Add<&f32>>
+ <f32 as Add<&f32>>
+ <f32 as Add>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x + 100.0
|
= help: the trait `Add<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&f64 as Add<&f64>>
+ <f64 as Add<&f64>>
+ <f64 as Add>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x + 100.0
= help: the trait `Sub<{integer}>` is not implemented for `f32`
= help: the following other types implement trait `Sub<Rhs>`:
<&'a f32 as Sub<f32>>
- <&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&f32 as Sub<&f32>>
+ <f32 as Sub<&f32>>
+ <f32 as Sub>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x - 100.0
|
= help: the trait `Sub<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Sub<Rhs>`:
- <&'a f32 as Sub<f32>>
<&'a f64 as Sub<f64>>
- <&'a i128 as Sub<i128>>
- <&'a i16 as Sub<i16>>
- <&'a i32 as Sub<i32>>
- <&'a i64 as Sub<i64>>
- <&'a i8 as Sub<i8>>
- <&'a isize as Sub<isize>>
- and 48 others
+ <&f64 as Sub<&f64>>
+ <f64 as Sub<&f64>>
+ <f64 as Sub>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x - 100.0
= help: the trait `Mul<{integer}>` is not implemented for `f32`
= help: the following other types implement trait `Mul<Rhs>`:
<&'a f32 as Mul<f32>>
- <&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
- <&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&f32 as Mul<&f32>>
+ <f32 as Mul<&f32>>
+ <f32 as Mul>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x * 100.0
|
= help: the trait `Mul<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Mul<Rhs>`:
- <&'a f32 as Mul<f32>>
<&'a f64 as Mul<f64>>
- <&'a i128 as Mul<i128>>
- <&'a i16 as Mul<i16>>
- <&'a i32 as Mul<i32>>
- <&'a i64 as Mul<i64>>
- <&'a i8 as Mul<i8>>
- <&'a isize as Mul<isize>>
- and 49 others
+ <&f64 as Mul<&f64>>
+ <f64 as Mul<&f64>>
+ <f64 as Mul>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x * 100.0
= help: the trait `Div<{integer}>` is not implemented for `f32`
= help: the following other types implement trait `Div<Rhs>`:
<&'a f32 as Div<f32>>
- <&'a f64 as Div<f64>>
- <&'a i128 as Div<i128>>
- <&'a i16 as Div<i16>>
- <&'a i32 as Div<i32>>
- <&'a i64 as Div<i64>>
- <&'a i8 as Div<i8>>
- <&'a isize as Div<isize>>
- and 54 others
+ <&f32 as Div<&f32>>
+ <f32 as Div<&f32>>
+ <f32 as Div>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x / 100.0
|
= help: the trait `Div<{integer}>` is not implemented for `f64`
= help: the following other types implement trait `Div<Rhs>`:
- <&'a f32 as Div<f32>>
<&'a f64 as Div<f64>>
- <&'a i128 as Div<i128>>
- <&'a i16 as Div<i16>>
- <&'a i32 as Div<i32>>
- <&'a i64 as Div<i64>>
- <&'a i8 as Div<i8>>
- <&'a isize as Div<isize>>
- and 54 others
+ <&f64 as Div<&f64>>
+ <f64 as Div<&f64>>
+ <f64 as Div>
help: consider using a floating-point literal by writing it with `.0`
|
LL | x / 100.0
= help: consider adding an explicit lifetime bound `Self: 'a`...
= note: ...so that the type `Self` will meet its required lifetime bounds...
note: ...that is required by this bound
- --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39
+ --> $DIR/object-safety-supertrait-mentions-GAT.rs:6:15
|
-LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
- | ^^^^^^^^^^^
+LL | Self: 'a;
+ | ^^
error: associated item referring to unboxed trait object for its own trait
--> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
{ foo(); } || { true } //~ ERROR E0308
}
+// https://github.com/rust-lang/rust/issues/105179
+fn r#match() -> i32 {
+ (match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
+ //~^ ERROR mismatched types
+}
+
+// https://github.com/rust-lang/rust/issues/102171
+fn r#unsafe() -> i32 {
+ (unsafe { 1 }) + unsafe { 1 } //~ ERROR expected expression, found `+`
+ //~^ ERROR mismatched types
+}
+
fn main() {}
{ foo() } || { true } //~ ERROR E0308
}
+// https://github.com/rust-lang/rust/issues/105179
+fn r#match() -> i32 {
+ match () { () => 1 } + match () { () => 1 } //~ ERROR expected expression, found `+`
+ //~^ ERROR mismatched types
+}
+
+// https://github.com/rust-lang/rust/issues/102171
+fn r#unsafe() -> i32 {
+ unsafe { 1 } + unsafe { 1 } //~ ERROR expected expression, found `+`
+ //~^ ERROR mismatched types
+}
+
fn main() {}
LL | ({ true }) | { true }
| + +
+error: expected expression, found `+`
+ --> $DIR/expr-as-stmt.rs:69:26
+ |
+LL | match () { () => 1 } + match () { () => 1 }
+ | ^ expected expression
+ |
+help: parentheses are required to parse this as an expression
+ |
+LL | (match () { () => 1 }) + match () { () => 1 }
+ | + +
+
+error: expected expression, found `+`
+ --> $DIR/expr-as-stmt.rs:75:18
+ |
+LL | unsafe { 1 } + unsafe { 1 }
+ | ^ expected expression
+ |
+help: parentheses are required to parse this as an expression
+ |
+LL | (unsafe { 1 }) + unsafe { 1 }
+ | + +
+
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:64:7
|
LL | ({ true }) || { true }
| + +
-error: aborting due to 18 previous errors
+error[E0308]: mismatched types
+ --> $DIR/expr-as-stmt.rs:69:5
+ |
+LL | match () { () => 1 } + match () { () => 1 }
+ | ^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
+ | |
+ | expected `()`, found integer
+
+error[E0308]: mismatched types
+ --> $DIR/expr-as-stmt.rs:75:14
+ |
+LL | unsafe { 1 } + unsafe { 1 }
+ | ^ expected `()`, found integer
+ |
+help: you might have meant to return this value
+ |
+LL | unsafe { return 1; } + unsafe { 1 }
+ | ++++++ +
+
+error: aborting due to 22 previous errors
Some errors have detailed explanations: E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0308`.
|
LL | B == 2
| ^^ help: try using `=` instead
+ |
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
error: expected item, found `==`
--> $DIR/issue-101477-enum.rs:6:7
--- /dev/null
+enum VecOrMap{
+ vec: Vec<usize>,
+ //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
+ //~| HELP: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+ //~| ERROR expected item, found `:`
+ map: HashMap<String,usize>
+}
+
+fn main() {}
--- /dev/null
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
+ --> $DIR/issue-103869.rs:2:8
+ |
+LL | vec: Vec<usize>,
+ | ^ expected one of `(`, `,`, `=`, `{`, or `}`
+ |
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+
+error: expected item, found `:`
+ --> $DIR/issue-103869.rs:2:8
+ |
+LL | vec: Vec<usize>,
+ | ^ expected item
+
+error: aborting due to 2 previous errors
+
LL | test_macro!(String,);
| -------------------- in this macro invocation
|
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
= note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
impl PartialEq for Foo {
fn eq(&self, _: &Foo) -> bool {
- false // ha ha sucker!
+ false // ha ha!
}
}
|
= help: the trait `Add<()>` is not implemented for `u32`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&'a u32 as Add<u32>>
+ <&u32 as Add<&u32>>
+ <u32 as Add<&u32>>
+ <u32 as Add>
error: aborting due to previous error
//~^ ERROR functions are not allowed in enum definitions
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+ //~| HELP enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
}
fn main() {}
|
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
error: aborting due to 3 previous errors
--- /dev/null
+trait Trait<T> {
+ fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
+}
+
+impl Trait<()> for () {
+ fn foo<'a, K>(self, _: (), _: K) where { //~ ERROR E0195
+ todo!();
+ }
+}
+
+struct State;
+
+trait Foo<T> {
+ fn foo<'a>(&self, state: &'a State) -> &'a T
+ where
+ T: 'a;
+}
+
+impl<F, T> Foo<T> for F
+where
+ F: Fn(&State) -> &T,
+{
+ fn foo<'a>(&self, state: &'a State) -> &'a T { //~ ERROR E0195
+ self(state)
+ }
+}
+
+trait Bar {
+ fn foo<'a>(&'a self) {}
+}
+
+impl Bar for () {
+ fn foo<'a: 'a>(&'a self) {} //~ ERROR E0195
+}
+
+fn main() {
+ ().foo((), ());
+}
--- /dev/null
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+ --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:6:11
+ |
+LL | fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
+ | ------- -- -- this bound might be missing in the impl
+ | | |
+ | | this bound might be missing in the impl
+ | lifetimes in impl do not match this method in trait
+...
+LL | fn foo<'a, K>(self, _: (), _: K) where {
+ | ^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+ --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11
+ |
+LL | fn foo<'a>(&self, state: &'a State) -> &'a T
+ | ---- lifetimes in impl do not match this method in trait
+LL | where
+LL | T: 'a;
+ | -- this bound might be missing in the impl
+...
+LL | fn foo<'a>(&self, state: &'a State) -> &'a T {
+ | ^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+ --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11
+ |
+LL | fn foo<'a>(&'a self) {}
+ | ---- lifetimes in impl do not match this method in trait
+...
+LL | fn foo<'a: 'a>(&'a self) {}
+ | ^^^^^^^^ lifetimes do not match method in trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0195`.
LL | bar: &'a mut T
| ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&mut T`
|
- = help: the following other types implement trait `Clone`:
- &T
- *const T
- *mut T
+ = help: the trait `Clone` is implemented for `&T`
= note: `Clone` is implemented for `&T`, but not for `&mut T`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
- <f32 as From<i16>>
- <f32 as From<i8>>
- <f32 as From<u16>>
- <f32 as From<u8>>
- <f64 as From<f32>>
- <f64 as From<i16>>
- <f64 as From<i32>>
- <f64 as From<i8>>
- and 68 others
+ <u8 as From<NonZeroU8>>
+ <u8 as From<bool>>
= note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>`
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
| ------ return type was inferred to be `i32` here
|
= help: the trait `PartialEq<Foo>` is not implemented for `i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error: aborting due to previous error
| - return type was inferred to be `&i32` here
|
= help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
--> $DIR/self-referential-4.rs:11:31
| - return type was inferred to be `&i32` here
|
= help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
--> $DIR/self-referential-4.rs:17:31
| - return type was inferred to be `&i32` here
|
= help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error: aborting due to 3 previous errors
| - return type was inferred to be `&i32` here
|
= help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error[E0277]: can't compare `&i32` with `(i32, &i32)`
--> $DIR/self-referential.rs:12:31
| ------- return type was inferred to be `(i32, &i32)` here
|
= help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
--> $DIR/self-referential.rs:19:31
| ------- return type was inferred to be `(i32, &i32)` here
|
= help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32`
- = help: the following other types implement trait `PartialEq<Rhs>`:
- f32
- f64
- i128
- i16
- i32
- i64
- i8
- isize
- and 6 others
+ = help: the trait `PartialEq` is implemented for `i32`
error: aborting due to 3 previous errors
|
= help: the trait `Add<u8>` is not implemented for `i32`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&i32 as Add<&i32>>
+ <i32 as Add<&i32>>
+ <i32 as Add>
error: aborting due to 7 previous errors
|
= help: the trait `Add<u16>` is not implemented for `usize`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
- <&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&'a usize as Add<usize>>
+ <&usize as Add<&usize>>
+ <usize as Add<&usize>>
+ <usize as Add>
error: aborting due to 3 previous errors
|
= help: the trait `Add<u32>` is not implemented for `i32`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&i32 as Add<&i32>>
+ <i32 as Add<&i32>>
+ <i32 as Add>
error[E0308]: mismatched types
--> $DIR/ufcs-qpath-self-mismatch.rs:7:28
|
= help: the trait `Add<u32>` is not implemented for `i32`
= help: the following other types implement trait `Add<Rhs>`:
- <&'a f32 as Add<f32>>
- <&'a f64 as Add<f64>>
- <&'a i128 as Add<i128>>
- <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>>
- <&'a i64 as Add<i64>>
- <&'a i8 as Add<i8>>
- <&'a isize as Add<isize>>
- and 48 others
+ <&i32 as Add<&i32>>
+ <i32 as Add<&i32>>
+ <i32 as Add>
error: aborting due to 4 previous errors
--- /dev/null
+[package]
+name = "collect-license-metadata"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.65"
+serde = { version = "1.0.147", features = ["derive"] }
+serde_json = "1.0.85"
+spdx-rs = "0.5.1"
--- /dev/null
+use std::collections::HashMap;
+
+const COPYRIGHT_PREFIXES: &[&str] = &["SPDX-FileCopyrightText:", "Copyright", "(c)", "(C)", "©"];
+
+pub(crate) struct LicensesInterner {
+ by_id: Vec<License>,
+ by_struct: HashMap<License, usize>,
+}
+
+impl LicensesInterner {
+ pub(crate) fn new() -> Self {
+ LicensesInterner { by_id: Vec::new(), by_struct: HashMap::new() }
+ }
+
+ pub(crate) fn intern(&mut self, mut license: License) -> LicenseId {
+ license.simplify();
+ if let Some(id) = self.by_struct.get(&license) {
+ LicenseId(*id)
+ } else {
+ let id = self.by_id.len();
+ self.by_id.push(license.clone());
+ self.by_struct.insert(license, id);
+ LicenseId(id)
+ }
+ }
+
+ pub(crate) fn resolve(&self, id: LicenseId) -> &License {
+ &self.by_id[id.0]
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
+#[serde(transparent)]
+pub(crate) struct LicenseId(usize);
+
+#[derive(Clone, Hash, PartialEq, Eq, serde::Serialize)]
+pub(crate) struct License {
+ pub(crate) spdx: String,
+ pub(crate) copyright: Vec<String>,
+}
+
+impl License {
+ fn simplify(&mut self) {
+ self.remove_copyright_prefixes();
+ self.copyright.sort();
+ self.copyright.dedup();
+ }
+
+ fn remove_copyright_prefixes(&mut self) {
+ for copyright in &mut self.copyright {
+ let mut stripped = copyright.trim();
+ let mut previous_stripped;
+ loop {
+ previous_stripped = stripped;
+ for pattern in COPYRIGHT_PREFIXES {
+ stripped = stripped.trim_start_matches(pattern).trim_start();
+ }
+ if stripped == previous_stripped {
+ break;
+ }
+ }
+ *copyright = stripped.into();
+ }
+ }
+}
--- /dev/null
+mod licenses;
+mod path_tree;
+mod reuse;
+
+use crate::licenses::LicensesInterner;
+use anyhow::Error;
+use std::path::PathBuf;
+
+fn main() -> Result<(), Error> {
+ let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
+ let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
+
+ let mut interner = LicensesInterner::new();
+ let paths = crate::reuse::collect(&reuse_exe, &mut interner)?;
+
+ let mut tree = crate::path_tree::build(paths);
+ tree.simplify();
+
+ if let Some(parent) = dest.parent() {
+ std::fs::create_dir_all(parent)?;
+ }
+ std::fs::write(
+ &dest,
+ &serde_json::to_vec_pretty(&serde_json::json!({
+ "files": crate::path_tree::expand_interned_licenses(tree, &interner),
+ }))?,
+ )?;
+
+ Ok(())
+}
--- /dev/null
+//! Tools like REUSE output per-file licensing information, but we need to condense it in the
+//! minimum amount of data that still represents the same licensing metadata. This module is
+//! responsible for that, by turning the list of paths into a tree and executing simplification
+//! passes over the tree to remove redundant information.
+
+use crate::licenses::{License, LicenseId, LicensesInterner};
+use std::collections::BTreeMap;
+use std::path::{Path, PathBuf};
+
+#[derive(serde::Serialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+pub(crate) enum Node<L> {
+ Root { childs: Vec<Node<L>> },
+ Directory { name: PathBuf, childs: Vec<Node<L>>, license: Option<L> },
+ File { name: PathBuf, license: L },
+ FileGroup { names: Vec<PathBuf>, license: L },
+ Empty,
+}
+
+impl Node<LicenseId> {
+ pub(crate) fn simplify(&mut self) {
+ self.merge_directories();
+ self.collapse_in_licensed_directories();
+ self.merge_directory_licenses();
+ self.merge_file_groups();
+ self.remove_empty();
+ }
+
+ /// Initially, the build() function constructs a list of separate paths from the file
+ /// system root down to each file, like so:
+ ///
+ /// ```text
+ /// ┌─► ./ ──► compiler/ ──► rustc/ ──► src/ ──► main.rs
+ /// │
+ /// <root> ─┼─► ./ ──► compiler/ ──► rustc/ ──► Cargo.toml
+ /// │
+ /// └─► ./ ──► library/ ───► std/ ──► Cargo.toml
+ /// ```
+ ///
+ /// This pass is responsible for turning that into a proper directory tree:
+ ///
+ /// ```text
+ /// ┌─► compiler/ ──► rustc/ ──┬─► src/ ──► main.rs
+ /// │ │
+ /// <root> ──► ./ ──┤ └─► Cargo.toml
+ /// │
+ /// └─► library/ ───► std/ ──► Cargo.toml
+ /// ```
+ fn merge_directories(&mut self) {
+ match self {
+ Node::Root { childs } | Node::Directory { childs, license: None, .. } => {
+ let mut directories = BTreeMap::new();
+ let mut files = Vec::new();
+
+ for child in childs.drain(..) {
+ match child {
+ Node::Directory { name, mut childs, license: None } => {
+ directories.entry(name).or_insert_with(Vec::new).append(&mut childs);
+ }
+ file @ Node::File { .. } => {
+ files.push(file);
+ }
+ Node::Empty => {}
+ Node::Root { .. } => {
+ panic!("can't have a root inside another element");
+ }
+ Node::FileGroup { .. } => {
+ panic!("FileGroup should not be present at this stage");
+ }
+ Node::Directory { license: Some(_), .. } => {
+ panic!("license should not be set at this stage");
+ }
+ }
+ }
+
+ childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory {
+ name,
+ childs,
+ license: None,
+ }));
+ childs.append(&mut files);
+
+ for child in &mut *childs {
+ child.merge_directories();
+ }
+ }
+ Node::Empty => {}
+ Node::File { .. } => {}
+ Node::FileGroup { .. } => {
+ panic!("FileGroup should not be present at this stage");
+ }
+ Node::Directory { license: Some(_), .. } => {
+ panic!("license should not be set at this stage");
+ }
+ }
+ }
+
+ /// In our codebase, most files in a directory have the same license as the other files in that
+ /// same directory, so it's redundant to store licensing metadata for all the files. Instead,
+ /// we can add a license for a whole directory, and only record the exceptions to a directory
+ /// licensing metadata.
+ ///
+ /// We cannot instead record only the difference to Rust's standard licensing, as the majority
+ /// of the files in our repository are *not* licensed under Rust's standard licensing due to
+ /// our inclusion of LLVM.
+ fn collapse_in_licensed_directories(&mut self) {
+ match self {
+ Node::Directory { childs, license, .. } => {
+ for child in &mut *childs {
+ child.collapse_in_licensed_directories();
+ }
+
+ let mut licenses_count = BTreeMap::new();
+ for child in &*childs {
+ let Some(license) = child.license() else { continue };
+ *licenses_count.entry(license).or_insert(0) += 1;
+ }
+
+ let most_popular_license = licenses_count
+ .into_iter()
+ .max_by_key(|(_, count)| *count)
+ .map(|(license, _)| license);
+
+ if let Some(most_popular_license) = most_popular_license {
+ childs.retain(|child| child.license() != Some(most_popular_license));
+ *license = Some(most_popular_license);
+ }
+ }
+ Node::Root { childs } => {
+ for child in &mut *childs {
+ child.collapse_in_licensed_directories();
+ }
+ }
+ Node::File { .. } => {}
+ Node::FileGroup { .. } => {}
+ Node::Empty => {}
+ }
+ }
+
+ /// Reduce the depth of the tree by merging subdirectories with the same license as their
+ /// parent directory into their parent, and adjusting the paths of the childs accordingly.
+ fn merge_directory_licenses(&mut self) {
+ match self {
+ Node::Root { childs } => {
+ for child in &mut *childs {
+ child.merge_directory_licenses();
+ }
+ }
+ Node::Directory { childs, license, .. } => {
+ let mut to_add = Vec::new();
+ for child in &mut *childs {
+ child.merge_directory_licenses();
+
+ let Node::Directory {
+ name: child_name,
+ childs: child_childs,
+ license: child_license,
+ } = child else { continue };
+
+ if child_license != license {
+ continue;
+ }
+ for mut child_child in child_childs.drain(..) {
+ match &mut child_child {
+ Node::Root { .. } => {
+ panic!("can't have a root inside another element");
+ }
+ Node::FileGroup { .. } => {
+ panic!("FileGroup should not be present at this stage");
+ }
+ Node::Directory { name: child_child_name, .. } => {
+ *child_child_name = child_name.join(&child_child_name);
+ }
+ Node::File { name: child_child_name, .. } => {
+ *child_child_name = child_name.join(&child_child_name);
+ }
+ Node::Empty => {}
+ }
+ to_add.push(child_child);
+ }
+
+ *child = Node::Empty;
+ }
+ childs.append(&mut to_add);
+ }
+ Node::Empty => {}
+ Node::File { .. } => {}
+ Node::FileGroup { .. } => {}
+ }
+ }
+
+ /// This pass groups multiple files in a directory with the same license into a single
+ /// "FileGroup", so that the license of all those files can be reported as a group.
+ ///
+ /// Crucially this pass runs after collapse_in_licensed_directories, so the most common license
+ /// will already be marked as the directory's license and won't be turned into a group.
+ fn merge_file_groups(&mut self) {
+ match self {
+ Node::Root { childs } | Node::Directory { childs, .. } => {
+ let mut grouped = BTreeMap::new();
+
+ for child in &mut *childs {
+ child.merge_file_groups();
+ if let Node::File { name, license } = child {
+ grouped.entry(*license).or_insert_with(Vec::new).push(name.clone());
+ *child = Node::Empty;
+ }
+ }
+
+ for (license, mut names) in grouped.into_iter() {
+ if names.len() == 1 {
+ childs.push(Node::File { license, name: names.pop().unwrap() });
+ } else {
+ childs.push(Node::FileGroup { license, names });
+ }
+ }
+ }
+ Node::File { .. } => {}
+ Node::FileGroup { .. } => panic!("FileGroup should not be present at this stage"),
+ Node::Empty => {}
+ }
+ }
+
+ /// Some nodes were replaced with Node::Empty to mark them for deletion. As the last step, make
+ /// sure to remove them from the tree.
+ fn remove_empty(&mut self) {
+ match self {
+ Node::Root { childs } | Node::Directory { childs, .. } => {
+ for child in &mut *childs {
+ child.remove_empty();
+ }
+ childs.retain(|child| !matches!(child, Node::Empty));
+ }
+ Node::FileGroup { .. } => {}
+ Node::File { .. } => {}
+ Node::Empty => {}
+ }
+ }
+
+ fn license(&self) -> Option<LicenseId> {
+ match self {
+ Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => {
+ Some(*license)
+ }
+ Node::File { license, .. } => Some(*license),
+ _ => None,
+ }
+ }
+}
+
+pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
+ let mut childs = Vec::new();
+
+ // Ensure reproducibility of all future steps.
+ input.sort();
+
+ for (path, license) in input {
+ let mut node = Node::File { name: path.file_name().unwrap().into(), license };
+ for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() {
+ node = Node::Directory {
+ name: component.as_os_str().into(),
+ childs: vec![node],
+ license: None,
+ };
+ }
+
+ childs.push(node);
+ }
+
+ Node::Root { childs }
+}
+
+/// Convert a `Node<LicenseId>` into a `Node<&License>`, expanding all interned license IDs with a
+/// reference to the actual license metadata.
+pub(crate) fn expand_interned_licenses(
+ node: Node<LicenseId>,
+ interner: &LicensesInterner,
+) -> Node<&License> {
+ match node {
+ Node::Root { childs } => Node::Root {
+ childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
+ },
+ Node::Directory { name, childs, license } => Node::Directory {
+ childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
+ license: license.map(|license| interner.resolve(license)),
+ name,
+ },
+ Node::File { name, license } => Node::File { name, license: interner.resolve(license) },
+ Node::FileGroup { names, license } => {
+ Node::FileGroup { names, license: interner.resolve(license) }
+ }
+ Node::Empty => Node::Empty,
+ }
+}
--- /dev/null
+use crate::licenses::{License, LicenseId, LicensesInterner};
+use anyhow::Error;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::time::Instant;
+
+pub(crate) fn collect(
+ reuse_exe: &Path,
+ interner: &mut LicensesInterner,
+) -> Result<Vec<(PathBuf, LicenseId)>, Error> {
+ eprintln!("gathering license information from REUSE");
+ let start = Instant::now();
+ let raw = &obtain_spdx_document(reuse_exe)?;
+ eprintln!("finished gathering the license information from REUSE in {:.2?}", start.elapsed());
+
+ let document = spdx_rs::parsers::spdx_from_tag_value(&raw)?;
+
+ let mut result = Vec::new();
+ for file in document.file_information {
+ let license = interner.intern(License {
+ spdx: file.concluded_license.to_string(),
+ copyright: file.copyright_text.split('\n').map(|s| s.into()).collect(),
+ });
+
+ result.push((file.file_name.into(), license));
+ }
+
+ Ok(result)
+}
+
+fn obtain_spdx_document(reuse_exe: &Path) -> Result<String, Error> {
+ let output = Command::new(reuse_exe)
+ .args(&["spdx", "--add-license-concluded", "--creator-person=bors"])
+ .stdout(Stdio::piped())
+ .spawn()?
+ .wait_with_output()?;
+
+ if !output.status.success() {
+ eprintln!();
+ eprintln!("Note that Rust requires some REUSE features that might not be present in the");
+ eprintln!("release you're using. Make sure your REUSE release includes these PRs:");
+ eprintln!();
+ eprintln!(" - https://github.com/fsfe/reuse-tool/pull/623");
+ eprintln!();
+ anyhow::bail!("collecting licensing information with REUSE failed");
+ }
+
+ Ok(String::from_utf8(output.stdout)?)
+}
props.load_from(testfile, cfg, config);
match (props.pass_mode, props.fail_mode) {
- (None, None) => props.fail_mode = Some(FailMode::Check),
- (Some(_), None) | (None, Some(_)) => {}
+ (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
(Some(_), Some(_)) => panic!("cannot use a *-fail and *-pass mode together"),
+ _ => {}
}
props
}
pub fn pass_mode(&self, config: &Config) -> Option<PassMode> {
- if !self.ignore_pass && self.fail_mode.is_none() && config.mode == Mode::Ui {
- if let (mode @ Some(_), Some(_)) = (config.force_pass_mode, self.pass_mode) {
+ if !self.ignore_pass && self.fail_mode.is_none() {
+ if let mode @ Some(_) = config.force_pass_mode {
return mode;
}
}
--- /dev/null
+[package]
+name = "generate-copyright"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.65"
+serde = { version = "1.0.147", features = ["derive"] }
+serde_json = "1.0.85"
--- /dev/null
+use anyhow::Error;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() -> Result<(), Error> {
+ let dest = env_path("DEST")?;
+ let license_metadata = env_path("LICENSE_METADATA")?;
+
+ let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+
+ let mut buffer = Vec::new();
+ render_recursive(&metadata.files, &mut buffer, 0)?;
+
+ std::fs::write(&dest, &buffer)?;
+
+ Ok(())
+}
+
+fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
+ let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
+
+ match node {
+ Node::Root { childs } => {
+ for child in childs {
+ render_recursive(child, buffer, depth)?;
+ }
+ }
+ Node::Directory { name, childs, license } => {
+ render_license(&prefix, std::iter::once(name), license, buffer)?;
+ if !childs.is_empty() {
+ writeln!(buffer, "{prefix}")?;
+ writeln!(buffer, "{prefix}*Exceptions:*")?;
+ for child in childs {
+ writeln!(buffer, "{prefix}")?;
+ render_recursive(child, buffer, depth + 1)?;
+ }
+ }
+ }
+ Node::FileGroup { names, license } => {
+ render_license(&prefix, names.iter(), license, buffer)?;
+ }
+ Node::File { name, license } => {
+ render_license(&prefix, std::iter::once(name), license, buffer)?;
+ }
+ }
+
+ Ok(())
+}
+
+fn render_license<'a>(
+ prefix: &str,
+ names: impl Iterator<Item = &'a String>,
+ license: &License,
+ buffer: &mut Vec<u8>,
+) -> Result<(), Error> {
+ for name in names {
+ writeln!(buffer, "{prefix}**`{name}`** ")?;
+ }
+ writeln!(buffer, "{prefix}License: `{}` ", license.spdx)?;
+ for (i, copyright) in license.copyright.iter().enumerate() {
+ let suffix = if i == license.copyright.len() - 1 { "" } else { " " };
+ writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?;
+ }
+
+ Ok(())
+}
+
+#[derive(serde::Deserialize)]
+struct Metadata {
+ files: Node,
+}
+
+#[derive(serde::Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+pub(crate) enum Node {
+ Root { childs: Vec<Node> },
+ Directory { name: String, childs: Vec<Node>, license: License },
+ File { name: String, license: License },
+ FileGroup { names: Vec<String>, license: License },
+}
+
+#[derive(serde::Deserialize)]
+struct License {
+ spdx: String,
+ copyright: Vec<String>,
+}
+
+fn env_path(var: &str) -> Result<PathBuf, Error> {
+ if let Some(var) = std::env::var_os(var) {
+ Ok(var.into())
+ } else {
+ anyhow::bail!("missing environment variable {var}")
+ }
+}
-cef44f53034eac46be3a0e3eec7b2b3d4ef5140b
+203c8765ea33c65d888febe0e8219c4bb11b0d89
/// new pointer.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum RefKind {
- /// `&mut` and `Box`.
+ /// `Box`.
+ Box,
+ /// `&mut`.
Unique { two_phase: bool },
/// `&` with or without interior mutability.
Shared,
impl fmt::Display for RefKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
+ RefKind::Box => write!(f, "Box"),
RefKind::Unique { two_phase: false } => write!(f, "unique reference"),
RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"),
RefKind::Shared => write!(f, "shared reference"),
let (perm, access) = match kind {
RefKind::Unique { two_phase } => {
// Permission is Unique only if the type is `Unpin` and this is not twophase
- let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
- Permission::Unique
+ if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
+ (Permission::Unique, Some(AccessKind::Write))
} else {
- Permission::SharedReadWrite
- };
- // We do an access for all full borrows, even if `!Unpin`.
- let access = if !two_phase { Some(AccessKind::Write) } else { None };
- (perm, access)
+ // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
+ // should do fake accesses here. But then we run into
+ // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
+ // we don't do that.
+ (Permission::SharedReadWrite, None)
+ }
}
+ RefKind::Box => (Permission::Unique, Some(AccessKind::Write)),
RefKind::Raw { mutable: true } => {
// Creating a raw ptr does not count as an access
(Permission::SharedReadWrite, None)
// Boxes get a weak protectors, since they may be deallocated.
self.retag_place(
place,
- RefKind::Unique { two_phase: false },
+ RefKind::Box,
self.retag_cause,
/*protector*/
(self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
+++ /dev/null
-//! Reborrowing a `&mut !Unpin` must still act like a (fake) read.
-use std::marker::PhantomPinned;
-
-struct NotUnpin(i32, PhantomPinned);
-
-fn main() {
- unsafe {
- let mut x = NotUnpin(0, PhantomPinned);
- // Mutable borrow of `Unpin` field (with lifetime laundering)
- let fieldref = &mut *(&mut x.0 as *mut i32);
- // Mutable reborrow of the entire `x`, which is `!Unpin` but should
- // still count as a read since we would add `dereferenceable`.
- let _xref = &mut x;
- // That read should have invalidated `fieldref`.
- *fieldref = 0; //~ ERROR: /write access .* tag does not exist in the borrow stack/
- }
-}
+++ /dev/null
-error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | *fieldref = 0;
- | ^^^^^^^^^^^^^
- | |
- | attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
- | this error occurs as part of an access at ALLOC[0x0..0x4]
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
-help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | let fieldref = &mut *(&mut x.0 as *mut i32);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | let _xref = &mut x;
- | ^^^^^^
- = note: BACKTRACE:
- = note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
--- /dev/null
+#![feature(pin_macro)]
+
+use std::future::*;
+use std::marker::PhantomPinned;
+use std::pin::*;
+use std::ptr;
+use std::task::*;
+
+struct Delay {
+ delay: usize,
+}
+
+impl Delay {
+ fn new(delay: usize) -> Self {
+ Delay { delay }
+ }
+}
+
+impl Future for Delay {
+ type Output = ();
+ fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
+ if self.delay > 0 {
+ self.delay -= 1;
+ Poll::Pending
+ } else {
+ Poll::Ready(())
+ }
+ }
+}
+
+async fn do_stuff() {
+ (&mut Delay::new(1)).await;
+}
+
+// Same thing implemented by hand
+struct DoStuff {
+ state: usize,
+ delay: Delay,
+ delay_ref: *mut Delay,
+ _marker: PhantomPinned,
+}
+
+impl DoStuff {
+ fn new() -> Self {
+ DoStuff {
+ state: 0,
+ delay: Delay::new(1),
+ delay_ref: ptr::null_mut(),
+ _marker: PhantomPinned,
+ }
+ }
+}
+
+impl Future for DoStuff {
+ type Output = ();
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+ unsafe {
+ let this = self.get_unchecked_mut();
+ match this.state {
+ 0 => {
+ // Set up self-ref.
+ this.delay_ref = &mut this.delay;
+ // Move to next state.
+ this.state = 1;
+ Poll::Pending
+ }
+ 1 => {
+ let delay = &mut *this.delay_ref;
+ Pin::new_unchecked(delay).poll(cx)
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+ use std::sync::Arc;
+
+ struct MyWaker;
+ impl Wake for MyWaker {
+ fn wake(self: Arc<Self>) {
+ unimplemented!()
+ }
+ }
+
+ let waker = Waker::from(Arc::new(MyWaker));
+ let mut context = Context::from_waker(&waker);
+
+ let mut pinned = pin!(fut);
+ loop {
+ match pinned.as_mut().poll(&mut context) {
+ Poll::Pending => continue,
+ Poll::Ready(v) => return v,
+ }
+ }
+}
+
+fn main() {
+ run_fut(do_stuff());
+ run_fut(DoStuff::new());
+}