Skip to content

Commit 2fbb075

Browse files
committed
Auto merge of rust-lang#70427 - Centril:rollup-lrcad2c, r=Centril
Rollup of 5 pull requests Successful merges: - rust-lang#68004 (permit negative impls for non-auto traits) - rust-lang#70385 (Miri nits: comment and var name improvement) - rust-lang#70411 (Fix for rust-lang#62691: use the largest niche across all fields) - rust-lang#70417 (parser: recover on `...` as a pattern, suggesting `..`) - rust-lang#70424 (simplify match stmt) Failed merges: r? @ghost
2 parents 3b1d735 + 608715b commit 2fbb075

File tree

142 files changed

+956
-377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+956
-377
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# `negative_impls`
2+
3+
The tracking issue for this feature is [#68318].
4+
5+
[#68318]: https://github.com/rust-lang/rust/issues/68318
6+
7+
----
8+
9+
With the feature gate `negative_impls`, you can write negative impls as well as positive ones:
10+
11+
```rust
12+
#![feature(negative_impls)]
13+
trait DerefMut { }
14+
impl<T: ?Sized> !DerefMut for &T { }
15+
```
16+
17+
Negative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below.
18+
19+
Negative impls have the following characteristics:
20+
21+
* They do not have any items.
22+
* They must obey the orphan rules as if they were a positive impl.
23+
* They cannot "overlap" with any positive impls.
24+
25+
## Semver interaction
26+
27+
It is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types.
28+
29+
## Orphan and overlap rules
30+
31+
Negative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth.
32+
33+
Similarly, negative impls cannot overlap with positive impls, again using the same "overlap" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.)
34+
35+
## Interaction with auto traits
36+
37+
Declaring a negative impl `impl !SomeAutoTrait for SomeType` for an
38+
auto-trait serves two purposes:
39+
40+
* as with any trait, it declares that `SomeType` will never implement `SomeAutoTrait`;
41+
* it disables the automatic `SomeType: SomeAutoTrait` impl that would otherwise have been generated.
42+
43+
Note that, at present, there is no way to indicate that a given type
44+
does not implement an auto trait *but that it may do so in the
45+
future*. For ordinary types, this is done by simply not declaring any
46+
impl at all, but that is not an option for auto traits. A workaround
47+
is that one could embed a marker type as one of the fields, where the
48+
marker type is `!AutoTrait`.
49+
50+
## Immediate uses
51+
52+
Negative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, as required to fix the soundness of `Pin` described in [#66544](https://github.com/rust-lang/rust/issues/66544).
53+
54+
This serves two purposes:
55+
56+
* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists.
57+
* It prevents downstream crates from creating such impls.

src/doc/unstable-book/src/language-features/optin-builtin-traits.md

+63-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ The `optin_builtin_traits` feature gate allows you to define auto traits.
1010

1111
Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits
1212
that are automatically implemented for every type, unless the type, or a type it contains,
13-
has explicitly opted out via a negative impl.
13+
has explicitly opted out via a negative impl. (Negative impls are separately controlled
14+
by the `negative_impls` feature.)
1415

1516
[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
1617
[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
@@ -22,6 +23,7 @@ impl !Trait for Type
2223
Example:
2324

2425
```rust
26+
#![feature(negative_impls)]
2527
#![feature(optin_builtin_traits)]
2628

2729
auto trait Valid {}
@@ -43,3 +45,63 @@ fn main() {
4345
// must_be_valid( MaybeValid(False) );
4446
}
4547
```
48+
49+
## Automatic trait implementations
50+
51+
When a type is declared as an `auto trait`, we will automatically
52+
create impls for every struct/enum/union, unless an explicit impl is
53+
provided. These automatic impls contain a where clause for each field
54+
of the form `T: AutoTrait`, where `T` is the type of the field and
55+
`AutoTrait` is the auto trait in question. As an example, consider the
56+
struct `List` and the auto trait `Send`:
57+
58+
```rust
59+
struct List<T> {
60+
data: T,
61+
next: Option<Box<List<T>>>,
62+
}
63+
```
64+
65+
Presuming that there is no explicit impl of `Send` for `List`, the
66+
compiler will supply an automatic impl of the form:
67+
68+
```rust
69+
struct List<T> {
70+
data: T,
71+
next: Option<Box<List<T>>>,
72+
}
73+
74+
unsafe impl<T> Send for List<T>
75+
where
76+
T: Send, // from the field `data`
77+
Option<Box<List<T>>>: Send, // from the field `next`
78+
{ }
79+
```
80+
81+
Explicit impls may be either positive or negative. They take the form:
82+
83+
```rust,ignore
84+
impl<...> AutoTrait for StructName<..> { }
85+
impl<...> !AutoTrait for StructName<..> { }
86+
```
87+
88+
## Coinduction: Auto traits permit cyclic matching
89+
90+
Unlike ordinary trait matching, auto traits are **coinductive**. This
91+
means, in short, that cycles which occur in trait matching are
92+
considered ok. As an example, consider the recursive struct `List`
93+
introduced in the previous section. In attempting to determine whether
94+
`List: Send`, we would wind up in a cycle: to apply the impl, we must
95+
show that `Option<Box<List>>: Send`, which will in turn require
96+
`Box<List>: Send` and then finally `List: Send` again. Under ordinary
97+
trait matching, this cycle would be an error, but for an auto trait it
98+
is considered a successful match.
99+
100+
## Items
101+
102+
Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.
103+
104+
## Supertraits
105+
106+
Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.
107+

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#![feature(internal_uninit_const)]
100100
#![feature(lang_items)]
101101
#![feature(libc)]
102+
#![cfg_attr(not(bootstrap), feature(negative_impls))]
102103
#![feature(nll)]
103104
#![feature(optin_builtin_traits)]
104105
#![feature(pattern)]

src/libcore/clone.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,17 @@ mod impls {
219219
}
220220
}
221221

222-
// Shared references can be cloned, but mutable references *cannot*!
222+
/// Shared references can be cloned, but mutable references *cannot*!
223223
#[stable(feature = "rust1", since = "1.0.0")]
224224
impl<T: ?Sized> Clone for &T {
225225
#[inline]
226226
fn clone(&self) -> Self {
227227
*self
228228
}
229229
}
230+
231+
/// Shared references can be cloned, but mutable references *cannot*!
232+
#[stable(feature = "rust1", since = "1.0.0")]
233+
#[cfg(not(bootstrap))]
234+
impl<T: ?Sized> !Clone for &mut T {}
230235
}

src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
#![feature(is_sorted)]
9999
#![feature(lang_items)]
100100
#![feature(link_llvm_intrinsics)]
101+
#![cfg_attr(not(bootstrap), feature(negative_impls))]
101102
#![feature(never_type)]
102103
#![feature(nll)]
103104
#![feature(exhaustive_patterns)]

src/libcore/marker.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<T: ?Sized> !Send for *mut T {}
8787
message = "the size for values of type `{Self}` cannot be known at compilation time",
8888
label = "doesn't have a size known at compile-time",
8989
note = "to learn more, visit <https://doc.rust-lang.org/book/\
90-
ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
90+
ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
9191
)]
9292
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
9393
#[cfg_attr(not(bootstrap), rustc_specialization_trait)]
@@ -790,7 +790,7 @@ mod copy_impls {
790790
#[stable(feature = "rust1", since = "1.0.0")]
791791
impl<T: ?Sized> Copy for *mut T {}
792792

793-
// Shared references can be copied, but mutable references *cannot*!
793+
/// Shared references can be copied, but mutable references *cannot*!
794794
#[stable(feature = "rust1", since = "1.0.0")]
795795
impl<T: ?Sized> Copy for &T {}
796796
}

