@@ -8,7 +8,7 @@ use rustc_hir as hir;
8
8
use rustc_middle:: ty:: subst:: InternalSubsts ;
9
9
use rustc_middle:: ty:: util:: IgnoreRegions ;
10
10
use rustc_middle:: ty:: {
11
- self , ImplPolarity , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
11
+ self , AliasKind , ImplPolarity , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
12
12
} ;
13
13
use rustc_session:: lint;
14
14
use rustc_span:: def_id:: { DefId , LocalDefId } ;
@@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>(
86
86
// struct B { }
87
87
// impl Foo for A { }
88
88
// impl Foo for B { }
89
- // impl !Send for (A, B) { }
89
+ // impl !Foo for (A, B) { }
90
90
// ```
91
91
//
92
92
// This final impl is legal according to the orphan
@@ -99,50 +99,171 @@ fn do_orphan_check_impl<'tcx>(
99
99
tcx. trait_is_auto( trait_def_id)
100
100
) ;
101
101
102
- if tcx. trait_is_auto ( trait_def_id) && !trait_def_id . is_local ( ) {
102
+ if tcx. trait_is_auto ( trait_def_id) {
103
103
let self_ty = trait_ref. self_ty ( ) ;
104
- let opt_self_def_id = match * self_ty. kind ( ) {
105
- ty:: Adt ( self_def, _) => Some ( self_def. did ( ) ) ,
106
- ty:: Foreign ( did) => Some ( did) ,
107
- _ => None ,
108
- } ;
109
104
110
- let msg = match opt_self_def_id {
111
- // We only want to permit nominal types, but not *all* nominal types.
112
- // They must be local to the current crate, so that people
113
- // can't do `unsafe impl Send for Rc<SomethingLocal>` or
114
- // `impl !Send for Box<SomethingLocalAndSend>`.
115
- Some ( self_def_id) => {
116
- if self_def_id. is_local ( ) {
117
- None
105
+ // If the impl is in the same crate as the auto-trait, almost anything
106
+ // goes.
107
+ //
108
+ // impl MyAuto for Rc<Something> {} // okay
109
+ // impl<T> !MyAuto for *const T {} // okay
110
+ // impl<T> MyAuto for T {} // okay
111
+ //
112
+ // But there is one important exception: implementing for a trait object
113
+ // is not allowed.
114
+ //
115
+ // impl MyAuto for dyn Trait {} // NOT OKAY
116
+ // impl<T: ?Sized> MyAuto for T {} // NOT OKAY
117
+ //
118
+ enum LocalImpl {
119
+ Allow ,
120
+ Disallow { problematic_kind : & ' static str } ,
121
+ }
122
+
123
+ // If the auto-trait is from a dependency, it must only be getting
124
+ // implemented for a nominal type, and specifically one local to the
125
+ // current crate.
126
+ //
127
+ // impl<T> Sync for MyStruct<T> {} // okay
128
+ //
129
+ // impl Sync for Rc<MyStruct> {} // NOT OKAY
130
+ enum NonlocalImpl {
131
+ Allow ,
132
+ DisallowBecauseNonlocal ,
133
+ DisallowOther ,
134
+ }
135
+
136
+ // Exhaustive match considering that this logic is essential for
137
+ // soundness.
138
+ let ( local_impl, nonlocal_impl) = match self_ty. kind ( ) {
139
+ // struct Struct<T>;
140
+ // impl AutoTrait for Struct<Foo> {}
141
+ ty:: Adt ( self_def, _) => (
142
+ LocalImpl :: Allow ,
143
+ if self_def. did ( ) . is_local ( ) {
144
+ NonlocalImpl :: Allow
145
+ } else {
146
+ NonlocalImpl :: DisallowBecauseNonlocal
147
+ } ,
148
+ ) ,
149
+
150
+ // extern { type OpaqueType; }
151
+ // impl AutoTrait for OpaqueType {}
152
+ ty:: Foreign ( did) => (
153
+ LocalImpl :: Allow ,
154
+ if did. is_local ( ) {
155
+ NonlocalImpl :: Allow
118
156
} else {
119
- Some ( (
120
- format ! (
121
- "cross-crate traits with a default impl, like `{}`, \
122
- can only be implemented for a struct/enum type \
123
- defined in the current crate",
124
- tcx. def_path_str( trait_def_id)
125
- ) ,
126
- "can't implement cross-crate trait for type in another crate" ,
127
- ) )
157
+ NonlocalImpl :: DisallowBecauseNonlocal
158
+ } ,
159
+ ) ,
160
+
161
+ // impl AutoTrait for dyn Trait {}
162
+ ty:: Dynamic ( ..) => (
163
+ LocalImpl :: Disallow { problematic_kind : "trait object" } ,
164
+ NonlocalImpl :: DisallowOther ,
165
+ ) ,
166
+
167
+ // impl<T> AutoTrait for T {}
168
+ // impl<T: ?Sized> AutoTrait for T {}
169
+ ty:: Param ( ..) => (
170
+ if self_ty. is_sized ( tcx, tcx. param_env ( def_id) ) {
171
+ LocalImpl :: Allow
172
+ } else {
173
+ LocalImpl :: Disallow { problematic_kind : "generic type" }
174
+ } ,
175
+ NonlocalImpl :: DisallowOther ,
176
+ ) ,
177
+
178
+ // trait Id { type This: ?Sized; }
179
+ // impl<T: ?Sized> Id for T {
180
+ // type This = T;
181
+ // }
182
+ // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
183
+ ty:: Alias ( AliasKind :: Projection , _) => (
184
+ LocalImpl :: Disallow { problematic_kind : "associated type" } ,
185
+ NonlocalImpl :: DisallowOther ,
186
+ ) ,
187
+
188
+ // type Opaque = impl Trait;
189
+ // impl AutoTrait for Opaque {}
190
+ ty:: Alias ( AliasKind :: Opaque , _) => (
191
+ LocalImpl :: Disallow { problematic_kind : "opaque type" } ,
192
+ NonlocalImpl :: DisallowOther ,
193
+ ) ,
194
+
195
+ ty:: Bool
196
+ | ty:: Char
197
+ | ty:: Int ( ..)
198
+ | ty:: Uint ( ..)
199
+ | ty:: Float ( ..)
200
+ | ty:: Str
201
+ | ty:: Array ( ..)
202
+ | ty:: Slice ( ..)
203
+ | ty:: RawPtr ( ..)
204
+ | ty:: Ref ( ..)
205
+ | ty:: FnDef ( ..)
206
+ | ty:: FnPtr ( ..)
207
+ | ty:: Never
208
+ | ty:: Tuple ( ..) => ( LocalImpl :: Allow , NonlocalImpl :: DisallowOther ) ,
209
+
210
+ ty:: Closure ( ..)
211
+ | ty:: Generator ( ..)
212
+ | ty:: GeneratorWitness ( ..)
213
+ | ty:: GeneratorWitnessMIR ( ..)
214
+ | ty:: Bound ( ..)
215
+ | ty:: Placeholder ( ..)
216
+ | ty:: Infer ( ..) => span_bug ! ( sp, "weird self type for autotrait impl" ) ,
217
+
218
+ ty:: Error ( ..) => ( LocalImpl :: Allow , NonlocalImpl :: Allow ) ,
219
+ } ;
220
+
221
+ if trait_def_id. is_local ( ) {
222
+ match local_impl {
223
+ LocalImpl :: Allow => { }
224
+ LocalImpl :: Disallow { problematic_kind } => {
225
+ let msg = format ! (
226
+ "traits with a default impl, like `{trait}`, \
227
+ cannot be implemented for {problematic_kind} `{self_ty}`",
228
+ trait = tcx. def_path_str( trait_def_id) ,
229
+ ) ;
230
+ let label = format ! (
231
+ "a trait object implements `{trait}` if and only if `{trait}` \
232
+ is one of the trait object's trait bounds",
233
+ trait = tcx. def_path_str( trait_def_id) ,
234
+ ) ;
235
+ let reported =
236
+ struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . note ( label) . emit ( ) ;
237
+ return Err ( reported) ;
128
238
}
129
239
}
130
- _ => Some ( (
131
- format ! (
132
- "cross-crate traits with a default impl, like `{}`, can \
240
+ } else {
241
+ if let Some ( ( msg, label) ) = match nonlocal_impl {
242
+ NonlocalImpl :: Allow => None ,
243
+ NonlocalImpl :: DisallowBecauseNonlocal => Some ( (
244
+ format ! (
245
+ "cross-crate traits with a default impl, like `{}`, \
246
+ can only be implemented for a struct/enum type \
247
+ defined in the current crate",
248
+ tcx. def_path_str( trait_def_id)
249
+ ) ,
250
+ "can't implement cross-crate trait for type in another crate" ,
251
+ ) ) ,
252
+ NonlocalImpl :: DisallowOther => Some ( (
253
+ format ! (
254
+ "cross-crate traits with a default impl, like `{}`, can \
133
255
only be implemented for a struct/enum type, not `{}`",
134
- tcx. def_path_str( trait_def_id) ,
135
- self_ty
136
- ) ,
137
- "can't implement cross-crate trait with a default impl for \
138
- non-struct/enum type",
139
- ) ) ,
140
- } ;
141
-
142
- if let Some ( ( msg, label) ) = msg {
143
- let reported =
144
- struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . span_label ( sp, label) . emit ( ) ;
145
- return Err ( reported) ;
256
+ tcx. def_path_str( trait_def_id) ,
257
+ self_ty
258
+ ) ,
259
+ "can't implement cross-crate trait with a default impl for \
260
+ non-struct/enum type",
261
+ ) ) ,
262
+ } {
263
+ let reported =
264
+ struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . span_label ( sp, label) . emit ( ) ;
265
+ return Err ( reported) ;
266
+ }
146
267
}
147
268
}
148
269
0 commit comments