Auto merge of #95382 - Dylan-DPC:rollup-bebyfd1, r=Dylan-DPC

Rollup of 5 pull requests

Successful merges:

 - #94939 (diagnostics: suggest missing comma in bad FRU syntax)
 - #95120 (Implement `apply_switch_int_edge_effects` for backward analyses)
 - #95364 (Add long error explanation for E0667)
 - #95366 (Remove test files with duplicated checksums)
 - #95368 (Fix typo in `String::try_reserve_exact` docs)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-03-27 21:36:42 +00:00
commit 62523045ec
23 changed files with 287 additions and 80 deletions

View file

@ -394,6 +394,7 @@ E0663: include_str!("./error_codes/E0663.md"),
E0664: include_str!("./error_codes/E0664.md"),
E0665: include_str!("./error_codes/E0665.md"),
E0666: include_str!("./error_codes/E0666.md"),
E0667: include_str!("./error_codes/E0667.md"),
E0668: include_str!("./error_codes/E0668.md"),
E0669: include_str!("./error_codes/E0669.md"),
E0670: include_str!("./error_codes/E0670.md"),
@ -633,7 +634,6 @@ E0787: include_str!("./error_codes/E0787.md"),
// attribute
E0640, // infer outlives requirements
// E0645, // trait aliases not finished
E0667, // `impl Trait` in projections
// E0694, // an unknown tool name found in scoped attributes
// E0702, // replaced with a generic attribute input check
// E0707, // multiple elided lifetimes used in arguments of `async fn`

View file

@ -0,0 +1,18 @@
`impl Trait` is not allowed in path parameters.
Erroneous code example:
```compile_fail,E0667
fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
x.next().unwrap()
}
```
You cannot use `impl Trait` in path parameters. If you want something
equivalent, you can do this instead:
```
fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok!
x.next().unwrap()
}
```

View file

@ -45,6 +45,7 @@ use std::{iter, mem, option};
use self::graph_cyclic_cache::GraphIsCyclicCache;
use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;
use self::switch_sources::{SwitchSourceCache, SwitchSources};
pub mod coverage;
mod generic_graph;
@ -58,6 +59,7 @@ mod predecessors;
pub mod pretty;
mod query;
pub mod spanview;
mod switch_sources;
pub mod tcx;
pub mod terminator;
pub use terminator::*;
@ -296,6 +298,7 @@ pub struct Body<'tcx> {
pub is_polymorphic: bool,
predecessor_cache: PredecessorCache,
switch_source_cache: SwitchSourceCache,
is_cyclic: GraphIsCyclicCache,
pub tainted_by_errors: Option<ErrorGuaranteed>,
@ -344,6 +347,7 @@ impl<'tcx> Body<'tcx> {
required_consts: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
switch_source_cache: SwitchSourceCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
tainted_by_errors,
};
@ -372,6 +376,7 @@ impl<'tcx> Body<'tcx> {
var_debug_info: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
switch_source_cache: SwitchSourceCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
tainted_by_errors: None,
};
@ -392,6 +397,7 @@ impl<'tcx> Body<'tcx> {
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
// invalidate the caches.
self.predecessor_cache.invalidate();
self.switch_source_cache.invalidate();
self.is_cyclic.invalidate();
&mut self.basic_blocks
}
@ -401,6 +407,7 @@ impl<'tcx> Body<'tcx> {
&mut self,
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
self.predecessor_cache.invalidate();
self.switch_source_cache.invalidate();
self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls)
}
@ -414,6 +421,7 @@ impl<'tcx> Body<'tcx> {
&mut Vec<VarDebugInfo<'tcx>>,
) {
self.predecessor_cache.invalidate();
self.switch_source_cache.invalidate();
self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
}
@ -541,6 +549,11 @@ impl<'tcx> Body<'tcx> {
self.predecessor_cache.compute(&self.basic_blocks)
}
#[inline]
pub fn switch_sources(&self) -> &SwitchSources {
self.switch_source_cache.compute(&self.basic_blocks)
}
#[inline]
pub fn dominators(&self) -> Dominators<BasicBlock> {
dominators(self)

View file

@ -0,0 +1,82 @@
//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
//! `Predecessors`/`PredecessorCache`.
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::OnceCell;
use rustc_index::vec::IndexVec;
use rustc_serialize as serialize;
use smallvec::SmallVec;
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
pub type SwitchSources = IndexVec<BasicBlock, IndexVec<BasicBlock, SmallVec<[Option<u128>; 1]>>>;
#[derive(Clone, Debug)]
pub(super) struct SwitchSourceCache {
cache: OnceCell<SwitchSources>,
}
impl SwitchSourceCache {
#[inline]
pub(super) fn new() -> Self {
SwitchSourceCache { cache: OnceCell::new() }
}
/// Invalidates the switch source cache.
#[inline]
pub(super) fn invalidate(&mut self) {
self.cache = OnceCell::new();
}
/// Returns the switch sources for this MIR.
#[inline]
pub(super) fn compute(
&self,
basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
) -> &SwitchSources {
self.cache.get_or_init(|| {
let mut switch_sources = IndexVec::from_elem(
IndexVec::from_elem(SmallVec::new(), basic_blocks),
basic_blocks,
);
for (bb, data) in basic_blocks.iter_enumerated() {
if let Some(Terminator {
kind: TerminatorKind::SwitchInt { targets, .. }, ..
}) = &data.terminator
{
for (value, target) in targets.iter() {
switch_sources[target][bb].push(Some(value));
}
switch_sources[targets.otherwise()][bb].push(None);
}
}
switch_sources
})
}
}
impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
#[inline]
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_unit()
}
}
impl<D: serialize::Decoder> serialize::Decodable<D> for SwitchSourceCache {
#[inline]
fn decode(_: &mut D) -> Self {
Self::new()
}
}
impl<CTX> HashStable<CTX> for SwitchSourceCache {
#[inline]
fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
// do nothing
}
}
TrivialTypeFoldableAndLiftImpls! {
SwitchSourceCache,
}

