Auto merge of #94392 - matthiaskrgr:rollup-npscf95, r=matthiaskrgr

Rollup of 5 pull requests

Successful merges:

 - #93400 (Do not suggest using a const parameter when there are bounds on an unused type parameter)
 - #93982 (Provide extra note if synthetic type args are specified)
 - #94087 (Remove unused `unsound_ignore_borrow_on_drop`)
 - #94235 (chalk: Fix wrong debrujin index in opaque type handling.)
 - #94306 (Avoid exhausting stack space in dominator compression)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-02-26 07:00:33 +00:00
commit d5a9bc9476
17 changed files with 268 additions and 117 deletions

View File

@ -241,9 +241,19 @@ fn compress(
v: PreorderIndex,
) {
assert!(is_processed(v, lastlinked));
let u = ancestor[v];
if is_processed(u, lastlinked) {
compress(ancestor, lastlinked, semi, label, u);
// Compute the processed list of ancestors
//
// We use a heap stack here to avoid recursing too deeply, exhausting the
// stack space.
let mut stack: smallvec::SmallVec<[_; 8]> = smallvec::smallvec![v];
let mut u = ancestor[v];
while is_processed(u, lastlinked) {
stack.push(u);
u = ancestor[u];
}
// Then in reverse order, popping the stack
for &[v, u] in stack.array_windows().rev() {
if semi[label[u]] < semi[label[v]] {
label[v] = label[u];
}

View File

@ -10,38 +10,11 @@
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
/// immovable generators.
pub struct MaybeBorrowedLocals {
ignore_borrow_on_drop: bool,
}
pub struct MaybeBorrowedLocals;
impl MaybeBorrowedLocals {
/// A dataflow analysis that records whether a pointer or reference exists that may alias the
/// given local.
pub fn all_borrows() -> Self {
MaybeBorrowedLocals { ignore_borrow_on_drop: false }
}
}
impl MaybeBorrowedLocals {
/// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
///
/// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
/// parameter. In the general case, a drop impl could launder that reference into the
/// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
/// dropped local. We are not yet willing to declare this particular case UB, so we must treat
/// all dropped locals as mutably borrowed for now. See discussion on [#61069].
///
/// In some contexts, we know that this borrow will never occur. For example, during
/// const-eval, custom drop glue cannot be run. Code that calls this should document the
/// assumptions that justify ignoring `Drop` terminators in this way.
///
/// [#61069]: https://github.com/rust-lang/rust/pull/61069
pub fn unsound_ignore_borrow_on_drop(self) -> Self {
MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
}
fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
TransferFunction { trans }
}
}
@ -92,7 +65,6 @@ fn call_return_effect(
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
struct TransferFunction<'a, T> {
trans: &'a mut T,
ignore_borrow_on_drop: bool,
}
impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
@ -146,10 +118,15 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
match terminator.kind {
mir::TerminatorKind::Drop { place: dropped_place, .. }
| mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
// See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
if !self.ignore_borrow_on_drop {
self.trans.gen(dropped_place.local);
}
// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut
// self` as a parameter. In the general case, a drop impl could launder that
// reference into the surrounding environment through a raw pointer, thus creating
// a valid `*mut` pointing to the dropped local. We are not yet willing to declare
// this particular case UB, so we must treat all dropped locals as mutably borrowed
// for now. See discussion on [#61069].
//
// [#61069]: https://github.com/rust-lang/rust/pull/61069
self.trans.gen(dropped_place.local);
}
TerminatorKind::Abort

View File

@ -463,10 +463,8 @@ fn locals_live_across_suspend_points<'tcx>(
// Calculate the MIR locals which have been previously
// borrowed (even if they are still active).
let borrowed_locals_results = MaybeBorrowedLocals::all_borrows()
.into_engine(tcx, body_ref)
.pass_name("generator")
.iterate_to_fixpoint();
let borrowed_locals_results =
MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
let mut borrowed_locals_cursor =
rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);

View File

@ -8,7 +8,7 @@
use rustc_middle::traits::ChalkRustInterner as RustInterner;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, AssocItemContainer, AssocKind, Ty, TyCtxt, TypeFoldable};
use rustc_ast::ast;
use rustc_attr as attr;
@ -482,21 +482,11 @@ fn opaque_ty_data(
.iter()
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
.map(|bound| {
bound.fold_with(&mut ty::fold::BottomUpFolder {
bound.fold_with(&mut ReplaceOpaqueTyFolder {
tcx: self.interner.tcx,
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = *ty.kind() {
if def_id == opaque_ty_id.0 && substs == identity_substs {
return self.interner.tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy::from(ty::BoundVar::from_u32(0)),
));
}
}
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
opaque_ty_id,
identity_substs,
binder_index: ty::INNERMOST,
})
})
.filter_map(|bound| {
@ -739,3 +729,38 @@ fn binders_for<'tcx>(
}),
)
}
struct ReplaceOpaqueTyFolder<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
identity_substs: SubstsRef<'tcx>,
binder_index: ty::DebruijnIndex,
}
impl<'tcx> ty::TypeFolder<'tcx> for ReplaceOpaqueTyFolder<'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
self.binder_index.shift_in(1);
let t = t.super_fold_with(self);
self.binder_index.shift_out(1);
t
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Opaque(def_id, substs) = *ty.kind() {
if def_id == self.opaque_ty_id.0 && substs == self.identity_substs {
return self.tcx.mk_ty(ty::Bound(
self.binder_index,
ty::BoundTy::from(ty::BoundVar::from_u32(0)),
));
}
}
ty
}
}

