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:
bors 2021-10-12 00:20:34 +00:00
commit 97e3b30285
22 changed files with 383 additions and 181 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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>,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
) -> Fallible<()> {
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(
infcx,
borrowck_context,
param_env,
locations,
category,
UniverseInfo::relate(a, b),
),
v,
)
.relate(a, b)?;
Ok(())
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,
) -> Fallible<()> {
TypeRelating::new(
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 {
sup,
sub,
locations: self.locations,
category: self.category,
variance_info: info,
});
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

View File

@ -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

View 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

View File

@ -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> {

View File

@ -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,32 +82,41 @@ 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;
}
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());
}
}
}
for it in imp
.items
.iter()
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
{
to_implement.remove(&it.ident);
}
// all nonconst trait functions (not marked with #[default_method_body_is_const])
// must be implemented
if !to_implement.is_empty() {
@ -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();
}
}

View File

@ -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();

View File

@ -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() {
// Create a new connected region
let region = ConnectedRegion {
.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 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();
region.impl_blocks.insert(i);
region.idents.extend_from_slice(&idents_to_add);
id_to_set
};
let (_id, region) = connected_regions.iter().next().unwrap();
},
);
}
// Take the only id inside the list
&[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);
// 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);
// 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.
&[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();

View File

@ -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)]

View File

@ -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"

View File

@ -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;

View File

@ -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>> {

View File

@ -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()
}
}

View File

@ -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":

View File

@ -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

View File

@ -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 };

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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...