Skip to content

Rollup of 8 pull requests #74724

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

Merged
merged 28 commits into from
Jul 24, 2020
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6813c1c
revise RwLock, which is derived from the wasm implementation
stlankes Jun 3, 2020
3acc3ef
minor changes to pass the format check
stlankes Jun 3, 2020
beb1b1f
reorder crates to pass the format check
stlankes Jun 4, 2020
f9c6091
remove some compiler warnings
stlankes Jun 26, 2020
6925ebd
use latest version of hermit-abi
stlankes Jul 6, 2020
711a680
Optimize away BitAnd and BitOr when possible
xldenis Jul 18, 2020
c276334
add RegionName::span
SNCPlay42 Jul 21, 2020
51af5af
extract RegionNameHighlight
SNCPlay42 Jul 22, 2020
601518e
change returns to RegionNameHighlight
SNCPlay42 Jul 22, 2020
723ea90
rename functions
SNCPlay42 Jul 22, 2020
b56f5b9
clean up give_name_if_anonymous_region_appears_in_arguments
SNCPlay42 Jul 22, 2020
a7450b7
decouple highlight_if_we_cannot_match_hir_ty
SNCPlay42 Jul 22, 2020
ebb4aba
move highlight_if_we_can_match_hir_ty call
SNCPlay42 Jul 22, 2020
8a776ee
rename arguments to highlight_if_we_can_match_hir_ty
SNCPlay42 Jul 22, 2020
ef74e50
Rearrange the pipeline of `pow` to gain efficiency
Neutron3529 Jul 15, 2020
e46219c
Downgrade glibc to 2.11.1 for ppc, ppc64 and s390x
Jul 22, 2020
5a5846f
delay_span_bug instead of silent ignore
Mark-Simulacrum Jul 23, 2020
bae1e03
fixed error reporting for mismatched traits
ayrtonm Jul 23, 2020
b75ed4f
added a test case for reporting mismatched traits
ayrtonm Jul 24, 2020
b56ea88
Add a system for creating diffs across multiple mir optimizations.
oli-obk Jul 24, 2020
dfedb84
Rollup merge of #72954 - hermitcore:rwlock, r=dtolnay
Manishearth Jul 24, 2020
3226d72
Rollup merge of #74367 - Neutron3529:patch-1, r=nagisa
Manishearth Jul 24, 2020
e59effe
Rollup merge of #74491 - xldenis:constant-binop-opt, r=oli-obk
Manishearth Jul 24, 2020
a4024ba
Rollup merge of #74639 - msirringhaus:master, r=cuviper
Manishearth Jul 24, 2020
ceaef73
Rollup merge of #74661 - SNCPlay42:lifetime-names-refactor, r=estebank
Manishearth Jul 24, 2020
db83a21
Rollup merge of #74692 - Mark-Simulacrum:delay-bug, r=pnkfelix
Manishearth Jul 24, 2020
7f24c7d
Rollup merge of #74698 - ayrtonm:handle-traitref-mismatch, r=estebank
Manishearth Jul 24, 2020
5d1d94e
Rollup merge of #74715 - oli-obk:mir_pass_diff, r=wesleywiser
Manishearth Jul 24, 2020
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
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -1242,9 +1242,9 @@ dependencies = [

[[package]]
name = "hermit-abi"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
dependencies = [
"compiler_builtins",
"libc",
6 changes: 3 additions & 3 deletions src/ci/docker/README.md
Original file line number Diff line number Diff line change
@@ -238,7 +238,7 @@ For targets: `powerpc-unknown-linux-gnu`
- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > C++ = ENABLE -- to cross compile LLVM

@@ -255,7 +255,7 @@ For targets: `powerpc64-unknown-linux-gnu`
- Target options > Tune for CPU = power6 -- (+)
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > C++ = ENABLE -- to cross compile LLVM

@@ -272,7 +272,7 @@ For targets: `s390x-unknown-linux-gnu`
- Target options > Bitness = 64-bit
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
- C compiler > C++ = ENABLE -- to cross compile LLVM
Original file line number Diff line number Diff line change
@@ -290,7 +290,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# C-library
#
CT_LIBC="glibc"
CT_LIBC_VERSION="2.12.2"
CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
@@ -309,9 +309,9 @@ CT_THREADS="nptl"
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
CT_LIBC_GLIBC_V_2_12_2=y
# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
# CT_LIBC_GLIBC_V_2_11_1 is not set
CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
Original file line number Diff line number Diff line change
@@ -290,7 +290,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# C-library
#
CT_LIBC="glibc"
CT_LIBC_VERSION="2.12.2"
CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
@@ -309,9 +309,9 @@ CT_THREADS="nptl"
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
CT_LIBC_GLIBC_V_2_12_2=y
# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
# CT_LIBC_GLIBC_V_2_11_1 is not set
CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
Original file line number Diff line number Diff line change
@@ -270,7 +270,7 @@ CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# C-library
#
CT_LIBC="glibc"
CT_LIBC_VERSION="2.12.2"
CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
@@ -289,9 +289,9 @@ CT_THREADS="nptl"
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
CT_LIBC_GLIBC_V_2_12_2=y
# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
# CT_LIBC_GLIBC_V_2_11_1 is not set
CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
87 changes: 44 additions & 43 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
@@ -1095,6 +1095,9 @@ $EndFeature, "
without modifying the original"]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;

@@ -1105,15 +1108,11 @@ $EndFeature, "
exp /= 2;
base = try_opt!(base.checked_mul(base));
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = try_opt!(acc.checked_mul(base));
}

Some(acc)
Some(try_opt!(acc.checked_mul(base)))
}
}

