Skip to content

Commit 32db83b

Browse files
committed
Support extern in paths
1 parent b107f72 commit 32db83b

File tree

14 files changed

+185
-26
lines changed

14 files changed

+185
-26
lines changed

src/librustc_resolve/lib.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,8 @@ impl<'a> Resolver<'a> {
29822982
let msg = "There are too many initial `super`s.".to_string();
29832983
return PathResult::Failed(ident.span, msg, false);
29842984
}
2985+
} else if i == 0 && ns == TypeNS && name == keywords::Extern.name() {
2986+
continue;
29852987
}
29862988
allow_super = false;
29872989

@@ -2996,16 +2998,19 @@ impl<'a> Resolver<'a> {
29962998
// `$crate::a::b`
29972999
module = Some(self.resolve_crate_root(ident.node.ctxt));
29983000
continue
2999-
} else if i == 1 && self.session.features.borrow().extern_absolute_paths &&
3000-
path[0].node.name == keywords::CrateRoot.name() &&
3001-
!token::Ident(ident.node).is_path_segment_keyword() {
3002-
// `::extern_crate::a::b`
3003-
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
3004-
let crate_root =
3005-
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
3006-
self.populate_module_if_necessary(crate_root);
3007-
module = Some(crate_root);
3008-
continue
3001+
} else if i == 1 && !token::Ident(ident.node).is_path_segment_keyword() {
3002+
let prev_name = path[0].node.name;
3003+
if prev_name == keywords::Extern.name() ||
3004+
prev_name == keywords::CrateRoot.name() &&
3005+
self.session.features.borrow().extern_absolute_paths {
3006+
// `::extern_crate::a::b`
3007+
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
3008+
let crate_root =
3009+
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
3010+
self.populate_module_if_necessary(crate_root);
3011+
module = Some(crate_root);
3012+
continue
3013+
}
30093014
}
30103015
}
30113016

