Skip to content

Commit 759702f

Browse files
committed
Fix issue rust-lang#3212: Allow empty structure
The fix is straight-forward, but there are several changes while fixing the issue. 1) disallow `mut` keyword when making a new struct In code base, there are following code, struct Foo { mut a: int }; let a = Foo { mut a: 1 }; This is because of structural record, which is deprecated corrently (see issue rust-lang#3089) In structural record, `mut` keyword should be allowd to control mutability. But without structural record, we don't need to allow `mut` keyword while constructing struct. 2) disallow structural records in parser level This is related to 1). With structural records, there is an ambiguity between empty block and empty struct To solve the problem, I change parser to stop parsing structural records. I think this is not a problem, because structural records are not compiled already. Misc. issues There is an ambiguity between empty struct vs. empty match stmt. with following code, match x{} {} Two interpretation is possible, which is listed blow match (x{}) {} // matching with newly-constructed empty struct (match x{}) {} // matching with empty enum(or struct) x // and then empty block It seems that there is no such code in rust code base, but there is one test which uses empty match statement: https://github.com/mozilla/rust/blob/incoming/src/test/run-pass/issue-3037.rs All other cases could be distinguished with look-ahead, but this can't be. One possible solution is wrapping with parentheses when matching with an uninhabited type. enum what { } fn match_with_empty(x: what) -> ~str { match (x) { //use parentheses to remove the ambiguity } }
1 parent 93a7f23 commit 759702f

File tree

11 files changed

+96
-65
lines changed

11 files changed

+96
-65
lines changed

src/libcore/dvec.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ pub struct DVec<A> {
6262

6363
/// Creates a new, empty dvec
6464
pub pure fn DVec<A>() -> DVec<A> {
65-
DVec {mut data: ~[]}
65+
DVec {data: ~[]}
6666
}
6767

6868
/// Creates a new dvec with a single element
6969
pub pure fn from_elem<A>(e: A) -> DVec<A> {
70-
DVec {mut data: ~[e]}
70+
DVec {data: ~[e]}
7171
}
7272

7373
/// Creates a new dvec with the contents of a vector
7474
pub pure fn from_vec<A>(v: ~[A]) -> DVec<A> {
75-
DVec {mut data: v}
75+
DVec {data: v}
7676
}
7777

7878
/// Consumes the vector and returns its contents

src/libcore/os.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ pub struct Pipe { mut in: c_int, mut out: c_int }
322322
#[cfg(unix)]
323323
pub fn pipe() -> Pipe {
324324
unsafe {
325-
let mut fds = Pipe {mut in: 0 as c_int,
326-
mut out: 0 as c_int };
325+
let mut fds = Pipe {in: 0 as c_int,
326+
out: 0 as c_int };
327327
assert (libc::pipe(&mut fds.in) == (0 as c_int));
328328
return Pipe {in: fds.in, out: fds.out};
329329
}
@@ -339,8 +339,8 @@ pub fn pipe() -> Pipe {
339339
// fully understand. Here we explicitly make the pipe non-inheritable,
340340
// which means to pass it to a subprocess they need to be duplicated
341341
// first, as in rust_run_program.
342-
let mut fds = Pipe { mut in: 0 as c_int,
343-
mut out: 0 as c_int };
342+
let mut fds = Pipe {in: 0 as c_int,
343+
out: 0 as c_int };
344344
let res = libc::pipe(&mut fds.in, 1024 as c_uint,
345345
(libc::O_BINARY | libc::O_NOINHERIT) as c_int);
346346
assert (res == 0 as c_int);
@@ -566,13 +566,17 @@ pub fn path_exists(p: &Path) -> bool {
566566
*
567567
* If the given path is relative, return it prepended with the current working
568568
* directory. If the given path is already an absolute path, return it
569-
* as is. This is a shortcut for calling os::getcwd().unsafe_join(p)
569+
* as is.
570570
*/
571571
// NB: this is here rather than in path because it is a form of environment
572572
// querying; what it does depends on the process working directory, not just
573573
// the input paths.
574574
pub fn make_absolute(p: &Path) -> Path {
575-
getcwd().unsafe_join(p)
575+
if p.is_absolute {
576+
copy *p
577+
} else {
578+
getcwd().push_many(p.components)
579+
}
576580
}
577581

578582

src/libcore/ptr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,15 +300,15 @@ impl<T:Ord> Ord for &const T {
300300
pub fn test() {
301301
unsafe {
302302
struct Pair {mut fst: int, mut snd: int};
303-
let mut p = Pair {mut fst: 10, mut snd: 20};
303+
let mut p = Pair {fst: 10, snd: 20};
304304
let pptr: *mut Pair = &mut p;
305305
let iptr: *mut int = cast::reinterpret_cast(&pptr);
306306
assert (*iptr == 10);;
307307
*iptr = 30;
308308
assert (*iptr == 30);
309309
assert (p.fst == 30);;
310310

311-
*pptr = Pair {mut fst: 50, mut snd: 60};
311+
*pptr = Pair {fst: 50, snd: 60};
312312
assert (*iptr == 50);
313313
assert (p.fst == 50);
314314
assert (p.snd == 60);

src/libstd/ebml.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub mod reader {
219219
}
220220

221221
pub fn Decoder(d: Doc) -> Decoder {
222-
Decoder { mut parent: d, mut pos: d.start }
222+
Decoder { parent: d, pos: d.start }
223223
}
224224

225225
priv impl Decoder {

src/libstd/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ enum Sem<Q> = Exclusive<SemInner<Q>>;
8686
#[doc(hidden)]
8787
fn new_sem<Q:Owned>(count: int, q: Q) -> Sem<Q> {
8888
Sem(exclusive(SemInner {
89-
mut count: count, waiters: new_waitqueue(), blocked: q }))
89+
count: count, waiters: new_waitqueue(), blocked: q }))
9090
}
9191
#[doc(hidden)]
9292
fn new_sem_and_signal(count: int, num_condvars: uint)

src/libsyntax/parse/parser.rs

Lines changed: 57 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove};
7575
use parse::obsolete::{ObsoleteStructCtor, ObsoleteWith};
7676
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
7777
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
78-
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
78+
use parse::obsolete::{ObsoleteTraitBoundSeparator};
7979
use parse::prec::{as_prec, token_to_binop};
8080
use parse::token::{can_begin_expr, is_ident, is_ident_or_path};
8181
use parse::token::{is_plain_ident, INTERPOLATED, special_idents};
@@ -677,11 +677,6 @@ pub impl Parser {
677677
// rather than boxed ptrs. But the special casing of str/vec is not
678678
// reflected in the AST type.
679679
let mt = self.parse_mt();
680-
681-
if mt.mutbl == m_mutbl && sigil == OwnedSigil {
682-
self.obsolete(*self.last_span, ObsoleteMutOwnedPointer);
683-
}
684-
685680
ctor(mt)
686681
}
687682

@@ -753,6 +748,18 @@ pub impl Parser {
753748
}
754749
}
755750

751+
fn parse_capture_item_or(parse_arg_fn: fn(Parser) -> arg_or_capture_item)
752+
-> arg_or_capture_item
753+
{
754+
if self.eat_keyword(~"copy") {
755+
// XXX outdated syntax now that moves-based-on-type has gone in
756+
self.parse_ident();
757+
either::Right(())
758+
} else {
759+
parse_arg_fn(self)
760+
}
761+
}
762+
756763
// This version of parse arg doesn't necessarily require
757764
// identifier names.
758765
fn parse_arg_general(require_name: bool) -> arg {
@@ -781,26 +788,32 @@ pub impl Parser {
781788
either::Left(self.parse_arg_general(true))
782789
}
783790
791+
fn parse_arg_or_capture_item() -> arg_or_capture_item {
792+
self.parse_capture_item_or(|p| p.parse_arg())
793+
}
794+
784795
fn parse_fn_block_arg() -> arg_or_capture_item {
785-
let m = self.parse_arg_mode();
786-
let is_mutbl = self.eat_keyword(~"mut");
787-
let pat = self.parse_pat(false);
788-
let t = if self.eat(token::COLON) {
789-
self.parse_ty(false)
790-
} else {
791-
@Ty {
792-
id: self.get_id(),
793-
node: ty_infer,
794-
span: mk_sp(self.span.lo, self.span.hi),
795-
}
796-
};
797-
either::Left(ast::arg {
798-
mode: m,
799-
is_mutbl: is_mutbl,
800-
ty: t,
801-
pat: pat,
802-
id: self.get_id()
803-
})
796+
do self.parse_capture_item_or |p| {
797+
let m = p.parse_arg_mode();
798+
let is_mutbl = self.eat_keyword(~"mut");
799+
let pat = p.parse_pat(false);
800+
let t = if p.eat(token::COLON) {
801+
p.parse_ty(false)
802+
} else {
803+
@Ty {
804+
id: p.get_id(),
805+
node: ty_infer,
806+
span: mk_sp(p.span.lo, p.span.hi),
807+
}
808+
};
809+
either::Left(ast::arg {
810+
mode: m,
811+
is_mutbl: is_mutbl,
812+
ty: t,
813+
pat: pat,
814+
id: p.get_id()
815+
})
816+
}
804817
}
805818

806819
fn maybe_parse_fixed_vstore_with_star() -> Option<uint> {
@@ -1095,15 +1108,10 @@ pub impl Parser {
10951108
self.mk_expr(lo, hi, expr_tup(es))
10961109
}
10971110
} else if *self.token == token::LBRACE {
1098-
if self.looking_at_record_literal() {
1099-
ex = self.parse_record_literal();
1100-
hi = self.span.hi;
1101-
} else {
1102-
self.bump();
1103-
let blk = self.parse_block_tail(lo, default_blk);
1104-
return self.mk_expr(blk.span.lo, blk.span.hi,
1105-
expr_block(blk));
1106-
}
1111+
self.bump();
1112+
let blk = self.parse_block_tail(lo, default_blk);
1113+
return self.mk_expr(blk.span.lo, blk.span.hi,
1114+
expr_block(blk));
11071115
} else if token::is_bar(*self.token) {
11081116
return self.parse_lambda_expr();
11091117
} else if self.eat_keyword(~"if") {
@@ -1221,24 +1229,21 @@ pub impl Parser {
12211229
self.bump();
12221230
let mut fields = ~[];
12231231
let mut base = None;
1224-
fields.push(self.parse_field(token::COLON));
12251232
while *self.token != token::RBRACE {
1226-
if self.try_parse_obsolete_with() {
1227-
break;
1228-
}
1229-
1230-
self.expect(token::COMMA);
1233+
fields.push(self.parse_field(token::COLON));
12311234

1232-
if self.eat(token::DOTDOT) {
1233-
base = Some(self.parse_expr());
1235+
if self.try_parse_obsolete_with() {
12341236
break;
12351237
}
12361238

1237-
if *self.token == token::RBRACE {
1238-
// Accept an optional trailing comma.
1239+
if self.eat(token::COMMA) {
1240+
if self.eat(token::DOTDOT) {
1241+
base = Some(self.parse_expr());
1242+
break;
1243+
}
1244+
} else {
12391245
break;
12401246
}
1241-
fields.push(self.parse_field(token::COLON));
12421247
}
12431248

12441249
hi = pth.span.hi;
@@ -1709,7 +1714,7 @@ pub impl Parser {
17091714

17101715
// if we want to allow fn expression argument types to be inferred in
17111716
// the future, just have to change parse_arg to parse_fn_block_arg.
1712-
let decl = self.parse_fn_decl(|p| p.parse_arg());
1717+
let decl = self.parse_fn_decl(|p| p.parse_arg_or_capture_item());
17131718

17141719
let body = self.parse_block();
17151720

@@ -1885,10 +1890,13 @@ pub impl Parser {
18851890
// For distingishing between record literals and blocks
18861891
fn looking_at_record_literal() -> bool {
18871892
let lookahead = self.look_ahead(1);
1893+
let next_lookahead = self.look_ahead(2);
18881894
*self.token == token::LBRACE &&
1889-
(self.token_is_keyword(~"mut", lookahead) ||
1890-
(is_plain_ident(lookahead) &&
1891-
self.look_ahead(2) == token::COLON))
1895+
((is_plain_ident(lookahead) &&
1896+
next_lookahead == token::COLON) ||
1897+
(lookahead == token::RBRACE &&
1898+
*self.restriction != RESTRICT_NO_BAR_OR_DOUBLEBAR_OP &&
1899+
!can_begin_expr(next_lookahead)))
18921900
}
18931901

18941902
fn parse_record_literal() -> expr_ {
File renamed without changes.

src/test/run-pass/lint-structural-records.rs renamed to src/test/run-fail/structural-records.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[warn(structural_records)];
1211
pub fn main() {
1312
let _foo = {x:5};
1413
}

src/test/run-pass/issue-3037.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ enum what { }
1212

1313
fn what_to_str(x: what) -> ~str
1414
{
15-
match x {
15+
match (x) {
1616
}
1717
}
1818

src/test/run-pass/struct-empty.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
13+
// -*- rust -*-
14+
struct Foo {
15+
}
16+
17+
18+
pub fn main() {
19+
let _foo = Foo{};
20+
}

src/test/run-pass/uniq-cc-generic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn make_uniq_closure<A:Owned + Copy>(a: A) -> fn~() -> uint {
2424

2525
fn empty_pointy() -> @mut Pointy {
2626
return @mut Pointy {
27-
mut a : none,
27+
a : none,
2828
d : make_uniq_closure(~"hi")
2929
}
3030
}

0 commit comments

Comments
 (0)