Auto merge of #128213 - matthiaskrgr:rollup-v40q1j3, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #126090 (Fix supertrait associated type unsoundness)
 - #127220 (Graciously handle `Drop` impls introducing more generic parameters than the ADT)
 - #127950 (Use `#[rustfmt::skip]` on some `use` groups to prevent reordering.)
 - #128085 (Various notes on match lowering)
 - #128150 (Stop using `unsized_const_parameters` in core/std)
 - #128194 (LLVM: LLVM-20.0 removes MMX types)
 - #128211 (fix: compilation issue w/ refactored type)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-26 01:13:26 +00:00
commit 72d73cec61
31 changed files with 911 additions and 350 deletions

View File

@ -305,7 +305,6 @@ pub enum TypeKind {
Pointer = 12,
Vector = 13,
Metadata = 14,
X86_MMX = 15,
Token = 16,
ScalableVector = 17,
BFloat = 18,
@ -330,7 +329,6 @@ impl TypeKind {
TypeKind::Pointer => rustc_codegen_ssa::common::TypeKind::Pointer,
TypeKind::Vector => rustc_codegen_ssa::common::TypeKind::Vector,
TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,

View File

@ -91,7 +91,6 @@ pub enum TypeKind {
Pointer,
Vector,
Metadata,
X86_MMX,
Token,
ScalableVector,
BFloat,

View File

@ -34,6 +34,8 @@ use super::{
Pointer, Projectable, Scalar, ValueVisitor,
};
// for the validation errors
#[rustfmt::skip]
use super::InterpError::UndefinedBehavior as Ub;
use super::InterpError::Unsupported as Unsup;
use super::UndefinedBehaviorInfo::*;

View File

@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_infer::traits::ObligationCauseCode;
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{GenericArgsRef, Ty};
use rustc_trait_selection::regions::InferCtxtRegionExt;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@ -115,8 +115,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
Err(err.emit())
}
/// Confirms that every predicate imposed by dtor_predicates is
/// implied by assuming the predicates attached to self_type_did.
/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
/// implied by the ADT being well formed.
fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
tcx: TyCtxt<'tcx>,
drop_impl_def_id: LocalDefId,
@ -126,6 +127,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
// Take the param-env of the adt and instantiate the args that show up in
// the implementation's self type. This gives us the assumptions that the
// self ty of the implementation is allowed to know just from it being a
@ -135,14 +138,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
// We don't need to normalize this param-env or anything, since we're only
// instantiating it with free params, so no additional param-env normalization
// can occur on top of what has been done in the param_env query itself.
let param_env =
//
// Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
// could instead use identity args for the adt. Unfortunately this would cause any errors to
// reference the params from the ADT instead of from the impl which is bad UX. To resolve
// this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
let adt_env =
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id());
let fresh_adt_ty =
tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
.unwrap();
for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) {
let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
let pred = ocx.normalize(&normalize_cause, param_env, pred);
let pred = ocx.normalize(&normalize_cause, adt_env, clause);
let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl);
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
}
// All of the custom error reporting logic is to preserve parity with the old
@ -176,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
return Err(guar.unwrap());
}
let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(adt_env));
if !errors.is_empty() {
let mut guar = None;
for error in errors {

View File

@ -122,6 +122,7 @@ use types::*;
use unit_bindings::*;
use unused::*;
#[rustfmt::skip]
pub use builtin::{MissingDoc, SoftLints};
pub use context::{CheckLintNameResult, FindLintError, LintStore};
pub use context::{EarlyContext, LateContext, LintContext};

View File

@ -1419,8 +1419,6 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
return LLVMPointerTypeKind;
case Type::FixedVectorTyID:
return LLVMVectorTypeKind;
case Type::X86_MMXTyID:
return LLVMX86_MMXTypeKind;
case Type::TokenTyID:
return LLVMTokenTypeKind;
case Type::ScalableVectorTyID:

View File

@ -528,12 +528,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
end_block.unit()
}
/// Binds the variables and ascribes types for a given `match` arm or
/// `let` binding.
/// For a top-level `match` arm or a `let` binding, binds the variables and
/// ascribes types, and also checks the match arm guard (if present).
///
/// Also check if the guard matches, if it's provided.
/// `arm_scope` should be `Some` if and only if this is called for a
/// `match` arm.
///
/// In the presence of or-patterns, a match arm might have multiple
/// sub-branches representing different ways to match, with each sub-branch
/// requiring its own bindings and its own copy of the guard. This method
/// handles those sub-branches individually, and then has them jump together
/// to a common block.
///
/// Returns a single block that the match arm can be lowered into.
/// (For `let` bindings, this is the code that can use the bindings.)
fn bind_pattern(
&mut self,
outer_source_info: SourceInfo,
@ -638,12 +646,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Optimize the case of `let x: T = ...` to write directly
// into `x` and then require that `T == typeof(x)`.
//
// Weirdly, this is needed to prevent the
// `intrinsic-move-val.rs` test case from crashing. That
// test works with uninitialized values in a rather
// dubious way, so it may be that the test is kind of
// broken.
PatKind::AscribeUserType {
subpattern:
box Pat {
@ -1022,7 +1024,8 @@ impl<'tcx> PatternExtraData<'tcx> {
}
}
/// A pattern in a form suitable for generating code.
/// A pattern in a form suitable for lowering the match tree, with all irrefutable
/// patterns simplified away, and or-patterns sorted to the end.
///
/// Here, "flat" indicates that the pattern's match pairs have been recursively
/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily
@ -1055,36 +1058,89 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
ascriptions: Vec::new(),
is_never: pattern.is_never_pattern(),
};
// Partly-flatten and sort the match pairs, while recording extra data.
// Recursively remove irrefutable match pairs, while recording their
// bindings/ascriptions, and sort or-patterns after other match pairs.
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
Self { match_pairs, extra_data }
}
}
/// Candidates are a generalization of (a) top-level match arms, and
/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle
/// them both in a mostly-uniform way. For example, the list of candidates passed
/// to [`Builder::match_candidates`] will often contain a mixture of top-level
/// candidates and or-pattern subcandidates.
///
/// At the start of match lowering, there is one candidate for each match arm.
/// During match lowering, arms with or-patterns will be expanded into a tree
/// of candidates, where each "leaf" candidate represents one of the ways for
/// the arm pattern to successfully match.
#[derive(Debug)]
struct Candidate<'pat, 'tcx> {
/// For the candidate to match, all of these must be satisfied...
// Invariant: all the match pairs are recursively simplified.
// Invariant: or-patterns must be sorted at the end.
///
/// ---
/// Initially contains a list of match pairs created by [`FlatPat`], but is
/// subsequently mutated (in a queue-like way) while lowering the match tree.
/// When this list becomes empty, the candidate is fully matched and becomes
/// a leaf (see [`Builder::select_matched_candidate`]).
///
/// Key mutations include:
///
/// - When a match pair is fully satisfied by a test, it is removed from the
/// list, and its subpairs are added instead (see [`Builder::sort_candidate`]).
/// - During or-pattern expansion, any leading or-pattern is removed, and is
/// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
/// - After a candidate's subcandidates have been lowered, a copy of any remaining
/// or-patterns is added to each leaf subcandidate
/// (see [`Builder::test_remaining_match_pairs_after_or`]).
///
/// Invariants:
/// - All [`TestCase::Irrefutable`] patterns have been removed by simplification.
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
match_pairs: Vec<MatchPairTree<'pat, 'tcx>>,
/// ...and if this is non-empty, one of these subcandidates also has to match...
// Invariant: at the end of the algorithm, this must never contain a `is_never` candidate
// because that would break binding consistency.
///
/// ---
/// Initially a candidate has no subcandidates; they are added (and then immediately
/// lowered) during or-pattern expansion. Their main function is to serve as _output_
/// of match tree lowering, allowing later steps to see the leaf candidates that
/// represent a match of the entire match arm.
///
/// A candidate no subcandidates is either incomplete (if it has match pairs left),
/// or is a leaf in the match tree. A candidate with one or more subcandidates is
/// an internal node in the match tree.
///
/// Invariant: at the end of match tree lowering, this must not contain an
/// `is_never` candidate, because that would break binding consistency.
/// - See [`Builder::remove_never_subcandidates`].
subcandidates: Vec<Candidate<'pat, 'tcx>>,
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
///
/// ---
/// For subcandidates, this is copied from the parent candidate, so it indicates
/// whether the enclosing match arm has a guard.
has_guard: bool,
/// If the candidate matches, bindings and ascriptions must be established.
/// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and
/// ascriptions that must be established if this candidate succeeds.
extra_data: PatternExtraData<'tcx>,
/// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
// Invariant: it is `None` iff `subcandidates.is_empty()`.
/// When setting `self.subcandidates`, we store here the span of the or-pattern they came from.
///
/// ---
/// Invariant: it is `None` iff `subcandidates.is_empty()`.
/// - FIXME: We sometimes don't unset this when clearing `subcandidates`.
or_span: Option<Span>,
/// The block before the `bindings` have been established.
///
/// After the match tree has been lowered, [`Builder::lower_match_arms`]
/// will use this as the start point for lowering bindings and guards, and
/// then jump to a shared block containing the arm body.
pre_binding_block: Option<BasicBlock>,
/// The block to branch to if the guard or a nested candidate fails to match.
@ -1144,14 +1200,24 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
/// A depth-first traversal of the `Candidate` and all of its recursive
/// subcandidates.
///
/// This signature is very generic, to support traversing candidate trees by
/// reference or by value, and to allow a mutable "context" to be shared by the
/// traversal callbacks. Most traversals can use the simpler
/// [`Candidate::visit_leaves`] wrapper instead.
fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
candidate: C,
context: &mut T,
// Called when visiting a "leaf" candidate (with no subcandidates).
visit_leaf: &mut impl FnMut(C, &mut T),
// Called when visiting a "node" candidate (with one or more subcandidates).
// Returns an iterator over the candidate's children (by value or reference).
// Can perform setup before visiting the node's children.
get_children: impl Copy + Fn(C, &mut T) -> I,
// Called after visiting a "node" candidate's children.
complete_children: impl Copy + Fn(&mut T),
) where
C: Borrow<Candidate<'pat, 'tcx>>,
C: Borrow<Candidate<'pat, 'tcx>>, // Typically `Candidate` or `&mut Candidate`
I: Iterator<Item = C>,
{
if candidate.borrow().subcandidates.is_empty() {
@ -1182,6 +1248,24 @@ struct Ascription<'tcx> {
variance: ty::Variance,
}
/// Partial summary of a [`thir::Pat`], indicating what sort of test should be
/// performed to match/reject the pattern, and what the desired test outcome is.
/// This avoids having to perform a full match on [`thir::PatKind`] in some places,
/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target
/// values to use.
///
/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair)
///
/// Two variants are unlike the others and deserve special mention:
///
/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`].
/// They are then flattened away by [`Builder::simplify_match_pairs`], with any
/// bindings/ascriptions incorporated into the enclosing [`FlatPat`].
/// - [`Self::Or`] are not tested directly like the other variants. Instead they
/// participate in or-pattern expansion, where they are transformed into subcandidates.
/// - See [`Builder::expand_and_match_or_candidates`].
#[derive(Debug, Clone)]
enum TestCase<'pat, 'tcx> {
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
@ -1224,6 +1308,12 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
test_case: TestCase<'pat, 'tcx>,
/// ... and these subpairs must match.
///
/// ---
/// Subpairs typically represent tests that can only be performed after their
/// parent has succeeded. For example, the pattern `Some(3)` might have an
/// outer match pair that tests for the variant `Some`, and then a subpair
/// that tests its field for the value `3`.
subpairs: Vec<Self>,
/// The pattern this was created from.
@ -1234,15 +1324,22 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
#[derive(Clone, Debug, PartialEq)]
enum TestKind<'tcx> {
/// Test what enum variant a value is.
///
/// The subset of expected variants is not stored here; instead they are
/// extracted from the [`TestCase`]s of the candidates participating in the
/// test.
Switch {
/// The enum type being tested.
adt_def: ty::AdtDef<'tcx>,
},
/// Test what value an integer or `char` has.
///
/// The test's target values are not stored here; instead they are extracted
/// from the [`TestCase`]s of the candidates participating in the test.
SwitchInt,
/// Test what value a `bool` has.
/// Test whether a `bool` is `true` or `false`.
If,
/// Test for equality with value, possibly after an unsizing coercion to
@ -1258,7 +1355,7 @@ enum TestKind<'tcx> {
/// Test whether the value falls within an inclusive or exclusive range.
Range(Box<PatRange<'tcx>>),
/// Test that the length of the slice is equal to `len`.
/// Test that the length of the slice is `== len` or `>= len`.
Len { len: u64, op: BinOp },
/// Call `Deref::deref[_mut]` on the value.
@ -1385,20 +1482,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
/// generating code that branches to an appropriate block if the scrutinee matches one of these
/// candidates. The
/// candidates are sorted such that the first item in the list
/// candidates are ordered such that the first item in the list
/// has the highest priority. When a candidate is found to match
/// the value, we will set and generate a branch to the appropriate
/// pre-binding block.
///
/// If none of the candidates apply, we continue to the returned `otherwise_block`.
///
/// It might be surprising that the input can be non-exhaustive.
/// Indeed, for matches, initially, it is not, because all matches are
/// exhaustive in Rust. But during processing we sometimes divide
/// up the list of candidates and recurse with a non-exhaustive
/// list. This is how our lowering approach (called "backtracking
/// automaton" in the literature) works.
/// See [`Builder::test_candidates`] for more details.
/// Note that while `match` expressions in the Rust language are exhaustive,
/// candidate lists passed to this method are often _non-exhaustive_.
/// For example, the match lowering process will frequently divide up the
/// list of candidates, and recursively call this method with a non-exhaustive
/// subset of candidates.
/// See [`Builder::test_candidates`] for more details on this
/// "backtracking automata" approach.
///
/// For an example of how we use `otherwise_block`, consider:
/// ```
@ -1478,14 +1575,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
return start_block;
}
[first, remaining @ ..] if first.match_pairs.is_empty() => {
// The first candidate has satisfied all its match pairs; we link it up and continue
// with the remaining candidates.
// The first candidate has satisfied all its match pairs.
// We record the blocks that will be needed by match arm lowering,
// and then continue with the remaining candidates.
let remainder_start = self.select_matched_candidate(first, start_block);
remainder_start.and(remaining)
}
candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
// If any candidate starts with an or-pattern, we have to expand the or-pattern before we
// can proceed further.
// If any candidate starts with an or-pattern, we want to expand or-patterns
// before we do any more tests.
//
// The only candidate we strictly _need_ to expand here is the first one.
// But by expanding other candidates as early as possible, we unlock more
// opportunities to include them in test outcomes, making the match tree
// smaller and simpler.
self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)
}
candidates => {
@ -1588,6 +1691,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
// Expand one level of or-patterns for each candidate in `candidates_to_expand`.
// We take care to preserve the relative ordering of candidates, so that
// or-patterns are expanded in their parent's relative position.
let mut expanded_candidates = Vec::new();
for candidate in candidates_to_expand.iter_mut() {
if candidate.starts_with_or_pattern() {
@ -1608,7 +1713,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
// Process the expanded candidates.
// Recursively lower the part of the match tree represented by the
// expanded candidates. This is where subcandidates actually get lowered!
let remainder_start = self.match_candidates(
span,
scrutinee_span,
@ -1628,6 +1734,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.remove_never_subcandidates(candidate);
}
}
// It's important to perform the above simplifications _before_ dealing
// with remaining match pairs, to avoid exponential blowup if possible
// (for trivial or-patterns), and avoid useless work (for never patterns).
if let Some(last_candidate) = candidates_to_expand.last_mut() {
self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
}
@ -1808,6 +1917,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
);
// Visit each leaf candidate within this subtree, add a copy of the remaining
// match pairs to it, and then recursively lower the rest of the match tree
// from that point.
candidate.visit_leaves(|leaf_candidate| {
// At this point the leaf's own match pairs have all been lowered
// and removed, so `extend` and assignment are equivalent,
@ -1860,17 +1972,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
(match_place, test)
}
/// Given a test, we sort the input candidates into several buckets. If a candidate only matches
/// in one of the branches of `test`, we move it there. If it could match in more than one of
/// the branches of `test`, we stop sorting candidates.
/// Given a test, we partition the input candidates into several buckets.
/// If a candidate matches in exactly one of the branches of `test`
/// (and no other branches), we put it into the corresponding bucket.
/// If it could match in more than one of the branches of `test`, the test
/// doesn't usefully apply to it, and we stop partitioning candidates.
///
/// Importantly, we also **mutate** the branched candidates to remove match pairs
/// that are entailed by the outcome of the test, and add any sub-pairs of the
/// removed pairs.
///
/// This returns a pair of
/// - the candidates that weren't sorted;
/// - for each possible outcome of the test, the candidates that match in that outcome.
///
/// Moreover, we transform the branched candidates to reflect the fact that we know which
/// outcome of `test` occurred.
///
/// For example:
/// ```
/// # let (x, y, z) = (true, true, true);
@ -1883,14 +1998,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// # ;
/// ```
///
/// Assume we are testing on `x`. There are 2 overlapping candidate sets:
/// - If the outcome is that `x` is true, candidates 0, 2, and 3
/// - If the outcome is that `x` is false, candidates 1 and 2
/// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets:
/// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible
/// - If the outcome is that `x` is false, candidates {1, 2} are possible
///
/// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes
/// into outcome `x == false`, and candidate 2 and 3 remain unsorted.
/// Following our algorithm:
/// - Candidate 0 is sorted into outcome `x == true`
/// - Candidate 1 is sorted into outcome `x == false`
/// - Candidate 2 remains unsorted, because testing `x` has no effect on it
/// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
/// - This helps preserve the illusion that candidates are tested "in order"
///
/// The sorted candidates are transformed:
/// The sorted candidates are mutated to remove entailed match pairs:
/// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
/// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
fn sort_candidates<'b, 'c, 'pat>(
@ -1933,15 +2052,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
(candidates, target_candidates)
}
/// This is the most subtle part of the match lowering algorithm. At this point, the input
/// candidates have been fully simplified, so all remaining match-pairs require some sort of
/// test.
/// This is the most subtle part of the match lowering algorithm. At this point, there are
/// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to
/// perform some sort of test to make progress.
///
/// Once we pick what sort of test we are going to perform, this test will help us winnow down
/// our candidates. So we walk over the candidates (from high to low priority) and check. We
/// compute, for each outcome of the test, a transformed list of candidates. If a candidate
/// matches in a single branch of our test, we add it to the corresponding outcome. We also
/// transform it to record the fact that we know which outcome occurred.
/// compute, for each outcome of the test, a list of (modified) candidates. If a candidate
/// matches in exactly one branch of our test, we add it to the corresponding outcome. We also
/// **mutate its list of match pairs** if appropriate, to reflect the fact that we know which
/// outcome occurred.
///
/// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1
/// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the
@ -2036,32 +2156,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
start_block: BasicBlock,
) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
// Extract the match-pair from the highest priority candidate and build a test from it.
// Choose a match pair from the first candidate, and use it to determine a
// test to perform that will confirm or refute that match pair.
let (match_place, test) = self.pick_test(candidates);
// For each of the N possible test outcomes, build the vector of candidates that applies if
// the test has that particular outcome.
// the test has that particular outcome. This also mutates the candidates to remove match
// pairs that are fully satisfied by the relevant outcome.
let (remaining_candidates, target_candidates) =
self.sort_candidates(match_place, &test, candidates);
// The block that we should branch to if none of the
// `target_candidates` match.
// The block that we should branch to if none of the `target_candidates` match.
let remainder_start = self.cfg.start_new_block();
// For each outcome of test, process the candidates that still apply.
// For each outcome of the test, recursively lower the rest of the match tree
// from that point. (Note that we haven't lowered the actual test yet!)
let target_blocks: FxIndexMap<_, _> = target_candidates
.into_iter()
.map(|(branch, mut candidates)| {
let branch_start = self.cfg.start_new_block();
// Recursively lower the rest of the match tree after the relevant outcome.
let branch_otherwise =
self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
// Link up the `otherwise` block of the subtree to `remainder_start`.
let source_info = self.source_info(span);
self.cfg.goto(branch_otherwise, source_info, remainder_start);
(branch, branch_start)
})
.collect();
// Perform the test, branching to one of N blocks.
// Perform the chosen test, branching to one of the N subtrees prepared above
// (or to `remainder_start` if no outcome was satisfied).
self.perform_test(
span,
scrutinee_span,

View File

@ -51,6 +51,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestCase::Never => TestKind::Never,
// Or-patterns are not tested directly; instead they are expanded into subcandidates,
// which are then distinguished by testing whatever non-or patterns they contain.
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
TestCase::Irrefutable { .. } => span_bug!(
@ -544,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.enumerate()
.find(|&(_, mp)| mp.place == Some(test_place))?;
// If true, the match pair is completely entailed by its corresponding test
// branch, so it can be removed. If false, the match pair is _compatible_
// with its test branch, but still needs a more specific test.
let fully_matched;
let ret = match (&test.kind, &match_pair.test_case) {
// If we are performing a variant switch, then this
@ -565,8 +570,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
(TestKind::SwitchInt, &TestCase::Constant { value })
if is_switch_ty(match_pair.pattern.ty) =>
{
// Beware: there might be some ranges sorted into the failure case; we must not add
// a success case that could be matched by one of these ranges.
// An important invariant of candidate sorting is that a candidate
// must not match in multiple branches. For `SwitchInt` tests, adding
// a new value might invalidate that property for range patterns that
// have already been sorted into the failure arm, so we must take care
// not to add such values here.
let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
test_case.as_range().is_some_and(|range| {
matches!(range.contains(value, self.tcx, self.param_env), None | Some(true))
@ -591,6 +599,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
(TestKind::SwitchInt, TestCase::Range(range)) => {
// When performing a `SwitchInt` test, a range pattern can be
// sorted into the failure arm if it doesn't contain _any_ of
// the values being tested. (This restricts what values can be
// added to the test by subsequent candidates.)
fully_matched = false;
let not_contained =
sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(

View File

@ -12,17 +12,16 @@ use super::elaborate;
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use crate::traits::{util, Obligation, ObligationCause};
use rustc_errors::FatalError;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, Upcast,
};
use rustc_middle::ty::{GenericArg, GenericArgs};
use rustc_middle::ty::{TypeVisitableExt, Upcast};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::abi::Abi;
@ -195,7 +194,13 @@ fn predicates_reference_self(
.predicates
.iter()
.map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
.filter_map(|predicate| predicate_references_self(tcx, predicate))
.filter_map(|(clause, sp)| {
// Super predicates cannot allow self projections, since they're
// impossible to make into existential bounds without eager resolution
// or something.
// e.g. `trait A: B<Item = Self::Assoc>`.
predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
})
.collect()
}
@ -204,20 +209,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
.filter_map(|c| predicate_references_self(tcx, c))
.filter_map(|(clause, sp)| {
// Item bounds *can* have self projections, since they never get
// their self type erased.
predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
})
.collect()
}
fn predicate_references_self<'tcx>(
tcx: TyCtxt<'tcx>,
(predicate, sp): (ty::Clause<'tcx>, Span),
trait_def_id: DefId,
predicate: ty::Clause<'tcx>,
sp: Span,
allow_self_projections: AllowSelfProjections,
) -> Option<Span> {
let self_ty = tcx.types.self_param;
let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
match predicate.kind().skip_binder() {
ty::ClauseKind::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
data.trait_ref.args[1..].iter().any(has_self_ty).then_some(sp)
data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
}
ty::ClauseKind::Projection(ref data) => {
// And similarly for projections. This should be redundant with
@ -235,9 +245,9 @@ fn predicate_references_self<'tcx>(
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
data.projection_term.args[1..].iter().any(has_self_ty).then_some(sp)
data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
}
ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
ty::ClauseKind::WellFormed(..)
| ty::ClauseKind::TypeOutlives(..)
@ -383,7 +393,12 @@ fn virtual_call_violations_for_method<'tcx>(
let mut errors = Vec::new();
for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
if contains_illegal_self_type_reference(
tcx,
trait_def_id,
sig.rebind(input_ty),
AllowSelfProjections::Yes,
) {
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
..
@ -396,7 +411,12 @@ fn virtual_call_violations_for_method<'tcx>(
errors.push(MethodViolationCode::ReferencesSelfInput(span));
}
}
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
if contains_illegal_self_type_reference(
tcx,
trait_def_id,
sig.output(),
AllowSelfProjections::Yes,
) {
errors.push(MethodViolationCode::ReferencesSelfOutput);
}
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
@ -482,7 +502,7 @@ fn virtual_call_violations_for_method<'tcx>(
return false;
}
contains_illegal_self_type_reference(tcx, trait_def_id, pred)
contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
}) {
errors.push(MethodViolationCode::WhereClauseReferencesSelf);
}
@ -711,121 +731,181 @@ fn receiver_is_dispatchable<'tcx>(
infcx.predicate_must_hold_modulo_regions(&obligation)
}
#[derive(Copy, Clone)]
enum AllowSelfProjections {
Yes,
No,
}
/// This is somewhat subtle. In general, we want to forbid
/// references to `Self` in the argument and return types,
/// since the value of `Self` is erased. However, there is one
/// exception: it is ok to reference `Self` in order to access
/// an associated type of the current trait, since we retain
/// the value of those associated types in the object type
/// itself.
///
/// ```rust,ignore (example)
/// trait SuperTrait {
/// type X;
/// }
///
/// trait Trait : SuperTrait {
/// type Y;
/// fn foo(&self, x: Self) // bad
/// fn foo(&self) -> Self // bad
/// fn foo(&self) -> Option<Self> // bad
/// fn foo(&self) -> Self::Y // OK, desugars to next example
/// fn foo(&self) -> <Self as Trait>::Y // OK
/// fn foo(&self) -> Self::X // OK, desugars to next example
/// fn foo(&self) -> <Self as SuperTrait>::X // OK
/// }
/// ```
///
/// However, it is not as simple as allowing `Self` in a projected
/// type, because there are illegal ways to use `Self` as well:
///
/// ```rust,ignore (example)
/// trait Trait : SuperTrait {
/// ...
/// fn foo(&self) -> <Self as SomeOtherTrait>::X;
/// }
/// ```
///
/// Here we will not have the type of `X` recorded in the
/// object type, and we cannot resolve `Self as SomeOtherTrait`
/// without knowing what `Self` is.
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
value: T,
allow_self_projections: AllowSelfProjections,
) -> bool {
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
// exception: it is ok to reference `Self` in order to access
// an associated type of the current trait, since we retain
// the value of those associated types in the object type
// itself.
//
// ```rust
// trait SuperTrait {
// type X;
// }
//
// trait Trait : SuperTrait {
// type Y;
// fn foo(&self, x: Self) // bad
// fn foo(&self) -> Self // bad
// fn foo(&self) -> Option<Self> // bad
// fn foo(&self) -> Self::Y // OK, desugars to next example
// fn foo(&self) -> <Self as Trait>::Y // OK
// fn foo(&self) -> Self::X // OK, desugars to next example
// fn foo(&self) -> <Self as SuperTrait>::X // OK
// }
// ```
//
// However, it is not as simple as allowing `Self` in a projected
// type, because there are illegal ways to use `Self` as well:
//
// ```rust
// trait Trait : SuperTrait {
// ...
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
// }
// ```
//
// Here we will not have the type of `X` recorded in the
// object type, and we cannot resolve `Self as SomeOtherTrait`
// without knowing what `Self` is.
value
.visit_with(&mut IllegalSelfTypeVisitor {
tcx,
trait_def_id,
supertraits: None,
allow_self_projections,
})
.is_break()
}
struct IllegalSelfTypeVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
supertraits: Option<Vec<DefId>>,
}
struct IllegalSelfTypeVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
allow_self_projections: AllowSelfProjections,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
type Result = ControlFlow<()>;
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
match t.kind() {
ty::Param(_) => {
if t == self.tcx.types.self_param {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
ty::Alias(ty::Projection, ref data)
if self.tcx.is_impl_trait_in_trait(data.def_id) =>
{
// We'll deny these later in their own pass
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
match t.kind() {
ty::Param(_) => {
if t == self.tcx.types.self_param {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
ty::Alias(ty::Projection, ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazily.
if self.supertraits.is_none() {
let trait_ref =
ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
self.supertraits = Some(
traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
);
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let is_supertrait_of_current_trait = self
.supertraits
.as_ref()
.unwrap()
.contains(&data.trait_ref(self.tcx).def_id);
// only walk contained types if it's not a super trait
if is_supertrait_of_current_trait {
ControlFlow::Continue(())
} else {
t.super_visit_with(self) // POSSIBLY reporting an error
}
}
_ => t.super_visit_with(self), // walk contained types, if any
}
}
ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
// We'll deny these later in their own pass
ControlFlow::Continue(())
}
ty::Alias(ty::Projection, ref data) => {
match self.allow_self_projections {
AllowSelfProjections::Yes => {
// This is a projected type `<Foo as SomeTrait>::X`.
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
// Constants can only influence object safety if they are generic and reference `Self`.
// This is only possible for unevaluated constants, so we walk these here.
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
// Compute supertraits of current trait lazily.
if self.supertraits.is_none() {
self.supertraits = Some(
util::supertraits(
self.tcx,
ty::Binder::dummy(ty::TraitRef::identity(
self.tcx,
self.trait_def_id,
)),
)
.map(|trait_ref| {
self.tcx.erase_regions(
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
)
})
.collect(),
);
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let is_supertrait_of_current_trait =
self.supertraits.as_ref().unwrap().contains(
&data.trait_ref(self.tcx).fold_with(
&mut EraseEscapingBoundRegions {
tcx: self.tcx,
binder: ty::INNERMOST,
},
),
);
// only walk contained types if it's not a super trait
if is_supertrait_of_current_trait {
ControlFlow::Continue(())
} else {
t.super_visit_with(self) // POSSIBLY reporting an error
}
}
AllowSelfProjections::No => t.super_visit_with(self),
}
}
_ => t.super_visit_with(self),
}
}
value
.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
.is_break()
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
// Constants can only influence object safety if they are generic and reference `Self`.
// This is only possible for unevaluated constants, so we walk these here.
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
}
}
struct EraseEscapingBoundRegions<'tcx> {
tcx: TyCtxt<'tcx>,
binder: ty::DebruijnIndex,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.binder.shift_in(1);
let result = t.super_fold_with(self);
self.binder.shift_out(1);
result
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReBound(debruijn, _) = *r
&& debruijn < self.binder
{
r
} else {
self.tcx.lifetimes.re_erased
}
}
}
pub fn contains_illegal_impl_trait_in_trait<'tcx>(

