Skip to content

Commit db493ef

Browse files
authored
Rollup merge of rust-lang#63919 - matthewjasper:remove-gensymmed, r=petrochenkov
Use hygiene for AST passes AST passes are now able to have resolve consider their expansions as if they were opaque macros defined either in some module in the current crate, or a fake empty module with `#[no_implicit_prelude]`. * Add an ExpnKind for AST passes. * Remove gensyms in AST passes. * Remove gensyms in`#[test]`, `#[bench]` and `#[test_case]`. * Allow opaque macros to define tests. * Move tests for unit tests to their own directory. * Remove `Ident::{gensym, is_gensymed}` - `Ident::gensym_if_underscore` still exists. cc rust-lang#60869, rust-lang#61019 r? @petrochenkov
2 parents da13f06 + 3f3fc52 commit db493ef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+555
-439
lines changed

src/librustc/ich/impls_syntax.rs

+8
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,17 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData {
390390
impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind {
391391
Root,
392392
Macro(kind, descr),
393+
AstPass(kind),
393394
Desugaring(kind)
394395
});
395396

397+
impl_stable_hash_for!(enum ::syntax_pos::hygiene::AstPass {
398+
StdImports,
399+
TestHarness,
400+
ProcMacroHarness,
401+
PluginMacroDefs,
402+
});
403+
396404
impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind {
397405
CondTemporary,
398406
Async,

src/librustc/lint/mod.rs

+25-21
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,30 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
646646
(Level::Forbid, None) => sess.struct_err(msg),
647647
};
648648

649+
// Check for future incompatibility lints and issue a stronger warning.
650+
let lints = sess.lint_store.borrow();
651+
let lint_id = LintId::of(lint);
652+
let future_incompatible = lints.future_incompatible(lint_id);
653+
654+
// If this code originates in a foreign macro, aka something that this crate
655+
// did not itself author, then it's likely that there's nothing this crate
656+
// can do about it. We probably want to skip the lint entirely.
657+
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
658+
// Any suggestions made here are likely to be incorrect, so anything we
659+
// emit shouldn't be automatically fixed by rustfix.
660+
err.allow_suggestions(false);
661+
662+
// If this is a future incompatible lint it'll become a hard error, so
663+
// we have to emit *something*. Also allow lints to whitelist themselves
664+
// on a case-by-case basis for emission in a foreign macro.
665+
if future_incompatible.is_none() && !lint.report_in_external_macro {
666+
err.cancel();
667+
// Don't continue further, since we don't want to have
668+
// `diag_span_note_once` called for a diagnostic that isn't emitted.
669+
return err;
670+
}
671+
}
672+
649673
let name = lint.name_lower();
650674
match src {
651675
LintSource::Default => {
@@ -695,10 +719,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
695719

696720
err.code(DiagnosticId::Lint(name));
697721

698-
// Check for future incompatibility lints and issue a stronger warning.
699-
let lints = sess.lint_store.borrow();
700-
let lint_id = LintId::of(lint);
701-
let future_incompatible = lints.future_incompatible(lint_id);
702722
if let Some(future_incompatible) = future_incompatible {
703723
const STANDARD_MESSAGE: &str =
704724
"this was previously accepted by the compiler but is being phased out; \
@@ -723,22 +743,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
723743
err.note(&citation);
724744
}
725745

726-
// If this code originates in a foreign macro, aka something that this crate
727-
// did not itself author, then it's likely that there's nothing this crate
728-
// can do about it. We probably want to skip the lint entirely.
729-
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
730-
// Any suggestions made here are likely to be incorrect, so anything we
731-
// emit shouldn't be automatically fixed by rustfix.
732-
err.allow_suggestions(false);
733-
734-
// If this is a future incompatible lint it'll become a hard error, so
735-
// we have to emit *something*. Also allow lints to whitelist themselves
736-
// on a case-by-case basis for emission in a foreign macro.
737-
if future_incompatible.is_none() && !lint.report_in_external_macro {
738-
err.cancel()
739-
}
740-
}
741-
742746
return err
743747
}
744748

