Skip to content

Commit 4bb5d35

Browse files
committed
Auto merge of #56392 - petrochenkov:regensym, r=oli-obk
Delay gensym creation for "underscore items" (`use foo as _`/`const _`) until name resolution So they cannot be cloned by macros. See #56303 for the discussion. Mostly fix cross-crate use of underscore items by inverting the "gensyms are lost in metadata" bug as described in #56303 (comment). Fix unused import warnings for single-segment imports (first commit) and `use crate_name as _` imports (as specified in #56303 (comment)). Prohibit accidentally implemented `static _: TYPE = EXPR;` (cc #55983). Add more tests for `use foo as _` imports.
2 parents 367e783 + eb1d2e6 commit 4bb5d35

19 files changed

+212
-70
lines changed

src/librustc_resolve/build_reduced_graph.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
157157
};
158158
match use_tree.kind {
159159
ast::UseTreeKind::Simple(rename, ..) => {
160-
let mut ident = use_tree.ident();
160+
let mut ident = use_tree.ident().gensym_if_underscore();
161161
let mut module_path = prefix;
162162
let mut source = module_path.pop().unwrap();
163163
let mut type_ns_only = false;
@@ -230,13 +230,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
230230
}
231231

232232
let subclass = SingleImport {
233-
target: ident,
234233
source: source.ident,
235-
result: PerNS {
234+
target: ident,
235+
source_bindings: PerNS {
236236
type_ns: Cell::new(Err(Undetermined)),
237237
value_ns: Cell::new(Err(Undetermined)),
238238
macro_ns: Cell::new(Err(Undetermined)),
239239
},
240+
target_bindings: PerNS {
241+
type_ns: Cell::new(None),
242+
value_ns: Cell::new(None),
243+
macro_ns: Cell::new(None),
244+
},
240245
type_ns_only,
241246
};
242247
self.add_import_directive(
@@ -329,7 +334,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
329334
fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) {
330335
let parent = parent_scope.module;
331336
let expansion = parent_scope.expansion;
332-
let ident = item.ident;
337+
let ident = item.ident.gensym_if_underscore();
333338
let sp = item.span;
334339
let vis = self.resolve_visibility(&item.vis);
335340

@@ -623,7 +628,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
623628

624629
/// Builds the reduced graph for a single item in an external crate.
625630
fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) {
626-
let Export { ident, def, vis, span, .. } = child;
631+
let Export { ident, def, vis, span } = child;
632+
// FIXME: We shouldn't create the gensym here, it should come from metadata,
633+
// but metadata cannot encode gensyms currently, so we create it here.
634+
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
635+
let ident = ident.gensym_if_underscore();
627636
let def_id = def.def_id();
628637
let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene
629638
match def {

src/librustc_resolve/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1519,8 +1519,12 @@ pub struct Resolver<'a, 'b: 'a> {
15191519
/// The current self item if inside an ADT (used for better errors).
15201520
current_self_item: Option<NodeId>,
15211521

1522-
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
1522+
/// FIXME: Refactor things so that these fields are passed through arguments and not resolver.
1523+
/// We are resolving a last import segment during import validation.
15231524
last_import_segment: bool,
1525+
/// This binding should be ignored during in-module resolution, so that we don't get
1526+
/// "self-confirming" import resolutions during import validation.
1527+
blacklisted_binding: Option<&'a NameBinding<'a>>,
15241528

15251529
/// The idents for the primitive types.
15261530
primitive_type_table: PrimitiveTypeTable,
@@ -1871,6 +1875,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18711875
current_self_type: None,
18721876
current_self_item: None,
18731877
last_import_segment: false,
1878+
blacklisted_binding: None,
18741879

18751880
primitive_type_table: PrimitiveTypeTable::new(),
18761881

src/librustc_resolve/macros.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -977,12 +977,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
977977
let what = self.binding_description(binding, ident,
978978
flags.contains(Flags::MISC_FROM_PRELUDE));
979979
let note_msg = format!("this import refers to {what}", what = what);
980-
if binding.span.is_dummy() {
980+
let label_span = if binding.span.is_dummy() {
981981
err.note(&note_msg);
982+
ident.span
982983
} else {
983984
err.span_note(binding.span, &note_msg);
984-
err.span_label(binding.span, "not an extern crate passed with `--extern`");
985-
}
985+
binding.span
986+
};
987+
err.span_label(label_span, "not an extern crate passed with `--extern`");
986988
err.emit();
987989
}
988990

src/librustc_resolve/resolve_imports.rs

+43-18
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@ use std::{mem, ptr};
4242
#[derive(Clone, Debug)]
4343
pub enum ImportDirectiveSubclass<'a> {
4444
SingleImport {
45-
target: Ident,
45+
/// `source` in `use prefix::source as target`.
4646
source: Ident,
47-
result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
47+
/// `target` in `use prefix::source as target`.
48+
target: Ident,
49+
/// Bindings to which `source` refers to.
50+
source_bindings: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
51+
/// Bindings introduced by `target`.
52+
target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>,
53+
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
4854
type_ns_only: bool,
4955
},
5056
GlobImport {
@@ -227,6 +233,11 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
227233
}
228234

229235
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
236+
if let Some(blacklisted_binding) = this.blacklisted_binding {
237+
if ptr::eq(binding, blacklisted_binding) {
238+
return Err((Determined, Weak::No));
239+
}
240+
}
230241
// `extern crate` are always usable for backwards compatibility, see issue #37020,
231242
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
232243
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
@@ -642,10 +653,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
642653
if let Some((span, err, note)) = self.finalize_import(import) {
643654
errors = true;
644655

645-
if let SingleImport { source, ref result, .. } = import.subclass {
656+
if let SingleImport { source, ref source_bindings, .. } = import.subclass {
646657
if source.name == "self" {
647658
// Silence `unresolved import` error if E0429 is already emitted
648-
if let Err(Determined) = result.value_ns.get() {
659+
if let Err(Determined) = source_bindings.value_ns.get() {
649660
continue;
650661
}
651662
}
@@ -765,9 +776,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
765776
};
766777

767778
directive.imported_module.set(Some(module));
768-
let (source, target, result, type_ns_only) = match directive.subclass {
769-
SingleImport { source, target, ref result, type_ns_only } =>
770-
(source, target, result, type_ns_only),
779+
let (source, target, source_bindings, target_bindings, type_ns_only) =
780+
match directive.subclass {
781+
SingleImport { source, target, ref source_bindings,
782+
ref target_bindings, type_ns_only } =>
783+
(source, target, source_bindings, target_bindings, type_ns_only),
771784
GlobImport { .. } => {
772785
self.resolve_glob_import(directive);
773786
return true;
@@ -777,7 +790,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
777790

778791
let mut indeterminate = false;
779792
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
780-
if let Err(Undetermined) = result[ns].get() {
793+
if let Err(Undetermined) = source_bindings[ns].get() {
781794
// For better failure detection, pretend that the import will
782795
// not define any names while resolving its module path.
783796
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
@@ -786,13 +799,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
786799
);
787800
directive.vis.set(orig_vis);
788801

789-
result[ns].set(binding);
802+
source_bindings[ns].set(binding);
790803
} else {
791804
return
792805
};
793806

794807
let parent = directive.parent_scope.module;
795-
match result[ns].get() {
808+
match source_bindings[ns].get() {
796809
Err(Undetermined) => indeterminate = true,
797810
Err(Determined) => {
798811
this.update_resolution(parent, target, ns, |_, resolution| {
@@ -810,6 +823,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
810823
}
811824
Ok(binding) => {
812825
let imported_binding = this.import(binding, directive);
826+
target_bindings[ns].set(Some(imported_binding));
813827
let conflict = this.try_define(parent, target, ns, imported_binding);
814828
if let Err(old_binding) = conflict {
815829
this.report_conflict(parent, target, ns, imported_binding, old_binding);
@@ -879,8 +893,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
879893
PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(),
880894
};
881895

882-
let (ident, result, type_ns_only) = match directive.subclass {
883-
SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
896+
let (ident, target, source_bindings, target_bindings, type_ns_only) =
897+
match directive.subclass {
898+
SingleImport { source, target, ref source_bindings,
899+
ref target_bindings, type_ns_only } =>
900+
(source, target, source_bindings, target_bindings, type_ns_only),
884901
GlobImport { is_prelude, ref max_vis } => {
885902
if directive.module_path.len() <= 1 {
886903
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
@@ -919,20 +936,28 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
919936
let mut all_ns_err = true;
920937
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
921938
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
939+
let orig_blacklisted_binding =
940+
mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get());
922941
let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
923942
let binding = this.resolve_ident_in_module(
924943
module, ident, ns, Some(&directive.parent_scope), true, directive.span
925944
);
926945
this.last_import_segment = orig_last_import_segment;
946+
this.blacklisted_binding = orig_blacklisted_binding;
927947
directive.vis.set(orig_vis);
928948

929949
match binding {
930950
Ok(binding) => {
931951
// Consistency checks, analogous to `finalize_current_module_macro_resolutions`.
932-
let initial_def = result[ns].get().map(|initial_binding| {
952+
let initial_def = source_bindings[ns].get().map(|initial_binding| {
933953
all_ns_err = false;
934-
this.record_use(ident, ns, initial_binding,
935-
directive.module_path.is_empty());
954+
if let Some(target_binding) = target_bindings[ns].get() {
955+
if target.name == "_" &&
956+
initial_binding.is_extern_crate() && !initial_binding.is_import() {
957+
this.record_use(ident, ns, target_binding,
958+
directive.module_path.is_empty());
959+
}
960+
}
936961
initial_binding.def_ignoring_ambiguity()
937962
});
938963
let def = binding.def_ignoring_ambiguity();
@@ -1034,7 +1059,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10341059
let mut reexport_error = None;
10351060
let mut any_successful_reexport = false;
10361061
self.per_ns(|this, ns| {
1037-
if let Ok(binding) = result[ns].get() {
1062+
if let Ok(binding) = source_bindings[ns].get() {
10381063
let vis = directive.vis.get();
10391064
if !binding.pseudo_vis().is_at_least(vis, &*this) {
10401065
reexport_error = Some((ns, binding));
@@ -1078,7 +1103,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10781103
let mut full_path = directive.module_path.clone();
10791104
full_path.push(Segment::from_ident(ident));
10801105
self.per_ns(|this, ns| {
1081-
if let Ok(binding) = result[ns].get() {
1106+
if let Ok(binding) = source_bindings[ns].get() {
10821107
this.lint_if_path_starts_with_module(
10831108
directive.crate_lint(),
10841109
&full_path,
@@ -1092,7 +1117,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10921117
// Record what this import resolves to for later uses in documentation,
10931118
// this may resolve to either a value or a type, but for documentation
10941119
// purposes it's good enough to just favor one over the other.
1095-
self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
1120+
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
10961121
let mut def = binding.def();
10971122
if let Def::Macro(def_id, _) = def {
10981123
// `DefId`s from the "built-in macro crate" should not leak from resolve because

src/libsyntax/parse/parser.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,17 @@ impl<'a> Parser<'a> {
20172017
}
20182018
}
20192019

2020+
fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
2021+
match self.token {
2022+
token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
2023+
let span = self.span;
2024+
self.bump();
2025+
Ok(Ident::new(ident.name, span))
2026+
}
2027+
_ => self.parse_ident(),
2028+
}
2029+
}
2030+
20202031
/// Parses qualified path.
20212032
/// Assumes that the leading `<` has been parsed already.
20222033
///
@@ -6434,13 +6445,7 @@ impl<'a> Parser<'a> {
64346445
}
64356446

64366447
fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
6437-
let id = match self.token {
6438-
token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
6439-
self.bump(); // `_`
6440-
ident.gensym()
6441-
},
6442-
_ => self.parse_ident()?,
6443-
};
6448+
let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
64446449
self.expect(&token::Colon)?;
64456450
let ty = self.parse_ty()?;
64466451
self.expect(&token::Eq)?;
@@ -7725,13 +7730,7 @@ impl<'a> Parser<'a> {
77257730

77267731
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
77277732
if self.eat_keyword(keywords::As) {
7728-
match self.token {
7729-
token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
7730-
self.bump(); // `_`
7731-
Ok(Some(ident.gensym()))
7732-
}
7733-
_ => self.parse_ident().map(Some),
7734-
}
7733+
self.parse_ident_or_underscore().map(Some)
77357734
} else {
77367735
Ok(None)
77377736
}

src/libsyntax_pos/symbol.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ impl Ident {
8080
Ident::new(self.name.gensymed(), self.span)
8181
}
8282

83+
pub fn gensym_if_underscore(self) -> Ident {
84+
if self.name == keywords::Underscore.name() { self.gensym() } else { self }
85+
}
86+
8387
pub fn as_str(self) -> LocalInternedString {
8488
self.name.as_str()
8589
}
@@ -473,7 +477,7 @@ impl Ident {
473477
// We see this identifier in a normal identifier position, like variable name or a type.
474478
// How was it written originally? Did it use the raw form? Let's try to guess.
475479
pub fn is_raw_guess(self) -> bool {
476-
self.name != keywords::Invalid.name() &&
480+
self.name != keywords::Invalid.name() && self.name != keywords::Underscore.name() &&
477481
self.is_reserved() && !self.is_path_segment_keyword()
478482
}
479483
}

src/test/ui/feature-gates/feature-gate-uniform-paths.stderr

+3-15
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ LL | use inline; //~ ERROR imports can only refer to extern crate names
2525
| ^^^^^^ not an extern crate passed with `--extern`
2626
|
2727
= help: add #![feature(uniform_paths)] to the crate attributes to enable
28-
note: this import refers to the built-in attribute imported here
29-
--> $DIR/feature-gate-uniform-paths.rs:21:5
30-
|
31-
LL | use inline; //~ ERROR imports can only refer to extern crate names
32-
| ^^^^^^
28+
= note: this import refers to a built-in attribute
3329

3430
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
3531
--> $DIR/feature-gate-uniform-paths.rs:23:5
@@ -38,11 +34,7 @@ LL | use Vec; //~ ERROR imports can only refer to extern crate names
3834
| ^^^ not an extern crate passed with `--extern`
3935
|
4036
= help: add #![feature(uniform_paths)] to the crate attributes to enable
41-
note: this import refers to the struct imported here
42-
--> $DIR/feature-gate-uniform-paths.rs:23:5
43-
|
44-
LL | use Vec; //~ ERROR imports can only refer to extern crate names
45-
| ^^^
37+
= note: this import refers to a struct from prelude
4638

4739
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
4840
--> $DIR/feature-gate-uniform-paths.rs:25:5
@@ -51,11 +43,7 @@ LL | use vec; //~ ERROR imports can only refer to extern crate names
5143
| ^^^ not an extern crate passed with `--extern`
5244
|
5345
= help: add #![feature(uniform_paths)] to the crate attributes to enable
54-
note: this import refers to the macro imported here
55-
--> $DIR/feature-gate-uniform-paths.rs:25:5
56-
|
57-
LL | use vec; //~ ERROR imports can only refer to extern crate names
58-
| ^^^
46+
= note: this import refers to a macro from prelude
5947

6048
error: aborting due to 4 previous errors
6149

src/test/ui/underscore_const_names_feature_gate.rs renamed to src/test/ui/feature-gates/underscore_const_names_feature_gate.rs

-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,5 @@
99
// except according to those terms.
1010

1111
const _: () = (); //~ ERROR is unstable
12-
static _: () = (); //~ ERROR is unstable
1312

1413
fn main() {}

src/test/ui/underscore_const_names_feature_gate.stderr renamed to src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr

+1-9
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ LL | const _: () = (); //~ ERROR is unstable
66
|
77
= help: add #![feature(underscore_const_names)] to the crate attributes to enable
88

9-
error[E0658]: naming constants with `_` is unstable (see issue #54912)
10-
--> $DIR/underscore_const_names_feature_gate.rs:12:1
11-
|
12-
LL | static _: () = (); //~ ERROR is unstable
13-
| ^^^^^^^^^^^^^^^^^^
14-
|
15-
= help: add #![feature(underscore_const_names)] to the crate attributes to enable
16-
17-
error: aborting due to 2 previous errors
9+
error: aborting due to previous error
1810

1911
For more information about this error, try `rustc --explain E0658`.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// compile-flags: -Z parse-only
2+
3+
static _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected identifier, found reserved identifier `_`
2+
--> $DIR/underscore_static.rs:3:8
3+
|
4+
LL | static _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
5+
| ^ expected identifier, found reserved identifier
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)