View File

@ -24,6 +24,8 @@ mod convert;
mod decode;
mod methods;
// stable re-exports
#[rustfmt::skip]
#[stable(feature = "try_from", since = "1.34.0")]
pub use self::convert::CharTryFromError;
#[stable(feature = "char_from_str", since = "1.20.0")]
@ -31,11 +33,14 @@ pub use self::convert::ParseCharError;
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
// perma-unstable re-exports
#[rustfmt::skip]
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
pub use self::methods::encode_utf16_raw; // perma-unstable
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
pub use self::methods::encode_utf8_raw; // perma-unstable
#[rustfmt::skip]
use crate::ascii;
use crate::error::Error;
use crate::escape;

View File

@ -243,18 +243,6 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
/// Shuffle two vectors by const indices.
///
/// `T` must be a vector.
///
/// `U` must be a vector with the same element type as `T` and the same length as `IDX`.
///
/// Returns a new vector such that element `i` is selected from `xy[IDX[i]]`, where `xy`
/// is the concatenation of `x` and `y`. It is a compile-time error if `IDX[i]` is out-of-bounds
/// of `xy`.
#[rustc_nounwind]
pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
/// Read a vector of pointers.
///
/// `T` must be a vector.

View File

@ -249,7 +249,6 @@
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_const_params)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]
// tidy-alphabetical-end

