Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 12 pull requests #82010

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2b9ba46
fix indefinite article in cell.rs
petar-dambovaliev Dec 12, 2020
86a4b27
Increment `self.index` before calling `Iterator::self.a.__iterator_ge…
sdroege Feb 4, 2021
55ca27f
use rwlock for accessing ENV
the8472 Feb 6, 2021
406fd3a
silence dead code warnings on windows
the8472 Feb 7, 2021
c7d9bff
HWASan support
Jan 23, 2021
9c34c14
HWASan documentation
Feb 8, 2021
2200cf1
avoid &mut on the read path since it now allows concurrent readers
the8472 Feb 8, 2021
44abad5
introduce StaticRWLock wrapper to make methods safe
the8472 Feb 8, 2021
1d9ac3c
Fix const generics in GAT
BoxyUwU Feb 9, 2021
4fc181d
split guard into read and write types
the8472 Feb 9, 2021
471ed5f
Use ItemCtxt::to_ty
camsteffen Feb 10, 2021
883988b
RELEASES.md 1.50: Group platform support notes together
joshtriplett Feb 10, 2021
d3fea13
bootstrap: Locate llvm-dwp based on llvm-config bindir
dtolnay Feb 10, 2021
2c4337a
Comments :3
BoxyUwU Feb 10, 2021
0422745
Fix comment smol mistakes
BoxyUwU Feb 10, 2021
0ffa2da
comma...
BoxyUwU Feb 10, 2021
a6d4137
Fix assosiated typo
therealprof Feb 10, 2021
7ca96ed
rewrite the comments
BoxyUwU Feb 10, 2021
f13bbea
Catch errors on localStorage setting failure
lovasoa Feb 10, 2021
16f0ccd
Fix getCurrentValue
lovasoa Feb 10, 2021
5034b50
bootstrap: fix wrong docs installation path
pietroalbini Feb 10, 2021
bfd1ccf
Seal the CommandExt, OsStrExt and OsStringExt traits
Amanieu Feb 10, 2021
02ab235
Rollup merge of #79983 - petar-dambovaliev:master, r=Dylan-DPC
Dylan-DPC Feb 11, 2021
9fad47a
Rollup merge of #81506 - vo4:hwasan, r=nagisa
Dylan-DPC Feb 11, 2021
94d1441
Rollup merge of #81741 - sdroege:zip-trusted-random-access-specializa…
Dylan-DPC Feb 11, 2021
9947da8
Rollup merge of #81850 - the8472:env-rwlock, r=m-ou-se
Dylan-DPC Feb 11, 2021
ebe4041
Rollup merge of #81911 - BoxyUwU:constgenericgaticefix, r=nikomatsakis
Dylan-DPC Feb 11, 2021
dd73aab
Rollup merge of #81947 - camsteffen:to-ty, r=jyn514
Dylan-DPC Feb 11, 2021
3a0fb95
Rollup merge of #81954 - joshtriplett:release-notes-group-platform-no…
Dylan-DPC Feb 11, 2021
daccdb3
Rollup merge of #81955 - dtolnay:dwp, r=Mark-Simulacrum
Dylan-DPC Feb 11, 2021
9e4c98d
Rollup merge of #81959 - therealprof:fix-typo, r=oli-obk
Dylan-DPC Feb 11, 2021
0db0a0a
Rollup merge of #81964 - lovasoa:patch-1, r=GuillaumeGomez
Dylan-DPC Feb 11, 2021
67cc5e4
Rollup merge of #81968 - pietroalbini:fix-doc-install-path, r=Mark-Si…
Dylan-DPC Feb 11, 2021
12c5065
Rollup merge of #81975 - Amanieu:seal2, r=m-ou-se
Dylan-DPC Feb 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Compiler
- [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142]
- [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484]
- [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484]
- [Dropped support for all cloudabi targets.][78439]

\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.
Expand Down Expand Up @@ -77,7 +78,6 @@ Compatibility Notes
- [`#![test]` as an inner attribute is now considered unstable like other inner macro
attributes, and reports an error by default through the `soft_unstable` lint.][79003]
- [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864]
- [Dropped support for all cloudabi targets.][78439]
- [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's
recommended to use the `#[panic_handler]` attribute to provide your own implementation.
- [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296]
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
if enabled.contains(SanitizerSet::THREAD) {
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
}
if enabled.contains(SanitizerSet::HWADDRESS) {
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
}
}