@@ -1622,6 +1621,9 @@ $EndFeature, "
without modifying the original"]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;

@@ -1633,14 +1635,11 @@ $EndFeature, "
base = base.wrapping_mul(base);
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.wrapping_mul(base);
}

acc
acc.wrapping_mul(base)
}
}

@@ -1989,6 +1988,9 @@ $EndFeature, "
without modifying the original"]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
if exp == 0 {
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
@@ -2007,16 +2009,13 @@ $EndFeature, "
overflown |= r.1;
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}

(acc, overflown)
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
}
}

@@ -2040,6 +2039,9 @@ $EndFeature, "
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn pow(self, mut exp: u32) -> Self {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;

@@ -2051,14 +2053,11 @@ $EndFeature, "
base = base * base;
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc * base;
}

acc
acc * base
}
}

@@ -3295,6 +3294,9 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
without modifying the original"]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;

@@ -3306,14 +3308,12 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
base = try_opt!(base.checked_mul(base));
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = try_opt!(acc.checked_mul(base));
}

Some(acc)
Some(try_opt!(acc.checked_mul(base)))
}
}

@@ -3704,6 +3704,9 @@ assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
without modifying the original"]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;

@@ -3715,14 +3718,11 @@ assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
base = base.wrapping_mul(base);
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc.wrapping_mul(base);
}

acc
acc.wrapping_mul(base)
}
}

@@ -4029,6 +4029,9 @@ assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
without modifying the original"]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
if exp == 0{
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
@@ -4047,16 +4050,14 @@ assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
overflown |= r.1;
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
r = acc.overflowing_mul(base);
r.1 |= overflown;

(acc, overflown)
r
}
}

@@ -4077,6 +4078,9 @@ Basic usage:
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn pow(self, mut exp: u32) -> Self {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;

@@ -4088,14 +4092,11 @@ Basic usage:
base = base * base;
}

// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
if exp == 1 {
acc = acc * base;
}

acc
acc * base
}
}

33 changes: 32 additions & 1 deletion src/libcore/tests/num/int_macros.rs
Original file line number Diff line number Diff line change
@@ -255,12 +255,43 @@ macro_rules! int_module {
#[test]
fn test_pow() {
let mut r = 2 as $T;

assert_eq!(r.pow(2), 4 as $T);
assert_eq!(r.pow(0), 1 as $T);
assert_eq!(r.wrapping_pow(2), 4 as $T);
assert_eq!(r.wrapping_pow(0), 1 as $T);
assert_eq!(r.checked_pow(2), Some(4 as $T));
assert_eq!(r.checked_pow(0), Some(1 as $T));
assert_eq!(r.overflowing_pow(2), (4 as $T, false));
assert_eq!(r.overflowing_pow(0), (1 as $T, false));
assert_eq!(r.saturating_pow(2), 4 as $T);
assert_eq!(r.saturating_pow(0), 1 as $T);

r = MAX;
// use `^` to represent .pow() with no overflow.
// if itest::MAX == 2^j-1, then itest is a `j` bit int,
// so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
// thussaturating_pow the overflowing result is exactly 1.
assert_eq!(r.wrapping_pow(2), 1 as $T);
assert_eq!(r.checked_pow(2), None);
assert_eq!(r.overflowing_pow(2), (1 as $T, true));
assert_eq!(r.saturating_pow(2), MAX);
//test for negative exponent.
r = -2 as $T;
assert_eq!(r.pow(2), 4 as $T);
assert_eq!(r.pow(3), -8 as $T);
assert_eq!(r.pow(0), 1 as $T);
assert_eq!(r.wrapping_pow(2), 4 as $T);
assert_eq!(r.wrapping_pow(3), -8 as $T);
assert_eq!(r.wrapping_pow(0), 1 as $T);
assert_eq!(r.checked_pow(2), Some(4 as $T));
assert_eq!(r.checked_pow(3), Some(-8 as $T));
assert_eq!(r.checked_pow(0), Some(1 as $T));
assert_eq!(r.overflowing_pow(2), (4 as $T, false));
assert_eq!(r.overflowing_pow(3), (-8 as $T, false));
assert_eq!(r.overflowing_pow(0), (1 as $T, false));
assert_eq!(r.saturating_pow(2), 4 as $T);
assert_eq!(r.saturating_pow(3), -8 as $T);
assert_eq!(r.saturating_pow(0), 1 as $T);
}
}
};
25 changes: 25 additions & 0 deletions src/libcore/tests/num/uint_macros.rs
Original file line number Diff line number Diff line change
@@ -184,6 +184,31 @@ macro_rules! uint_module {
assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
}

