Skip to content

Commit 322632a

Browse files
Rollup merge of rust-lang#51952 - petrochenkov:transmark, r=alexcrichton
hygiene: Decouple transparencies from expansion IDs And remove fallback to parent modules during resolution of names in scope. This is a breaking change for users of unstable macros 2.0 (both procedural and declarative), code like this: ```rust #![feature(decl_macro)] macro m($S: ident) { struct $S; mod m { type A = $S; } } fn main() { m!(S); } ``` or equivalent ```rust #![feature(decl_macro)] macro m($S: ident) { mod m { type A = $S; } } fn main() { struct S; m!(S); } ``` stops working due to module boundaries being properly enforced. For proc macro derives this is still reported as a compatibility warning to give `actix_derive`, `diesel_derives` and `palette_derive` time to fix their issues. Fixes rust-lang#50504 in accordance with [this comment](rust-lang#50504 (comment)).
2 parents d2a8a2b + fc74e35 commit 322632a

File tree

21 files changed

+450
-173
lines changed

21 files changed

+450
-173
lines changed

src/libproc_macro/lib.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ pub mod __internal {
13511351
use syntax::parse::token::{self, Token};
13521352
use syntax::tokenstream;
13531353
use syntax_pos::{BytePos, Loc, DUMMY_SP};
1354-
use syntax_pos::hygiene::{Mark, SyntaxContext, Transparency};
1354+
use syntax_pos::hygiene::{SyntaxContext, Transparency};
13551355

13561356
use super::{TokenStream, LexError, Span};
13571357

@@ -1436,20 +1436,15 @@ pub mod __internal {
14361436

14371437
// No way to determine def location for a proc macro right now, so use call location.
14381438
let location = cx.current_expansion.mark.expn_info().unwrap().call_site;
1439-
// Opaque mark was already created by expansion, now create its transparent twin.
1440-
// We can't use the call-site span literally here, even if it appears to provide
1441-
// correct name resolution, because it has all the `ExpnInfo` wrong, so the edition
1442-
// checks, lint macro checks, macro backtraces will all break.
1443-
let opaque_mark = cx.current_expansion.mark;
1444-
let transparent_mark = Mark::fresh_cloned(opaque_mark);
1445-
transparent_mark.set_transparency(Transparency::Transparent);
1446-
1447-
let to_span = |mark| Span(location.with_ctxt(SyntaxContext::empty().apply_mark(mark)));
1439+
let to_span = |transparency| Span(location.with_ctxt(
1440+
SyntaxContext::empty().apply_mark_with_transparency(cx.current_expansion.mark,
1441+
transparency))
1442+
);
14481443
p.set(ProcMacroSess {
14491444
parse_sess: cx.parse_sess,
14501445
data: ProcMacroData {
1451-
def_site: to_span(opaque_mark),
1452-
call_site: to_span(transparent_mark),
1446+
def_site: to_span(Transparency::Opaque),
1447+
call_site: to_span(Transparency::Transparent),
14531448
},
14541449
});
14551450
f()

src/librustc/hir/def.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,16 @@ pub enum Namespace {
129129
MacroNS,
130130
}
131131

132+
impl Namespace {
133+
pub fn descr(self) -> &'static str {
134+
match self {
135+
TypeNS => "type",
136+
ValueNS => "value",
137+
MacroNS => "macro",
138+
}
139+
}
140+
}
141+
132142
/// Just a helper ‒ separate structure for each namespace.
133143
#[derive(Copy, Clone, Default, Debug)]
134144
pub struct PerNS<T> {

src/librustc/hir/map/definitions.rs

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ impl Decodable for DefPathTable {
153153
/// The definition table containing node definitions.
154154
/// It holds the DefPathTable for local DefIds/DefPaths and it also stores a
155155
/// mapping from NodeIds to local DefIds.
156+
#[derive(Clone)]
156157
pub struct Definitions {
157158
table: DefPathTable,
158159
node_to_def_index: NodeMap<DefIndex>,
@@ -161,34 +162,12 @@ pub struct Definitions {
161162
/// If `Mark` is an ID of some macro expansion,
162163
/// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
163164
parent_modules_of_macro_defs: FxHashMap<Mark, DefId>,
164-
/// Item with a given `DefIndex` was defined during opaque macro expansion with ID `Mark`.
165-
/// It can actually be defined during transparent macro expansions inside that opaque expansion,
166-
/// but transparent expansions are ignored here.
167-
opaque_expansions_that_defined: FxHashMap<DefIndex, Mark>,
165+
/// Item with a given `DefIndex` was defined during macro expansion with ID `Mark`.
166+
expansions_that_defined: FxHashMap<DefIndex, Mark>,
168167
next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
169168
def_index_to_span: FxHashMap<DefIndex, Span>,
170169
}
171170

172-
// Unfortunately we have to provide a manual impl of Clone because of the
173-
// fixed-sized array field.
174-
impl Clone for Definitions {
175-
fn clone(&self) -> Self {
176-
Definitions {
177-
table: self.table.clone(),
178-
node_to_def_index: self.node_to_def_index.clone(),
179-
def_index_to_node: [
180-
self.def_index_to_node[0].clone(),
181-
self.def_index_to_node[1].clone(),
182-
],
183-
node_to_hir_id: self.node_to_hir_id.clone(),
184-
parent_modules_of_macro_defs: self.parent_modules_of_macro_defs.clone(),
185-
opaque_expansions_that_defined: self.opaque_expansions_that_defined.clone(),
186-
next_disambiguator: self.next_disambiguator.clone(),
187-
def_index_to_span: self.def_index_to_span.clone(),
188-
}
189-
}
190-
}
191-
192171
/// A unique identifier that we can use to lookup a definition
193172
/// precisely. It combines the index of the definition's parent (if
194173
/// any) with a `DisambiguatedDefPathData`.
@@ -409,7 +388,7 @@ impl Definitions {
409388
def_index_to_node: [vec![], vec![]],
410389
node_to_hir_id: IndexVec::new(),
411390
parent_modules_of_macro_defs: FxHashMap(),
412-
opaque_expansions_that_defined: FxHashMap(),
391+
expansions_that_defined: FxHashMap(),
413392
next_disambiguator: FxHashMap(),
414393
def_index_to_span: FxHashMap(),
415394
}
@@ -584,9 +563,8 @@ impl Definitions {
584563
self.node_to_def_index.insert(node_id, index);
585564
}
586565

587-
let expansion = expansion.modern();
588566
if expansion != Mark::root() {
589-
self.opaque_expansions_that_defined.insert(index, expansion);
567+
self.expansions_that_defined.insert(index, expansion);
590568
}
591569

592570
// The span is added if it isn't dummy
@@ -606,8 +584,8 @@ impl Definitions {
606584
self.node_to_hir_id = mapping;
607585
}
608586

609-
pub fn opaque_expansion_that_defined(&self, index: DefIndex) -> Mark {
610-
self.opaque_expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root())
587+
pub fn expansion_that_defined(&self, index: DefIndex) -> Mark {
588+
self.expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root())
611589
}
612590

613591
pub fn parent_module_of_macro_def(&self, mark: Mark) -> DefId {

src/librustc/lint/builtin.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ declare_lint! {
316316
"checks the object safety of where clauses"
317317
}
318318

319+
declare_lint! {
320+
pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
321+
Warn,
322+
"detects proc macro derives using inaccessible names from parent modules"
323+
}
324+
319325
/// Does nothing as a lint pass, but registers some `Lint`s
320326
/// which are used by other parts of the compiler.
321327
#[derive(Copy, Clone)]
@@ -372,6 +378,7 @@ impl LintPass for HardwiredLints {
372378
DUPLICATE_MACRO_EXPORTS,
373379
INTRA_DOC_LINK_RESOLUTION_FAILURE,
374380
WHERE_CLAUSES_OBJECT_SAFETY,
381+
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
375382
)
376383
}
377384
}
@@ -384,6 +391,7 @@ pub enum BuiltinLintDiagnostics {
384391
BareTraitObject(Span, /* is_global */ bool),
385392
AbsPathWithModule(Span),
386393
DuplicatedMacroExports(ast::Ident, Span, Span),
394+
ProcMacroDeriveResolutionFallback(Span),
387395
}
388396

389397
impl BuiltinLintDiagnostics {
@@ -420,6 +428,10 @@ impl BuiltinLintDiagnostics {
420428
db.span_label(later_span, format!("`{}` already exported", ident));
421429
db.span_note(earlier_span, "previous macro export is now shadowed");
422430
}
431+
BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => {
432+
db.span_label(span, "names from parent modules are not \
433+
accessible without an explicit import");
434+
}
423435
}
424436
}
425437
}

src/librustc/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2724,7 +2724,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
27242724
pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) {
27252725
ident = ident.modern();
27262726
let target_expansion = match scope.krate {
2727-
LOCAL_CRATE => self.hir.definitions().opaque_expansion_that_defined(scope.index),
2727+
LOCAL_CRATE => self.hir.definitions().expansion_that_defined(scope.index),
27282728
_ => Mark::root(),
27292729
};
27302730
let scope = match ident.span.adjust(target_expansion) {

src/librustc_lint/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
293293
reference: "issue #50589 <https://github.com/rust-lang/rust/issues/50589>",
294294
edition: None,
295295
},
296+
FutureIncompatibleInfo {
297+
id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK),
298+
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
299+
edition: None,
300+
},
296301
]);
297302