View File

@ -42,6 +42,8 @@ use crate::hash::Hasher;
/// }
/// ```
#[unstable(feature = "internal_impls_macro", issue = "none")]
// Allow implementations of `UnsizedConstParamTy` even though std cannot use that feature.
#[allow_internal_unstable(unsized_const_params)]
macro marker_impls {
( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => {
$(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {}

View File

@ -1,13 +1,15 @@
#![unstable(feature = "unicode_internals", issue = "none")]
#![allow(missing_docs)]
// The `pub use` ones are for use in alloc, and are not re-exported in std.
pub(crate) use unicode_data::alphabetic::lookup as Alphabetic;
// for use in alloc, not re-exported in std.
#[rustfmt::skip]
pub use unicode_data::case_ignorable::lookup as Case_Ignorable;
pub use unicode_data::cased::lookup as Cased;
pub(crate) use unicode_data::cc::lookup as Cc;
pub use unicode_data::conversions;
#[rustfmt::skip]
pub(crate) use unicode_data::alphabetic::lookup as Alphabetic;
pub(crate) use unicode_data::cc::lookup as Cc;
pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend;
pub(crate) use unicode_data::lowercase::lookup as Lowercase;
pub(crate) use unicode_data::n::lookup as N;

View File

@ -16,9 +16,11 @@
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(unused_macros)]
#[rustfmt::skip]
pub use crate::panicking::{begin_panic, panic_count};
pub use core::panicking::{panic_display, panic_fmt};
#[rustfmt::skip]
use crate::sync::Once;
use crate::sys;
use crate::thread::{self, Thread};

View File

@ -416,8 +416,8 @@ impl File {
dwHighDateTime: (info.LastWriteTime >> 32) as u32,
},
change_time: Some(c::FILETIME {
dhLowDateTime: info.ChangeTime as c::DWORD,
dhHighDateTime: (info.ChangeTime >> 32) as c::DWORD,
dwLowDateTime: info.ChangeTime as u32,
dwHighDateTime: (info.ChangeTime >> 32) as u32,
}),
file_size: 0,
reparse_tag: 0,

View File

@ -1,10 +1,23 @@
//@compile-flags: -Zmiri-strict-provenance
#![feature(portable_simd, adt_const_params, core_intrinsics, repr_simd)]
#![feature(
portable_simd,
unsized_const_params,
adt_const_params,
rustc_attrs,
intrinsics,
core_intrinsics,
repr_simd
)]
#![allow(incomplete_features, internal_features)]
use std::intrinsics::simd as intrinsics;
use std::ptr;
use std::simd::{prelude::*, StdFloat};
extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
}
fn simd_ops_f32() {
let a = f32x4::splat(10.0);
let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]);