#[test]
fn test_pow() {
let mut r = 2 as $T;
assert_eq!(r.pow(2), 4 as $T);
assert_eq!(r.pow(0), 1 as $T);
assert_eq!(r.wrapping_pow(2), 4 as $T);
assert_eq!(r.wrapping_pow(0), 1 as $T);
assert_eq!(r.checked_pow(2), Some(4 as $T));
assert_eq!(r.checked_pow(0), Some(1 as $T));
assert_eq!(r.overflowing_pow(2), (4 as $T, false));
assert_eq!(r.overflowing_pow(0), (1 as $T, false));
assert_eq!(r.saturating_pow(2), 4 as $T);
assert_eq!(r.saturating_pow(0), 1 as $T);

r = MAX;
// use `^` to represent .pow() with no overflow.
// if itest::MAX == 2^j-1, then itest is a `j` bit int,
// so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
// thussaturating_pow the overflowing result is exactly 1.
assert_eq!(r.wrapping_pow(2), 1 as $T);
assert_eq!(r.checked_pow(2), None);
assert_eq!(r.overflowing_pow(2), (1 as $T, true));
assert_eq!(r.saturating_pow(2), MAX);
}
}
};
}
29 changes: 24 additions & 5 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -1402,8 +1402,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

debug!("note_type_err(diag={:?})", diag);
enum Mismatch<'a> {
Variable(ty::error::ExpectedFound<Ty<'a>>),
Fixed(&'static str),
}
let (expected_found, exp_found, is_simple_error) = match values {
None => (None, None, false),
None => (None, Mismatch::Fixed("type"), false),
Some(values) => {
let (is_simple_error, exp_found) = match values {
ValuePairs::Types(exp_found) => {
@@ -1417,9 +1421,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
)
.report(diag);

(is_simple_err, Some(exp_found))
(is_simple_err, Mismatch::Variable(exp_found))
}
_ => (false, None),
ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
_ => (false, Mismatch::Fixed("type")),
};
let vals = match self.values_str(&values) {
Some((expected, found)) => Some((expected, found)),
@@ -1445,8 +1450,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
};
if let Some((expected, found)) = expected_found {
let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
let expected_label = match exp_found {
Mismatch::Variable(ef) => ef.expected.prefix_string(),
Mismatch::Fixed(s) => s.into(),
};
let found_label = match exp_found {
Mismatch::Variable(ef) => ef.found.prefix_string(),
Mismatch::Fixed(s) => s.into(),
};
let exp_found = match exp_found {
Mismatch::Variable(exp_found) => Some(exp_found),
Mismatch::Fixed(_) => None,
};
match (&terr, expected == found) {
(TypeError::Sorts(values), extra) => {
let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) {
@@ -1499,6 +1514,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
}
let exp_found = match exp_found {
Mismatch::Variable(exp_found) => Some(exp_found),
Mismatch::Fixed(_) => None,
};
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
}
Original file line number Diff line number Diff line change
@@ -60,9 +60,7 @@ impl OutlivesSuggestionBuilder {
// Don't give suggestions for upvars, closure return types, or other unnamable
// regions.
RegionNameSource::SynthesizedFreeEnvRegion(..)
| RegionNameSource::CannotMatchHirTy(..)
| RegionNameSource::MatchedHirTy(..)
| RegionNameSource::MatchedAdtAndSegment(..)
| RegionNameSource::AnonRegionFromArgument(..)
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
16 changes: 3 additions & 13 deletions src/librustc_mir/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use crate::borrow_check::{
MirBorrowckCtxt,
};

use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
use super::{OutlivesSuggestionBuilder, RegionName};

impl ConstraintDescription for ConstraintCategory {
fn description(&self) -> &'static str {
@@ -396,18 +396,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
diag.span_label(upvar_span, "variable captured here");
}

match self.give_region_a_name(*outlived_fr).unwrap().source {
RegionNameSource::NamedEarlyBoundRegion(fr_span)
| RegionNameSource::NamedFreeRegion(fr_span)
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
| RegionNameSource::CannotMatchHirTy(fr_span, _)
| RegionNameSource::MatchedHirTy(fr_span)
| RegionNameSource::MatchedAdtAndSegment(fr_span)
| RegionNameSource::AnonRegionFromUpvar(fr_span, _)
| RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
diag.span_label(fr_span, "inferred to be a `FnMut` closure");
}
_ => {}
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
diag.span_label(fr_span, "inferred to be a `FnMut` closure");
}

diag.note(
161 changes: 88 additions & 73 deletions src/librustc_mir/borrow_check/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
@@ -34,13 +34,8 @@ crate enum RegionNameSource {
Static,
/// The free region corresponding to the environment of a closure.
SynthesizedFreeEnvRegion(Span, String),
/// The region name corresponds to a region where the type annotation is completely missing
/// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
CannotMatchHirTy(Span, String),
/// The region name corresponds a reference that was found by traversing the type in the HIR.
MatchedHirTy(Span),
/// A region name from the generics list of a struct/enum/union.
MatchedAdtAndSegment(Span),
/// The region corresponding to an argument.
AnonRegionFromArgument(RegionNameHighlight),
/// The region corresponding to a closure upvar.
AnonRegionFromUpvar(Span, String),
/// The region corresponding to the return type of a closure.
@@ -51,23 +46,52 @@ crate enum RegionNameSource {
AnonRegionFromAsyncFn(Span),
}

/// Describes what to highlight to explain to the user that we're giving an anonymous region a
/// synthesized name, and how to highlight it.
#[derive(Debug, Clone)]
crate enum RegionNameHighlight {
/// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
MatchedHirTy(Span),
/// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union.
MatchedAdtAndSegment(Span),
/// The anonymous region corresponds to a region where the type annotation is completely missing
/// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
CannotMatchHirTy(Span, String),
}

impl RegionName {
crate fn was_named(&self) -> bool {
match self.source {
RegionNameSource::NamedEarlyBoundRegion(..)
| RegionNameSource::NamedFreeRegion(..)
| RegionNameSource::Static => true,
RegionNameSource::SynthesizedFreeEnvRegion(..)
| RegionNameSource::CannotMatchHirTy(..)
| RegionNameSource::MatchedHirTy(..)
| RegionNameSource::MatchedAdtAndSegment(..)
| RegionNameSource::AnonRegionFromArgument(..)
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
| RegionNameSource::AnonRegionFromAsyncFn(..) => false,
}
}

crate fn span(&self) -> Option<Span> {
match self.source {
RegionNameSource::Static => None,
RegionNameSource::NamedEarlyBoundRegion(span)
| RegionNameSource::NamedFreeRegion(span)
| RegionNameSource::SynthesizedFreeEnvRegion(span, _)
| RegionNameSource::AnonRegionFromUpvar(span, _)
| RegionNameSource::AnonRegionFromOutput(span, _, _)
| RegionNameSource::AnonRegionFromYieldTy(span, _)
| RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
RegionNameSource::AnonRegionFromArgument(ref highlight) => match *highlight {
RegionNameHighlight::MatchedHirTy(span)
| RegionNameHighlight::MatchedAdtAndSegment(span)
| RegionNameHighlight::CannotMatchHirTy(span, _) => Some(span),
},
}
}

crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
match &self.source {
RegionNameSource::NamedFreeRegion(span)
@@ -81,17 +105,22 @@ impl RegionName {
);
diag.note(&note);
}
RegionNameSource::CannotMatchHirTy(span, type_name) => {
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
span,
type_name,
)) => {
diag.span_label(*span, format!("has type `{}`", type_name));
}
RegionNameSource::MatchedHirTy(span)
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
| RegionNameSource::AnonRegionFromAsyncFn(span) => {
diag.span_label(
*span,
format!("let's call the lifetime of this reference `{}`", self),
);
}
RegionNameSource::MatchedAdtAndSegment(span) => {
RegionNameSource::AnonRegionFromArgument(
RegionNameHighlight::MatchedAdtAndSegment(span),
) => {
diag.span_label(*span, format!("let's call this `{}`", self));
}
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
@@ -307,21 +336,31 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {

let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
[implicit_inputs + argument_index];
if let Some(region_name) =
self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
{
return Some(region_name);
}
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
&self.body,
&self.local_names,
argument_index,
);

self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
self.get_argument_hir_ty_for_highlighting(argument_index)
.and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
.or_else(|| {
// `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
// the anonymous region. If it succeeds, the `synthesize_region_name` call below
// will increment the counter, "reserving" the number we just used.
let counter = *self.next_region_name.try_borrow().unwrap();
self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter)
})
.map(|highlight| RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::AnonRegionFromArgument(highlight),
})
}

fn give_name_if_we_can_match_hir_ty_from_argument(
fn get_argument_hir_ty_for_highlighting(
&self,
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
argument_index: usize,
) -> Option<RegionName> {
) -> Option<&hir::Ty<'tcx>> {
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
@@ -333,7 +372,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// (`give_name_if_anonymous_region_appears_in_arguments`).
hir::TyKind::Infer => None,

_ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
_ => Some(argument_hir_ty),
}
}

@@ -348,42 +387,28 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | | has type `&'1 u32`
/// | has type `&'2 u32`
/// ```
fn give_name_if_we_cannot_match_hir_ty(
fn highlight_if_we_cannot_match_hir_ty(
&self,
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
) -> Option<RegionName> {
let counter = *self.next_region_name.try_borrow().unwrap();
ty: Ty<'tcx>,
span: Span,
counter: usize,
) -> Option<RegionNameHighlight> {
let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(needle_fr, counter);
let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0;

debug!(
"give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
type_name, needle_fr
);
let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
if type_name.find(&format!("'{}", counter)).is_some() {
// Only add a label if we can confirm that a region was labelled.
let argument_index =
self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
&self.body,
&self.local_names,
argument_index,
);

Some(RegionName {
// This counter value will already have been used, so this function will increment
// it so the next value will be used next and return the region name that would
// have been used.
name: self.synthesize_region_name(),
source: RegionNameSource::CannotMatchHirTy(span, type_name),
})

Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
} else {
None
};

assigned_region_name
}
}

/// Attempts to highlight the specific part of a type annotation
@@ -395,9 +420,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | - let's call the lifetime of this reference `'1`
/// ```
///
/// the way this works is that we match up `argument_ty`, which is
/// the way this works is that we match up `ty`, which is
/// a `Ty<'tcx>` (the internal form of the type) with
/// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
/// `hir_ty`, a `hir::Ty` (the syntax of the type
/// annotation). We are descending through the types stepwise,
/// looking in to find the region `needle_fr` in the internal
/// type. Once we find that, we can use the span of the `hir::Ty`
@@ -407,18 +432,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// keep track of the **closest** type we've found. If we fail to
/// find the exact `&` or `'_` to highlight, then we may fall back
/// to highlighting that closest type instead.
fn give_name_if_we_can_match_hir_ty(
fn highlight_if_we_can_match_hir_ty(
&self,
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
argument_hir_ty: &hir::Ty<'_>,
) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
&mut vec![(argument_ty, argument_hir_ty)];
ty: Ty<'tcx>,
hir_ty: &hir::Ty<'_>,
) -> Option<RegionNameHighlight> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)];

