Auto merge of #126671 - fmease:rollup-dmet4fi, r=fmease

Rollup of 7 pull requests

Successful merges:

 - #123782 (Test that opaque types can't have themselves as a hidden type with incompatible lifetimes)
 - #124580 (Suggest removing unused tuple fields if they are the last fields)
 - #125787 (Migrate `bin-emit-no-symbols` `run-make` test to `rmake`)
 - #126553 (match lowering: expand or-candidates mixed with candidates above)
 - #126594 (Make async drop code more consistent with regular drop code)
 - #126654 (Make pretty printing for `f16` and `f128` consistent)
 - #126656 (rustc_type_ir: Omit some struct fields from Debug output)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-06-19 08:56:43 +00:00
commit 5978f35330
39 changed files with 700 additions and 221 deletions

View file

@ -371,7 +371,7 @@ fn exported_symbols_provider_local(
}) => {
// A little sanity-check
debug_assert_eq!(
args.non_erasable_generics(tcx, def_id).skip(1).next(),
args.non_erasable_generics(tcx, def_id).next(),
Some(GenericArgKind::Type(ty))
);
symbols.push((
@ -422,10 +422,7 @@ fn upstream_monomorphizations_provider(
}
ExportedSymbol::AsyncDropGlueCtorShim(ty) => {
if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id {
(
async_drop_in_place_fn_def_id,
tcx.mk_args(&[tcx.lifetimes.re_erased.into(), ty.into()]),
)
(async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
} else {
// `drop_in_place` in place does not exist, don't try
// to use it.
@ -473,11 +470,16 @@ fn upstream_drop_glue_for_provider<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
) -> Option<CrateNum> {
if let Some(def_id) = tcx.lang_items().drop_in_place_fn() {
tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned())
} else {
None
}
let def_id = tcx.lang_items().drop_in_place_fn()?;
tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned()
}
fn upstream_async_drop_glue_for_provider<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
) -> Option<CrateNum> {
let def_id = tcx.lang_items().async_drop_in_place_fn()?;
tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned()
}
fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
@ -491,6 +493,7 @@ pub fn provide(providers: &mut Providers) {
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;
providers.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider;
providers.wasm_import_module_map = wasm_import_module_map;
providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.extern_queries.upstream_monomorphizations_for =

View file

@ -1554,12 +1554,13 @@
}
}
/// The entire set of monomorphizations the local crate can safely link
/// to because they are exported from upstream crates. Do not depend on
/// this directly, as its value changes anytime a monomorphization gets
/// added or removed in any upstream crate. Instead use the narrower
/// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
/// better, `Instance::upstream_monomorphization()`.
/// The entire set of monomorphizations the local crate can safely
/// link to because they are exported from upstream crates. Do
/// not depend on this directly, as its value changes anytime
/// a monomorphization gets added or removed in any upstream
/// crate. Instead use the narrower `upstream_monomorphizations_for`,
/// `upstream_drop_glue_for`, `upstream_async_drop_glue_for`, or,
/// even better, `Instance::upstream_monomorphization()`.
query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> {
arena_cache
desc { "collecting available upstream monomorphizations" }
@ -1601,6 +1602,26 @@
desc { "available upstream drop-glue for `{:?}`", args }
}
/// Returns the upstream crate that exports async-drop-glue for
/// the given type (`args` is expected to be a single-item list
/// containing the type one wants async-drop-glue for).
///
/// This is a subset of `upstream_monomorphizations_for` in order
/// to increase dep-tracking granularity. Otherwise adding or
/// removing any type with async-drop-glue in any upstream crate
/// would invalidate all functions calling async-drop-glue of an
/// upstream type.
///
/// You likely want to call `Instance::upstream_monomorphization()`
/// instead of invoking this query directly.
///
/// NOTE: This query could easily be extended to also support other
/// common functions that have are large set of monomorphizations
/// (like `Clone::clone` for example).
query upstream_async_drop_glue_for(args: GenericArgsRef<'tcx>) -> Option<CrateNum> {
desc { "available upstream async-drop-glue for `{:?}`", args }
}
/// Returns a list of all `extern` blocks of a crate.
query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> {
arena_cache

View file

@ -219,8 +219,9 @@ pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
InstanceKind::Item(def) => tcx
.upstream_monomorphizations_for(def)
.and_then(|monos| monos.get(&self.args).cloned()),
InstanceKind::DropGlue(_, Some(_)) | InstanceKind::AsyncDropGlueCtorShim(_, _) => {
tcx.upstream_drop_glue_for(self.args)
InstanceKind::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args),
InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => {
tcx.upstream_async_drop_glue_for(self.args)
}
_ => None,
}
@ -256,7 +257,7 @@ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
match self {
ty::InstanceKind::Item(def) => Some(def),
ty::InstanceKind::DropGlue(def_id, Some(_))
| InstanceKind::AsyncDropGlueCtorShim(def_id, _)
| InstanceKind::AsyncDropGlueCtorShim(def_id, Some(_))
| InstanceKind::ThreadLocalShim(def_id) => Some(def_id),
InstanceKind::VTableShim(..)
| InstanceKind::ReifyShim(..)
@ -267,6 +268,7 @@ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
| ty::InstanceKind::ConstructCoroutineInClosureShim { .. }
| ty::InstanceKind::CoroutineKindShim { .. }
| InstanceKind::DropGlue(..)
| InstanceKind::AsyncDropGlueCtorShim(..)
| InstanceKind::CloneShim(..)
| InstanceKind::FnPtrAddrShim(..) => None,
}
@ -312,7 +314,9 @@ pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool {
if self.requires_inline(tcx) {
return true;
}
if let ty::InstanceKind::DropGlue(.., Some(ty)) = *self {
if let ty::InstanceKind::DropGlue(.., Some(ty))
| ty::InstanceKind::AsyncDropGlueCtorShim(.., Some(ty)) = *self
{
// Drop glue generally wants to be instantiated at every codegen
// unit, but without an #[inline] hint. We should make this
// available to normal end-users.
@ -327,9 +331,14 @@ pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool {
// drops of `Option::None` before LTO. We also respect the intent of
// `#[inline]` on `Drop::drop` implementations.
return ty.ty_adt_def().map_or(true, |adt_def| {
adt_def
.destructor(tcx)
.map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did))
match *self {
ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did),
ty::InstanceKind::AsyncDropGlueCtorShim(..) => {
adt_def.async_destructor(tcx).map(|dtor| dtor.ctor)
}
_ => unreachable!(),
}
.map_or_else(|| adt_def.is_enum(), |did| tcx.cross_crate_inlinable(did))
});
}
if let ty::InstanceKind::ThreadLocalShim(..) = *self {

View file

@ -7,7 +7,7 @@
ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
};
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::Float;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::unord::UnordMap;
@ -1710,6 +1710,10 @@ fn pretty_print_const_scalar_int(
ty::Bool if int == ScalarInt::FALSE => p!("false"),
ty::Bool if int == ScalarInt::TRUE => p!("true"),
// Float
ty::Float(ty::FloatTy::F16) => {
let val = Half::try_from(int).unwrap();
p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" }))
}
ty::Float(ty::FloatTy::F32) => {
let val = Single::try_from(int).unwrap();
p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" }))
@ -1718,6 +1722,10 @@ fn pretty_print_const_scalar_int(
let val = Double::try_from(int).unwrap();
p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" }))
}
ty::Float(ty::FloatTy::F128) => {
let val = Quad::try_from(int).unwrap();
p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" }))
}
// Int
ty::Uint(_) | ty::Int(_) => {
let int =

View file

@ -1074,12 +1074,9 @@ struct Candidate<'pat, 'tcx> {
// because that would break binding consistency.
subcandidates: Vec<Candidate<'pat, 'tcx>>,
/// ...and the guard must be evaluated if there is one.
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
has_guard: bool,
/// If the guard is `false` then branch to `otherwise_block`.
otherwise_block: Option<BasicBlock>,
/// If the candidate matches, bindings and ascriptions must be established.
extra_data: PatternExtraData<'tcx>,
@ -1090,6 +1087,9 @@ struct Candidate<'pat, 'tcx> {
/// The block before the `bindings` have been established.
pre_binding_block: Option<BasicBlock>,
/// The block to branch to if the guard or a nested candidate fails to match.
otherwise_block: Option<BasicBlock>,
/// The earliest block that has only candidates >= this one as descendents. Used for false
/// edges, see the doc for [`Builder::match_expr`].
false_edge_start_block: Option<BasicBlock>,
@ -1364,56 +1364,105 @@ fn match_candidates<'pat>(
otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
) {
let mut split_or_candidate = false;
for candidate in &mut *candidates {
if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs {
// Split a candidate in which the only match-pair is an or-pattern into multiple
// candidates. This is so that
//
// match x {
// 0 | 1 => { ... },
// 2 | 3 => { ... },
// }
//
// only generates a single switch.
let match_pair = candidate.match_pairs.pop().unwrap();
self.create_or_subcandidates(candidate, match_pair);
split_or_candidate = true;
// We process or-patterns here. If any candidate starts with an or-pattern, we have to
// expand the or-pattern before we can proceed further.
//
// We can't expand them freely however. The rule is: if the candidate has an or-pattern as
// its only remaining match pair, we can expand it freely. If it has other match pairs, we
// can expand it but we can't process more candidates after it.
//
// If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
// or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
// cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
// set of candidates, when we reach the block that tests `false` we don't know whether we
// came from `1` or `2`, hence we can't know where to branch on failure.
// ```ignore(illustrative)
// match (1, true) {
// (1 | 2, false) => {},
// (2, _) => {},
// _ => {}
// }
// ```
//
// We therefore split the `candidates` slice in two, expand or-patterns in the first half,
// and process both halves separately.
let mut expand_until = 0;
for (i, candidate) in candidates.iter().enumerate() {
if matches!(
&*candidate.match_pairs,
[MatchPair { test_case: TestCase::Or { .. }, .. }, ..]
) {
expand_until = i + 1;
if candidate.match_pairs.len() > 1 {
break;
}
}
}
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
ensure_sufficient_stack(|| {
if split_or_candidate {
// At least one of the candidates has been split into subcandidates.
// We need to change the candidate list to include those.
let mut new_candidates = Vec::new();
for candidate in candidates.iter_mut() {
candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
if candidates_to_expand.is_empty() {
// No candidates start with an or-pattern, we can continue.
self.match_expanded_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
remaining_candidates,
);
} else {
// Expand one level of or-patterns for each candidate in `candidates_to_expand`.
let mut expanded_candidates = Vec::new();
for candidate in candidates_to_expand.iter_mut() {
if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] =
&*candidate.match_pairs
{
let or_match_pair = candidate.match_pairs.remove(0);
// Expand the or-pattern into subcandidates.
self.create_or_subcandidates(candidate, or_match_pair);
// Collect the newly created subcandidates.
for subcandidate in candidate.subcandidates.iter_mut() {
expanded_candidates.push(subcandidate);
}
} else {
expanded_candidates.push(candidate);
}
}
// Process the expanded candidates.
let remainder_start = self.cfg.start_new_block();
// There might be new or-patterns obtained from expanding the old ones, so we call
// `match_candidates` again.
self.match_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
&mut *new_candidates,
remainder_start,
expanded_candidates.as_mut_slice(),
);
for candidate in candidates {
self.merge_trivial_subcandidates(candidate);
// Simplify subcandidates and process any leftover match pairs.
for candidate in candidates_to_expand {
if !candidate.subcandidates.is_empty() {
self.finalize_or_candidate(span, scrutinee_span, candidate);
}
}
} else {
self.match_simplified_candidates(
// Process the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
start_block,
remainder_start,
otherwise_block,
candidates,
remaining_candidates,
);
}
});
}
fn match_simplified_candidates(
/// Construct the decision tree for `candidates`. Caller must ensure that no candidate in
/// `candidates` starts with an or-pattern.
fn match_expanded_candidates(
&mut self,
span: Span,
scrutinee_span: Span,
@ -1438,7 +1487,7 @@ fn match_simplified_candidates(
// The first candidate has satisfied all its match pairs; we link it up and continue
// with the remaining candidates.
start_block = self.select_matched_candidate(first, start_block);
self.match_simplified_candidates(
self.match_expanded_candidates(
span,
scrutinee_span,
start_block,
@ -1448,7 +1497,7 @@ fn match_simplified_candidates(
}
candidates => {
// The first candidate has some unsatisfied match pairs; we proceed to do more tests.
self.test_candidates_with_or(
self.test_candidates(
span,
scrutinee_span,
candidates,
@ -1495,16 +1544,14 @@ fn select_matched_candidate(
candidate.pre_binding_block = Some(start_block);
let otherwise_block = self.cfg.start_new_block();
if candidate.has_guard {
// Create the otherwise block for this candidate, which is the
// pre-binding block for the next candidate.
candidate.otherwise_block = Some(otherwise_block);
}
// Create the otherwise block for this candidate, which is the
// pre-binding block for the next candidate.
candidate.otherwise_block = Some(otherwise_block);
otherwise_block
}
/// Tests a candidate where there are only or-patterns left to test, or
/// forwards to [Builder::test_candidates].
/// Simplify subcandidates and process any leftover match pairs. The candidate should have been
/// expanded with `create_or_subcandidates`.
///
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
/// so:
@ -1556,84 +1603,56 @@ fn select_matched_candidate(
/// |
/// ...
/// ```
fn test_candidates_with_or(
fn finalize_or_candidate(
&mut self,
span: Span,
scrutinee_span: Span,
candidates: &mut [&mut Candidate<'_, 'tcx>],
start_block: BasicBlock,
otherwise_block: BasicBlock,
candidate: &mut Candidate<'_, 'tcx>,
) {
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
assert!(first_candidate.subcandidates.is_empty());
if !matches!(first_candidate.match_pairs[0].test_case, TestCase::Or { .. }) {
self.test_candidates(span, scrutinee_span, candidates, start_block, otherwise_block);
if candidate.subcandidates.is_empty() {
return;
}
let first_match_pair = first_candidate.match_pairs.remove(0);
let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs);
let remainder_start = self.cfg.start_new_block();
// Test the alternatives of this or-pattern.
self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair);
self.merge_trivial_subcandidates(candidate);
if !remaining_match_pairs.is_empty() {
if !candidate.match_pairs.is_empty() {
// If more match pairs remain, test them after each subcandidate.
// We could add them to the or-candidates before the call to `test_or_pattern` but this
// would make it impossible to detect simplifiable or-patterns. That would guarantee
// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
first_candidate.visit_leaves(|leaf_candidate| {
let mut last_otherwise = None;
candidate.visit_leaves(|leaf_candidate| {
last_otherwise = leaf_candidate.otherwise_block;
});
let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
candidate.visit_leaves(|leaf_candidate| {
assert!(leaf_candidate.match_pairs.is_empty());
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
let or_start = leaf_candidate.pre_binding_block.unwrap();
// In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b,
// c | d)` will fail too. If there is no guard, we skip testing of `b` by branching
// directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`.
let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start);
self.test_candidates_with_or(
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
// directly to `last_otherwise`. If there is a guard,
// `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we
// can't skip `Q`.
let or_otherwise = if leaf_candidate.has_guard {
leaf_candidate.otherwise_block.unwrap()
} else {
last_otherwise.unwrap()
};
self.match_candidates(
span,
scrutinee_span,
&mut [leaf_candidate],
or_start,
or_otherwise,
&mut [leaf_candidate],
);
});
}
// Test the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
);
}
#[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
start_block: BasicBlock,
otherwise_block: BasicBlock,
match_pair: MatchPair<'pat, 'tcx>,
) {
let or_span = match_pair.pattern.span;
self.create_or_subcandidates(candidate, match_pair);
let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect();
self.match_candidates(
or_span,
or_span,
start_block,
otherwise_block,
&mut or_candidate_refs,
);
self.merge_trivial_subcandidates(candidate);
}
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
/// subcandidate. Any candidate that has been expanded that way should be passed to
/// `merge_trivial_subcandidates` after its subcandidates have been processed.
/// `finalize_or_candidate` after its subcandidates have been processed.
fn create_or_subcandidates<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
@ -1651,8 +1670,8 @@ fn create_or_subcandidates<'pat>(
}
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have
/// been expanded with `create_or_subcandidates`.
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
/// expanded with `create_or_subcandidates`.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() || candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
@ -1664,6 +1683,7 @@ fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
});
if can_merge {
let mut last_otherwise = None;
let any_matches = self.cfg.start_new_block();
let or_span = candidate.or_span.take().unwrap();
let source_info = self.source_info(or_span);
@ -1674,8 +1694,11 @@ fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
for subcandidate in mem::take(&mut candidate.subcandidates) {
let or_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(or_block, source_info, any_matches);
last_otherwise = subcandidate.otherwise_block;
}
candidate.pre_binding_block = Some(any_matches);
assert!(last_otherwise.is_some());
candidate.otherwise_block = last_otherwise;
} else {
// Never subcandidates may have a set of bindings inconsistent with their siblings,
// which would break later code. So we filter them out. Note that we can't filter out

View file

@ -595,6 +595,15 @@ passes_pass_by_value =
passes_proc_macro_bad_sig = {$kind} has incorrect signature
passes_remove_fields =
consider removing { $num ->
[one] this
*[other] these
} { $num ->
[one] field
*[other] fields
}
passes_repr_conflicting =
conflicting representation hints

View file

@ -24,8 +24,7 @@
use std::mem;
use crate::errors::{
ChangeFieldsToBeOfUnitType, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo,
UselessAssignment,
ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment,
};
// Any local node that may call something in its body block should be
@ -1071,17 +1070,50 @@ fn lint_at_single_level(
};
let diag = match report_on {
ReportOn::TupleField => MultipleDeadCodes::UnusedTupleStructFields {
multiple,
num,
descr,
participle,
name_list,
change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() },
parent_info,
ignored_derived_impls,
},
ReportOn::TupleField => {
let tuple_fields = if let Some(parent_id) = parent_item
&& let node = tcx.hir_node_by_def_id(parent_id)
&& let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(fields, _, _), _),
..
}) = node
{
*fields
} else {
&[]
};
let trailing_tuple_fields = if tuple_fields.len() >= dead_codes.len() {
LocalDefIdSet::from_iter(
tuple_fields
.iter()
.skip(tuple_fields.len() - dead_codes.len())
.map(|f| f.def_id),
)
} else {
LocalDefIdSet::default()
};
let fields_suggestion =
// Suggest removal if all tuple fields are at the end.
// Otherwise suggest removal or changing to unit type
if dead_codes.iter().all(|dc| trailing_tuple_fields.contains(&dc.def_id)) {
ChangeFields::Remove { num }
} else {
ChangeFields::ChangeToUnitTypeOrRemove { num, spans: spans.clone() }
};
MultipleDeadCodes::UnusedTupleStructFields {
multiple,
num,
descr,
participle,
name_list,
change_fields_suggestion: fields_suggestion,
parent_info,
ignored_derived_impls,
}
}
ReportOn::NamedField => MultipleDeadCodes::DeadCodes {
multiple,
num,

View file

@ -1574,7 +1574,7 @@ pub enum MultipleDeadCodes<'tcx> {
participle: &'tcx str,
name_list: DiagSymbolList,
#[subdiagnostic]
change_fields_suggestion: ChangeFieldsToBeOfUnitType,
change_fields_suggestion: ChangeFields,
#[subdiagnostic]
parent_info: Option<ParentInfo<'tcx>>,
#[subdiagnostic]
@ -1601,11 +1601,18 @@ pub struct IgnoredDerivedImpls {
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(passes_change_fields_to_be_of_unit_type, applicability = "has-placeholders")]
pub struct ChangeFieldsToBeOfUnitType {
pub num: usize,
#[suggestion_part(code = "()")]
pub spans: Vec<Span>,
pub enum ChangeFields {
#[multipart_suggestion(
passes_change_fields_to_be_of_unit_type,
applicability = "has-placeholders"
)]
ChangeToUnitTypeOrRemove {
num: usize,
#[suggestion_part(code = "()")]
spans: Vec<Span>,
},
#[help(passes_remove_fields)]
Remove { num: usize },
}
#[derive(Diagnostic)]

View file

@ -288,6 +288,7 @@ pub fn transform_instance<'tcx>(
mut instance: Instance<'tcx>,
options: TransformTyOptions,
) -> Instance<'tcx> {
// FIXME: account for async-drop-glue
if (matches!(instance.def, ty::InstanceKind::Virtual(..))
&& tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace))
|| matches!(instance.def, ty::InstanceKind::DropGlue(..))

View file

@ -361,6 +361,7 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result {
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub struct EarlyBinder<I: Interner, T> {
value: T,
#[derivative(Debug = "ignore")]
_tcx: PhantomData<I>,
}

View file

@ -485,8 +485,8 @@ pub struct AliasTerm<I: Interner> {
/// aka. `interner.parent(def_id)`.
pub def_id: I::DefId,
/// This field exists to prevent the creation of `AliasTerm` without using
/// [AliasTerm::new].
/// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new`].
#[derivative(Debug = "ignore")]
_use_alias_term_new_instead: (),
}

View file

@ -452,8 +452,8 @@ pub struct AliasTy<I: Interner> {
/// aka. `interner.parent(def_id)`.
pub def_id: I::DefId,
/// This field exists to prevent the creation of `AliasTy` without using
/// [AliasTy::new].
/// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new`].
#[derivative(Debug = "ignore")]
pub(crate) _use_alias_ty_new_instead: (),
}

View file

@ -2,8 +2,8 @@
use crate::{env_var, Command};
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
/// at `$LLVM_BIN_DIR/llvm-readobj`.
/// Construct a new `llvm-readobj` invocation with the `GNU` output style.
/// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`.
#[track_caller]
pub fn llvm_readobj() -> LlvmReadobj {
LlvmReadobj::new()
@ -70,13 +70,24 @@ pub fn llvm_bin_dir() -> PathBuf {
}
impl LlvmReadobj {
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
/// at `$LLVM_BIN_DIR/llvm-readobj`.
/// Construct a new `llvm-readobj` invocation with the `GNU` output style.
/// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`.
#[track_caller]
pub fn new() -> Self {
let llvm_readobj = llvm_bin_dir().join("llvm-readobj");
let cmd = Command::new(llvm_readobj);
Self { cmd }
let mut readobj = Self { cmd };
readobj.elf_output_style("GNU");
readobj
}
/// Specify the format of the ELF information.
///
/// Valid options are `LLVM` (default), `GNU`, and `JSON`.
pub fn elf_output_style(&mut self, style: &str) -> &mut Self {
self.cmd.arg("--elf-output-style");
self.cmd.arg(style);
self
}
/// Provide an input file.
@ -90,6 +101,13 @@ pub fn file_header(&mut self) -> &mut Self {
self.cmd.arg("--file-header");
self
}
/// Specify the section to display.
pub fn section(&mut self, section: &str) -> &mut Self {
self.cmd.arg("--string-dump");
self.cmd.arg(section);
self
}
}
impl LlvmProfdata {

View file

@ -83,7 +83,6 @@ run-make/issue-37839/Makefile
run-make/issue-40535/Makefile
run-make/issue-47384/Makefile
run-make/issue-47551/Makefile
run-make/issue-51671/Makefile
run-make/issue-68794-textrel-on-minimal-lib/Makefile
run-make/issue-69368/Makefile
run-make/issue-83045/Makefile

View file

@ -0,0 +1,24 @@
// skip-filecheck
// EMIT_MIR or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir
fn shortcut_second_or() {
// Check that after matching `0`, failing to match `2 | 3` skips trying to match `(1, 2 | 3)`.
match ((0, 0), 0) {
(x @ (0, _) | x @ (_, 1), y @ 2 | y @ 3) => {}
_ => {}
}
}
// EMIT_MIR or_pattern.single_switchint.SimplifyCfg-initial.after.mir
fn single_switchint() {
// Check how many `SwitchInt`s we do. In theory a single one is necessary.
match (1, true) {
(1, true) => 1,
(2, false) => 2,
(1 | 2, true | false) => 3,
(3 | 4, true | false) => 4,
_ => 5,
};
}
fn main() {}

View file

@ -0,0 +1,100 @@
// MIR for `shortcut_second_or` after SimplifyCfg-initial
fn shortcut_second_or() -> () {
let mut _0: ();
let mut _1: ((i32, i32), i32);
let mut _2: (i32, i32);
let _3: (i32, i32);
let _4: i32;
scope 1 {
debug x => _3;
debug y => _4;
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = (const 0_i32, const 0_i32);
_1 = (move _2, const 0_i32);
StorageDead(_2);
PlaceMention(_1);
switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb4, otherwise: bb2];
}
bb1: {
_0 = const ();
goto -> bb14;
}
bb2: {
switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb3, otherwise: bb1];
}
bb3: {
switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1];
}
bb4: {
switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1];
}
bb5: {
falseEdge -> [real: bb10, imaginary: bb6];
}
bb6: {
falseEdge -> [real: bb11, imaginary: bb2];
}
bb7: {
falseEdge -> [real: bb12, imaginary: bb8];
}
bb8: {
falseEdge -> [real: bb13, imaginary: bb1];
}
bb9: {
_0 = const ();
StorageDead(_4);
StorageDead(_3);
goto -> bb14;
}
bb10: {
StorageLive(_3);
_3 = (_1.0: (i32, i32));
StorageLive(_4);
_4 = (_1.1: i32);
goto -> bb9;
}
bb11: {
StorageLive(_3);
_3 = (_1.0: (i32, i32));
StorageLive(_4);
_4 = (_1.1: i32);
goto -> bb9;
}
bb12: {
StorageLive(_3);
_3 = (_1.0: (i32, i32));
StorageLive(_4);
_4 = (_1.1: i32);
goto -> bb9;
}
bb13: {
StorageLive(_3);
_3 = (_1.0: (i32, i32));
StorageLive(_4);
_4 = (_1.1: i32);
goto -> bb9;
}
bb14: {
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,75 @@
// MIR for `single_switchint` after SimplifyCfg-initial
fn single_switchint() -> () {
let mut _0: ();
let _1: i32;
let mut _2: (i32, bool);
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = (const 1_i32, const true);
PlaceMention(_2);
switchInt((_2.0: i32)) -> [1: bb2, 2: bb4, otherwise: bb1];
}
bb1: {
switchInt((_2.0: i32)) -> [3: bb8, 4: bb8, otherwise: bb7];
}
bb2: {
switchInt((_2.1: bool)) -> [0: bb6, otherwise: bb3];
}
bb3: {
falseEdge -> [real: bb9, imaginary: bb4];
}
bb4: {
switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb6];
}
bb5: {
falseEdge -> [real: bb10, imaginary: bb6];
}
bb6: {
falseEdge -> [real: bb11, imaginary: bb1];
}
bb7: {
_1 = const 5_i32;
goto -> bb13;
}
bb8: {
falseEdge -> [real: bb12, imaginary: bb7];
}
bb9: {
_1 = const 1_i32;
goto -> bb13;
}
bb10: {
_1 = const 2_i32;
goto -> bb13;
}
bb11: {
_1 = const 3_i32;
goto -> bb13;
}
bb12: {
_1 = const 4_i32;
goto -> bb13;
}
bb13: {
StorageDead(_2);
StorageDead(_1);
_0 = const ();
return;
}
}

View file

@ -0,0 +1,16 @@
// When setting the crate type as a "bin" (in app.rs),
// this could cause a bug where some symbols would not be
// emitted in the object files. This has been fixed, and
// this test checks that the correct symbols have been successfully
// emitted inside the object files.
// See https://github.com/rust-lang/rust/issues/51671
use run_make_support::{llvm_readobj, rustc};
fn main() {
rustc().emit("obj").input("app.rs").run();
let out = llvm_readobj().input("app.o").arg("--symbols").run();
out.assert_stdout_contains("rust_begin_unwind");
out.assert_stdout_contains("rust_eh_personality");
out.assert_stdout_contains("__rg_oom");
}

View file

@ -1,9 +0,0 @@
include ../tools.mk
# ignore-windows-msvc
all:
$(RUSTC) --emit=obj app.rs
nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind
nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality
nm $(TMPDIR)/app.o | $(CGREP) __rg_oom

View file

@ -1,7 +1,7 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
--> $DIR/associated-type.rs:31:1
|

View file

@ -1,11 +1,11 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
--> $DIR/associated-type.rs:31:1
|

View file

@ -1,5 +1,5 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
--> $DIR/structually-relate-aliases.rs:13:36
|

View file

@ -5,15 +5,20 @@
const LEN: usize = 4;
struct SingleUnused(i32, [u8; LEN], String);
//~^ ERROR: field `1` is never read
//~| NOTE: field in this struct
//~| HELP: consider changing the field to be of unit type
struct MultipleUnused(i32, f32, String, u8);
//~^ ERROR: fields `0`, `1`, `2`, and `3` are never read
struct UnusedAtTheEnd(i32, f32, [u8; LEN], String, u8);
//~^ ERROR:fields `1`, `2`, `3`, and `4` are never read
//~| NOTE: fields in this struct
//~| HELP: consider changing the fields to be of unit type
//~| HELP: consider removing these fields
struct UnusedJustOneField(i32);
//~^ ERROR: field `0` is never read
//~| NOTE: field in this struct
//~| HELP: consider removing this field
struct UnusedInTheMiddle(i32, f32, String, u8, u32);
//~^ ERROR: fields `1`, `2`, and `4` are never read
//~| NOTE: fields in this struct
//~| HELP: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields
struct GoodUnit(());
@ -23,15 +28,19 @@
struct GoodVoid(Void);
fn main() {
let w = SingleUnused(42, [0, 1, 2, 3], "abc".to_string());
let _ = w.0;
let _ = w.2;
let u1 = UnusedAtTheEnd(42, 3.14, [0, 1, 2, 3], "def".to_string(), 4u8);
let _ = u1.0;
let _ = UnusedJustOneField(42);
let u2 = UnusedInTheMiddle(42, 3.14, "def".to_string(), 4u8, 5);
let _ = u2.0;
let _ = u2.3;
let m = MultipleUnused(42, 3.14, "def".to_string(), 4u8);
let gu = GoodUnit(());
let gp = GoodPhantom(PhantomData);
let gv = GoodVoid(Void);
let _ = (gu, gp, gv, m);
let _ = (gu, gp, gv);
}

View file

@ -1,33 +1,40 @@
error: field `1` is never read
--> $DIR/tuple-struct-field.rs:8:26
error: fields `1`, `2`, `3`, and `4` are never read
--> $DIR/tuple-struct-field.rs:8:28
|
LL | struct SingleUnused(i32, [u8; LEN], String);
| ------------ ^^^^^^^^^
LL | struct UnusedAtTheEnd(i32, f32, [u8; LEN], String, u8);
| -------------- ^^^ ^^^^^^^^^ ^^^^^^ ^^
| |
| field in this struct
| fields in this struct
|
= help: consider removing these fields
note: the lint level is defined here
--> $DIR/tuple-struct-field.rs:1:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
|
LL | struct SingleUnused(i32, (), String);
| ~~
error: fields `0`, `1`, `2`, and `3` are never read
--> $DIR/tuple-struct-field.rs:13:23
error: field `0` is never read
--> $DIR/tuple-struct-field.rs:13:27
|
LL | struct MultipleUnused(i32, f32, String, u8);
| -------------- ^^^ ^^^ ^^^^^^ ^^
LL | struct UnusedJustOneField(i32);
| ------------------ ^^^
| |
| field in this struct
|
= help: consider removing this field
error: fields `1`, `2`, and `4` are never read
--> $DIR/tuple-struct-field.rs:18:31
|
LL | struct UnusedInTheMiddle(i32, f32, String, u8, u32);
| ----------------- ^^^ ^^^^^^ ^^^
| |
| fields in this struct
|
help: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields
|
LL | struct MultipleUnused((), (), (), ());
| ~~ ~~ ~~ ~~
LL | struct UnusedInTheMiddle(i32, (), (), u8, ());
| ~~ ~~ ~~
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

View file

@ -26,5 +26,6 @@ fn main() {
assert_eq!(or_at(Err(7)), 207);
assert_eq!(or_at(Err(8)), 8);
assert_eq!(or_at(Err(20)), 220);
assert_eq!(or_at(Err(34)), 134);
assert_eq!(or_at(Err(50)), 500);
}

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/inner-or-pat.rs:38:54
--> $DIR/inner-or-pat.rs:36:54
|
LL | match x {
| - this expression has type `&str`

View file

@ -1,5 +1,5 @@
error[E0408]: variable `x` is not bound in all patterns
--> $DIR/inner-or-pat.rs:53:37
--> $DIR/inner-or-pat.rs:51:37
|
LL | (x @ "red" | (x @ "blue" | "red")) => {
| - ^^^^^ pattern doesn't bind `x`

View file

@ -1,7 +1,5 @@
//@ revisions: or1 or2 or3 or4 or5
//@ revisions: or1 or3 or4
//@ [or1] run-pass
//@ [or2] run-pass
//@ [or5] run-pass
#![allow(unreachable_patterns)]
#![allow(unused_variables)]

View file

@ -1,21 +1,20 @@
//@ check-pass
//@ run-pass
#![deny(unreachable_patterns)]
fn main() {
match (3,42) {
(a,_) | (_,a) if a > 10 => {println!("{}", a)}
_ => ()
match (3, 42) {
(a, _) | (_, a) if a > 10 => {}
_ => unreachable!(),
}
match Some((3,42)) {
Some((a, _)) | Some((_, a)) if a > 10 => {println!("{}", a)}
_ => ()
match Some((3, 42)) {
Some((a, _)) | Some((_, a)) if a > 10 => {}
_ => unreachable!(),
}
match Some((3,42)) {
Some((a, _) | (_, a)) if a > 10 => {println!("{}", a)}
_ => ()
match Some((3, 42)) {
Some((a, _) | (_, a)) if a > 10 => {}
_ => unreachable!(),
}
}

View file

@ -42,6 +42,23 @@ fn search_old_style(target: (bool, bool, bool)) -> u32 {
}
}
// Check that a dummy or-pattern also leads to running the guard multiple times.
fn search_with_dummy(target: (bool, bool)) -> u32 {
let x = ((false, true), (false, true), ());
let mut guard_count = 0;
match x {
((a, _) | (_, a), (b, _) | (_, b), _ | _)
if {
guard_count += 1;
(a, b) == target
} =>
{
guard_count
}
_ => unreachable!(),
}
}
fn main() {
assert_eq!(search((false, false, false)), 1);
assert_eq!(search((false, false, true)), 2);
@ -60,4 +77,9 @@ fn main() {
assert_eq!(search_old_style((true, false, true)), 6);
assert_eq!(search_old_style((true, true, false)), 7);
assert_eq!(search_old_style((true, true, true)), 8);
assert_eq!(search_with_dummy((false, false)), 1);
assert_eq!(search_with_dummy((false, true)), 3);
assert_eq!(search_with_dummy((true, false)), 5);
assert_eq!(search_with_dummy((true, true)), 7);
}

View file

@ -0,0 +1,11 @@
//@ run-pass
#[allow(unreachable_patterns)]
fn main() {
// Test that we don't naively sort the two `2`s together and confuse the failure paths.
match (1, true) {
(1 | 2, false | false) => unreachable!(),
(2, _) => unreachable!(),
_ => {}
}
}

View file

@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one
LL | trait ToUnit<'a> {
| ^^^^^^^^^^^^^^^^
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)`
--> $DIR/issue-118950-root-region.rs:19:1
|

View file

@ -0,0 +1,14 @@
#![feature(type_alias_impl_trait)]
pub type Opaque<'a> = impl Sized;
fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
a
}
fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
//~^ ERROR: item does not constrain
None::<Opaque<'static>>
}
fn main() {}

View file

@ -0,0 +1,15 @@
error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature
--> $DIR/different_args_considered_equal.rs:9:4
|
LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
| ^^^^^^^^
|
= note: consider moving the opaque type's declaration and defining uses into a separate module
note: this opaque type is in the signature
--> $DIR/different_args_considered_equal.rs:3:23
|
LL | pub type Opaque<'a> = impl Sized;
| ^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,14 @@
#![feature(type_alias_impl_trait)]
pub type Opaque<'a> = impl Sized;
fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> {
if a.is_null() {
Some(a)
} else {
None::<Opaque<'static>>
//~^ ERROR hidden type for `Opaque<'static>` captures lifetime that does not appear in bounds
}
}
fn main() {}

View file

@ -0,0 +1,20 @@
error[E0700]: hidden type for `Opaque<'static>` captures lifetime that does not appear in bounds
--> $DIR/different_args_considered_equal2.rs:9:9
|
LL | pub type Opaque<'a> = impl Sized;
| ---------- opaque type defined here
LL |
LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> {
| -- hidden type `*mut &'a str` captures the lifetime `'a` as defined here
...
LL | None::<Opaque<'static>>
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that `impl IntoIterator<Item = Opaque<'a>>` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> + 'a {
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0700`.

View file

@ -0,0 +1,22 @@
//! Test that we don't allow coercing an opaque type with a non-static
//! lifetime to one with a static lifetime. While `get_iter` looks like
//! it would be doing the opposite, the way we're handling projections
//! makes `Opaque<'a>` the hidden type of `Opaque<'static>`.
#![feature(type_alias_impl_trait)]
mod defining_scope {
pub type Opaque<'a> = impl Sized;
fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> {
a
}
}
use defining_scope::Opaque;
fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
None::<Opaque<'static>>
//~^ ERROR lifetime may not live long enough
}
fn main() {}

View file

@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/different_args_considered_equal3.rs:18:5
|
LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> {
| -- lifetime `'a` defined here
LL | None::<Opaque<'static>>
| ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to 1 previous error