View File

@ -0,0 +1,11 @@
#![feature(effects)]
//~^ WARN: the feature `effects` is incomplete
struct A();
impl const Drop for A {}
//~^ ERROR: const trait impls are experimental
//~| const `impl` for trait `Drop` which is not marked with `#[const_trait]`
//~| not all trait items implemented, missing: `drop`
fn main() {}

View File

@ -0,0 +1,45 @@
error[E0658]: const trait impls are experimental
--> $DIR/const_drop_is_valid.rs:6:6
|
LL | impl const Drop for A {}
| ^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/const_drop_is_valid.rs:1:12
|
LL | #![feature(effects)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
error: using `#![feature(effects)]` without enabling next trait solver globally
|
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable
error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
--> $DIR/const_drop_is_valid.rs:6:12
|
LL | impl const Drop for A {}
| ^^^^
|
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
error[E0046]: not all trait items implemented, missing: `drop`
--> $DIR/const_drop_is_valid.rs:6:1
|
LL | impl const Drop for A {}
| ^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation
|
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0046, E0658.
For more information about an error, try `rustc --explain E0046`.

View File

@ -0,0 +1,13 @@
//@ check-pass
struct Foo<T: Trait>(T);
trait Trait {
type Assoc;
}
impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T> {
fn drop(&mut self) {}
}
fn main() {}

