Skip to content

Commit

Permalink
Auto merge of #92927 - matthiaskrgr:rollup-pgzwfcm, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 8 pull requests

Successful merges:

 - #92747 (Simplification of BigNum::bit_length)
 - #92767 (Use the new language identifier for Rust in the PDB debug format)
 - #92775 (Inline std::os::unix::ffi::OsStringExt methods)
 - #92863 (Remove `&mut` from `io::read_to_string` signature)
 - #92865 (Ignore static lifetimes for GATs outlives lint)
 - #92873 (Generate more precise generator names)
 - #92879 (Add Sync bound to allocator parameter in vec::IntoIter)
 - #92892 (Do not fail evaluation in const blocks)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 15, 2022
2 parents 38c22af + 539175c commit b13a5bf
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 70 deletions.
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,12 +519,18 @@ fn push_unqualified_item_name(
output.push_str(tcx.crate_name(def_id.krate).as_str());
}
DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
let key = match tcx.generator_kind(def_id).unwrap() {
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
hir::GeneratorKind::Gen => "generator",
};
// Generators look like closures, but we want to treat them differently
// in the debug info.
if cpp_like_debuginfo(tcx) {
write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
write!(output, "{}${}", key, disambiguated_data.disambiguator).unwrap();
} else {
write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
write!(output, "{{{}#{}}}", key, disambiguated_data.disambiguator).unwrap();
}
}
_ => match disambiguated_data.data.name() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let body = self.tcx.hir().body(anon_const.body);

// Create a new function context.
let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);

let ty = fcx.check_expr_with_expectation(&body.value, expected);
Expand Down
94 changes: 48 additions & 46 deletions compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::{self, RegionckMode};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
Expand Down Expand Up @@ -332,6 +333,12 @@ fn check_gat_where_clauses(
// outlives relationship (`Self: 'a`), then we want to ensure that is
// reflected in a where clause on the GAT itself.
for (region, region_idx) in &regions {
// Ignore `'static` lifetimes for the purpose of this lint: it's
// because we know it outlives everything and so doesn't give meaninful
// clues
if let ty::ReStatic = region {
continue;
}
for (ty, ty_idx) in &types {
// In our example, requires that Self: 'a
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
Expand Down Expand Up @@ -371,10 +378,19 @@ fn check_gat_where_clauses(
// outlives relationship, then we want to ensure that is
// reflected in a where clause on the GAT itself.
for (region_a, region_a_idx) in &regions {
// Ignore `'static` lifetimes for the purpose of this lint: it's
// because we know it outlives everything and so doesn't give meaninful
// clues
if let ty::ReStatic = region_a {
continue;
}
for (region_b, region_b_idx) in &regions {
if region_a == region_b {
continue;
}
if let ty::ReStatic = region_b {
continue;
}

if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
debug!(?region_a_idx, ?region_b_idx);
Expand Down Expand Up @@ -502,8 +518,6 @@ fn check_gat_where_clauses(
}
}

// FIXME(jackh726): refactor some of the shared logic between the two functions below

/// Given a known `param_env` and a set of well formed types, can we prove that
/// `ty` outlives `region`.
fn ty_known_to_outlive<'tcx>(
Expand All @@ -514,54 +528,49 @@ fn ty_known_to_outlive<'tcx>(
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
// region constraints get added and solved there and we need to test each
// call individually.
tcx.infer_ctxt().enter(|infcx| {
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
outlives_environment.save_implied_bounds(id);
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();

let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);

let sup_type = ty;
let sub_region = region;

let origin = SubregionOrigin::from_obligation_cause(&cause, || {
infer::RelateParamBound(cause.span, sup_type, None)
});

resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
let outlives = &mut TypeOutlives::new(
&infcx,
infcx,
tcx,
&region_bound_pairs,
region_bound_pairs,
Some(infcx.tcx.lifetimes.re_root_empty),
param_env,
);
outlives.type_must_outlive(origin, sup_type, sub_region);

let errors = infcx.resolve_regions(
id.expect_owner().to_def_id(),
&outlives_environment,
RegionckMode::default(),
);

debug!(?errors, "errors");

// If we were able to prove that the type outlives the region without
// an error, it must be because of the implied or explicit bounds...
errors.is_empty()
outlives.type_must_outlive(origin, ty, region);
})
}

/// Given a known `param_env` and a set of well formed types, can we prove that
/// `region_a` outlives `region_b`
fn region_known_to_outlive<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
wf_tys: &FxHashSet<Ty<'tcx>>,
region_a: ty::Region<'tcx>,
region_b: ty::Region<'tcx>,
) -> bool {
resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| {
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
let origin = infer::RelateRegionParamBound(DUMMY_SP);
// `region_a: region_b` -> `region_b <= region_a`
infcx.push_sub_region_constraint(origin, region_b, region_a);
})
}

/// Given a known `param_env` and a set of well formed types, set up an
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
/// to be tested), then resolve region and return errors
fn resolve_regions_with_wf_tys<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
wf_tys: &FxHashSet<Ty<'tcx>>,
add_constraints: impl for<'a> FnOnce(
&'a InferCtxt<'a, 'tcx>,
&'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
),
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
// region constraints get added and solved there and we need to test each
Expand All @@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>(
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
outlives_environment.save_implied_bounds(id);
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();

let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);

let origin = SubregionOrigin::from_obligation_cause(&cause, || {
infer::RelateRegionParamBound(cause.span)
});

use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
// `region_a: region_b` -> `region_b <= region_a`
(&infcx).push_sub_region_constraint(origin, region_b, region_a);
add_constraints(&infcx, region_bound_pairs);