@@ -868,7 +872,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
868872
let expn_data = span.ctxt().outer_expn_data();
869873
match expn_data.kind {
870874
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
871-
ExpnKind::Desugaring(_) => true, // well, it's "external"
875+
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
872876
ExpnKind::Macro(MacroKind::Bang, _) => {
873877
if expn_data.def_site.is_dummy() {
874878
// dummy span for the def_site means it's an external macro

src/librustc_interface/passes.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ pub fn register_plugins<'a>(
233233
syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr)
234234
});
235235

236-
let (mut krate, features) = syntax::config::features(
236+
let (krate, features) = syntax::config::features(
237237
krate,
238238
&sess.parse_sess,
239239
sess.edition(),
@@ -268,16 +268,6 @@ pub fn register_plugins<'a>(
268268
middle::recursion_limit::update_limits(sess, &krate);
269269
});
270270

271-
krate = time(sess, "crate injection", || {
272-
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s);
273-
let (krate, name) =
274-
syntax_ext::standard_library_imports::inject(krate, alt_std_name, sess.edition());
275-
if let Some(name) = name {
276-
sess.parse_sess.injected_crate_name.set(name);
277-
}
278-
krate
279-
});
280-
281271
let registrars = time(sess, "plugin loading", || {
282272
plugin::load::load_plugins(
283273
sess,
@@ -370,6 +360,21 @@ fn configure_and_expand_inner<'a>(
370360
&resolver_arenas,
371361
);
372362
syntax_ext::register_builtin_macros(&mut resolver, sess.edition());
363+
364+
krate = time(sess, "crate injection", || {
365+
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
366+
let (krate, name) = syntax_ext::standard_library_imports::inject(
367+
krate,
368+
&mut resolver,
369+
&sess.parse_sess,
370+
alt_std_name,
371+
);
372+
if let Some(name) = name {
373+
sess.parse_sess.injected_crate_name.set(name);
374+
}
375+
krate
376+
});
377+
373378
syntax_ext::plugin_macro_defs::inject(
374379
&mut krate, &mut resolver, plugin_info.syntax_exts, sess.edition()
375380
);

src/librustc_resolve/build_reduced_graph.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ impl<'a> Resolver<'a> {
126126
crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
127127
let def_id = match self.macro_defs.get(&expn_id) {
128128
Some(def_id) => *def_id,
129-
None => return self.graph_root,
129+
None => return self.ast_transform_scopes.get(&expn_id)
130+
.unwrap_or(&self.graph_root),
130131
};
131132
if let Some(id) = self.definitions.as_local_node_id(def_id) {
132133
self.local_macro_def_scopes[&id]

src/librustc_resolve/diagnostics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,14 @@ impl<'a> Resolver<'a> {
604604
if lookup_ident.span.rust_2018() {
605605
let extern_prelude_names = self.extern_prelude.clone();
606606
for (ident, _) in extern_prelude_names.into_iter() {
607+
if ident.span.from_expansion() {
608+
// Idents are adjusted to the root context before being
609+
// resolved in the extern prelude, so reporting this to the
610+
// user is no help. This skips the injected
611+
// `extern crate std` in the 2018 edition, which would
612+
// otherwise cause duplicate suggestions.
613+
continue;
614+
}
607615
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
608616
ident.span) {
609617
let crate_root = self.get_module(DefId {

src/librustc_resolve/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,10 @@ pub struct Resolver<'a> {
880880
/// There will be an anonymous module created around `g` with the ID of the
881881
/// entry block for `f`.
882882
block_map: NodeMap<Module<'a>>,
883+
/// A fake module that contains no definition and no prelude. Used so that
884+
/// some AST passes can generate identifiers that only resolve to local or
885+
/// language items.
886+
empty_module: Module<'a>,
883887
module_map: FxHashMap<DefId, Module<'a>>,
884888
extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
885889
binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
@@ -914,6 +918,7 @@ pub struct Resolver<'a> {
914918
non_macro_attrs: [Lrc<SyntaxExtension>; 2],
915919
macro_defs: FxHashMap<ExpnId, DefId>,
916920
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
921+
ast_transform_scopes: FxHashMap<ExpnId, Module<'a>>,
917922
unused_macros: NodeMap<Span>,
918923
proc_macro_stubs: NodeSet,
919924
/// Traces collected during macro resolution and validated when it's complete.
@@ -1081,6 +1086,21 @@ impl<'a> Resolver<'a> {
10811086
no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
10821087
..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
10831088
});
1089+
let empty_module_kind = ModuleKind::Def(
1090+
DefKind::Mod,
1091+
root_def_id,
1092+
kw::Invalid,
1093+
);
1094+
let empty_module = arenas.alloc_module(ModuleData {
1095+
no_implicit_prelude: true,
1096+
..ModuleData::new(
1097+
Some(graph_root),
1098+
empty_module_kind,
1099+
root_def_id,
1100+
ExpnId::root(),
1101+
DUMMY_SP,
1102+
)
1103+
});
10841104
let mut module_map = FxHashMap::default();
10851105
module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
10861106

@@ -1140,10 +1160,12 @@ impl<'a> Resolver<'a> {
11401160
label_res_map: Default::default(),
11411161
export_map: FxHashMap::default(),
11421162
trait_map: Default::default(),
1163+
empty_module,
11431164
module_map,
11441165
block_map: Default::default(),
11451166
extern_module_map: FxHashMap::default(),
11461167
binding_parent_modules: FxHashMap::default(),
1168+
ast_transform_scopes: FxHashMap::default(),
11471169

11481170
glob_map: Default::default(),
11491171

src/librustc_resolve/macros.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
88
use crate::Namespace::*;
99
use crate::resolve_imports::ImportResolver;
1010
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
11+
use rustc::hir::def_id;
1112
use rustc::middle::stability;
1213
use rustc::{ty, lint, span_bug};
1314
use syntax::ast::{self, NodeId, Ident};
@@ -25,6 +26,7 @@ use syntax_pos::{Span, DUMMY_SP};
2526

2627
use std::{mem, ptr};
2728
use rustc_data_structures::sync::Lrc;
29+
use syntax_pos::hygiene::AstPass;
2830

2931
type Res = def::Res<NodeId>;
3032

@@ -95,16 +97,6 @@ impl<'a> base::Resolver for Resolver<'a> {
9597
self.session.next_node_id()
9698
}
9799

98-
fn get_module_scope(&mut self, id: NodeId) -> ExpnId {
99-
let expn_id = ExpnId::fresh(Some(ExpnData::default(
100-
ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
101-
)));
102-
let module = self.module_map[&self.definitions.local_def_id(id)];
103-
self.invocation_parent_scopes.insert(expn_id, ParentScope::module(module));
104-
self.definitions.set_invocation_parent(expn_id, module.def_id().unwrap().index);
105-
expn_id
106-
}
107-
108100
fn resolve_dollar_crates(&mut self) {
109101
hygiene::update_dollar_crate_names(|ctxt| {
110102
let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
@@ -136,6 +128,37 @@ impl<'a> base::Resolver for Resolver<'a> {
136128
}
137129
}
138130

131+
// Create a new Expansion with a definition site of the provided module, or
132+
// a fake empty `#[no_implicit_prelude]` module if no module is provided.
133+
fn expansion_for_ast_pass(
134+
&mut self,
135+
call_site: Span,
136+
pass: AstPass,
137+
features: &[Symbol],
138+
parent_module_id: Option<NodeId>,
139+
) -> ExpnId {
140+
let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable(
141+
ExpnKind::AstPass(pass),
142+
call_site,
143+
self.session.edition(),
144+
features.into(),
145+
)));
146+
147+
let parent_scope = if let Some(module_id) = parent_module_id {
148+
let parent_def_id = self.definitions.local_def_id(module_id);
149+
self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id);
150+
self.module_map[&parent_def_id]
151+
} else {
152+
self.definitions.add_parent_module_of_macro_def(
153+
expn_id,
154+
def_id::DefId::local(def_id::CRATE_DEF_INDEX),
155+
);
156+
self.empty_module
157+
};
158+
self.ast_transform_scopes.insert(expn_id, parent_scope);
159+
expn_id
160+
}
161+
139162
fn resolve_imports(&mut self) {
140163
ImportResolver { r: self }.resolve_imports()
141164
}

src/librustc_resolve/resolve_imports.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1307,12 +1307,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
13071307
None => continue,
13081308
};
13091309

1310-
// Filter away ambiguous and gensymed imports. Gensymed imports
1311-
// (e.g. implicitly injected `std`) cannot be properly encoded in metadata,
1312-
// so they can cause name conflict errors downstream.
1313-
let is_good_import = binding.is_import() && !binding.is_ambiguity() &&
1314-
// Note that as_str() de-gensyms the Symbol
1315-
!(ident.is_gensymed() && ident.name.as_str() != "_");
1310+
// Filter away ambiguous imports and anything that has def-site
1311+
// hygiene.
1312+
// FIXME: Implement actual cross-crate hygiene.
1313+
let is_good_import = binding.is_import() && !binding.is_ambiguity()
1314+
&& !ident.span.modern().from_expansion();
13161315
if is_good_import || binding.is_macro_def() {
13171316
let res = binding.res();
13181317
if res != Res::Err {

src/libsyntax/ext/base.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::attr::{self, HasAttrs, Stability, Deprecation};
33
use crate::source_map::SourceMap;
44
use crate::edition::Edition;
55
use crate::ext::expand::{self, AstFragment, Invocation};
6-
use crate::ext::hygiene::{ExpnId, Transparency};
6+
use crate::ext::hygiene::ExpnId;
77
use crate::mut_visit::{self, MutVisitor};
88
use crate::parse::{self, parser, ParseSess, DirectoryOwnership};
99
use crate::parse::token;
@@ -16,7 +16,7 @@ use crate::visit::Visitor;
1616
use errors::{DiagnosticBuilder, DiagnosticId};
1717
use smallvec::{smallvec, SmallVec};
1818
use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP};
19-
use syntax_pos::hygiene::{ExpnData, ExpnKind};
19+
use syntax_pos::hygiene::{AstPass, ExpnData, ExpnKind};
2020

2121
use rustc_data_structures::fx::FxHashMap;
2222
use rustc_data_structures::sync::{self, Lrc};
@@ -732,13 +732,19 @@ bitflags::bitflags! {
732732
pub trait Resolver {
733733
fn next_node_id(&mut self) -> NodeId;
734734

735-
fn get_module_scope(&mut self, id: NodeId) -> ExpnId;
736-
737735
fn resolve_dollar_crates(&mut self);
738736
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
739737
extra_placeholders: &[NodeId]);
740738
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
741739

740+
fn expansion_for_ast_pass(
741+
&mut self,
742+
call_site: Span,
743+
pass: AstPass,
744+
features: &[Symbol],
745+
parent_module_id: Option<NodeId>,
746+
) -> ExpnId;
747+
742748
fn resolve_imports(&mut self);
743749

744750
fn resolve_macro_invocation(
@@ -822,20 +828,20 @@ impl<'a> ExtCtxt<'a> {
822828
/// Equivalent of `Span::def_site` from the proc macro API,
823829
/// except that the location is taken from the span passed as an argument.
824830
pub fn with_def_site_ctxt(&self, span: Span) -> Span {
825-
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Opaque)
831+
span.with_def_site_ctxt(self.current_expansion.id)
826832
}
827833

828834
/// Equivalent of `Span::call_site` from the proc macro API,
829835
/// except that the location is taken from the span passed as an argument.
830836
pub fn with_call_site_ctxt(&self, span: Span) -> Span {
831-
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Transparent)
837+
span.with_call_site_ctxt(self.current_expansion.id)
832838
}
833839

834840
/// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
835841
/// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
836842
/// or with `with_call_site_ctxt` (where necessary).
837843
pub fn with_legacy_ctxt(&self, span: Span) -> Span {
838-
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::SemiTransparent)
844+
span.with_legacy_ctxt(self.current_expansion.id)
839845
}
840846

841847
/// Returns span for the macro which originally caused the current expansion to happen.

src/libsyntax/print/pprust.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,14 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
128128
let fake_attr = attr::mk_attr_inner(list);
129129
s.print_attribute(&fake_attr);
130130

131-
// #![no_std]
132-
let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std));
133-
let fake_attr = attr::mk_attr_inner(no_std_meta);
134-
s.print_attribute(&fake_attr);
131+
// Currently on Rust 2018 we don't have `extern crate std;` at the crate
132+
// root, so this is not needed, and actually breaks things.
133+
if sess.edition == syntax_pos::edition::Edition::Edition2015 {
134+
// #![no_std]
135+
let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std));
136+
let fake_attr = attr::mk_attr_inner(no_std_meta);
137+
s.print_attribute(&fake_attr);
138+
}
135139
}
136140

137141
s.print_mod(&krate.module, &krate.attrs);

0 commit comments

Comments
 (0)