Skip to content

Commit

Permalink
Fix hygiene bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
jseyfried committed Nov 29, 2017
1 parent 560a5da commit dfa6c25
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/libproc_macro/lib.rs
Expand Up @@ -95,7 +95,7 @@ impl FromStr for TokenStream {
// notify the expansion info that it is unhygienic
let mark = Mark::fresh(mark);
mark.set_expn_info(expn_info);
let span = call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark));
let span = call_site.with_ctxt(call_site.ctxt().apply_mark(mark));
let stream = parse::parse_stream_from_source_str(name, src, sess, Some(span));
Ok(__internal::token_stream_wrap(stream))
})
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/hir/map/definitions.rs
Expand Up @@ -575,7 +575,8 @@ impl Definitions {
self.node_to_def_index.insert(node_id, index);
}

if expansion.is_modern() {
let expansion = expansion.modern();
if expansion != Mark::root() {
self.expansions.insert(index, expansion);
}

Expand Down
13 changes: 11 additions & 2 deletions src/librustc_resolve/lib.rs
Expand Up @@ -1560,6 +1560,15 @@ impl<'a> Resolver<'a> {
}
}

fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
loop {
match self.macro_defs.get(&ctxt.outer()) {
Some(&def_id) => return def_id,
None => ctxt.remove_mark(),
};
}
}

/// Entry point to crate resolution.
pub fn resolve_crate(&mut self, krate: &Crate) {
ImportResolver { resolver: self }.finalize_imports();
Expand Down Expand Up @@ -1663,7 +1672,7 @@ impl<'a> Resolver<'a> {

module = match self.ribs[ns][i].kind {
ModuleRibKind(module) => module,
MacroDefinition(def) if def == self.macro_defs[&ident.ctxt.outer()] => {
MacroDefinition(def) if def == self.macro_def(ident.ctxt) => {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
ident.ctxt.remove_mark();
Expand Down Expand Up @@ -1830,7 +1839,7 @@ impl<'a> Resolver<'a> {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
MacroDefinition(def) => {
if def == self.macro_defs[&ident.ctxt.outer()] {
if def == self.macro_def(ident.ctxt) {
ident.ctxt.remove_mark();
}
}
Expand Down
13 changes: 10 additions & 3 deletions src/libsyntax/parse/lexer/mod.rs
Expand Up @@ -73,6 +73,13 @@ impl<'a> StringReader<'a> {
fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
unwrap_or!(self.override_span, Span::new(lo, hi, NO_EXPANSION))
}
fn mk_ident(&self, string: &str) -> Ident {
let mut ident = Ident::from_str(string);
if let Some(span) = self.override_span {
ident.ctxt = span.ctxt();
}
ident
}

fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
let res = self.try_next_token();
Expand Down Expand Up @@ -1103,7 +1110,7 @@ impl<'a> StringReader<'a> {
token::Underscore
} else {
// FIXME: perform NFKC normalization here. (Issue #2253)
token::Ident(Ident::from_str(string))
token::Ident(self.mk_ident(string))
}
}));
}
Expand Down Expand Up @@ -1286,13 +1293,13 @@ impl<'a> StringReader<'a> {
// expansion purposes. See #12512 for the gory details of why
// this is necessary.
let ident = self.with_str_from(start, |lifetime_name| {
Ident::from_str(&format!("'{}", lifetime_name))
self.mk_ident(&format!("'{}", lifetime_name))
});

// Conjure up a "keyword checking ident" to make sure that
// the lifetime name is not a keyword.
let keyword_checking_ident = self.with_str_from(start, |lifetime_name| {
Ident::from_str(lifetime_name)
self.mk_ident(lifetime_name)
});
let keyword_checking_token = &token::Ident(keyword_checking_ident);
let last_bpos = self.pos;
Expand Down
Expand Up @@ -23,5 +23,5 @@ fn main() {
bang_proc_macro2!();
//~^ ERROR cannot find value `foobar2` in this scope
//~^^ did you mean `foobar`?
println!("{}", x);
println!("{}", x); //~ ERROR cannot find value `x` in this scope
}
28 changes: 28 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-42708.rs
@@ -0,0 +1,28 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// no-prefer-dynamic

#![crate_type = "proc-macro"]
#![feature(proc_macro)]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Test)]
pub fn derive(_input: TokenStream) -> TokenStream {
"fn f(s: S) { s.x }".parse().unwrap()
}

#[proc_macro_attribute]
pub fn attr_test(_attr: TokenStream, input: TokenStream) -> TokenStream {
input
}
36 changes: 36 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/issue-42708.rs
@@ -0,0 +1,36 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:issue-42708.rs
// ignore-stage1

#![feature(decl_macro, proc_macro)]
#![allow(unused)]

extern crate issue_42708;

macro m() {
#[derive(issue_42708::Test)]
struct S { x: () }

#[issue_42708::attr_test]
struct S2 { x: () }

#[derive(Clone)]
struct S3 { x: () }

fn g(s: S, s2: S2, s3: S3) {
(s.x, s2.x, s3.x);
}
}

m!();

fn main() {}

0 comments on commit dfa6c25

Please sign in to comment.