@@ -3232,6 +3232,7 @@ impl<'a> Resolver<'a> {
3232
3232
-> PathResult < ' a > {
3233
3233
let mut module = None ;
3234
3234
let mut allow_super = true ;
3235
+ let mut second_binding = None ;
3235
3236
3236
3237
for ( i, & ident) in path. iter ( ) . enumerate ( ) {
3237
3238
debug ! ( "resolve_path ident {} {:?}" , i, ident) ;
@@ -3321,7 +3322,9 @@ impl<'a> Resolver<'a> {
3321
3322
. map ( MacroBinding :: binding)
3322
3323
} else {
3323
3324
match self . resolve_ident_in_lexical_scope ( ident, ns, record_used, path_span) {
3325
+ // we found a locally-imported or available item/module
3324
3326
Some ( LexicalScopeBinding :: Item ( binding) ) => Ok ( binding) ,
3327
+ // we found a local variable or type param
3325
3328
Some ( LexicalScopeBinding :: Def ( def) )
3326
3329
if opt_ns == Some ( TypeNS ) || opt_ns == Some ( ValueNS ) => {
3327
3330
return PathResult :: NonModule ( PathResolution :: with_unresolved_segments (
@@ -3334,13 +3337,22 @@ impl<'a> Resolver<'a> {
3334
3337
3335
3338
match binding {
3336
3339
Ok ( binding) => {
3340
+ if i == 1 {
3341
+ second_binding = Some ( binding) ;
3342
+ }
3337
3343
let def = binding. def ( ) ;
3338
3344
let maybe_assoc = opt_ns != Some ( MacroNS ) && PathSource :: Type . is_expected ( def) ;
3339
3345
if let Some ( next_module) = binding. module ( ) {
3340
3346
module = Some ( next_module) ;
3341
3347
} else if def == Def :: Err {
3342
3348
return PathResult :: NonModule ( err_path_resolution ( ) ) ;
3343
3349
} else if opt_ns. is_some ( ) && ( is_last || maybe_assoc) {
3350
+ self . lint_if_path_starts_with_module (
3351
+ node_id,
3352
+ path,
3353
+ path_span,
3354
+ second_binding,
3355
+ ) ;
3344
3356
return PathResult :: NonModule ( PathResolution :: with_unresolved_segments (
3345
3357
def, path. len ( ) - i - 1
3346
3358
) ) ;
@@ -3349,33 +3361,6 @@ impl<'a> Resolver<'a> {
3349
3361
format ! ( "Not a module `{}`" , ident) ,
3350
3362
is_last) ;
3351
3363
}
3352
-
3353
- if let Some ( id) = node_id {
3354
- if i == 1 && self . session . features_untracked ( ) . crate_in_paths
3355
- && !self . session . rust_2018 ( ) {
3356
- let prev_name = path[ 0 ] . name ;
3357
- if prev_name == keywords:: Extern . name ( ) ||
3358
- prev_name == keywords:: CrateRoot . name ( ) {
3359
- let mut is_crate = false ;
3360
- if let NameBindingKind :: Import { directive : d, .. } = binding. kind {
3361
- if let ImportDirectiveSubclass :: ExternCrate ( ..) = d. subclass {
3362
- is_crate = true ;
3363
- }
3364
- }
3365
-
3366
- if !is_crate {
3367
- let diag = lint:: builtin:: BuiltinLintDiagnostics
3368
- :: AbsPathWithModule ( path_span) ;
3369
- self . session . buffer_lint_with_diagnostic (
3370
- lint:: builtin:: ABSOLUTE_PATH_STARTING_WITH_MODULE ,
3371
- id, path_span,
3372
- "Absolute paths must start with `self`, `super`, \
3373
- `crate`, or an external crate name in the 2018 edition",
3374
- diag) ;
3375
- }
3376
- }
3377
- }
3378
- }
3379
3364
}
3380
3365
Err ( Undetermined ) => return PathResult :: Indeterminate ,
3381
3366
Err ( Determined ) => {
@@ -3408,9 +3393,77 @@ impl<'a> Resolver<'a> {
3408
3393
}
3409
3394
}
3410
3395
3396
+ self . lint_if_path_starts_with_module ( node_id, path, path_span, second_binding) ;
3397
+
3411
3398
PathResult :: Module ( module. unwrap_or ( self . graph_root ) )
3412
3399
}
3413
3400
3401
+ fn lint_if_path_starts_with_module ( & self ,
3402
+ id : Option < NodeId > ,
3403
+ path : & [ Ident ] ,
3404
+ path_span : Span ,
3405
+ second_binding : Option < & NameBinding > ) {
3406
+ let id = match id {
3407
+ Some ( id) => id,
3408
+ None => return ,
3409
+ } ;
3410
+
3411
+ let first_name = match path. get ( 0 ) {
3412
+ Some ( ident) => ident. name ,
3413
+ None => return ,
3414
+ } ;
3415
+
3416
+ // We're only interested in `use` paths which should start with
3417
+ // `{{root}}` or `extern` currently.
3418
+ if first_name != keywords:: Extern . name ( ) && first_name != keywords:: CrateRoot . name ( ) {
3419
+ return
3420
+ }
3421
+
3422
+ match path. get ( 1 ) {
3423
+ // If this import looks like `crate::...` it's already good
3424
+ Some ( name) if name. name == keywords:: Crate . name ( ) => return ,
3425
+ // Otherwise go below to see if it's an extern crate
3426
+ Some ( _) => { }
3427
+ // If the path has length one (and it's `CrateRoot` most likely)
3428
+ // then we don't know whether we're gonna be importing a crate or an
3429
+ // item in our crate. Defer this lint to elsewhere
3430
+ None => return ,
3431
+ }
3432
+
3433
+ // If the first element of our path was actually resolved to an
3434
+ // `ExternCrate` (also used for `crate::...`) then no need to issue a
3435
+ // warning, this looks all good!
3436
+ if let Some ( binding) = second_binding {
3437
+ if let NameBindingKind :: Import { directive : d, .. } = binding. kind {
3438
+ if let ImportDirectiveSubclass :: ExternCrate ( ..) = d. subclass {
3439
+ return
3440
+ }
3441
+ }
3442
+ }
3443
+
3444
+ self . lint_path_starts_with_module ( id, path_span) ;
3445
+ }
3446
+
3447
+ fn lint_path_starts_with_module ( & self , id : NodeId , span : Span ) {
3448
+ // In the 2018 edition this lint is a hard error, so nothing to do
3449
+ if self . session . rust_2018 ( ) {
3450
+ return
3451
+ }
3452
+ // In the 2015 edition there's no use in emitting lints unless the
3453
+ // crate's already enabled the feature that we're going to suggest
3454
+ if !self . session . features_untracked ( ) . crate_in_paths {
3455
+ return
3456
+ }
3457
+ let diag = lint:: builtin:: BuiltinLintDiagnostics
3458
+ :: AbsPathWithModule ( span) ;
3459
+ self . session . buffer_lint_with_diagnostic (
3460
+ lint:: builtin:: ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE ,
3461
+ id, span,
3462
+ "absolute paths must start with `self`, `super`, \
3463
+ `crate`, or an external crate name in the 2018 edition",
3464
+ diag) ;
3465
+ }
3466
+
3414
3467
// Resolve a local definition, potentially adjusting for closures.
3415
3468
fn adjust_local_def ( & mut self ,
3416
3469
ns : Namespace ,
0 commit comments