Skip to content

Rollup of 11 pull requests #82036

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

Closed
wants to merge 34 commits into from
Closed
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
86a4b27
Increment `self.index` before calling `Iterator::self.a.__iterator_ge…
sdroege Feb 4, 2021
f82315a
Don't release Miri if its tests only failed on Windows
Feb 2, 2021
f87afe5
Extend the comment of `check_toolstate()` to clarify that the tool wo…
Feb 6, 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
2c4337a
Comments :3
BoxyUwU Feb 10, 2021
0422745
Fix comment smol mistakes
BoxyUwU Feb 10, 2021
0ffa2da
comma...
BoxyUwU Feb 10, 2021
d64b749
Allow casting mut array ref to mut ptr
osa1 Jan 28, 2021
7ca96ed
rewrite the comments
BoxyUwU Feb 10, 2021
01f5a2a
Ensures `make` tests run under /bin/dash, like CI, and fixes a Makefile
richkadel Feb 4, 2021
625803d
Set SHELL = /bin/dash only if it exists
richkadel Feb 6, 2021
b211acf
Re-blessed the partial_eq.rs coverage test
richkadel Feb 11, 2021
02ffe9e
Fix injected errors when running doctests on a crate named after a ke…
jyn514 Dec 6, 2020
fda71d6
Push a `char` instead of a `str` with len one into a String
LingMan Feb 12, 2021
f546633
Remove unnecessary lint allow attrs on example
MikailBag Feb 12, 2021
fde59a8
Use `Iterator::all` instead of open-coding it
LingMan Feb 12, 2021
c2ac7cf
Rollup merge of #79775 - jyn514:doctest, r=GuillaumeGomez
Dylan-DPC Feb 12, 2021
7946b80
Rollup merge of #81479 - osa1:issue24151, r=lcnr
Dylan-DPC Feb 12, 2021
a1b0549
Rollup merge of #81506 - vo4:hwasan, r=nagisa
Dylan-DPC Feb 12, 2021
abafbf3
Rollup merge of #81666 - hyd-dev:miri-windows-test-fail, r=Mark-Simul…
Dylan-DPC Feb 12, 2021
b92d132
Rollup merge of #81734 - richkadel:fixfordash, r=pnkfelix
Dylan-DPC Feb 12, 2021
a79a1da
Rollup merge of #81741 - sdroege:zip-trusted-random-access-specializa…
Dylan-DPC Feb 12, 2021
8683bff
Rollup merge of #81850 - the8472:env-rwlock, r=m-ou-se
Dylan-DPC Feb 12, 2021
172adb4
Rollup merge of #81911 - BoxyUwU:constgenericgaticefix, r=nikomatsakis
Dylan-DPC Feb 12, 2021
a88ae80
Rollup merge of #82022 - LingMan:single_char, r=jonas-schievink
Dylan-DPC Feb 12, 2021
3db4afd
Rollup merge of #82023 - MikailBag:boxed-docs-unallow, r=jyn514
Dylan-DPC Feb 12, 2021
3c50257
Rollup merge of #82030 - LingMan:init_directly, r=varkor
Dylan-DPC Feb 12, 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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -349,6 +349,7 @@ jobs:
env:
SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json"
DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
os: windows-latest-xl
- name: i686-mingw-1
env:
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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(
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -131,6 +131,7 @@ pub enum Attribute {
ReturnsTwice = 25,
ReadNone = 26,
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
}

/// LLVMIntPredicate
@@ -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
@@ -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,
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -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) {
1 change: 1 addition & 0 deletions compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
Original file line number Diff line number Diff line change
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
ReturnsTwice = 25,
ReadNone = 26,
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
};

typedef struct OpaqueRustString *RustStringRef;
26 changes: 26 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
@@ -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"

@@ -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);
@@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
bool SanitizeMemoryRecover;
int SanitizeMemoryTrackOrigins;
bool SanitizeThread;
bool SanitizeHWAddress;
bool SanitizeHWAddressRecover;
};

extern "C" void
@@ -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
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
@@ -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");
}
39 changes: 24 additions & 15 deletions compiler/rustc_mir/src/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -2191,19 +2191,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
CastKind::Pointer(PointerCast::ArrayToPointer) => {
let ty_from = op.ty(body, tcx);

let opt_ty_elem = match ty_from.kind() {
ty::RawPtr(ty::TypeAndMut {
mutbl: hir::Mutability::Not,
ty: array_ty,
}) => match array_ty.kind() {
ty::Array(ty_elem, _) => Some(ty_elem),
_ => None,
},
let opt_ty_elem_mut = match ty_from.kind() {
ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
match array_ty.kind() {
ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
_ => None,
}
}
_ => None,
};

let ty_elem = match opt_ty_elem {
Some(ty_elem) => ty_elem,
let (ty_elem, ty_mut) = match opt_ty_elem_mut {
Some(ty_elem_mut) => ty_elem_mut,
None => {
span_mirbug!(
self,
@@ -2215,11 +2214,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};

let ty_to = match ty.kind() {
ty::RawPtr(ty::TypeAndMut {
mutbl: hir::Mutability::Not,
ty: ty_to,
}) => ty_to,
let (ty_to, ty_to_mut) = match ty.kind() {
ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
(ty_to, *ty_to_mut)
}
_ => {
span_mirbug!(
self,
@@ -2231,6 +2229,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};

if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not {
span_mirbug!(
self,
rvalue,
"ArrayToPointer cast from const {:?} to mut {:?}",
ty,
ty_to
);
return;
}

if let Err(terr) = self.sub_types(
ty_elem,
ty_to,
20 changes: 14 additions & 6 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ bitflags! {
const LEAK = 1 << 1;
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
}
}

@@ -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 {
@@ -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()
}
}

3 changes: 2 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
@@ -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`";
@@ -476,6 +476,7 @@ macro_rules! options {
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return false,
}
}
6 changes: 5 additions & 1 deletion compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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 {
@@ -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()) {
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -593,6 +593,7 @@ symbols! {
html_no_source,
html_playground_url,
html_root_url,
hwaddress,
i,
i128,
i128_type,
5 changes: 2 additions & 3 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
@@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
m_expr: ty::TypeAndMut<'tcx>,
m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError> {
// array-ptr-cast.

if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not {
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
if let ty::Array(ety, _) = m_expr.ty.kind() {
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
12 changes: 3 additions & 9 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
@@ -1211,7 +1211,7 @@ fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
ProjectionKind::Subslice => String::from("Subslice"),
};
if i != 0 {
projections_str.push_str(",");
projections_str.push(',');
}
projections_str.push_str(proj.as_str());
}
@@ -1382,14 +1382,8 @@ fn determine_place_ancestry_relation(
// Assume of length of projections_b = m
let projections_b = &place_b.projections;

let mut same_initial_projections = true;

for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) {
if proj_a != proj_b {
same_initial_projections = false;
break;
}
}
let same_initial_projections =
projections_a.iter().zip(projections_b.iter()).all(|(proj_a, proj_b)| proj_a == proj_b);

if same_initial_projections {
// First min(n, m) projections are the same
4 changes: 3 additions & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
67 changes: 67 additions & 0 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
@@ -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)),
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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)]
2 changes: 0 additions & 2 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
@@ -99,13 +99,11 @@
//! pub struct Foo;
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_new() -> Box<Foo> {
//! Box::new(Foo)
//! }
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
//! ```
//!
7 changes: 4 additions & 3 deletions library/core/src/iter/adapters/zip.rs
Original file line number Diff line number Diff line change
@@ -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
19 changes: 10 additions & 9 deletions library/std/src/sys/unix/os.rs
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ use crate::str;
use crate::sys::cvt;
use crate::sys::fd;
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock};
use crate::vec;