src/libcore/ops/deref.rs

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ impl<T: ?Sized> Deref for &T {
8181
}
8282
}
8383

84+
#[cfg(not(bootstrap))]
85+
#[stable(feature = "rust1", since = "1.0.0")]
86+
impl<T: ?Sized> !DerefMut for &T {}
87+
8488
#[stable(feature = "rust1", since = "1.0.0")]
8589
impl<T: ?Sized> Deref for &mut T {
8690
type Target = T;

src/libproc_macro/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#![feature(decl_macro)]
2525
#![feature(extern_types)]
2626
#![feature(in_band_lifetimes)]
27+
#![cfg_attr(not(bootstrap), feature(negative_impls))]
2728
#![feature(optin_builtin_traits)]
2829
#![feature(rustc_attrs)]
2930
#![cfg_attr(bootstrap, feature(specialization))]

src/librustc/ty/layout.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
282282

283283
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
284284

285-
let mut sized = true;
286-
let mut offsets = vec![Size::ZERO; fields.len()];
287285
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
288286

289287
let mut optimize = !repr.inhibit_struct_field_reordering_opt();
@@ -320,6 +318,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
320318
// At the bottom of this function, we invert `inverse_memory_index` to
321319
// produce `memory_index` (see `invert_mapping`).
322320

321+
let mut sized = true;
322+
let mut offsets = vec![Size::ZERO; fields.len()];
323323
let mut offset = Size::ZERO;
324324
let mut largest_niche = None;
325325
let mut largest_niche_available = 0;
@@ -900,18 +900,19 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
900900
let count = (niche_variants.end().as_u32()
901901
- niche_variants.start().as_u32()
902902
+ 1) as u128;
903-
// FIXME(#62691) use the largest niche across all fields,
904-
// not just the first one.
905-
for (field_index, &field) in variants[i].iter().enumerate() {
906-
let niche = match &field.largest_niche {
907-
Some(niche) => niche,
908-
_ => continue,
909-
};
910-
let (niche_start, niche_scalar) = match niche.reserve(self, count) {
911-
Some(pair) => pair,
912-
None => continue,
913-
};
914903

904+
// Find the field with the largest niche
905+
let niche_candidate = variants[i]
906+
.iter()
907+
.enumerate()
908+
.filter_map(|(j, &field)| Some((j, field.largest_niche.as_ref()?)))
909+
.max_by_key(|(_, niche)| niche.available(dl));
910+
911+
if let Some((field_index, niche, (niche_start, niche_scalar))) =
912+
niche_candidate.and_then(|(field_index, niche)| {
913+
Some((field_index, niche, niche.reserve(self, count)?))
914+
})
915+
{
915916
let mut align = dl.aggregate_align;
916917
let st = variants
917918
.iter_enumerated()

src/librustc_ast_passes/ast_validation.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,7 @@ impl<'a> AstValidator<'a> {
289289
match expr.kind {
290290
ExprKind::Lit(..) | ExprKind::Err => {}
291291
ExprKind::Path(..) if allow_paths => {}
292-
ExprKind::Unary(UnOp::Neg, ref inner)
293-
if match inner.kind {
294-
ExprKind::Lit(_) => true,
295-
_ => false,
296-
} => {}
292+
ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
297293
_ => self.err_handler().span_err(
298294
expr.span,
299295
"arbitrary expressions aren't allowed \

src/librustc_ast_passes/feature_gate.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
286286
start,
287287
i.span,
288288
"`#[start]` functions are experimental \
289-
and their signature may change \
290-
over time"
289+
and their signature may change \
290+
over time"
291291
);
292292
}
293293
if attr::contains_name(&i.attrs[..], sym::main) {
@@ -296,8 +296,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
296296
main,
297297
i.span,
298298
"declaration of a non-standard `#[main]` \
299-
function may change over time, for now \
300-
a top-level `fn main()` is required"
299+
function may change over time, for now \
300+
a top-level `fn main()` is required"
301301
);
302302
}
303303
}
@@ -341,7 +341,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
341341
if let ast::ImplPolarity::Negative(span) = polarity {
342342
gate_feature_post!(
343343
&self,
344-
optin_builtin_traits,
344+
negative_impls,
345345
span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)),
346346
"negative trait bounds are not yet fully implemented; \
347347
use marker types for now"

src/librustc_error_codes/error_codes.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ E0184: include_str!("./error_codes/E0184.md"),
9797
E0185: include_str!("./error_codes/E0185.md"),
9898
E0186: include_str!("./error_codes/E0186.md"),
9999
E0191: include_str!("./error_codes/E0191.md"),
100-
E0192: include_str!("./error_codes/E0192.md"),
101100
E0193: include_str!("./error_codes/E0193.md"),
102101
E0195: include_str!("./error_codes/E0195.md"),
103102
E0197: include_str!("./error_codes/E0197.md"),
@@ -426,6 +425,9 @@ E0745: include_str!("./error_codes/E0745.md"),
426425
E0746: include_str!("./error_codes/E0746.md"),
427426
E0747: include_str!("./error_codes/E0747.md"),
428427
E0748: include_str!("./error_codes/E0748.md"),
428+
E0749: include_str!("./error_codes/E0749.md"),
429+
E0750: include_str!("./error_codes/E0750.md"),
430+
E0751: include_str!("./error_codes/E0751.md"),
429431
;
430432
// E0006, // merged with E0005
431433
// E0008, // cannot bind by-move into a pattern guard
@@ -460,6 +462,7 @@ E0748: include_str!("./error_codes/E0748.md"),
460462
// E0188, // can not cast an immutable reference to a mutable pointer
461463
// E0189, // deprecated: can only cast a boxed pointer to a boxed object
462464
// E0190, // deprecated: can only cast a &-pointer to an &-object
465+
// E0192, // negative impl only applicable to auto traits
463466
// E0194, // merged into E0403
464467
// E0196, // cannot determine a type for this closure
465468
E0208,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Negative impls are not allowed to have any items. Negative impls
2+
declare that a trait is **not** implemented (and never will be) and
3+
hence there is no need to specify the values for trait methods or
4+
other items.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Negative impls cannot be default impls. A default impl supplies
2+
default values for the items within to be used by other impls, whereas
3+
a negative impl declares that there are no other impls. These don't
4+
make sense to combine.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
There are both a positive and negative trait implementation for the same type.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0748
6+
trait MyTrait {}
7+
impl MyTrait for i32 { }
8+
impl !MyTrait for i32 { }
9+
```
10+
11+
Negative implementations are a promise that the trait will never be
12+
implemented for the given types.

src/librustc_errors/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -802,13 +802,13 @@ impl HandlerInner {
802802
));
803803
self.failure(&format!(
804804
"For more information about an error, try \
805-
`rustc --explain {}`.",
805+
`rustc --explain {}`.",
806806
&error_codes[0]
807807
));
808808
} else {
809809
self.failure(&format!(
810810
"For more information about this error, try \
811-
`rustc --explain {}`.",
811+
`rustc --explain {}`.",
812812
&error_codes[0]
813813
));
814814
}

src/librustc_feature/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,9 @@ declare_features! (
554554
// Allows limiting the evaluation steps of const expressions
555555
(active, const_eval_limit, "1.43.0", Some(67217), None),
556556

557+
/// Allow negative trait implementations.
558+
(active, negative_impls, "1.44.0", Some(68318), None),
559+
557560
// -------------------------------------------------------------------------
558561
// feature-group-end: actual feature gates
559562
// -------------------------------------------------------------------------

0 commit comments

Comments
 (0)