@@ -8,7 +8,7 @@ use rustc_hir as hir;
88use rustc_middle:: ty:: subst:: InternalSubsts ;
99use rustc_middle:: ty:: util:: IgnoreRegions ;
1010use rustc_middle:: ty:: {
11- self , ImplPolarity , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
11+ self , AliasKind , ImplPolarity , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
1212} ;
1313use rustc_session:: lint;
1414use rustc_span:: def_id:: { DefId , LocalDefId } ;
@@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>(
8686 // struct B { }
8787 // impl Foo for A { }
8888 // impl Foo for B { }
89- // impl !Send for (A, B) { }
89+ // impl !Foo for (A, B) { }
9090 // ```
9191 //
9292 // This final impl is legal according to the orphan
@@ -99,50 +99,171 @@ fn do_orphan_check_impl<'tcx>(
9999 tcx. trait_is_auto( trait_def_id)
100100 ) ;
101101
102- if tcx. trait_is_auto ( trait_def_id) && !trait_def_id . is_local ( ) {
102+ if tcx. trait_is_auto ( trait_def_id) {
103103 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- } ;
109104
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
118156 } 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) ;
128238 }
129239 }
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 \
133255 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+ }
146267 }
147268 }
148269
0 commit comments