@@ -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) ;
@@ -3334,13 +3335,22 @@ impl<'a> Resolver<'a> {
3334
3335
3335
3336
match binding {
3336
3337
Ok ( binding) => {
3338
+ if i == 1 {
3339
+ second_binding = Some ( binding) ;
3340
+ }
3337
3341
let def = binding. def ( ) ;
3338
3342
let maybe_assoc = opt_ns != Some ( MacroNS ) && PathSource :: Type . is_expected ( def) ;
3339
3343
if let Some ( next_module) = binding. module ( ) {
3340
3344
module = Some ( next_module) ;
3341
3345
} else if def == Def :: Err {
3342
3346
return PathResult :: NonModule ( err_path_resolution ( ) ) ;
3343
3347
} else if opt_ns. is_some ( ) && ( is_last || maybe_assoc) {
3348
+ self . lint_if_path_starts_with_module (
3349
+ node_id,
3350
+ path,
3351
+ path_span,
3352
+ second_binding,
3353
+ ) ;
3344
3354
return PathResult :: NonModule ( PathResolution :: with_unresolved_segments (
3345
3355
def, path. len ( ) - i - 1
3346
3356
) ) ;
@@ -3349,33 +3359,6 @@ impl<'a> Resolver<'a> {
3349
3359
format ! ( "Not a module `{}`" , ident) ,
3350
3360
is_last) ;
3351
3361
}
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
3362
}
3380
3363
Err ( Undetermined ) => return PathResult :: Indeterminate ,
3381
3364
Err ( Determined ) => {
@@ -3408,9 +3391,67 @@ impl<'a> Resolver<'a> {
3408
3391
}
3409
3392
}
3410
3393
3394
+ self . lint_if_path_starts_with_module ( node_id, path, path_span, second_binding) ;
3395
+
3411
3396
PathResult :: Module ( module. unwrap_or ( self . graph_root ) )
3412
3397
}
3413
3398
3399
+ fn lint_if_path_starts_with_module ( & self ,
3400
+ id : Option < NodeId > ,
3401
+ path : & [ Ident ] ,
3402
+ path_span : Span ,
3403
+ second_binding : Option < & NameBinding > ) {
3404
+ // In the 2018 edition this lint is a hard error, so nothing to do
3405
+ if self . session . rust_2018 ( ) {
3406
+ return
3407
+ }
3408
+ // In the 2015 edition there's no use in emitting lints unless the
3409
+ // crate's already enabled the feature that we're going to suggest
3410
+ if !self . session . features_untracked ( ) . crate_in_paths {
3411
+ return
3412
+ }
3413
+ let id = match id {
3414
+ Some ( id) => id,
3415
+ None => return ,
3416
+ } ;
3417
+ let first_name = match path. get ( 0 ) {
3418
+ Some ( ident) => ident. name ,
3419
+ None => return ,
3420
+ } ;
3421
+
3422
+ // We're only interested in `use` paths which should start with
3423
+ // `{{root}}` or `extern` currently.
3424
+ if first_name != keywords:: Extern . name ( ) && first_name != keywords:: CrateRoot . name ( ) {
3425
+ return
3426
+ }
3427
+
3428
+ if let Some ( part) = path. get ( 1 ) {
3429
+ if part. name == keywords:: Crate . name ( ) {
3430
+ return
3431
+ }
3432
+ }
3433
+
3434
+ // If the first element of our path was actually resolved to an
3435
+ // `ExternCrate` (also used for `crate::...`) then no need to issue a
3436
+ // warning, this looks all good!
3437
+ if let Some ( binding) = second_binding {
3438
+ if let NameBindingKind :: Import { directive : d, .. } = binding. kind {
3439
+ if let ImportDirectiveSubclass :: ExternCrate ( ..) = d. subclass {
3440
+ return
3441
+ }
3442
+ }
3443
+ }
3444
+
3445
+ let diag = lint:: builtin:: BuiltinLintDiagnostics
3446
+ :: AbsPathWithModule ( path_span) ;
3447
+ self . session . buffer_lint_with_diagnostic (
3448
+ lint:: builtin:: ABSOLUTE_PATH_STARTING_WITH_MODULE ,
3449
+ id, path_span,
3450
+ "Absolute paths must start with `self`, `super`, \
3451
+ `crate`, or an external crate name in the 2018 edition",
3452
+ diag) ;
3453
+ }
3454
+
3414
3455
// Resolve a local definition, potentially adjusting for closures.
3415
3456
fn adjust_local_def ( & mut self ,
3416
3457
ns : Namespace ,
0 commit comments