Skip to content

Commit 3f92e8d

Browse files
committed
Auto merge of #46455 - petrochenkov:pimpl, r=nikomatsakis
syntax: Rewrite parsing of impls Properly parse impls for the never type `!` Recover from missing `for` in `impl Trait for Type` Prohibit inherent default impls and default impls of auto traits (#37653 (comment), #37653 (comment)) Change wording in more diagnostics to use "auto traits" Fix some spans in diagnostics Some other minor code cleanups in the parser Disambiguate generics and qualified paths in impls (parse `impl <Type as Trait>::AssocTy { ... }`) Replace the future-compatibility hack from #38268 with actually parsing generic parameters Add a test for #46438
2 parents adc9d86 + 60c48dd commit 3f92e8d

26 files changed

+382
-290
lines changed

src/librustc/hir/lowering.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1502,8 +1502,8 @@ impl<'a> LoweringContext<'a> {
15021502
fn_def_id: Option<DefId>,
15031503
impl_trait_return_allow: bool)
15041504
-> P<hir::FnDecl> {
1505-
// NOTE: The two last paramters here have to do with impl Trait. If fn_def_id is Some,
1506-
// then impl Trait arguments are lowered into generic paramters on the given
1505+
// NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
1506+
// then impl Trait arguments are lowered into generic parameters on the given
15071507
// fn_def_id, otherwise impl Trait is disallowed. (for now)
15081508
//
15091509
// Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in

src/librustc_passes/ast_validation.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -215,24 +215,36 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
215215

216216
fn visit_item(&mut self, item: &'a Item) {
217217
match item.node {
218-
ItemKind::Impl(.., Some(..), ref ty, ref impl_items) => {
218+
ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => {
219219
self.invalid_visibility(&item.vis, item.span, None);
220220
if ty.node == TyKind::Err {
221221
self.err_handler()
222222
.struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax")
223223
.help("use `auto trait Trait {}` instead").emit();
224224
}
225+
if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
226+
span_err!(self.session, item.span, E0198, "negative impls cannot be unsafe");
227+
}
225228
for impl_item in impl_items {
226229
self.invalid_visibility(&impl_item.vis, impl_item.span, None);
227230
if let ImplItemKind::Method(ref sig, _) = impl_item.node {
228231
self.check_trait_fn_not_const(sig.constness);
229232
}
230233
}
231234
}
232-
ItemKind::Impl(.., None, _, _) => {
235+
ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => {
233236
self.invalid_visibility(&item.vis,
234237
item.span,
235238
Some("place qualifiers on individual impl items instead"));
239+
if unsafety == Unsafety::Unsafe {
240+
span_err!(self.session, item.span, E0197, "inherent impls cannot be unsafe");
241+
}
242+
if polarity == ImplPolarity::Negative {
243+
self.err_handler().span_err(item.span, "inherent impls cannot be negative");
244+
}
245+
if defaultness == Defaultness::Default {
246+
self.err_handler().span_err(item.span, "inherent impls cannot be default");
247+
}
236248
}
237249
ItemKind::ForeignMod(..) => {
238250
self.invalid_visibility(&item.vis,

src/librustc_passes/diagnostics.rs

+46
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,52 @@ extern {
8282
```
8383
"##,
8484

85+
E0197: r##"
86+
Inherent implementations (one that do not implement a trait but provide
87+
methods associated with a type) are always safe because they are not
88+
implementing an unsafe trait. Removing the `unsafe` keyword from the inherent
89+
implementation will resolve this error.
90+
91+
```compile_fail,E0197
92+
struct Foo;
93+
94+
// this will cause this error
95+
unsafe impl Foo { }
96+
// converting it to this will fix it
97+
impl Foo { }
98+
```
99+
"##,
100+
101+
E0198: r##"
102+
A negative implementation is one that excludes a type from implementing a
103+
particular trait. Not being able to use a trait is always a safe operation,
104+
so negative implementations are always safe and never need to be marked as
105+
unsafe.
106+
107+
```compile_fail
108+
#![feature(optin_builtin_traits)]
109+
110+
struct Foo;
111+
112+
// unsafe is unnecessary
113+
unsafe impl !Clone for Foo { }
114+
```
115+
116+
This will compile:
117+
118+
```ignore (ignore auto_trait future compatibility warning)
119+
#![feature(optin_builtin_traits)]
120+
121+
struct Foo;
122+
123+
auto trait Enterprise {}
124+
125+
impl !Enterprise for Foo { }
126+
```
127+
128+
Please note that negative impls are only allowed for auto traits.
129+
"##,
130+
85131
E0265: r##"
86132
This error indicates that a static or constant references itself.
87133
All statics and constants need to resolve to a value in an acyclic manner.

src/librustc_typeck/check/wfcheck.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,21 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
107107
//
108108
// won't be allowed unless there's an *explicit* implementation of `Send`
109109
// for `T`
110-
hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _,
111-
ref trait_ref, ref self_ty, _) => {
112-
self.check_impl(item, self_ty, trait_ref);
113-
}
114-
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => {
115-
// FIXME(#27579) what amount of WF checking do we need for neg impls?
116-
117-
let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();
118-
if !tcx.trait_is_auto(trait_ref.def_id) {
119-
error_192(tcx, item.span);
110+
hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
111+
let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id))
112+
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
113+
if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
114+
tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
115+
}
116+
if polarity == hir::ImplPolarity::Positive {
117+
self.check_impl(item, self_ty, trait_ref);
118+
} else {
119+
// FIXME(#27579) what amount of WF checking do we need for neg impls?
120+
if trait_ref.is_some() && !is_auto {
121+
span_err!(tcx.sess, item.span, E0192,
122+
"negative impls are only allowed for \
123+
auto traits (e.g., `Send` and `Sync`)")
124+
}
120125
}
121126
}
122127
hir::ItemFn(..) => {
@@ -661,12 +666,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
661666
}
662667
}
663668

664-
fn error_192(tcx: TyCtxt, span: Span) {
665-
span_err!(tcx.sess, span, E0192,
666-
"negative impls are only allowed for traits with \
667-
default impls (e.g., `Send` and `Sync`)")
668-
}
669-
670669
fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name)
671670
-> DiagnosticBuilder<'tcx> {
672671
let mut err = struct_span_err!(tcx.sess, span, E0392,

src/librustc_typeck/coherence/inherent_impls.rs

+2-14
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,11 @@ struct InherentCollect<'a, 'tcx: 'a> {
9393

9494
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
9595
fn visit_item(&mut self, item: &hir::Item) {
96-
let (unsafety, ty) = match item.node {
97-
hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
96+
let ty = match item.node {
97+
hir::ItemImpl(.., None, ref ty, _) => ty,
9898
_ => return
9999
};
100100

101-
match unsafety {
102-
hir::Unsafety::Normal => {
103-
// OK
104-
}
105-
hir::Unsafety::Unsafe => {
106-
span_err!(self.tcx.sess,
107-
item.span,
108-
E0197,
109-
"inherent impls cannot be declared as unsafe");
110-
}
111-
}
112-
113101
let def_id = self.tcx.hir.local_def_id(item.id);
114102
let self_ty = self.tcx.type_of(def_id);
115103
let lang_items = self.tcx.lang_items();

src/librustc_typeck/coherence/orphan.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,15 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
6767
}
6868
}
6969

70-
// In addition to the above rules, we restrict impls of defaulted traits
70+
// In addition to the above rules, we restrict impls of auto traits
7171
// so that they can only be implemented on nominal types, such as structs,
7272
// enums or foreign types. To see why this restriction exists, consider the
73-
// following example (#22978). Imagine that crate A defines a defaulted trait
73+
// following example (#22978). Imagine that crate A defines an auto trait
7474
// `Foo` and a fn that operates on pairs of types:
7575
//
7676
// ```
7777
// // Crate A
78-
// trait Foo { }
79-
// impl Foo for .. { }
78+
// auto trait Foo { }
8079
// fn two_foos<A:Foo,B:Foo>(..) {
8180
// one_foo::<(A,B)>(..)
8281
// }

src/librustc_typeck/coherence/unsafety.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
3737
let trait_def = self.tcx.trait_def(trait_ref.def_id);
3838
let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr());
3939
match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
40-
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
41-
span_err!(self.tcx.sess,
42-
item.span,
43-
E0198,
44-
"negative implementations are not unsafe");
45-
}
46-
47-
(Unsafety::Normal, None, Unsafety::Unsafe, _) => {
40+
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
4841
span_err!(self.tcx.sess,
4942
item.span,
5043
E0199,
@@ -69,6 +62,10 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
6962
g.attr_name());
7063
}
7164

65+
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
66+
// Reported in AST validation
67+
self.tcx.sess.delay_span_bug(item.span, "unsafe negative impl");
68+
}
7269
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative) |
7370
(Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) |
7471
(Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) |

src/librustc_typeck/diagnostics.rs

+1-47
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,7 @@ type Foo = Trait<Bar=i32>; // ok!
17151715
"##,
17161716

17171717
E0192: r##"
1718-
Negative impls are only allowed for traits with default impls. For more
1718+
Negative impls are only allowed for auto traits. For more
17191719
information see the [opt-in builtin traits RFC][RFC 19].
17201720
17211721
[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md
@@ -1821,52 +1821,6 @@ impl Trait for Foo {
18211821
```
18221822
"##,
18231823

1824-
E0197: r##"
1825-
Inherent implementations (one that do not implement a trait but provide
1826-
methods associated with a type) are always safe because they are not
1827-
implementing an unsafe trait. Removing the `unsafe` keyword from the inherent
1828-
implementation will resolve this error.
1829-
1830-
```compile_fail,E0197
1831-
struct Foo;
1832-
1833-
// this will cause this error
1834-
unsafe impl Foo { }
1835-
// converting it to this will fix it
1836-
impl Foo { }
1837-
```
1838-
"##,
1839-
1840-
E0198: r##"
1841-
A negative implementation is one that excludes a type from implementing a
1842-
particular trait. Not being able to use a trait is always a safe operation,
1843-
so negative implementations are always safe and never need to be marked as
1844-
unsafe.
1845-
1846-
```compile_fail
1847-
#![feature(optin_builtin_traits)]
1848-
1849-
struct Foo;
1850-
1851-
// unsafe is unnecessary
1852-
unsafe impl !Clone for Foo { }
1853-
```
1854-
1855-
This will compile:
1856-
1857-
```
1858-
#![feature(optin_builtin_traits)]
1859-
1860-
struct Foo;
1861-
1862-
auto trait Enterprise {}
1863-
1864-
impl !Enterprise for Foo { }
1865-
```
1866-
1867-
Please note that negative impls are only allowed for traits with default impls.
1868-
"##,
1869-
18701824
E0199: r##"
18711825
Safe traits should not have unsafe implementations, therefore marking an
18721826
implementation for a safe trait unsafe will cause a compiler error. Removing

0 commit comments

Comments
 (0)