Skip to content
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

[beta] Beta rollup #89527

Merged
merged 14 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -871,9 +871,9 @@ dependencies = [

[[package]]
name = "curl-sys"
version = "0.4.45+curl-7.78.0"
version = "0.4.49+curl-7.79.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de9e5a72b1c744eb5dd20b2be4d7eb84625070bb5c4ab9b347b70464ab1e62eb"
checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483"
dependencies = [
"cc",
"libc",
Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1373,14 +1373,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
// `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
// See #78991 for an investigation of treating macros in this position
// as statements, rather than expressions, during parsing.
if let StmtKind::Expr(expr) = &stmt.kind {
if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) {
let res = match &stmt.kind {
StmtKind::Expr(expr)
if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
{
self.cx.current_expansion.is_trailing_mac = true;
// Don't use `assign_id` for this statement - it may get removed
// entirely due to a `#[cfg]` on the contained expression
noop_flat_map_stmt(stmt, self)
}
}

let res = assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self));

_ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
};
self.cx.current_expansion.is_trailing_mac = false;
res
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir/src/transform/remove_zsts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub struct RemoveZsts;

impl<'tcx> MirPass<'tcx> for RemoveZsts {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Avoid query cycles (generators require optimized MIR for layout).
if tcx.type_of(body.source.def_id()).is_generator() {
return;
}
let param_env = tcx.param_env(body.source.def_id());
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks.iter_mut() {
Expand Down
38 changes: 28 additions & 10 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,15 +388,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
// to make sure we don't forget to fold the substs regardless.

match *ty.kind() {
ty::Opaque(def_id, substs) => {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),

Reveal::All => {
// N.b. there is an assumption here all this code can handle
// escaping bound vars.

let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
let obligation = Obligation::with_depth(
Expand Down Expand Up @@ -844,6 +844,10 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Ty<'tcx>>, InProgress> {
let infcx = selcx.infcx();
// Don't use the projection cache in intercrate mode -
// the `infcx` may be re-used between intercrate in non-intercrate
// mode, which could lead to using incorrect cache results.
let use_cache = !selcx.is_intercrate();

let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
let cache_key = ProjectionCacheKey::new(projection_ty);
Expand All @@ -856,7 +860,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
// bounds. It might be the case that we want two distinct caches,
// or else another kind of cache entry.

let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
let cache_result = if use_cache {
infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
} else {
Ok(())
};
match cache_result {
Ok(()) => debug!("no cache"),
Err(ProjectionCacheEntry::Ambiguous) => {
Expand All @@ -881,7 +889,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
// should ensure that, unless this happens within a snapshot that's
// rolled back, fulfillment or evaluation will notice the cycle.

infcx.inner.borrow_mut().projection_cache().recur(cache_key);
if use_cache {
infcx.inner.borrow_mut().projection_cache().recur(cache_key);
}
return Err(InProgress);
}
Err(ProjectionCacheEntry::Recur) => {
Expand Down Expand Up @@ -963,20 +973,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
.map_or(false, |res| res.must_apply_considering_regions())
});

infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
}
obligations.extend(result.obligations);
Ok(Some(result.value))
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
debug!(?projected_ty, "opt_normalize_projection_type: no progress");
let result = Normalized { value: projected_ty, obligations: vec![] };
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
}
// No need to extend `obligations`.
Ok(Some(result.value))
}
Err(ProjectionTyError::TooManyCandidates) => {
debug!("opt_normalize_projection_type: too many candidates");
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
if use_cache {
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
}
Ok(None)
}
Err(ProjectionTyError::TraitSelectionError(_)) => {
Expand All @@ -986,7 +1002,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
// Trait`, which when processed will cause the error to be
// reported later

infcx.inner.borrow_mut().projection_cache().error(cache_key);
if use_cache {
infcx.inner.borrow_mut().projection_cache().error(cache_key);
}
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations);
Ok(Some(result.value))
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {

// Wrap this in a closure so we don't accidentally return from the outer function
let res = (|| match *ty.kind() {
ty::Opaque(def_id, substs) => {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),

Reveal::All => {
// N.b. there is an assumption here all this code can handle
// escaping bound vars.

let substs = substs.super_fold_with(self);
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.tcx
}

pub fn is_intercrate(&self) -> bool {
self.intercrate
}

/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
match pred.constness {
Expand Down Expand Up @@ -982,6 +986,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
return None;
}

let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_ref), tcx) {
Expand All @@ -1004,6 +1016,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}

// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
return;
}

if self.can_use_global_caches(param_env) {
if !trait_ref.needs_infer() {
debug!(?trait_ref, ?result, "insert_evaluation_cache global");
Expand Down Expand Up @@ -1185,6 +1205,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
return None;
}
let tcx = self.tcx();
let pred = &cache_fresh_trait_pred.skip_binder();
let trait_ref = pred.trait_ref;
Expand Down Expand Up @@ -1221,6 +1248,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&self,
result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
) -> bool {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate {
return false;
}
match result {
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(),
_ => true,
Expand Down
76 changes: 58 additions & 18 deletions compiler/rustc_ty_utils/src/needs_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::Limit;
Expand All @@ -12,7 +13,8 @@ type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;

fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
let adt_fields =
move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());

// If we don't know a type doesn't need drop, for example if it's a type
// parameter without a `Copy` bound, then we conservatively return that it
// needs drop.
Expand All @@ -25,8 +27,9 @@ fn has_significant_drop_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
let significant_drop_fields =
move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
};
let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
.next()
.is_some();
Expand Down Expand Up @@ -71,7 +74,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {

impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
where
F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
I: Iterator<Item = Ty<'tcx>>,
{
type Item = NeedsDropResult<Ty<'tcx>>;
Expand Down Expand Up @@ -135,7 +138,7 @@ where
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
// impl then check whether the field types need `Drop`.
ty::Adt(adt_def, substs) => {
let tys = match (self.adt_components)(adt_def) {
let tys = match (self.adt_components)(adt_def, substs) {
Err(e) => return Some(Err(e)),
Ok(tys) => tys,
};
Expand Down Expand Up @@ -168,22 +171,44 @@ where
}
}

enum DtorType {
/// Type has a `Drop` but it is considered insignificant.
/// Check the query `adt_significant_drop_tys` for understanding
/// "significant" / "insignificant".
Insignificant,

/// Type has a `Drop` implentation.
Significant,
}

// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
// ADT has a destructor or if the ADT only has a significant destructor. For
// understanding significant destructor look at `adt_significant_drop_tys`.
fn adt_drop_tys_helper(
tcx: TyCtxt<'_>,
fn adt_drop_tys_helper<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_components = move |adt_def: &ty::AdtDef| {
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
} else if adt_has_dtor(adt_def) {
debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
return Err(AlwaysRequiresDrop);
} else if let Some(dtor_info) = adt_has_dtor(adt_def) {
match dtor_info {
DtorType::Significant => {
debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
return Err(AlwaysRequiresDrop);
}
DtorType::Insignificant => {
debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);

// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
}
}
} else if adt_def.is_union() {
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
Expand All @@ -201,7 +226,10 @@ fn adt_drop_tys_helper(
}

fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some();
// This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
// significant.
let adt_has_dtor =
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}

Expand All @@ -210,10 +238,22 @@ fn adt_significant_drop_tys(
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_has_dtor = |adt_def: &ty::AdtDef| {
adt_def
.destructor(tcx)
.map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor))
.unwrap_or(false)
let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
if is_marked_insig {
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
// a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
// outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
// `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
Some(DtorType::Insignificant)
} else if adt_def.destructor(tcx).is_some() {
// There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
// significant.
Some(DtorType::Significant)
} else {
// No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
// treat this as the simple case of Drop impl for type.
None
}
};
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
Expand Down
Loading