Skip to content

Commit d19e4c4

Browse files
committed
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 Change wording in more diagnostics to use "auto traits" Some minor code cleanups in the parser
1 parent 48ab4cd commit d19e4c4

23 files changed

+330
-274
lines changed

src/librustc/hir/lowering.rs

Lines changed: 2 additions & 2 deletions
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

Lines changed: 14 additions & 2 deletions
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

Lines changed: 46 additions & 0 deletions
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

Lines changed: 15 additions & 16 deletions
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

Lines changed: 2 additions & 14 deletions
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

Lines changed: 3 additions & 4 deletions
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

Lines changed: 5 additions & 8 deletions
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

Lines changed: 1 addition & 47 deletions
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)