@@ -21,7 +21,7 @@ use middle::typeck::{method_static, method_object};
21
21
22
22
use syntax:: ast;
23
23
use syntax:: ast_map;
24
- use syntax:: ast_util:: is_local;
24
+ use syntax:: ast_util:: { is_local, def_id_of_def } ;
25
25
use syntax:: attr;
26
26
use syntax:: codemap:: Span ;
27
27
use syntax:: parse:: token;
@@ -250,6 +250,12 @@ struct PrivacyVisitor<'self> {
250
250
last_private_map : resolve:: LastPrivateMap ,
251
251
}
252
252
253
+ enum PrivacyResult {
254
+ Allowable ,
255
+ ExternallyDenied ,
256
+ DisallowedBy ( ast:: NodeId ) ,
257
+ }
258
+
253
259
impl < ' self > PrivacyVisitor < ' self > {
254
260
// used when debugging
255
261
fn nodestr ( & self , id : ast:: NodeId ) -> ~str {
@@ -258,11 +264,11 @@ impl<'self> PrivacyVisitor<'self> {
258
264
259
265
// Determines whether the given definition is public from the point of view
260
266
// of the current item.
261
- fn def_public ( & self , did : ast:: DefId ) -> bool {
267
+ fn def_privacy ( & self , did : ast:: DefId ) -> PrivacyResult {
262
268
if !is_local ( did) {
263
269
if self . external_exports . contains ( & did) {
264
270
debug2 ! ( "privacy - {:?} was externally exported" , did) ;
265
- return true ;
271
+ return Allowable ;
266
272
}
267
273
debug2 ! ( "privacy - is {:?} a public method" , did) ;
268
274
return match self . tcx . methods . find ( & did) {
@@ -271,38 +277,42 @@ impl<'self> PrivacyVisitor<'self> {
271
277
match meth. container {
272
278
ty:: TraitContainer ( id) => {
273
279
debug2 ! ( "privacy - recursing on trait {:?}" , id) ;
274
- self . def_public ( id)
280
+ self . def_privacy ( id)
275
281
}
276
282
ty:: ImplContainer ( id) => {
277
283
match ty:: impl_trait_ref ( self . tcx , id) {
278
284
Some ( t) => {
279
285
debug2 ! ( "privacy - impl of trait {:?}" , id) ;
280
- self . def_public ( t. def_id )
286
+ self . def_privacy ( t. def_id )
281
287
}
282
288
None => {
283
289
debug2 ! ( "privacy - found a method {:?}" ,
284
290
meth. vis) ;
285
- meth. vis == ast:: public
291
+ if meth. vis == ast:: public {
292
+ Allowable
293
+ } else {
294
+ ExternallyDenied
295
+ }
286
296
}
287
297
}
288
298
}
289
299
}
290
300
}
291
301
None => {
292
302
debug2 ! ( "privacy - nope, not even a method" ) ;
293
- false
303
+ ExternallyDenied
294
304
}
295
305
} ;
296
306
} else if self . exported_items . contains ( & did. node ) {
297
307
debug2 ! ( "privacy - exported item {}" , self . nodestr( did. node) ) ;
298
- return true ;
308
+ return Allowable ;
299
309
}
300
310
301
311
debug2 ! ( "privacy - local {:?} not public all the way down" , did) ;
302
312
// return quickly for things in the same module
303
313
if self . parents . find ( & did. node ) == self . parents . find ( & self . curitem ) {
304
314
debug2 ! ( "privacy - same parent, we're done here" ) ;
305
- return true ;
315
+ return Allowable ;
306
316
}
307
317
308
318
// We now know that there is at least one private member between the
@@ -330,7 +340,11 @@ impl<'self> PrivacyVisitor<'self> {
330
340
assert ! ( closest_private_id != ast:: DUMMY_NODE_ID ) ;
331
341
}
332
342
debug2 ! ( "privacy - closest priv {}" , self . nodestr( closest_private_id) ) ;
333
- return self . private_accessible ( closest_private_id) ;
343
+ if self . private_accessible ( closest_private_id) {
344
+ Allowable
345
+ } else {
346
+ DisallowedBy ( closest_private_id)
347
+ }
334
348
}
335
349
336
350
/// For a local private node in the AST, this function will determine
@@ -365,12 +379,51 @@ impl<'self> PrivacyVisitor<'self> {
365
379
}
366
380
}
367
381
382
+ /// Guarantee that a particular definition is public, possibly emitting an
383
+ /// error message if it's not.
384
+ fn ensure_public ( & self , span : Span , to_check : ast:: DefId ,
385
+ source_did : Option < ast:: DefId > , msg : & str ) -> bool {
386
+ match self . def_privacy ( to_check) {
387
+ ExternallyDenied => {
388
+ self . tcx . sess . span_err ( span, format ! ( "{} is private" , msg) )
389
+ }
390
+ DisallowedBy ( id) => {
391
+ if id == source_did. unwrap_or ( to_check) . node {
392
+ self . tcx . sess . span_err ( span, format ! ( "{} is private" , msg) ) ;
393
+ return false ;
394
+ } else {
395
+ self . tcx . sess . span_err ( span, format ! ( "{} is inaccessible" ,
396
+ msg) ) ;
397
+ }
398
+ match self . tcx . items . find ( & id) {
399
+ Some ( & ast_map:: node_item( item, _) ) => {
400
+ let desc = match item. node {
401
+ ast:: item_mod( * ) => "module" ,
402
+ ast:: item_trait( * ) => "trait" ,
403
+ _ => return false ,
404
+ } ;
405
+ let msg = format ! ( "{} `{}` is private" , desc,
406
+ token:: ident_to_str( & item. ident) ) ;
407
+ self . tcx . sess . span_note ( span, msg) ;
408
+ }
409
+ Some ( * ) | None => { }
410
+ }
411
+ }
412
+ Allowable => return true
413
+ }
414
+ return false ;
415
+ }
416
+
368
417
// Checks that a dereference of a univariant enum can occur.
369
418
fn check_variant ( & self , span : Span , enum_id : ast:: DefId ) {
370
419
let variant_info = ty:: enum_variants ( self . tcx , enum_id) [ 0 ] ;
371
- if !self . def_public ( variant_info. id ) {
372
- self . tcx . sess . span_err ( span, "can only dereference enums \
373
- with a single, public variant") ;
420
+
421
+ match self . def_privacy ( variant_info. id ) {
422
+ Allowable => { }
423
+ ExternallyDenied | DisallowedBy ( * ) => {
424
+ self . tcx . sess . span_err ( span, "can only dereference enums \
425
+ with a single, public variant") ;
426
+ }
374
427
}
375
428
}
376
429
@@ -399,29 +452,24 @@ impl<'self> PrivacyVisitor<'self> {
399
452
let method_id = ty:: method ( self . tcx , method_id) . provided_source
400
453
. unwrap_or ( method_id) ;
401
454
402
- if !self . def_public ( method_id) {
403
- debug2 ! ( "private: {:?}" , method_id) ;
404
- self . tcx . sess . span_err ( span, format ! ( "method `{}` is private" ,
405
- token:: ident_to_str( name) ) ) ;
406
- }
455
+ self . ensure_public ( span, method_id, None ,
456
+ format ! ( "method `{}`" , token:: ident_to_str( name) ) ) ;
407
457
}
408
458
409
459
// Checks that a path is in scope.
410
460
fn check_path ( & mut self , span : Span , path_id : ast:: NodeId , path : & ast:: Path ) {
411
461
debug2 ! ( "privacy - path {}" , self . nodestr( path_id) ) ;
462
+ let def = self . tcx . def_map . get_copy ( & path_id) ;
412
463
let ck = |tyname : & str | {
413
- let last_private = * self . last_private_map . get ( & path_id) ;
414
- debug2 ! ( "privacy - {:?}" , last_private) ;
415
- let public = match last_private {
416
- resolve:: AllPublic => true ,
417
- resolve:: DependsOn ( def) => self . def_public ( def) ,
418
- } ;
419
- if !public {
420
- debug2 ! ( "denying {:?}" , path) ;
421
- let name = token:: ident_to_str ( & path. segments . last ( )
422
- . identifier ) ;
423
- self . tcx . sess . span_err ( span,
424
- format ! ( "{} `{}` is private" , tyname, name) ) ;
464
+ let origdid = def_id_of_def ( def) ;
465
+ match * self . last_private_map . get ( & path_id) {
466
+ resolve:: AllPublic => { } ,
467
+ resolve:: DependsOn ( def) => {
468
+ let name = token:: ident_to_str ( & path. segments . last ( )
469
+ . identifier ) ;
470
+ self . ensure_public ( span, def, Some ( origdid) ,
471
+ format ! ( "{} `{}`" , tyname, name) ) ;
472
+ }
425
473
}
426
474
} ;
427
475
match self . tcx . def_map . get_copy ( & path_id) {
@@ -456,9 +504,8 @@ impl<'self> PrivacyVisitor<'self> {
456
504
method_num : method_num,
457
505
_
458
506
} ) => {
459
- if !self . def_public ( trait_id) {
460
- self . tcx . sess . span_err ( span, "source trait is private" ) ;
461
- return ;
507
+ if !self . ensure_public ( span, trait_id, None , "source trait" ) {
508
+ return
462
509
}
463
510
match self . tcx . items . find ( & trait_id. node ) {
464
511
Some ( & ast_map:: node_item( item, _) ) => {
@@ -470,12 +517,10 @@ impl<'self> PrivacyVisitor<'self> {
470
517
node : method. id ,
471
518
crate : trait_id. crate ,
472
519
} ;
473
- if self . def_public ( def) { return }
474
- let msg = format ! ( "method `{}` is \
475
- private",
520
+ self . ensure_public ( span, def, None ,
521
+ format ! ( "method `{}`" ,
476
522
token:: ident_to_str(
477
- & method. ident) ) ;
478
- self . tcx . sess . span_err ( span, msg) ;
523
+ & method. ident) ) ) ;
479
524
}
480
525
ast:: required( _) => {
481
526
// Required methods can't be private.
0 commit comments