Skip to content

Commit 9ddb9a7

Browse files
committed
librustc: Fix the issue with labels shadowing variable names by making
the leading quote part of the identifier for the purposes of hygiene. This adopts @jbclements' solution to #14539. I'm not sure if this is a breaking change or not. Closes #12512. [breaking-change]
1 parent 021bea1 commit 9ddb9a7

17 files changed

+159
-89
lines changed

src/librustc/middle/resolve_lifetime.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
151151
fn visit_lifetime_ref(&mut self,
152152
lifetime_ref: &ast::Lifetime,
153153
scope: Scope<'a>) {
154-
if lifetime_ref.name == special_idents::statik.name {
154+
if lifetime_ref.name == special_idents::static_lifetime.name {
155155
self.insert_lifetime(lifetime_ref, ast::DefStaticRegion);
156156
return;
157157
}
@@ -340,15 +340,15 @@ impl<'a> LifetimeContext<'a> {
340340
lifetime_ref: &ast::Lifetime) {
341341
self.sess.span_err(
342342
lifetime_ref.span,
343-
format!("use of undeclared lifetime name `'{}`",
343+
format!("use of undeclared lifetime name `{}`",
344344
token::get_name(lifetime_ref.name)).as_slice());
345345
}
346346

347347
fn check_lifetime_names(&self, lifetimes: &Vec<ast::Lifetime>) {
348348
for i in range(0, lifetimes.len()) {
349349
let lifetime_i = lifetimes.get(i);
350350

351-
let special_idents = [special_idents::statik];
351+
let special_idents = [special_idents::static_lifetime];
352352
for lifetime in lifetimes.iter() {
353353
if special_idents.iter().any(|&i| i.name == lifetime.name) {
354354
self.sess.span_err(
@@ -364,7 +364,7 @@ impl<'a> LifetimeContext<'a> {
364364
if lifetime_i.name == lifetime_j.name {
365365
self.sess.span_err(
366366
lifetime_j.span,
367-
format!("lifetime name `'{}` declared twice in \
367+
format!("lifetime name `{}` declared twice in \
368368
the same scope",
369369
token::get_name(lifetime_j.name)).as_slice());
370370
}

src/librustc/middle/typeck/infer/error_reporting.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,8 @@ impl LifeGiver {
15031503
fn give_lifetime(&self) -> ast::Lifetime {
15041504
let mut lifetime;
15051505
loop {
1506-
let s = num_to_str(self.counter.get());
1506+
let mut s = String::from_str("'");
1507+
s.push_str(num_to_str(self.counter.get()).as_slice());
15071508
if !self.taken.contains(&s) {
15081509
lifetime = name_to_dummy_lifetime(
15091510
token::str_to_ident(s.as_slice()).name);

src/librustc/util/ppaux.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub fn bound_region_to_str(cx: &ctxt,
156156

157157
match br {
158158
BrNamed(_, name) => {
159-
format!("{}'{}{}", prefix, token::get_name(name), space_str)
159+
format!("{}{}{}", prefix, token::get_name(name), space_str)
160160
}
161161
BrAnon(_) => prefix.to_string(),
162162
BrFresh(_) => prefix.to_string(),

src/libsyntax/ext/build.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub trait AstBuilder {
8585
typ: P<ast::Ty>,
8686
ex: Gc<ast::Expr>)
8787
-> Gc<ast::Stmt>;
88+
fn stmt_item(&self, sp: Span, item: Gc<ast::Item>) -> Gc<ast::Stmt>;
8889

8990
// blocks
9091
fn block(&self, span: Span, stmts: Vec<Gc<ast::Stmt>>,
@@ -239,6 +240,14 @@ pub trait AstBuilder {
239240
vi: Vec<ast::ViewItem>,
240241
items: Vec<Gc<ast::Item>>) -> Gc<ast::Item>;
241242

243+
fn item_static(&self,
244+
span: Span,
245+
name: Ident,
246+
ty: P<ast::Ty>,
247+
mutbl: ast::Mutability,
248+
expr: Gc<ast::Expr>)
249+
-> Gc<ast::Item>;
250+
242251
fn item_ty_poly(&self,
243252
span: Span,
244253
name: Ident,
@@ -484,11 +493,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
484493
box(GC) respan(sp, ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID))
485494
}
486495

487-
fn block(&self, span: Span, stmts: Vec<Gc<ast::Stmt>>,
488-
expr: Option<Gc<Expr>>) -> P<ast::Block> {
496+
fn block(&self,
497+
span: Span,
498+
stmts: Vec<Gc<ast::Stmt>>,
499+
expr: Option<Gc<Expr>>)
500+
-> P<ast::Block> {
489501
self.block_all(span, Vec::new(), stmts, expr)
490502
}
491503

504+
fn stmt_item(&self, sp: Span, item: Gc<ast::Item>) -> Gc<ast::Stmt> {
505+
let decl = respan(sp, ast::DeclItem(item));
506+
box(GC) respan(sp, ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID))
507+
}
508+
492509
fn block_expr(&self, expr: Gc<ast::Expr>) -> P<ast::Block> {
493510
self.block_all(expr.span, Vec::new(), Vec::new(), Some(expr))
494511
}
@@ -942,6 +959,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
942959
)
943960
}
944961

962+
fn item_static(&self,
963+
span: Span,
964+
name: Ident,
965+
ty: P<ast::Ty>,
966+
mutbl: ast::Mutability,
967+
expr: Gc<ast::Expr>)
968+
-> Gc<ast::Item> {
969+
self.item(span, name, Vec::new(), ast::ItemStatic(ty, mutbl, expr))
970+
}
971+
945972
fn item_ty_poly(&self, span: Span, name: Ident, ty: P<ast::Ty>,
946973
generics: Generics) -> Gc<ast::Item> {
947974
self.item(span, name, Vec::new(), ast::ItemTy(ty, generics))

src/libsyntax/ext/bytes.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
9494
}
9595

9696
let e = cx.expr_vec_slice(sp, bytes);
97-
let e = quote_expr!(cx, { static BYTES: &'static [u8] = $e; BYTES});
97+
let ty = cx.ty(sp, ast::TyVec(cx.ty_ident(sp, cx.ident_of("u8"))));
98+
let lifetime = cx.lifetime(sp, cx.ident_of("'static").name);
99+
let item = cx.item_static(sp,
100+
cx.ident_of("BYTES"),
101+
cx.ty_rptr(sp,
102+
ty,
103+
Some(lifetime),
104+
ast::MutImmutable),
105+
ast::MutImmutable,
106+
e);
107+
let e = cx.expr_block(cx.block(sp,
108+
vec!(cx.stmt_item(sp, item)),
109+
Some(cx.expr_ident(sp, cx.ident_of("BYTES")))));
98110
MacExpr::new(e)
99111
}

src/libsyntax/ext/env.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
4343
cx.ident_of("str")),
4444
Some(cx.lifetime(sp,
4545
cx.ident_of(
46-
"static").name)),
46+
"'static").name)),
4747
ast::MutImmutable))))
4848
}
4949
Some(s) => {

src/libsyntax/ext/format.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ impl<'a, 'b> Context<'a, 'b> {
511511
self.ecx.expr_vec_slice(sp, default)))
512512
}
513513
};
514-
let life = self.ecx.lifetime(sp, self.ecx.ident_of("static").name);
514+
let life = self.ecx.lifetime(sp, self.ecx.ident_of("'static").name);
515515
let ty = self.ecx.ty_path(self.ecx.path_all(
516516
sp,
517517
true,
@@ -641,7 +641,7 @@ impl<'a, 'b> Context<'a, 'b> {
641641
self.ecx.ident_of("rt"),
642642
self.ecx.ident_of("Piece")),
643643
vec!(self.ecx.lifetime(self.fmtsp,
644-
self.ecx.ident_of("static").name)),
644+
self.ecx.ident_of("'static").name)),
645645
Vec::new()
646646
), None);
647647
let ty = ast::TyFixedLengthVec(

src/libsyntax/parse/lexer/mod.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -757,19 +757,34 @@ impl<'a> StringReader<'a> {
757757
while ident_continue(self.curr) {
758758
self.bump();
759759
}
760+
761+
// Include the leading `'` in the real identifier, for macro
762+
// expansion purposes. See #12512 for the gory details of why
763+
// this is necessary.
760764
let ident = self.with_str_from(start, |lifetime_name| {
761-
str_to_ident(lifetime_name)
765+
str_to_ident(format!("'{}", lifetime_name).as_slice())
762766
});
763-
let tok = &token::IDENT(ident, false);
764-
765-
if token::is_keyword(token::keywords::Self, tok) {
766-
self.err_span(start, self.last_pos,
767-
"invalid lifetime name: 'self \
768-
is no longer a special lifetime");
769-
} else if token::is_any_keyword(tok) &&
770-
!token::is_keyword(token::keywords::Static, tok) {
771-
self.err_span(start, self.last_pos,
772-
"invalid lifetime name");
767+
768+
// Conjure up a "keyword checking ident" to make sure that
769+
// the lifetime name is not a keyword.
770+
let keyword_checking_ident =
771+
self.with_str_from(start, |lifetime_name| {
772+
str_to_ident(lifetime_name)
773+
});
774+
let keyword_checking_token =
775+
&token::IDENT(keyword_checking_ident, false);
776+
if token::is_keyword(token::keywords::Self,
777+
keyword_checking_token) {
778+
self.err_span(start,
779+
self.last_pos,
780+
"invalid lifetime name: 'self \
781+
is no longer a special lifetime");
782+
} else if token::is_any_keyword(keyword_checking_token) &&
783+
!token::is_keyword(token::keywords::Static,
784+
keyword_checking_token) {
785+
self.err_span(start,
786+
self.last_pos,
787+
"invalid lifetime name");
773788
}
774789
return token::LIFETIME(ident);
775790
}
@@ -1128,7 +1143,7 @@ mod test {
11281143

11291144
#[test] fn lifetime_name() {
11301145
assert_eq!(setup(&mk_sh(), "'abc".to_string()).next_token().tok,
1131-
token::LIFETIME(token::str_to_ident("abc")));
1146+
token::LIFETIME(token::str_to_ident("'abc")));
11321147
}
11331148

11341149
#[test] fn raw_string() {

src/libsyntax/parse/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3430,7 +3430,7 @@ impl<'a> Parser<'a> {
34303430
match self.token {
34313431
token::LIFETIME(lifetime) => {
34323432
let lifetime_interned_string = token::get_ident(lifetime);
3433-
if lifetime_interned_string.equiv(&("static")) {
3433+
if lifetime_interned_string.equiv(&("'static")) {
34343434
result.push(StaticRegionTyParamBound);
34353435
if allow_any_lifetime && ret_lifetime.is_none() {
34363436
ret_lifetime = Some(ast::Lifetime {

src/libsyntax/parse/token.rs

+52-51
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ pub fn to_str(t: &Token) -> String {
232232
/* Name components */
233233
IDENT(s, _) => get_ident(s).get().to_string(),
234234
LIFETIME(s) => {
235-
(format!("'{}", get_ident(s))).to_string()
235+
(format!("{}", get_ident(s))).to_string()
236236
}
237237
UNDERSCORE => "_".to_string(),
238238

@@ -433,71 +433,72 @@ declare_special_idents_and_keywords! {
433433
(0, invalid, "");
434434
(super::SELF_KEYWORD_NAME, self_, "self");
435435
(super::STATIC_KEYWORD_NAME, statik, "static");
436+
(3, static_lifetime, "'static");
436437

437438
// for matcher NTs
438-
(3, tt, "tt");
439-
(4, matchers, "matchers");
439+
(4, tt, "tt");
440+
(5, matchers, "matchers");
440441

441442
// outside of libsyntax
442-
(5, clownshoe_abi, "__rust_abi");
443-
(6, opaque, "<opaque>");
444-
(7, unnamed_field, "<unnamed_field>");
445-
(8, type_self, "Self");
443+
(6, clownshoe_abi, "__rust_abi");
444+
(7, opaque, "<opaque>");
445+
(8, unnamed_field, "<unnamed_field>");
446+
(9, type_self, "Self");
446447
}
447448

448449
pub mod keywords {
449450
// These ones are variants of the Keyword enum
450451

451452
'strict:
452-
(9, As, "as");
453-
(10, Break, "break");
454-
(11, Crate, "crate");
455-
(12, Else, "else");
456-
(13, Enum, "enum");
457-
(14, Extern, "extern");
458-
(15, False, "false");
459-
(16, Fn, "fn");
460-
(17, For, "for");
461-
(18, If, "if");
462-
(19, Impl, "impl");
463-
(20, In, "in");
464-
(21, Let, "let");
465-
(22, Loop, "loop");
466-
(23, Match, "match");
467-
(24, Mod, "mod");
468-
(25, Mut, "mut");
469-
(26, Once, "once");
470-
(27, Pub, "pub");
471-
(28, Ref, "ref");
472-
(29, Return, "return");
453+
(10, As, "as");
454+
(11, Break, "break");
455+
(12, Crate, "crate");
456+
(13, Else, "else");
457+
(14, Enum, "enum");
458+
(15, Extern, "extern");
459+
(16, False, "false");
460+
(17, Fn, "fn");
461+
(18, For, "for");
462+
(19, If, "if");
463+
(20, Impl, "impl");
464+
(21, In, "in");
465+
(22, Let, "let");
466+
(23, Loop, "loop");
467+
(24, Match, "match");
468+
(25, Mod, "mod");
469+
(26, Mut, "mut");
470+
(27, Once, "once");
471+
(28, Pub, "pub");
472+
(29, Ref, "ref");
473+
(30, Return, "return");
473474
// Static and Self are also special idents (prefill de-dupes)
474475
(super::STATIC_KEYWORD_NAME, Static, "static");
475476
(super::SELF_KEYWORD_NAME, Self, "self");
476-
(30, Struct, "struct");
477-
(31, Super, "super");
478-
(32, True, "true");
479-
(33, Trait, "trait");
480-
(34, Type, "type");
481-
(35, Unsafe, "unsafe");
482-
(36, Use, "use");
483-
(37, Virtual, "virtual");
484-
(38, While, "while");
485-
(39, Continue, "continue");
486-
(40, Proc, "proc");
487-
(41, Box, "box");
477+
(31, Struct, "struct");
478+
(32, Super, "super");
479+
(33, True, "true");
480+
(34, Trait, "trait");
481+
(35, Type, "type");
482+
(36, Unsafe, "unsafe");
483+
(37, Use, "use");
484+
(38, Virtual, "virtual");
485+
(39, While, "while");
486+
(40, Continue, "continue");
487+
(41, Proc, "proc");
488+
(42, Box, "box");
488489

489490
'reserved:
490-
(42, Alignof, "alignof");
491-
(43, Be, "be");
492-
(44, Const, "const");
493-
(45, Offsetof, "offsetof");
494-
(46, Priv, "priv");
495-
(47, Pure, "pure");
496-
(48, Sizeof, "sizeof");
497-
(49, Typeof, "typeof");
498-
(50, Unsized, "unsized");
499-
(51, Yield, "yield");
500-
(52, Do, "do");
491+
(43, Alignof, "alignof");
492+
(44, Be, "be");
493+
(45, Const, "const");
494+
(46, Offsetof, "offsetof");
495+
(47, Priv, "priv");
496+
(48, Pure, "pure");
497+
(49, Sizeof, "sizeof");
498+
(50, Typeof, "typeof");
499+
(51, Unsized, "unsized");
500+
(52, Yield, "yield");
501+
(53, Do, "do");
501502
}
502503
}
503504

0 commit comments

Comments
 (0)