Merge ref '4ba1cf9ade' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref:4ba1cf9adeFiltered ref: 84b64d836ed478c54972a1d2639e60fa5f3ce26f Upstream diff:2a9bacf618...4ba1cf9adeThis merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
520e45a538
123 changed files with 2168 additions and 1286 deletions
135
Cargo.lock
135
Cargo.lock
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 { ... }`).
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
32
library/std/src/sys/pal/unix/weak/tests.rs
Normal file
32
library/std/src/sys/pal/unix/weak/tests.rs
Normal 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());
|
||||
}
|
||||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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
8
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ pub static CRATES: &[&str] = &[
|
|||
"rustc-hash",
|
||||
"self_cell",
|
||||
"serde",
|
||||
"serde_derive_internals",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"stable_deref_trait",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:?}"))),
|
||||
}
|
||||
|
|
|
|||
26
tests/assembly-llvm/c-variadic-arm.rs
Normal file
26
tests/assembly-llvm/c-variadic-arm.rs
Normal 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
|
||||
}
|
||||
21
tests/codegen-llvm/c-variadic-lifetime.rs
Normal file
21
tests/codegen-llvm/c-variadic-lifetime.rs
Normal 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)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
23
tests/rustdoc-js/literal-path.js
Normal file
23
tests/rustdoc-js/literal-path.js
Normal 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': [
|
||||
],
|
||||
},
|
||||
];
|
||||
7
tests/rustdoc-js/literal-path.rs
Normal file
7
tests/rustdoc-js/literal-path.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
pub mod some {
|
||||
pub struct Path;
|
||||
}
|
||||
|
||||
pub mod somea {
|
||||
pub struct Path;
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
25
tests/ui/attributes/malformed-no-std.rs
Normal file
25
tests/ui/attributes/malformed-no-std.rs
Normal 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() {}
|
||||
86
tests/ui/attributes/malformed-no-std.stderr
Normal file
86
tests/ui/attributes/malformed-no-std.stderr
Normal 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`.
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue