@@ -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 } ;
@@ -101,97 +101,169 @@ fn do_orphan_check_impl<'tcx>(
101101
102102 if tcx. trait_is_auto ( trait_def_id) {
103103 let self_ty = trait_ref. self_ty ( ) ;
104- let self_ty_kind = self_ty. kind ( ) ;
104+
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+ // With this restriction, it's guaranteed that an auto-trait is
119+ // implemented for a trait object if and only if the auto-trait is one
120+ // of the trait object's trait bounds (or a supertrait of a bound). In
121+ // other words `dyn Trait + AutoTrait` always implements AutoTrait,
122+ // while `dyn Trait` never implements AutoTrait.
123+ //
124+ // This is necessary in order for autotrait bounds on methods of trait
125+ // objects to be sound.
126+ //
127+ // auto trait AutoTrait {}
128+ //
129+ // trait ObjectSafeTrait {
130+ // fn f(&self) where Self: AutoTrait;
131+ // }
132+ //
133+ // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
134+ //
135+ // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
136+ // for the ObjectSafeTrait shown above to be object safe because someone
137+ // could take some type implementing ObjectSafeTrait but not AutoTrait,
138+ // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
139+ // concrete implementation (issue #50781).
140+ enum LocalImpl {
141+ Allow ,
142+ Disallow { problematic_kind : & ' static str } ,
143+ }
144+
145+ // If the auto-trait is from a dependency, it must only be getting
146+ // implemented for a nominal type, and specifically one local to the
147+ // current crate.
148+ //
149+ // impl<T> Sync for MyStruct<T> {} // okay
150+ //
151+ // impl Sync for Rc<MyStruct> {} // NOT OKAY
152+ enum NonlocalImpl {
153+ Allow ,
154+ DisallowBecauseNonlocal ,
155+ DisallowOther ,
156+ }
157+
158+ // Exhaustive match considering that this logic is essential for
159+ // soundness.
160+ let ( local_impl, nonlocal_impl) = match self_ty. kind ( ) {
161+ // struct Struct<T>;
162+ // impl AutoTrait for Struct<Foo> {}
163+ ty:: Adt ( self_def, _) => (
164+ LocalImpl :: Allow ,
165+ if self_def. did ( ) . is_local ( ) {
166+ NonlocalImpl :: Allow
167+ } else {
168+ NonlocalImpl :: DisallowBecauseNonlocal
169+ } ,
170+ ) ,
171+
172+ // extern { type OpaqueType; }
173+ // impl AutoTrait for OpaqueType {}
174+ ty:: Foreign ( did) => (
175+ LocalImpl :: Allow ,
176+ if did. is_local ( ) {
177+ NonlocalImpl :: Allow
178+ } else {
179+ NonlocalImpl :: DisallowBecauseNonlocal
180+ } ,
181+ ) ,
182+
183+ // impl AutoTrait for dyn Trait {}
184+ ty:: Dynamic ( ..) => (
185+ LocalImpl :: Disallow { problematic_kind : "trait object" } ,
186+ NonlocalImpl :: DisallowOther ,
187+ ) ,
188+
189+ // impl<T> AutoTrait for T {}
190+ // impl<T: ?Sized> AutoTrait for T {}
191+ ty:: Param ( ..) => (
192+ if self_ty. is_sized ( tcx, tcx. param_env ( def_id) ) {
193+ LocalImpl :: Allow
194+ } else {
195+ LocalImpl :: Disallow { problematic_kind : "generic type" }
196+ } ,
197+ NonlocalImpl :: DisallowOther ,
198+ ) ,
199+
200+ // trait Id { type This: ?Sized; }
201+ // impl<T: ?Sized> Id for T {
202+ // type This = T;
203+ // }
204+ // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
205+ ty:: Alias ( AliasKind :: Projection , _) => (
206+ LocalImpl :: Disallow { problematic_kind : "associated type" } ,
207+ NonlocalImpl :: DisallowOther ,
208+ ) ,
209+
210+ // Some of these should perhaps be a delay_span_bug.
211+ ty:: Bool
212+ | ty:: Char
213+ | ty:: Int ( ..)
214+ | ty:: Uint ( ..)
215+ | ty:: Float ( ..)
216+ | ty:: Str
217+ | ty:: Array ( ..)
218+ | ty:: Slice ( ..)
219+ | ty:: RawPtr ( ..)
220+ | ty:: Ref ( ..)
221+ | ty:: FnDef ( ..)
222+ | ty:: FnPtr ( ..)
223+ | ty:: Closure ( ..)
224+ | ty:: Generator ( ..)
225+ | ty:: GeneratorWitness ( ..)
226+ | ty:: Never
227+ | ty:: Tuple ( ..)
228+ | ty:: Alias ( AliasKind :: Opaque , ..)
229+ | ty:: Bound ( ..)
230+ | ty:: Placeholder ( ..)
231+ | ty:: Infer ( ..)
232+ | ty:: Error ( ..) => ( LocalImpl :: Allow , NonlocalImpl :: DisallowOther ) ,
233+ } ;
105234
106235 if trait_def_id. is_local ( ) {
107- // If the auto-trait is local, almost anything goes.
108- //
109- // impl MyAuto for Rc<Something> {} // okay
110- // impl<T> !MyAuto for *const T {} // okay
111- // impl<T> MyAuto for T {} // okay
112- //
113- // But there is one important exception: implementing for a trait
114- // object is not allowed.
115- //
116- // impl MyAuto for dyn Trait {} // NOT OKAY
117- // impl<T: ?Sized> MyAuto for T {} // NOT OKAY
118- //
119- // With this restriction, it's guaranteed that an auto-trait is
120- // implemented for a trait object if and only if the auto-trait is
121- // one of the trait object's trait bounds (or a supertrait of a
122- // bound). In other words `dyn Trait + AutoTrait` always implements
123- // AutoTrait, while `dyn Trait` never implements AutoTrait.
124- //
125- // This is necessary in order for autotrait bounds on methods of
126- // trait objects to be sound.
127- //
128- // auto trait AutoTrait {}
129- //
130- // trait ObjectSafeTrait {
131- // fn f(&self) where Self: AutoTrait;
132- // }
133- //
134- // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
135- //
136- // If we didn't deny `impl AutoTrait for dyn Trait`, it would be
137- // unsound for the ObjectSafeTrait shown above to be object safe
138- // because someone could take some type implementing ObjectSafeTrait
139- // but not AutoTrait, unsize it to `dyn ObjectSafeTrait`, and call
140- // .f() which has no concrete implementation (issue #50781).
141- let problematic_kind = match self_ty_kind {
142- ty:: Dynamic ( ..) => Some ( "trait object" ) ,
143- ty:: Param ( ..) if !self_ty. is_sized ( tcx, tcx. param_env ( def_id) ) => {
144- Some ( "generic type" )
236+ match local_impl {
237+ LocalImpl :: Allow => { }
238+ LocalImpl :: Disallow { problematic_kind } => {
239+ let msg = format ! (
240+ "traits with a default impl, like `{trait}`, \
241+ cannot be implemented for {problematic_kind} `{self_ty}`",
242+ trait = tcx. def_path_str( trait_def_id) ,
243+ ) ;
244+ let label = format ! (
245+ "a trait object implements `{trait}` if and only if `{trait}` \
246+ is one of the trait object's trait bounds",
247+ trait = tcx. def_path_str( trait_def_id) ,
248+ ) ;
249+ let reported =
250+ struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . note ( label) . emit ( ) ;
251+ return Err ( reported) ;
145252 }
146- _ => None ,
147- } ;
148-
149- if let Some ( problematic_kind) = problematic_kind {
150- let msg = format ! (
151- "traits with a default impl, like `{trait}`, \
152- cannot be implemented for {problematic_kind} `{self_ty}`",
153- trait = tcx. def_path_str( trait_def_id) ,
154- ) ;
155- let label = format ! (
156- "a trait object implements `{trait}` if and only if `{trait}` \
157- is one of the trait object's trait bounds",
158- trait = tcx. def_path_str( trait_def_id) ,
159- ) ;
160- let reported = struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . note ( label) . emit ( ) ;
161- return Err ( reported) ;
162253 }
163254 } else {
164- // If the auto-trait is not local, it must only be getting
165- // implemented for a nominal type, and specifically one local to the
166- // current crate.
167- //
168- // impl<T> Sync for MyStruct<T> {} // okay
169- //
170- // impl Sync for Rc<MyStruct> {} // NOT OKAY
171- //
172- let opt_self_def_id = match * self_ty_kind {
173- ty:: Adt ( self_def, _) => Some ( self_def. did ( ) ) ,
174- ty:: Foreign ( did) => Some ( did) ,
175- _ => None ,
176- } ;
177-
178- let msg = match opt_self_def_id {
179- Some ( self_def_id) => {
180- if self_def_id. is_local ( ) {
181- None
182- } else {
183- Some ( (
184- format ! (
185- "cross-crate traits with a default impl, like `{}`, \
186- can only be implemented for a struct/enum type \
187- defined in the current crate",
188- tcx. def_path_str( trait_def_id)
189- ) ,
190- "can't implement cross-crate trait for type in another crate" ,
191- ) )
192- }
193- }
194- None => Some ( (
255+ if let Some ( ( msg, label) ) = match nonlocal_impl {
256+ NonlocalImpl :: Allow => None ,
257+ NonlocalImpl :: DisallowBecauseNonlocal => Some ( (
258+ format ! (
259+ "cross-crate traits with a default impl, like `{}`, \
260+ can only be implemented for a struct/enum type \
261+ defined in the current crate",
262+ tcx. def_path_str( trait_def_id)
263+ ) ,
264+ "can't implement cross-crate trait for type in another crate" ,
265+ ) ) ,
266+ NonlocalImpl :: DisallowOther => Some ( (
195267 format ! (
196268 "cross-crate traits with a default impl, like `{}`, can \
197269 only be implemented for a struct/enum type, not `{}`",
@@ -201,9 +273,7 @@ fn do_orphan_check_impl<'tcx>(
201273 "can't implement cross-crate trait with a default impl for \
202274 non-struct/enum type",
203275 ) ) ,
204- } ;
205-
206- if let Some ( ( msg, label) ) = msg {
276+ } {
207277 let reported =
208278 struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . span_label ( sp, label) . emit ( ) ;
209279 return Err ( reported) ;
0 commit comments