use libc::{c_char, c_int, c_void};
@@ -490,20 +491,20 @@ pub unsafe fn environ() -> *mut *const *const c_char {
extern "C" {
static mut environ: *const *const c_char;
}
&mut environ
ptr::addr_of_mut!(environ)
}

pub unsafe fn env_lock() -> StaticMutexGuard {
// It is UB to attempt to acquire this mutex reentrantly!
static ENV_LOCK: StaticMutex = StaticMutex::new();
ENV_LOCK.lock()
static ENV_LOCK: StaticRWLock = StaticRWLock::new();

pub fn env_read_lock() -> RWLockReadGuard {
ENV_LOCK.read_with_guard()
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
unsafe {
let _guard = env_lock();
let _guard = env_read_lock();
let mut environ = *environ();
let mut result = Vec::new();
if !environ.is_null() {
@@ -540,7 +541,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
let _guard = env_lock();
let _guard = env_read_lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
@@ -556,7 +557,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let v = CString::new(v.as_bytes())?;

unsafe {
let _guard = env_lock();
let _guard = ENV_LOCK.write_with_guard();
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
}
}
@@ -565,7 +566,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?;

unsafe {
let _guard = env_lock();
let _guard = ENV_LOCK.write_with_guard();
cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
}
}
6 changes: 3 additions & 3 deletions library/std/src/sys/unix/process/process_unix.rs
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ impl Command {
// a lock any more because the parent won't do anything and the child is
// in its own process.
let result = unsafe {
let _env_lock = sys::os::env_lock();
let _env_lock = sys::os::env_read_lock();
cvt(libc::fork())?
};

@@ -124,7 +124,7 @@ impl Command {
// Similar to when forking, we want to ensure that access to
// the environment is synchronized, so make sure to grab the
// environment lock before we try to exec.
let _lock = sys::os::env_lock();
let _lock = sys::os::env_read_lock();

let Err(e) = self.do_exec(theirs, envp.as_ref());
e
@@ -404,7 +404,7 @@ impl Command {
cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;

// Make sure we synchronize access to the global `environ` resource
let _env_lock = sys::os::env_lock();
let _env_lock = sys::os::env_read_lock();
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
cvt_nz(libc::posix_spawnp(
&mut p.pid,
59 changes: 59 additions & 0 deletions library/std/src/sys_common/rwlock.rs
Original file line number Diff line number Diff line change
@@ -86,3 +86,62 @@ impl RWLock {
self.0.destroy()
}
}

// the cfg annotations only exist due to dead code warnings. the code itself is portable
#[cfg(unix)]
pub struct StaticRWLock(RWLock);

#[cfg(unix)]
impl StaticRWLock {
pub const fn new() -> StaticRWLock {
StaticRWLock(RWLock::new())
}

/// Acquires shared access to the underlying lock, blocking the current
/// thread to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn read_with_guard(&'static self) -> RWLockReadGuard {
// Safety: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.read();
}
RWLockReadGuard(&self.0)
}

/// Acquires write access to the underlying lock, blocking the current thread
/// to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
// Safety: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.write();
}
RWLockWriteGuard(&self.0)
}
}

#[cfg(unix)]
pub struct RWLockReadGuard(&'static RWLock);

#[cfg(unix)]
impl Drop for RWLockReadGuard {
fn drop(&mut self) {
unsafe { self.0.read_unlock() }
}
}

#[cfg(unix)]
pub struct RWLockWriteGuard(&'static RWLock);

#[cfg(unix)]
impl Drop for RWLockWriteGuard {
fn drop(&mut self) {
unsafe { self.0.write_unlock() }
}
}
2 changes: 1 addition & 1 deletion src/bootstrap/configure.py
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ def v(*args):
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
o("profiler", "build.profiler", "build the profiler runtime")
2 changes: 1 addition & 1 deletion src/bootstrap/native.rs
Original file line number Diff line number Diff line change
@@ -804,7 +804,7 @@ fn supported_sanitizers(
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
"aarch64-unknown-linux-gnu" => {
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
}
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
1 change: 1 addition & 0 deletions src/ci/github-actions/ci.yml
Original file line number Diff line number Diff line change
@@ -531,6 +531,7 @@ jobs:
env:
SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
<<: *job-windows-xl

# 32/64-bit MinGW builds.
89 changes: 87 additions & 2 deletions src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
@@ -7,12 +7,15 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
This feature allows for use of one of following sanitizers:

* [AddressSanitizer][clang-asan] a fast memory error detector.
* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
AddressSanitizer, but based on partial hardware assistance.
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
* [ThreadSanitizer][clang-tsan] a fast data race detector.

To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
`-Zsanitizer=memory` or `-Zsanitizer=thread`.
To enable a sanitizer compile with `-Zsanitizer=address`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
`-Zsanitizer=thread`.

# AddressSanitizer

@@ -174,6 +177,86 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
==39249==ABORTING
```
# HWAddressSanitizer
HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
less memory.
HWAddressSanitizer is supported on the following targets:
* `aarch64-linux-android`
* `aarch64-unknown-linux-gnu`
HWAddressSanitizer requires `tagged-globals` target feature to instrument
globals. To enable this target feature compile with `-C
target-feature=+tagged-globals`
## Example
Heap buffer overflow:
```rust
fn main() {
let xs = vec![0, 1, 2, 3];
let _y = unsafe { *xs.as_ptr().offset(4) };
}
```
```shell
$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
aarch64-unknown-linux-gnu
```
```shell
$ ./main
==241==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdeffff0050 at pc 0xaaaae0ae4a98
READ of size 4 at 0xefdeffff0050 tags: 2c/00 (ptr/mem) in thread T0
#0 0xaaaae0ae4a94 (/.../main+0x54a94)
...

[0xefdeffff0040,0xefdeffff0060) is a small allocated heap chunk; size: 32 offset: 16
0xefdeffff0050 is located 0 bytes to the right of 16-byte region [0xefdeffff0040,0xefdeffff0050)
allocated here:
#0 0xaaaae0acb80c (/.../main+0x3b80c)
...

Thread: T0 0xeffe00002000 stack: [0xffffc28ad000,0xffffc30ad000) sz: 8388608 tls: [0xffffaa10a020,0xffffaa10a7d0)
Memory tags around the buggy address (one tag corresponds to 16 bytes):
0xfefcefffef80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffef90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffefa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffefb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffefc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffefd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffefe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefcefffeff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xfefceffff000: d7 d7 05 00 2c [00] 00 00 00 00 00 00 00 00 00 00
0xfefceffff010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfefceffff080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
0xfefcefffeff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
=>0xfefceffff000: .. .. 8c .. .. [..] .. .. .. .. .. .. .. .. .. ..
0xfefceffff010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags
Registers where the failure occurred (pc 0xaaaae0ae4a98):
x0 2c00efdeffff0050 x1 0000000000000004 x2 0000000000000004 x3 0000000000000000
x4 0000fffefc30ac37 x5 000000000000005d x6 00000ffffc30ac37 x7 0000efff00000000
x8 2c00efdeffff0050 x9 0200efff00000000 x10 0000000000000000 x11 0200efff00000000
x12 0200effe00000310 x13 0200effe00000310 x14 0000000000000008 x15 5d00ffffc30ac360
x16 0000aaaae0ad062c x17 0000000000000003 x18 0000000000000001 x19 0000ffffc30ac658
x20 4e00ffffc30ac6e0 x21 0000aaaae0ac5e10 x22 0000000000000000 x23 0000000000000000
x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000
x28 0000000000000000 x29 0000ffffc30ac5a0 x30 0000aaaae0ae4a98
SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)
```
# LeakSanitizer
LeakSanitizer is run-time memory leak detector.
@@ -321,11 +404,13 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
* [AddressSanitizer in Clang][clang-asan]
* [HWAddressSanitizer in Clang][clang-hwasan]
* [LeakSanitizer in Clang][clang-lsan]
* [MemorySanitizer in Clang][clang-msan]
* [ThreadSanitizer in Clang][clang-tsan]
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
7 changes: 5 additions & 2 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
@@ -546,9 +546,12 @@ crate fn make_test(
// compiler.
if !already_has_extern_crate && !opts.no_crate_inject && cratename != Some("std") {
if let Some(cratename) = cratename {
// Make sure its actually used if not included.
// Don't inject `extern crate` if the crate is never used.
// NOTE: this is terribly inaccurate because it doesn't actually
// parse the source, but only has false positives, not false
// negatives.
if s.contains(cratename) {
prog.push_str(&format!("extern crate {};\n", cratename));
prog.push_str(&format!("extern crate r#{};\n", cratename));
line_offset += 1;
}
}
8 changes: 4 additions & 4 deletions src/librustdoc/doctest/tests.rs
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ fn make_test_crate_name() {
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
extern crate asdf;
extern crate r#asdf;
fn main() {
use asdf::qwop;
assert_eq!(2+2, 4);
@@ -128,7 +128,7 @@ fn make_test_opts_attrs() {
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![feature(sick_rad)]
extern crate asdf;
extern crate r#asdf;
fn main() {
use asdf::qwop;
assert_eq!(2+2, 4);
@@ -141,7 +141,7 @@ assert_eq!(2+2, 4);
opts.attrs.push("feature(hella_dope)".to_string());
let expected = "#![feature(sick_rad)]
#![feature(hella_dope)]
extern crate asdf;
extern crate r#asdf;
fn main() {
use asdf::qwop;
assert_eq!(2+2, 4);
@@ -250,7 +250,7 @@ assert_eq!(asdf::foo, 4);";

let expected = "#![allow(unused)]
extern crate hella_qwop;
extern crate asdf;
extern crate r#asdf;
fn main() {
assert_eq!(asdf::foo, 4);
}"
3 changes: 1 addition & 2 deletions src/test/run-make-fulldeps/coverage-reports/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# ignore-test Broken; accidentally silently ignored on Linux CI; FIXME(#81688)
# needs-profiler-support
# ignore-windows-gnu
# min-llvm-version: 11.0
@@ -128,7 +127,7 @@ endif
$$( \
for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
do \
[[ -x $$file ]] && printf "%s %s " -object $$file; \
[ -x "$$file" ] && printf "%s %s " -object $$file; \
done \
) \
2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
Original file line number Diff line number Diff line change
@@ -2,11 +2,11 @@
2| |// structure of this test.
3| |
4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
^0 ^0 ^0 ^0 ^1 ^0 ^0^0
^0 ^0 ^0 ^0 ^1 ^1 ^0^0
5| |pub struct Version {
6| | major: usize,
7| 1| minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0
8| 0| patch: usize, // Count: 0 - `PartialOrd` was determined by `minor` (2 < 3)
7| | minor: usize,
8| | patch: usize,
9| |}
10| |
11| |impl Version {
@@ -45,19 +45,4 @@
44| |`function_source_hash` without a code region, if necessary.
45| |
46| |*/
47| |
48| |// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear
49| |// to get two coverage execution counts at different positions:
50| |//
51| |// ```text
52| |// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
53| |// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0
54| |// ```text
55| |//
56| |// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2
57| |// characters) have counts at their first and last characters.
58| |//
59| |// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking
60| |// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them?
61| |// If merged, do we lose some information?

2 changes: 0 additions & 2 deletions src/test/run-make-fulldeps/coverage/coverage_tools.mk
Original file line number Diff line number Diff line change
@@ -12,5 +12,3 @@
# Enabling `-C link-dead-code` is not necessary when compiling with `-Z instrument-coverage`,
# due to improvements in the coverage map generation, to add unreachable functions known to Rust.
# Therefore, `-C link-dead-code` is no longer automatically enabled.

UNAME = $(shell uname)
19 changes: 2 additions & 17 deletions src/test/run-make-fulldeps/coverage/partial_eq.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
major: usize,
minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0
patch: usize, // Count: 0 - `PartialOrd` was determined by `minor` (2 < 3)
minor: usize,
patch: usize,
}

impl Version {
@@ -44,18 +44,3 @@ one expression, which is allowed, but the `function_source_hash` was only passed
`function_source_hash` without a code region, if necessary.
*/

// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear
// to get two coverage execution counts at different positions:
//
// ```text
// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0
// ```text
//
// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2
// characters) have counts at their first and last characters.
//
// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking
// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them?
// If merged, do we lose some information?
13 changes: 13 additions & 0 deletions src/test/run-make-fulldeps/tools.mk
Original file line number Diff line number Diff line change
@@ -21,6 +21,19 @@ CGREP := "$(S)/src/etc/cat-and-grep.sh"
# diff with common flags for multi-platform diffs against text output
DIFF := diff -u --strip-trailing-cr

# Some of the Rust CI platforms use `/bin/dash` to run `shell` script in
# Makefiles. Other platforms, including many developer platforms, default to
# `/bin/bash`. (In many cases, `make` is actually using `/bin/sh`, but `sh`
# is configured to execute one or the other shell binary). `dash` features
# support only a small subset of `bash` features, so `dash` can be thought of as
# the lowest common denominator, and tests should be validated against `dash`
# whenever possible. Most developer platforms include `/bin/dash`, but to ensure
# tests still work when `/bin/dash`, if not available, this `SHELL` override is
# conditional:
ifneq (,$(wildcard /bin/dash))
SHELL := /bin/dash
endif

# This is the name of the binary we will generate and run; use this
# e.g. for `$(CC) -o $(RUN_BINFILE)`.
RUN_BINFILE = $(TMPDIR)/$(1)
2 changes: 1 addition & 1 deletion src/test/rustdoc/playground-arg.rs
Original file line number Diff line number Diff line change
@@ -11,4 +11,4 @@
pub fn dummy() {}

// ensure that `extern crate foo;` was inserted into code snips automatically:
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
14 changes: 12 additions & 2 deletions src/test/ui/array-slice-vec/vector-cast-weirdness.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Issue #14893. Tests that casts from vectors don't behave strangely in the
// presence of the `_` type shorthand notation.
//
// Update: after a change to the way casts are done, we have more type information
// around and so the errors here are no longer exactly the same.
//
// Update: With PR #81479 some of the previously rejected cases are now allowed.
// New test cases added.

struct X {
y: [u8; 2],
@@ -12,13 +16,19 @@ fn main() {

// No longer a type mismatch - the `_` can be fully resolved by type inference.
let p1: *const u8 = &x1.y as *const _;
let p1: *mut u8 = &x1.y as *mut _;
//~^ ERROR: casting `&[u8; 2]` as `*mut u8` is invalid
let t1: *const [u8; 2] = &x1.y as *const _;
let t1: *mut [u8; 2] = &x1.y as *mut _;
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid

let mut x1 = X { y: [0, 0] };

// This is still an error since we don't allow casts from &mut [T; n] to *mut T.
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR casting
let p1: *mut u8 = &mut x1.y as *mut _;
let p2: *const u8 = &mut x1.y as *const _;
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
}
22 changes: 17 additions & 5 deletions src/test/ui/array-slice-vec/vector-cast-weirdness.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid
--> $DIR/vector-cast-weirdness.rs:21:23
error[E0606]: casting `&[u8; 2]` as `*mut u8` is invalid
--> $DIR/vector-cast-weirdness.rs:19:23
|
LL | let p1: *mut u8 = &mut x1.y as *mut _;
| ^^^^^^^^^^^^^^^^^^^
LL | let p1: *mut u8 = &x1.y as *mut _;
| ^^^^^^^^^^^^^^^

error: aborting due to previous error
error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
--> $DIR/vector-cast-weirdness.rs:22:28
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut _;
| ^^^^^^^^^^^^^^^

error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
--> $DIR/vector-cast-weirdness.rs:25:28
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0606`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-pass
#![feature(generic_associated_types)]
#![allow(incomplete_features)]

// This test unsures that with_opt_const_param returns the
// def_id of the N param in the Foo::Assoc GAT.

trait Foo {
type Assoc<const N: usize>;
fn foo(&self) -> Self::Assoc<3>;
}

impl Foo for () {
type Assoc<const N: usize> = [(); N];
fn foo(&self) -> Self::Assoc<3> {
[(); 3]
}
}

fn main() {
assert_eq!(().foo(), [(); 3]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-pass
#![feature(generic_associated_types)]
#![allow(incomplete_features)]

// This test unsures that with_opt_const_param returns the
// def_id of the N param in the Foo::Assoc GAT.

trait Foo {
type Assoc<const N: usize>;
fn foo<const N: usize>(&self) -> Self::Assoc<N>;
}

impl Foo for () {
type Assoc<const N: usize> = [(); N];
fn foo<const N: usize>(&self) -> Self::Assoc<N> {
[(); N]
}
}

fn main() {
assert_eq!(().foo::<10>(), [(); 10]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// run-pass
#![feature(generic_associated_types)]
#![allow(incomplete_features)]

// This test unsures that with_opt_const_param returns the
// def_id of the N param in the Bar::Assoc GAT.

trait Bar {
type Assoc<const N: usize>;
}
trait Foo: Bar {
fn foo(&self) -> Self::Assoc<3>;
}

impl Bar for () {
type Assoc<const N: usize> = [(); N];
}

impl Foo for () {
fn foo(&self) -> Self::Assoc<3> {
[(); 3]
}
}

fn main() {
assert_eq!(().foo(), [(); 3]);
}
2 changes: 1 addition & 1 deletion src/test/ui/invalid/invalid-no-sanitize.stderr
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
LL | #[no_sanitize(brontosaurus)]
| ^^^^^^^^^^^^
|
= note: expected one of: `address`, `memory` or `thread`
= note: expected one of: `address`, `hwaddress`, `memory` or `thread`

error: aborting due to previous error

19 changes: 19 additions & 0 deletions src/test/ui/sanitize/hwaddress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// needs-sanitizer-support
// needs-sanitizer-hwaddress
//
// compile-flags: -Z sanitizer=hwaddress -O -g
//
// run-fail
// error-pattern: HWAddressSanitizer: tag-mismatch

#![feature(test)]

use std::hint::black_box;

fn main() {
let xs = vec![0, 1, 2, 3];
// Avoid optimizing everything out.
let xs = black_box(xs.as_ptr());
let code = unsafe { *xs.offset(4) };
std::process::exit(code);
}
30 changes: 16 additions & 14 deletions src/tools/build-manifest/src/main.rs
Original file line number Diff line number Diff line change
@@ -254,24 +254,26 @@ impl Builder {
t!(self.checksums.store_cache());
}

/// If a tool does not pass its tests, don't ship it.
/// If a tool does not pass its tests on *any* of Linux and Windows, don't ship
/// it on *all* targets, because tools like Miri can "cross-run" programs for
/// different targets, for example, run a program for `x86_64-pc-windows-msvc`
/// on `x86_64-unknown-linux-gnu`.
/// Right now, we do this only for Miri.
fn check_toolstate(&mut self) {
let toolstates: Option<HashMap<String, String>> =
File::open(self.input.join("toolstates-linux.json"))
for file in &["toolstates-linux.json", "toolstates-windows.json"] {
let toolstates: Option<HashMap<String, String>> = File::open(self.input.join(file))
.ok()
.and_then(|f| serde_json::from_reader(&f).ok());
let toolstates = toolstates.unwrap_or_else(|| {
println!(
"WARNING: `toolstates-linux.json` missing/malformed; \
assuming all tools failed"
);
HashMap::default() // Use empty map if anything went wrong.
});
// Mark some tools as missing based on toolstate.
if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") {
println!("Miri tests are not passing, removing component");
self.versions.disable_version(&PkgType::Miri);
let toolstates = toolstates.unwrap_or_else(|| {
println!("WARNING: `{}` missing/malformed; assuming all tools failed", file);
HashMap::default() // Use empty map if anything went wrong.
});
// Mark some tools as missing based on toolstate.
if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") {
println!("Miri tests are not passing, removing component");
self.versions.disable_version(&PkgType::Miri);
break;
}
}
}

5 changes: 5 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ impl EarlyProps {
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);

iter_header(testfile, None, rdr, &mut |ln| {
// we should check if any only-<platform> exists and if it exists
@@ -101,6 +102,10 @@ impl EarlyProps {
props.ignore = true;
}

if !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress") {
props.ignore = true;
}

if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
props.ignore = true;
}
3 changes: 3 additions & 0 deletions src/tools/compiletest/src/util.rs
Original file line number Diff line number Diff line change
@@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
"x86_64-unknown-linux-gnu",
];

pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

const BIG_ENDIAN: &[&str] = &[
"aarch64_be",
"armebv7r",