View File

@ -323,7 +323,10 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'
ty::Closure(def_id, substs) => {
chalk_ir::TyKind::Closure(chalk_ir::ClosureId(def_id), substs.lower_into(interner))
}
ty::Generator(_def_id, _substs, _) => unimplemented!(),
ty::Generator(def_id, substs, _) => chalk_ir::TyKind::Generator(
chalk_ir::GeneratorId(def_id),
substs.lower_into(interner),
),
ty::GeneratorWitness(_) => unimplemented!(),
ty::Never => chalk_ir::TyKind::Never,
ty::Tuple(types) => {

View File

@ -512,62 +512,70 @@ pub(crate) fn check_generic_arg_count(
explicit_late_bound == ExplicitLateBound::Yes,
);
let mut check_types_and_consts =
|expected_min, expected_max, provided, params_offset, args_offset| {
debug!(
?expected_min,
?expected_max,
?provided,
?params_offset,
?args_offset,
"check_types_and_consts"
let mut check_types_and_consts = |expected_min,
expected_max,
expected_max_with_synth,
provided,
params_offset,
args_offset| {
debug!(
?expected_min,
?expected_max,
?provided,
?params_offset,
?args_offset,
"check_types_and_consts"
);
if (expected_min..=expected_max).contains(&provided) {
return true;
}
let num_default_params = expected_max - expected_min;
let gen_args_info = if provided > expected_max {
invalid_args.extend(
gen_args.args[args_offset + expected_max..args_offset + provided]
.iter()
.map(|arg| arg.span()),
);
if (expected_min..=expected_max).contains(&provided) {
return true;
let num_redundant_args = provided - expected_max;
// Provide extra note if synthetic arguments like `impl Trait` are specified.
let synth_provided = provided <= expected_max_with_synth;
GenericArgsInfo::ExcessTypesOrConsts {
num_redundant_args,
num_default_params,
args_offset,
synth_provided,
}
} else {
let num_missing_args = expected_max - provided;
let num_default_params = expected_max - expected_min;
let gen_args_info = if provided > expected_max {
invalid_args.extend(
gen_args.args[args_offset + expected_max..args_offset + provided]
.iter()
.map(|arg| arg.span()),
);
let num_redundant_args = provided - expected_max;
GenericArgsInfo::ExcessTypesOrConsts {
num_redundant_args,
num_default_params,
args_offset,
}
} else {
let num_missing_args = expected_max - provided;
GenericArgsInfo::MissingTypesOrConsts {
num_missing_args,
num_default_params,
args_offset,
}
};
debug!(?gen_args_info);
WrongNumberOfGenericArgs::new(
tcx,
gen_args_info,
seg,
gen_params,
params_offset,
gen_args,
def_id,
)
.diagnostic()
.emit_unless(gen_args.has_err());
false
GenericArgsInfo::MissingTypesOrConsts {
num_missing_args,
num_default_params,
args_offset,
}
};
debug!(?gen_args_info);
WrongNumberOfGenericArgs::new(
tcx,
gen_args_info,
seg,
gen_params,
params_offset,
gen_args,
def_id,
)
.diagnostic()
.emit_unless(gen_args.has_err());
false
};
let args_correct = {
let expected_min = if infer_args {
0
@ -582,6 +590,7 @@ pub(crate) fn check_generic_arg_count(
check_types_and_consts(
expected_min,
param_counts.consts + named_type_param_count,
param_counts.consts + named_type_param_count + synth_type_param_count,
gen_args.num_generic_params(),
param_counts.lifetimes + has_self as usize,
gen_args.num_lifetime_params(),

View File

@ -31,6 +31,7 @@
use std::convert::TryInto;
use std::iter;
use std::lazy::Lazy;
use std::ops::ControlFlow;
/// Helper type of a temporary returned by `.for_item(...)`.
@ -1720,8 +1721,29 @@ fn check_variances_for_type_defn<'tcx>(
identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
// Lazily calculated because it is only needed in case of an error.
let explicitly_bounded_params = Lazy::new(|| {
let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
hir_generics
.where_clause
.predicates
.iter()
.filter_map(|predicate| match predicate {
hir::WherePredicate::BoundPredicate(predicate) => {
match icx.to_ty(predicate.bounded_ty).kind() {
ty::Param(data) => Some(Parameter(data.index)),
_ => None,
}
}
_ => None,
})
.collect::<FxHashSet<_>>()
});
for (index, _) in variances.iter().enumerate() {
if constrained_parameters.contains(&Parameter(index as u32)) {
let parameter = Parameter(index as u32);
if constrained_parameters.contains(&parameter) {
continue;
}
@ -1730,13 +1752,19 @@ fn check_variances_for_type_defn<'tcx>(
match param.name {
hir::ParamName::Error => {}
_ => {
report_bivariance(tcx, param);
let has_explicit_bounds =
!param.bounds.is_empty() || explicitly_bounded_params.contains(&parameter);
report_bivariance(tcx, param, has_explicit_bounds);
}
}
}
}
fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> ErrorReported {
fn report_bivariance(
tcx: TyCtxt<'_>,
param: &rustc_hir::GenericParam<'_>,
has_explicit_bounds: bool,
) -> ErrorReported {
let span = param.span;
let param_name = param.name.ident().name;
let mut err = error_392(tcx, span, param_name);
@ -1754,7 +1782,7 @@ fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> Er
};
err.help(&msg);
if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
err.help(&format!(
"if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
param_name

View File

@ -68,6 +68,7 @@
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
#![feature(once_cell)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]

View File

@ -84,6 +84,9 @@ pub enum GenericArgsInfo {
// us infer the position of type and const generic arguments
// in the angle brackets
args_offset: usize,
// if synthetic type arguments (e.g. `impl Trait`) are specified
synth_provided: bool,
},
}
@ -254,6 +257,13 @@ fn get_num_default_params(&self) -> usize {
}
}
fn is_synth_provided(&self) -> bool {
match self.gen_args_info {
ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
_ => false,
}
}
// Helper function to choose a quantifier word for the number of expected arguments
// and to give a bound for the number of expected arguments
fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
@ -780,6 +790,15 @@ fn show_definition(&self, err: &mut Diagnostic) {
err.span_note(spans, &msg);
}
/// Add note if `impl Trait` is explicitly specified.
fn note_synth_provided(&self, err: &mut Diagnostic) {
if !self.is_synth_provided() {
return;
}
err.note("`impl Trait` cannot be explicitly specified as a generic argument");
}
}
impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
@ -797,6 +816,7 @@ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorReported> {
self.notify(&mut err);
self.suggest(&mut err);
self.show_definition(&mut err);
self.note_synth_provided(&mut err);
err
}

View File

@ -0,0 +1,9 @@
// check-fail
// known-bug
// compile-flags: -Z chalk --edition=2021
fn main() -> () {}
async fn foo(x: u32) -> u32 {
x
}

View File

@ -0,0 +1,39 @@
error[E0277]: the trait bound `[static generator@$DIR/async.rs:7:29: 9:2]: Generator<ResumeTy>` is not satisfied
--> $DIR/async.rs:7:29
|
LL | async fn foo(x: u32) -> u32 {
| _____________________________^
LL | | x
LL | | }
| |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]`
|
note: required by a bound in `from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `from_generator`
error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator<ResumeTy>>::Yield == ()` is not satisfied
--> $DIR/async.rs:7:29
|
LL | async fn foo(x: u32) -> u32 {
| _____________________________^
LL | | x
LL | | }
| |_^
|
note: required by a bound in `from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `from_generator`
error[E0280]: the requirement `<impl Future<Output = [async output]> as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:25
|
LL | async fn foo(x: u32) -> u32 {
| ^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -11,6 +11,7 @@ note: function defined here, with 1 generic parameter: `T`
|
LL | fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
| ^^^ -
= note: `impl Trait` cannot be explicitly specified as a generic argument
error: aborting due to previous error

View File

@ -5,7 +5,6 @@ LL | struct Foo<T> where T: Copy;
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to previous error

View File

@ -22,7 +22,6 @@ LL | struct Foo<T: ?Hash> { }
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -16,4 +16,13 @@ enum ListCell<T> {
Nil
}
struct WithBounds<T: Sized> {}
//~^ ERROR parameter `T` is never used
struct WithWhereBounds<T> where T: Sized {}
//~^ ERROR parameter `T` is never used
struct WithOutlivesBounds<T: 'static> {}
//~^ ERROR parameter `T` is never used
fn main() {}

View File

@ -25,6 +25,30 @@ LL | enum ListCell<T> {
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 3 previous errors
error[E0392]: parameter `T` is never used
--> $DIR/variance-unused-type-param.rs:19:19
|
LL | struct WithBounds<T: Sized> {}
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: parameter `T` is never used
--> $DIR/variance-unused-type-param.rs:22:24
|
LL | struct WithWhereBounds<T> where T: Sized {}
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: parameter `T` is never used
--> $DIR/variance-unused-type-param.rs:25:27
|
LL | struct WithOutlivesBounds<T: 'static> {}
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0392`.

View File

@ -10,8 +10,8 @@
// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
"E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519",
"E0523", "E0554", "E0640", "E0717", "E0729",
"E0279", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519", "E0523",
"E0554", "E0640", "E0717", "E0729",
];
// Some error codes don't have any tests apparently...