View File

@ -0,0 +1,12 @@
trait Trait {
type Assoc;
}
struct Foo<T: Trait, U: ?Sized>(T, U);
impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T, U> {
//~^ ERROR: `Drop` impl requires `<T as Trait>::Assoc == U`
fn drop(&mut self) {}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0367]: `Drop` impl requires `<T as Trait>::Assoc == U` but the struct it is implemented for does not
--> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:7:15
|
LL | impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T, U> {
| ^^^^^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:5:1
|
LL | struct Foo<T: Trait, U: ?Sized>(T, U);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0367`.

View File

@ -1,75 +1,145 @@
// Issue 8142: Test that Drop impls cannot be specialized beyond the
// predicates attached to the type definition itself.
trait Bound { fn foo(&self) { } }
struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
struct M<'m> { x: &'m i8 }
struct N<'n> { x: &'n i8 }
struct O<To> { x: *const To }
struct P<Tp> { x: *const Tp }
struct Q<Tq> { x: *const Tq }
struct R<Tr> { x: *const Tr }
struct S<Ts:Bound> { x: *const Ts }
struct T<'t,Ts:'t> { x: &'t Ts }
trait Bound {
fn foo(&self) {}
}
struct K<'l1, 'l2> {
x: &'l1 i8,
y: &'l2 u8,
}
struct L<'l1, 'l2> {
x: &'l1 i8,
y: &'l2 u8,
}
struct M<'m> {
x: &'m i8,
}
struct N<'n> {
x: &'n i8,
}
struct O<To> {
x: *const To,
}
struct P<Tp> {
x: *const Tp,
}
struct Q<Tq> {
x: *const Tq,
}
struct R<Tr> {
x: *const Tr,
}
struct S<Ts: Bound> {
x: *const Ts,
}
struct T<'t, Ts: 't> {
x: &'t Ts,
}
struct U;
struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
struct V<Tva, Tvb> {
x: *const Tva,
y: *const Tvb,
}
struct W<'l1, 'l2> {
x: &'l1 i8,
y: &'l2 u8,
}
struct X<const Ca: usize>;
struct Y<const Ca: usize, const Cb: usize>;
enum Enum<T> { Variant(T) }
enum Enum<T> {
Variant(T),
}
struct TupleStruct<T>(T);
union Union<T: Copy> { f: T }
union Union<T: Copy> {
f: T,
}
impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> {
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
fn drop(&mut self) { } }
fn drop(&mut self) {}
}
impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
fn drop(&mut self) { } }
impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd>
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
where
'adds_bnd: 'al,
{
fn drop(&mut self) {}
}
impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
impl<'ml> Drop for M<'ml> {
fn drop(&mut self) {}
}
impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl Drop for N<'static> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl<COkNoBound> Drop for O<COkNoBound> { fn drop(&mut self) { } } // ACCEPT
impl<COkNoBound> Drop for O<COkNoBound> {
fn drop(&mut self) {}
}
impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl Drop for P<i8> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
impl<AddsBnd: Bound> Drop for Q<AddsBnd> {
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
fn drop(&mut self) {}
}
impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impl requires `AddsRBnd: 'rbnd`
impl<'rbnd, AddsRBnd: 'rbnd> Drop for R<AddsRBnd> {
fn drop(&mut self) {}
}
impl<Bs:Bound> Drop for S<Bs> { fn drop(&mut self) { } } // ACCEPT
impl<Bs: Bound> Drop for S<Bs> {
fn drop(&mut self) {}
}
impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
impl<'t, Bt: 't> Drop for T<'t, Bt> {
fn drop(&mut self) {}
}
impl Drop for U { fn drop(&mut self) { } } // ACCEPT
impl Drop for U {
fn drop(&mut self) {}
}
impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl<One> Drop for V<One, One> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl<'lw> Drop for W<'lw, 'lw> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl Drop for X<3> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impls cannot be specialized
impl<const Ca: usize> Drop for Y<Ca, Ca> {
//~^ ERROR `Drop` impls cannot be specialized
fn drop(&mut self) {}
}
impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
impl<AddsBnd: Bound> Drop for Enum<AddsBnd> {
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
fn drop(&mut self) {}
}
impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
impl<AddsBnd: Bound> Drop for TupleStruct<AddsBnd> {
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
fn drop(&mut self) {}
}
impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
impl<AddsBnd: Copy + Bound> Drop for Union<AddsBnd> {
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
fn drop(&mut self) {}
}
pub fn main() { }
pub fn main() {}

