Merge ref '4ba1cf9ade' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: 4ba1cf9ade
Filtered ref: 84b64d836ed478c54972a1d2639e60fa5f3ce26f
Upstream diff: 2a9bacf618...4ba1cf9ade

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot 2025-09-13 04:59:55 +00:00
commit 520e45a538
123 changed files with 2168 additions and 1286 deletions

View file

@ -1191,6 +1191,12 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
[[package]]
name = "dyn-clone"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
[[package]]
name = "either"
version = "1.15.0"
@ -2347,11 +2353,11 @@ dependencies = [
[[package]]
name = "miow"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.60.2",
]
[[package]]
@ -3122,6 +3128,26 @@ dependencies = [
"thiserror 2.0.15",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "regex"
version = "1.11.1"
@ -4577,6 +4603,7 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"schemars",
"serde",
"serde_derive",
"serde_json",
@ -4900,6 +4927,31 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "schemars"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
dependencies = [
"dyn-clone",
"ref-cast",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.106",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -4974,6 +5026,17 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "serde_json"
version = "1.0.142"
@ -6314,15 +6377,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -6350,21 +6404,6 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@ -6407,12 +6446,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@ -6425,12 +6458,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@ -6443,12 +6470,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@ -6473,12 +6494,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@ -6491,12 +6506,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@ -6509,12 +6518,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@ -6527,12 +6530,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"

View file

@ -176,3 +176,27 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
})
}
}
pub(crate) struct NoCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
// because it's a crate-level attribute, we already warn about it.
// Putting target limitations here would give duplicate warnings
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
const TYPE: AttributeType = AttributeType::CrateLevel;
}
pub(crate) struct NoStdParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const PATH: &[Symbol] = &[sym::no_std];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
// because it's a crate-level attribute, we already warn about it.
// Putting target limitations here would give duplicate warnings
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
const TYPE: AttributeType = AttributeType::CrateLevel;
}

View file

@ -25,8 +25,8 @@ use crate::attributes::codegen_attrs::{
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, PatternComplexityLimitParser, RecursionLimitParser,
TypeLengthLimitParser,
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, TypeLengthLimitParser,
};
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::dummy::DummyParser;
@ -223,8 +223,10 @@ attribute_parsers!(
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,

View file

@ -908,6 +908,21 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
)
}
"aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
"arm" => {
// Types wider than 16 bytes are not currently supported. Clang has special logic for
// such types, but `VaArgSafe` is not implemented for any type that is this large.
assert!(bx.cx.size_of(target_ty).bytes() <= 16);
emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
SlotSize::Bytes4,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
)
}
"s390x" => emit_s390x_va_arg(bx, addr, target_ty),
"powerpc" => emit_powerpc_va_arg(bx, addr, target_ty),
"powerpc64" | "powerpc64le" => emit_ptr_va_arg(

View file

@ -109,7 +109,7 @@ impl Command {
}
Program::Lld(ref p, flavor) => {
let mut c = process::Command::new(p);
c.arg("-flavor").arg(flavor.as_str());
c.arg("-flavor").arg(flavor.desc());
c
}
};

View file

@ -520,7 +520,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
LocalRef::Place(va_list) => {
bx.va_end(va_list.val.llval);
// Explicitly end the lifetime of the `va_list`, this matters for LLVM.
// Explicitly end the lifetime of the `va_list`, improves LLVM codegen.
bx.lifetime_end(va_list.val.llval, va_list.layout.size);
}
_ => bug!("C-variadic function must have a `VaList` place"),

View file

@ -438,6 +438,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
// Explicitly start the lifetime of the `va_list`, improves LLVM codegen.
bx.lifetime_start(va_list.val.llval, va_list.layout.size);
bx.va_start(va_list.val.llval);
return LocalRef::Place(va_list);

View file

@ -668,6 +668,10 @@ fn print_crate_info(
TargetSpecJson => {
println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
}
TargetSpecJsonSchema => {
let schema = rustc_target::spec::json_schema();
println_info!("{}", serde_json::to_string_pretty(&schema).unwrap());
}
AllTargetSpecsJson => {
let mut targets = BTreeMap::new();
for name in rustc_target::spec::TARGETS {

View file

@ -940,11 +940,27 @@ fn extract_symbol_from_pnr<'a>(
{
Ok(*symbol)
}
ParseNtResult::Literal(expr)
if let ExprKind::Lit(lit @ Lit { kind: LitKind::Integer, symbol, suffix }) =
&expr.kind =>
{
if lit.is_semantic_float() {
Err(dcx
.struct_err("floats are not supported as metavariables of `${concat(..)}`")
.with_span(span_err))
} else if suffix.is_none() {
Ok(*symbol)
} else {
Err(dcx
.struct_err("integer metavariables of `${concat(..)}` must not be suffixed")
.with_span(span_err))
}
}
_ => Err(dcx
.struct_err(
"metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`",
)
.with_note("currently only string literals are supported")
.with_note("currently only string and integer literals are supported")
.with_span(span_err)),
}
}

View file

@ -579,12 +579,18 @@ pub enum AttributeKind {
/// Represents `#[naked]`
Naked(Span),
/// Represents `#[no_core]`
NoCore(Span),
/// Represents `#[no_implicit_prelude]`
NoImplicitPrelude(Span),
/// Represents `#[no_mangle]`
NoMangle(Span),
/// Represents `#[no_std]`
NoStd(Span),
/// Represents `#[non_exhaustive]`
NonExhaustive(Span),

View file

@ -64,8 +64,10 @@ impl AttributeKind {
MoveSizeLimit { .. } => No,
MustUse { .. } => Yes,
Naked(..) => No,
NoCore(..) => No,
NoImplicitPrelude(..) => No,
NoMangle(..) => Yes, // Needed for rustdoc
NoMangle(..) => Yes, // Needed for rustdoc
NoStd(..) => No,
NonExhaustive(..) => Yes, // Needed for rustdoc
Optimize(..) => No,
ParenSugar(..) => No,

View file

@ -440,6 +440,43 @@ impl DefKind {
| DefKind::ExternCrate => false,
}
}
/// Returns `true` if `self` is a kind of definition that does not have its own
/// type-checking context, i.e. closure, coroutine or inline const.
#[inline]
pub fn is_typeck_child(self) -> bool {
match self {
DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => true,
DefKind::Mod
| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static { .. }
| DefKind::Ctor(_, _)
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::Macro(_)
| DefKind::ExternCrate
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Impl { .. } => false,
}
}
}
/// The resolution of a path or export.

View file

@ -238,7 +238,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
_ => (),
}
// Skip `AnonConst`s because we feed their `type_of`.
if !matches!(def_kind, DefKind::AnonConst) {
// Also skip items for which typeck forwards to parent typeck.
if !(matches!(def_kind, DefKind::AnonConst) || def_kind.is_typeck_child()) {
tcx.ensure_ok().typeck(item_def_id);
}
// Ensure we generate the new `DefId` before finishing `check_crate`.

View file

@ -651,7 +651,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
}
let trait_impls = tcx.trait_impls_of(trait_def_id);
#[allow(rustc::usage_of_type_ir_traits)]
self.for_each_blanket_impl(trait_def_id, f)
}
fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) {
let trait_impls = self.trait_impls_of(trait_def_id);
for &impl_def_id in trait_impls.blanket_impls() {
f(impl_def_id);
}

View file

@ -608,10 +608,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns `true` if `def_id` refers to a definition that does not have its own
/// type-checking context, i.e. closure, coroutine or inline const.
pub fn is_typeck_child(self, def_id: DefId) -> bool {
matches!(
self.def_kind(def_id),
DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody
)
self.def_kind(def_id).is_typeck_child()
}
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).

View file

@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::search_graph::CandidateHeadUsages;
use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::{
self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate,
self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
elaborate,
};
use tracing::{debug, instrument};
@ -187,6 +188,7 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
impl_def_id: I::ImplId,
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution>;
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
@ -365,6 +367,15 @@ pub(super) enum AssembleCandidatesFrom {
EnvAndBounds,
}
impl AssembleCandidatesFrom {
fn should_assemble_impl_candidates(&self) -> bool {
match self {
AssembleCandidatesFrom::All => true,
AssembleCandidatesFrom::EnvAndBounds => false,
}
}
}
/// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv`
/// candidates. This is then used to ignore their head usages in case there's another
/// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is
@ -397,14 +408,15 @@ where
return (candidates, failed_candidate_info);
};
let goal: Goal<I, G> = goal
.with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
if normalized_self_ty.is_ty_var() {
debug!("self type has been normalized to infer");
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates);
return (candidates, failed_candidate_info);
}
let goal: Goal<I, G> = goal
.with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
// Vars that show up in the rest of the goal substs may have been constrained by
// normalizing the self type as well, since type variables are not uniquified.
let goal = self.resolve_vars_if_possible(goal);
@ -484,8 +496,9 @@ where
if cx.impl_is_default(impl_def_id) {
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id) {
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
}) {
Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
@ -943,6 +956,116 @@ where
}
}
/// If the self type is the hidden type of an opaque, try to assemble
/// candidates for it by consider its item bounds and by using blanket
/// impls. This is used to incompletely guide type inference when handling
/// non-defining uses in the defining scope.
///
/// We otherwise just fail fail with ambiguity. Even if we're using an
/// opaque type item bound or a blank impls, we still force its certainty
/// to be `Maybe` so that we properly prove this goal later.
///
/// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/182>
/// for why this is necessary.
fn try_assemble_bounds_via_registered_opaques<G: GoalKind<D>>(
&mut self,
goal: Goal<I, G>,
assemble_from: AssembleCandidatesFrom,
candidates: &mut Vec<Candidate<I>>,
) {
let self_ty = goal.predicate.self_ty();
// If the self type is sub unified with any opaque type, we
// also look at blanket impls for it.
let mut assemble_blanket_impls = false;
for alias_ty in self.opaques_with_sub_unified_hidden_type(self_ty) {
assemble_blanket_impls = true;
debug!("self ty is sub unified with {alias_ty:?}");
struct ReplaceOpaque<I: Interner> {
cx: I,
alias_ty: ty::AliasTy<I>,
self_ty: I::Ty,
}
impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> {
fn cx(&self) -> I {
self.cx
}
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
if alias_ty == self.alias_ty {
return self.self_ty;
}
}
ty.super_fold_with(self)
}
}
// We look at all item-bounds of the opaque, replacing the
// opaque with the current self type before considering
// them as a candidate. Imagine e've got `?x: Trait<?y>`
// and `?x` has been sub-unified with the hidden type of
// `impl Trait<u32>`, We take the item bound `opaque: Trait<u32>`
// and replace all occurrences of `opaque` with `?x`. This results
// in a `?x: Trait<u32>` alias-bound candidate.
for item_bound in self
.cx()
.item_self_bounds(alias_ty.def_id)
.iter_instantiated(self.cx(), alias_ty.args)
{
let assumption =
item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
candidates.extend(G::probe_and_match_goal_against_assumption(
self,
CandidateSource::AliasBound,
goal,
assumption,
|ecx| {
// We want to reprove this goal once we've inferred the
// hidden type, so we force the certainty to `Maybe`.
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
},
));
}
}
// We also need to consider blanket impls for not-yet-defined opaque types.
//
// See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
if assemble_blanket_impls && assemble_from.should_assemble_impl_candidates() {
let cx = self.cx();
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if cx.impl_is_default(impl_def_id) {
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
if ecx.shallow_resolve(self_ty).is_ty_var() {
// We force the certainty of impl candidates to be `Maybe`.
let certainty = certainty.and(Certainty::AMBIGUOUS);
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
} else {
// We don't want to use impls if they constrain the opaque.
//
// FIXME(trait-system-refactor-initiative#229): This isn't
// perfect yet as it still allows us to incorrectly constrain
// other inference variables.
Err(NoSolution)
}
}) {
Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
});
}
if candidates.is_empty() {
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
}
}
/// Assemble and merge candidates for goals which are related to an underlying trait
/// goal. Right now, this is normalizes-to and host effect goals.
///