/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
})
} else {
None
Expand Down Expand Up @@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
if config.sanitizer.contains(SanitizerSet::THREAD) {
passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
}
if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
}
}

pub(crate) fn link(
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pub enum Attribute {
ReturnsTwice = 25,
ReadNone = 26,
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
}

/// LLVMIntPredicate
Expand Down Expand Up @@ -439,6 +440,8 @@ pub struct SanitizerOptions {
pub sanitize_memory_recover: bool,
pub sanitize_memory_track_origins: c_int,
pub sanitize_thread: bool,
pub sanitize_hwaddress: bool,
pub sanitize_hwaddress_recover: bool,
}

/// LLVMRelocMode
Expand Down Expand Up @@ -2128,6 +2131,7 @@ extern "C" {
Recover: bool,
) -> &'static mut Pass;
pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
pub fn LLVMRustAddLastExtensionPasses(
PMB: &PassManagerBuilder,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
if sanitizer.contains(SanitizerSet::THREAD) {
link_sanitizer_runtime(sess, linker, "tsan");
}
if sanitizer.contains(SanitizerSet::HWADDRESS) {
link_sanitizer_runtime(sess, linker, "hwasan");
}
}

fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ enum LLVMRustAttribute {
ReturnsTwice = 25,
ReadNone = 26,
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
};

typedef struct OpaqueRustString *RustStringRef;
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
#include "llvm/Transforms/Utils/NameAnonGlobals.h"

Expand Down Expand Up @@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
return wrap(createThreadSanitizerLegacyPassPass());
}

extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
const bool CompileKernel = false;

return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
}

extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
assert(RustPass);
Pass *Pass = unwrap(RustPass);
Expand Down Expand Up @@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
bool SanitizeMemoryRecover;
int SanitizeMemoryTrackOrigins;
bool SanitizeThread;
bool SanitizeHWAddress;
bool SanitizeHWAddressRecover;
};

extern "C" void
Expand Down Expand Up @@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
}
);
#endif
}
if (SanitizerOptions->SanitizeHWAddress) {
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
MPM.addPass(HWAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
}
);
#else
PipelineStartEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM) {
MPM.addPass(HWAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
}
);
#endif
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::ReadNone;
case InaccessibleMemOnly:
return Attribute::InaccessibleMemOnly;
case SanitizeHWAddress:
return Attribute::SanitizeHWAddress;
}
report_fatal_error("bad AttributeKind");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
}

// Attempt to search similar mutable assosiated items for suggestion.
// Attempt to search similar mutable associated items for suggestion.
// In the future, attempt in all path but initially for RHS of for_loop
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
let hir = self.infcx.tcx.hir();
Expand Down
20 changes: 14 additions & 6 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ bitflags! {
const LEAK = 1 << 1;
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
}
}