while let Some((ty, hir_ty)) = search_stack.pop() {
match (&ty.kind, &hir_ty.kind) {
// Check if the `argument_ty` is `&'X ..` where `'X`
// Check if the `ty` is `&'X ..` where `'X`
// is the region we are looking for -- if so, and we have a `&T`
// on the RHS, then we want to highlight the `&` like so:
//
@@ -429,16 +453,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
hir::TyKind::Rptr(_lifetime, referent_hir_ty),
) => {
if region.to_region_vid() == needle_fr {
let region_name = self.synthesize_region_name();

// Just grab the first character, the `&`.
let source_map = self.infcx.tcx.sess.source_map();
let ampersand_span = source_map.start_point(hir_ty.span);

return Some(RegionName {
name: region_name,
source: RegionNameSource::MatchedHirTy(ampersand_span),
});
return Some(RegionNameHighlight::MatchedHirTy(ampersand_span));
}

// Otherwise, let's descend into the referent types.
@@ -458,13 +477,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
Res::Def(DefKind::TyAlias, _) => (),
_ => {
if let Some(last_segment) = path.segments.last() {
if let Some(name) = self.match_adt_and_segment(
if let Some(highlight) = self.match_adt_and_segment(
substs,
needle_fr,
last_segment,
search_stack,
) {
return Some(name);
return Some(highlight);
}
}
}
@@ -507,7 +526,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
needle_fr: RegionVid,
last_segment: &'hir hir::PathSegment<'hir>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
) -> Option<RegionName> {
) -> Option<RegionNameHighlight> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
let args = last_segment.args.as_ref()?;
let lifetime =
@@ -517,12 +536,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
| hir::LifetimeName::Error
| hir::LifetimeName::Static
| hir::LifetimeName::Underscore => {
let region_name = self.synthesize_region_name();
let ampersand_span = lifetime.span;
Some(RegionName {
name: region_name,
source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
})
let lifetime_span = lifetime.span;
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}

hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
106 changes: 85 additions & 21 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
@@ -28,9 +28,9 @@ use rustc_trait_selection::traits;

use crate::const_eval::error_to_const_error;
use crate::interpret::{
self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
ScalarMaybeUninit, StackPopCleanup,
self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
Pointer, ScalarMaybeUninit, StackPopCleanup,
};
use crate::transform::{MirPass, MirSource};

@@ -527,11 +527,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
right: &Operand<'tcx>,
source_info: SourceInfo,
) -> Option<()> {
let r =
self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?;
let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
if op == BinOp::Shr || op == BinOp::Shl {
let r = r?;
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
let left_ty = left.ty(&self.local_decls, self.tcx);
@@ -564,21 +564,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
}

let l = l?;

// The remaining operators are handled through `overflowing_binary_op`.
if self.use_ecx(|this| {
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
Ok(overflow)
})? {
self.report_assert_as_lint(
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
"this arithmetic operation will overflow",
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
)?;
if let (Some(l), Some(r)) = (l, r) {
// The remaining operators are handled through `overflowing_binary_op`.
if self.use_ecx(|this| {
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
Ok(overflow)
})? {
self.report_assert_as_lint(
lint::builtin::ARITHMETIC_OVERFLOW,
source_info,
"this arithmetic operation will overflow",
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
)?;
}
}

Some(())
}

@@ -659,9 +658,74 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}

if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 {
self.eval_rvalue_with_identities(rvalue, place)
} else {
self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
}
}

