@@ -3232,6 +3232,7 @@ impl<'a> Resolver<'a> {
32323232 -> PathResult < ' a > {
32333233 let mut module = None ;
32343234 let mut allow_super = true ;
3235+ let mut second_binding = None ;
32353236
32363237 for ( i, & ident) in path. iter ( ) . enumerate ( ) {
32373238 debug ! ( "resolve_path ident {} {:?}" , i, ident) ;
@@ -3321,7 +3322,9 @@ impl<'a> Resolver<'a> {
33213322 . map ( MacroBinding :: binding)
33223323 } else {
33233324 match self . resolve_ident_in_lexical_scope ( ident, ns, record_used, path_span) {
3325+ // we found a locally-imported or available item/module
33243326 Some ( LexicalScopeBinding :: Item ( binding) ) => Ok ( binding) ,
3327+ // we found a local variable or type param
33253328 Some ( LexicalScopeBinding :: Def ( def) )
33263329 if opt_ns == Some ( TypeNS ) || opt_ns == Some ( ValueNS ) => {
33273330 return PathResult :: NonModule ( PathResolution :: with_unresolved_segments (
@@ -3334,13 +3337,22 @@ impl<'a> Resolver<'a> {
33343337
33353338 match binding {
33363339 Ok ( binding) => {
3340+ if i == 1 {
3341+ second_binding = Some ( binding) ;
3342+ }
33373343 let def = binding. def ( ) ;
33383344 let maybe_assoc = opt_ns != Some ( MacroNS ) && PathSource :: Type . is_expected ( def) ;
33393345 if let Some ( next_module) = binding. module ( ) {
33403346 module = Some ( next_module) ;
33413347 } else if def == Def :: Err {
33423348 return PathResult :: NonModule ( err_path_resolution ( ) ) ;
33433349 } 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+ ) ;
33443356 return PathResult :: NonModule ( PathResolution :: with_unresolved_segments (
33453357 def, path. len ( ) - i - 1
33463358 ) ) ;
@@ -3349,33 +3361,6 @@ impl<'a> Resolver<'a> {
33493361 format ! ( "Not a module `{}`" , ident) ,
33503362 is_last) ;
33513363 }
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- }
33793364 }
33803365 Err ( Undetermined ) => return PathResult :: Indeterminate ,
33813366 Err ( Determined ) => {
@@ -3408,9 +3393,77 @@ impl<'a> Resolver<'a> {
34083393 }
34093394 }
34103395
3396+ self . lint_if_path_starts_with_module ( node_id, path, path_span, second_binding) ;
3397+
34113398 PathResult :: Module ( module. unwrap_or ( self . graph_root ) )
34123399 }
34133400
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+
34143467 // Resolve a local definition, potentially adjusting for closures.
34153468 fn adjust_local_def ( & mut self ,
34163469 ns : Namespace ,
0 commit comments