Skip to content

Commit

Permalink
librustc: Always parse macro!()/macro![] as expressions if not
Browse files Browse the repository at this point in the history
followed by a semicolon.

This allows code like `vec![1i, 2, 3].len();` to work.

This breaks code that uses macros as statements without putting
semicolons after them, such as:

    fn main() {
        ...
        assert!(a == b)
        assert!(c == d)
        println(...);
    }

It also breaks code that uses macros as items without semicolons:

    local_data_key!(foo)

    fn main() {
        println("hello world")
    }

Add semicolons to fix this code. Those two examples can be fixed as
follows:

    fn main() {
        ...
        assert!(a == b);
        assert!(c == d);
        println(...);
    }

    local_data_key!(foo);

    fn main() {
        println("hello world")
    }

RFC rust-lang#378.

Closes rust-lang#18635.

[breaking-change]
  • Loading branch information
pcwalton authored and Jorge Aparicio committed Dec 18, 2014
1 parent c0b2885 commit ddb2466
Show file tree
Hide file tree
Showing 222 changed files with 2,338 additions and 2,047 deletions.
34 changes: 17 additions & 17 deletions src/doc/guide-macros.md
Expand Up @@ -58,7 +58,7 @@ macro_rules! early_return(
_ => {}
}
);
)
);
// ...
early_return!(input_1 T::SpecialA);
// ...
Expand Down Expand Up @@ -179,8 +179,8 @@ macro_rules! early_return(
)+
_ => {}
}
);
)
)
);
// ...
early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]);
// ...
Expand Down Expand Up @@ -275,17 +275,17 @@ macro_rules! biased_match (
_ => { $err }
};
)
)
);
# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
biased_match!((x) ~ (T1::Good1(g1, val)) else { return 0 };
binds g1, val )
binds g1, val );
biased_match!((g1.body) ~ (T3::Good2(result) )
else { panic!("Didn't get good_2") };
binds result )
binds result );
// complicated stuff goes here
return result + val;
# }
Expand All @@ -303,7 +303,7 @@ pattern we want is clear:
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
binds $( $bind_res:ident ),*
)
# => (0))
# => (0));
~~~~

However, it's not possible to directly expand to nested match statements. But
Expand All @@ -323,7 +323,7 @@ input patterns:
# #![feature(macro_rules)]
# macro_rules! b(
( binds $( $bind_res:ident ),* )
# => (0))
# => (0));
# fn main() {}
~~~~

Expand All @@ -337,7 +337,7 @@ input patterns:
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
binds $( $bind_res:ident ),*
)
# => (0))
# => (0));
~~~~