// Attempt to use albegraic identities to eliminate constant expressions
fn eval_rvalue_with_identities(
&mut self,
rvalue: &Rvalue<'tcx>,
place: Place<'tcx>,
) -> Option<()> {
self.use_ecx(|this| {
trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
this.ecx.eval_rvalue_into_place(rvalue, place)?;
match rvalue {
Rvalue::BinaryOp(op, left, right) | Rvalue::CheckedBinaryOp(op, left, right) => {
let l = this.ecx.eval_operand(left, None);
let r = this.ecx.eval_operand(right, None);

let const_arg = match (l, r) {
(Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
(Err(e), Err(_)) => return Err(e),
(Ok(_), Ok(_)) => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
return Ok(());
}
};

let arg_value =
this.ecx.force_bits(const_arg.to_scalar()?, const_arg.layout.size)?;
let dest = this.ecx.eval_place(place)?;

match op {
BinOp::BitAnd => {
if arg_value == 0 {
this.ecx.write_immediate(*const_arg, dest)?;
}
}
BinOp::BitOr => {
if arg_value == truncate(u128::MAX, const_arg.layout.size)
|| (const_arg.layout.ty.is_bool() && arg_value == 1)
{
this.ecx.write_immediate(*const_arg, dest)?;
}
}
BinOp::Mul => {
if const_arg.layout.ty.is_integral() && arg_value == 0 {
if let Rvalue::CheckedBinaryOp(_, _, _) = rvalue {
let val = Immediate::ScalarPair(
const_arg.to_scalar()?.into(),
Scalar::from_bool(false).into(),
);
this.ecx.write_immediate(val, dest)?;
} else {
this.ecx.write_immediate(*const_arg, dest)?;
}
}
}
_ => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
}
}
}
_ => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
}
}

Ok(())
})
}
30 changes: 18 additions & 12 deletions src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
@@ -1506,18 +1506,24 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
pat.walk(&mut |pat| {
debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind);
match pat.kind {
// In tuple struct patterns ignore the invalid `ident @ ...`.
// It will be handled as an error by the AST lowering.
PatKind::Ident(bmode, ident, ref sub)
if !(is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some()) =>
{
// First try to resolve the identifier as some existing entity,
// then fall back to a fresh binding.
let has_sub = sub.is_some();
let res = self
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
.unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
self.r.record_partial_res(pat.id, PartialRes::new(res));
PatKind::Ident(bmode, ident, ref sub) => {
if is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some() {
// In tuple struct patterns ignore the invalid `ident @ ...`.
// It will be handled as an error by the AST lowering.
self.r
.session
.delay_span_bug(ident.span, "ident in tuple pattern is invalid");
} else {
// First try to resolve the identifier as some existing entity,
// then fall back to a fresh binding.
let has_sub = sub.is_some();
let res = self
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
.unwrap_or_else(|| {
self.fresh_binding(ident, pat.id, pat_src, bindings)
});
self.r.record_partial_res(pat.id, PartialRes::new(res));
}
}
PatKind::TupleStruct(ref path, ..) => {
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span));
2 changes: 1 addition & 1 deletion src/libstd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }

[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }

[target.wasm32-wasi.dependencies]
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
64 changes: 34 additions & 30 deletions src/libstd/sys/hermit/condvar.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,64 @@
use crate::cmp;
use crate::ffi::c_void;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;

// The implementation is inspired by Andrew D. Birrell's paper
// "Implementing Condition Variables with Semaphores"

pub struct Condvar {
identifier: usize,
counter: AtomicUsize,
sem1: *const c_void,
sem2: *const c_void,
}

unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

impl Condvar {
pub const fn new() -> Condvar {
Condvar { identifier: 0 }
Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
}

pub unsafe fn init(&mut self) {
let _ = abi::init_queue(self.id());
let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
}

pub unsafe fn notify_one(&self) {
let _ = abi::notify(self.id(), 1);
if self.counter.load(SeqCst) > 0 {
self.counter.fetch_sub(1, SeqCst);
abi::sem_post(self.sem1);
abi::sem_timedwait(self.sem2, 0);
}
}

#[inline]
pub unsafe fn notify_all(&self) {
let _ = abi::notify(self.id(), -1 /* =all */);
let counter = self.counter.swap(0, SeqCst);
for _ in 0..counter {
abi::sem_post(self.sem1);
}
for _ in 0..counter {
abi::sem_timedwait(self.sem2, 0);
}
}

pub unsafe fn wait(&self, mutex: &Mutex) {
// add current task to the wait queue
let _ = abi::add_queue(self.id(), -1 /* no timeout */);
self.counter.fetch_add(1, SeqCst);
mutex.unlock();
let _ = abi::wait(self.id());
abi::sem_timedwait(self.sem1, 0);
abi::sem_post(self.sem2);
mutex.lock();
}

pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let nanos = dur.as_nanos();
let nanos = cmp::min(i64::MAX as u128, nanos);

// add current task to the wait queue
let _ = abi::add_queue(self.id(), nanos as i64);

mutex.unlock();
// If the return value is !0 then a timeout happened, so we return
// `false` as we weren't actually notified.
let ret = abi::wait(self.id()) == 0;
mutex.lock();

ret
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
panic!("wait_timeout not supported on hermit");
}

pub unsafe fn destroy(&self) {
let _ = abi::destroy_queue(self.id());
}

#[inline]
fn id(&self) -> usize {
&self.identifier as *const usize as usize
let _ = abi::sem_destroy(self.sem1);
let _ = abi::sem_destroy(self.sem2);
}
}
115 changes: 105 additions & 10 deletions src/libstd/sys/hermit/rwlock.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,144 @@
use super::mutex::Mutex;
use crate::cell::UnsafeCell;
use crate::sys::condvar::Condvar;
use crate::sys::mutex::Mutex;

