mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #89791 - matthiaskrgr:rollup-1lhxh5b, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #89471 (Use Ancestory to check default fn in const impl instead of comparing idents) - #89643 (Fix inherent impl overlap check.) - #89651 (Add `Poll::ready` and revert stabilization of `task::ready!`) - #89675 (Re-use TypeChecker instead of passing around some of its fields ) - #89710 (Add long explanation for error E0482) - #89756 (Greatly reduce amount of debuginfo compiled for bootstrap itself) - #89760 (Remove hack ignoring unused attributes for stage 0 std) - #89772 (Fix function-names test for GDB 10.1) - #89785 (Fix ICE when compiling nightly std/rustc on beta compiler) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
97e3b30285
@ -89,6 +89,15 @@ gimli.debug = 0
|
||||
miniz_oxide.debug = 0
|
||||
object.debug = 0
|
||||
|
||||
# The only package that ever uses debug builds is bootstrap.
|
||||
# We care a lot about bootstrap's compile times, so don't include debug info for
|
||||
# dependencies, only bootstrap itself.
|
||||
[profile.dev]
|
||||
debug = 0
|
||||
[profile.dev.package]
|
||||
# Only use debuginfo=1 to further reduce compile times.
|
||||
bootstrap.debug = 1
|
||||
|
||||
# We want the RLS to use the version of Cargo that we've got vendored in this
|
||||
# repository to ensure that the same exact version of Cargo is used by both the
|
||||
# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository
|
||||
|
@ -64,7 +64,6 @@ Stabilised APIs
|
||||
- [`VecDeque::shrink_to`]
|
||||
- [`HashMap::shrink_to`]
|
||||
- [`HashSet::shrink_to`]
|
||||
- [`task::ready!`]
|
||||
|
||||
These APIs are now usable in const contexts:
|
||||
|
||||
@ -128,7 +127,6 @@ and related tools.
|
||||
[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to
|
||||
[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to
|
||||
[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to
|
||||
[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html
|
||||
[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
|
||||
[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first
|
||||
[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first
|
||||
|
@ -1153,28 +1153,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
.convert_all(data);
|
||||
}
|
||||
|
||||
/// Convenient wrapper around `relate_tys::relate_types` -- see
|
||||
/// that fn for docs.
|
||||
fn relate_types(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
v: ty::Variance,
|
||||
b: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
relate_tys::relate_types(
|
||||
self.infcx,
|
||||
self.param_env,
|
||||
a,
|
||||
v,
|
||||
b,
|
||||
locations,
|
||||
category,
|
||||
self.borrowck_context,
|
||||
)
|
||||
}
|
||||
|
||||
/// Try to relate `sub <: sup`
|
||||
fn sub_types(
|
||||
&mut self,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
@ -7,48 +7,38 @@ use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::type_check::{BorrowCheckContext, Locations};
|
||||
use crate::type_check::{Locations, TypeChecker};
|
||||
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
///
|
||||
/// - "Covariant" `a <: b`
|
||||
/// - "Invariant" `a == b`
|
||||
/// - "Contravariant" `a :> b`
|
||||
///
|
||||
/// N.B., the type `a` is permitted to have unresolved inference
|
||||
/// variables, but not the type `b`.
|
||||
#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")]
|
||||
pub(super) fn relate_types<'tcx>(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
///
|
||||
/// - "Covariant" `a <: b`
|
||||
/// - "Invariant" `a == b`
|
||||
/// - "Contravariant" `a :> b`
|
||||
///
|
||||
/// N.B., the type `a` is permitted to have unresolved inference
|
||||
/// variables, but not the type `b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn relate_types(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
v: ty::Variance,
|
||||
b: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
|
||||
) -> Fallible<()> {
|
||||
) -> Fallible<()> {
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
NllTypeRelatingDelegate::new(
|
||||
infcx,
|
||||
borrowck_context,
|
||||
param_env,
|
||||
locations,
|
||||
category,
|
||||
UniverseInfo::relate(a, b),
|
||||
),
|
||||
self.infcx,
|
||||
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
|
||||
v,
|
||||
)
|
||||
.relate(a, b)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
|
||||
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
locations: Locations,
|
||||
@ -63,25 +53,24 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
|
||||
impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
universe_info: UniverseInfo<'tcx>,
|
||||
) -> Self {
|
||||
Self { infcx, borrowck_context, param_env, locations, category, universe_info }
|
||||
Self { type_checker, locations, category, universe_info }
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.param_env
|
||||
self.type_checker.param_env
|
||||
}
|
||||
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
||||
let universe = self.infcx.create_next_universe();
|
||||
self.borrowck_context
|
||||
let universe = self.type_checker.infcx.create_next_universe();
|
||||
self.type_checker
|
||||
.borrowck_context
|
||||
.constraints
|
||||
.universe_causes
|
||||
.insert(universe, self.universe_info.clone());
|
||||
@ -90,15 +79,18 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
|
||||
fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall };
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
self.type_checker.infcx.next_nll_region_var(origin)
|
||||
}
|
||||
|
||||
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
|
||||
self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
|
||||
self.type_checker
|
||||
.borrowck_context
|
||||
.constraints
|
||||
.placeholder_region(self.type_checker.infcx, placeholder)
|
||||
}
|
||||
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
self.infcx.next_nll_region_var_in_universe(
|
||||
self.type_checker.infcx.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
universe,
|
||||
)
|
||||
@ -110,15 +102,17 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
) {
|
||||
let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
|
||||
self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
|
||||
self.type_checker.borrowck_context.constraints.outlives_constraints.push(
|
||||
OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
variance_info: info,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// We don't have to worry about the equality of consts during borrow checking
|
||||
|
@ -242,6 +242,7 @@ E0468: include_str!("./error_codes/E0468.md"),
|
||||
E0469: include_str!("./error_codes/E0469.md"),
|
||||
E0477: include_str!("./error_codes/E0477.md"),
|
||||
E0478: include_str!("./error_codes/E0478.md"),
|
||||
E0482: include_str!("./error_codes/E0482.md"),
|
||||
E0491: include_str!("./error_codes/E0491.md"),
|
||||
E0492: include_str!("./error_codes/E0492.md"),
|
||||
E0493: include_str!("./error_codes/E0493.md"),
|
||||
@ -599,7 +600,6 @@ E0785: include_str!("./error_codes/E0785.md"),
|
||||
// E0479, // the type `..` (provided as the value of a type parameter) is...
|
||||
// E0480, // lifetime of method receiver does not outlive the method call
|
||||
// E0481, // lifetime of function argument does not outlive the function call
|
||||
E0482, // lifetime of return value does not outlive the function call
|
||||
// E0483, // lifetime of operand does not outlive the operation
|
||||
// E0484, // reference is not valid at the time of borrow
|
||||
// E0485, // automatically reference is not valid at the time of borrow
|
||||
|
73
compiler/rustc_error_codes/src/error_codes/E0482.md
Normal file
73
compiler/rustc_error_codes/src/error_codes/E0482.md
Normal file
@ -0,0 +1,73 @@
|
||||
A lifetime of a returned value does not outlive the function call.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0482
|
||||
fn prefix<'a>(
|
||||
words: impl Iterator<Item = &'a str>
|
||||
) -> impl Iterator<Item = String> { // error!
|
||||
words.map(|v| format!("foo-{}", v))
|
||||
}
|
||||
```
|
||||
|
||||
To fix this error, make the lifetime of the returned value explicit:
|
||||
|
||||
```
|
||||
fn prefix<'a>(
|
||||
words: impl Iterator<Item = &'a str> + 'a
|
||||
) -> impl Iterator<Item = String> + 'a { // ok!
|
||||
words.map(|v| format!("foo-{}", v))
|
||||
}
|
||||
```
|
||||
|
||||
The [`impl Trait`] feature in this example uses an implicit `'static` lifetime
|
||||
restriction in the returned type. However the type implementing the `Iterator`
|
||||
passed to the function lives just as long as `'a`, which is not long enough.
|
||||
|
||||
The solution involves adding lifetime bound to both function argument and
|
||||
the return value to make sure that the values inside the iterator
|
||||
are not dropped when the function goes out of the scope.
|
||||
|
||||
An alternative solution would be to guarantee that the `Item` references
|
||||
in the iterator are alive for the whole lifetime of the program.
|
||||
|
||||
```
|
||||
fn prefix(
|
||||
words: impl Iterator<Item = &'static str>
|
||||
) -> impl Iterator<Item = String> { // ok!
|
||||
words.map(|v| format!("foo-{}", v))
|
||||
}
|
||||
```
|
||||
|
||||
A similar lifetime problem might arise when returning closures:
|
||||
|
||||
```compile_fail,E0482
|
||||
fn foo(
|
||||
x: &mut Vec<i32>
|
||||
) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
|
||||
|y| {
|
||||
y.append(x);
|
||||
y
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Analogically, a solution here is to use explicit return lifetime
|
||||
and move the ownership of the variable to the closure.
|
||||
|
||||
```
|
||||
fn foo<'a>(
|
||||
x: &'a mut Vec<i32>
|
||||
) -> impl FnMut(&mut Vec<i32>) -> &[i32] + 'a { // ok!
|
||||
move |y| {
|
||||
y.append(x);
|
||||
y
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To better understand the lifetime treatment in the [`impl Trait`],
|
||||
please see the [RFC 1951].
|
||||
|
||||
[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html
|
||||
[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html
|
@ -738,6 +738,12 @@ impl<I: Idx, T> IndexVec<I, Option<T>> {
|
||||
self.ensure_contains_elem(index, || None);
|
||||
self[index].get_or_insert_with(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove(&mut self, index: I) -> Option<T> {
|
||||
self.ensure_contains_elem(index, || None);
|
||||
self[index].take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, T: Clone> IndexVec<I, T> {
|
||||
|
@ -8,7 +8,6 @@
|
||||
//! through, but errors for structured control flow in a `const` should be emitted here.
|
||||
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
@ -83,30 +82,39 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind {
|
||||
if let hir::Constness::Const = imp.constness {
|
||||
let did = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let mut to_implement = FxHashSet::default();
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = self
|
||||
.tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(self.tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
for did in self.tcx.associated_item_def_ids(did) {
|
||||
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn, ident, defaultness, ..
|
||||
} = self.tcx.associated_item(*did)
|
||||
} = trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be catched by typeck.
|
||||
if defaultness.has_value()
|
||||
&& !self.tcx.has_attr(*did, sym::default_method_body_is_const)
|
||||
if !defaultness.has_value()
|
||||
|| self
|
||||
.tcx
|
||||
.has_attr(trait_item.def_id, sym::default_method_body_is_const)
|
||||
{
|
||||
to_implement.insert(ident);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for it in imp
|
||||
.items
|
||||
.iter()
|
||||
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
||||
{
|
||||
to_implement.remove(&it.ident);
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(self.tcx, trait_item.ident, trait_item.kind)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(ident.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `")))
|
||||
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -704,7 +704,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
.filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
|
||||
.collect();
|
||||
|
||||
never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::Send).unwrap());
|
||||
if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
|
||||
never_suggest_borrow.push(def_id);
|
||||
}
|
||||
|
||||
let param_env = obligation.param_env;
|
||||
let trait_ref = poly_trait_ref.skip_binder();
|
||||
|
@ -3,6 +3,7 @@ use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_trait_selection::traits::{self, SkipLeakCheck};
|
||||
@ -158,14 +159,18 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
|
||||
// This is advantageous to running the algorithm over the
|
||||
// entire graph when there are many connected regions.
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
pub struct RegionId {
|
||||
ENCODABLE = custom
|
||||
}
|
||||
}
|
||||
struct ConnectedRegion {
|
||||
idents: SmallVec<[Symbol; 8]>,
|
||||
impl_blocks: FxHashSet<usize>,
|
||||
}
|
||||
// Highest connected region id
|
||||
let mut highest_region_id = 0;
|
||||
let mut connected_regions: IndexVec<RegionId, _> = Default::default();
|
||||
// Reverse map from the Symbol to the connected region id.
|
||||
let mut connected_region_ids = FxHashMap::default();
|
||||
let mut connected_regions = FxHashMap::default();
|
||||
|
||||
for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() {
|
||||
if impl_items.len() == 0 {
|
||||
@ -173,7 +178,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
|
||||
}
|
||||
// First obtain a list of existing connected region ids
|
||||
let mut idents_to_add = SmallVec::<[Symbol; 8]>::new();
|
||||
let ids = impl_items
|
||||
let mut ids = impl_items
|
||||
.in_definition_order()
|
||||
.filter_map(|item| {
|
||||
let entry = connected_region_ids.entry(item.ident.name);
|
||||
@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<FxHashSet<usize>>();
|
||||
match ids.len() {
|
||||
0 | 1 => {
|
||||
let id_to_set = if ids.is_empty() {
|
||||
.collect::<SmallVec<[RegionId; 8]>>();
|
||||
// Sort the id list so that the algorithm is deterministic
|
||||
ids.sort_unstable();
|
||||
let ids = ids;
|
||||
match &ids[..] {
|
||||
// Create a new connected region
|
||||
let region = ConnectedRegion {
|
||||
[] => {
|
||||
let id_to_set = connected_regions.next_index();
|
||||
// Update the connected region ids
|
||||
for ident in &idents_to_add {
|
||||
connected_region_ids.insert(*ident, id_to_set);
|
||||
}
|
||||
connected_regions.insert(
|
||||
id_to_set,
|
||||
ConnectedRegion {
|
||||
idents: idents_to_add,
|
||||
impl_blocks: std::iter::once(i).collect(),
|
||||
};
|
||||
connected_regions.insert(highest_region_id, region);
|
||||
(highest_region_id, highest_region_id += 1).0
|
||||
} else {
|
||||
},
|
||||
);
|
||||
}
|
||||
// Take the only id inside the list
|
||||
let id_to_set = *ids.iter().next().unwrap();
|
||||
let region = connected_regions.get_mut(&id_to_set).unwrap();
|
||||
&[id_to_set] => {
|
||||
let region = connected_regions[id_to_set].as_mut().unwrap();
|
||||
region.impl_blocks.insert(i);
|
||||
region.idents.extend_from_slice(&idents_to_add);
|
||||
id_to_set
|
||||
};
|
||||
let (_id, region) = connected_regions.iter().next().unwrap();
|
||||
// Update the connected region ids
|
||||
for ident in region.idents.iter() {
|
||||
for ident in &idents_to_add {
|
||||
connected_region_ids.insert(*ident, id_to_set);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// We have multiple connected regions to merge.
|
||||
// In the worst case this might add impl blocks
|
||||
// one by one and can thus be O(n^2) in the size
|
||||
// of the resulting final connected region, but
|
||||
// this is no issue as the final step to check
|
||||
// for overlaps runs in O(n^2) as well.
|
||||
|
||||
// Take the smallest id from the list
|
||||
let id_to_set = *ids.iter().min().unwrap();
|
||||
|
||||
// Sort the id list so that the algorithm is deterministic
|
||||
let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>();
|
||||
ids.sort_unstable();
|
||||
|
||||
let mut region = connected_regions.remove(&id_to_set).unwrap();
|
||||
region.idents.extend_from_slice(&idents_to_add);
|
||||
&[id_to_set, ..] => {
|
||||
let mut region = connected_regions.remove(id_to_set).unwrap();
|
||||
region.impl_blocks.insert(i);
|
||||
region.idents.extend_from_slice(&idents_to_add);
|
||||
// Update the connected region ids
|
||||
for ident in &idents_to_add {
|
||||
connected_region_ids.insert(*ident, id_to_set);
|
||||
}
|
||||
|
||||
// Remove other regions from ids.
|
||||
for &id in ids.iter() {
|
||||
if id == id_to_set {
|
||||
continue;
|
||||
}
|
||||
let r = connected_regions.remove(&id).unwrap();
|
||||
// Update the connected region ids
|
||||
let r = connected_regions.remove(id).unwrap();
|
||||
for ident in r.idents.iter() {
|
||||
connected_region_ids.insert(*ident, id_to_set);
|
||||
}
|
||||
region.idents.extend_from_slice(&r.idents);
|
||||
region.impl_blocks.extend(r.impl_blocks);
|
||||
}
|
||||
|
||||
connected_regions.insert(id_to_set, region);
|
||||
}
|
||||
}
|
||||
@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
|
||||
let avg = impls.len() / connected_regions.len();
|
||||
let s = connected_regions
|
||||
.iter()
|
||||
.map(|r| r.1.impl_blocks.len() as isize - avg as isize)
|
||||
.flatten()
|
||||
.map(|r| r.impl_blocks.len() as isize - avg as isize)
|
||||
.map(|v| v.abs() as usize)
|
||||
.sum::<usize>();
|
||||
s / connected_regions.len()
|
||||
},
|
||||
connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap()
|
||||
connected_regions
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|r| r.impl_blocks.len())
|
||||
.max()
|
||||
.unwrap()
|
||||
);
|
||||
// List of connected regions is built. Now, run the overlap check
|
||||
// for each pair of impl blocks in the same connected region.
|
||||
for (_id, region) in connected_regions.into_iter() {
|
||||
for region in connected_regions.into_iter().flatten() {
|
||||
let mut impl_blocks =
|
||||
region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
|
||||
impl_blocks.sort_unstable();
|
||||
|
@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(nll)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(never_type)]
|
||||
|
@ -30,7 +30,8 @@ use crate::hash::Hasher;
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [ub]: ../../reference/behavior-considered-undefined.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Send")]
|
||||
#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")]
|
||||
#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")]
|
||||
#[rustc_on_unimplemented(
|
||||
message = "`{Self}` cannot be sent between threads safely",
|
||||
label = "`{Self}` cannot be sent between threads safely"
|
||||
|
@ -11,5 +11,7 @@ mod wake;
|
||||
pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
mod ready;
|
||||
#[stable(feature = "ready_macro", since = "1.56.0")]
|
||||
#[unstable(feature = "ready_macro", issue = "70922")]
|
||||
pub use ready::ready;
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
pub use ready::Ready;
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::convert;
|
||||
use crate::ops::{self, ControlFlow};
|
||||
use crate::result::Result;
|
||||
use crate::task::Ready;
|
||||
|
||||
/// Indicates whether a value is available or if the current task has been
|
||||
/// scheduled to receive a wakeup instead.
|
||||
@ -92,6 +93,38 @@ impl<T> Poll<T> {
|
||||
pub const fn is_pending(&self) -> bool {
|
||||
!self.is_ready()
|
||||
}
|
||||
|
||||
/// Extracts the successful type of a [`Poll<T>`].
|
||||
///
|
||||
/// When combined with the `?` operator, this function will
|
||||
/// propogate any [`Poll::Pending`] values to the caller, and
|
||||
/// extract the `T` from [`Poll::Ready`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(poll_ready)]
|
||||
///
|
||||
/// use std::task::{Context, Poll};
|
||||
/// use std::future::{self, Future};
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
|
||||
/// let mut fut = future::ready(42);
|
||||
/// let fut = Pin::new(&mut fut);
|
||||
///
|
||||
/// let num = fut.poll(cx).ready()?;
|
||||
/// # drop(num);
|
||||
/// // ... use num
|
||||
///
|
||||
/// Poll::Ready(())
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
pub fn ready(self) -> Ready<T> {
|
||||
Ready(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Poll<Result<T, E>> {
|
||||
|
@ -1,3 +1,8 @@
|
||||
use core::convert;
|
||||
use core::fmt;
|
||||
use core::ops::{ControlFlow, FromResidual, Try};
|
||||
use core::task::Poll;
|
||||
|
||||
/// Extracts the successful type of a [`Poll<T>`].
|
||||
///
|
||||
/// This macro bakes in propagation of [`Pending`] signals by returning early.
|
||||
@ -8,6 +13,8 @@
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ready_macro)]
|
||||
///
|
||||
/// use std::task::{ready, Context, Poll};
|
||||
/// use std::future::{self, Future};
|
||||
/// use std::pin::Pin;
|
||||
@ -27,6 +34,7 @@
|
||||
/// The `ready!` call expands to:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(ready_macro)]
|
||||
/// # use std::task::{Context, Poll};
|
||||
/// # use std::future::{self, Future};
|
||||
/// # use std::pin::Pin;
|
||||
@ -45,7 +53,7 @@
|
||||
/// # Poll::Ready(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "ready_macro", since = "1.56.0")]
|
||||
#[unstable(feature = "ready_macro", issue = "70922")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
pub macro ready($e:expr) {
|
||||
match $e {
|
||||
@ -55,3 +63,55 @@ pub macro ready($e:expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the successful type of a [`Poll<T>`].
|
||||
///
|
||||
/// See [`Poll::ready`] for details.
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
pub struct Ready<T>(pub(crate) Poll<T>);
|
||||
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
impl<T> Try for Ready<T> {
|
||||
type Output = T;
|
||||
type Residual = Ready<convert::Infallible>;
|
||||
|
||||
#[inline]
|
||||
fn from_output(output: Self::Output) -> Self {
|
||||
Ready(Poll::Ready(output))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||
match self.0 {
|
||||
Poll::Ready(v) => ControlFlow::Continue(v),
|
||||
Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
impl<T> FromResidual for Ready<T> {
|
||||
#[inline]
|
||||
fn from_residual(residual: Ready<convert::Infallible>) -> Self {
|
||||
match residual.0 {
|
||||
Poll::Pending => Ready(Poll::Pending),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
impl<T> FromResidual<Ready<convert::Infallible>> for Poll<T> {
|
||||
#[inline]
|
||||
fn from_residual(residual: Ready<convert::Infallible>) -> Self {
|
||||
match residual.0 {
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "poll_ready", issue = "89780")]
|
||||
impl<T> fmt::Debug for Ready<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("Ready").finish()
|
||||
}
|
||||
}
|
||||
|
@ -933,10 +933,9 @@ class RustBuild(object):
|
||||
env["LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \
|
||||
(os.pathsep + env["LIBRARY_PATH"]) \
|
||||
if "LIBRARY_PATH" in env else ""
|
||||
|
||||
# preserve existing RUSTFLAGS
|
||||
env.setdefault("RUSTFLAGS", "")
|
||||
env["RUSTFLAGS"] += " -Cdebuginfo=2"
|
||||
|
||||
build_section = "target.{}".format(self.build)
|
||||
target_features = []
|
||||
if self.get_toml("crt-static", build_section) == "true":
|
||||
|
@ -1342,12 +1342,6 @@ impl<'a> Builder<'a> {
|
||||
rustdocflags.arg("-Dwarnings");
|
||||
}
|
||||
|
||||
// FIXME(#58633) hide "unused attribute" errors in incremental
|
||||
// builds of the standard library, as the underlying checks are
|
||||
// not yet properly integrated with incremental recompilation.
|
||||
if mode == Mode::Std && compiler.stage == 0 && self.config.incremental {
|
||||
lint_flags.push("-Aunused-attributes");
|
||||
}
|
||||
// This does not use RUSTFLAGS due to caching issues with Cargo.
|
||||
// Clippy is treated as an "in tree" tool, but shares the same
|
||||
// cache as other "submodule" tools. With these options set in
|
||||
|
@ -9,36 +9,37 @@
|
||||
// gdb-command:info functions -q function_names::main
|
||||
// gdb-check:[...]static fn function_names::main();
|
||||
// gdb-command:info functions -q function_names::generic_func<*
|
||||
// gdb-check:[...]static fn function_names::generic_func(i32) -> i32;
|
||||
// gdb-check:[...]static fn function_names::generic_func<i32>(i32) -> i32;
|
||||
|
||||
// Implementations
|
||||
// gdb-command:info functions -q function_names::.*::impl_function.*
|
||||
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function();
|
||||
// gdb-check:[...]static fn function_names::GenericStruct<i32, i32>::impl_function<i32, i32>();
|
||||
// gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function();
|
||||
// gdb-check:[...]static fn function_names::TestStruct1::impl_function();
|
||||
|
||||
// Trait implementations
|
||||
// gdb-command:info functions -q function_names::.*::trait_function.*
|
||||
// gdb-check:[...]static fn <function_names::GenericStruct<T,i32> as function_names::TestTrait1>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::GenericStruct<[T; N],f32> as function_names::TestTrait1>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::Mod1::TestStruct2 as function_names::Mod1::TestTrait2>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::TestStruct1 as function_names::TestTrait1>::trait_function();
|
||||
// gdb-check:[...]static fn function_names::Mod1::{impl#1}::trait_function();
|
||||
// gdb-check:[...]static fn function_names::{impl#1}::trait_function();
|
||||
// gdb-check:[...]static fn function_names::{impl#3}::trait_function<i32>();
|
||||
// gdb-check:[...]static fn function_names::{impl#5}::trait_function3<function_names::TestStruct1>();
|
||||
// gdb-check:[...]static fn function_names::{impl#6}::trait_function<i32, 1>();
|
||||
|
||||
// Closure
|
||||
// gdb-command:info functions -q function_names::.*::{{closure.*
|
||||
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0});
|
||||
// gdb-command:info functions -q function_names::.*::{closure.*
|
||||
// gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(*mut function_names::generic_func::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(*mut function_names::{impl#2}::impl_function::{closure#0});
|
||||
|
||||
// Generator
|
||||
// Generators don't seem to appear in GDB's symbol table.
|
||||
|
||||
// Const generic parameter
|
||||
// gdb-command:info functions -q function_names::const_generic_fn.*
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_bool();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_non_int();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
|
||||
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
|
||||
|
||||
// === CDB TESTS ===================================================================================
|
||||
|
||||
@ -103,7 +104,7 @@ fn main() {
|
||||
GenericStruct::<TestStruct1, usize>::trait_function3();
|
||||
|
||||
// Generic function
|
||||
let _ = generic_func(42);
|
||||
let _ = generic_func(42i32);
|
||||
|
||||
// Closure
|
||||
let closure = || { TestStruct1 };
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
trait Tr {
|
||||
fn req(&self);
|
||||
@ -18,11 +19,6 @@ impl const Tr for S {
|
||||
fn req(&self) {}
|
||||
} //~^^ ERROR const trait implementations may not use non-const default functions
|
||||
|
||||
impl const Tr for u8 {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
|
||||
impl const Tr for u16 {
|
||||
fn prov(&self) {}
|
||||
fn default() {}
|
@ -1,5 +1,5 @@
|
||||
error: const trait implementations may not use non-const default functions
|
||||
--> $DIR/impl-with-default-fn.rs:17:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:18:1
|
||||
|
|
||||
LL | / impl const Tr for S {
|
||||
LL | | fn req(&self) {}
|
||||
@ -9,7 +9,7 @@ LL | | }
|
||||
= note: `prov` not implemented
|
||||
|
||||
error: const trait implementations may not use non-const default functions
|
||||
--> $DIR/impl-with-default-fn.rs:32:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:28:1
|
||||
|
|
||||
LL | / impl const Tr for u32 {
|
||||
LL | | fn req(&self) {}
|
||||
@ -20,7 +20,7 @@ LL | | }
|
||||
= note: `prov` not implemented
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `req`
|
||||
--> $DIR/impl-with-default-fn.rs:26:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:22:1
|
||||
|
|
||||
LL | fn req(&self);
|
||||
| -------------- `req` from trait
|
@ -0,0 +1,34 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
trait Tr {
|
||||
fn req(&self);
|
||||
|
||||
fn prov(&self) {
|
||||
println!("lul");
|
||||
self.req();
|
||||
}
|
||||
|
||||
#[default_method_body_is_const]
|
||||
fn default() {}
|
||||
}
|
||||
|
||||
impl const Tr for u8 {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
|
||||
macro_rules! impl_tr {
|
||||
($ty: ty) => {
|
||||
impl const Tr for $ty {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_tr!(u64);
|
||||
|
||||
fn main() {}
|
@ -11,7 +11,7 @@ use regex::Regex;
|
||||
// A few of those error codes can't be tested but all the others can and *should* be tested!
|
||||
const EXEMPTED_FROM_TEST: &[&str] = &[
|
||||
"E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0464", "E0465", "E0476",
|
||||
"E0482", "E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
|
||||
"E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
|
||||
];
|
||||
|
||||
// Some error codes don't have any tests apparently...
|
||||
|
Loading…
Reference in New Issue
Block a user