HIR ty lowering: Validate PointeeSized bounds
This commit is contained in:
parent
cdc3d701cb
commit
82a02aefe0
10 changed files with 135 additions and 78 deletions
|
|
@ -445,8 +445,6 @@ hir_analysis_parenthesized_fn_trait_expansion =
|
|||
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
|
||||
.label = not allowed in type signatures
|
||||
|
||||
hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects
|
||||
|
||||
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
|
||||
|
||||
|
|
|
|||
|
|
@ -311,13 +311,6 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits {
|
|||
pub trait_alias_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_pointee_sized_trait_object)]
|
||||
pub(crate) struct PointeeSizedTraitObject {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)]
|
||||
pub(crate) struct AmbiguousLifetimeBound {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
|
||||
use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
|
||||
use rustc_hir::{AmbigArg, PolyTraitRef};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
|
|
@ -124,13 +124,13 @@ fn collect_sizedness_bounds<'tcx>(
|
|||
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
|
||||
span: Span,
|
||||
) -> CollectedSizednessBounds {
|
||||
let sized_did = tcx.require_lang_item(LangItem::Sized, span);
|
||||
let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span);
|
||||
let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did);
|
||||
|
||||
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
|
||||
let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span);
|
||||
let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did);
|
||||
|
||||
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
|
||||
let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
|
||||
let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did);
|
||||
|
||||
CollectedSizednessBounds { sized, meta_sized, pointee_sized }
|
||||
|
|
@ -151,24 +151,6 @@ fn add_trait_bound<'tcx>(
|
|||
}
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Skip `PointeeSized` bounds.
|
||||
///
|
||||
/// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there
|
||||
/// is actually the absence of any bounds. This avoids limitations around non-global where
|
||||
/// clauses being preferred over item bounds (where `PointeeSized` bounds would be
|
||||
/// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is
|
||||
/// added to some items.
|
||||
pub(crate) fn should_skip_sizedness_bound<'hir>(
|
||||
&self,
|
||||
bound: &'hir hir::GenericBound<'tcx>,
|
||||
) -> bool {
|
||||
bound
|
||||
.trait_ref()
|
||||
.and_then(|tr| tr.trait_def_id())
|
||||
.map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type.
|
||||
///
|
||||
/// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit
|
||||
|
|
@ -193,8 +175,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
return;
|
||||
}
|
||||
|
||||
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
|
||||
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
|
||||
let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span);
|
||||
let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
|
||||
|
||||
// If adding sizedness bounds to a trait, then there are some relevant early exits
|
||||
if let Some(trait_did) = trait_did {
|
||||
|
|
@ -244,7 +226,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
} else {
|
||||
// If there are no explicit sizedness bounds on a parameter then add a default
|
||||
// `Sized` bound.
|
||||
let sized_did = tcx.require_lang_item(LangItem::Sized, span);
|
||||
let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span);
|
||||
add_trait_bound(tcx, bounds, self_ty, sized_did, span);
|
||||
}
|
||||
}
|
||||
|
|
@ -476,10 +458,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
'tcx: 'hir,
|
||||
{
|
||||
for hir_bound in hir_bounds {
|
||||
if self.should_skip_sizedness_bound(hir_bound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// In order to avoid cycles, when we're lowering `SelfTraitThatDefines`,
|
||||
// we skip over any traits that don't define the given associated type.
|
||||
if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
|
||||
use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
|
||||
|
|
@ -70,13 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let guar = self.report_trait_object_addition_traits(®ular_traits);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// We don't support `PointeeSized` principals
|
||||
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
|
||||
if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) {
|
||||
let guar = self.report_pointee_sized_trait_object(span);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
|
||||
// Don't create a dyn trait if we have errors in the principal.
|
||||
if let Err(guar) = regular_traits.error_reported() {
|
||||
return Ty::new_error(tcx, guar);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use tracing::debug;
|
|||
use super::InherentAssocCandidate;
|
||||
use crate::errors::{
|
||||
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
|
||||
ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits,
|
||||
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
|
||||
|
|
@ -1405,10 +1405,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
|
||||
}
|
||||
|
||||
pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.dcx().emit_err(PointeeSizedTraitObject { span })
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an error for the given associated item constraint.
|
||||
|
|
|
|||
|
|
@ -755,6 +755,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> GenericArgCountResult {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// We use the *resolved* bound vars later instead of the HIR ones since the former
|
||||
// also include the bound vars of the overarching predicate if applicable.
|
||||
let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
|
||||
|
|
@ -762,6 +764,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
|
||||
|
||||
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
||||
|
||||
// Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the `middle::ty` IR
|
||||
// as they denote the *absence* of a default bound. However, we can't bail out early here since
|
||||
// we still need to perform several validation steps (see below). Instead, simply "pour" all
|
||||
// resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end.
|
||||
let (polarity, bounds) = match polarity {
|
||||
rustc_ast::BoundPolarity::Positive
|
||||
if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) =>
|
||||
{
|
||||
// To elaborate on the comment directly above, regarding `PointeeSized` specifically,
|
||||
// we don't "reify" such bounds to avoid trait system limitations -- namely,
|
||||
// non-global where-clauses being preferred over item bounds (where `PointeeSized`
|
||||
// bounds would be proven) -- which can result in errors when a `PointeeSized`
|
||||
// supertrait / bound / predicate is added to some items.
|
||||
(ty::PredicatePolarity::Positive, &mut Vec::new())
|
||||
}
|
||||
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
|
||||
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
|
||||
rustc_ast::BoundPolarity::Maybe(_) => {
|
||||
(ty::PredicatePolarity::Positive, &mut Vec::new())
|
||||
}
|
||||
};
|
||||
|
||||
let trait_segment = trait_ref.path.segments.last().unwrap();
|
||||
|
||||
let _ = self.prohibit_generic_args(
|
||||
|
|
@ -778,7 +803,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Some(self_ty),
|
||||
);
|
||||
|
||||
let tcx = self.tcx();
|
||||
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
|
||||
debug!(?bound_vars);
|
||||
|
||||
|
|
@ -789,27 +813,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
debug!(?poly_trait_ref);
|
||||
|
||||
let polarity = match polarity {
|
||||
rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
|
||||
rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
|
||||
rustc_ast::BoundPolarity::Maybe(_) => {
|
||||
// Validate associated type at least. We may want to reject these
|
||||
// outright in the future...
|
||||
for constraint in trait_segment.args().constraints {
|
||||
let _ = self.lower_assoc_item_constraint(
|
||||
trait_ref.hir_ref_id,
|
||||
poly_trait_ref,
|
||||
constraint,
|
||||
&mut Default::default(),
|
||||
&mut Default::default(),
|
||||
constraint.span,
|
||||
predicate_filter,
|
||||
);
|
||||
}
|
||||
return arg_count;
|
||||
}
|
||||
};
|
||||
|
||||
// We deal with const conditions later.
|
||||
match predicate_filter {
|
||||
PredicateFilter::All
|
||||
|
|
@ -912,7 +915,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Don't register any associated item constraints for negative bounds,
|
||||
// since we should have emitted an error for them earlier, and they
|
||||
// would not be well-formed!
|
||||
if polarity != ty::PredicatePolarity::Positive {
|
||||
if polarity == ty::PredicatePolarity::Negative {
|
||||
self.dcx().span_delayed_bug(
|
||||
constraint.span,
|
||||
"negative trait bounds should not have assoc item constraints",
|
||||
|
|
|
|||
20
tests/ui/sized-hierarchy/pointee-validation.rs
Normal file
20
tests/ui/sized-hierarchy/pointee-validation.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Test that despite us dropping `PointeeSized` bounds during HIR ty lowering
|
||||
// we still validate it first.
|
||||
// issue: <https://github.com/rust-lang/rust/issues/142718>
|
||||
#![feature(sized_hierarchy)]
|
||||
|
||||
use std::marker::PointeeSized;
|
||||
|
||||
struct T where (): PointeeSized<(), Undefined = ()>;
|
||||
//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
|
||||
//~| ERROR associated type `Undefined` not found for `PointeeSized`
|
||||
|
||||
const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
//~^ ERROR `const` can only be applied to `const` traits
|
||||
//~| ERROR `const` can only be applied to `const` traits
|
||||
//~| ERROR const trait impls are experimental
|
||||
//~| ERROR `[const]` can only be applied to `const` traits
|
||||
//~| ERROR `[const]` can only be applied to `const` traits
|
||||
//~| ERROR const trait impls are experimental
|
||||
|
||||
fn main() {}
|
||||
76
tests/ui/sized-hierarchy/pointee-validation.stderr
Normal file
76
tests/ui/sized-hierarchy/pointee-validation.stderr
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/pointee-validation.rs:12:32
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> 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
|
||||
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/pointee-validation.rs:12:55
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> 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
|
||||
|
||||
error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
|
||||
--> $DIR/pointee-validation.rs:8:20
|
||||
|
|
||||
LL | struct T where (): PointeeSized<(), Undefined = ()>;
|
||||
| ^^^^^^^^^^^^-------------------- help: remove the unnecessary generics
|
||||
| |
|
||||
| expected 0 generic arguments
|
||||
|
||||
error[E0220]: associated type `Undefined` not found for `PointeeSized`
|
||||
--> $DIR/pointee-validation.rs:8:37
|
||||
|
|
||||
LL | struct T where (): PointeeSized<(), Undefined = ()>;
|
||||
| ^^^^^^^^^ associated type `Undefined` not found
|
||||
|
||||
error: `const` can only be applied to `const` traits
|
||||
--> $DIR/pointee-validation.rs:12:32
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^ can't be applied to `PointeeSized`
|
||||
|
|
||||
note: `PointeeSized` can't be used with `const` because it isn't `const`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
|
||||
error: `[const]` can only be applied to `const` traits
|
||||
--> $DIR/pointee-validation.rs:12:55
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^^^ can't be applied to `PointeeSized`
|
||||
|
|
||||
note: `PointeeSized` can't be used with `[const]` because it isn't `const`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
|
||||
error: `const` can only be applied to `const` traits
|
||||
--> $DIR/pointee-validation.rs:12:32
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^ can't be applied to `PointeeSized`
|
||||
|
|
||||
note: `PointeeSized` can't be used with `const` because it isn't `const`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `[const]` can only be applied to `const` traits
|
||||
--> $DIR/pointee-validation.rs:12:55
|
||||
|
|
||||
LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
|
||||
| ^^^^^^^ can't be applied to `PointeeSized`
|
||||
|
|
||||
note: `PointeeSized` can't be used with `[const]` because it isn't `const`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0220, E0658.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
use std::marker::PointeeSized;
|
||||
|
||||
type Foo = dyn PointeeSized;
|
||||
//~^ ERROR `PointeeSized` cannot be used with trait objects
|
||||
//~^ ERROR at least one trait is required for an object type
|
||||
|
||||
fn foo(f: &Foo) {}
|
||||
|
||||
|
|
@ -12,5 +12,5 @@ fn main() {
|
|||
|
||||
let x = main;
|
||||
let y: Box<dyn PointeeSized> = x;
|
||||
//~^ ERROR `PointeeSized` cannot be used with trait objects
|
||||
//~^ ERROR at least one trait is required for an object type
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
error: `PointeeSized` cannot be used with trait objects
|
||||
error[E0224]: at least one trait is required for an object type
|
||||
--> $DIR/reject-dyn-pointeesized.rs:5:12
|
||||
|
|
||||
LL | type Foo = dyn PointeeSized;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `PointeeSized` cannot be used with trait objects
|
||||
error[E0224]: at least one trait is required for an object type
|
||||
--> $DIR/reject-dyn-pointeesized.rs:14:16
|
||||
|
|
||||
LL | let y: Box<dyn PointeeSized> = x;
|
||||
|
|
@ -12,3 +12,4 @@ LL | let y: Box<dyn PointeeSized> = x;
|
|||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0224`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue