mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Auto merge of #100525 - Dylan-DPC:rollup-4cp6nu0, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #99582 (Delay a span bug if we see ty/const generic params during writeback) - #99861 (orphan check: rationalize our handling of constants) - #100026 (Add `Iterator::array_chunks` (take N+1)) - #100115 (Suggest removing `let` if `const let` or `let const` is used) - #100126 (rustc_target: Update some old naming around self contained linking) - #100487 (`assert_{inhabited,zero_valid,uninit_valid}` intrinsics are safe) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4c56655838
@ -20,7 +20,7 @@ use rustc_session::utils::NativeLibKind;
|
||||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::DebuggerVisualizerFile;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
|
||||
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
|
||||
|
||||
@ -764,15 +764,15 @@ fn link_natively<'a>(
|
||||
"Linker does not support -static-pie command line option. Retrying with -static instead."
|
||||
);
|
||||
// Mirror `add_(pre,post)_link_objects` to replace CRT objects.
|
||||
let self_contained = crt_objects_fallback(sess, crate_type);
|
||||
let self_contained = self_contained(sess, crate_type);
|
||||
let opts = &sess.target;
|
||||
let pre_objects = if self_contained {
|
||||
&opts.pre_link_objects_fallback
|
||||
&opts.pre_link_objects_self_contained
|
||||
} else {
|
||||
&opts.pre_link_objects
|
||||
};
|
||||
let post_objects = if self_contained {
|
||||
&opts.post_link_objects_fallback
|
||||
&opts.post_link_objects_self_contained
|
||||
} else {
|
||||
&opts.post_link_objects
|
||||
};
|
||||
@ -1556,26 +1556,26 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
|
||||
/// Various toolchain components used during linking are used from rustc distribution
|
||||
/// instead of being found somewhere on the host system.
|
||||
/// We only provide such support for a very limited number of targets.
|
||||
fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
|
||||
fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
|
||||
if let Some(self_contained) = sess.opts.cg.link_self_contained {
|
||||
return self_contained;
|
||||
}
|
||||
|
||||
match sess.target.crt_objects_fallback {
|
||||
match sess.target.link_self_contained {
|
||||
LinkSelfContainedDefault::False => false,
|
||||
LinkSelfContainedDefault::True => true,
|
||||
// FIXME: Find a better heuristic for "native musl toolchain is available",
|
||||
// based on host and linker path, for example.
|
||||
// (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
|
||||
Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
|
||||
Some(CrtObjectsFallback::Mingw) => {
|
||||
LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)),
|
||||
LinkSelfContainedDefault::Mingw => {
|
||||
sess.host == sess.target
|
||||
&& sess.target.vendor != "uwp"
|
||||
&& detect_self_contained_mingw(&sess)
|
||||
}
|
||||
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
|
||||
Some(CrtObjectsFallback::Wasm) => true,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1592,7 +1592,7 @@ fn add_pre_link_objects(
|
||||
let opts = &sess.target;
|
||||
let empty = Default::default();
|
||||
let objects = if self_contained {
|
||||
&opts.pre_link_objects_fallback
|
||||
&opts.pre_link_objects_self_contained
|
||||
} else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
|
||||
&opts.pre_link_objects
|
||||
} else {
|
||||
@ -1610,9 +1610,11 @@ fn add_post_link_objects(
|
||||
link_output_kind: LinkOutputKind,
|
||||
self_contained: bool,
|
||||
) {
|
||||
let opts = &sess.target;
|
||||
let objects =
|
||||
if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
|
||||
let objects = if self_contained {
|
||||
&sess.target.post_link_objects_self_contained
|
||||
} else {
|
||||
&sess.target.post_link_objects
|
||||
};
|
||||
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
|
||||
cmd.add_object(&get_object_file_path(sess, obj, self_contained));
|
||||
}
|
||||
@ -1891,12 +1893,12 @@ fn linker_with_args<'a>(
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
) -> Result<Command, ErrorGuaranteed> {
|
||||
let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
|
||||
let self_contained = self_contained(sess, crate_type);
|
||||
let cmd = &mut *super::linker::get_linker(
|
||||
sess,
|
||||
path,
|
||||
flavor,
|
||||
crt_objects_fallback,
|
||||
self_contained,
|
||||
&codegen_results.crate_info.target_cpu,
|
||||
);
|
||||
let link_output_kind = link_output_kind(sess, crate_type);
|
||||
@ -1923,7 +1925,7 @@ fn linker_with_args<'a>(
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Pre-link CRT objects.
|
||||
add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback);
|
||||
add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained);
|
||||
|
||||
add_linked_symbol_object(
|
||||
cmd,
|
||||
@ -2033,7 +2035,7 @@ fn linker_with_args<'a>(
|
||||
cmd,
|
||||
sess,
|
||||
link_output_kind,
|
||||
crt_objects_fallback,
|
||||
self_contained,
|
||||
flavor,
|
||||
crate_type,
|
||||
codegen_results,
|
||||
@ -2049,7 +2051,7 @@ fn linker_with_args<'a>(
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Post-link CRT objects.
|
||||
add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
|
||||
add_post_link_objects(cmd, sess, link_output_kind, self_contained);
|
||||
|
||||
// ------------ Late order-dependent options ------------
|
||||
|
||||
@ -2066,7 +2068,7 @@ fn add_order_independent_options(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
link_output_kind: LinkOutputKind,
|
||||
crt_objects_fallback: bool,
|
||||
self_contained: bool,
|
||||
flavor: LinkerFlavor,
|
||||
crate_type: CrateType,
|
||||
codegen_results: &CodegenResults,
|
||||
@ -2098,7 +2100,7 @@ fn add_order_independent_options(
|
||||
// Make the binary compatible with data execution prevention schemes.
|
||||
cmd.add_no_exec();
|
||||
|
||||
if crt_objects_fallback {
|
||||
if self_contained {
|
||||
cmd.no_crt_objects();
|
||||
}
|
||||
|
||||
@ -2127,7 +2129,7 @@ fn add_order_independent_options(
|
||||
|
||||
cmd.linker_plugin_lto();
|
||||
|
||||
add_library_search_dirs(cmd, sess, crt_objects_fallback);
|
||||
add_library_search_dirs(cmd, sess, self_contained);
|
||||
|
||||
cmd.output_filename(out_filename);
|
||||
|
||||
|
@ -1162,6 +1162,16 @@ impl<'a> Parser<'a> {
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
} else if self.eat_keyword(kw::Let) {
|
||||
let span = self.prev_token.span;
|
||||
self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive")
|
||||
.span_suggestion(
|
||||
const_span.to(span),
|
||||
"remove `let`",
|
||||
"const",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,6 +247,22 @@ impl<'a> Parser<'a> {
|
||||
/// Parses a local variable declaration.
|
||||
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
||||
let lo = self.prev_token.span;
|
||||
|
||||
if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
|
||||
self.struct_span_err(
|
||||
lo.to(self.token.span),
|
||||
"`const` and `let` are mutually exclusive",
|
||||
)
|
||||
.span_suggestion(
|
||||
lo.to(self.token.span),
|
||||
"remove `let`",
|
||||
"const",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
}
|
||||
|
||||
let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?;
|
||||
|
||||
let (err, ty) = if colon {
|
||||
|
@ -63,7 +63,7 @@ pub(super) fn all(obj: &'static str) -> CrtObjects {
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn pre_musl_fallback() -> CrtObjects {
|
||||
pub(super) fn pre_musl_self_contained() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]),
|
||||
@ -74,7 +74,7 @@ pub(super) fn pre_musl_fallback() -> CrtObjects {
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_musl_fallback() -> CrtObjects {
|
||||
pub(super) fn post_musl_self_contained() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]),
|
||||
@ -85,7 +85,7 @@ pub(super) fn post_musl_fallback() -> CrtObjects {
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn pre_mingw_fallback() -> CrtObjects {
|
||||
pub(super) fn pre_mingw_self_contained() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
@ -96,7 +96,7 @@ pub(super) fn pre_mingw_fallback() -> CrtObjects {
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_mingw_fallback() -> CrtObjects {
|
||||
pub(super) fn post_mingw_self_contained() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ pub(super) fn post_mingw() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_wasi_fallback() -> CrtObjects {
|
||||
pub(super) fn pre_wasi_self_contained() -> CrtObjects {
|
||||
// Use crt1-command.o instead of crt1.o to enable support for new-style
|
||||
// commands. See https://reviews.llvm.org/D81689 for more info.
|
||||
new(&[
|
||||
@ -120,37 +120,41 @@ pub(super) fn pre_wasi_fallback() -> CrtObjects {
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_wasi_fallback() -> CrtObjects {
|
||||
pub(super) fn post_wasi_self_contained() -> CrtObjects {
|
||||
new(&[])
|
||||
}
|
||||
|
||||
/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
|
||||
/// Which logic to use to determine whether to use self-contained linking mode
|
||||
/// if `-Clink-self-contained` is not specified explicitly.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum CrtObjectsFallback {
|
||||
pub enum LinkSelfContainedDefault {
|
||||
False,
|
||||
True,
|
||||
Musl,
|
||||
Mingw,
|
||||
Wasm,
|
||||
}
|
||||
|
||||
impl FromStr for CrtObjectsFallback {
|
||||
impl FromStr for LinkSelfContainedDefault {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<CrtObjectsFallback, ()> {
|
||||
fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> {
|
||||
Ok(match s {
|
||||
"musl" => CrtObjectsFallback::Musl,
|
||||
"mingw" => CrtObjectsFallback::Mingw,
|
||||
"wasm" => CrtObjectsFallback::Wasm,
|
||||
"false" => LinkSelfContainedDefault::False,
|
||||
"true" | "wasm" => LinkSelfContainedDefault::True,
|
||||
"musl" => LinkSelfContainedDefault::Musl,
|
||||
"mingw" => LinkSelfContainedDefault::Mingw,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for CrtObjectsFallback {
|
||||
impl ToJson for LinkSelfContainedDefault {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
CrtObjectsFallback::Musl => "musl",
|
||||
CrtObjectsFallback::Mingw => "mingw",
|
||||
CrtObjectsFallback::Wasm => "wasm",
|
||||
LinkSelfContainedDefault::False => "false",
|
||||
LinkSelfContainedDefault::True => "true",
|
||||
LinkSelfContainedDefault::Musl => "musl",
|
||||
LinkSelfContainedDefault::Mingw => "mingw",
|
||||
}
|
||||
.to_json()
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::spec::crt_objects::{self, CrtObjectsFallback};
|
||||
use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
|
||||
use crate::spec::TargetOptions;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut base = super::linux_base::opts();
|
||||
|
||||
base.env = "musl".into();
|
||||
base.pre_link_objects_fallback = crt_objects::pre_musl_fallback();
|
||||
base.post_link_objects_fallback = crt_objects::post_musl_fallback();
|
||||
base.crt_objects_fallback = Some(CrtObjectsFallback::Musl);
|
||||
base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained();
|
||||
base.post_link_objects_self_contained = crt_objects::post_musl_self_contained();
|
||||
base.link_self_contained = LinkSelfContainedDefault::Musl;
|
||||
|
||||
// These targets statically link libc by default
|
||||
base.crt_static_default = true;
|
||||
|
@ -37,7 +37,7 @@
|
||||
use crate::abi::Endian;
|
||||
use crate::json::{Json, ToJson};
|
||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||
use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
@ -1172,13 +1172,10 @@ pub struct TargetOptions {
|
||||
/// Objects to link before and after all other object code.
|
||||
pub pre_link_objects: CrtObjects,
|
||||
pub post_link_objects: CrtObjects,
|
||||
/// Same as `(pre|post)_link_objects`, but when we fail to pull the objects with help of the
|
||||
/// target's native gcc and fall back to the "self-contained" mode and pull them manually.
|
||||
/// See `crt_objects.rs` for some more detailed documentation.
|
||||
pub pre_link_objects_fallback: CrtObjects,
|
||||
pub post_link_objects_fallback: CrtObjects,
|
||||
/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
|
||||
pub crt_objects_fallback: Option<CrtObjectsFallback>,
|
||||
/// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
|
||||
pub pre_link_objects_self_contained: CrtObjects,
|
||||
pub post_link_objects_self_contained: CrtObjects,
|
||||
pub link_self_contained: LinkSelfContainedDefault,
|
||||
|
||||
/// Linker arguments that are unconditionally passed after any
|
||||
/// user-defined but before post-link objects. Standard platform
|
||||
@ -1554,9 +1551,9 @@ impl Default for TargetOptions {
|
||||
relro_level: RelroLevel::None,
|
||||
pre_link_objects: Default::default(),
|
||||
post_link_objects: Default::default(),
|
||||
pre_link_objects_fallback: Default::default(),
|
||||
post_link_objects_fallback: Default::default(),
|
||||
crt_objects_fallback: None,
|
||||
pre_link_objects_self_contained: Default::default(),
|
||||
post_link_objects_self_contained: Default::default(),
|
||||
link_self_contained: LinkSelfContainedDefault::False,
|
||||
late_link_args: LinkArgs::new(),
|
||||
late_link_args_dynamic: LinkArgs::new(),
|
||||
late_link_args_static: LinkArgs::new(),
|
||||
@ -1977,20 +1974,20 @@ impl Target {
|
||||
Ok::<(), String>(())
|
||||
} );
|
||||
|
||||
($key_name:ident, crt_objects_fallback) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||
match s.parse::<CrtObjectsFallback>() {
|
||||
Ok(fallback) => base.$key_name = Some(fallback),
|
||||
_ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
|
||||
Use 'musl', 'mingw' or 'wasm'", s))),
|
||||
($key_name:ident = $json_name:expr, link_self_contained) => ( {
|
||||
let name = $json_name;
|
||||
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
|
||||
match s.parse::<LinkSelfContainedDefault>() {
|
||||
Ok(lsc_default) => base.$key_name = lsc_default,
|
||||
_ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
|
||||
Use 'false', 'true', 'musl' or 'mingw'", s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, link_objects) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
if let Some(val) = obj.remove(&name) {
|
||||
($key_name:ident = $json_name:expr, link_objects) => ( {
|
||||
let name = $json_name;
|
||||
if let Some(val) = obj.remove(name) {
|
||||
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
|
||||
JSON object with fields per CRT object kind.", name))?;
|
||||
let mut args = CrtObjects::new();
|
||||
@ -2112,11 +2109,11 @@ impl Target {
|
||||
key!(linker_flavor, LinkerFlavor)?;
|
||||
key!(linker, optional);
|
||||
key!(lld_flavor, LldFlavor)?;
|
||||
key!(pre_link_objects, link_objects);
|
||||
key!(post_link_objects, link_objects);
|
||||
key!(pre_link_objects_fallback, link_objects);
|
||||
key!(post_link_objects_fallback, link_objects);
|
||||
key!(crt_objects_fallback, crt_objects_fallback)?;
|
||||
key!(pre_link_objects = "pre-link-objects", link_objects);
|
||||
key!(post_link_objects = "post-link-objects", link_objects);
|
||||
key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
|
||||
key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
|
||||
key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
|
||||
key!(pre_link_args, link_args);
|
||||
key!(late_link_args, link_args);
|
||||
key!(late_link_args_dynamic, link_args);
|
||||
@ -2357,9 +2354,9 @@ impl ToJson for Target {
|
||||
target_option_val!(lld_flavor);
|
||||
target_option_val!(pre_link_objects);
|
||||
target_option_val!(post_link_objects);
|
||||
target_option_val!(pre_link_objects_fallback);
|
||||
target_option_val!(post_link_objects_fallback);
|
||||
target_option_val!(crt_objects_fallback);
|
||||
target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
|
||||
target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
|
||||
target_option_val!(link_self_contained, "crt-objects-fallback");
|
||||
target_option_val!(link_args - pre_link_args);
|
||||
target_option_val!(link_args - late_link_args);
|
||||
target_option_val!(link_args - late_link_args_dynamic);
|
||||
|
@ -110,9 +110,9 @@ impl Target {
|
||||
}
|
||||
|
||||
assert!(
|
||||
(self.pre_link_objects_fallback.is_empty()
|
||||
&& self.post_link_objects_fallback.is_empty())
|
||||
|| self.crt_objects_fallback.is_some()
|
||||
(self.pre_link_objects_self_contained.is_empty()
|
||||
&& self.post_link_objects_self_contained.is_empty())
|
||||
|| self.link_self_contained != LinkSelfContainedDefault::False
|
||||
);
|
||||
|
||||
// If your target really needs to deviate from the rules below,
|
||||
|
@ -82,8 +82,8 @@ pub fn target() -> Target {
|
||||
options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
|
||||
options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]);
|
||||
|
||||
options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback();
|
||||
options.post_link_objects_fallback = crt_objects::post_wasi_fallback();
|
||||
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
|
||||
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
|
||||
|
||||
// Right now this is a bit of a workaround but we're currently saying that
|
||||
// the target by default has a static crt which we're taking as a signal
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::crt_objects::CrtObjectsFallback;
|
||||
use super::crt_objects::LinkSelfContainedDefault;
|
||||
use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
|
||||
|
||||
pub fn options() -> TargetOptions {
|
||||
@ -96,7 +96,8 @@ pub fn options() -> TargetOptions {
|
||||
|
||||
pre_link_args,
|
||||
|
||||
crt_objects_fallback: Some(CrtObjectsFallback::Wasm),
|
||||
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
|
||||
link_self_contained: LinkSelfContainedDefault::True,
|
||||
|
||||
// This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
|
||||
// PIC code is implemented this has quite a drastic effect if it stays
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::spec::crt_objects::{self, CrtObjectsFallback};
|
||||
use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
|
||||
use crate::spec::{cvs, LinkerFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
@ -76,9 +76,9 @@ pub fn opts() -> TargetOptions {
|
||||
pre_link_args,
|
||||
pre_link_objects: crt_objects::pre_mingw(),
|
||||
post_link_objects: crt_objects::post_mingw(),
|
||||
pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
|
||||
post_link_objects_fallback: crt_objects::post_mingw_fallback(),
|
||||
crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
|
||||
pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(),
|
||||
post_link_objects_self_contained: crt_objects::post_mingw_self_contained(),
|
||||
link_self_contained: LinkSelfContainedDefault::Mingw,
|
||||
late_link_args,
|
||||
late_link_args_dynamic,
|
||||
late_link_args_static,
|
||||
|
@ -734,7 +734,21 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
// FIXME: Constants should participate in orphan checking.
|
||||
/// All possible values for a constant parameter already exist
|
||||
/// in the crate defining the trait, so they are always non-local[^1].
|
||||
///
|
||||
/// Because there's no way to have an impl where the first local
|
||||
/// generic argument is a constant, we also don't have to fail
|
||||
/// the orphan check when encountering a parameter or a generic constant.
|
||||
///
|
||||
/// This means that we can completely ignore constants during the orphan check.
|
||||
///
|
||||
/// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
|
||||
///
|
||||
/// [^1]: This might not hold for function pointers or trait objects in the future.
|
||||
/// As these should be quite rare as const arguments and especially rare as impl
|
||||
/// parameters, allowing uncovered const parameters in impls seems more useful
|
||||
/// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
|
||||
fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
@ -69,6 +69,9 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
|
||||
// to note that it's safe to call, since
|
||||
// safe extern fns are otherwise unprecedented.
|
||||
sym::abort
|
||||
| sym::assert_inhabited
|
||||
| sym::assert_zero_valid
|
||||
| sym::assert_uninit_valid
|
||||
| sym::size_of
|
||||
| sym::min_align_of
|
||||
| sym::needs_drop
|
||||
|
@ -292,6 +292,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
intravisit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
||||
match &p.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => {
|
||||
// Nothing to write back here
|
||||
}
|
||||
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => {
|
||||
self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
|
||||
self.visit_node_id(b.span, b.hir_id);
|
||||
intravisit::walk_block(self, b);
|
||||
|
182
library/core/src/iter/adapters/array_chunks.rs
Normal file
182
library/core/src/iter/adapters/array_chunks.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use crate::array;
|
||||
use crate::iter::{ByRefSized, FusedIterator, Iterator};
|
||||
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
|
||||
|
||||
/// An iterator over `N` elements of the iterator at a time.
|
||||
///
|
||||
/// The chunks do not overlap. If `N` does not divide the length of the
|
||||
/// iterator, then the last up to `N-1` elements will be omitted.
|
||||
///
|
||||
/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks]
|
||||
/// method on [`Iterator`]. See its documentation for more.
|
||||
#[derive(Debug, Clone)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
pub struct ArrayChunks<I: Iterator, const N: usize> {
|
||||
iter: I,
|
||||
remainder: Option<array::IntoIter<I::Item, N>>,
|
||||
}
|
||||
|
||||
impl<I, const N: usize> ArrayChunks<I, N>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
#[track_caller]
|
||||
pub(in crate::iter) fn new(iter: I) -> Self {
|
||||
assert!(N != 0, "chunk size must be non-zero");
|
||||
Self { iter, remainder: None }
|
||||
}
|
||||
|
||||
/// Returns an iterator over the remaining elements of the original iterator
|
||||
/// that are not going to be returned by this iterator. The returned
|
||||
/// iterator will yield at most `N-1` elements.
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
#[inline]
|
||||
pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
|
||||
self.remainder
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
impl<I, const N: usize> Iterator for ArrayChunks<I, N>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
type Item = [I::Item; N];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.try_for_each(ControlFlow::Break).break_value()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (lower, upper) = self.iter.size_hint();
|
||||
|
||||
(lower / N, upper.map(|n| n / N))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.iter.count() / N
|
||||
}
|
||||
|
||||
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
let mut acc = init;
|
||||
loop {
|
||||
match self.iter.next_chunk() {
|
||||
Ok(chunk) => acc = f(acc, chunk)?,
|
||||
Err(remainder) => {
|
||||
// Make sure to not override `self.remainder` with an empty array
|
||||
// when `next` is called after `ArrayChunks` exhaustion.
|
||||
self.remainder.get_or_insert(remainder);
|
||||
|
||||
break try { acc };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold<B, F>(mut self, init: B, f: F) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
|
||||
where
|
||||
I: DoubleEndedIterator + ExactSizeIterator,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
|
||||
}
|
||||
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
// We are iterating from the back we need to first handle the remainder.
|
||||
self.next_back_remainder();
|
||||
|
||||
let mut acc = init;
|
||||
let mut iter = ByRefSized(&mut self.iter).rev();
|
||||
|
||||
// NB remainder is handled by `next_back_remainder`, so
|
||||
// `next_chunk` can't return `Err` with non-empty remainder
|
||||
// (assuming correct `I as ExactSizeIterator` impl).
|
||||
while let Ok(mut chunk) = iter.next_chunk() {
|
||||
// FIXME: do not do double reverse
|
||||
// (we could instead add `next_chunk_back` for example)
|
||||
chunk.reverse();
|
||||
acc = f(acc, chunk)?
|
||||
}
|
||||
|
||||
try { acc }
|
||||
}
|
||||
|
||||
fn rfold<B, F>(mut self, init: B, f: F) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, const N: usize> ArrayChunks<I, N>
|
||||
where
|
||||
I: DoubleEndedIterator + ExactSizeIterator,
|
||||
{
|
||||
/// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
|
||||
fn next_back_remainder(&mut self) {
|
||||
// Make sure to not override `self.remainder` with an empty array
|
||||
// when `next_back` is called after `ArrayChunks` exhaustion.
|
||||
if self.remainder.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We use the `ExactSizeIterator` implementation of the underlying
|
||||
// iterator to know how many remaining elements there are.
|
||||
let rem = self.iter.len() % N;
|
||||
|
||||
// Take the last `rem` elements out of `self.iter`.
|
||||
let mut remainder =
|
||||
// SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
|
||||
unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
|
||||
|
||||
// We used `.rev()` above, so we need to re-reverse the reminder
|
||||
remainder.as_mut_slice().reverse();
|
||||
self.remainder = Some(remainder);
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
|
||||
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
|
||||
where
|
||||
I: ExactSizeIterator,
|
||||
{
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.iter.len() / N
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_empty(&self) -> bool {
|
||||
self.iter.len() < N
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use crate::iter::{InPlaceIterable, Iterator};
|
||||
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
|
||||
|
||||
mod array_chunks;
|
||||
mod by_ref_sized;
|
||||
mod chain;
|
||||
mod cloned;
|
||||
@ -32,6 +33,9 @@ pub use self::{
|
||||
scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
|
||||
};
|
||||
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
pub use self::array_chunks::ArrayChunks;
|
||||
|
||||
#[unstable(feature = "std_internals", issue = "none")]
|
||||
pub use self::by_ref_sized::ByRefSized;
|
||||
|
||||
|
@ -398,6 +398,8 @@ pub use self::traits::{
|
||||
|
||||
#[stable(feature = "iter_zip", since = "1.59.0")]
|
||||
pub use self::adapters::zip;
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
pub use self::adapters::ArrayChunks;
|
||||
#[unstable(feature = "std_internals", issue = "none")]
|
||||
pub use self::adapters::ByRefSized;
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
|
@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
|
||||
use super::super::try_process;
|
||||
use super::super::ByRefSized;
|
||||
use super::super::TrustedRandomAccessNoCoerce;
|
||||
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
|
||||
use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
|
||||
use super::super::{FlatMap, Flatten};
|
||||
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
|
||||
use super::super::{
|
||||
@ -3316,6 +3316,49 @@ pub trait Iterator {
|
||||
Cycle::new(self)
|
||||
}
|
||||
|
||||
/// Returns an iterator over `N` elements of the iterator at a time.
|
||||
///
|
||||
/// The chunks do not overlap. If `N` does not divide the length of the
|
||||
/// iterator, then the last up to `N-1` elements will be omitted and can be
|
||||
/// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder]
|
||||
/// function of the iterator.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `N` is 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_array_chunks)]
|
||||
///
|
||||
/// let mut iter = "lorem".chars().array_chunks();
|
||||
/// assert_eq!(iter.next(), Some(['l', 'o']));
|
||||
/// assert_eq!(iter.next(), Some(['r', 'e']));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_array_chunks)]
|
||||
///
|
||||
/// let data = [1, 1, 2, -2, 6, 0, 3, 1];
|
||||
/// // ^-----^ ^------^
|
||||
/// for [x, y, z] in data.iter().array_chunks() {
|
||||
/// assert_eq!(x + y + z, 4);
|
||||
/// }
|
||||
/// ```
|
||||
#[track_caller]
|
||||
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
|
||||
fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
ArrayChunks::new(self)
|
||||
}
|
||||
|
||||
/// Sums the elements of an iterator.
|
||||
///
|
||||
/// Takes each element, adds them together, and returns the result.
|
||||
|
179
library/core/tests/iter/adapters/array_chunks.rs
Normal file
179
library/core/tests/iter/adapters/array_chunks.rs
Normal file
@ -0,0 +1,179 @@
|
||||
use core::cell::Cell;
|
||||
use core::iter::{self, Iterator};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_infer() {
|
||||
let xs = [1, 1, 2, -2, 6, 0, 3, 1];
|
||||
for [a, b, c] in xs.iter().copied().array_chunks() {
|
||||
assert_eq!(a + b + c, 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_clone_and_drop() {
|
||||
let count = Cell::new(0);
|
||||
let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>();
|
||||
assert_eq!(it.by_ref().count(), 1);
|
||||
assert_eq!(count.get(), 3);
|
||||
let mut it2 = it.clone();
|
||||
assert_eq!(count.get(), 3);
|
||||
assert_eq!(it.into_remainder().unwrap().len(), 2);
|
||||
assert_eq!(count.get(), 5);
|
||||
assert!(it2.next().is_none());
|
||||
assert_eq!(it2.into_remainder().unwrap().len(), 2);
|
||||
assert_eq!(count.get(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_remainder() {
|
||||
let mut it = (0..11).array_chunks::<4>();
|
||||
assert_eq!(it.next(), Some([0, 1, 2, 3]));
|
||||
assert_eq!(it.next(), Some([4, 5, 6, 7]));
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_size_hint() {
|
||||
let it = (0..6).array_chunks::<1>();
|
||||
assert_eq!(it.size_hint(), (6, Some(6)));
|
||||
|
||||
let it = (0..6).array_chunks::<3>();
|
||||
assert_eq!(it.size_hint(), (2, Some(2)));
|
||||
|
||||
let it = (0..6).array_chunks::<5>();
|
||||
assert_eq!(it.size_hint(), (1, Some(1)));
|
||||
|
||||
let it = (0..6).array_chunks::<7>();
|
||||
assert_eq!(it.size_hint(), (0, Some(0)));
|
||||
|
||||
let it = (1..).array_chunks::<2>();
|
||||
assert_eq!(it.size_hint(), (usize::MAX / 2, None));
|
||||
|
||||
let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>();
|
||||
assert_eq!(it.size_hint(), (0, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_count() {
|
||||
let it = (0..6).array_chunks::<1>();
|
||||
assert_eq!(it.count(), 6);
|
||||
|
||||
let it = (0..6).array_chunks::<3>();
|
||||
assert_eq!(it.count(), 2);
|
||||
|
||||
let it = (0..6).array_chunks::<5>();
|
||||
assert_eq!(it.count(), 1);
|
||||
|
||||
let it = (0..6).array_chunks::<7>();
|
||||
assert_eq!(it.count(), 0);
|
||||
|
||||
let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>();
|
||||
assert_eq!(it.count(), 1);
|
||||
|
||||
let it = iter::empty::<i32>().array_chunks::<2>();
|
||||
assert_eq!(it.count(), 0);
|
||||
|
||||
let it = [(); usize::MAX].iter().array_chunks::<2>();
|
||||
assert_eq!(it.count(), usize::MAX / 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_next_and_next_back() {
|
||||
let mut it = (0..11).array_chunks::<3>();
|
||||
assert_eq!(it.next(), Some([0, 1, 2]));
|
||||
assert_eq!(it.next_back(), Some([6, 7, 8]));
|
||||
assert_eq!(it.next(), Some([3, 4, 5]));
|
||||
assert_eq!(it.next_back(), None);
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.next_back(), None);
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_rev_remainder() {
|
||||
let mut it = (0..11).array_chunks::<4>();
|
||||
{
|
||||
let mut it = it.by_ref().rev();
|
||||
assert_eq!(it.next(), Some([4, 5, 6, 7]));
|
||||
assert_eq!(it.next(), Some([0, 1, 2, 3]));
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_try_fold() {
|
||||
let count = Cell::new(0);
|
||||
let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
|
||||
let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1));
|
||||
assert_eq!(result, Ok(3));
|
||||
assert_eq!(count.get(), 9);
|
||||
drop(it);
|
||||
assert_eq!(count.get(), 10);
|
||||
|
||||
let count = Cell::new(0);
|
||||
let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
|
||||
let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) });
|
||||
assert_eq!(result, Err(2));
|
||||
assert_eq!(count.get(), 9);
|
||||
drop(it);
|
||||
assert_eq!(count.get(), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_fold() {
|
||||
let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| {
|
||||
assert_eq!(acc + 1, a);
|
||||
assert_eq!(acc + 2, b);
|
||||
assert_eq!(acc + 3, c);
|
||||
acc + 3
|
||||
});
|
||||
assert_eq!(result, 9);
|
||||
|
||||
let count = Cell::new(0);
|
||||
let result =
|
||||
(0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1);
|
||||
assert_eq!(result, 3);
|
||||
assert_eq!(count.get(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_try_rfold() {
|
||||
let count = Cell::new(0);
|
||||
let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
|
||||
let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1));
|
||||
assert_eq!(result, Ok(3));
|
||||
assert_eq!(count.get(), 9);
|
||||
drop(it);
|
||||
assert_eq!(count.get(), 10);
|
||||
|
||||
let count = Cell::new(0);
|
||||
let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
|
||||
let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) });
|
||||
assert_eq!(result, Err(2));
|
||||
assert_eq!(count.get(), 9);
|
||||
drop(it);
|
||||
assert_eq!(count.get(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_array_chunks_rfold() {
|
||||
let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| {
|
||||
assert_eq!(10 - (acc + 1), c);
|
||||
assert_eq!(10 - (acc + 2), b);
|
||||
assert_eq!(10 - (acc + 3), a);
|
||||
acc + 3
|
||||
});
|
||||
assert_eq!(result, 9);
|
||||
|
||||
let count = Cell::new(0);
|
||||
let result =
|
||||
(0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1);
|
||||
assert_eq!(result, 3);
|
||||
assert_eq!(count.get(), 10);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod array_chunks;
|
||||
mod chain;
|
||||
mod cloned;
|
||||
mod copied;
|
||||
@ -183,3 +184,25 @@ impl Clone for CountClone {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CountDrop<'a> {
|
||||
dropped: bool,
|
||||
count: &'a Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'a> CountDrop<'a> {
|
||||
pub fn new(count: &'a Cell<usize>) -> Self {
|
||||
Self { dropped: false, count }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CountDrop<'_> {
|
||||
fn drop(&mut self) {
|
||||
if self.dropped {
|
||||
panic!("double drop");
|
||||
}
|
||||
self.dropped = true;
|
||||
self.count.set(self.count.get() + 1);
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(int_log)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(iter_array_chunks)]
|
||||
#![feature(iter_collect_into)]
|
||||
#![feature(iter_partition_in_place)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
6
src/test/ui/closures/binder/disallow-const.rs
Normal file
6
src/test/ui/closures/binder/disallow-const.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
for<const N: i32> || -> () {};
|
||||
//~^ ERROR only lifetime parameters can be used in this context
|
||||
}
|
8
src/test/ui/closures/binder/disallow-const.stderr
Normal file
8
src/test/ui/closures/binder/disallow-const.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
--> $DIR/disallow-const.rs:4:15
|
||||
|
|
||||
LL | for<const N: i32> || -> () {};
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
6
src/test/ui/closures/binder/disallow-ty.rs
Normal file
6
src/test/ui/closures/binder/disallow-ty.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
for<T> || -> () {};
|
||||
//~^ ERROR only lifetime parameters can be used in this context
|
||||
}
|
8
src/test/ui/closures/binder/disallow-ty.stderr
Normal file
8
src/test/ui/closures/binder/disallow-ty.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
--> $DIR/disallow-ty.rs:4:9
|
||||
|
|
||||
LL | for<T> || -> () {};
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1 @@
|
||||
pub trait Trait<const N: usize, T> {}
|
28
src/test/ui/coherence/const-generics-orphan-check-ok.rs
Normal file
28
src/test/ui/coherence/const-generics-orphan-check-ok.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// check-pass
|
||||
// aux-build:trait-with-const-param.rs
|
||||
extern crate trait_with_const_param;
|
||||
use trait_with_const_param::*;
|
||||
|
||||
// Trivial case, const param after local type.
|
||||
struct Local1;
|
||||
impl<const N: usize, T> Trait<N, T> for Local1 {}
|
||||
|
||||
// Concrete consts behave the same as foreign types,
|
||||
// so this also trivially works.
|
||||
impl Trait<3, Local1> for i32 {}
|
||||
|
||||
// This case isn't as trivial as we would forbid type
|
||||
// parameters here, we do allow const parameters though.
|
||||
//
|
||||
// The reason that type parameters are forbidden for
|
||||
// `impl<T> Trait<T, LocalInA> for i32 {}` is that another
|
||||
// downstream crate can add `impl<T> Trait<LocalInB, T> for i32`.
|
||||
// As these two impls would overlap we forbid any impls which
|
||||
// have a type parameter in front of a local type.
|
||||
//
|
||||
// With const parameters this issue does not exist as there are no
|
||||
// constants local to another downstream crate.
|
||||
struct Local2;
|
||||
impl<const N: usize> Trait<N, Local2> for i32 {}
|
||||
|
||||
fn main() {}
|
@ -13,10 +13,10 @@ fn main() {
|
||||
const _BAD1: () = unsafe {
|
||||
MaybeUninit::<!>::uninit().assume_init();
|
||||
};
|
||||
const _BAD2: () = unsafe {
|
||||
const _BAD2: () = {
|
||||
intrinsics::assert_uninit_valid::<bool>();
|
||||
};
|
||||
const _BAD3: () = unsafe {
|
||||
const _BAD3: () = {
|
||||
intrinsics::assert_zero_valid::<&'static i32>();
|
||||
};
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ LL | MaybeUninit::<!>::uninit().assume_init();
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:17:9
|
||||
|
|
||||
LL | const _BAD2: () = unsafe {
|
||||
LL | const _BAD2: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
|
||||
@ -24,7 +24,7 @@ LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:20:9
|
||||
|
|
||||
LL | const _BAD3: () = unsafe {
|
||||
LL | const _BAD3: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_zero_valid::<&'static i32>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
|
||||
@ -51,7 +51,7 @@ Future breakage diagnostic:
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:17:9
|
||||
|
|
||||
LL | const _BAD2: () = unsafe {
|
||||
LL | const _BAD2: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
|
||||
@ -64,7 +64,7 @@ Future breakage diagnostic:
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:20:9
|
||||
|
|
||||
LL | const _BAD3: () = unsafe {
|
||||
LL | const _BAD3: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_zero_valid::<&'static i32>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
|
||||
|
@ -0,0 +1,8 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
const _FOO: i32 = 123;
|
||||
//~^ ERROR const` and `let` are mutually exclusive
|
||||
const _BAR: i32 = 123;
|
||||
//~^ ERROR `const` and `let` are mutually exclusive
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
const let _FOO: i32 = 123;
|
||||
//~^ ERROR const` and `let` are mutually exclusive
|
||||
let const _BAR: i32 = 123;
|
||||
//~^ ERROR `const` and `let` are mutually exclusive
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error: `const` and `let` are mutually exclusive
|
||||
--> $DIR/issue-99910-const-let-mutually-exclusive.rs:4:5
|
||||
|
|
||||
LL | const let _FOO: i32 = 123;
|
||||
| ^^^^^^^^^ help: remove `let`: `const`
|
||||
|
||||
error: `const` and `let` are mutually exclusive
|
||||
--> $DIR/issue-99910-const-let-mutually-exclusive.rs:6:5
|
||||
|
|
||||
LL | let const _BAR: i32 = 123;
|
||||
| ^^^^^^^^^ help: remove `let`: `const`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user