Skip to content

Commit

Permalink
Handle negative literals a bit better
Browse files Browse the repository at this point in the history
Looks like upstream in rust-lang/rust negative integers are represented as two
tokens instead of one token (and it looks like proc_macro may erroneously (?)
accept negative integers as literals, see rust-lang/rust#48889). As a result
tweak the `ToTokens` impls for signed integers to maybe put a `-` token out in
front. Similar treatment is applied to f32/f64 as well.

Special treatment is required, however, for the `iNN::min_value()` constants.
The actual integral portion isn't actually representable as a positive integer
literal (as it'd overflow back to negative) so to handle this case everything is
just represented as a u64 literal cast to the right type.
  • Loading branch information
alexcrichton committed Mar 9, 2018
1 parent 3bdfd71 commit d0c4c52
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 2 deletions.
53 changes: 52 additions & 1 deletion src/to_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::Tokens;
use std::borrow::Cow;

use proc_macro2::{Literal, Span, Term, TokenNode, TokenTree, TokenStream};
use proc_macro2::{Spacing, Delimiter};

fn tt(kind: TokenNode) -> TokenTree {
TokenTree {
Expand Down Expand Up @@ -126,8 +127,58 @@ macro_rules! primitive {
}

primitive! {
i8 i16 i32 i64 isize
u8 u16 u32 u64 usize
}

macro_rules! signed_primitive {
($(($t:ident => $signed:ident))*) => ($(
impl ToTokens for $t {
fn to_tokens(&self, tokens: &mut Tokens) {
let val = if *self == <$t>::min_value() {
let mut sub_tokens = Tokens::new();
(*self as u64).to_tokens(&mut sub_tokens);
sub_tokens.append(tt(TokenNode::Term(Term::intern("as"))));
sub_tokens.append(tt(TokenNode::Term(Term::intern(stringify!($t)))));
let sub_tokens = sub_tokens.into();
tokens.append(tt(TokenNode::Group(Delimiter::Parenthesis, sub_tokens)));
return
} else if *self < 0 {
tokens.append(tt(TokenNode::Op('-', Spacing::Alone)));
self.abs()
} else {
*self
};
tokens.append(tt(TokenNode::Literal(Literal::$t(val))));
}
}
)*)
}

signed_primitive! {
(i8 => u8)
(i16 => u16)
(i32 => u32)
(i64 => u64)
(isize => usize)
}

macro_rules! float_primitive {
($($t:ident)*) => ($(
impl ToTokens for $t {
fn to_tokens(&self, tokens: &mut Tokens) {
let val = if *self < 0.0 {
tokens.append(tt(TokenNode::Op('-', Spacing::Alone)));
-*self
} else {
*self
};
tokens.append(tt(TokenNode::Literal(Literal::$t(val))));
}
}
)*)
}

float_primitive! {
f32 f64
}

Expand Down
16 changes: 15 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fn test_integer() {
#ii8 #ii16 #ii32 #ii64 #iisize
#uu8 #uu16 #uu32 #uu64 #uusize
};
let expected = "-1i8 -1i16 -1i32 -1i64 -1isize 1u8 1u16 1u32 1u64 1usize";
let expected = "- 1i8 - 1i16 - 1i32 - 1i64 - 1isize 1u8 1u16 1u32 1u64 1usize";
assert_eq!(expected, tokens.to_string());
}

Expand Down Expand Up @@ -290,3 +290,17 @@ fn test_append_tokens() {
a.append_all(b);
assert_eq!("a b", a.to_string());
}

#[test]
fn negative_integers() {
let a = -1i32;
let a = quote!(#a);
assert_eq!("- 1i32", a.to_string());
}

#[test]
fn negative_min() {
let a = -128i8;
let a = quote!(#a);
assert_eq!("( 18446744073709551488u64 as i8 )", a.to_string());
}

0 comments on commit d0c4c52

Please sign in to comment.