@@ -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,93 @@ 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
- } ;
104
+ let self_ty_kind = self_ty. kind ( ) ;
109
105
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
118
- } 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
- ) )
106
+ 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
+ let problematic_kind = match self_ty_kind {
120
+ ty:: Dynamic ( ..) => Some ( "trait object" ) ,
121
+ ty:: Param ( ..) if !self_ty. is_sized ( tcx, tcx. param_env ( def_id) ) => {
122
+ Some ( "generic type" )
128
123
}
124
+ _ => None ,
125
+ } ;
126
+
127
+ if let Some ( problematic_kind) = problematic_kind {
128
+ let msg = format ! (
129
+ "traits with a default impl, like `{trait}`, \
130
+ cannot be implemented for {problematic_kind} `{self_ty}`",
131
+ trait = tcx. def_path_str( trait_def_id) ,
132
+ ) ;
133
+ let label = format ! (
134
+ "a trait object implements `{trait}` if and only if `{trait}` \
135
+ is one of the trait object's trait bounds",
136
+ trait = tcx. def_path_str( trait_def_id) ,
137
+ ) ;
138
+ let reported = struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . note ( label) . emit ( ) ;
139
+ return Err ( reported) ;
129
140
}
130
- _ => Some ( (
131
- format ! (
132
- "cross-crate traits with a default impl, like `{}`, can \
141
+ } else {
142
+ // If the auto-trait is not local, it must only be getting
143
+ // implemented for a nominal type, and specifically one local to the
144
+ // current crate.
145
+ //
146
+ // impl<T> Sync for MyStruct<T> {} // okay
147
+ //
148
+ // impl Sync for Rc<MyStruct> {} // NOT OKAY
149
+ //
150
+ let opt_self_def_id = match * self_ty_kind {
151
+ ty:: Adt ( self_def, _) => Some ( self_def. did ( ) ) ,
152
+ ty:: Foreign ( did) => Some ( did) ,
153
+ _ => None ,
154
+ } ;
155
+
156
+ let msg = match opt_self_def_id {
157
+ Some ( self_def_id) => {
158
+ if self_def_id. is_local ( ) {
159
+ None
160
+ } else {
161
+ Some ( (
162
+ format ! (
163
+ "cross-crate traits with a default impl, like `{}`, \
164
+ can only be implemented for a struct/enum type \
165
+ defined in the current crate",
166
+ tcx. def_path_str( trait_def_id)
167
+ ) ,
168
+ "can't implement cross-crate trait for type in another crate" ,
169
+ ) )
170
+ }
171
+ }
172
+ None => Some ( (
173
+ format ! (
174
+ "cross-crate traits with a default impl, like `{}`, can \
133
175
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
- } ;
176
+ tcx. def_path_str( trait_def_id) ,
177
+ self_ty
178
+ ) ,
179
+ "can't implement cross-crate trait with a default impl for \
180
+ non-struct/enum type",
181
+ ) ) ,
182
+ } ;
141
183
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) ;
184
+ if let Some ( ( msg, label) ) = msg {
185
+ let reported =
186
+ struct_span_err ! ( tcx. sess, sp, E0321 , "{}" , msg) . span_label ( sp, label) . emit ( ) ;
187
+ return Err ( reported) ;
188
+ }
146
189
}
147
190
}
148
191
0 commit comments