let errors = infcx.resolve_regions(
id.expect_owner().to_def_id(),
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> Iterator for IntoIter<T, A> {
Expand Down
21 changes: 6 additions & 15 deletions library/core/src/num/bignum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,24 +158,15 @@ macro_rules! define_bignum {
/// Returns the number of bits necessary to represent this value. Note that zero
/// is considered to need 0 bits.
pub fn bit_length(&self) -> usize {
// Skip over the most significant digits which are zero.
let digitbits = <$ty>::BITS as usize;
let digits = self.digits();
let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
let end = digits.len() - zeros;
let nonzero = &digits[..end];

if nonzero.is_empty() {
// Find the most significant non-zero digit.
let msd = digits.iter().rposition(|&x| x != 0);
match msd {
Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
// There are no non-zero digits, i.e., the number is zero.
return 0;
}
// This could be optimized with leading_zeros() and bit shifts, but that's
// probably not worth the hassle.
let digitbits = <$ty>::BITS as usize;
let mut i = nonzero.len() * digitbits - 1;
while self.get_bit(i) == 0 {
i -= 1;
_ => 0,
}
i + 1
}

/// Adds `other` to itself and returns its own mutable reference.
Expand Down
35 changes: 35 additions & 0 deletions library/core/tests/num/bignum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::num::bignum::tests::Big8x3 as Big;
use core::num::bignum::Big32x40;

#[test]
#[should_panic]
Expand Down Expand Up @@ -215,6 +216,16 @@ fn test_get_bit_out_of_range() {

#[test]
fn test_bit_length() {
for i in 0..8 * 3 {
// 010000...000
assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1);
}
for i in 1..8 * 3 - 1 {
// 010000...001
assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1);
// 110000...000
assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2);
}
assert_eq!(Big::from_small(0).bit_length(), 0);
assert_eq!(Big::from_small(1).bit_length(), 1);
assert_eq!(Big::from_small(5).bit_length(), 3);
Expand All @@ -223,6 +234,30 @@ fn test_bit_length() {
assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
}

#[test]
fn test_bit_length_32x40() {
for i in 0..32 * 40 {
// 010000...000
assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1);
}
for i in 1..32 * 40 - 1 {
// 010000...001
assert_eq!(
Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(),
i + 1
);
// 110000...000
assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2);
}
assert_eq!(Big32x40::from_small(0).bit_length(), 0);
assert_eq!(Big32x40::from_small(1).bit_length(), 1);
assert_eq!(Big32x40::from_small(5).bit_length(), 3);
assert_eq!(Big32x40::from_small(0x18).bit_length(), 5);
assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15);
assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24);
assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64);
}

#[test]
fn test_ord() {
assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,14 +1031,14 @@ pub trait Read {
///
/// # use std::io;
/// fn main() -> io::Result<()> {
/// let stdin = io::read_to_string(&mut io::stdin())?;
/// let stdin = io::read_to_string(io::stdin())?;
/// println!("Stdin was:");
/// println!("{}", stdin);
/// Ok(())
/// }
/// ```
#[unstable(feature = "io_read_to_string", issue = "80218")]
pub fn read_to_string<R: Read>(reader: &mut R) -> Result<String> {
pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
Ok(buf)
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/os/unix/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ pub trait OsStringExt: Sealed {

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
#[inline]
fn from_vec(vec: Vec<u8>) -> OsString {
FromInner::from_inner(Buf { inner: vec })
}
#[inline]
fn into_vec(self) -> Vec<u8> {
self.into_inner().inner
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/async-fn-debug-msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async fn async_fn_test() {
// FIXME: No way to reliably check the filename.

// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator$0"
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn$0"
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/async-fn-debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async fn async_fn_test() {
// FIXME: No way to reliably check the filename.

// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator#0}", scope: [[ASYNC_FN]]
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn#0}", scope: [[ASYNC_FN]]
// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/consts/const-block-const-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![allow(unused)]
#![feature(const_fn_trait_bound, const_trait_impl, inline_const)]

const fn f<T: ~const Drop>(x: T) {}

struct UnconstDrop;

impl Drop for UnconstDrop {
fn drop(&mut self) {}
}

fn main() {
const {
f(UnconstDrop);
//~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied
}
}
21 changes: 21 additions & 0 deletions src/test/ui/consts/const-block-const-bound.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied
--> $DIR/const-block-const-bound.rs:14:11
|
LL | f(UnconstDrop);
| - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop`
| |
| required by a bound introduced by this call
|
note: required by a bound in `f`
--> $DIR/const-block-const-bound.rs:4:15
|
LL | const fn f<T: ~const Drop>(x: T) {}
| ^^^^^^^^^^^ required by this bound in `f`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
LL | fn main() where UnconstDrop: Drop {
| +++++++++++++++++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
13 changes: 13 additions & 0 deletions src/test/ui/generic-associated-types/self-outlives-lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,17 @@ trait Trait: 'static {
fn make_assoc(_: &u32) -> Self::Assoc<'_>;
}

// We ignore `'static` lifetimes for any lints
trait StaticReturn<'a> {
type Y<'b>;
fn foo(&self) -> Self::Y<'static>;
}

// Same as above, but with extra method that takes GAT - just make sure this works
trait StaticReturnAndTakes<'a> {
type Y<'b>;
fn foo(&self) -> Self::Y<'static>;
fn bar<'b>(&self, arg: Self::Y<'b>);
}

fn main() {}

0 comments on commit b13a5bf

Please sign in to comment.