pub struct RWLock {
mutex: Mutex,
lock: Mutex,
cond: Condvar,
state: UnsafeCell<State>,
}

enum State {
Unlocked,
Reading(usize),
Writing,
}

unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}

// This rwlock implementation is a relatively simple implementation which has a
// condition variable for readers/writers as well as a mutex protecting the
// internal state of the lock. A current downside of the implementation is that
// unlocking the lock will notify *all* waiters rather than just readers or just
// writers. This can cause lots of "thundering stampede" problems. While
// hopefully correct this implementation is very likely to want to be changed in
// the future.

impl RWLock {
pub const fn new() -> RWLock {
RWLock { mutex: Mutex::new() }
RWLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
}

#[inline]
pub unsafe fn read(&self) {
self.mutex.lock();
self.lock.lock();
while !(*self.state.get()).inc_readers() {
self.cond.wait(&self.lock);
}
self.lock.unlock();
}

#[inline]
pub unsafe fn try_read(&self) -> bool {
self.mutex.try_lock()
self.lock.lock();
let ok = (*self.state.get()).inc_readers();
self.lock.unlock();
return ok;
}

#[inline]
pub unsafe fn write(&self) {
self.mutex.lock();
self.lock.lock();
while !(*self.state.get()).inc_writers() {
self.cond.wait(&self.lock);
}
self.lock.unlock();
}

#[inline]
pub unsafe fn try_write(&self) -> bool {
self.mutex.try_lock()
self.lock.lock();
let ok = (*self.state.get()).inc_writers();
self.lock.unlock();
return ok;
}

#[inline]
pub unsafe fn read_unlock(&self) {
self.mutex.unlock();
self.lock.lock();
let notify = (*self.state.get()).dec_readers();
self.lock.unlock();
if notify {
// FIXME: should only wake up one of these some of the time
self.cond.notify_all();
}
}

#[inline]
pub unsafe fn write_unlock(&self) {
self.mutex.unlock();
self.lock.lock();
(*self.state.get()).dec_writers();
self.lock.unlock();
// FIXME: should only wake up one of these some of the time
self.cond.notify_all();
}

#[inline]
pub unsafe fn destroy(&self) {
self.mutex.destroy();
self.lock.destroy();
self.cond.destroy();
}
}