The resulting macro looks like this. Note that the separation into
Expand Down Expand Up @@ -366,7 +366,7 @@ macro_rules! biased_match_rec (
);
// Produce the requested values
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
)
);
// Wrap the whole thing in a `let`.
macro_rules! biased_match (
Expand All @@ -388,7 +388,7 @@ macro_rules! biased_match (
binds $( $bind_res ),*
);
)
)
);
# enum T1 { Good1(T2, uint), Bad1}
Expand All @@ -398,7 +398,7 @@ macro_rules! biased_match (
biased_match!(
(x) ~ (T1::Good1(g1, val)) else { return 0 };
(g1.body) ~ (T3::Good2(result) ) else { panic!("Didn't get Good2") };
binds val, result )
binds val, result );
// complicated stuff goes here
return result + val;
# }
Expand Down Expand Up @@ -444,7 +444,7 @@ macro_rules! loop_x (
$e
}
);
)
);
fn main() {
'x: loop {
Expand Down Expand Up @@ -482,30 +482,30 @@ An example:

```rust
# #![feature(macro_rules)]
macro_rules! m1 (() => (()))
macro_rules! m1 (() => (()));

// visible here: m1

mod foo {
// visible here: m1

#[macro_export]
macro_rules! m2 (() => (()))
macro_rules! m2 (() => (()));

// visible here: m1, m2
}

// visible here: m1

macro_rules! m3 (() => (()))
macro_rules! m3 (() => (()));

// visible here: m1, m3

#[macro_escape]
mod bar {
// visible here: m1, m3

macro_rules! m4 (() => (()))
macro_rules! m4 (() => (()));

// visible here: m1, m3, m4
}
Expand Down
2 changes: 1 addition & 1 deletion src/etc/regex-match-tests.py
Expand Up @@ -63,7 +63,7 @@ def read_tests(f):
def test_tostr(t):
lineno, pat, text, groups = t
options = map(group_tostr, groups)
return 'mat!(match_%s, r"%s", r"%s", %s)' \
return 'mat!{match_%s, r"%s", r"%s", %s}' \
% (lineno, pat, '' if text == "NULL" else text, ', '.join(options))


Expand Down
18 changes: 9 additions & 9 deletions src/libcollections/bit.rs
Expand Up @@ -2083,7 +2083,7 @@ mod tests {
let bools = vec![true, false, true, true];
let bitv: Bitv = bools.iter().map(|n| *n).collect();

assert_eq!(bitv.iter().collect::<Vec<bool>>(), bools)
assert_eq!(bitv.iter().collect::<Vec<bool>>(), bools);

let long = Vec::from_fn(10000, |i| i % 2 == 0);
let bitv: Bitv = long.iter().map(|n| *n).collect();
Expand Down Expand Up @@ -2112,8 +2112,8 @@ mod tests {
for &b in bools.iter() {
for &l in lengths.iter() {
let bitset = BitvSet::from_bitv(Bitv::with_capacity(l, b));
assert_eq!(bitset.contains(&1u), b)
assert_eq!(bitset.contains(&(l-1u)), b)
assert_eq!(bitset.contains(&1u), b);
assert_eq!(bitset.contains(&(l-1u)), b);
assert!(!bitset.contains(&l))
}
}
Expand Down Expand Up @@ -2321,12 +2321,12 @@ mod tests {
assert!(!a.is_disjoint(&d));
assert!(!d.is_disjoint(&a));

assert!(a.is_disjoint(&b))
assert!(a.is_disjoint(&c))
assert!(b.is_disjoint(&a))
assert!(b.is_disjoint(&c))
assert!(c.is_disjoint(&a))
assert!(c.is_disjoint(&b))
assert!(a.is_disjoint(&b));
assert!(a.is_disjoint(&c));
assert!(b.is_disjoint(&a));
assert!(b.is_disjoint(&c));
assert!(c.is_disjoint(&a));
assert!(c.is_disjoint(&b));
}

#[test]
Expand Down
26 changes: 13 additions & 13 deletions src/libcollections/enum_set.rs
Expand Up @@ -411,7 +411,7 @@ mod test {

assert!(e1.is_subset(&e2));
assert!(e2.is_superset(&e1));
assert!(!e3.is_superset(&e2))
assert!(!e3.is_superset(&e2));
assert!(!e2.is_superset(&e3))
}

Expand All @@ -438,23 +438,23 @@ mod test {
let mut e1: EnumSet<Foo> = EnumSet::new();

let elems: ::vec::Vec<Foo> = e1.iter().collect();
assert!(elems.is_empty())
assert!(elems.is_empty());

e1.insert(A);
let elems: ::vec::Vec<_> = e1.iter().collect();
assert_eq!(vec![A], elems)
assert_eq!(vec![A], elems);

e1.insert(C);
let elems: ::vec::Vec<_> = e1.iter().collect();
assert_eq!(vec![A,C], elems)
assert_eq!(vec![A,C], elems);

e1.insert(C);
let elems: ::vec::Vec<_> = e1.iter().collect();
assert_eq!(vec![A,C], elems)
assert_eq!(vec![A,C], elems);

e1.insert(B);
let elems: ::vec::Vec<_> = e1.iter().collect();
assert_eq!(vec![A,B,C], elems)
assert_eq!(vec![A,B,C], elems);
}

///////////////////////////////////////////////////////////////////////////
Expand All @@ -472,35 +472,35 @@ mod test {

let e_union = e1 | e2;
let elems: ::vec::Vec<_> = e_union.iter().collect();
assert_eq!(vec![A,B,C], elems)
assert_eq!(vec![A,B,C], elems);

let e_intersection = e1 & e2;
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
assert_eq!(vec![C], elems)
assert_eq!(vec![C], elems);

// Another way to express intersection
let e_intersection = e1 - (e1 - e2);
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
assert_eq!(vec![C], elems)
assert_eq!(vec![C], elems);

let e_subtract = e1 - e2;
let elems: ::vec::Vec<_> = e_subtract.iter().collect();
assert_eq!(vec![A], elems)
assert_eq!(vec![A], elems);

// Bitwise XOR of two sets, aka symmetric difference
let e_symmetric_diff = e1 ^ e2;
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
assert_eq!(vec![A,B], elems)
assert_eq!(vec![A,B], elems);

// Another way to express symmetric difference
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
assert_eq!(vec![A,B], elems)
assert_eq!(vec![A,B], elems);

// Yet another way to express symmetric difference
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
assert_eq!(vec![A,B], elems)
assert_eq!(vec![A,B], elems);
}

#[test]
Expand Down
5 changes: 3 additions & 2 deletions src/libcollections/macros.rs
Expand Up @@ -11,12 +11,13 @@
#![macro_escape]

/// Creates a `std::vec::Vec` containing the arguments.
macro_rules! vec(
macro_rules! vec {
($($e:expr),*) => ({
// leading _ to allow empty construction without a warning.
let mut _temp = ::vec::Vec::new();
$(_temp.push($e);)*
_temp
});
($($e:expr),+,) => (vec!($($e),+))
)
}

2 changes: 1 addition & 1 deletion src/libcollections/slice.rs
Expand Up @@ -2515,7 +2515,7 @@ mod tests {
assert_eq!(format!("{}", x), x_str);
assert_eq!(format!("{}", x.as_slice()), x_str);
})
)
);
let empty: Vec<int> = vec![];
test_show_vec!(empty, "[]");
test_show_vec!(vec![1i], "[1]");
Expand Down
8 changes: 4 additions & 4 deletions src/libcollections/str.rs
Expand Up @@ -415,14 +415,14 @@ Section: Misc
// Return the initial codepoint accumulator for the first byte.
// The first byte is special, only want bottom 5 bits for width 2, 4 bits
// for width 3, and 3 bits for width 4
macro_rules! utf8_first_byte(
macro_rules! utf8_first_byte {
($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
)
}

// return the value of $ch updated with continuation byte $byte
macro_rules! utf8_acc_cont_byte(
macro_rules! utf8_acc_cont_byte {
($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32)
)
}

/*
Section: MaybeOwned
Expand Down
6 changes: 3 additions & 3 deletions src/libcollections/string.rs
Expand Up @@ -167,7 +167,7 @@ impl String {
subseqidx = i;
res.as_mut_vec().push_all(REPLACEMENT);
}
}))
}));

if byte < 128u8 {
// subseqidx handles this
Expand Down Expand Up @@ -788,8 +788,8 @@ macro_rules! impl_eq {
}
}

impl_eq!(String, &'a str)
impl_eq!(CowString<'a>, String)
impl_eq! { String, &'a str }
impl_eq! { CowString<'a>, String }

impl<'a, 'b> PartialEq<&'b str> for CowString<'a> {
#[inline]
Expand Down
12 changes: 6 additions & 6 deletions src/libcollections/tree/map.rs
Expand Up @@ -900,7 +900,7 @@ macro_rules! define_iterator {
) => {
// private methods on the forward iterator (item!() for the
// addr_mut in the next_ return value)
item!(impl<'a, K, V> $name<'a, K, V> {
item! { impl<'a, K, V> $name<'a, K, V> {
#[inline(always)]
fn next_(&mut self, forward: bool) -> Option<(&'a K, &'a $($addr_mut)* V)> {
while !self.stack.is_empty() || !self.node.is_null() {
Expand Down Expand Up @@ -968,10 +968,10 @@ macro_rules! define_iterator {
self.node = ptr::RawPtr::null();
}
}
})
} }

// the forward Iterator impl.
item!(impl<'a, K, V> Iterator<(&'a K, &'a $($addr_mut)* V)> for $name<'a, K, V> {
item! { impl<'a, K, V> Iterator<(&'a K, &'a $($addr_mut)* V)> for $name<'a, K, V> {
/// Advances the iterator to the next node (in order) and return a
/// tuple with a reference to the key and value. If there are no
/// more nodes, return `None`.
Expand All @@ -983,10 +983,10 @@ macro_rules! define_iterator {
fn size_hint(&self) -> (uint, Option<uint>) {
(self.remaining_min, Some(self.remaining_max))
}
})
} }

// the reverse Iterator impl.
item!(impl<'a, K, V> Iterator<(&'a K, &'a $($addr_mut)* V)> for $rev_name<'a, K, V> {
item! { impl<'a, K, V> Iterator<(&'a K, &'a $($addr_mut)* V)> for $rev_name<'a, K, V> {
fn next(&mut self) -> Option<(&'a K, &'a $($addr_mut)* V)> {
self.iter.next_(false)
}
Expand All @@ -995,7 +995,7 @@ macro_rules! define_iterator {
fn size_hint(&self) -> (uint, Option<uint>) {
self.iter.size_hint()
}
})
} }
}
} // end of define_iterator

Expand Down
4 changes: 2 additions & 2 deletions src/libcollections/trie/map.rs
Expand Up @@ -1141,7 +1141,7 @@ macro_rules! iterator_impl {
}
}

item!(impl<'a, T> Iterator<(uint, &'a $($mut_)* T)> for $name<'a, T> {
item! { impl<'a, T> Iterator<(uint, &'a $($mut_)* T)> for $name<'a, T> {
// you might wonder why we're not even trying to act within the
// rules, and are just manipulating raw pointers like there's no
// such thing as invalid pointers and memory unsafety. The
Expand Down Expand Up @@ -1213,7 +1213,7 @@ macro_rules! iterator_impl {
fn size_hint(&self) -> (uint, Option<uint>) {
(self.remaining_min, Some(self.remaining_max))
}
})
} }
}
}

Expand Down

1 comment on commit ddb2466

@alexcrichton
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+ p=10

Please sign in to comment.