Expand All @@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet {
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
_ => panic!("unrecognized sanitizer {:?}", s),
};
if !first {
Expand All @@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet {
type IntoIter = std::vec::IntoIter<SanitizerSet>;

fn into_iter(self) -> Self::IntoIter {
[SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
.iter()
.copied()
.filter(|&s| self.contains(s))
.collect::<Vec<_>>()
.into_iter()
[
SanitizerSet::ADDRESS,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::THREAD,
SanitizerSet::HWADDRESS,
]
.iter()
.copied()
.filter(|&s| self.contains(s))
.collect::<Vec<_>>()
.into_iter()
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ macro_rules! options {
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
Expand Down Expand Up @@ -476,6 +476,7 @@ macro_rules! options {
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return false,
}
}
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,8 @@ impl Session {
self.opts.optimize != config::OptLevel::No
// AddressSanitizer uses lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
}

pub fn link_dead_code(&self) -> bool {
Expand Down Expand Up @@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
"x86_64-unknown-freebsd",
"x86_64-unknown-linux-gnu",
];
const HWASAN_SUPPORTED_TARGETS: &[&str] =
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

// Sanitizers can only be used on some tested platforms.
for s in sess.opts.debugging_opts.sanitizer {
Expand All @@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
_ => panic!("unrecognized sanitizer {}", s),
};
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ symbols! {
html_no_source,
html_playground_url,
html_root_url,
hwaddress,
i,
i128,
i128_type,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl ItemCtxt<'tcx> {
ItemCtxt { tcx, item_def_id }
}

pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
AstConv::ast_ty_to_ty(self, ast_ty)
}

Expand Down Expand Up @@ -2709,10 +2709,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::thread) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else if item.has_name(sym::hwaddress) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
.note("expected one of: `address`, `memory` or `thread`")
.note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
.emit();
}
}
Expand Down
67 changes: 67 additions & 0 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,73 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
let parent_node = tcx.hir().get(parent_node_id);

match parent_node {
// This match arm is for when the def_id appears in a GAT whose
// path can't be resolved without typechecking e.g.
//
// trait Foo {
// type Assoc<const N: usize>;
// fn foo() -> Self::Assoc<3>;
// }
//
// In the above code we would call this query with the def_id of 3 and
// the parent_node we match on would be the hir node for Self::Assoc<3>
//
// `Self::Assoc<3>` cant be resolved without typchecking here as we
// didnt write <Self as Foo>::Assoc<3>. If we did then another match
// arm would handle this.
//
// I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
// Find the Item containing the associated type so we can create an ItemCtxt.
// Using the ItemCtxt convert the HIR for the unresolved assoc type into a
// ty which is a fully resolved projection.
// For the code example above, this would mean converting Self::Assoc<3>
// into a ty::Projection(<Self as Foo>::Assoc<3>)
let item_hir_id = tcx
.hir()
.parent_iter(hir_id)
.filter(|(_, node)| matches!(node, Node::Item(_)))
.map(|(id, _)| id)
.next()
.unwrap();
let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
let ty = item_ctxt.ast_ty_to_ty(hir_ty);

// Iterate through the generics of the projection to find the one that corresponds to
// the def_id that this query was called with. We filter to only const args here as a
// precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
// but it can't hurt to be safe ^^
if let ty::Projection(projection) = ty.kind() {
let generics = tcx.generics_of(projection.item_def_id);

let arg_index = segment
.args
.and_then(|args| {
args.args
.iter()
.filter(|arg| arg.is_const())
.position(|arg| arg.id() == hir_id)
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in segment");
});

return generics
.params
.iter()
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
.nth(arg_index)
.map(|param| param.def_id);
}

// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
"unexpected non-GAT usage of an anon const",
);
return None;
}
Node::Expr(&Expr {
kind:
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ This API is completely unstable and subject to change.
*/

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
Expand Down Expand Up @@ -421,8 +422,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
let env_def_id = tcx.hir().local_def_id(env_node_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());

astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
item_cx.to_ty(hir_ty)
}

pub fn hir_trait_to_predicates<'tcx>(
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the
/// wrapped type. Types with an `UnsafeCell<T>` field are considered to have an 'unsafe interior'.
/// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered
/// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior.
/// mutable. In general, transmuting a `&T` type into a `&mut T` is considered undefined behavior.
///
/// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are
/// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably
Expand Down
7 changes: 4 additions & 3 deletions library/core/src/iter/adapters/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,13 @@ where
Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
}
} else if A::may_have_side_effect() && self.index < self.a.size() {
let i = self.index;
self.index += 1;
// match the base implementation's potential side effects
// SAFETY: we just checked that `self.index` < `self.a.len()`
// SAFETY: we just checked that `i` < `self.a.len()`
unsafe {
self.a.__iterator_get_unchecked(self.index);
self.a.__iterator_get_unchecked(i);
}
self.index += 1;
None
} else {
None
Expand Down
Loading