impl State {
fn inc_readers(&mut self) -> bool {
match *self {
State::Unlocked => {
*self = State::Reading(1);
true
}
State::Reading(ref mut cnt) => {
*cnt += 1;
true
}
State::Writing => false,
}
}

fn inc_writers(&mut self) -> bool {
match *self {
State::Unlocked => {
*self = State::Writing;
true
}
State::Reading(_) | State::Writing => false,
}
}

fn dec_readers(&mut self) -> bool {
let zero = match *self {
State::Reading(ref mut cnt) => {
*cnt -= 1;
*cnt == 0
}
State::Unlocked | State::Writing => invalid(),
};
if zero {
*self = State::Unlocked;
}
zero
}

fn dec_writers(&mut self) {
match *self {
State::Writing => {}
State::Unlocked | State::Reading(_) => invalid(),
}
*self = State::Unlocked;
}
}

fn invalid() -> ! {
panic!("inconsistent rwlock");
}
10 changes: 10 additions & 0 deletions src/test/mir-opt/const_prop/boolean_identities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// compile-flags: -O -Zmir-opt-level=3

// EMIT_MIR rustc.test.ConstProp.diff
pub fn test(x: bool, y: bool) -> bool {
(y | true) & (x & false)
}

fn main() {
test(true, false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
- // MIR for `test` before ConstProp
+ // MIR for `test` after ConstProp

fn test(_1: bool, _2: bool) -> bool {
debug x => _1; // in scope 0 at $DIR/boolean_identities.rs:4:13: 4:14
debug y => _2; // in scope 0 at $DIR/boolean_identities.rs:4:22: 4:23
let mut _0: bool; // return place in scope 0 at $DIR/boolean_identities.rs:4:34: 4:38
let mut _3: bool; // in scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
let mut _4: bool; // in scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
let mut _5: bool; // in scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
let mut _6: bool; // in scope 0 at $DIR/boolean_identities.rs:5:19: 5:20

bb0: {
StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
_4 = _2; // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+ _3 = const true; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
// ty::Const
// + ty: bool
// + val: Value(Scalar(0x01))
// mir::Constant
- // + span: $DIR/boolean_identities.rs:5:10: 5:14
+ // + span: $DIR/boolean_identities.rs:5:5: 5:15
// + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:5:14: 5:15
StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
_6 = _1; // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
// ty::Const
// + ty: bool
// + val: Value(Scalar(0x00))
// mir::Constant
- // + span: $DIR/boolean_identities.rs:5:23: 5:28
+ // + span: $DIR/boolean_identities.rs:5:18: 5:29
// + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
- _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
+ _0 = const false; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/boolean_identities.rs:5:5: 5:29
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
return; // scope 0 at $DIR/boolean_identities.rs:6:2: 6:2
}
}

10 changes: 10 additions & 0 deletions src/test/mir-opt/const_prop/mult_by_zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// compile-flags: -O -Zmir-opt-level=3

// EMIT_MIR rustc.test.ConstProp.diff
fn test(x : i32) -> i32 {
x * 0
}

fn main() {
test(10);
}
25 changes: 25 additions & 0 deletions src/test/mir-opt/const_prop/mult_by_zero/rustc.test.ConstProp.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
- // MIR for `test` before ConstProp
+ // MIR for `test` after ConstProp

fn test(_1: i32) -> i32 {
debug x => _1; // in scope 0 at $DIR/mult_by_zero.rs:4:9: 4:10
let mut _0: i32; // return place in scope 0 at $DIR/mult_by_zero.rs:4:21: 4:24
let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4

bb0: {
StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
_2 = _1; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
+ _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000000))
// mir::Constant
- // + span: $DIR/mult_by_zero.rs:5:7: 5:8
+ // + span: $DIR/mult_by_zero.rs:5:3: 5:8
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:5:7: 5:8
return; // scope 0 at $DIR/mult_by_zero.rs:6:2: 6:2
}
}