298303
// Register renamed and removed lints

src/librustc_resolve/lib.rs

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
5555

5656
use syntax::visit::{self, FnKind, Visitor};
5757
use syntax::attr;
58-
use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
58+
use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
5959
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
6060
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
6161
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
@@ -1891,7 +1891,12 @@ impl<'a> Resolver<'a> {
18911891

18921892
ident.span = ident.span.modern();
18931893
loop {
1894-
module = unwrap_or!(self.hygienic_lexical_parent(module, &mut ident.span), break);
1894+
let (opt_module, poisoned) = if record_used {
1895+
self.hygienic_lexical_parent_with_compatibility_fallback(module, &mut ident.span)
1896+
} else {
1897+
(self.hygienic_lexical_parent(module, &mut ident.span), false)
1898+
};
1899+
module = unwrap_or!(opt_module, break);
18951900
let orig_current_module = self.current_module;
18961901
self.current_module = module; // Lexical resolutions can never be a privacy error.
18971902
let result = self.resolve_ident_in_module_unadjusted(
@@ -1900,7 +1905,19 @@ impl<'a> Resolver<'a> {
19001905
self.current_module = orig_current_module;
19011906

19021907
match result {
1903-
Ok(binding) => return Some(LexicalScopeBinding::Item(binding)),
1908+
Ok(binding) => {
1909+
if poisoned {
1910+
self.session.buffer_lint_with_diagnostic(
1911+
lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
1912+
CRATE_NODE_ID, ident.span,
1913+
&format!("cannot find {} `{}` in this scope", ns.descr(), ident),
1914+
lint::builtin::BuiltinLintDiagnostics::
1915+
ProcMacroDeriveResolutionFallback(ident.span),
1916+
);
1917+
}
1918+
return Some(LexicalScopeBinding::Item(binding))
1919+
}
1920+
_ if poisoned => break,
19041921
Err(Undetermined) => return None,
19051922
Err(Determined) => {}
19061923
}
@@ -1935,7 +1952,7 @@ impl<'a> Resolver<'a> {
19351952
None
19361953
}
19371954

1938-
fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span)
1955+
fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span)
19391956
-> Option<Module<'a>> {
19401957
if !module.expansion.is_descendant_of(span.ctxt().outer()) {
19411958
return Some(self.macro_def_scope(span.remove_mark()));
@@ -1945,22 +1962,41 @@ impl<'a> Resolver<'a> {
19451962
return Some(module.parent.unwrap());
19461963
}
19471964

1948-
let mut module_expansion = module.expansion.modern(); // for backward compatibility
1949-
while let Some(parent) = module.parent {
1950-
let parent_expansion = parent.expansion.modern();
1951-
if module_expansion.is_descendant_of(parent_expansion) &&
1952-
parent_expansion != module_expansion {
1953-
return if parent_expansion.is_descendant_of(span.ctxt().outer()) {
1954-
Some(parent)
1955-
} else {
1956-
None
1957-
};
1965+
None
1966+
}
1967+
1968+
fn hygienic_lexical_parent_with_compatibility_fallback(
1969+
&mut self, module: Module<'a>, span: &mut Span) -> (Option<Module<'a>>, /* poisoned */ bool
1970+
) {
1971+
if let module @ Some(..) = self.hygienic_lexical_parent(module, span) {
1972+
return (module, false);
1973+
}
1974+
1975+
// We need to support the next case under a deprecation warning
1976+
// ```
1977+
// struct MyStruct;
1978+
// ---- begin: this comes from a proc macro derive
1979+
// mod implementation_details {
1980+
// // Note that `MyStruct` is not in scope here.
1981+
// impl SomeTrait for MyStruct { ... }
1982+
// }
1983+
// ---- end
1984+
// ```
1985+
// So we have to fall back to the module's parent during lexical resolution in this case.
1986+
if let Some(parent) = module.parent {
1987+
// Inner module is inside the macro, parent module is outside of the macro.
1988+
if module.expansion != parent.expansion &&
1989+
module.expansion.is_descendant_of(parent.expansion) {
1990+
// The macro is a proc macro derive
1991+
if module.expansion.looks_like_proc_macro_derive() {
1992+
if parent.expansion.is_descendant_of(span.ctxt().outer()) {
1993+
return (module.parent, true);
1994+
}
1995+
}
19581996
}
1959-
module = parent;
1960-
module_expansion = parent_expansion;
19611997
}
19621998

1963-
None
1999+
(None, false)
19642000
}
19652001

19662002
fn resolve_ident_in_module(&mut self,
@@ -1996,17 +2032,17 @@ impl<'a> Resolver<'a> {
19962032
let mut iter = ctxt.marks().into_iter().rev().peekable();
19972033
let mut result = None;
19982034
// Find the last modern mark from the end if it exists.
1999-
while let Some(&mark) = iter.peek() {
2000-
if mark.transparency() == Transparency::Opaque {
2035+
while let Some(&(mark, transparency)) = iter.peek() {
2036+
if transparency == Transparency::Opaque {
20012037
result = Some(mark);
20022038
iter.next();
20032039
} else {
20042040
break;
20052041
}
20062042
}
20072043
// Then find the last legacy mark from the end if it exists.
2008-
for mark in iter {
2009-
if mark.transparency() == Transparency::SemiTransparent {
2044+
for (mark, transparency) in iter {
2045+
if transparency == Transparency::SemiTransparent {
20102046
result = Some(mark);
20112047
} else {
20122048
break;
@@ -4037,8 +4073,9 @@ impl<'a> Resolver<'a> {
40374073
let mut search_module = self.current_module;
40384074
loop {
40394075
self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
4040-
search_module =
4041-
unwrap_or!(self.hygienic_lexical_parent(search_module, &mut ident.span), break);
4076+
search_module = unwrap_or!(
4077+
self.hygienic_lexical_parent(search_module, &mut ident.span), break
4078+
);
40424079
}
40434080

40444081
if let Some(prelude) = self.prelude {
@@ -4406,12 +4443,6 @@ impl<'a> Resolver<'a> {
44064443
(TypeNS, _) => "type",
44074444
};
44084445

4409-
let namespace = match ns {
4410-
ValueNS => "value",
4411-
MacroNS => "macro",
4412-
TypeNS => "type",
4413-
};
4414-
44154446
let msg = format!("the name `{}` is defined multiple times", name);
44164447

44174448
let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
@@ -4429,7 +4460,7 @@ impl<'a> Resolver<'a> {
44294460

44304461
err.note(&format!("`{}` must be defined only once in the {} namespace of this {}",
44314462
name,
4432-
namespace,
4463+
ns.descr(),
44334464
container));
44344465

44354466
err.span_label(span, format!("`{}` re{} here", name, new_participle));

src/librustc_resolve/macros.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder;
2424
use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
2525
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
2626
use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, InvocationKind};
27-
use syntax::ext::hygiene::{self, Mark, Transparency};
27+
use syntax::ext::hygiene::{self, Mark};
2828
use syntax::ext::placeholders::placeholder;
2929
use syntax::ext::tt::macro_rules;
3030
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
@@ -331,13 +331,8 @@ impl<'a> base::Resolver for Resolver<'a> {
331331

332332
self.unused_macros.remove(&def_id);
333333
let ext = self.get_macro(def);
334-
if ext.is_modern() {
335-
let transparency =
336-
if ext.is_transparent() { Transparency::Transparent } else { Transparency::Opaque };
337-
invoc.expansion_data.mark.set_transparency(transparency);
338-
} else if def_id.krate == BUILTIN_MACROS_CRATE {
339-
invoc.expansion_data.mark.set_is_builtin(true);
340-
}
334+
invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
335+
invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
341336
Ok(Some(ext))
342337
}
343338

0 commit comments

Comments
 (0)