View file

@ -248,6 +248,7 @@ impl Direction for Backward {
);
propagate(pred, &tmp);
}
mir::TerminatorKind::InlineAsm {
destination: Some(dest), ref operands, ..
} if dest == bb => {
@ -266,6 +267,23 @@ impl Direction for Backward {
propagate(pred, &tmp);
}
mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
pred,
exit_state,
values: &body.switch_sources()[bb][pred],
bb,
propagate: &mut propagate,
effects_applied: false,
};
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
if !applier.effects_applied {
propagate(pred, exit_state)
}
}
// Ignore dead unwinds.
mir::TerminatorKind::Call { cleanup: Some(unwind), .. }
| mir::TerminatorKind::Assert { cleanup: Some(unwind), .. }
@ -286,6 +304,37 @@ impl Direction for Backward {
}
}
struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
pred: BasicBlock,
exit_state: &'a mut D,
values: &'a [Option<u128>],
bb: BasicBlock,
propagate: &'a mut F,
effects_applied: bool,
}
impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, D, F>
where
D: Clone,
F: FnMut(BasicBlock, &D),
{
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied);
let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
let mut tmp = None;
for target in targets {
let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
apply_edge_effect(tmp, target);
(self.propagate)(self.pred, tmp);
}
self.effects_applied = true;
}
}
/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator).
pub struct Forward;
@ -528,7 +577,7 @@ impl Direction for Forward {
}
SwitchInt { ref targets, ref discr, switch_ty: _ } => {
let mut applier = SwitchIntEdgeEffectApplier {
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
exit_state,
targets,
propagate,
@ -537,8 +586,11 @@ impl Direction for Forward {
analysis.apply_switch_int_edge_effects(bb, discr, &mut applier);
let SwitchIntEdgeEffectApplier {
exit_state, mut propagate, effects_applied, ..
let ForwardSwitchIntEdgeEffectsApplier {
exit_state,
mut propagate,
effects_applied,
..
} = applier;
if !effects_applied {
@ -551,7 +603,7 @@ impl Direction for Forward {
}
}
struct SwitchIntEdgeEffectApplier<'a, D, F> {
struct ForwardSwitchIntEdgeEffectsApplier<'a, D, F> {
exit_state: &'a mut D,
targets: &'a SwitchTargets,
propagate: F,
@ -559,7 +611,7 @@ struct SwitchIntEdgeEffectApplier<'a, D, F> {
effects_applied: bool,
}
impl<D, F> super::SwitchIntEdgeEffects<D> for SwitchIntEdgeEffectApplier<'_, D, F>
impl<D, F> super::SwitchIntEdgeEffects<D> for ForwardSwitchIntEdgeEffectsApplier<'_, D, F>
where
D: Clone,
F: FnMut(BasicBlock, &D),

View file

@ -234,8 +234,6 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the
/// engine doesn't need to clone the exit state for a block unless
/// `SwitchIntEdgeEffects::apply` is actually called.
///
/// FIXME: This class of effects is not supported for backward dataflow analyses.
fn apply_switch_int_edge_effects(
&self,
_block: BasicBlock,

View file

@ -28,7 +28,7 @@ pub use self::drop_flag_effects::{
pub use self::framework::{
fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
ResultsRefCursor, ResultsVisitable, ResultsVisitor,
ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
};
use self::move_paths::MoveData;

View file

@ -32,6 +32,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, HirId, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@ -1556,7 +1557,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if inaccessible_remaining_fields {
self.report_inaccessible_fields(adt_ty, span);
} else {
self.report_missing_fields(adt_ty, span, remaining_fields);
self.report_missing_fields(
adt_ty,
span,
remaining_fields,
variant,
ast_fields,
substs,
);
}
}
}
@ -1590,6 +1598,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
adt_ty: Ty<'tcx>,
span: Span,
remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
substs: SubstsRef<'tcx>,
) {
let len = remaining_fields.len();
@ -1615,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
struct_span_err!(
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0063,
@ -1624,9 +1635,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
remaining_fields_names,
truncated_fields_error,
adt_ty
)
.span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error))
.emit();
);
err.span_label(
span,
format!("missing {}{}", remaining_fields_names, truncated_fields_error),
);
// If the last field is a range literal, but it isn't supposed to be, then they probably
// meant to use functional update syntax.
//
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
if let Some((
last,
ExprKind::Struct(
QPath::LangItem(LangItem::Range, ..),
&[ref range_start, ref range_end],
_,
),
)) = ast_fields.last().map(|last| (last, &last.expr.kind)) &&
let variant_field =
variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) &&
let range_def_id = self.tcx.lang_items().range_struct() &&
variant_field
.and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
.map(|adt| adt.did())
!= range_def_id
{
let instead = self
.tcx
.sess
.source_map()
.span_to_snippet(range_end.expr.span)
.map(|s| format!(" from `{s}`"))
.unwrap_or(String::new());
err.span_suggestion(
range_start.span.shrink_to_hi(),
&format!("to set the remaining fields{instead}, separate the last named field with a comma"),
",".to_string(),
Applicability::MaybeIncorrect,
);
}
err.emit();
}
/// Report an error for a struct field expression when there are invisible fields.

