From bcabcf53cfe2a86ebf02aa762b8ab7278060ce10 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 17 Jan 2014 22:30:36 -0800 Subject: [PATCH] Make bytes!() return 'static Change `bytes!()` to return { static BYTES: &'static [u8] = &[...]; BYTES } This gives it the `'static` lifetime, whereas before it had an rvalue lifetime. Until recently this would have prevented assigning `bytes!()` to a static, as in static FOO: &'static [u8] = bytes!(1,2,3); but #14183 fixed it so blocks are now allowed in constant expressions (with restrictions). Fixes #11641. --- src/libsyntax/ext/bytes.rs | 33 ++++++++++++++++++++----- src/test/run-pass/bytes-macro-static.rs | 21 ++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/bytes-macro-static.rs diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index 06b50e37cbd..b2088d2bc82 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -25,6 +25,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) Some(e) => e, }; let mut bytes = Vec::new(); + let mut err = false; for expr in exprs.iter() { match expr.node { @@ -40,7 +41,8 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // u8 literal, push to vector expression ast::LitUint(v, ast::TyU8) => { if v > 0xFF { - cx.span_err(expr.span, "too large u8 literal in bytes!") + cx.span_err(expr.span, "too large u8 literal in bytes!"); + err = true; } else { bytes.push(cx.expr_u8(expr.span, v as u8)); } @@ -49,9 +51,11 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // integer literal, push to vector expression ast::LitIntUnsuffixed(v) => { if v > 0xFF { - cx.span_err(expr.span, "too large integer literal in bytes!") + cx.span_err(expr.span, "too large integer literal in bytes!"); + err = true; } else if v < 0 { - cx.span_err(expr.span, "negative integer literal in bytes!") + cx.span_err(expr.span, "negative integer literal in bytes!"); + err = true; } else { bytes.push(cx.expr_u8(expr.span, v as u8)); } @@ -62,17 +66,34 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) if v.is_ascii() { bytes.push(cx.expr_u8(expr.span, v as u8)); } else { - cx.span_err(expr.span, "non-ascii char literal in bytes!") + cx.span_err(expr.span, "non-ascii char literal in bytes!"); + err = true; } } - _ => cx.span_err(expr.span, "unsupported literal in bytes!") + _ => { + cx.span_err(expr.span, "unsupported literal in bytes!"); + err = true; + } }, - _ => cx.span_err(expr.span, "non-literal in bytes!") + _ => { + cx.span_err(expr.span, "non-literal in bytes!"); + err = true; + } } } + // For some reason using quote_expr!() here aborts if we threw an error. + // I'm assuming that the end of the recursive parse tricks the compiler + // into thinking this is a good time to stop. But we'd rather keep going. + if err { + // Since the compiler will stop after the macro expansion phase anyway, we + // don't need type info, so we can just return a DummyResult + return DummyResult::expr(sp); + } + let e = cx.expr_vec_slice(sp, bytes); + let e = quote_expr!(cx, { static BYTES: &'static [u8] = $e; BYTES}); MacExpr::new(e) } diff --git a/src/test/run-pass/bytes-macro-static.rs b/src/test/run-pass/bytes-macro-static.rs new file mode 100644 index 00000000000..7f4bbda8e30 --- /dev/null +++ b/src/test/run-pass/bytes-macro-static.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static FOO: &'static [u8] = bytes!("hello, world"); + +pub fn main() { + let b = match true { + true => bytes!("test"), + false => unreachable!() + }; + + assert_eq!(b, "test".as_bytes()); + assert_eq!(FOO, "hello, world".as_bytes()); +}