View file

@ -124,6 +124,7 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
impl_def_id: I::ImplId,
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
let cx = ecx.cx();
@ -175,7 +176,7 @@ where
});
ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
then(ecx, certainty)
})
}

View file

@ -407,20 +407,21 @@ where
// If we have run this goal before, and it was stalled, check that any of the goal's
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
// stalled, since it'll canonicalize the same way and evaluation is pure.
if let Some(stalled_on) = stalled_on
&& !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !self
.delegate
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
if let Some(GoalStalledOn { num_opaques, ref stalled_vars, ref sub_roots, stalled_cause }) =
stalled_on
&& !stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !sub_roots
.iter()
.any(|&vid| self.delegate.sub_unification_table_root_var(vid) != vid)
&& !self.delegate.opaque_types_storage_num_entries().needs_reevaluation(num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause),
certainty: Certainty::Maybe(stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
stalled_on,
},
));
}
@ -476,16 +477,6 @@ where
HasChanged::No => {
let mut stalled_vars = orig_values;
// Remove the canonicalized universal vars, since we only care about stalled existentials.
stalled_vars.retain(|arg| match arg.kind() {
ty::GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Infer(_)),
ty::GenericArgKind::Const(ct) => {
matches!(ct.kind(), ty::ConstKind::Infer(_))
}
// Lifetimes can never stall goals.
ty::GenericArgKind::Lifetime(_) => false,
});
// Remove the unconstrained RHS arg, which is expected to have changed.
if let Some(normalizes_to) = goal.predicate.as_normalizes_to() {
let normalizes_to = normalizes_to.skip_binder();
@ -497,6 +488,27 @@ where
stalled_vars.swap_remove(idx);
}
// Remove the canonicalized universal vars, since we only care about stalled existentials.
let mut sub_roots = Vec::new();
stalled_vars.retain(|arg| match arg.kind() {
// Lifetimes can never stall goals.
ty::GenericArgKind::Lifetime(_) => false,
ty::GenericArgKind::Type(ty) => match ty.kind() {
ty::Infer(ty::TyVar(vid)) => {
sub_roots.push(self.delegate.sub_unification_table_root_var(vid));
true
}
ty::Infer(_) => true,
ty::Param(_) | ty::Placeholder(_) => false,
_ => unreachable!("unexpected orig_value: {ty:?}"),
},
ty::GenericArgKind::Const(ct) => match ct.kind() {
ty::ConstKind::Infer(_) => true,
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => false,
_ => unreachable!("unexpected orig_value: {ct:?}"),
},
});
Some(GoalStalledOn {
num_opaques: canonical_goal
.canonical
@ -505,6 +517,7 @@ where
.opaque_types
.len(),
stalled_vars,
sub_roots,
stalled_cause,
})
}
@ -1047,6 +1060,10 @@ where
self.delegate.resolve_vars_if_possible(value)
}
pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty {
self.delegate.shallow_resolve(ty)
}
pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
if let ty::ReVar(vid) = r.kind() {
self.delegate.opportunistic_resolve_lt_var(vid)
@ -1163,6 +1180,33 @@ where
) -> bool {
may_use_unstable_feature(&**self.delegate, param_env, symbol)
}
pub(crate) fn opaques_with_sub_unified_hidden_type(
&self,
self_ty: I::Ty,
) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> {
let delegate = self.delegate;
delegate
.clone_opaque_types_lookup_table()
.into_iter()
.chain(delegate.clone_duplicate_opaque_types())
.filter_map(move |(key, hidden_ty)| {
if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() {
if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() {
if delegate.sub_unification_table_root_var(self_vid)
== delegate.sub_unification_table_root_var(hidden_vid)
{
return Some(ty::AliasTy::new_from_args(
delegate.cx(),
key.def_id.into(),
key.args,
));
}
}
}
None
})
}
}
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`

View file

@ -24,7 +24,7 @@ mod trait_goals;
use derive_where::derive_where;
use rustc_type_ir::inherent::*;
pub use rustc_type_ir::solve::*;
use rustc_type_ir::{self as ty, Interner, TypingMode};
use rustc_type_ir::{self as ty, Interner, TyVid, TypingMode};
use tracing::instrument;
pub use self::eval_ctxt::{
@ -418,11 +418,6 @@ pub struct GoalEvaluation<I: Interner> {
pub has_changed: HasChanged,
/// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed
/// before rerunning it.
///
/// We knowingly ignore the `sub_root` of our inference variables here. This means we
/// may not reevaluate a goal even though a change to the `sub_root` could cause a goal
/// to make progress. Tracking them adds additional complexity for an incredibly minor
/// type inference improvement. We could look into properly handling this in the future.
pub stalled_on: Option<GoalStalledOn<I>>,
}
@ -431,6 +426,7 @@ pub struct GoalEvaluation<I: Interner> {
pub struct GoalStalledOn<I: Interner> {
pub num_opaques: usize,
pub stalled_vars: Vec<I::GenericArg>,
pub sub_roots: Vec<TyVid>,
/// The cause that will be returned on subsequent evaluations if this goal remains stalled.
pub stalled_cause: MaybeCause,
}

View file

@ -194,6 +194,7 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, NormalizesTo<I>>,
impl_def_id: I::ImplId,
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
let cx = ecx.cx();
@ -314,8 +315,7 @@ where
// nested goal for consistency.
ty::TypingMode::Coherence => {
ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous));
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
return then(ecx, Certainty::Yes);
}
ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
@ -325,8 +325,7 @@ where
goal,
goal.predicate.alias,
);
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
return then(ecx, Certainty::Yes);
}
}
} else {

View file

@ -55,6 +55,7 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, TraitPredicate<I>>,
impl_def_id: I::ImplId,
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
let cx = ecx.cx();
@ -112,7 +113,7 @@ where
.map(|pred| goal.with(cx, pred)),
);
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
then(ecx, maximal_certainty)
})
}

View file

@ -274,6 +274,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::MoveSizeLimit { .. }
| AttributeKind::TypeLengthLimit { .. }
| AttributeKind::PatternComplexityLimit { .. }
| AttributeKind::NoCore { .. }
| AttributeKind::NoStd { .. }
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);

View file

@ -70,6 +70,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[
("target-libdir", PrintKind::TargetLibdir),
("target-list", PrintKind::TargetList),
("target-spec-json", PrintKind::TargetSpecJson),
("target-spec-json-schema", PrintKind::TargetSpecJsonSchema),
("tls-models", PrintKind::TlsModels),
// tidy-alphabetical-end
];
@ -1043,6 +1044,7 @@ pub enum PrintKind {
TargetLibdir,
TargetList,
TargetSpecJson,
TargetSpecJsonSchema,
TlsModels,
// tidy-alphabetical-end
}
@ -2323,7 +2325,8 @@ fn is_print_request_stable(print_kind: PrintKind) -> bool {
| PrintKind::CheckCfg
| PrintKind::CrateRootLintLevels
| PrintKind::SupportedCrateTypes
| PrintKind::TargetSpecJson => false,
| PrintKind::TargetSpecJson
| PrintKind::TargetSpecJsonSchema => false,
_ => true,
}
}

View file

@ -14,6 +14,7 @@ rustc_fs_util = { path = "../rustc_fs_util" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
schemars = "1.0.4"
serde = "1.0.219"
serde_derive = "1.0.219"
serde_json = "1.0.59"

View file

@ -72,3 +72,65 @@ fn find_relative_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> {
Some(libdir) => libdir.into(),
}
}
macro_rules! target_spec_enum {
(
$( #[$attr:meta] )*
pub enum $name:ident {
$(
$( #[$variant_attr:meta] )*
$variant:ident = $string:literal,
)*
}
parse_error_type = $parse_error_type:literal;
) => {
$( #[$attr] )*
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(schemars::JsonSchema)]
pub enum $name {
$(
$( #[$variant_attr] )*
#[serde(rename = $string)] // for JSON schema generation only
$variant,
)*
}
impl FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
$( $string => Self::$variant, )*
_ => {
let all = [$( concat!("'", $string, "'") ),*].join(", ");
return Err(format!("invalid {}: '{s}'. allowed values: {all}", $parse_error_type));
}
})
}
}
impl $name {
pub fn desc(&self) -> &'static str {
match self {
$( Self::$variant => $string, )*
}
}
}
impl crate::json::ToJson for $name {
fn to_json(&self) -> crate::json::Json {
self.desc().to_json()
}
}
crate::json::serde_deserialize_from_str!($name);
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.desc())
}
}
};
}
use target_spec_enum;

View file

@ -408,12 +408,12 @@ impl ToJson for Target {
}
}
#[derive(serde_derive::Deserialize)]
#[derive(serde_derive::Deserialize, schemars::JsonSchema)]
struct LinkSelfContainedComponentsWrapper {
components: Vec<LinkSelfContainedComponents>,
}
#[derive(serde_derive::Deserialize)]
#[derive(serde_derive::Deserialize, schemars::JsonSchema)]
#[serde(untagged)]
enum TargetFamiliesJson {
Array(StaticCow<[StaticCow<str>]>),
@ -429,6 +429,18 @@ impl FromStr for EndianWrapper {
}
}
crate::json::serde_deserialize_from_str!(EndianWrapper);
impl schemars::JsonSchema for EndianWrapper {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Endian".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema! ({
"type": "string",
"enum": ["big", "little"]
})
.into()
}
}
/// `ExternAbi` is in `rustc_abi`, which doesn't have access to the macro and serde.
struct ExternAbiWrapper(rustc_abi::ExternAbi);
@ -441,8 +453,22 @@ impl FromStr for ExternAbiWrapper {
}
}
crate::json::serde_deserialize_from_str!(ExternAbiWrapper);
impl schemars::JsonSchema for ExternAbiWrapper {
fn schema_name() -> std::borrow::Cow<'static, str> {
"ExternAbi".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
let all =
rustc_abi::ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect::<Vec<_>>();
schemars::json_schema! ({
"type": "string",
"enum": all,
})
.into()
}
}
#[derive(serde_derive::Deserialize)]
#[derive(serde_derive::Deserialize, schemars::JsonSchema)]
struct TargetSpecJsonMetadata {
description: Option<StaticCow<str>>,
tier: Option<u64>,
@ -450,7 +476,7 @@ struct TargetSpecJsonMetadata {
std: Option<bool>,
}
#[derive(serde_derive::Deserialize)]
#[derive(serde_derive::Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "kebab-case")]
// Ensure that all unexpected fields get turned into errors.
// This helps users stay up to date when the schema changes instead of silently
@ -593,3 +619,7 @@ struct TargetSpecJson {
supports_xray: Option<bool>,
entry_abi: Option<ExternAbiWrapper>,
}
pub fn json_schema() -> schemars::Schema {
schemars::schema_for!(TargetSpecJson)
}

File diff suppressed because it is too large Load diff

View file

@ -27,8 +27,8 @@ use rustc_middle::ty::print::{
with_forced_trimmed_paths,
};
use rustc_middle::ty::{
self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
Upcast,
self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
@ -2316,7 +2316,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
cand
})
.collect();
impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref.to_string()));
impl_candidates.sort_by_key(|cand| {
// When suggesting array types, sort them by the length of the array, not lexicographically (#135098)
let len = if let GenericArgKind::Type(ty) = cand.trait_ref.args[0].kind()
&& let ty::Array(_, len) = ty.kind()
{
// Deprioritize suggestions for parameterized arrays.
len.try_to_target_usize(self.tcx).unwrap_or(u64::MAX)
} else {
0
};
(cand.similarity, len, cand.trait_ref.to_string())
});
let mut impl_candidates: Vec<_> =
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
impl_candidates.dedup();

View file

@ -347,6 +347,7 @@ pub trait Interner:
self_ty: Self::Ty,
f: impl FnMut(Self::ImplId),
);
fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId));
fn has_item_definition(self, def_id: Self::DefId) -> bool;

View file

@ -705,7 +705,8 @@ impl dyn Any + Send + Sync {
/// std::mem::forget(fake_one_ring);
/// }
/// ```
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
#[derive(Copy, PartialOrd, Ord)]
#[derive_const(Clone, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "type_id"]
pub struct TypeId {

View file

@ -1,9 +1,10 @@
use crate::cmp::BytewiseEq;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<[U; N]> for [T; N]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U; N]) -> bool {
@ -16,9 +17,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<[U]> for [T; N]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<[U]> for [T; N]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U]) -> bool {
@ -37,9 +39,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<[U; N]> for [T]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<[U; N]> for [T]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U; N]) -> bool {
@ -58,9 +61,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<&[U]> for [T; N]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<&[U]> for [T; N]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&[U]) -> bool {
@ -73,9 +77,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<[U; N]> for &[T]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<[U; N]> for &[T]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U; N]) -> bool {
@ -88,9 +93,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<&mut [U]> for [T; N]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<&mut [U]> for [T; N]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&mut [U]) -> bool {
@ -103,9 +109,10 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, const N: usize> PartialEq<[U; N]> for &mut [T]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T, U, const N: usize> const PartialEq<[U; N]> for &mut [T]
where
T: PartialEq<U>,
T: [const] PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U; N]) -> bool {
@ -122,14 +129,18 @@ where
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, const N: usize> Eq for [T; N] {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] Eq, const N: usize> const Eq for [T; N] {}
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
trait SpecArrayEq<Other, const N: usize>: Sized {
fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool;
fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool;
}
impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] PartialEq<Other>, Other, const N: usize> const SpecArrayEq<Other, N> for T {
default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool {
a[..] == b[..]
}
@ -138,7 +149,8 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
}
}
impl<T: BytewiseEq<U>, U, const N: usize> SpecArrayEq<U, N> for T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] BytewiseEq<U>, U, const N: usize> const SpecArrayEq<U, N> for T {
fn spec_eq(a: &[T; N], b: &[U; N]) -> bool {
// SAFETY: Arrays are compared element-wise, and don't add any padding
// between elements, so when the elements are `BytewiseEq`, we can

View file

@ -54,7 +54,8 @@ use crate::{assert_unsafe_precondition, fmt};
/// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
/// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
/// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Hash)]
#[derive_const(Clone, Eq, PartialEq, Ord, PartialOrd)]
#[unstable(feature = "ascii_char", issue = "110998")]
#[repr(u8)]
pub enum AsciiChar {

View file

@ -29,7 +29,7 @@ mod bytewise;
pub(crate) use bytewise::BytewiseEq;
use self::Ordering::*;
use crate::marker::PointeeSized;
use crate::marker::{Destruct, PointeeSized};
use crate::ops::ControlFlow;
/// Trait for comparisons using the equality operator.
@ -334,7 +334,9 @@ pub macro PartialEq($item:item) {
#[doc(alias = "!=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Eq"]
pub trait Eq: PartialEq<Self> + PointeeSized {
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub trait Eq: [const] PartialEq<Self> + PointeeSized {
// this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
// type implements `Eq` itself. The current deriving infrastructure means doing this assertion
// without using a method on this trait is nearly impossible.
@ -380,8 +382,8 @@ pub struct AssertParamIsEq<T: Eq + PointeeSized> {
///
/// assert_eq!(2.cmp(&1), Ordering::Greater);
/// ```
#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)]
#[derive_const(PartialEq)]
#[derive(Copy, Debug, Hash)]
#[derive_const(Clone, Eq, PartialOrd, Ord, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
// This is a lang item only so that `BinOp::Cmp` in MIR can return it.
// It has no special behavior, but does require that the three variants
@ -635,7 +637,11 @@ impl Ordering {
#[inline]
#[must_use]
#[stable(feature = "ordering_chaining", since = "1.17.0")]
pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn then_with<F>(self, f: F) -> Ordering
where
F: [const] FnOnce() -> Ordering + [const] Destruct,
{
match self {
Equal => f(),
_ => self,
@ -659,13 +665,15 @@ impl Ordering {
/// v.sort_by_key(|&num| (num > 3, Reverse(num)));
/// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);
/// ```
#[derive(PartialEq, Eq, Debug, Copy, Default, Hash)]
#[derive(Copy, Debug, Hash)]
#[derive_const(PartialEq, Eq, Default)]
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
#[repr(transparent)]
pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
impl<T: PartialOrd> PartialOrd for Reverse<T> {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] PartialOrd> const PartialOrd for Reverse<T> {
#[inline]
fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
other.0.partial_cmp(&self.0)
@ -690,7 +698,8 @@ impl<T: PartialOrd> PartialOrd for Reverse<T> {
}
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
impl<T: Ord> Ord for Reverse<T> {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] Ord> const Ord for Reverse<T> {
#[inline]
fn cmp(&self, other: &Reverse<T>) -> Ordering {
other.0.cmp(&self.0)
@ -957,7 +966,9 @@ impl<T: Clone> Clone for Reverse<T> {
#[doc(alias = ">=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Ord"]
pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub trait Ord: [const] Eq + [const] PartialOrd<Self> + PointeeSized {
/// This method returns an [`Ordering`] between `self` and `other`.
///
/// By convention, `self.cmp(&other)` returns the ordering matching the expression
@ -1011,7 +1022,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
#[rustc_diagnostic_item = "cmp_ord_max"]
fn max(self, other: Self) -> Self
where
Self: Sized,
Self: Sized + [const] Destruct,
{
if other < self { self } else { other }
}
@ -1050,7 +1061,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
#[rustc_diagnostic_item = "cmp_ord_min"]
fn min(self, other: Self) -> Self
where
Self: Sized,
Self: Sized + [const] Destruct,
{
if other < self { other } else { self }
}
@ -1076,7 +1087,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
#[stable(feature = "clamp", since = "1.50.0")]
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
Self: Sized + [const] Destruct,
{
assert!(min <= max);
if self < min {
@ -1341,6 +1352,8 @@ pub macro Ord($item:item) {
)]
#[rustc_diagnostic_item = "PartialOrd"]
#[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
/// This method returns an ordering between `self` and `other` values if one exists.
///
@ -1481,13 +1494,14 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
}
}
fn default_chaining_impl<T, U>(
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
const fn default_chaining_impl<T, U>(
lhs: &T,
rhs: &U,
p: impl FnOnce(Ordering) -> bool,
p: impl [const] FnOnce(Ordering) -> bool + [const] Destruct,
) -> ControlFlow<bool>
where
T: PartialOrd<U> + PointeeSized,
T: [const] PartialOrd<U> + PointeeSized,
U: PointeeSized,
{
// It's important that this only call `partial_cmp` once, not call `eq` then
@ -1545,7 +1559,8 @@ pub macro PartialOrd($item:item) {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_min"]
pub fn min<T: Ord>(v1: T, v2: T) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn min<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T {
v1.min(v2)
}
@ -1575,7 +1590,12 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn min_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>(
v1: T,
v2: T,
compare: F,
) -> T {
if compare(&v1, &v2).is_le() { v1 } else { v2 }
}
@ -1600,7 +1620,13 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn min_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T
where
T: [const] Destruct,
F: [const] FnMut(&T) -> K + [const] Destruct,
K: [const] Ord + [const] Destruct,
{
if f(&v2) < f(&v1) { v2 } else { v1 }
}
@ -1640,7 +1666,8 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "cmp_max"]
pub fn max<T: Ord>(v1: T, v2: T) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn max<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T {
v1.max(v2)
}
@ -1670,7 +1697,12 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn max_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>(
v1: T,
v2: T,
compare: F,
) -> T {
if compare(&v1, &v2).is_gt() { v1 } else { v2 }
}
@ -1695,7 +1727,13 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn max_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T
where
T: [const] Destruct,
F: [const] FnMut(&T) -> K + [const] Destruct,
K: [const] Ord + [const] Destruct,
{
if f(&v2) < f(&v1) { v1 } else { v2 }
}
@ -1739,9 +1777,10 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
#[inline]
#[must_use]
#[unstable(feature = "cmp_minmax", issue = "115939")]
pub fn minmax<T>(v1: T, v2: T) -> [T; 2]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn minmax<T>(v1: T, v2: T) -> [T; 2]
where
T: Ord,
T: [const] Ord,
{
if v2 < v1 { [v2, v1] } else { [v1, v2] }
}
@ -1773,9 +1812,10 @@ where
#[inline]
#[must_use]
#[unstable(feature = "cmp_minmax", issue = "115939")]
pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
where
F: FnOnce(&T, &T) -> Ordering,
F: [const] FnOnce(&T, &T) -> Ordering,
{
if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] }
}
@ -1801,10 +1841,11 @@ where
#[inline]
#[must_use]
#[unstable(feature = "cmp_minmax", issue = "115939")]
pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2]
where
F: FnMut(&T) -> K,
K: Ord,
F: [const] FnMut(&T) -> K + [const] Destruct,
K: [const] Ord + [const] Destruct,
{
if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] }
}
@ -1830,7 +1871,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for () {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialEq for () {
#[inline]
fn eq(&self, _other: &()) -> bool {
true
@ -1848,7 +1890,8 @@ mod impls {
macro_rules! eq_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for $t {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Eq for $t {}
)*)
}
@ -1896,7 +1939,8 @@ mod impls {
macro_rules! partial_ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for $t {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self <= *other, *self >= *other) {
@ -1913,7 +1957,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for () {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for () {
#[inline]
fn partial_cmp(&self, _: &()) -> Option<Ordering> {
Some(Equal)
@ -1921,7 +1966,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for bool {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for bool {
#[inline]
fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
Some(self.cmp(other))
@ -1935,7 +1981,8 @@ mod impls {
macro_rules! ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for $t {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(crate::intrinsics::three_way_compare(*self, *other))
@ -1945,7 +1992,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for $t {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Ord for $t {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
crate::intrinsics::three_way_compare(*self, *other)
@ -1955,7 +2003,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for () {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Ord for () {
#[inline]
fn cmp(&self, _other: &()) -> Ordering {
Equal
@ -1963,7 +2012,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for bool {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Ord for bool {
#[inline]
fn cmp(&self, other: &bool) -> Ordering {
// Casting to i8's and converting the difference to an Ordering generates
@ -1998,7 +2048,8 @@ mod impls {
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
#[unstable(feature = "never_type", issue = "35121")]
impl PartialEq for ! {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialEq for ! {
#[inline]
fn eq(&self, _: &!) -> bool {
*self
@ -2006,10 +2057,12 @@ mod impls {
}
#[unstable(feature = "never_type", issue = "35121")]
impl Eq for ! {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Eq for ! {}
#[unstable(feature = "never_type", issue = "35121")]
impl PartialOrd for ! {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for ! {
#[inline]
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
@ -2017,7 +2070,8 @@ mod impls {
}
#[unstable(feature = "never_type", issue = "35121")]
impl Ord for ! {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Ord for ! {
#[inline]
fn cmp(&self, _: &!) -> Ordering {
*self
@ -2042,9 +2096,10 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized, B: PointeeSized> PartialOrd<&B> for &A
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&B> for &A
where
A: PartialOrd<B>,
A: [const] PartialOrd<B>,
{
#[inline]
fn partial_cmp(&self, other: &&B) -> Option<Ordering> {
@ -2084,9 +2139,10 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized> Ord for &A
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized> const Ord for &A
where
A: Ord,
A: [const] Ord,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
@ -2094,7 +2150,8 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized> Eq for &A where A: Eq {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized> const Eq for &A where A: [const] Eq {}
// &mut pointers
@ -2114,9 +2171,10 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized, B: PointeeSized> PartialOrd<&mut B> for &mut A
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&mut B> for &mut A
where
A: PartialOrd<B>,
A: [const] PartialOrd<B>,
{
#[inline]
fn partial_cmp(&self, other: &&mut B) -> Option<Ordering> {
@ -2156,9 +2214,10 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized> Ord for &mut A
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized> const Ord for &mut A
where
A: Ord,
A: [const] Ord,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
@ -2166,7 +2225,8 @@ mod impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PointeeSized> Eq for &mut A where A: Eq {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: PointeeSized> const Eq for &mut A where A: [const] Eq {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]

View file

@ -963,17 +963,20 @@ impl const PartialEq for Infallible {
}
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl Eq for Infallible {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Eq for Infallible {}
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl PartialOrd for Infallible {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const PartialOrd for Infallible {
fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> {
match *self {}
}
}
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl Ord for Infallible {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Ord for Infallible {
fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
match *self {}
}

View file

@ -4,7 +4,7 @@ use super::{IntErrorKind, ParseIntError};
use crate::clone::UseCloned;
use crate::cmp::Ordering;
use crate::hash::{Hash, Hasher};
use crate::marker::{Freeze, StructuralPartialEq};
use crate::marker::{Destruct, Freeze, StructuralPartialEq};
use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::str::FromStr;
@ -220,12 +220,14 @@ where
impl<T> StructuralPartialEq for NonZero<T> where T: ZeroablePrimitive + StructuralPartialEq {}
#[stable(feature = "nonzero", since = "1.28.0")]
impl<T> Eq for NonZero<T> where T: ZeroablePrimitive + Eq {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T> const Eq for NonZero<T> where T: ZeroablePrimitive + [const] Eq {}
#[stable(feature = "nonzero", since = "1.28.0")]
impl<T> PartialOrd for NonZero<T>
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T> const PartialOrd for NonZero<T>
where
T: ZeroablePrimitive + PartialOrd,
T: ZeroablePrimitive + [const] PartialOrd,
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@ -254,9 +256,12 @@ where
}
#[stable(feature = "nonzero", since = "1.28.0")]
impl<T> Ord for NonZero<T>
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T> const Ord for NonZero<T>
where
T: ZeroablePrimitive + Ord,
// FIXME(const_hack): the T: ~const Destruct should be inferred from the Self: ~const Destruct.
// See https://github.com/rust-lang/rust/issues/144207
T: ZeroablePrimitive + [const] Ord + [const] Destruct,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {

View file

@ -83,7 +83,8 @@ use crate::{convert, ops};
#[must_use]
// ControlFlow should not implement PartialOrd or Ord, per RFC 3058:
// https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Copy, Debug, Hash)]
#[derive_const(Clone, PartialEq, Eq)]
pub enum ControlFlow<B, C = ()> {
/// Move on to the next phase of the operation as normal.
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]

View file

@ -585,7 +585,8 @@ use crate::{cmp, convert, hint, mem, slice};
/// The `Option` type. See [the module level documentation](self) for more.
#[doc(search_unbox)]
#[derive(Copy, Eq, Debug, Hash)]
#[derive(Copy, Debug, Hash)]
#[derive_const(Eq)]
#[rustc_diagnostic_item = "Option"]
#[lang = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
@ -2363,7 +2364,8 @@ impl<T: [const] PartialEq> const PartialEq for Option<T> {
// https://github.com/rust-lang/rust/issues/49892, although still
// not optimal.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for Option<T> {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] PartialOrd> const PartialOrd for Option<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
match (self, other) {
@ -2376,7 +2378,8 @@ impl<T: PartialOrd> PartialOrd for Option<T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Ord for Option<T> {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] Ord> const Ord for Option<T> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
match (self, other) {

View file

@ -49,7 +49,8 @@ pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, R
/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
/// ```
#[lang = "RangeCopy"]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
#[derive(Copy, Hash)]
#[derive_const(Clone, Default, PartialEq, Eq)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct Range<Idx> {
/// The lower bound of the range (inclusive).
@ -424,7 +425,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
/// ```
#[lang = "RangeFromCopy"]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Copy, Hash)]
#[derive_const(Clone, PartialEq, Eq)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct RangeFrom<Idx> {
/// The lower bound of the range (inclusive).

View file

@ -542,7 +542,8 @@ use crate::{convert, fmt, hint};
///
/// See the [module documentation](self) for details.
#[doc(search_unbox)]
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[derive(Copy, Debug, Hash)]
#[derive_const(PartialEq, PartialOrd, Eq, Ord)]
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
#[rustc_diagnostic_item = "Result"]
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -23,7 +23,8 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq> Eq for [T] {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T: [const] Eq> const Eq for [T] {}
/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
#[stable(feature = "rust1", since = "1.0.0")]
@ -34,7 +35,7 @@ impl<T: Ord> Ord for [T] {
}
#[inline]
fn as_underlying(x: ControlFlow<bool>) -> u8 {
const fn as_underlying(x: ControlFlow<bool>) -> u8 {
// SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same
// size (which isn't guaranteed but this is libcore). Because they have the same
// size, it's a niched implementation, which in one byte means there can't be
@ -154,12 +155,16 @@ where
}
#[doc(hidden)]
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
// intermediate trait for specialization of slice's PartialOrd
trait SlicePartialOrd: Sized {
fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
}
#[doc(hidden)]
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
// intermediate trait for specialization of slice's PartialOrd chaining methods
trait SliceChain: Sized {
fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
@ -231,14 +236,17 @@ where
}
*/
impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: [const] AlwaysApplicableOrd> const SlicePartialOrd for A {
fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
Some(SliceOrd::compare(left, right))
}
}
#[rustc_specialization_trait]
trait AlwaysApplicableOrd: SliceOrd + Ord {}
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
trait AlwaysApplicableOrd: [const] SliceOrd + [const] Ord {}
macro_rules! always_applicable_ord {
($([$($p:tt)*] $t:ty,)*) => {
@ -257,6 +265,8 @@ always_applicable_ord! {
}
#[doc(hidden)]
#[const_trait]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
// intermediate trait for specialization of slice's Ord
trait SliceOrd: Sized {
fn compare(left: &[Self], right: &[Self]) -> Ordering;
@ -282,17 +292,24 @@ impl<A: Ord> SliceOrd for A {
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
#[rustc_specialization_trait]
unsafe trait UnsignedBytewiseOrd: Ord {}
#[const_trait]
unsafe trait UnsignedBytewiseOrd: [const] Ord {}
unsafe impl UnsignedBytewiseOrd for bool {}
unsafe impl UnsignedBytewiseOrd for u8 {}
unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
unsafe impl UnsignedBytewiseOrd for ascii::Char {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
unsafe impl const UnsignedBytewiseOrd for bool {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
unsafe impl const UnsignedBytewiseOrd for u8 {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
unsafe impl const UnsignedBytewiseOrd for NonZero<u8> {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
unsafe impl const UnsignedBytewiseOrd for Option<NonZero<u8>> {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
unsafe impl const UnsignedBytewiseOrd for ascii::Char {}
// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: [const] Ord + [const] UnsignedBytewiseOrd> const SliceOrd for A {
#[inline]
fn compare(left: &[Self], right: &[Self]) -> Ordering {
// Since the length of a slice is always less than or equal to
@ -317,7 +334,9 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
}
// Don't generate our own chaining loops for `memcmp`-able things either.
impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<A: [const] PartialOrd + [const] UnsignedBytewiseOrd> const SliceChain for A {
#[inline]
fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
match SliceOrd::compare(left, right) {

View file

@ -32,7 +32,8 @@ impl const PartialEq for str {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for str {}
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl const Eq for str {}
/// Implements comparison operations on strings.
///

View file

@ -23,7 +23,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T: PartialEq),+> PartialEq for ($($T,)+) {
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<$($T: [const] PartialEq),+> const PartialEq for ($($T,)+) {
#[inline]
fn eq(&self, other: &($($T,)+)) -> bool {
$( ${ignore($T)} self.${index()} == other.${index()} )&&+
@ -38,7 +39,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T: Eq),+> Eq for ($($T,)+)
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<$($T: [const] Eq),+> const Eq for ($($T,)+)
{}
}
@ -66,7 +68,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<$($T: [const] PartialOrd),+> const PartialOrd for ($($T,)+)
{
#[inline]
fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
@ -110,7 +113,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T: Ord),+> Ord for ($($T,)+)
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<$($T: [const] Ord),+> const Ord for ($($T,)+)
{
#[inline]
fn cmp(&self, other: &($($T,)+)) -> Ordering {

View file

@ -55,6 +55,30 @@ fn layout_array_edge_cases() {
}
}
#[test]
fn layout_errors() {
let layout = Layout::new::<[u8; 2]>();
// Should error if the alignment is not a power of two.
assert!(layout.align_to(3).is_err());
// The remaining assertions ensure that the methods error on arithmetic overflow as the
// alignment cannot overflow `isize`.
let size = layout.size();
let size_max = isize::MAX as usize;
let align_max = size_max / size;
assert!(layout.align_to(size_max + 1).is_err());
assert!(layout.repeat(align_max).is_ok());
assert!(layout.repeat(align_max + 1).is_err());
assert!(layout.repeat_packed(align_max).is_ok());
assert!(layout.repeat_packed(align_max + 1).is_err());
let next = Layout::from_size_align(size_max, 1).unwrap();
assert!(layout.extend(next).is_err());
}
#[test]
fn layout_debug_shows_log2_of_alignment() {
// `Debug` is not stable, but here's what it does right now

View file

@ -220,6 +220,7 @@ fn test_escape_default() {
}
assert_eq!(string('\n'), "\\n");
assert_eq!(string('\r'), "\\r");
assert_eq!(string('\t'), "\\t");
assert_eq!(string('\''), "\\'");
assert_eq!(string('"'), "\\\"");
assert_eq!(string(' '), " ");
@ -417,3 +418,45 @@ fn eu_iterator_specializations() {
check('\u{12340}');
check('\u{10FFFF}');
}
#[test]
#[should_panic]
fn test_from_digit_radix_too_high() {
let _ = char::from_digit(0, 37);
}
#[test]
fn test_from_digit_invalid_radix() {
assert!(char::from_digit(10, 9).is_none());
}
#[test]
#[should_panic]
fn test_to_digit_radix_too_low() {
let _ = 'a'.to_digit(1);
}
#[test]
#[should_panic]
fn test_to_digit_radix_too_high() {
let _ = 'a'.to_digit(37);
}
#[test]
fn test_as_ascii_invalid() {
assert!('❤'.as_ascii().is_none());
}
#[test]
#[should_panic]
fn test_encode_utf8_raw_buffer_too_small() {
let mut buf = [0u8; 1];
let _ = char::encode_utf8_raw('ß'.into(), &mut buf);
}
#[test]
#[should_panic]
fn test_encode_utf16_raw_buffer_too_small() {
let mut buf = [0u16; 1];
let _ = char::encode_utf16_raw('𐐷'.into(), &mut buf);
}

View file

@ -215,19 +215,18 @@ fn cmp_default() {
assert_eq!(Fool(false), Fool(true));
}
/* FIXME(#110395)
mod const_cmp {
use super::*;
struct S(i32);
impl PartialEq for S {
impl const PartialEq for S {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl PartialOrd for S {
impl const PartialOrd for S {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let ret = match (self.0, other.0) {
(a, b) if a > b => Ordering::Greater,
@ -247,4 +246,3 @@ mod const_cmp {
const _: () = assert!(S(0) < S(1));
const _: () = assert!(S(1) > S(0));
}
*/

View file

@ -53,12 +53,14 @@ fn test_writer_hasher() {
assert_eq!(hash(&5_u16), 5);
assert_eq!(hash(&5_u32), 5);
assert_eq!(hash(&5_u64), 5);
assert_eq!(hash(&5_u128), 5);
assert_eq!(hash(&5_usize), 5);
assert_eq!(hash(&5_i8), 5);
assert_eq!(hash(&5_i16), 5);
assert_eq!(hash(&5_i32), 5);
assert_eq!(hash(&5_i64), 5);
assert_eq!(hash(&5_i128), 5);
assert_eq!(hash(&5_isize), 5);
assert_eq!(hash(&false), 0);
@ -85,6 +87,17 @@ fn test_writer_hasher() {
let ptr = ptr::without_provenance_mut::<i32>(5_usize);
assert_eq!(hash(&ptr), 5);
// Use a newtype to test the `Hash::hash_slice` default implementation.
struct Byte(u8);
impl Hash for Byte {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u8(self.0)
}
}
assert_eq!(hash(&[Byte(b'a')]), 97 + 1);
if cfg!(miri) {
// Miri cannot hash pointers
return;

View file

@ -13,8 +13,10 @@
#![feature(bool_to_result)]
#![feature(bstr)]
#![feature(cfg_target_has_reliable_f16_f128)]
#![feature(char_internals)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(const_cmp)]
#![feature(const_convert)]
#![feature(const_destruct)]
#![feature(const_eval_select)]

View file

@ -350,6 +350,7 @@
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
#![feature(fmt_internals)]
#![feature(fn_ptr_trait)]
#![feature(generic_atomic)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]

View file

@ -304,7 +304,8 @@ impl Socket {
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unimplemented!()
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
}
// This is used by sys_common code to abstract over Windows and Unix.

View file

@ -3,7 +3,7 @@ use crate::ffi::{OsStr, OsString};
use crate::marker::PhantomData;
use crate::path::{self, PathBuf};
use crate::sys::unsupported;
use crate::{fmt, io, str};
use crate::{fmt, io};
pub fn errno() -> i32 {
unsafe { hermit_abi::get_errno() }

View file

@ -22,11 +22,24 @@
#![allow(dead_code, unused_macros)]
#![forbid(unsafe_op_in_unsafe_fn)]
use crate::ffi::CStr;
use crate::marker::PhantomData;
use crate::sync::atomic::{self, Atomic, AtomicPtr, Ordering};
use crate::ffi::{CStr, c_char, c_void};
use crate::marker::{FnPtr, PhantomData};
use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
use crate::{mem, ptr};
// We currently only test `dlsym!`, but that doesn't work on all platforms, so
// we gate the tests to only the platforms where it is actually used.
//
// FIXME(joboet): add more tests, reorganise the whole module and get rid of
// `#[allow(dead_code, unused_macros)]`.
#[cfg(any(
target_vendor = "apple",
all(target_os = "linux", target_env = "gnu"),
target_os = "freebsd",
))]
#[cfg(test)]
mod tests;
// We can use true weak linkage on ELF targets.
#[cfg(all(unix, not(target_vendor = "apple")))]
pub(crate) macro weak {
@ -64,7 +77,7 @@ impl<F: Copy> ExternWeak<F> {
pub(crate) macro dlsym {
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
dlsym!(
dlsym!(
#[link_name = stringify!($name)]
fn $name($($param : $t),*) -> $ret;
);
@ -73,21 +86,39 @@ pub(crate) macro dlsym {
#[link_name = $sym:expr]
fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
) => (
static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
DlsymWeak::new(concat!($sym, '\0'));
static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
let Ok(name) = CStr::from_bytes_with_nul(concat!($sym, '\0').as_bytes()) else {
panic!("symbol name may not contain NUL")
};
// SAFETY: Whoever calls the function pointer returned by `get()`
// is responsible for ensuring that the signature is correct. Just
// like with extern blocks, this is syntactically enforced by making
// the function pointer be unsafe.
unsafe { DlsymWeak::new(name) }
};
let $name = &DLSYM;
)
}
pub(crate) struct DlsymWeak<F> {
name: &'static str,
/// A pointer to the nul-terminated name of the symbol.
// Use a pointer instead of `&'static CStr` to save space.
name: *const c_char,
func: Atomic<*mut libc::c_void>,
_marker: PhantomData<F>,
}
impl<F> DlsymWeak<F> {
pub(crate) const fn new(name: &'static str) -> Self {
impl<F: FnPtr> DlsymWeak<F> {
/// # Safety
///
/// If the signature of `F` does not match the signature of the symbol (if
/// it exists), calling the function pointer returned by `get()` is
/// undefined behaviour.
pub(crate) const unsafe fn new(name: &'static CStr) -> Self {
DlsymWeak {
name,
name: name.as_ptr(),
func: AtomicPtr::new(ptr::without_provenance_mut(1)),
_marker: PhantomData,
}
@ -95,62 +126,59 @@ impl<F> DlsymWeak<F> {
#[inline]
pub(crate) fn get(&self) -> Option<F> {
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
match self.func.load(Ordering::Relaxed) {
func if func.addr() == 1 => self.initialize(),
func if func.is_null() => None,
func => {
let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
// The caller is presumably going to read through this value
// (by calling the function we've dlsymed). This means we'd
// need to have loaded it with at least C11's consume
// ordering in order to be guaranteed that the data we read
// from the pointer isn't from before the pointer was
// stored. Rust has no equivalent to memory_order_consume,
// so we use an acquire fence (sorry, ARM).
//
// Now, in practice this likely isn't needed even on CPUs
// where relaxed and consume mean different things. The
// symbols we're loading are probably present (or not) at
// init, and even if they aren't the runtime dynamic loader
// is extremely likely have sufficient barriers internally
// (possibly implicitly, for example the ones provided by
// invoking `mprotect`).
//
// That said, none of that's *guaranteed*, and so we fence.
atomic::fence(Ordering::Acquire);
Some(func)
}
}
// The caller is presumably going to read through this value
// (by calling the function we've dlsymed). This means we'd
// need to have loaded it with at least C11's consume
// ordering in order to be guaranteed that the data we read
// from the pointer isn't from before the pointer was
// stored. Rust has no equivalent to memory_order_consume,
// so we use an acquire load (sorry, ARM).
//
// Now, in practice this likely isn't needed even on CPUs
// where relaxed and consume mean different things. The
// symbols we're loading are probably present (or not) at
// init, and even if they aren't the runtime dynamic loader
// is extremely likely have sufficient barriers internally
// (possibly implicitly, for example the ones provided by
// invoking `mprotect`).
//
// That said, none of that's *guaranteed*, so we use acquire.
match self.func.load(Ordering::Acquire) {
func if func.addr() == 1 => self.initialize(),
func if func.is_null() => None,
// SAFETY:
// `func` is not null and `F` implements `FnPtr`, thus this
// transmutation is well-defined. It is the responsibility of the
// creator of this `DlsymWeak` to ensure that calling the resulting
// function pointer does not result in undefined behaviour (though
// the `dlsym!` macro delegates this responsibility to the caller
// of the function by using `unsafe` function pointers).
// FIXME: use `transmute` once it stops complaining about generics.
func => Some(unsafe { mem::transmute_copy::<*mut c_void, F>(&func) }),
}
}
// Cold because it should only happen during first-time initialization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
assert_eq!(size_of::<F>(), size_of::<*mut libc::c_void>());
let val = unsafe { fetch(self.name) };
// This synchronizes with the acquire fence in `get`.
fn initialize(&self) -> Option<F> {
// SAFETY: `self.name` was created from a `&'static CStr` and is
// therefore a valid C string pointer.
let val = unsafe { libc::dlsym(libc::RTLD_DEFAULT, self.name) };
// This synchronizes with the acquire load in `get`.
self.func.store(val, Ordering::Release);
if val.is_null() {
None
} else {
// SAFETY: see the comment in `get`.
// FIXME: use `transmute` once it stops complaining about generics.
Some(unsafe { mem::transmute_copy::<*mut libc::c_void, F>(&val) })
}
}
}
unsafe fn fetch(name: &str) -> *mut libc::c_void {
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
Ok(cstr) => cstr,
Err(..) => return ptr::null_mut(),
};
unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) }
}
unsafe impl<F> Send for DlsymWeak<F> {}
unsafe impl<F> Sync for DlsymWeak<F> {}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub(crate) macro syscall {

View file

@ -0,0 +1,32 @@
use super::*;
#[test]
fn dlsym_existing() {
const TEST_STRING: &'static CStr = c"Ferris!";
// Try to find a symbol that definitely exists.
dlsym! {
fn strlen(cs: *const c_char) -> usize;
}
dlsym! {
#[link_name = "strlen"]
fn custom_name(cs: *const c_char) -> usize;
}
let strlen = strlen.get().unwrap();
assert_eq!(unsafe { strlen(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
let custom_name = custom_name.get().unwrap();
assert_eq!(unsafe { custom_name(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
}
#[test]
fn dlsym_missing() {
// Try to find a symbol that definitely does not exist.
dlsym! {
fn test_symbol_that_does_not_exist() -> i32;
}
assert!(test_symbol_that_does_not_exist.get().is_none());
}

View file

@ -276,7 +276,9 @@ fn wait(
// If the managing thread happens to signal and unpark us before we
// can park ourselves, the result could be this thread never gets
// unparked. Luckily `park` comes with the guarantee that if it got
// an `unpark` just before on an unparked thread it does not park.
// an `unpark` just before on an unparked thread it does not park. Crucially, we know
// the `unpark` must have happened between the `compare_exchange_weak` above and here,
// and there's no other `park` in that code that could steal our token.
// SAFETY: we retrieved this handle on the current thread above.
unsafe { node.thread.park() }
}

View file

@ -1021,13 +1021,23 @@ impl Drop for PanicGuard {
/// specifying a maximum time to block the thread for.
///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
/// if it wasn't already. Because the token is initially absent, [`unpark`]
/// followed by [`park`] will result in the second call returning immediately.
/// if it wasn't already. Because the token can be held by a thread even if it is currently not
/// parked, [`unpark`] followed by [`park`] will result in the second call returning immediately.
/// However, note that to rely on this guarantee, you need to make sure that your `unpark` happens
/// after all `park` that may be done by other data structures!
///
/// The API is typically used by acquiring a handle to the current thread,
/// placing that handle in a shared data structure so that other threads can
/// find it, and then `park`ing in a loop. When some desired condition is met, another
/// thread calls [`unpark`] on the handle.
/// The API is typically used by acquiring a handle to the current thread, placing that handle in a
/// shared data structure so that other threads can find it, and then `park`ing in a loop. When some
/// desired condition is met, another thread calls [`unpark`] on the handle. The last bullet point
/// above guarantees that even if the `unpark` occurs before the thread is finished `park`ing, it
/// will be woken up properly.
///
/// Note that the coordination via the shared data structure is crucial: If you `unpark` a thread
/// without first establishing that it is about to be `park`ing within your code, that `unpark` may
/// get consumed by a *different* `park` in the same thread, leading to a deadlock. This also means
/// you must not call unknown code between setting up for parking and calling `park`; for instance,
/// if you invoke `println!`, that may itself call `park` and thus consume your `unpark` and cause a
/// deadlock.
///
/// The motivation for this design is twofold:
///
@ -1058,21 +1068,24 @@ impl Drop for PanicGuard {
///
/// ```
/// use std::thread;
/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
/// use std::sync::atomic::{Ordering, AtomicBool};
/// use std::time::Duration;
///
/// let flag = Arc::new(AtomicBool::new(false));
/// let flag2 = Arc::clone(&flag);
/// static QUEUED: AtomicBool = AtomicBool::new(false);
/// static FLAG: AtomicBool = AtomicBool::new(false);
///
/// let parked_thread = thread::spawn(move || {
/// println!("Thread spawned");
/// // Signal that we are going to `park`. Between this store and our `park`, there may
/// // be no other `park`, or else that `park` could consume our `unpark` token!
/// QUEUED.store(true, Ordering::Release);
/// // We want to wait until the flag is set. We *could* just spin, but using
/// // park/unpark is more efficient.
/// while !flag2.load(Ordering::Relaxed) {
/// println!("Parking thread");
/// while !FLAG.load(Ordering::Acquire) {
/// // We can *not* use `println!` here since that could use thread parking internally.
/// thread::park();
/// // We *could* get here spuriously, i.e., way before the 10ms below are over!
/// // But that is no problem, we are in a loop until the flag is set anyway.
/// println!("Thread unparked");
/// }
/// println!("Flag received");
/// });
@ -1080,11 +1093,22 @@ impl Drop for PanicGuard {
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// // Ensure the thread is about to park.
/// // This is crucial! It guarantees that the `unpark` below is not consumed
/// // by some other code in the parked thread (e.g. inside `println!`).
/// while !QUEUED.load(Ordering::Acquire) {
/// // Spinning is of course inefficient; in practice, this would more likely be
/// // a dequeue where we have no work to do if there's nobody queued.
/// std::hint::spin_loop();
/// }
///
/// // Set the flag, and let the thread wake up.
/// // There is no race condition here, if `unpark`
/// // There is no race condition here: if `unpark`
/// // happens first, `park` will return immediately.
/// // There is also no other `park` that could consume this token,
/// // since we waited until the other thread got queued.
/// // Hence there is no risk of a deadlock.
/// flag.store(true, Ordering::Relaxed);
/// FLAG.store(true, Ordering::Release);
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
@ -1494,10 +1518,14 @@ impl Thread {
/// ```
/// use std::thread;
/// use std::time::Duration;
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// static QUEUED: AtomicBool = AtomicBool::new(false);
///
/// let parked_thread = thread::Builder::new()
/// .spawn(|| {
/// println!("Parking thread");
/// QUEUED.store(true, Ordering::Release);
/// thread::park();
/// println!("Thread unparked");
/// })
@ -1506,6 +1534,15 @@ impl Thread {
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// // Wait until the other thread is queued.
/// // This is crucial! It guarantees that the `unpark` below is not consumed
/// // by some other code in the parked thread (e.g. inside `println!`).
/// while !QUEUED.load(Ordering::Acquire) {
/// // Spinning is of course inefficient; in practice, this would more likely be
/// // a dequeue where we have no work to do if there's nobody queued.
/// std::hint::spin_loop();
/// }
///
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///

View file

@ -287,6 +287,8 @@ fn test_park_unpark_called_other_thread() {
for _ in 0..10 {
let th = thread::current();
// Here we rely on `thread::spawn` (specifically the part that runs after spawning
// the thread) to not consume the parking token.
let _guard = thread::spawn(move || {
super::sleep(Duration::from_millis(50));
th.unpark();
@ -316,6 +318,8 @@ fn test_park_timeout_unpark_called_other_thread() {
for _ in 0..10 {
let th = thread::current();
// Here we rely on `thread::spawn` (specifically the part that runs after spawning
// the thread) to not consume the parking token.
let _guard = thread::spawn(move || {
super::sleep(Duration::from_millis(50));
th.unpark();

View file

@ -17,7 +17,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: notify_one,
test_body: {
@ -38,7 +38,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: notify_all,
test_body: {
@ -79,7 +79,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: test_mutex_arc_condvar,
test_body: {
@ -116,7 +116,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_while,
test_body: {
@ -141,7 +141,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_timeout_wait,
test_body: {
@ -164,7 +164,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_timeout_while_wait,
test_body: {
@ -180,7 +180,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_timeout_while_instant_satisfy,
test_body: {
@ -197,7 +197,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_timeout_while_wake,
test_body: {
@ -226,7 +226,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
nonpoison_and_poison_unwrap_test!(
name: wait_timeout_wake,
test_body: {

View file

@ -58,6 +58,9 @@ fn result_unwrap<T, E: std::fmt::Debug>(x: Result<T, E>) -> T {
/// a no-op (the identity function).
///
/// The test names will be prefiex with `poison_` or `nonpoison_`.
///
/// Important: most attributes (except `cfg`) will not work properly! (They are only applied to the first test.)
/// See <https://github.com/rust-lang/rust/pull/146433> for more information.
macro_rules! nonpoison_and_poison_unwrap_test {
(
name: $name:ident,

View file

@ -266,7 +266,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
#[cfg(panic = "unwind")] // Requires unwinding support.
nonpoison_and_poison_unwrap_test!(
name: test_panics,
test_body: {
@ -297,7 +297,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
#[cfg(panic = "unwind")] // Requires unwinding support.
nonpoison_and_poison_unwrap_test!(
name: test_mutex_arc_access_in_unwind,
test_body: {

View file

@ -50,7 +50,7 @@ nonpoison_and_poison_unwrap_test!(
// FIXME: On macOS we use a provenance-incorrect implementation and Miri
// catches that issue with a chance of around 1/1000.
// See <https://github.com/rust-lang/rust/issues/121950> for details.
#[cfg_attr(all(miri, target_os = "macos"), ignore)]
#[cfg(not(all(miri, target_os = "macos")))]
nonpoison_and_poison_unwrap_test!(
name: frob,
test_body: {
@ -124,7 +124,7 @@ nonpoison_and_poison_unwrap_test!(
}
);
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
#[cfg(panic = "unwind")] // Requires unwinding support.
nonpoison_and_poison_unwrap_test!(
name: test_rw_arc_access_in_unwind,
test_body: {
@ -315,7 +315,7 @@ nonpoison_and_poison_unwrap_test!(
// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
// See <https://github.com/rust-lang/rust/issues/121950> for details.
#[cfg_attr(all(miri, target_os = "macos"), ignore)]
#[cfg(not(all(miri, target_os = "macos")))]
nonpoison_and_poison_unwrap_test!(
name: test_downgrade_observe,
test_body: {
@ -362,7 +362,7 @@ nonpoison_and_poison_unwrap_test!(
// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
// See <https://github.com/rust-lang/rust/issues/121950> for details.
#[cfg_attr(all(miri, target_os = "macos"), ignore)]
#[cfg(not(all(miri, target_os = "macos")))]
nonpoison_and_poison_unwrap_test!(
name: test_downgrade_atomic,
test_body: {

8
package-lock.json generated
View file

@ -5,7 +5,7 @@
"packages": {
"": {
"dependencies": {
"browser-ui-test": "^0.22.0",
"browser-ui-test": "^0.22.2",
"es-check": "^6.2.1",
"eslint": "^8.57.1",
"eslint-js": "github:eslint/js",
@ -485,9 +485,9 @@
}
},
"node_modules/browser-ui-test": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.0.tgz",
"integrity": "sha512-p/C02TMybTDKsAjpGOdnyNC0Q25KDae/fKMnvHaqcJ0tXRqNKwndW2Ltq7HTmin5xqg8GGOmysEgWTZkXu6pfA==",
"version": "0.22.2",
"resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.2.tgz",
"integrity": "sha512-eNB/PN2yDGe5n5IwE3ld/N6A39jM1oRzJmT5nOVQqrvoZEtcd9JSggDQPNVUnMEyuGcD4OEOWMsEa4oJppAmDQ==",
"license": "MIT",
"dependencies": {
"css-unit-converter": "^1.1.2",

View file

@ -1,6 +1,6 @@
{
"dependencies": {
"browser-ui-test": "^0.22.0",
"browser-ui-test": "^0.22.2",
"es-check": "^6.2.1",
"eslint": "^8.57.1",
"eslint-js": "github:eslint/js",

View file

@ -14,6 +14,10 @@ compiletest-use-stage0-libtest = false
[llvm]
download-ci-llvm = false
# Most users installing from source want to build all parts of the project from source.
[gcc]
download-ci-gcc = false
[rust]
# We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`).
# Make sure they don't get set when installing from source.

View file

@ -1383,14 +1383,17 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
}
}
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
// See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step.
if builder.config.jemalloc(target)
&& target.starts_with("aarch64")
&& env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none()
{
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");
if builder.config.jemalloc(target) && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
if target.starts_with("aarch64") {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");
}
// Build jemalloc on LoongArch with support for page sizes up to 16K
else if target.starts_with("loongarch") {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14");
}
}
}

View file

@ -590,6 +590,8 @@ impl Step for Rustc {
// Debugger scripts
builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target });
generate_target_spec_json_schema(builder, image);
// HTML copyright files
let file_list = builder.ensure(super::run::GenerateCopyright);
for file in file_list {
@ -618,6 +620,28 @@ impl Step for Rustc {
}
}
fn generate_target_spec_json_schema(builder: &Builder<'_>, sysroot: &Path) {
// Since we run rustc in bootstrap, we need to ensure that we use the host compiler.
// We do this by using the stage 1 compiler, which is always compiled for the host,
// even in a cross build.
let stage1_host = builder.compiler(1, builder.host_target);
let mut rustc = command(builder.rustc(stage1_host)).fail_fast();
rustc
.env("RUSTC_BOOTSTRAP", "1")
.args(["--print=target-spec-json-schema", "-Zunstable-options"]);
let schema = rustc.run_capture(builder).stdout();
let schema_dir = tmpdir(builder);
t!(fs::create_dir_all(&schema_dir));
let schema_file = schema_dir.join("target-spec-json-schema.json");
t!(std::fs::write(&schema_file, schema));
let dst = sysroot.join("etc");
t!(fs::create_dir_all(&dst));
builder.install(&schema_file, &dst, FileType::Regular);
}
/// Copies debugger scripts for `target` into the given compiler `sysroot`.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DebuggerScripts {

View file

@ -32,6 +32,10 @@ pub struct GccOutput {
impl GccOutput {
/// Install the required libgccjit library file(s) to the specified `path`.
pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
if builder.config.dry_run() {
return;
}
// At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
// However, at runtime, it will by default look for libgccjit.so.0.
// So when we install the built libgccjit.so file to the target `directory`, we add it there
@ -39,8 +43,16 @@ impl GccOutput {
let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
target_filename.push_str(".0");
// If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink.
// In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,
// which wouldn't work.
let actual_libgccjit_path = t!(
self.libgccjit.canonicalize(),
format!("Cannot find libgccjit at {}", self.libgccjit.display())
);
let dst = directory.join(target_filename);
builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary);
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
}
}

View file

@ -228,12 +228,18 @@ pub fn prepare_tool_cargo(
// own copy
cargo.env("LZMA_API_STATIC", "1");
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
// Note that `miri` always uses jemalloc. As such, there is no checking of the jemalloc build flag.
// See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the compile build step.
if target.starts_with("aarch64") && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");
if env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
if target.starts_with("aarch64") {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");
}
// Build jemalloc on LoongArch with support for page sizes up to 16K
else if target.starts_with("loongarch") {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14");
}
}
// CFG_RELEASE is needed by rustfmt (and possibly other tools) which

View file

@ -422,10 +422,10 @@ impl std::str::FromStr for RustcLto {
#[derive(Default, Clone)]
pub enum GccCiMode {
/// Build GCC from the local `src/gcc` submodule.
#[default]
BuildLocally,
/// Try to download GCC from CI.
/// If it is not available on CI, it will be built locally instead.
#[default]
DownloadFromCi,
}

View file

@ -541,4 +541,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
severity: ChangeSeverity::Info,
summary: "Added a new option `rust.break-on-ice` to control if internal compiler errors cause a debug break on Windows.",
},
ChangeInfo {
change_id: 146435,
severity: ChangeSeverity::Info,
summary: "The default value of the `gcc.download-ci-gcc` option has been changed to `true`.",
},
];

View file

@ -43,6 +43,7 @@ pub static CRATES: &[&str] = &[
"rustc-hash",
"self_cell",
"serde",
"serde_derive_internals",
"sha2",
"smallvec",
"stable_deref_trait",

View file

@ -16,6 +16,21 @@ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print targe
To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`.
<div class="warning">
The target JSON properties are not stable and subject to change.
Always pin your compiler version when using custom targets!
</div>
## JSON Schema
`rustc` provides a JSON schema for the custom target JSON specification.
Because the schema is subject to change, you should always use the schema from the version of rustc which you are passing the target to.
It can be found in `etc/target-spec-json-schema.json` in the sysroot (`rustc --print sysroot`) or printed with `rustc +nightly -Zunstable-options --print target-spec-json-schema`.
The existence and name of this schema is, just like the properties of the JSON specification, not stable and subject to change.
## Custom Target Lookup Path
When `rustc` is given an option `--target=TARGET` (where `TARGET` is any string), it uses the following logic:

View file

@ -3639,7 +3639,7 @@ class DocSearch {
if (contains.length === 0) {
return 0;
}
const maxPathEditDistance = Math.floor(
const maxPathEditDistance = parsedQuery.literalSearch ? 0 : Math.floor(
contains.reduce((acc, next) => acc + next.length, 0) / 3,
);
let ret_dist = maxPathEditDistance + 1;
@ -3650,7 +3650,9 @@ class DocSearch {
let dist_total = 0;
for (let x = 0; x < clength; ++x) {
const [p, c] = [path[i + x], contains[x]];
if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
if (parsedQuery.literalSearch && p !== c) {
continue pathiter;
} else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
p.indexOf(c) !== -1
) {
// discount distance on substring match

View file

@ -17,7 +17,10 @@ use crate::core::DocContext;
use crate::html::markdown::main_body_opts;
pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
let report_diag = |cx: &DocContext<'_>,
msg: &'static str,
range: Range<usize>,
without_brackets: Option<&str>| {
let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings)
.map(|(sp, _)| sp);
let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx));
@ -27,14 +30,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
// The fallback of using the attribute span is suitable for
// highlighting where the error is, but not for placing the < and >
if let Some(sp) = maybe_sp {
lint.multipart_suggestion(
"use an automatic link instead",
vec![
(sp.shrink_to_lo(), "<".to_string()),
(sp.shrink_to_hi(), ">".to_string()),
],
Applicability::MachineApplicable,
);
if let Some(without_brackets) = without_brackets {
lint.multipart_suggestion(
"use an automatic link instead",
vec![(sp, format!("<{without_brackets}>"))],
Applicability::MachineApplicable,
);
} else {
lint.multipart_suggestion(
"use an automatic link instead",
vec![
(sp.shrink_to_lo(), "<".to_string()),
(sp.shrink_to_hi(), ">".to_string()),
],
Applicability::MachineApplicable,
);
}
}
});
};
@ -43,7 +54,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
while let Some((event, range)) = p.next() {
match event {
Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag),
Event::Text(s) => find_raw_urls(cx, dox, &s, range, &report_diag),
// We don't want to check the text inside code blocks or links.
Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => {
for (event, _) in p.by_ref() {
@ -67,25 +78,35 @@ static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
r"https?://", // url scheme
r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
r"[a-zA-Z]{2,63}", // root domain
r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments
r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)", // optional query or url fragments
))
.expect("failed to build regex")
});
fn find_raw_urls(
cx: &DocContext<'_>,
dox: &str,
text: &str,
range: Range<usize>,
f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>),
f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>, Option<&str>),
) {
trace!("looking for raw urls in {text}");
// For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
for match_ in URL_REGEX.find_iter(text) {
let url_range = match_.range();
f(
cx,
"this URL is not a hyperlink",
Range { start: range.start + url_range.start, end: range.start + url_range.end },
);
let mut url_range = match_.range();
url_range.start += range.start;
url_range.end += range.start;
let mut without_brackets = None;
// If the link is contained inside `[]`, then we need to replace the brackets and
// not just add `<>`.
if dox[..url_range.start].ends_with('[')
&& url_range.end <= dox.len()
&& dox[url_range.end..].starts_with(']')
{
url_range.start -= 1;
url_range.end += 1;
without_brackets = Some(match_.as_str());
}
f(cx, "this URL is not a hyperlink", url_range, without_brackets);
}
}

View file

@ -2133,17 +2133,11 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
}
pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx
.hir_attrs(hir::CRATE_HIR_ID)
.iter()
.any(|attr| attr.has_name(sym::no_std))
find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoStd(..))
}
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx
.hir_attrs(hir::CRATE_HIR_ID)
.iter()
.any(|attr| attr.has_name(sym::no_core))
find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoCore(..))
}
/// Check if parent of a hir node is a trait implementation block.

View file

@ -606,6 +606,7 @@ Definite bugs found:
* [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
* [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
* [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816)
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):

View file

@ -267,6 +267,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"digest",
"displaydoc",
"dissimilar",
"dyn-clone",
"either",
"elsa",
"ena",
@ -346,6 +347,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"rand_xorshift", // dependency for doc-tests in rustc_thread_pool
"rand_xoshiro",
"redox_syscall",
"ref-cast",
"ref-cast-impl",
"regex",
"regex-automata",
"regex-syntax",
@ -357,11 +360,14 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"rustix",
"ruzstd", // via object in thorin-dwp
"ryu",
"schemars",
"schemars_derive",
"scoped-tls",
"scopeguard",
"self_cell",
"serde",
"serde_derive",
"serde_derive_internals",
"serde_json",
"serde_path_to_error",
"sha1",

View file

@ -124,6 +124,12 @@ fn check_impl(
};
}
let rerun_with_bless = |mode: &str, action: &str| {
if !bless {
eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}");
}
};
let python_lint = extra_check!(Py, Lint);
let python_fmt = extra_check!(Py, Fmt);
let shell_lint = extra_check!(Shell, Lint);
@ -147,14 +153,21 @@ fn check_impl(
}
if python_lint {
eprintln!("linting python files");
let py_path = py_path.as_ref().unwrap();
let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &["check".as_ref()]);
let args: &[&OsStr] = if bless {
eprintln!("linting python files and applying suggestions");
&["check".as_ref(), "--fix".as_ref()]
} else {
eprintln!("linting python files");
&["check".as_ref()]
};
if res.is_err() && show_diff {
let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args);
if res.is_err() && show_diff && !bless {
eprintln!("\npython linting failed! Printing diff suggestions:");
let _ = run_ruff(
let diff_res = run_ruff(
root_path,
outdir,
py_path,
@ -162,6 +175,10 @@ fn check_impl(
&file_args,
&["check".as_ref(), "--diff".as_ref()],
);
// `ruff check --diff` will return status 0 if there are no suggestions.
if diff_res.is_err() {
rerun_with_bless("py:lint", "apply ruff suggestions");
}
}
// Rethrow error
res?;
@ -192,7 +209,7 @@ fn check_impl(
&["format".as_ref(), "--diff".as_ref()],
);
}
eprintln!("rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code");
rerun_with_bless("py:fmt", "reformat Python code");
}
// Rethrow error
@ -225,7 +242,7 @@ fn check_impl(
let args = merge_args(&cfg_args_clang_format, &file_args_clang_format);
let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args);
if res.is_err() && show_diff {
if res.is_err() && show_diff && !bless {
eprintln!("\nclang-format linting failed! Printing diff suggestions:");
let mut cfg_args_clang_format_diff = cfg_args.clone();
@ -265,6 +282,7 @@ fn check_impl(
);
}
}
rerun_with_bless("cpp:fmt", "reformat C++ code");
}
// Rethrow error
res?;
@ -290,12 +308,16 @@ fn check_impl(
args.extend_from_slice(SPELLCHECK_DIRS);
if bless {
eprintln!("spellcheck files and fix");
eprintln!("spellchecking files and fixing typos");
args.push("--write-changes");
} else {
eprintln!("spellcheck files");
eprintln!("spellchecking files");
}
spellcheck_runner(root_path, &outdir, &cargo, &args)?;
let res = spellcheck_runner(root_path, &outdir, &cargo, &args);
if res.is_err() {
rerun_with_bless("spellcheck", "fix typos");
}
res?;
}
if js_lint || js_typecheck {
@ -303,11 +325,21 @@ fn check_impl(
}
if js_lint {
rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless)?;
if bless {
eprintln!("linting javascript files");
} else {
eprintln!("linting javascript files and applying suggestions");
}
let res = rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless);
if res.is_err() {
rerun_with_bless("js:lint", "apply eslint suggestions");
}
res?;
rustdoc_js::es_check(outdir, librustdoc_path)?;
}
if js_typecheck {
eprintln!("typechecking javascript files");
rustdoc_js::typecheck(outdir, librustdoc_path)?;
}

View file

@ -57,7 +57,7 @@ fn run_eslint(
if exit_status.success() {
return Ok(());
}
Err(super::Error::FailedCheck("eslint command failed"))
Err(super::Error::FailedCheck("eslint"))
}
Err(error) => Err(super::Error::Generic(format!("eslint command failed: {error:?}"))),
}
@ -94,7 +94,7 @@ pub(super) fn typecheck(outdir: &Path, librustdoc_path: &Path) -> Result<(), sup
if exit_status.success() {
return Ok(());
}
Err(super::Error::FailedCheck("tsc command failed"))
Err(super::Error::FailedCheck("tsc"))
}
Err(error) => Err(super::Error::Generic(format!("tsc command failed: {error:?}"))),
}
@ -112,7 +112,7 @@ pub(super) fn es_check(outdir: &Path, librustdoc_path: &Path) -> Result<(), supe
if exit_status.success() {
return Ok(());
}
Err(super::Error::FailedCheck("es-check command failed"))
Err(super::Error::FailedCheck("es-check"))
}
Err(error) => Err(super::Error::Generic(format!("es-check command failed: {error:?}"))),
}

View file

@ -0,0 +1,26 @@
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3
//@ only-arm
//@ ignore-thumb
//@ ignore-android
#![no_std]
#![crate_type = "lib"]
#![feature(c_variadic)]
// Check that the assembly that rustc generates matches what clang emits.
#[unsafe(no_mangle)]
unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
// CHECK-LABEL: variadic
// CHECK: sub sp, sp
// CHECK: vldr
// CHECK: vadd.f64
// CHECK: vldr
// CHECK: vadd.f64
let b = args.arg::<f64>();
let c = args.arg::<f64>();
a + b + c
// CHECK: add sp, sp
}

View file

@ -0,0 +1,21 @@
//@ add-core-stubs
//@ compile-flags: -Copt-level=3
#![feature(c_variadic)]
#![crate_type = "lib"]
// Check that `%args` explicitly has its lifetime start and end. Being explicit can improve
// instruction and register selection, see e.g. https://github.com/rust-lang/rust/pull/144549
#[unsafe(no_mangle)]
unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
// CHECK: call void @llvm.lifetime.start.p0(i64 {{[0-9]+}}, ptr nonnull %args)
// CHECK: call void @llvm.va_start.p0(ptr nonnull %args)
let b = args.arg::<f64>();
let c = args.arg::<f64>();
a + b + c
// CHECK: call void @llvm.va_end.p0(ptr nonnull %args)
// CHECK: call void @llvm.lifetime.end.p0(i64 {{[0-9]+}}, ptr nonnull %args)
}

View file

@ -2,6 +2,6 @@
error: unknown print request: `xxx`
|
- = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models`
+ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
+ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models`
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information

View file

@ -1,5 +1,5 @@
error: unknown print request: `xxx`
|
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
= help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models`
= help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information

View file

@ -43,7 +43,7 @@ Options:
--print <INFO>[=<FILE>]
Compiler information to print on stdout (or to a file)
INFO may be one of
<all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models>.
<all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|target-spec-json-schema|tls-models>.
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3
-o <FILENAME> Write output to FILENAME

View file

@ -43,7 +43,7 @@ Options:
--print <INFO>[=<FILE>]
Compiler information to print on stdout (or to a file)
INFO may be one of
<all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models>.
<all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|target-spec-json-schema|tls-models>.
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3
-o <FILENAME> Write output to FILENAME

View file

@ -0,0 +1,23 @@
// exact-check
// This test ensures that literal search is always applied on elements of the path.
const EXPECTED = [
{
'query': '"some::path"',
'others': [
{ 'path': 'literal_path::some', 'name': 'Path' },
],
},
{
'query': '"somea::path"',
'others': [
{ 'path': 'literal_path::somea', 'name': 'Path' },
],
},
{
'query': '"soma::path"',
'others': [
],
},
];

View file

@ -0,0 +1,7 @@
pub mod some {
pub struct Path;
}
pub mod somea {
pub struct Path;
}

View file

@ -68,3 +68,17 @@ pub mod foo {
/// https://somewhere.com/a?hello=12&bye=11#xyz
pub fn bar() {}
}
/// <https://bloob.blob>
//~^ ERROR this URL is not a hyperlink
/// [ <https://bloob.blob> ]
//~^ ERROR this URL is not a hyperlink
/// [ <https://bloob.blob>]
//~^ ERROR this URL is not a hyperlink
/// [<https://bloob.blob> ]
//~^ ERROR this URL is not a hyperlink
/// [<https://bloob.blob>
//~^ ERROR this URL is not a hyperlink
/// <https://bloob.blob>]
//~^ ERROR this URL is not a hyperlink
pub fn lint_with_brackets() {}

View file

@ -68,3 +68,17 @@ pub mod foo {
/// https://somewhere.com/a?hello=12&bye=11#xyz
pub fn bar() {}
}
/// [https://bloob.blob]
//~^ ERROR this URL is not a hyperlink
/// [ https://bloob.blob ]
//~^ ERROR this URL is not a hyperlink
/// [ https://bloob.blob]
//~^ ERROR this URL is not a hyperlink
/// [https://bloob.blob ]
//~^ ERROR this URL is not a hyperlink
/// [https://bloob.blob
//~^ ERROR this URL is not a hyperlink
/// https://bloob.blob]
//~^ ERROR this URL is not a hyperlink
pub fn lint_with_brackets() {}

View file

@ -243,5 +243,73 @@ help: use an automatic link instead
LL | #[doc = "<https://example.com/raw>"]
| + +
error: aborting due to 20 previous errors
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:72:5
|
LL | /// [https://bloob.blob]
| ^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://bloob.blob>`
|
= note: bare URLs are not automatically turned into clickable links
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:74:7
|
LL | /// [ https://bloob.blob ]
| ^^^^^^^^^^^^^^^^^^
|
= note: bare URLs are not automatically turned into clickable links
help: use an automatic link instead
|
LL | /// [ <https://bloob.blob> ]
| + +
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:76:7
|
LL | /// [ https://bloob.blob]
| ^^^^^^^^^^^^^^^^^^
|
= note: bare URLs are not automatically turned into clickable links
help: use an automatic link instead
|
LL | /// [ <https://bloob.blob>]
| + +
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:78:6
|
LL | /// [https://bloob.blob ]
| ^^^^^^^^^^^^^^^^^^
|
= note: bare URLs are not automatically turned into clickable links
help: use an automatic link instead
|
LL | /// [<https://bloob.blob> ]
| + +
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:80:6
|
LL | /// [https://bloob.blob
| ^^^^^^^^^^^^^^^^^^
|
= note: bare URLs are not automatically turned into clickable links
help: use an automatic link instead
|
LL | /// [<https://bloob.blob>
| + +
error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:82:5
|
LL | /// https://bloob.blob]
| ^^^^^^^^^^^^^^^^^^
|
= note: bare URLs are not automatically turned into clickable links
help: use an automatic link instead
|
LL | /// <https://bloob.blob>]
| + +
error: aborting due to 26 previous errors

View file

@ -0,0 +1,25 @@
#![feature(no_core)]
// these all still apply no_std and then later error
#![no_std = "foo"]
//~^ ERROR malformed `no_std` attribute input
#![no_std("bar")]
//~^ ERROR malformed `no_std` attribute input
#![no_std(foo = "bar")]
//~^ ERROR malformed `no_std` attribute input
#![no_core = "foo"]
//~^ ERROR malformed `no_core` attribute input
#![no_core("bar")]
//~^ ERROR malformed `no_core` attribute input
#![no_core(foo = "bar")]
//~^ ERROR malformed `no_core` attribute input
#[deny(unused_attributes)]
#[no_std]
//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark:
#[no_core]
//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark:
// to fix compilation
extern crate core;
extern crate std;
fn main() {}

View file

@ -0,0 +1,86 @@
error[E0565]: malformed `no_std` attribute input
--> $DIR/malformed-no-std.rs:3:1
|
LL | #![no_std = "foo"]
| ^^^^^^^^^^-------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_std]`
error[E0565]: malformed `no_std` attribute input
--> $DIR/malformed-no-std.rs:5:1
|
LL | #![no_std("bar")]
| ^^^^^^^^^-------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_std]`
error[E0565]: malformed `no_std` attribute input
--> $DIR/malformed-no-std.rs:7:1
|
LL | #![no_std(foo = "bar")]
| ^^^^^^^^^-------------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_std]`
error[E0565]: malformed `no_core` attribute input
--> $DIR/malformed-no-std.rs:9:1
|
LL | #![no_core = "foo"]
| ^^^^^^^^^^^-------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_core]`
error[E0565]: malformed `no_core` attribute input
--> $DIR/malformed-no-std.rs:11:1
|
LL | #![no_core("bar")]
| ^^^^^^^^^^-------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_core]`
error[E0565]: malformed `no_core` attribute input
--> $DIR/malformed-no-std.rs:13:1
|
LL | #![no_core(foo = "bar")]
| ^^^^^^^^^^-------------^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#![no_core]`
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/malformed-no-std.rs:17:1
|
LL | #[no_std]
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this extern crate
--> $DIR/malformed-no-std.rs:22:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/malformed-no-std.rs:16:8
|
LL | #[deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_core]`
--> $DIR/malformed-no-std.rs:19:1
|
LL | #[no_core]
| ^^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this extern crate
--> $DIR/malformed-no-std.rs:22:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0565`.

View file

@ -9,8 +9,7 @@ fn main() {
assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
assert!(TypeId::of::<()>() != TypeId::of::<u8>());
let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
//~^ ERROR: cannot call non-const operator in constants
// can't assert `_a` because it is not deterministic
// FIXME(const_trait_impl) make it pass
//~^ ERROR: the trait bound `TypeId: const PartialOrd` is not satisfied
// FIXME(const_trait_impl) make it pass; requires const comparison of pointers (#53020)
}
}

View file

@ -1,13 +1,9 @@
error[E0015]: cannot call non-const operator in constants
error[E0277]: the trait bound `TypeId: const PartialOrd` is not satisfied
--> $DIR/const_cmp_type_id.rs:11:18
|
LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,6 +1,5 @@
//@ known-bug: #110395
//@ check-pass
#![feature(const_fn_trait_ref_impls)]
#![feature(fn_traits)]
#![feature(unboxed_closures)]
#![feature(const_trait_impl)]

View file

@ -1,22 +0,0 @@
error[E0635]: unknown feature `const_fn_trait_ref_impls`
--> $DIR/fn_trait_refs.rs:3:12
|
LL | #![feature(const_fn_trait_ref_impls)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied
--> $DIR/fn_trait_refs.rs:71:17
|
LL | assert!(test_one == (1, 1, 1));
| ^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied
--> $DIR/fn_trait_refs.rs:74:17
|
LL | assert!(test_two == (2, 2));
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0635.
For more information about an error, try `rustc --explain E0277`.

View file

@ -8,11 +8,11 @@ LL | <[X; 35] as Default>::default();
&[T]
&mut [T]
[T; 0]
[T; 10]
[T; 11]
[T; 12]
[T; 13]
[T; 14]
[T; 1]
[T; 2]
[T; 3]
[T; 4]
[T; 5]
and 27 others
error: aborting due to 1 previous error

View file

@ -1,4 +1,3 @@
//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
#![feature(no_sanitize)] //~ ERROR feature has been removed
#[sanitize(address = "on")]

View file

@ -1,5 +1,5 @@
error[E0557]: feature has been removed
--> $DIR/feature-gate-sanitize.rs:2:12
--> $DIR/feature-gate-sanitize.rs:1:12
|
LL | #![feature(no_sanitize)]
| ^^^^^^^^^^^ feature has been removed
@ -8,7 +8,7 @@ LL | #![feature(no_sanitize)]
= note: renamed to sanitize(xyz = "on|off")
error[E0658]: the `#[sanitize]` attribute is an experimental feature
--> $DIR/feature-gate-sanitize.rs:4:1
--> $DIR/feature-gate-sanitize.rs:3:1
|
LL | #[sanitize(address = "on")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -539,26 +539,26 @@ mod macro_escape {
#[no_std]
//~^ WARN crate-level attribute should be an inner attribute
//~| HELP add a `!`
mod no_std {
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
mod inner { #![no_std] }
//~^ WARN crate-level attribute should be in the root module
//~^ WARN the `#![no_std]` attribute can only be used at the crate root
#[no_std] fn f() { }
//~^ WARN crate-level attribute should be an inner attribute
//~| HELP add a `!`
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
#[no_std] struct S;
//~^ WARN crate-level attribute should be an inner attribute
//~| HELP add a `!`
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
#[no_std] type T = S;
//~^ WARN crate-level attribute should be an inner attribute
//~| HELP add a `!`
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
#[no_std] impl S { }
//~^ WARN crate-level attribute should be an inner attribute
//~| HELP add a `!`
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
}
// At time of authorship, #[proc_macro_derive = "2500"] signals error

View file

@ -209,17 +209,6 @@ help: add a `!`
LL | #![reexport_test_harness_main = "2900"]
| +
warning: crate-level attribute should be an inner attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1
|
LL | #[no_std]
| ^^^^^^^^^
|
help: add a `!`
|
LL | #![no_std]
| +
warning: attribute should be applied to an `extern` block with non-Rust ABI
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:1
|
@ -387,56 +376,6 @@ help: add a `!`
LL | #![reexport_test_harness_main = "2900"] impl S { }
| +
warning: crate-level attribute should be in the root module
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
|
help: add a `!`
|
LL | #![no_std] fn f() { }
| +
warning: crate-level attribute should be an inner attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
|
help: add a `!`
|
LL | #![no_std] struct S;
| +
warning: crate-level attribute should be an inner attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
|
help: add a `!`
|
LL | #![no_std] type T = S;
| +
warning: crate-level attribute should be an inner attribute
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
|
help: add a `!`
|
LL | #![no_std] impl S { }
| +
warning: attribute should be applied to an `extern` block with non-Rust ABI
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17
|
@ -1095,6 +1034,76 @@ LL | #[macro_escape] impl S { }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[macro_escape]` can be applied to modules, extern crates, and crates
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1
|
LL | #[no_std]
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this module
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:1
|
LL | / mod no_std {
LL | |
LL | | mod inner { #![no_std] }
... |
LL | | }
| |_^
warning: the `#![no_std]` attribute can only be used at the crate root
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this function
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:15
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this struct
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:15
|
LL | #[no_std] struct S;
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this type alias
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:15
|
LL | #[no_std] type T = S;
| ^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
|
note: This attribute does not have an `!`, which means it is applied to this implementation block
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:15
|
LL | #[no_std] impl S { }
| ^^^^^^^^^^
warning: `#[cold]` attribute cannot be used on modules
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:1
|

View file

@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> $DIR/avoid-inference-constraints-from-blanket-2.rs:27:18
|
LL | let _: u32 = x;
| --- ^ expected `u32`, found `u64`
| |
| expected due to this
|
help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
|
LL | let _: u32 = x.try_into().unwrap();
| ++++++++++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

Some files were not shown because too many files have changed in this diff Show more