@@ -162,7 +162,7 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
162
162
// This is a list of all exported items in the AST. An exported item is any
163
163
// function/method/item which is usable by external crates. This essentially
164
164
// means that the result is "public all the way down", but the "path down"
165
- // may jump across private boundaries through reexport statements.
165
+ // may jump across private boundaries through reexport statements or type aliases .
166
166
exported_items : ExportedItems ,
167
167
168
168
// This sets contains all the destination nodes which are publicly
@@ -172,9 +172,12 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
172
172
// destination must also be exported.
173
173
reexports : NodeSet ,
174
174
175
+ // Items that are directly public without help of reexports or type aliases.
175
176
// These two fields are closely related to one another in that they are only
176
- // used for generation of the 'PublicItems' set, not for privacy checking at
177
- // all
177
+ // used for generation of the `public_items` set, not for privacy checking at
178
+ // all. Public items are mostly a subset of exported items with exception of
179
+ // fields and exported macros - they are public, but not exported.
180
+ // FIXME: Make fields and exported macros exported as well (requires fixing resulting ICEs)
178
181
public_items : PublicItems ,
179
182
prev_public : bool ,
180
183
}
@@ -194,58 +197,103 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
194
197
fn exported_trait ( & self , _id : ast:: NodeId ) -> bool {
195
198
true
196
199
}
200
+
201
+ fn is_public_exported_ty ( & self , ty : & hir:: Ty ) -> ( bool , bool ) {
202
+ if let hir:: TyPath ( ..) = ty. node {
203
+ match self . tcx . def_map . borrow ( ) . get ( & ty. id ) . unwrap ( ) . full_def ( ) {
204
+ def:: DefPrimTy ( ..) | def:: DefSelfTy ( ..) => ( true , true ) ,
205
+ def => {
206
+ if let Some ( node_id) = self . tcx . map . as_local_node_id ( def. def_id ( ) ) {
207
+ ( self . public_items . contains ( & node_id) ,
208
+ self . exported_items . contains ( & node_id) )
209
+ } else {
210
+ ( true , true )
211
+ }
212
+ }
213
+ }
214
+ } else {
215
+ ( true , true )
216
+ }
217
+ }
218
+
219
+ fn is_public_exported_trait ( & self , trait_ref : & hir:: TraitRef ) -> ( bool , bool ) {
220
+ let did = self . tcx . trait_ref_to_def_id ( trait_ref) ;
221
+ if let Some ( node_id) = self . tcx . map . as_local_node_id ( did) {
222
+ ( self . public_items . contains ( & node_id) , self . exported_items . contains ( & node_id) )
223
+ } else {
224
+ ( true , true )
225
+ }
226
+ }
227
+
228
+ fn maybe_insert_id ( & mut self , id : ast:: NodeId ) {
229
+ if self . prev_public { self . public_items . insert ( id) ; }
230
+ if self . prev_exported { self . exported_items . insert ( id) ; }
231
+ }
197
232
}
198
233
199
234
impl < ' a , ' tcx , ' v > Visitor < ' v > for EmbargoVisitor < ' a , ' tcx > {
200
235
fn visit_item ( & mut self , item : & hir:: Item ) {
201
- let orig_all_pub = self . prev_public ;
202
- self . prev_public = orig_all_pub && item. vis == hir:: Public ;
203
- if self . prev_public {
204
- self . public_items . insert ( item. id ) ;
205
- }
206
-
236
+ let orig_all_public = self . prev_public ;
207
237
let orig_all_exported = self . prev_exported ;
208
238
match item. node {
209
239
// impls/extern blocks do not break the "public chain" because they
210
- // cannot have visibility qualifiers on them anyway
240
+ // cannot have visibility qualifiers on them anyway. They are also not
241
+ // added to public/exported sets based on inherited publicity.
211
242
hir:: ItemImpl ( ..) | hir:: ItemDefaultImpl ( ..) | hir:: ItemForeignMod ( ..) => { }
212
243
213
244
// Traits are a little special in that even if they themselves are
214
245
// not public they may still be exported.
215
246
hir:: ItemTrait ( ..) => {
247
+ self . prev_public = self . prev_public && item. vis == hir:: Public ;
216
248
self . prev_exported = self . exported_trait ( item. id ) ;
249
+
250
+ self . maybe_insert_id ( item. id ) ;
217
251
}
218
252
219
253
// Private by default, hence we only retain the "public chain" if
220
254
// `pub` is explicitly listed.
221
255
_ => {
222
- self . prev_exported =
223
- ( orig_all_exported && item. vis == hir:: Public ) ||
224
- self . reexports . contains ( & item. id ) ;
256
+ self . prev_public = self . prev_public && item. vis == hir:: Public ;
257
+ self . prev_exported = self . prev_exported && item. vis == hir:: Public ||
258
+ self . reexports . contains ( & item. id ) ;
259
+
260
+ self . maybe_insert_id ( item. id ) ;
225
261
}
226
262
}
227
263
228
- let public_first = self . prev_exported &&
229
- self . exported_items . insert ( item. id ) ;
230
-
231
264
match item. node {
232
265
// Enum variants inherit from their parent, so if the enum is
233
- // public all variants are public unless they're explicitly priv
234
- hir:: ItemEnum ( ref def, _) if public_first => {
266
+ // public all variants are public
267
+ hir:: ItemEnum ( ref def, _) => {
235
268
for variant in & def. variants {
236
- self . exported_items . insert ( variant. node . data . id ( ) ) ;
237
- self . public_items . insert ( variant. node . data . id ( ) ) ;
269
+ self . maybe_insert_id ( variant. node . data . id ( ) ) ;
270
+ for field in variant. node . data . fields ( ) {
271
+ // Variant fields are always public
272
+ if self . prev_public { self . public_items . insert ( field. node . id ) ; }
273
+ // FIXME: Make fields exported (requires fixing resulting ICEs)
274
+ // if self.prev_exported { self.exported_items.insert(field.node.id); }
275
+ }
276
+ }
277
+ }
278
+
279
+ // * Inherent impls for public types only have public methods exported
280
+ // * Inherent impls for private types do not need to export their methods
281
+ // * Inherent impls themselves are not exported, they are nothing more than
282
+ // containers for other items
283
+ hir:: ItemImpl ( _, _, _, None , ref ty, ref impl_items) => {
284
+ let ( public_ty, exported_ty) = self . is_public_exported_ty ( & ty) ;
285
+
286
+ for impl_item in impl_items {
287
+ if impl_item. vis == hir:: Public {
288
+ if public_ty { self . public_items . insert ( impl_item. id ) ; }
289
+ if exported_ty { self . exported_items . insert ( impl_item. id ) ; }
290
+ }
238
291
}
239
292
}
240
293
241
294
// Implementations are a little tricky to determine what's exported
242
295
// out of them. Here's a few cases which are currently defined:
243
296
//
244
- // * Impls for private types do not need to export their methods
245
- // (either public or private methods)
246
- //
247
- // * Impls for public types only have public methods exported
248
- //
249
297
// * Public trait impls for public types must have all methods
250
298
// exported.
251
299
//
@@ -257,83 +305,51 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
257
305
// undefined symbols at linkage time if this case is not handled.
258
306
//
259
307
// * Private trait impls for private types can be completely ignored
260
- hir:: ItemImpl ( _, _, _, _, ref ty, ref impl_items) => {
261
- let public_ty = match ty. node {
262
- hir:: TyPath ( ..) => {
263
- match self . tcx . def_map . borrow ( ) . get ( & ty. id ) . unwrap ( ) . full_def ( ) {
264
- def:: DefPrimTy ( ..) => true ,
265
- def:: DefSelfTy ( ..) => true ,
266
- def => {
267
- let did = def. def_id ( ) ;
268
- if let Some ( node_id) = self . tcx . map . as_local_node_id ( did) {
269
- self . exported_items . contains ( & node_id)
270
- } else {
271
- true
272
- }
273
- }
274
- }
275
- }
276
- _ => true ,
277
- } ;
278
- let tr = self . tcx . impl_trait_ref ( self . tcx . map . local_def_id ( item. id ) ) ;
279
- let public_trait = tr. clone ( ) . map_or ( false , |tr| {
280
- if let Some ( node_id) = self . tcx . map . as_local_node_id ( tr. def_id ) {
281
- self . exported_items . contains ( & node_id)
282
- } else {
283
- true
284
- }
285
- } ) ;
308
+ hir:: ItemImpl ( _, _, _, Some ( ref trait_ref) , ref ty, ref impl_items) => {
309
+ let ( public_ty, _exported_ty) = self . is_public_exported_ty ( & ty) ;
310
+ let ( public_trait, exported_trait) = self . is_public_exported_trait ( trait_ref) ;
286
311
287
- if public_ty || public_trait {
288
- for impl_item in impl_items {
289
- match impl_item. node {
290
- hir:: ConstImplItem ( ..) => {
291
- if ( public_ty && impl_item. vis == hir:: Public )
292
- || tr. is_some ( ) {
293
- self . exported_items . insert ( impl_item. id ) ;
294
- }
295
- }
296
- hir:: MethodImplItem ( ref sig, _) => {
297
- let meth_public = match sig. explicit_self . node {
298
- hir:: SelfStatic => public_ty,
299
- _ => true ,
300
- } && impl_item. vis == hir:: Public ;
301
- if meth_public || tr. is_some ( ) {
302
- self . exported_items . insert ( impl_item. id ) ;
303
- }
304
- }
305
- hir:: TypeImplItem ( _) => { }
306
- }
307
- }
312
+ if public_ty && public_trait { self . public_items . insert ( item. id ) ; }
313
+ if exported_trait { self . exported_items . insert ( item. id ) ; }
314
+
315
+ for impl_item in impl_items {
316
+ if public_ty && public_trait { self . public_items . insert ( impl_item. id ) ; }
317
+ if exported_trait { self . exported_items . insert ( impl_item. id ) ; }
308
318
}
309
319
}
310
320
321
+ // Default trait impls are exported for public traits
322
+ hir:: ItemDefaultImpl ( _, ref trait_ref) => {
323
+ let ( public_trait, exported_trait) = self . is_public_exported_trait ( trait_ref) ;
324
+
325
+ if public_trait { self . public_items . insert ( item. id ) ; }
326
+ if exported_trait { self . exported_items . insert ( item. id ) ; }
327
+ }
328
+
311
329
// Default methods on traits are all public so long as the trait
312
330
// is public
313
- hir:: ItemTrait ( _, _, _, ref trait_items) if public_first => {
331
+ hir:: ItemTrait ( _, _, _, ref trait_items) => {
314
332
for trait_item in trait_items {
315
- debug ! ( "trait item {}" , trait_item. id) ;
316
- self . exported_items . insert ( trait_item. id ) ;
333
+ self . maybe_insert_id ( trait_item. id ) ;
317
334
}
318
335
}
319
336
320
337
// Struct constructors are public if the struct is all public.
321
- hir:: ItemStruct ( ref def, _) if public_first => {
338
+ hir:: ItemStruct ( ref def, _) => {
322
339
if !def. is_struct ( ) {
323
- self . exported_items . insert ( def. id ( ) ) ;
340
+ self . maybe_insert_id ( def. id ( ) ) ;
324
341
}
325
- // fields can be public or private, so lets check
326
342
for field in def. fields ( ) {
327
- let vis = match field . node . kind {
328
- hir :: NamedField ( _ , vis ) | hir:: UnnamedField ( vis ) => vis
329
- } ;
330
- if vis == hir :: Public {
331
- self . public_items . insert ( field. node . id ) ;
343
+ // Struct fields can be public or private, so lets check
344
+ if field . node . kind . visibility ( ) == hir:: Public {
345
+ if self . prev_public { self . public_items . insert ( field . node . id ) ; }
346
+ // FIXME: Make fields exported (requires fixing resulting ICEs)
347
+ // if self.prev_exported { self.exported_items. insert(field.node.id); }
332
348
}
333
349
}
334
350
}
335
351
336
- hir:: ItemTy ( ref ty, _) if public_first => {
352
+ hir:: ItemTy ( ref ty, _) if self . prev_exported => {
337
353
if let hir:: TyPath ( ..) = ty. node {
338
354
match self . tcx . def_map . borrow ( ) . get ( & ty. id ) . unwrap ( ) . full_def ( ) {
339
355
def:: DefPrimTy ( ..) | def:: DefSelfTy ( ..) | def:: DefTyParam ( ..) => { } ,
@@ -347,19 +363,37 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
347
363
}
348
364
}
349
365
366
+ hir:: ItemForeignMod ( ref foreign_mod) => {
367
+ for foreign_item in & foreign_mod. items {
368
+ let public = self . prev_public && foreign_item. vis == hir:: Public ;
369
+ let exported = self . prev_exported && foreign_item. vis == hir:: Public ||
370
+ self . reexports . contains ( & foreign_item. id ) ;
371
+
372
+ if public { self . public_items . insert ( foreign_item. id ) ; }
373
+ if exported { self . exported_items . insert ( foreign_item. id ) ; }
374
+ }
375
+ }
376
+
350
377
_ => { }
351
378
}
352
379
353
380
visit:: walk_item ( self , item) ;
354
381
382
+ self . prev_public = orig_all_public;
355
383
self . prev_exported = orig_all_exported;
356
- self . prev_public = orig_all_pub;
357
384
}
358
385
359
- fn visit_foreign_item ( & mut self , a : & hir:: ForeignItem ) {
360
- if ( self . prev_exported && a. vis == hir:: Public ) || self . reexports . contains ( & a. id ) {
361
- self . exported_items . insert ( a. id ) ;
362
- }
386
+ fn visit_block ( & mut self , b : & ' v hir:: Block ) {
387
+ let orig_all_public = replace ( & mut self . prev_public , false ) ;
388
+ let orig_all_exported = replace ( & mut self . prev_exported , false ) ;
389
+
390
+ // Blocks can have exported and public items, for example impls, but they always
391
+ // start as non-public and non-exported regardless of publicity of a function,
392
+ // constant, type, field, etc. in which this block resides
393
+ visit:: walk_block ( self , b) ;
394
+
395
+ self . prev_public = orig_all_public;
396
+ self . prev_exported = orig_all_exported;
363
397
}
364
398
365
399
fn visit_mod ( & mut self , m : & hir:: Mod , _sp : Span , id : ast:: NodeId ) {
@@ -375,6 +409,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
375
409
}
376
410
visit:: walk_mod ( self , m)
377
411
}
412
+
413
+ fn visit_macro_def ( & mut self , md : & ' v hir:: MacroDef ) {
414
+ self . public_items . insert ( md. id ) ;
415
+ // FIXME: Make exported macros exported (requires fixing resulting ICEs)
416
+ // self.exported_items.insert(md.id);
417
+ }
378
418
}
379
419
380
420
////////////////////////////////////////////////////////////////////////////////
@@ -1447,11 +1487,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
1447
1487
}
1448
1488
}
1449
1489
1450
-
1451
1490
// we don't need to introspect into these at all: an
1452
1491
// expression/block context can't possibly contain exported things.
1453
1492
// (Making them no-ops stops us from traversing the whole AST without
1454
1493
// having to be super careful about our `walk_...` calls above.)
1494
+ // FIXME: Unfortunately this ^^^ is not true, blocks can contain
1495
+ // exported items (e.g. impls) and actual code in rustc itself breaks
1496
+ // if we don't traverse blocks in `EmbargoVisitor`
1455
1497
fn visit_block ( & mut self , _: & hir:: Block ) { }
1456
1498
fn visit_expr ( & mut self , _: & hir:: Expr ) { }
1457
1499
}
@@ -1501,9 +1543,12 @@ pub fn check_crate(tcx: &ty::ctxt,
1501
1543
prev_public : true ,
1502
1544
} ;
1503
1545
loop {
1504
- let before = visitor. exported_items . len ( ) ;
1546
+ let before = ( visitor. exported_items . len ( ) , visitor. public_items . len ( ) ,
1547
+ visitor. reexports . len ( ) ) ;
1505
1548
visit:: walk_crate ( & mut visitor, krate) ;
1506
- if before == visitor. exported_items . len ( ) {
1549
+ let after = ( visitor. exported_items . len ( ) , visitor. public_items . len ( ) ,
1550
+ visitor. reexports . len ( ) ) ;
1551
+ if after == before {
1507
1552
break
1508
1553
}
1509
1554
}
0 commit comments