@@ -3015,6 +3020,7 @@ impl<'a> Resolver<'a> {
30153020
name == keywords::SelfValue.name() && i != 0 ||
30163021
name == keywords::SelfType.name() && i != 0 ||
30173022
name == keywords::Super.name() && i != 0 ||
3023+
name == keywords::Extern.name() && i != 0 ||
30183024
name == keywords::Crate.name() && i != 1 &&
30193025
path[0].node.name != keywords::CrateRoot.name() {
30203026
let name_str = if name == keywords::CrateRoot.name() {

src/librustc_resolve/resolve_imports.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -604,26 +604,28 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
604604
self.current_module = directive.parent;
605605
let ImportDirective { ref module_path, span, .. } = *directive;
606606

607-
// Extern crate mode for absolute paths needs some
608-
// special support for single-segment imports.
609-
let extern_absolute_paths = self.session.features.borrow().extern_absolute_paths;
610-
if module_path.len() == 1 && module_path[0].node.name == keywords::CrateRoot.name() {
607+
// FIXME: Last path segment is treated specially in import resolution, so extern crate
608+
// mode for absolute paths needs some special support for single-segment imports.
609+
if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() ||
610+
module_path[0].node.name == keywords::Extern.name()) {
611+
let is_extern = module_path[0].node.name == keywords::Extern.name() ||
612+
self.session.features.borrow().extern_absolute_paths;
611613
match directive.subclass {
612-
GlobImport { .. } if extern_absolute_paths => {
614+
GlobImport { .. } if is_extern => {
613615
return Some((directive.span,
614616
"cannot glob-import all possible crates".to_string()));
615617
}
616618
SingleImport { source, target, .. } => {
617-
let crate_root = if source.name == keywords::Crate.name() {
619+
let crate_root = if source.name == keywords::Crate.name() &&
620+
module_path[0].node.name != keywords::Extern.name() {
618621
if target.name == keywords::Crate.name() {
619622
return Some((directive.span,
620623
"crate root imports need to be explicitly named: \
621624
`use crate as name;`".to_string()));
622625
} else {
623626
Some(self.resolve_crate_root(source.ctxt.modern()))
624627
}
625-
} else if extern_absolute_paths &&
626-
!token::Ident(source).is_path_segment_keyword() {
628+
} else if is_extern && !token::Ident(source).is_path_segment_keyword() {
627629
let crate_id =
628630
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
629631
let crate_root =

src/libsyntax/feature_gate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ declare_features! (
450450

451451
// Allows use of the :lifetime macro fragment specifier
452452
(active, macro_lifetime_matcher, "1.24.0", Some(46895)),
453+
454+
// `extern` in paths
455+
(active, extern_in_paths, "1.23.0", Some(44660)),
453456
);
454457

455458
declare_features! (
@@ -1790,6 +1793,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17901793
if segment.identifier.name == keywords::Crate.name() {
17911794
gate_feature_post!(&self, crate_in_paths, segment.span,
17921795
"`crate` in paths is experimental");
1796+
} else if segment.identifier.name == keywords::Extern.name() {
1797+
gate_feature_post!(&self, extern_in_paths, segment.span,
1798+
"`extern` in paths is experimental");
17931799
}
17941800
}
17951801

src/libsyntax/parse/parser.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ impl<'a> Parser<'a> {
13871387
None
13881388
};
13891389
(ident, TraitItemKind::Const(ty, default), ast::Generics::default())
1390-
} else if self.token.is_path_start() {
1390+
} else if self.token.is_path_start() && !self.is_extern_non_path() {
13911391
// trait item macro.
13921392
// code copied from parse_macro_use_or_failure... abstraction!
13931393
let prev_span = self.prev_span;
@@ -4037,6 +4037,10 @@ impl<'a> Parser<'a> {
40374037
self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
40384038
}
40394039

4040+
fn is_extern_non_path(&self) -> bool {
4041+
self.token.is_keyword(keywords::Extern) && self.look_ahead(1, |t| t != &token::ModSep)
4042+
}
4043+
40404044
fn eat_auto_trait(&mut self) -> bool {
40414045
if self.token.is_keyword(keywords::Auto)
40424046
&& self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
@@ -4152,10 +4156,12 @@ impl<'a> Parser<'a> {
41524156
// like a path (1 token), but it fact not a path.
41534157
// `union::b::c` - path, `union U { ... }` - not a path.
41544158
// `crate::b::c` - path, `crate struct S;` - not a path.
4159+
// `extern::b::c` - path, `extern crate c;` - not a path.
41554160
} else if self.token.is_path_start() &&
41564161
!self.token.is_qpath_start() &&
41574162
!self.is_union_item() &&
4158-
!self.is_crate_vis() {
4163+
!self.is_crate_vis() &&
4164+
!self.is_extern_non_path() {
41594165
let pth = self.parse_path(PathStyle::Expr)?;
41604166

41614167
if !self.eat(&token::Not) {
@@ -5236,7 +5242,7 @@ impl<'a> Parser<'a> {
52365242
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::Generics,
52375243
ast::ImplItemKind)> {
52385244
// code copied from parse_macro_use_or_failure... abstraction!
5239-
if self.token.is_path_start() {
5245+
if self.token.is_path_start() && !self.is_extern_non_path() {
52405246
// Method macro.
52415247

52425248
let prev_span = self.prev_span;
@@ -6238,7 +6244,8 @@ impl<'a> Parser<'a> {
62386244
return Ok(Some(item));
62396245
}
62406246

6241-
if self.eat_keyword(keywords::Extern) {
6247+
if self.check_keyword(keywords::Extern) && self.is_extern_non_path() {
6248+
self.bump(); // `extern`
62426249
if self.eat_keyword(keywords::Crate) {
62436250
return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?));
62446251
}

src/libsyntax/parse/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ impl Token {
359359
Some(id) => id.name == keywords::Super.name() ||
360360
id.name == keywords::SelfValue.name() ||
361361
id.name == keywords::SelfType.name() ||
362+
id.name == keywords::Extern.name() ||
362363
id.name == keywords::Crate.name() ||
363364
id.name == keywords::DollarCrate.name(),
364365
None => false,

src/test/parse-fail/keyword-extern-as-identifier.rs src/test/compile-fail/keyword-extern-as-identifier.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only
12-
13-
// This file was auto-generated using 'src/etc/generate-keyword-tests.py extern'
11+
#![feature(extern_in_paths)]
1412

1513
fn main() {
16-
let extern = "foo"; //~ error: expected pattern, found keyword `extern`
14+
let extern = 0; //~ ERROR expected unit struct/variant or constant, found module `extern`
1715
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[derive(Debug)]
12+
pub struct S;
13+
14+
#[derive(Debug)]
15+
pub struct Z;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_in_paths)]
12+
13+
use extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_in_paths)]
12+
13+
fn main() {
14+
let s = extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_in_paths)]
12+
13+
use extern::ycrate; //~ ERROR can't find crate for `ycrate`
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:xcrate.rs
12+
13+
#![feature(extern_in_paths)]
14+
15+
use extern; //~ ERROR unresolved import `extern`
16+
//~^ NOTE no `extern` in the root
17+
use extern::*; //~ ERROR unresolved import `extern::*`
18+
//~^ NOTE cannot glob-import all possible crates
19+
20+
fn main() {
21+
let s = extern::xcrate; //~ ERROR expected value, found module `extern::xcrate`
22+
//~^ NOTE not a value
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:xcrate.rs
12+
13+
#![feature(extern_in_paths)]
14+
15+
use extern::xcrate::Z;
16+
17+
fn f() {
18+
use extern::xcrate;
19+
use extern::xcrate as ycrate;
20+
let s = xcrate::S;
21+
assert_eq!(format!("{:?}", s), "S");
22+
let z = ycrate::Z;
23+
assert_eq!(format!("{:?}", z), "Z");
24+
}
25+
26+
fn main() {
27+
let s = extern::xcrate::S;
28+
assert_eq!(format!("{:?}", s), "S");
29+
let z = Z;
30+
assert_eq!(format!("{:?}", z), "Z");
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S;
12+
13+
fn main() {
14+
let _ = extern::std::vec::Vec::new(); //~ ERROR `extern` in paths is experimental
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: `extern` in paths is experimental (see issue #44660)
2+
--> $DIR/feature-gate-extern_in_paths.rs:14:13
3+
|
4+
14 | let _ = extern::std::vec::Vec::new(); //~ ERROR `extern` in paths is experimental
5+
| ^^^^^^
6+
|
7+
= help: add #![feature(extern_in_paths)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)