View File

@ -1,166 +1,157 @@
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:24:20
--> $DIR/reject-specialized-drops-8142.rs:58:1
|
LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
| ^^^
LL | impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:4:1
--> $DIR/reject-specialized-drops-8142.rs:6:1
|
LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^^^^^^^^^^^^^^^
LL | struct K<'l1, 'l2> {
| ^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:28:67
--> $DIR/reject-specialized-drops-8142.rs:63:1
|
LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
| ^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:5:1
|
LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:34:1
|
LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `'static` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:7:1
|
LL | struct N<'n> { x: &'n i8 }
| ^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:39:1
|
LL | impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `i8` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:9:1
|
LL | struct P<Tp> { x: *const Tp }
| ^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:42:14
|
LL | impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
LL | / impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd>
LL | |
LL | | where
LL | | 'adds_bnd: 'al,
| |___________________^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:10:1
|
LL | struct Q<Tq> { x: *const Tq }
| ^^^^^^^^^^^^
LL | struct L<'l1, 'l2> {
| ^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:45:21
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:75:1
|
LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
LL | impl Drop for N<'static> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:11:1
= note: `'static` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:17:1
|
LL | struct R<Tr> { x: *const Tr }
LL | struct N<'n> {
| ^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:54:1
--> $DIR/reject-specialized-drops-8142.rs:84:1
|
LL | impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Drop for P<i8> {
| ^^^^^^^^^^^^^^^^^^^
|
= note: `i8` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:23:1
|
LL | struct P<Tp> {
| ^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:89:15
|
LL | impl<AddsBnd: Bound> Drop for Q<AddsBnd> {
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:26:1
|
LL | struct Q<Tq> {
| ^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:110:1
|
LL | impl<One> Drop for V<One, One> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `One` is mentioned multiple times
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:15:1
--> $DIR/reject-specialized-drops-8142.rs:39:1
|
LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
LL | struct V<Tva, Tvb> {
| ^^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:57:1
--> $DIR/reject-specialized-drops-8142.rs:115:1
|
LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<'lw> Drop for W<'lw, 'lw> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `'lw` is mentioned multiple times
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:16:1
--> $DIR/reject-specialized-drops-8142.rs:43:1
|
LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
LL | struct W<'l1, 'l2> {
| ^^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:60:1
--> $DIR/reject-specialized-drops-8142.rs:120:1
|
LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Drop for X<3> {
| ^^^^^^^^^^^^^^^^^^
|
= note: `3` is not a generic parameter
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:17:1
--> $DIR/reject-specialized-drops-8142.rs:47:1
|
LL | struct X<const Ca: usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
--> $DIR/reject-specialized-drops-8142.rs:63:1
--> $DIR/reject-specialized-drops-8142.rs:125:1
|
LL | impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
LL | impl<const Ca: usize> Drop for Y<Ca, Ca> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Ca` is mentioned multiple times
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
--> $DIR/reject-specialized-drops-8142.rs:18:1
--> $DIR/reject-specialized-drops-8142.rs:48:1
|
LL | struct Y<const Ca: usize, const Cb: usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:66:14
--> $DIR/reject-specialized-drops-8142.rs:130:15
|
LL | impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
LL | impl<AddsBnd: Bound> Drop for Enum<AddsBnd> {
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:20:1
--> $DIR/reject-specialized-drops-8142.rs:50:1
|
LL | enum Enum<T> { Variant(T) }
LL | enum Enum<T> {
| ^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:69:14
--> $DIR/reject-specialized-drops-8142.rs:135:15
|
LL | impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
LL | impl<AddsBnd: Bound> Drop for TupleStruct<AddsBnd> {
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:21:1
--> $DIR/reject-specialized-drops-8142.rs:53:1
|
LL | struct TupleStruct<T>(T);
| ^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
--> $DIR/reject-specialized-drops-8142.rs:72:21
--> $DIR/reject-specialized-drops-8142.rs:140:22
|
LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
LL | impl<AddsBnd: Copy + Bound> Drop for Union<AddsBnd> {
| ^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/reject-specialized-drops-8142.rs:22:1
--> $DIR/reject-specialized-drops-8142.rs:54:1
|
LL | union Union<T: Copy> { f: T }
LL | union Union<T: Copy> {
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 13 previous errors
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0366, E0367.
For more information about an error, try `rustc --explain E0366`.

View File

@ -1,8 +1,11 @@
error[E0367]: `Drop` impl requires `'a: 'c` but the struct it is implemented for does not
--> $DIR/transitive-outlives.rs:20:9
--> $DIR/transitive-outlives.rs:18:1
|
LL | 'a: 'c,
| ^^
LL | / impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
LL | |
LL | | where
LL | | 'a: 'c,
| |___________^
|
note: the implementor must specify the same requirement
--> $DIR/transitive-outlives.rs:7:1

View File

@ -16,9 +16,9 @@ where
#[cfg(bad)]
impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
//[bad]~^ ERROR `Drop` impl requires `'a: 'c`
where
'a: 'c,
//[bad]~^ ERROR `Drop` impl requires `'a: 'c`
{
fn drop(&mut self) {}
}

View File

@ -0,0 +1,7 @@
struct Foo {}
impl<const UNUSED: usize> Drop for Foo {}
//~^ ERROR: `Drop` impl requires `the constant `_` has type `usize``
//~| ERROR: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates
fn main() {}

View File

@ -0,0 +1,25 @@
error[E0367]: `Drop` impl requires `the constant `_` has type `usize`` but the struct it is implemented for does not
--> $DIR/unconstrained_const_param_on_drop.rs:3:6
|
LL | impl<const UNUSED: usize> Drop for Foo {}
| ^^^^^^^^^^^^^^^^^^^
|
note: the implementor must specify the same requirement
--> $DIR/unconstrained_const_param_on_drop.rs:1:1
|
LL | struct Foo {}
| ^^^^^^^^^^
error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained_const_param_on_drop.rs:3:6
|
LL | impl<const UNUSED: usize> Drop for Foo {}
| ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0207, E0367.
For more information about an error, try `rustc --explain E0207`.

View File

@ -0,0 +1,60 @@
// Test for fixed unsoundness in #126079.
// Enforces that the associated types that are object safe
use std::marker::PhantomData;
fn transmute<T, U>(t: T) -> U {
(&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
//~^ ERROR the trait `Foo` cannot be made into an object
//~| ERROR the trait `Foo` cannot be made into an object
}
struct ActuallySuper;
struct NotActuallySuper;
trait Super<Q> {
type Assoc;
}
trait Dyn {
type Out;
}
impl<T, U> Dyn for dyn Foo<T, U> + '_ {
//~^ ERROR the trait `Foo` cannot be made into an object
type Out = U;
}
impl<S: Dyn<Out = U> + ?Sized, U> Super<NotActuallySuper> for S {
type Assoc = U;
}
trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
where
<Self as Mirror>::Assoc: Super<NotActuallySuper>
{
fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
}
trait Mirror {
type Assoc: ?Sized;
}
impl<T: ?Sized> Mirror for T {
type Assoc = T;
}
impl<T, U> Foo<T, U> for PhantomData<T> {
fn transmute(&self, t: T) -> T {
t
}
}
impl<T> Super<ActuallySuper> for PhantomData<T> {
type Assoc = T;
}
impl<T> Super<NotActuallySuper> for PhantomData<T> {
type Assoc = T;
}
fn main() {
let x = String::from("hello, world");
let s = transmute::<&str, &'static str>(x.as_str());
drop(x);
println!("> {s}");
}

View File

@ -0,0 +1,55 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/almost-supertrait-associated-type.rs:21:20
|
LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ {
| ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
| --- this trait cannot be made into an object...
...
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
= help: consider moving `transmute` to another trait
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/almost-supertrait-associated-type.rs:7:27
|
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
| ^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
| --- this trait cannot be made into an object...
...
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
= help: consider moving `transmute` to another trait
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/almost-supertrait-associated-type.rs:7:6
|
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
| ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
| --- this trait cannot be made into an object...
...
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
= help: consider moving `transmute` to another trait
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
= note: required for the cast from `&PhantomData<T>` to `&dyn Foo<T, U>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0038`.

View File

@ -0,0 +1,11 @@
//@ check-pass
pub trait Foo {
type X: PartialEq;
type Y: PartialEq<Self::Y>;
type Z: PartialEq<Self::Y>;
}
fn uwu(x: &dyn Foo<X = i32, Y = i32, Z = i32>) {}
fn main() {}