View file

@ -1038,7 +1038,7 @@ impl String {
}
/// Tries to reserve the minimum capacity for exactly `additional` more elements to
/// be inserted in the given `String`. After calling `reserve_exact`,
/// be inserted in the given `String`. After calling `try_reserve_exact`,
/// capacity will be greater than or equal to `self.len() + additional`.
/// Does nothing if the capacity is already sufficient.
///

View file

@ -1,9 +0,0 @@
#![crate_name = "anonexternmod"]
#![feature(rustc_private)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t;
}

View file

@ -1,37 +0,0 @@
#![crate_name = "foreign_lib"]
#![feature(rustc_private)]
pub mod rustrt {
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t;
}
}
pub mod rustrt2 {
extern crate libc;
extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t;
}
}
pub mod rustrt3 {
// Different type, but same ABI (on all supported platforms).
// Ensures that we don't ICE or trigger LLVM asserts when
// importing the same symbol under different types.
// See https://github.com/rust-lang/rust/issues/32740.
extern "C" {
pub fn rust_get_test_int() -> *const u8;
}
}
pub fn local_uses() {
unsafe {
let x = rustrt::rust_get_test_int();
assert_eq!(x, rustrt2::rust_get_test_int());
assert_eq!(x as *const _, rustrt3::rust_get_test_int());
}
}

View file

@ -1,9 +0,0 @@
#![crate_name = "anonexternmod"]
#![feature(rustc_private)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t;
}

View file

@ -1,3 +0,0 @@
pub fn foo(x: &usize) -> usize {
*x
}

View file

@ -1,6 +0,0 @@
pub extern "C" fn bar() {
}
pub const foopy: &'static str = "hi there";
pub const uint_val: usize = 12;
pub const uint_expr: usize = (1 << uint_val) - 1;

View file

@ -30,4 +30,5 @@ LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0223`.
Some errors have detailed explanations: E0223, E0667.
For more information about an error, try `rustc --explain E0223`.

View file

@ -6,3 +6,4 @@ LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
error: aborting due to previous error
For more information about this error, try `rustc --explain E0667`.

View file

@ -0,0 +1,16 @@
// run-rustfix
#[derive(Debug, Default, Eq, PartialEq)]
struct A {
b: u32,
c: u64,
d: usize,
}
fn main() {
let q = A { c: 5, .. Default::default() };
//~^ ERROR mismatched types
//~| ERROR missing fields
//~| HELP separate the last named field with a comma
let r = A { c: 5, .. Default::default() };
assert_eq!(q, r);
}

View file

@ -0,0 +1,16 @@
// run-rustfix
#[derive(Debug, Default, Eq, PartialEq)]
struct A {
b: u32,
c: u64,
d: usize,
}
fn main() {
let q = A { c: 5 .. Default::default() };
//~^ ERROR mismatched types
//~| ERROR missing fields
//~| HELP separate the last named field with a comma
let r = A { c: 5, .. Default::default() };
assert_eq!(q, r);
}

View file

@ -0,0 +1,24 @@
error[E0308]: mismatched types
--> $DIR/struct-record-suggestion.rs:10:20
|
LL | let q = A { c: 5 .. Default::default() };
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
|
= note: expected type `u64`
found struct `std::ops::Range<{integer}>`
error[E0063]: missing fields `b` and `d` in initializer of `A`
--> $DIR/struct-record-suggestion.rs:10:13
|
LL | let q = A { c: 5 .. Default::default() };
| ^ missing `b` and `d`
|
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
LL | let q = A { c: 5, .. Default::default() };
| +
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0063, E0308.
For more information about an error, try `rustc --explain E0063`.