3 changes: 1 addition & 2 deletions src/test/mir-opt/match-arm-scopes.rs
Original file line number Diff line number Diff line change
@@ -9,8 +9,7 @@
// all of the bindings for that scope.
// * No drop flags are used.

// EMIT_MIR rustc.complicated_match.SimplifyCfg-initial.after.mir
// EMIT_MIR rustc.complicated_match.ElaborateDrops.after.mir
// EMIT_MIR rustc.complicated_match SimplifyCfg-initial.after ElaborateDrops.after
fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
match items {
(false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,

This file was deleted.

Large diffs are not rendered by default.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// build-fail

// Regression test for #66975
#![warn(const_err)]
#![warn(const_err, unconditional_panic)]
#![feature(never_type)]

struct PrintName<T>(T);

impl<T> PrintName<T> {
const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
//~^ WARN any use of this value will cause an error

}

fn f<T>() {
Original file line number Diff line number Diff line change
@@ -9,11 +9,11 @@ LL | const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
note: the lint level is defined here
--> $DIR/index-out-of-bounds-never-type.rs:4:9
|
LL | #![warn(const_err)]
LL | #![warn(const_err, unconditional_panic)]
| ^^^^^^^^^

error: erroneous constant encountered
--> $DIR/index-out-of-bounds-never-type.rs:15:13
--> $DIR/index-out-of-bounds-never-type.rs:16:13
|
LL | let _ = PrintName::<T>::VOID;
| ^^^^^^^^^^^^^^^^^^^^
12 changes: 12 additions & 0 deletions src/test/ui/error-codes/E0308-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trait DynEq {}

impl<'a> PartialEq for &'a (dyn DynEq + 'static) {
fn eq(&self, _other: &Self) -> bool {
true
}
}

impl Eq for &dyn DynEq {} //~ ERROR E0308

fn main() {
}
18 changes: 18 additions & 0 deletions src/test/ui/error-codes/E0308-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0308]: mismatched types
--> $DIR/E0308-2.rs:9:6
|
LL | impl Eq for &dyn DynEq {}
| ^^ lifetime mismatch
|
= note: expected trait `std::cmp::PartialEq`
found trait `std::cmp::PartialEq`
note: the lifetime `'_` as defined on the impl at 9:13...
--> $DIR/E0308-2.rs:9:13
|
LL | impl Eq for &dyn DynEq {}
| ^
= note: ...does not necessarily outlive the static lifetime

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
53 changes: 43 additions & 10 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
@@ -3135,14 +3135,47 @@ impl<'test> TestCx<'test> {
}
for l in test_file_contents.lines() {
if l.starts_with("// EMIT_MIR ") {
let test_name = l.trim_start_matches("// EMIT_MIR ");
let expected_file = test_dir.join(test_name);

let dumped_string = if test_name.ends_with(".diff") {
let test_name = test_name.trim_end_matches(".diff");
let before = format!("{}.before.mir", test_name);
let after = format!("{}.after.mir", test_name);
let before = self.get_mir_dump_dir().join(before);
let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
let mut test_names = test_name.split(' ');
// sometimes we specify two files so that we get a diff between the two files
let test_name = test_names.next().unwrap();
let expected_file;
let from_file;
let to_file;

if test_name.ends_with(".diff") {
let trimmed = test_name.trim_end_matches(".diff");
let test_against = format!("{}.after.mir", trimmed);
from_file = format!("{}.before.mir", trimmed);
expected_file = test_name.to_string();
assert!(
test_names.next().is_none(),
"two mir pass names specified for MIR diff"
);
to_file = Some(test_against);
} else if let Some(first_pass) = test_names.next() {
let second_pass = test_names.next().unwrap();
assert!(
test_names.next().is_none(),
"three mir pass names specified for MIR diff"
);
expected_file = format!("{}.{}-{}.diff", test_name, first_pass, second_pass);
let second_file = format!("{}.{}.mir", test_name, second_pass);
from_file = format!("{}.{}.mir", test_name, first_pass);
to_file = Some(second_file);
} else {
expected_file = test_name.to_string();
from_file = test_name.to_string();
assert!(
test_names.next().is_none(),
"two mir pass names specified for MIR dump"
);
to_file = None;
};
let expected_file = test_dir.join(expected_file);

let dumped_string = if let Some(after) = to_file {
let before = self.get_mir_dump_dir().join(from_file);
let after = self.get_mir_dump_dir().join(after);
debug!(
"comparing the contents of: {} with {}",
@@ -3166,7 +3199,7 @@ impl<'test> TestCx<'test> {
} else {
let mut output_file = PathBuf::new();
output_file.push(self.get_mir_dump_dir());
output_file.push(test_name);
output_file.push(&from_file);
debug!(
"comparing the contents of: {} with {}",
output_file.display(),
@@ -3179,7 +3212,7 @@ impl<'test> TestCx<'test> {
output_file.parent().unwrap().display()
);
}
self.check_mir_test_timestamp(test_name, &output_file);
self.check_mir_test_timestamp(&from_file, &output_file);
let dumped_string = fs::read_to_string(&output_file).unwrap();
self.normalize_output(&dumped_string, &[])
};