2022-09-26 13:00:29 +02:00
|
|
|
// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
|
2022-06-29 17:46:16 +02:00
|
|
|
//
|
|
|
|
// We don't do any drop checking during hir typeck.
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
2024-01-04 09:08:36 +11:00
|
|
|
use rustc_errors::{struct_span_code_err, ErrorGuaranteed};
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
|
|
|
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
2023-04-25 07:36:58 +00:00
|
|
|
use rustc_middle::ty::util::CheckRegions;
|
2023-07-11 22:35:29 +01:00
|
|
|
use rustc_middle::ty::GenericArgsRef;
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_middle::ty::{self, TyCtxt};
|
|
|
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
2014-10-27 12:55:16 +01:00
|
|
|
|
2023-04-26 18:22:32 +00:00
|
|
|
use crate::errors;
|
|
|
|
use crate::hir::def_id::{DefId, LocalDefId};
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// This function confirms that the `Drop` implementation identified by
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
/// `drop_impl_did` is not any more specialized than the type it is
|
|
|
|
/// attached to (Issue #8142).
|
|
|
|
///
|
|
|
|
/// This means:
|
|
|
|
///
|
|
|
|
/// 1. The self type must be nominal (this is already checked during
|
|
|
|
/// coherence),
|
|
|
|
///
|
2019-02-08 14:53:55 +01:00
|
|
|
/// 2. The generic region/type parameters of the impl's self type must
|
2018-11-27 02:59:49 +00:00
|
|
|
/// all be parameters of the Drop impl itself (i.e., no
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
/// specialization like `impl Drop for Foo<i32>`), and,
|
|
|
|
///
|
|
|
|
/// 3. Any bounds on the generic parameters must be reflected in the
|
|
|
|
/// struct/enum definition for the nominal type itself (i.e.
|
|
|
|
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
|
|
|
///
|
2022-01-23 12:34:26 -06:00
|
|
|
pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> {
|
2023-04-26 18:22:32 +00:00
|
|
|
match tcx.impl_polarity(drop_impl_did) {
|
|
|
|
ty::ImplPolarity::Positive => {}
|
|
|
|
ty::ImplPolarity::Negative => {
|
2023-12-18 22:21:37 +11:00
|
|
|
return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Negative {
|
2023-04-26 18:22:32 +00:00
|
|
|
span: tcx.def_span(drop_impl_did),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
ty::ImplPolarity::Reservation => {
|
2023-12-18 22:21:37 +11:00
|
|
|
return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Reservation {
|
2023-04-26 18:22:32 +00:00
|
|
|
span: tcx.def_span(drop_impl_did),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
let dtor_self_type = tcx.type_of(drop_impl_did).instantiate_identity();
|
2020-08-03 00:49:11 +02:00
|
|
|
match dtor_self_type.kind() {
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(adt_def, adt_to_impl_args) => {
|
2018-09-25 11:32:39 -04:00
|
|
|
ensure_drop_params_and_item_params_correspond(
|
|
|
|
tcx,
|
2020-04-12 13:45:41 +01:00
|
|
|
drop_impl_did.expect_local(),
|
2022-03-05 07:28:41 +11:00
|
|
|
adt_def.did(),
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args,
|
2018-09-25 11:32:39 -04:00
|
|
|
)?;
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
|
2018-09-25 11:32:39 -04:00
|
|
|
ensure_drop_predicates_are_implied_by_item_defn(
|
|
|
|
tcx,
|
2023-04-20 03:56:36 +00:00
|
|
|
drop_impl_did.expect_local(),
|
2022-03-05 07:28:41 +11:00
|
|
|
adt_def.did().expect_local(),
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args,
|
2018-09-25 11:32:39 -04:00
|
|
|
)
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
_ => {
|
2022-11-16 20:34:16 +00:00
|
|
|
// Destructors only work on nominal types. This was
|
2018-01-01 17:51:37 +00:00
|
|
|
// already checked by coherence, but compilation may
|
|
|
|
// not have been terminated.
|
2016-10-04 02:19:40 +03:00
|
|
|
let span = tcx.def_span(drop_impl_did);
|
2023-12-18 22:21:37 +11:00
|
|
|
let reported = tcx.dcx().span_delayed_bug(
|
2019-12-16 11:28:28 -05:00
|
|
|
span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!("should have been rejected by coherence check: {dtor_self_type}"),
|
2019-12-16 11:28:28 -05:00
|
|
|
);
|
2022-01-22 18:49:12 -06:00
|
|
|
Err(reported)
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 23:35:39 +03:00
|
|
|
fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-04-12 13:45:41 +01:00
|
|
|
drop_impl_did: LocalDefId,
|
2018-09-25 11:32:39 -04:00
|
|
|
self_type_did: DefId,
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args: GenericArgsRef<'tcx>,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-11-14 13:13:27 +00:00
|
|
|
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else {
|
2022-03-23 10:06:29 +01:00
|
|
|
return Ok(());
|
|
|
|
};
|
2016-03-25 05:22:44 +02:00
|
|
|
|
2022-03-23 10:06:29 +01:00
|
|
|
let drop_impl_span = tcx.def_span(drop_impl_did);
|
|
|
|
let item_span = tcx.def_span(self_type_did);
|
2023-02-21 14:05:32 -07:00
|
|
|
let self_descr = tcx.def_descr(self_type_did);
|
2024-01-04 09:08:36 +11:00
|
|
|
let mut err = struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
|
|
|
drop_impl_span,
|
|
|
|
E0366,
|
|
|
|
"`Drop` impls cannot be specialized"
|
|
|
|
);
|
2022-03-23 10:06:29 +01:00
|
|
|
match arg {
|
|
|
|
ty::util::NotUniqueParam::DuplicateParam(arg) => {
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.note(format!("`{arg}` is mentioned multiple times"))
|
2016-03-25 05:22:44 +02:00
|
|
|
}
|
2022-03-23 10:06:29 +01:00
|
|
|
ty::util::NotUniqueParam::NotParam(arg) => {
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.note(format!("`{arg}` is not a generic parameter"))
|
2016-03-25 05:22:44 +02:00
|
|
|
}
|
2022-03-23 10:06:29 +01:00
|
|
|
};
|
|
|
|
err.span_note(
|
|
|
|
item_span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!(
|
2022-03-29 07:29:59 +02:00
|
|
|
"use the same sequence of generic lifetime, type and const parameters \
|
2022-03-23 10:06:29 +01:00
|
|
|
as the {self_descr} definition",
|
|
|
|
),
|
|
|
|
);
|
|
|
|
Err(err.emit())
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Confirms that every predicate imposed by dtor_predicates is
|
|
|
|
/// implied by assuming the predicates attached to self_type_did.
|
2019-06-11 23:35:39 +03:00
|
|
|
fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2023-04-20 03:56:36 +00:00
|
|
|
drop_impl_def_id: LocalDefId,
|
|
|
|
adt_def_id: LocalDefId,
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args: GenericArgsRef<'tcx>,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-04-20 03:56:36 +00:00
|
|
|
let infcx = tcx.infer_ctxt().build();
|
|
|
|
let ocx = ObligationCtxt::new(&infcx);
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
// Take the param-env of the adt and substitute the args that show up in
|
2023-04-20 03:56:36 +00:00
|
|
|
// 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
|
|
|
|
// well-formed adt, since that's all we're allowed to assume while proving
|
|
|
|
// the Drop implementation is not specialized.
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
//
|
2023-04-20 03:56:36 +00:00
|
|
|
// We don't need to normalize this param-env or anything, since we're only
|
|
|
|
// substituting 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.
|
2023-07-27 15:50:42 +00:00
|
|
|
let param_env =
|
|
|
|
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
|
2023-04-20 03:56:36 +00:00
|
|
|
|
|
|
|
for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
|
|
|
|
let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
|
|
|
|
let pred = ocx.normalize(&normalize_cause, param_env, pred);
|
|
|
|
let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl);
|
|
|
|
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
|
|
|
|
}
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
// All of the custom error reporting logic is to preserve parity with the old
|
|
|
|
// error messages.
|
|
|
|
//
|
|
|
|
// They can probably get removed with better treatment of the new `DropImpl`
|
|
|
|
// obligation cause code, and perhaps some custom logic in `report_region_errors`.
|
|
|
|
|
|
|
|
let errors = ocx.select_all_or_error();
|
|
|
|
if !errors.is_empty() {
|
|
|
|
let mut guar = None;
|
|
|
|
let mut root_predicates = FxHashSet::default();
|
|
|
|
for error in errors {
|
|
|
|
let root_predicate = error.root_obligation.predicate;
|
|
|
|
if root_predicates.insert(root_predicate) {
|
|
|
|
let item_span = tcx.def_span(adt_def_id);
|
|
|
|
let self_descr = tcx.def_descr(adt_def_id.to_def_id());
|
|
|
|
guar = Some(
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2023-04-20 03:56:36 +00:00
|
|
|
error.root_obligation.cause.span,
|
|
|
|
E0367,
|
|
|
|
"`Drop` impl requires `{root_predicate}` \
|
|
|
|
but the {self_descr} it is implemented for does not",
|
|
|
|
)
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
|
|
|
.span_note_mv(item_span, "the implementor must specify the same requirement")
|
2023-04-20 03:56:36 +00:00
|
|
|
.emit(),
|
|
|
|
);
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
2023-04-20 03:56:36 +00:00
|
|
|
return Err(guar.unwrap());
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
|
|
|
|
if !errors.is_empty() {
|
|
|
|
let mut guar = None;
|
|
|
|
for error in errors {
|
|
|
|
let item_span = tcx.def_span(adt_def_id);
|
|
|
|
let self_descr = tcx.def_descr(adt_def_id.to_def_id());
|
|
|
|
let outlives = match error {
|
|
|
|
RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
|
|
|
|
RegionResolutionError::GenericBoundFailure(_, generic, r) => {
|
|
|
|
format!("{generic}: {r}")
|
|
|
|
}
|
|
|
|
RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
|
|
|
|
RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
|
2023-05-29 17:54:53 +00:00
|
|
|
format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
|
2023-04-20 03:56:36 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
guar = Some(
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2023-04-20 03:56:36 +00:00
|
|
|
error.origin().span(),
|
|
|
|
E0367,
|
|
|
|
"`Drop` impl requires `{outlives}` \
|
|
|
|
but the {self_descr} it is implemented for does not",
|
|
|
|
)
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
|
|
|
.span_note_mv(item_span, "the implementor must specify the same requirement")
|
2023-04-20 03:56:36 +00:00
|
|
|
.emit(),
|
|
|
|
);
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
2023-04-20 03:56:36 +00:00
|
|
|
return Err(guar.unwrap());
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
Ok(())
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|