incr.comp.: Hash more pieces of crate metadata to detect changes there.
This PR adds incr. comp. hashes for non-`Entry` pieces of data in crate metadata.
The first part of it I like: `EntryBuilder` is refactored into the more generally applicable `IsolatedEncoder` which provides means of encoding something into metadata while also feeding the encoded data into an incr. comp. hash. We already did this for `Entry`, now we are doing it for various other pieces of data too, like the set of exported symbols and so on. The hashes generated there are persisted together with the per-`Entry` hashes and are also used for dep-graph dirtying the same way.
The second part of the PR I'm not entirely happy with: In order to make sure that we don't forget registering a read to the new `DepNodes` introduced here, I added the `Tracked<T>` struct. This struct wraps a value and requires a `DepNode` when accessing the wrapped value. This makes it harder to overlook adding read edges in the right places and works just fine.
However, crate metadata is already used in places where there is no `tcx` yet or even in places where no `cnum` has been assigned -- this makes it harder to apply this feature consistently or implement it ergonomically. The result is not too bad but there's a bit more code churn and a bit more opportunity to get something wrong than I would have liked. On the other hand, wrapping things in `Tracked<T>` already has revealed some bugs, so there's definitely some value in it.
This is still a work in progress:
- [x] I need to write some test cases.
- [x] Accessing the CodeMap should really be dependency tracked too, especially with the new path-remapping feature.
cc @nikomatsakis
[[package]]
name = "rls-data"
-version = "0.1.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rls-span"
-version = "0.1.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_typeck 0.0.0",
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
-"checksum rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af1dfff00189fd7b78edb9af131b0de703676c04fa8126aed77fd2c586775a4d"
-"checksum rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8656f7b850ac85fb204ef94318c641bbb15a32766e12f9a589a23e4c0fbc38db"
+"checksum rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc4277ce3c57f456b11fe3145b181a844a25201bab5cbaa1978457e6e2f27d47"
+"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0"
"checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f"
"checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e"
% Rustc UX guidelines
Don't forget the user. Whether human or another program, such as an IDE, a
-good user experience with the compiler goes a long way into making developer
-lives better. We don't want users to be baffled by compiler output or
+good user experience with the compiler goes a long way toward making developers'
+lives better. We do not want users to be baffled by compiler output or
learn arcane patterns to compile their program.
## Error, Warning, Help, Note Messages
-When the compiler detects a problem, it can emit either an error, warning,
-note, or help message.
+When the compiler detects a problem, it can emit one of the following: an error, a warning,
+a note, or a help message.
An `error` is emitted when the compiler detects a problem that makes it unable
to compile the program, either because the program is invalid or the
A `warning` is emitted when the compiler detects something odd about a
program. For instance, dead code and unused `Result` values.
-A `help` is emitted following either an `error` or `warning` giving extra
+A `help` message is emitted following an `error` or `warning` to give additional
information to the user about how to solve their problem.
-A `note` is for identifying additional circumstances and parts of the code
-that lead to a warning or error. For example, the borrow checker will note any
+A `note` is emitted to identify additional circumstances and parts of the code
+that caused the warning or error. For example, the borrow checker will note any
previous conflicting borrows.
* Write in plain simple English. If your message, when shown on a – possibly
--- /dev/null
+*.class
+*.java
+*.tokens
--- /dev/null
+%{
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stdio.h>
+#include <ctype.h>
+
+static int num_hashes;
+static int end_hashes;
+static int saw_non_hash;
+
+%}
+
+%option stack
+%option yylineno
+
+%x str
+%x rawstr
+%x rawstr_esc_begin
+%x rawstr_esc_body
+%x rawstr_esc_end
+%x byte
+%x bytestr
+%x rawbytestr
+%x rawbytestr_nohash
+%x pound
+%x shebang_or_attr
+%x ltorchar
+%x linecomment
+%x doc_line
+%x blockcomment
+%x doc_block
+%x suffix
+
+ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]*
+
+%%
+
+<suffix>{ident} { BEGIN(INITIAL); }
+<suffix>(.|\n) { yyless(0); BEGIN(INITIAL); }
+
+[ \n\t\r] { }
+
+\xef\xbb\xbf {
+ // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise
+ if (yyget_lineno() != 1) {
+ return -1;
+ }
+}
+
+\/\/(\/|\!) { BEGIN(doc_line); yymore(); }
+<doc_line>\n { BEGIN(INITIAL);
+ yyleng--;
+ yytext[yyleng] = 0;
+ return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT);
+ }
+<doc_line>[^\n]* { yymore(); }
+
+\/\/|\/\/\/\/ { BEGIN(linecomment); }
+<linecomment>\n { BEGIN(INITIAL); }
+<linecomment>[^\n]* { }
+
+\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); }
+<doc_block>\/\* { yy_push_state(doc_block); yymore(); }
+<doc_block>\*\/ {
+ yy_pop_state();
+ if (yy_top_state() == doc_block) {
+ yymore();
+ } else {
+ return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT);
+ }
+}
+<doc_block>(.|\n) { yymore(); }
+
+\/\* { yy_push_state(blockcomment); }
+<blockcomment>\/\* { yy_push_state(blockcomment); }
+<blockcomment>\*\/ { yy_pop_state(); }
+<blockcomment>(.|\n) { }
+
+_ { return UNDERSCORE; }
+as { return AS; }
+box { return BOX; }
+break { return BREAK; }
+const { return CONST; }
+continue { return CONTINUE; }
+crate { return CRATE; }
+else { return ELSE; }
+enum { return ENUM; }
+extern { return EXTERN; }
+false { return FALSE; }
+fn { return FN; }
+for { return FOR; }
+if { return IF; }
+impl { return IMPL; }
+in { return IN; }
+let { return LET; }
+loop { return LOOP; }
+match { return MATCH; }
+mod { return MOD; }
+move { return MOVE; }
+mut { return MUT; }
+priv { return PRIV; }
+proc { return PROC; }
+pub { return PUB; }
+ref { return REF; }
+return { return RETURN; }
+self { return SELF; }
+static { return STATIC; }
+struct { return STRUCT; }
+trait { return TRAIT; }
+true { return TRUE; }
+type { return TYPE; }
+typeof { return TYPEOF; }
+unsafe { return UNSAFE; }
+use { return USE; }
+where { return WHERE; }
+while { return WHILE; }
+
+{ident} { return IDENT; }
+
+0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; }
+0o[0-8_]+ { BEGIN(suffix); return LIT_INTEGER; }
+0b[01_]+ { BEGIN(suffix); return LIT_INTEGER; }
+[0-9][0-9_]* { BEGIN(suffix); return LIT_INTEGER; }
+[0-9][0-9_]*\.(\.|[a-zA-Z]) { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; }
+
+[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)? { BEGIN(suffix); return LIT_FLOAT; }
+[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+ { BEGIN(suffix); return LIT_FLOAT; }
+
+; { return ';'; }
+, { return ','; }
+\.\.\. { return DOTDOTDOT; }
+\.\. { return DOTDOT; }
+\. { return '.'; }
+\( { return '('; }
+\) { return ')'; }
+\{ { return '{'; }
+\} { return '}'; }
+\[ { return '['; }
+\] { return ']'; }
+@ { return '@'; }
+# { BEGIN(pound); yymore(); }
+<pound>\! { BEGIN(shebang_or_attr); yymore(); }
+<shebang_or_attr>\[ {
+ BEGIN(INITIAL);
+ yyless(2);
+ return SHEBANG;
+}
+<shebang_or_attr>[^\[\n]*\n {
+ // Since the \n was eaten as part of the token, yylineno will have
+ // been incremented to the value 2 if the shebang was on the first
+ // line. This yyless undoes that, setting yylineno back to 1.
+ yyless(yyleng - 1);
+ if (yyget_lineno() == 1) {
+ BEGIN(INITIAL);
+ return SHEBANG_LINE;
+ } else {
+ BEGIN(INITIAL);
+ yyless(2);
+ return SHEBANG;
+ }
+}
+<pound>. { BEGIN(INITIAL); yyless(1); return '#'; }
+
+\~ { return '~'; }
+:: { return MOD_SEP; }
+: { return ':'; }
+\$ { return '$'; }
+\? { return '?'; }
+
+== { return EQEQ; }
+=> { return FAT_ARROW; }
+= { return '='; }
+\!= { return NE; }
+\! { return '!'; }
+\<= { return LE; }
+\<\< { return SHL; }
+\<\<= { return SHLEQ; }
+\< { return '<'; }
+\>= { return GE; }
+\>\> { return SHR; }
+\>\>= { return SHREQ; }
+\> { return '>'; }
+
+\x27 { BEGIN(ltorchar); yymore(); }
+<ltorchar>static { BEGIN(INITIAL); return STATIC_LIFETIME; }
+<ltorchar>{ident} { BEGIN(INITIAL); return LIFETIME; }
+<ltorchar>\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>\\u\{[0-9a-fA-F]?{6}\}\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>.\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar><<EOF>> { BEGIN(INITIAL); return -1; }
+
+b\x22 { BEGIN(bytestr); yymore(); }
+<bytestr>\x22 { BEGIN(suffix); return LIT_BYTE_STR; }
+
+<bytestr><<EOF>> { return -1; }
+<bytestr>\\[n\nrt\\\x27\x220] { yymore(); }
+<bytestr>\\x[0-9a-fA-F]{2} { yymore(); }
+<bytestr>\\u\{[0-9a-fA-F]?{6}\} { yymore(); }
+<bytestr>\\[^n\nrt\\\x27\x220] { return -1; }
+<bytestr>(.|\n) { yymore(); }
+
+br\x22 { BEGIN(rawbytestr_nohash); yymore(); }
+<rawbytestr_nohash>\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; }
+<rawbytestr_nohash>(.|\n) { yymore(); }
+<rawbytestr_nohash><<EOF>> { return -1; }
+
+br/# {
+ BEGIN(rawbytestr);
+ yymore();
+ num_hashes = 0;
+ saw_non_hash = 0;
+ end_hashes = 0;
+}
+<rawbytestr># {
+ if (!saw_non_hash) {
+ num_hashes++;
+ } else if (end_hashes != 0) {
+ end_hashes++;
+ if (end_hashes == num_hashes) {
+ BEGIN(INITIAL);
+ return LIT_BYTE_STR_RAW;
+ }
+ }
+ yymore();
+}
+<rawbytestr>\x22# {
+ end_hashes = 1;
+ if (end_hashes == num_hashes) {
+ BEGIN(INITIAL);
+ return LIT_BYTE_STR_RAW;
+ }
+ yymore();
+}
+<rawbytestr>(.|\n) {
+ if (!saw_non_hash) {
+ saw_non_hash = 1;
+ }
+ if (end_hashes != 0) {
+ end_hashes = 0;
+ }
+ yymore();
+}
+<rawbytestr><<EOF>> { return -1; }
+
+b\x27 { BEGIN(byte); yymore(); }
+<byte>\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\u[0-9a-fA-F]{4}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\U[0-9a-fA-F]{8}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>.\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte><<EOF>> { BEGIN(INITIAL); return -1; }
+
+r\x22 { BEGIN(rawstr); yymore(); }
+<rawstr>\x22 { BEGIN(suffix); return LIT_STR_RAW; }
+<rawstr>(.|\n) { yymore(); }
+<rawstr><<EOF>> { return -1; }
+
+r/# {
+ BEGIN(rawstr_esc_begin);
+ yymore();
+ num_hashes = 0;
+ saw_non_hash = 0;
+ end_hashes = 0;
+}
+
+<rawstr_esc_begin># {
+ num_hashes++;
+ yymore();
+}
+<rawstr_esc_begin>\x22 {
+ BEGIN(rawstr_esc_body);
+ yymore();
+}
+<rawstr_esc_begin>(.|\n) { return -1; }
+
+<rawstr_esc_body>\x22/# {
+ BEGIN(rawstr_esc_end);
+ yymore();
+ }
+<rawstr_esc_body>(.|\n) {
+ yymore();
+ }
+
+<rawstr_esc_end># {
+ end_hashes++;
+ if (end_hashes == num_hashes) {
+ BEGIN(INITIAL);
+ return LIT_STR_RAW;
+ }
+ yymore();
+ }
+<rawstr_esc_end>[^#] {
+ end_hashes = 0;
+ BEGIN(rawstr_esc_body);
+ yymore();
+ }
+
+<rawstr_esc_begin,rawstr_esc_body,rawstr_esc_end><<EOF>> { return -1; }
+
+\x22 { BEGIN(str); yymore(); }
+<str>\x22 { BEGIN(suffix); return LIT_STR; }
+
+<str><<EOF>> { return -1; }
+<str>\\[n\nr\rt\\\x27\x220] { yymore(); }
+<str>\\x[0-9a-fA-F]{2} { yymore(); }
+<str>\\u\{[0-9a-fA-F]?{6}\} { yymore(); }
+<str>\\[^n\nrt\\\x27\x220] { return -1; }
+<str>(.|\n) { yymore(); }
+
+\<- { return LARROW; }
+-\> { return RARROW; }
+- { return '-'; }
+-= { return MINUSEQ; }
+&& { return ANDAND; }
+& { return '&'; }
+&= { return ANDEQ; }
+\|\| { return OROR; }
+\| { return '|'; }
+\|= { return OREQ; }
+\+ { return '+'; }
+\+= { return PLUSEQ; }
+\* { return '*'; }
+\*= { return STAREQ; }
+\/ { return '/'; }
+\/= { return SLASHEQ; }
+\^ { return '^'; }
+\^= { return CARETEQ; }
+% { return '%'; }
+%= { return PERCENTEQ; }
+
+<<EOF>> { return 0; }
+
+%%
--- /dev/null
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern int yylex();
+extern int rsparse();
+
+#define PUSHBACK_LEN 4
+
+static char pushback[PUSHBACK_LEN];
+static int verbose;
+
+void print(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ if (verbose) {
+ vprintf(format, args);
+ }
+ va_end(args);
+}
+
+// If there is a non-null char at the head of the pushback queue,
+// dequeue it and shift the rest of the queue forwards. Otherwise,
+// return the token from calling yylex.
+int rslex() {
+ if (pushback[0] == '\0') {
+ return yylex();
+ } else {
+ char c = pushback[0];
+ memmove(pushback, pushback + 1, PUSHBACK_LEN - 1);
+ pushback[PUSHBACK_LEN - 1] = '\0';
+ return c;
+ }
+}
+
+// Note: this does nothing if the pushback queue is full. As long as
+// there aren't more than PUSHBACK_LEN consecutive calls to push_back
+// in an action, this shouldn't be a problem.
+void push_back(char c) {
+ for (int i = 0; i < PUSHBACK_LEN; ++i) {
+ if (pushback[i] == '\0') {
+ pushback[i] = c;
+ break;
+ }
+ }
+}
+
+extern int rsdebug;
+
+struct node {
+ struct node *next;
+ struct node *prev;
+ int own_string;
+ char const *name;
+ int n_elems;
+ struct node *elems[];
+};
+
+struct node *nodes = NULL;
+int n_nodes;
+
+struct node *mk_node(char const *name, int n, ...) {
+ va_list ap;
+ int i = 0;
+ unsigned sz = sizeof(struct node) + (n * sizeof(struct node *));
+ struct node *nn, *nd = (struct node *)malloc(sz);
+
+ print("# New %d-ary node: %s = %p\n", n, name, nd);
+
+ nd->own_string = 0;
+ nd->prev = NULL;
+ nd->next = nodes;
+ if (nodes) {
+ nodes->prev = nd;
+ }
+ nodes = nd;
+
+ nd->name = name;
+ nd->n_elems = n;
+
+ va_start(ap, n);
+ while (i < n) {
+ nn = va_arg(ap, struct node *);
+ print("# arg[%d]: %p\n", i, nn);
+ print("# (%s ...)\n", nn->name);
+ nd->elems[i++] = nn;
+ }
+ va_end(ap);
+ n_nodes++;
+ return nd;
+}
+
+struct node *mk_atom(char *name) {
+ struct node *nd = mk_node((char const *)strdup(name), 0);
+ nd->own_string = 1;
+ return nd;
+}
+
+struct node *mk_none() {
+ return mk_atom("<none>");
+}
+
+struct node *ext_node(struct node *nd, int n, ...) {
+ va_list ap;
+ int i = 0, c = nd->n_elems + n;
+ unsigned sz = sizeof(struct node) + (c * sizeof(struct node *));
+ struct node *nn;
+
+ print("# Extending %d-ary node by %d nodes: %s = %p",
+ nd->n_elems, c, nd->name, nd);
+
+ if (nd->next) {
+ nd->next->prev = nd->prev;
+ }
+ if (nd->prev) {
+ nd->prev->next = nd->next;
+ }
+ nd = realloc(nd, sz);
+ nd->prev = NULL;
+ nd->next = nodes;
+ nodes->prev = nd;
+ nodes = nd;
+
+ print(" ==> %p\n", nd);
+
+ va_start(ap, n);
+ while (i < n) {
+ nn = va_arg(ap, struct node *);
+ print("# arg[%d]: %p\n", i, nn);
+ print("# (%s ...)\n", nn->name);
+ nd->elems[nd->n_elems++] = nn;
+ ++i;
+ }
+ va_end(ap);
+ return nd;
+}
+
+int const indent_step = 4;
+
+void print_indent(int depth) {
+ while (depth) {
+ if (depth-- % indent_step == 0) {
+ print("|");
+ } else {
+ print(" ");
+ }
+ }
+}
+
+void print_node(struct node *n, int depth) {
+ int i = 0;
+ print_indent(depth);
+ if (n->n_elems == 0) {
+ print("%s\n", n->name);
+ } else {
+ print("(%s\n", n->name);
+ for (i = 0; i < n->n_elems; ++i) {
+ print_node(n->elems[i], depth + indent_step);
+ }
+ print_indent(depth);
+ print(")\n");
+ }
+}
+
+int main(int argc, char **argv) {
+ if (argc == 2 && strcmp(argv[1], "-v") == 0) {
+ verbose = 1;
+ } else {
+ verbose = 0;
+ }
+ int ret = 0;
+ struct node *tmp;
+ memset(pushback, '\0', PUSHBACK_LEN);
+ ret = rsparse();
+ print("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes);
+ if (nodes) {
+ print_node(nodes, 0);
+ }
+ while (nodes) {
+ tmp = nodes;
+ nodes = tmp->next;
+ if (tmp->own_string) {
+ free((void*)tmp->name);
+ }
+ free(tmp);
+ }
+ return ret;
+}
+
+void rserror(char const *s) {
+ fprintf(stderr, "%s\n", s);
+}
--- /dev/null
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+%{
+#define YYERROR_VERBOSE
+#define YYSTYPE struct node *
+struct node;
+extern int yylex();
+extern void yyerror(char const *s);
+extern struct node *mk_node(char const *name, int n, ...);
+extern struct node *mk_atom(char *text);
+extern struct node *mk_none();
+extern struct node *ext_node(struct node *nd, int n, ...);
+extern void push_back(char c);
+extern char *yytext;
+%}
+%debug
+
+%token SHL
+%token SHR
+%token LE
+%token EQEQ
+%token NE
+%token GE
+%token ANDAND
+%token OROR
+%token SHLEQ
+%token SHREQ
+%token MINUSEQ
+%token ANDEQ
+%token OREQ
+%token PLUSEQ
+%token STAREQ
+%token SLASHEQ
+%token CARETEQ
+%token PERCENTEQ
+%token DOTDOT
+%token DOTDOTDOT
+%token MOD_SEP
+%token RARROW
+%token LARROW
+%token FAT_ARROW
+%token LIT_BYTE
+%token LIT_CHAR
+%token LIT_INTEGER
+%token LIT_FLOAT
+%token LIT_STR
+%token LIT_STR_RAW
+%token LIT_BYTE_STR
+%token LIT_BYTE_STR_RAW
+%token IDENT
+%token UNDERSCORE
+%token LIFETIME
+
+// keywords
+%token SELF
+%token STATIC
+%token AS
+%token BREAK
+%token CRATE
+%token ELSE
+%token ENUM
+%token EXTERN
+%token FALSE
+%token FN
+%token FOR
+%token IF
+%token IMPL
+%token IN
+%token LET
+%token LOOP
+%token MATCH
+%token MOD
+%token MOVE
+%token MUT
+%token PRIV
+%token PUB
+%token REF
+%token RETURN
+%token STRUCT
+%token TRUE
+%token TRAIT
+%token TYPE
+%token UNSAFE
+%token DEFAULT
+%token USE
+%token WHILE
+%token CONTINUE
+%token PROC
+%token BOX
+%token CONST
+%token WHERE
+%token TYPEOF
+%token INNER_DOC_COMMENT
+%token OUTER_DOC_COMMENT
+
+%token SHEBANG
+%token SHEBANG_LINE
+%token STATIC_LIFETIME
+
+ /*
+ Quoting from the Bison manual:
+
+ "Finally, the resolution of conflicts works by comparing the precedence
+ of the rule being considered with that of the lookahead token. If the
+ token's precedence is higher, the choice is to shift. If the rule's
+ precedence is higher, the choice is to reduce. If they have equal
+ precedence, the choice is made based on the associativity of that
+ precedence level. The verbose output file made by ‘-v’ (see Invoking
+ Bison) says how each conflict was resolved"
+ */
+
+// We expect no shift/reduce or reduce/reduce conflicts in this grammar;
+// all potential ambiguities are scrutinized and eliminated manually.
+%expect 0
+
+// fake-precedence symbol to cause '|' bars in lambda context to parse
+// at low precedence, permit things like |x| foo = bar, where '=' is
+// otherwise lower-precedence than '|'. Also used for proc() to cause
+// things like proc() a + b to parse as proc() { a + b }.
+%precedence LAMBDA
+
+%precedence SELF
+
+// MUT should be lower precedence than IDENT so that in the pat rule,
+// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]"
+%precedence MUT
+
+// IDENT needs to be lower than '{' so that 'foo {' is shifted when
+// trying to decide if we've got a struct-construction expr (esp. in
+// contexts like 'if foo { .')
+//
+// IDENT also needs to be lower precedence than '<' so that '<' in
+// 'foo:bar . <' is shifted (in a trait reference occurring in a
+// bounds list), parsing as foo:(bar<baz>) rather than (foo:bar)<baz>.
+%precedence IDENT
+
+// A couple fake-precedence symbols to use in rules associated with +
+// and < in trailing type contexts. These come up when you have a type
+// in the RHS of operator-AS, such as "foo as bar<baz>". The "<" there
+// has to be shifted so the parser keeps trying to parse a type, even
+// though it might well consider reducing the type "bar" and then
+// going on to "<" as a subsequent binop. The "+" case is with
+// trailing type-bounds ("foo as bar:A+B"), for the same reason.
+%precedence SHIFTPLUS
+
+%precedence MOD_SEP
+%precedence RARROW ':'
+
+// In where clauses, "for" should have greater precedence when used as
+// a higher ranked constraint than when used as the beginning of a
+// for_in_type (which is a ty)
+%precedence FORTYPE
+%precedence FOR
+
+// Binops & unops, and their precedences
+%precedence BOX
+%precedence BOXPLACE
+%nonassoc DOTDOT
+
+// RETURN needs to be lower-precedence than tokens that start
+// prefix_exprs
+%precedence RETURN
+
+%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ
+%right LARROW
+%left OROR
+%left ANDAND
+%left EQEQ NE
+%left '<' '>' LE GE
+%left '|'
+%left '^'
+%left '&'
+%left SHL SHR
+%left '+' '-'
+%precedence AS
+%left '*' '/' '%'
+%precedence '!'
+
+%precedence '{' '[' '(' '.'
+
+%precedence RANGE
+
+%start crate
+
+%%
+
+////////////////////////////////////////////////////////////////////////
+// Part 1: Items and attributes
+////////////////////////////////////////////////////////////////////////
+
+crate
+: maybe_shebang inner_attrs maybe_mod_items { mk_node("crate", 2, $2, $3); }
+| maybe_shebang maybe_mod_items { mk_node("crate", 1, $2); }
+;
+
+maybe_shebang
+: SHEBANG_LINE
+| %empty
+;
+
+maybe_inner_attrs
+: inner_attrs
+| %empty { $$ = mk_none(); }
+;
+
+inner_attrs
+: inner_attr { $$ = mk_node("InnerAttrs", 1, $1); }
+| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); }
+;
+
+inner_attr
+: SHEBANG '[' meta_item ']' { $$ = mk_node("InnerAttr", 1, $3); }
+| INNER_DOC_COMMENT { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); }
+;
+
+maybe_outer_attrs
+: outer_attrs
+| %empty { $$ = mk_none(); }
+;
+
+outer_attrs
+: outer_attr { $$ = mk_node("OuterAttrs", 1, $1); }
+| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); }
+;
+
+outer_attr
+: '#' '[' meta_item ']' { $$ = $3; }
+| OUTER_DOC_COMMENT { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); }
+;
+
+meta_item
+: ident { $$ = mk_node("MetaWord", 1, $1); }
+| ident '=' lit { $$ = mk_node("MetaNameValue", 2, $1, $3); }
+| ident '(' meta_seq ')' { $$ = mk_node("MetaList", 2, $1, $3); }
+| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); }
+;
+
+meta_seq
+: %empty { $$ = mk_none(); }
+| meta_item { $$ = mk_node("MetaItems", 1, $1); }
+| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); }
+;
+
+maybe_mod_items
+: mod_items
+| %empty { $$ = mk_none(); }
+;
+
+mod_items
+: mod_item { $$ = mk_node("Items", 1, $1); }
+| mod_items mod_item { $$ = ext_node($1, 1, $2); }
+;
+
+attrs_and_vis
+: maybe_outer_attrs visibility { $$ = mk_node("AttrsAndVis", 2, $1, $2); }
+;
+
+mod_item
+: attrs_and_vis item { $$ = mk_node("Item", 2, $1, $2); }
+;
+
+// items that can appear outside of a fn block
+item
+: stmt_item
+| item_macro
+;
+
+// items that can appear in "stmts"
+stmt_item
+: item_static
+| item_const
+| item_type
+| block_item
+| view_item
+;
+
+item_static
+: STATIC ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $2, $4, $6); }
+| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $3, $5, $7); }
+;
+
+item_const
+: CONST ident ':' ty '=' expr ';' { $$ = mk_node("ItemConst", 3, $2, $4, $6); }
+;
+
+item_macro
+: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
+| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
+| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
+;
+
+view_item
+: use_item
+| extern_fn_item
+| EXTERN CRATE ident ';' { $$ = mk_node("ViewItemExternCrate", 1, $3); }
+| EXTERN CRATE ident AS ident ';' { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); }
+;
+
+extern_fn_item
+: EXTERN maybe_abi item_fn { $$ = mk_node("ViewItemExternFn", 2, $2, $3); }
+;
+
+use_item
+: USE view_path ';' { $$ = mk_node("ViewItemUse", 1, $2); }
+;
+
+view_path
+: path_no_types_allowed { $$ = mk_node("ViewPathSimple", 1, $1); }
+| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); }
+| MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); }
+| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 2, $1, $4); }
+| MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $3); }
+| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); }
+| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); }
+| path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); }
+| '{' '}' { $$ = mk_atom("ViewPathListEmpty"); }
+| '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); }
+| '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); }
+| path_no_types_allowed AS ident { $$ = mk_node("ViewPathSimple", 2, $1, $3); }
+;
+
+block_item
+: item_fn
+| item_unsafe_fn
+| item_mod
+| item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); }
+| item_struct
+| item_enum
+| item_trait
+| item_impl
+;
+
+maybe_ty_ascription
+: ':' ty_sum { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_init_expr
+: '=' expr { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+// structs
+item_struct
+: STRUCT ident generic_params maybe_where_clause struct_decl_args
+{
+ $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5);
+}
+| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';'
+{
+ $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5);
+}
+| STRUCT ident generic_params maybe_where_clause ';'
+{
+ $$ = mk_node("ItemStruct", 3, $2, $3, $4);
+}
+;
+
+struct_decl_args
+: '{' struct_decl_fields '}' { $$ = $2; }
+| '{' struct_decl_fields ',' '}' { $$ = $2; }
+;
+
+struct_tuple_args
+: '(' struct_tuple_fields ')' { $$ = $2; }
+| '(' struct_tuple_fields ',' ')' { $$ = $2; }
+;
+
+struct_decl_fields
+: struct_decl_field { $$ = mk_node("StructFields", 1, $1); }
+| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); }
+| %empty { $$ = mk_none(); }
+;
+
+struct_decl_field
+: attrs_and_vis ident ':' ty_sum { $$ = mk_node("StructField", 3, $1, $2, $4); }
+;
+
+struct_tuple_fields
+: struct_tuple_field { $$ = mk_node("StructFields", 1, $1); }
+| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); }
+;
+
+struct_tuple_field
+: attrs_and_vis ty_sum { $$ = mk_node("StructField", 2, $1, $2); }
+;
+
+// enums
+item_enum
+: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node("ItemEnum", 0); }
+| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); }
+;
+
+enum_defs
+: enum_def { $$ = mk_node("EnumDefs", 1, $1); }
+| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); }
+| %empty { $$ = mk_none(); }
+;
+
+enum_def
+: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); }
+;
+
+enum_args
+: '{' struct_decl_fields '}' { $$ = mk_node("EnumArgs", 1, $2); }
+| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); }
+| '(' maybe_ty_sums ')' { $$ = mk_node("EnumArgs", 1, $2); }
+| '=' expr { $$ = mk_node("EnumArgs", 1, $2); }
+| %empty { $$ = mk_none(); }
+;
+
+item_mod
+: MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); }
+| MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); }
+| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); }
+;
+
+item_foreign_mod
+: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 1, $4); }
+| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); }
+;
+
+maybe_abi
+: str
+| %empty { $$ = mk_none(); }
+;
+
+maybe_foreign_items
+: foreign_items
+| %empty { $$ = mk_none(); }
+;
+
+foreign_items
+: foreign_item { $$ = mk_node("ForeignItems", 1, $1); }
+| foreign_items foreign_item { $$ = ext_node($1, 1, $2); }
+;
+
+foreign_item
+: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); }
+| attrs_and_vis item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $2); }
+| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $3); }
+;
+
+item_foreign_static
+: maybe_mut ident ':' ty ';' { $$ = mk_node("StaticItem", 3, $1, $2, $4); }
+;
+
+item_foreign_fn
+: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); }
+;
+
+fn_decl_allow_variadic
+: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); }
+;
+
+fn_params_allow_variadic
+: '(' ')' { $$ = mk_none(); }
+| '(' params ')' { $$ = $2; }
+| '(' params ',' ')' { $$ = $2; }
+| '(' params ',' DOTDOTDOT ')' { $$ = $2; }
+;
+
+visibility
+: PUB { $$ = mk_atom("Public"); }
+| %empty { $$ = mk_atom("Inherited"); }
+;
+
+idents_or_self
+: ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); }
+| ident_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); }
+| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); }
+;
+
+ident_or_self
+: ident
+| SELF { $$ = mk_atom(yytext); }
+;
+
+item_type
+: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); }
+;
+
+for_sized
+: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); }
+| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); }
+| %empty { $$ = mk_none(); }
+;
+
+item_trait
+: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}'
+{
+ $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9);
+}
+;
+
+maybe_trait_items
+: trait_items
+| %empty { $$ = mk_none(); }
+;
+
+trait_items
+: trait_item { $$ = mk_node("TraitItems", 1, $1); }
+| trait_items trait_item { $$ = ext_node($1, 1, $2); }
+;
+
+trait_item
+: trait_const
+| trait_type
+| trait_method
+;
+
+trait_const
+: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); }
+;
+
+maybe_const_default
+: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
+| %empty { $$ = mk_none(); }
+;
+
+trait_type
+: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
+;
+
+maybe_unsafe
+: UNSAFE { $$ = mk_atom("Unsafe"); }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_default_maybe_unsafe
+: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); }
+| DEFAULT { $$ = mk_atom("Default"); }
+| UNSAFE { $$ = mk_atom("Unsafe"); }
+| %empty { $$ = mk_none(); }
+
+trait_method
+: type_method { $$ = mk_node("Required", 1, $1); }
+| method { $$ = mk_node("Provided", 1, $1); }
+;
+
+type_method
+: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
+{
+ $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7);
+}
+| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
+{
+ $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9);
+}
+;
+
+method
+: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8);
+}
+| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
+}
+;
+
+impl_method
+: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8);
+}
+| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
+}
+;
+
+// There are two forms of impl:
+//
+// impl (<...>)? TY { ... }
+// impl (<...>)? TRAIT for TY { ... }
+//
+// Unfortunately since TY can begin with '<' itself -- as part of a
+// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL:
+// should we reduce one of the early rules of TY (such as maybe_once)
+// or shall we continue shifting into the generic_params list for the
+// impl?
+//
+// The production parser disambiguates a different case here by
+// permitting / requiring the user to provide parens around types when
+// they are ambiguous with traits. We do the same here, regrettably,
+// by splitting ty into ty and ty_prim.
+item_impl
+: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+{
+ $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8);
+}
+| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+{
+ $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10);
+}
+| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+{
+ $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10);
+}
+| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+{
+ $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11);
+}
+| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
+{
+ $$ = mk_node("ItemImplDefault", 3, $1, $3, $4);
+}
+| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
+{
+ $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4);
+}
+;
+
+maybe_impl_items
+: impl_items
+| %empty { $$ = mk_none(); }
+;
+
+impl_items
+: impl_item { $$ = mk_node("ImplItems", 1, $1); }
+| impl_item impl_items { $$ = ext_node($1, 1, $2); }
+;
+
+impl_item
+: impl_method
+| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); }
+| impl_const
+| impl_type
+;
+
+impl_const
+: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
+;
+
+impl_type
+: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
+;
+
+item_fn
+: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6);
+}
+;
+
+item_unsafe_fn
+: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7);
+}
+| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
+{
+ $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9);
+}
+;
+
+fn_decl
+: fn_params ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); }
+;
+
+fn_decl_with_self
+: fn_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); }
+;
+
+fn_decl_with_self_allow_anon_params
+: fn_anon_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); }
+;
+
+fn_params
+: '(' maybe_params ')' { $$ = $2; }
+;
+
+fn_anon_params
+: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); }
+| '(' ')' { $$ = mk_none(); }
+;
+
+fn_params_with_self
+: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); }
+| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); }
+| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); }
+| '(' maybe_params ')' { $$ = mk_node("SelfStatic", 1, $2); }
+;
+
+fn_anon_params_with_self
+: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); }
+| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); }
+| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); }
+| '(' maybe_anon_params ')' { $$ = mk_node("SelfStatic", 1, $2); }
+;
+
+maybe_params
+: params
+| params ','
+| %empty { $$ = mk_none(); }
+;
+
+params
+: param { $$ = mk_node("Args", 1, $1); }
+| params ',' param { $$ = ext_node($1, 1, $3); }
+;
+
+param
+: pat ':' ty_sum { $$ = mk_node("Arg", 2, $1, $3); }
+;
+
+inferrable_params
+: inferrable_param { $$ = mk_node("InferrableParams", 1, $1); }
+| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); }
+;
+
+inferrable_param
+: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); }
+;
+
+maybe_unboxed_closure_kind
+: %empty
+| ':'
+| '&' maybe_mut ':'
+;
+
+maybe_comma_params
+: ',' { $$ = mk_none(); }
+| ',' params { $$ = $2; }
+| ',' params ',' { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_comma_anon_params
+: ',' { $$ = mk_none(); }
+| ',' anon_params { $$ = $2; }
+| ',' anon_params ',' { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_anon_params
+: anon_params
+| anon_params ','
+| %empty { $$ = mk_none(); }
+;
+
+anon_params
+: anon_param { $$ = mk_node("Args", 1, $1); }
+| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); }
+;
+
+// anon means it's allowed to be anonymous (type-only), but it can
+// still have a name
+anon_param
+: named_arg ':' ty { $$ = mk_node("Arg", 2, $1, $3); }
+| ty
+;
+
+anon_params_allow_variadic_tail
+: ',' DOTDOTDOT { $$ = mk_none(); }
+| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); }
+| %empty { $$ = mk_none(); }
+;
+
+named_arg
+: ident
+| UNDERSCORE { $$ = mk_atom("PatWild"); }
+| '&' ident { $$ = $2; }
+| '&' UNDERSCORE { $$ = mk_atom("PatWild"); }
+| ANDAND ident { $$ = $2; }
+| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); }
+| MUT ident { $$ = $2; }
+;
+
+ret_ty
+: RARROW '!' { $$ = mk_none(); }
+| RARROW ty { $$ = mk_node("ret-ty", 1, $2); }
+| %prec IDENT %empty { $$ = mk_none(); }
+;
+
+generic_params
+: '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); }
+| '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); }
+| '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
+| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
+| '<' lifetimes ',' ty_params '>' { $$ = mk_node("Generics", 2, $2, $4); }
+| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); }
+| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); }
+| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); }
+| '<' ty_params '>' { $$ = mk_node("Generics", 2, mk_none(), $2); }
+| '<' ty_params ',' '>' { $$ = mk_node("Generics", 2, mk_none(), $2); }
+| '<' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); }
+| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_where_clause
+: %empty { $$ = mk_none(); }
+| where_clause
+;
+
+where_clause
+: WHERE where_predicates { $$ = mk_node("WhereClause", 1, $2); }
+| WHERE where_predicates ',' { $$ = mk_node("WhereClause", 1, $2); }
+;
+
+where_predicates
+: where_predicate { $$ = mk_node("WherePredicates", 1, $1); }
+| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); }
+;
+
+where_predicate
+: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); }
+| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); }
+;
+
+maybe_for_lifetimes
+: FOR '<' lifetimes '>' { $$ = mk_none(); }
+| %prec FORTYPE %empty { $$ = mk_none(); }
+
+ty_params
+: ty_param { $$ = mk_node("TyParams", 1, $1); }
+| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); }
+;
+
+// A path with no type parameters; e.g. `foo::bar::Baz`
+//
+// These show up in 'use' view-items, because these are processed
+// without respect to types.
+path_no_types_allowed
+: ident { $$ = mk_node("ViewPath", 1, $1); }
+| MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); }
+| SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
+| MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
+| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); }
+;
+
+// A path with a lifetime and type parameters, with no double colons
+// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`
+//
+// These show up in "trait references", the components of
+// type-parameter bounds lists, as well as in the prefix of the
+// path_generic_args_and_bounds rule, which is the full form of a
+// named typed expression.
+//
+// They do not have (nor need) an extra '::' before '<' because
+// unlike in expr context, there are no "less-than" type exprs to
+// be ambiguous with.
+path_generic_args_without_colons
+: %prec IDENT
+ ident { $$ = mk_node("components", 1, $1); }
+| %prec IDENT
+ ident generic_args { $$ = mk_node("components", 2, $1, $2); }
+| %prec IDENT
+ ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node("components", 2, $1, $3); }
+| %prec IDENT
+ path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); }
+| %prec IDENT
+ path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); }
+| %prec IDENT
+ path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); }
+;
+
+generic_args
+: '<' generic_values '>' { $$ = $2; }
+| '<' generic_values SHR { push_back('>'); $$ = $2; }
+| '<' generic_values GE { push_back('='); $$ = $2; }
+| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; }
+// If generic_args starts with "<<", the first arg must be a
+// TyQualifiedPath because that's the only type that can start with a
+// '<'. This rule parses that as the first ty_sum and then continues
+// with the rest of generic_values.
+| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; }
+| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; }
+| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; }
+| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; }
+;
+
+generic_values
+: maybe_lifetimes maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 2, $1, $2); }
+;
+
+maybe_ty_sums_and_or_bindings
+: ty_sums
+| ty_sums ','
+| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); }
+| bindings
+| bindings ','
+| %empty { $$ = mk_none(); }
+;
+
+maybe_bindings
+: ',' bindings { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+////////////////////////////////////////////////////////////////////////
+// Part 2: Patterns
+////////////////////////////////////////////////////////////////////////
+
+pat
+: UNDERSCORE { $$ = mk_atom("PatWild"); }
+| '&' pat { $$ = mk_node("PatRegion", 1, $2); }
+| '&' MUT pat { $$ = mk_node("PatRegion", 1, $3); }
+| ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); }
+| '(' ')' { $$ = mk_atom("PatUnit"); }
+| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); }
+| '(' pat_tup ',' ')' { $$ = mk_node("PatTup", 1, $2); }
+| '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); }
+| lit_or_path
+| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); }
+| path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); }
+| path_expr '(' DOTDOT ')' { $$ = mk_node("PatEnum", 1, $1); }
+| path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); }
+| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); }
+| binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); }
+| ident '@' pat { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); }
+| binding_mode ident '@' pat { $$ = mk_node("PatIdent", 3, $1, $2, $4); }
+| BOX pat { $$ = mk_node("PatUniq", 1, $2); }
+| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); }
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident
+{
+ $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10);
+}
+;
+
+pats_or
+: pat { $$ = mk_node("Pats", 1, $1); }
+| pats_or '|' pat { $$ = ext_node($1, 1, $3); }
+;
+
+binding_mode
+: REF { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); }
+| REF MUT { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); }
+| MUT { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); }
+;
+
+lit_or_path
+: path_expr { $$ = mk_node("PatLit", 1, $1); }
+| lit { $$ = mk_node("PatLit", 1, $1); }
+| '-' lit { $$ = mk_node("PatLit", 1, $2); }
+;
+
+pat_field
+: ident { $$ = mk_node("PatField", 1, $1); }
+| binding_mode ident { $$ = mk_node("PatField", 2, $1, $2); }
+| BOX ident { $$ = mk_node("PatField", 2, mk_atom("box"), $2); }
+| BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); }
+| ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); }
+| binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); }
+;
+
+pat_fields
+: pat_field { $$ = mk_node("PatFields", 1, $1); }
+| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); }
+;
+
+pat_struct
+: pat_fields { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); }
+| pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); }
+| pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); }
+| DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); }
+;
+
+pat_tup
+: pat { $$ = mk_node("pat_tup", 1, $1); }
+| pat_tup ',' pat { $$ = ext_node($1, 1, $3); }
+;
+
+pat_vec
+: pat_vec_elts { $$ = mk_node("PatVec", 2, $1, mk_none()); }
+| pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, mk_none()); }
+| pat_vec_elts DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); }
+| pat_vec_elts ',' DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); }
+| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $4); }
+| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $4); }
+| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $5); }
+| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $5); }
+| DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, mk_none(), $3); }
+| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, mk_none(), $3); }
+| DOTDOT { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); }
+| %empty { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); }
+;
+
+pat_vec_elts
+: pat { $$ = mk_node("PatVecElts", 1, $1); }
+| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); }
+;
+
+////////////////////////////////////////////////////////////////////////
+// Part 3: Types
+////////////////////////////////////////////////////////////////////////
+
+ty
+: ty_prim
+| ty_closure
+| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); }
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); }
+| '(' ty_sums ')' { $$ = mk_node("TyTup", 1, $2); }
+| '(' ty_sums ',' ')' { $$ = mk_node("TyTup", 1, $2); }
+| '(' ')' { $$ = mk_atom("TyNil"); }
+;
+
+ty_prim
+: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); }
+| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); }
+| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); }
+| BOX ty { $$ = mk_node("TyBox", 1, $2); }
+| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); }
+| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); }
+| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); }
+| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); }
+| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); }
+| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); }
+| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); }
+| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); }
+| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); }
+| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); }
+| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); }
+| UNDERSCORE { $$ = mk_atom("TyInfer"); }
+| ty_bare_fn
+| ty_proc
+| for_in_type
+;
+
+ty_bare_fn
+: FN ty_fn_decl { $$ = $2; }
+| UNSAFE FN ty_fn_decl { $$ = $3; }
+| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; }
+| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; }
+;
+
+ty_fn_decl
+: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); }
+;
+
+ty_closure
+: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); }
+| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); }
+| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $3, $4); }
+| OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); }
+;
+
+ty_proc
+: PROC generic_params fn_params maybe_bounds ret_ty { $$ = mk_node("TyProc", 4, $2, $3, $4, $5); }
+;
+
+for_in_type
+: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); }
+;
+
+for_in_type_suffix
+: ty_proc
+| ty_bare_fn
+| trait_ref
+| ty_closure
+;
+
+maybe_mut
+: MUT { $$ = mk_atom("MutMutable"); }
+| %prec MUT %empty { $$ = mk_atom("MutImmutable"); }
+;
+
+maybe_mut_or_const
+: MUT { $$ = mk_atom("MutMutable"); }
+| CONST { $$ = mk_atom("MutImmutable"); }
+| %empty { $$ = mk_atom("MutImmutable"); }
+;
+
+ty_qualified_path_and_generic_values
+: ty_qualified_path maybe_bindings
+{
+ $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2);
+}
+| ty_qualified_path ',' ty_sums maybe_bindings
+{
+ $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4);
+}
+;
+
+ty_qualified_path
+: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); }
+| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); }
+;
+
+maybe_ty_sums
+: ty_sums
+| ty_sums ','
+| %empty { $$ = mk_none(); }
+;
+
+ty_sums
+: ty_sum { $$ = mk_node("TySums", 1, $1); }
+| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); }
+;
+
+ty_sum
+: ty { $$ = mk_node("TySum", 1, $1); }
+| ty '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); }
+;
+
+ty_prim_sum
+: ty_prim { $$ = mk_node("TySum", 1, $1); }
+| ty_prim '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); }
+;
+
+maybe_ty_param_bounds
+: ':' ty_param_bounds { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+ty_param_bounds
+: boundseq
+| %empty { $$ = mk_none(); }
+;
+
+boundseq
+: polybound
+| boundseq '+' polybound { $$ = ext_node($1, 1, $3); }
+;
+
+polybound
+: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); }
+| bound
+| '?' bound { $$ = $2; }
+;
+
+bindings
+: binding { $$ = mk_node("Bindings", 1, $1); }
+| bindings ',' binding { $$ = ext_node($1, 1, $3); }
+;
+
+binding
+: ident '=' ty { mk_node("Binding", 2, $1, $3); }
+;
+
+ty_param
+: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 3, $1, $2, $3); }
+| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); }
+;
+
+maybe_bounds
+: %prec SHIFTPLUS
+ ':' bounds { $$ = $2; }
+| %prec SHIFTPLUS %empty { $$ = mk_none(); }
+;
+
+bounds
+: bound { $$ = mk_node("bounds", 1, $1); }
+| bounds '+' bound { $$ = ext_node($1, 1, $3); }
+;
+
+bound
+: lifetime
+| trait_ref
+;
+
+maybe_ltbounds
+: %prec SHIFTPLUS
+ ':' ltbounds { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+ltbounds
+: lifetime { $$ = mk_node("ltbounds", 1, $1); }
+| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); }
+;
+
+maybe_ty_default
+: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_lifetimes
+: lifetimes
+| lifetimes ','
+| %empty { $$ = mk_none(); }
+;
+
+lifetimes
+: lifetime_and_bounds { $$ = mk_node("Lifetimes", 1, $1); }
+| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); }
+;
+
+lifetime_and_bounds
+: LIFETIME maybe_ltbounds { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); }
+| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); }
+;
+
+lifetime
+: LIFETIME { $$ = mk_node("lifetime", 1, mk_atom(yytext)); }
+| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); }
+;
+
+trait_ref
+: %prec IDENT path_generic_args_without_colons
+| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; }
+;
+
+////////////////////////////////////////////////////////////////////////
+// Part 4: Blocks, statements, and expressions
+////////////////////////////////////////////////////////////////////////
+
+inner_attrs_and_block
+: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node("ExprBlock", 2, $2, $3); }
+;
+
+block
+: '{' maybe_stmts '}' { $$ = mk_node("ExprBlock", 1, $2); }
+;
+
+maybe_stmts
+: stmts
+| stmts nonblock_expr { $$ = ext_node($1, 1, $2); }
+| nonblock_expr
+| %empty { $$ = mk_none(); }
+;
+
+// There are two sub-grammars within a "stmts: exprs" derivation
+// depending on whether each stmt-expr is a block-expr form; this is to
+// handle the "semicolon rule" for stmt sequencing that permits
+// writing
+//
+// if foo { bar } 10
+//
+// as a sequence of two stmts (one if-expr stmt, one lit-10-expr
+// stmt). Unfortunately by permitting juxtaposition of exprs in
+// sequence like that, the non-block expr grammar has to have a
+// second limited sub-grammar that excludes the prefix exprs that
+// are ambiguous with binops. That is to say:
+//
+// {10} - 1
+//
+// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that
+// is to say, two statements rather than one, at least according to
+// the mainline rust parser.
+//
+// So we wind up with a 3-way split in exprs that occur in stmt lists:
+// block, nonblock-prefix, and nonblock-nonprefix.
+//
+// In non-stmts contexts, expr can relax this trichotomy.
+//
+// There is also one other expr subtype: nonparen_expr disallows exprs
+// surrounded by parens (including tuple expressions), this is
+// necessary for BOX (place) expressions, so a parens expr following
+// the BOX is always parsed as the place.
+
+stmts
+: stmt { $$ = mk_node("stmts", 1, $1); }
+| stmts stmt { $$ = ext_node($1, 1, $2); }
+;
+
+stmt
+: let
+| stmt_item
+| PUB stmt_item { $$ = $2; }
+| outer_attrs stmt_item { $$ = $2; }
+| outer_attrs PUB stmt_item { $$ = $3; }
+| full_block_expr
+| block
+| nonblock_expr ';'
+| ';' { $$ = mk_none(); }
+;
+
+maybe_exprs
+: exprs
+| exprs ','
+| %empty { $$ = mk_none(); }
+;
+
+maybe_expr
+: expr
+| %empty { $$ = mk_none(); }
+;
+
+exprs
+: expr { $$ = mk_node("exprs", 1, $1); }
+| exprs ',' expr { $$ = ext_node($1, 1, $3); }
+;
+
+path_expr
+: path_generic_args_with_colons
+| MOD_SEP path_generic_args_with_colons { $$ = $2; }
+| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); }
+;
+
+// A path with a lifetime and type parameters with double colons before
+// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>`
+//
+// These show up in expr context, in order to disambiguate from "less-than"
+// expressions.
+path_generic_args_with_colons
+: ident { $$ = mk_node("components", 1, $1); }
+| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); }
+| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); }
+;
+
+// the braces-delimited macro is a block_expr so it doesn't appear here
+macro_expr
+: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); }
+| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); }
+;
+
+nonblock_expr
+: lit { $$ = mk_node("ExprLit", 1, $1); }
+| %prec IDENT
+ path_expr { $$ = mk_node("ExprPath", 1, $1); }
+| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
+| macro_expr { $$ = mk_node("ExprMac", 1, $1); }
+| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); }
+| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); }
+| nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); }
+| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); }
+| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); }
+| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); }
+| CONTINUE { $$ = mk_node("ExprAgain", 0); }
+| CONTINUE lifetime { $$ = mk_node("ExprAgain", 1, $2); }
+| RETURN { $$ = mk_node("ExprRet", 0); }
+| RETURN expr { $$ = mk_node("ExprRet", 1, $2); }
+| BREAK { $$ = mk_node("ExprBreak", 0); }
+| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); }
+| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
+| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
+| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
+| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
+| nonblock_expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
+| nonblock_expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
+| nonblock_expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
+| nonblock_expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
+| nonblock_expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
+| nonblock_expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
+| nonblock_expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
+| nonblock_expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
+| nonblock_expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
+| nonblock_expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
+| nonblock_expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
+| nonblock_expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
+| nonblock_expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
+| nonblock_expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
+| nonblock_expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
+| nonblock_expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
+| nonblock_expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
+| nonblock_expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
+| nonblock_expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
+| nonblock_expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
+| nonblock_expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
+| nonblock_expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
+| nonblock_expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
+| nonblock_expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
+| nonblock_expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
+| nonblock_expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
+| nonblock_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
+| nonblock_expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); }
+| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
+| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
+| nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); }
+| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); }
+| %prec BOXPLACE BOX '(' maybe_expr ')' nonblock_expr { $$ = mk_node("ExprBox", 2, $3, $5); }
+| expr_qualified_path
+| nonblock_prefix_expr
+;
+
+expr
+: lit { $$ = mk_node("ExprLit", 1, $1); }
+| %prec IDENT
+ path_expr { $$ = mk_node("ExprPath", 1, $1); }
+| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
+| macro_expr { $$ = mk_node("ExprMac", 1, $1); }
+| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); }
+| expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); }
+| expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); }
+| expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); }
+| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); }
+| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); }
+| CONTINUE { $$ = mk_node("ExprAgain", 0); }
+| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); }
+| RETURN { $$ = mk_node("ExprRet", 0); }
+| RETURN expr { $$ = mk_node("ExprRet", 1, $2); }
+| BREAK { $$ = mk_node("ExprBreak", 0); }
+| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
+| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
+| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
+| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
+| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
+| expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
+| expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
+| expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
+| expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
+| expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
+| expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
+| expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
+| expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
+| expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
+| expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
+| expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
+| expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
+| expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
+| expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
+| expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
+| expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
+| expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
+| expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
+| expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
+| expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
+| expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
+| expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
+| expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
+| expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
+| expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
+| expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
+| expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
+| expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); }
+| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
+| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
+| expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); }
+| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); }
+| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 2, $3, $5); }
+| expr_qualified_path
+| block_expr
+| block
+| nonblock_prefix_expr
+;
+
+nonparen_expr
+: lit { $$ = mk_node("ExprLit", 1, $1); }
+| %prec IDENT
+ path_expr { $$ = mk_node("ExprPath", 1, $1); }
+| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
+| macro_expr { $$ = mk_node("ExprMac", 1, $1); }
+| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); }
+| nonparen_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); }
+| nonparen_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| nonparen_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); }
+| nonparen_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); }
+| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); }
+| CONTINUE { $$ = mk_node("ExprAgain", 0); }
+| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); }
+| RETURN { $$ = mk_node("ExprRet", 0); }
+| RETURN expr { $$ = mk_node("ExprRet", 1, $2); }
+| BREAK { $$ = mk_node("ExprBreak", 0); }
+| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
+| nonparen_expr LARROW nonparen_expr { $$ = mk_node("ExprInPlace", 2, $1, $3); }
+| nonparen_expr '=' nonparen_expr { $$ = mk_node("ExprAssign", 2, $1, $3); }
+| nonparen_expr SHLEQ nonparen_expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
+| nonparen_expr SHREQ nonparen_expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
+| nonparen_expr MINUSEQ nonparen_expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
+| nonparen_expr ANDEQ nonparen_expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
+| nonparen_expr OREQ nonparen_expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
+| nonparen_expr PLUSEQ nonparen_expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
+| nonparen_expr STAREQ nonparen_expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
+| nonparen_expr SLASHEQ nonparen_expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
+| nonparen_expr CARETEQ nonparen_expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
+| nonparen_expr PERCENTEQ nonparen_expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
+| nonparen_expr OROR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
+| nonparen_expr ANDAND nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
+| nonparen_expr EQEQ nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
+| nonparen_expr NE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
+| nonparen_expr '<' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
+| nonparen_expr '>' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
+| nonparen_expr LE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
+| nonparen_expr GE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
+| nonparen_expr '|' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
+| nonparen_expr '^' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
+| nonparen_expr '&' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
+| nonparen_expr SHL nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
+| nonparen_expr SHR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
+| nonparen_expr '+' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
+| nonparen_expr '-' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
+| nonparen_expr '*' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
+| nonparen_expr '/' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
+| nonparen_expr '%' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
+| nonparen_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
+| nonparen_expr DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, $1, $3); }
+| DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
+| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
+| nonparen_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); }
+| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); }
+| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 1, $3, $5); }
+| expr_qualified_path
+| block_expr
+| block
+| nonblock_prefix_expr
+;
+
+expr_nostruct
+: lit { $$ = mk_node("ExprLit", 1, $1); }
+| %prec IDENT
+ path_expr { $$ = mk_node("ExprPath", 1, $1); }
+| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
+| macro_expr { $$ = mk_node("ExprMac", 1, $1); }
+| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); }
+| expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); }
+| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); }
+| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); }
+| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); }
+| CONTINUE { $$ = mk_node("ExprAgain", 0); }
+| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); }
+| RETURN { $$ = mk_node("ExprRet", 0); }
+| RETURN expr { $$ = mk_node("ExprRet", 1, $2); }
+| BREAK { $$ = mk_node("ExprBreak", 0); }
+| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); }
+| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); }
+| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); }
+| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
+| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
+| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
+| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
+| expr_nostruct OREQ expr_nostruct { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
+| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
+| expr_nostruct STAREQ expr_nostruct { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
+| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
+| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
+| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
+| expr_nostruct OROR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
+| expr_nostruct ANDAND expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
+| expr_nostruct EQEQ expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
+| expr_nostruct NE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
+| expr_nostruct '<' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
+| expr_nostruct '>' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
+| expr_nostruct LE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
+| expr_nostruct GE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
+| expr_nostruct '|' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
+| expr_nostruct '^' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
+| expr_nostruct '&' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
+| expr_nostruct SHL expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
+| expr_nostruct SHR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
+| expr_nostruct '+' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
+| expr_nostruct '-' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
+| expr_nostruct '*' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
+| expr_nostruct '/' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
+| expr_nostruct '%' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
+| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
+| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, $1, $3); }
+| DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
+| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
+| expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); }
+| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); }
+| %prec BOXPLACE BOX '(' maybe_expr ')' expr_nostruct { $$ = mk_node("ExprBox", 1, $3, $5); }
+| expr_qualified_path
+| block_expr
+| block
+| nonblock_prefix_expr_nostruct
+;
+
+nonblock_prefix_expr_nostruct
+: '-' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); }
+| '!' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); }
+| '*' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); }
+| '&' maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 2, $2, $3); }
+| ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
+| lambda_expr_nostruct
+| MOVE lambda_expr_nostruct { $$ = $2; }
+| proc_expr_nostruct
+;
+
+nonblock_prefix_expr
+: '-' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); }
+| '!' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); }
+| '*' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); }
+| '&' maybe_mut expr { $$ = mk_node("ExprAddrOf", 2, $2, $3); }
+| ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
+| lambda_expr
+| MOVE lambda_expr { $$ = $2; }
+| proc_expr
+;
+
+expr_qualified_path
+: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params
+{
+ $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7);
+}
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident
+{
+ $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10);
+}
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident
+{
+ $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11);
+}
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args
+{
+ $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11);
+}
+| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args
+{
+ $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12);
+}
+
+maybe_qpath_params
+: MOD_SEP generic_args { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+maybe_as_trait_ref
+: AS trait_ref { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+lambda_expr
+: %prec LAMBDA
+ OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
+| %prec LAMBDA
+ '|' maybe_unboxed_closure_kind '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $4, $5); }
+| %prec LAMBDA
+ '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); }
+| %prec LAMBDA
+ '|' '&' maybe_mut ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $5, $7, $8); }
+| %prec LAMBDA
+ '|' ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $3, $5, $6); }
+;
+
+lambda_expr_nostruct
+: %prec LAMBDA
+ OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); }
+| %prec LAMBDA
+ '|' maybe_unboxed_closure_kind '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $4); }
+| %prec LAMBDA
+ '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); }
+| %prec LAMBDA
+ '|' '&' maybe_mut ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $5, $7); }
+| %prec LAMBDA
+ '|' ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $3, $5); }
+
+;
+
+proc_expr
+: %prec LAMBDA
+ PROC '(' ')' expr { $$ = mk_node("ExprProc", 2, mk_none(), $4); }
+| %prec LAMBDA
+ PROC '(' inferrable_params ')' expr { $$ = mk_node("ExprProc", 2, $3, $5); }
+;
+
+proc_expr_nostruct
+: %prec LAMBDA
+ PROC '(' ')' expr_nostruct { $$ = mk_node("ExprProc", 2, mk_none(), $4); }
+| %prec LAMBDA
+ PROC '(' inferrable_params ')' expr_nostruct { $$ = mk_node("ExprProc", 2, $3, $5); }
+;
+
+vec_expr
+: maybe_exprs
+| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); }
+;
+
+struct_expr_fields
+: field_inits
+| field_inits ','
+| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); }
+;
+
+maybe_field_inits
+: field_inits
+| field_inits ','
+| %empty { $$ = mk_none(); }
+;
+
+field_inits
+: field_init { $$ = mk_node("FieldInits", 1, $1); }
+| field_inits ',' field_init { $$ = ext_node($1, 1, $3); }
+;
+
+field_init
+: ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); }
+;
+
+default_field_init
+: DOTDOT expr { $$ = mk_node("DefaultFieldInit", 1, $2); }
+;
+
+block_expr
+: expr_match
+| expr_if
+| expr_if_let
+| expr_while
+| expr_while_let
+| expr_loop
+| expr_for
+| UNSAFE block { $$ = mk_node("UnsafeBlock", 1, $2); }
+| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); }
+;
+
+full_block_expr
+: block_expr
+| full_block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); }
+| full_block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
+| full_block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
+| full_block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); }
+;
+
+expr_match
+: MATCH expr_nostruct '{' '}' { $$ = mk_node("ExprMatch", 1, $2); }
+| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node("ExprMatch", 2, $2, $4); }
+| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); }
+| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); }
+;
+
+match_clauses
+: match_clause { $$ = mk_node("Arms", 1, $1); }
+| match_clauses match_clause { $$ = ext_node($1, 1, $2); }
+;
+
+match_clause
+: nonblock_match_clause ','
+| block_match_clause
+| block_match_clause ','
+;
+
+nonblock_match_clause
+: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
+| maybe_outer_attrs pats_or maybe_guard FAT_ARROW full_block_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
+;
+
+block_match_clause
+: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
+;
+
+maybe_guard
+: IF expr_nostruct { $$ = $2; }
+| %empty { $$ = mk_none(); }
+;
+
+expr_if
+: IF expr_nostruct block { $$ = mk_node("ExprIf", 2, $2, $3); }
+| IF expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIf", 3, $2, $3, $5); }
+;
+
+expr_if_let
+: IF LET pat '=' expr_nostruct block { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); }
+| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); }
+;
+
+block_or_if
+: block
+| expr_if
+| expr_if_let
+;
+
+expr_while
+: maybe_label WHILE expr_nostruct block { $$ = mk_node("ExprWhile", 3, $1, $3, $4); }
+;
+
+expr_while_let
+: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); }
+;
+
+expr_loop
+: maybe_label LOOP block { $$ = mk_node("ExprLoop", 2, $1, $3); }
+;
+
+expr_for
+: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); }
+;
+
+maybe_label
+: lifetime ':'
+| %empty { $$ = mk_none(); }
+;
+
+let
+: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); }
+;
+
+////////////////////////////////////////////////////////////////////////
+// Part 5: Macros and misc. rules
+////////////////////////////////////////////////////////////////////////
+
+lit
+: LIT_BYTE { $$ = mk_node("LitByte", 1, mk_atom(yytext)); }
+| LIT_CHAR { $$ = mk_node("LitChar", 1, mk_atom(yytext)); }
+| LIT_INTEGER { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); }
+| LIT_FLOAT { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); }
+| TRUE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); }
+| FALSE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); }
+| str
+;
+
+str
+: LIT_STR { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); }
+| LIT_STR_RAW { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); }
+| LIT_BYTE_STR { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); }
+| LIT_BYTE_STR_RAW { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); }
+;
+
+maybe_ident
+: %empty { $$ = mk_none(); }
+| ident
+;
+
+ident
+: IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); }
+;
+
+unpaired_token
+: SHL { $$ = mk_atom(yytext); }
+| SHR { $$ = mk_atom(yytext); }
+| LE { $$ = mk_atom(yytext); }
+| EQEQ { $$ = mk_atom(yytext); }
+| NE { $$ = mk_atom(yytext); }
+| GE { $$ = mk_atom(yytext); }
+| ANDAND { $$ = mk_atom(yytext); }
+| OROR { $$ = mk_atom(yytext); }
+| LARROW { $$ = mk_atom(yytext); }
+| SHLEQ { $$ = mk_atom(yytext); }
+| SHREQ { $$ = mk_atom(yytext); }
+| MINUSEQ { $$ = mk_atom(yytext); }
+| ANDEQ { $$ = mk_atom(yytext); }
+| OREQ { $$ = mk_atom(yytext); }
+| PLUSEQ { $$ = mk_atom(yytext); }
+| STAREQ { $$ = mk_atom(yytext); }
+| SLASHEQ { $$ = mk_atom(yytext); }
+| CARETEQ { $$ = mk_atom(yytext); }
+| PERCENTEQ { $$ = mk_atom(yytext); }
+| DOTDOT { $$ = mk_atom(yytext); }
+| DOTDOTDOT { $$ = mk_atom(yytext); }
+| MOD_SEP { $$ = mk_atom(yytext); }
+| RARROW { $$ = mk_atom(yytext); }
+| FAT_ARROW { $$ = mk_atom(yytext); }
+| LIT_BYTE { $$ = mk_atom(yytext); }
+| LIT_CHAR { $$ = mk_atom(yytext); }
+| LIT_INTEGER { $$ = mk_atom(yytext); }
+| LIT_FLOAT { $$ = mk_atom(yytext); }
+| LIT_STR { $$ = mk_atom(yytext); }
+| LIT_STR_RAW { $$ = mk_atom(yytext); }
+| LIT_BYTE_STR { $$ = mk_atom(yytext); }
+| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); }
+| IDENT { $$ = mk_atom(yytext); }
+| UNDERSCORE { $$ = mk_atom(yytext); }
+| LIFETIME { $$ = mk_atom(yytext); }
+| SELF { $$ = mk_atom(yytext); }
+| STATIC { $$ = mk_atom(yytext); }
+| AS { $$ = mk_atom(yytext); }
+| BREAK { $$ = mk_atom(yytext); }
+| CRATE { $$ = mk_atom(yytext); }
+| ELSE { $$ = mk_atom(yytext); }
+| ENUM { $$ = mk_atom(yytext); }
+| EXTERN { $$ = mk_atom(yytext); }
+| FALSE { $$ = mk_atom(yytext); }
+| FN { $$ = mk_atom(yytext); }
+| FOR { $$ = mk_atom(yytext); }
+| IF { $$ = mk_atom(yytext); }
+| IMPL { $$ = mk_atom(yytext); }
+| IN { $$ = mk_atom(yytext); }
+| LET { $$ = mk_atom(yytext); }
+| LOOP { $$ = mk_atom(yytext); }
+| MATCH { $$ = mk_atom(yytext); }
+| MOD { $$ = mk_atom(yytext); }
+| MOVE { $$ = mk_atom(yytext); }
+| MUT { $$ = mk_atom(yytext); }
+| PRIV { $$ = mk_atom(yytext); }
+| PUB { $$ = mk_atom(yytext); }
+| REF { $$ = mk_atom(yytext); }
+| RETURN { $$ = mk_atom(yytext); }
+| STRUCT { $$ = mk_atom(yytext); }
+| TRUE { $$ = mk_atom(yytext); }
+| TRAIT { $$ = mk_atom(yytext); }
+| TYPE { $$ = mk_atom(yytext); }
+| UNSAFE { $$ = mk_atom(yytext); }
+| USE { $$ = mk_atom(yytext); }
+| WHILE { $$ = mk_atom(yytext); }
+| CONTINUE { $$ = mk_atom(yytext); }
+| PROC { $$ = mk_atom(yytext); }
+| BOX { $$ = mk_atom(yytext); }
+| CONST { $$ = mk_atom(yytext); }
+| WHERE { $$ = mk_atom(yytext); }
+| TYPEOF { $$ = mk_atom(yytext); }
+| INNER_DOC_COMMENT { $$ = mk_atom(yytext); }
+| OUTER_DOC_COMMENT { $$ = mk_atom(yytext); }
+| SHEBANG { $$ = mk_atom(yytext); }
+| STATIC_LIFETIME { $$ = mk_atom(yytext); }
+| ';' { $$ = mk_atom(yytext); }
+| ',' { $$ = mk_atom(yytext); }
+| '.' { $$ = mk_atom(yytext); }
+| '@' { $$ = mk_atom(yytext); }
+| '#' { $$ = mk_atom(yytext); }
+| '~' { $$ = mk_atom(yytext); }
+| ':' { $$ = mk_atom(yytext); }
+| '$' { $$ = mk_atom(yytext); }
+| '=' { $$ = mk_atom(yytext); }
+| '?' { $$ = mk_atom(yytext); }
+| '!' { $$ = mk_atom(yytext); }
+| '<' { $$ = mk_atom(yytext); }
+| '>' { $$ = mk_atom(yytext); }
+| '-' { $$ = mk_atom(yytext); }
+| '&' { $$ = mk_atom(yytext); }
+| '|' { $$ = mk_atom(yytext); }
+| '+' { $$ = mk_atom(yytext); }
+| '*' { $$ = mk_atom(yytext); }
+| '/' { $$ = mk_atom(yytext); }
+| '^' { $$ = mk_atom(yytext); }
+| '%' { $$ = mk_atom(yytext); }
+;
+
+token_trees
+: %empty { $$ = mk_node("TokenTrees", 0); }
+| token_trees token_tree { $$ = ext_node($1, 1, $2); }
+;
+
+token_tree
+: delimited_token_trees
+| unpaired_token { $$ = mk_node("TTTok", 1, $1); }
+;
+
+delimited_token_trees
+: parens_delimited_token_trees
+| braces_delimited_token_trees
+| brackets_delimited_token_trees
+;
+
+parens_delimited_token_trees
+: '(' token_trees ')'
+{
+ $$ = mk_node("TTDelim", 3,
+ mk_node("TTTok", 1, mk_atom("(")),
+ $2,
+ mk_node("TTTok", 1, mk_atom(")")));
+}
+;
+
+braces_delimited_token_trees
+: '{' token_trees '}'
+{
+ $$ = mk_node("TTDelim", 3,
+ mk_node("TTTok", 1, mk_atom("{")),
+ $2,
+ mk_node("TTTok", 1, mk_atom("}")));
+}
+;
+
+brackets_delimited_token_trees
+: '[' token_trees ']'
+{
+ $$ = mk_node("TTDelim", 3,
+ mk_node("TTTok", 1, mk_atom("[")),
+ $2,
+ mk_node("TTTok", 1, mk_atom("]")));
+}
+;
\ No newline at end of file
--- /dev/null
+Rust's lexical grammar is not context-free. Raw string literals are the source
+of the problem. Informally, a raw string literal is an `r`, followed by `N`
+hashes (where N can be zero), a quote, any characters, then a quote followed
+by `N` hashes. Critically, once inside the first pair of quotes,
+another quote cannot be followed by `N` consecutive hashes. e.g.
+`r###""###"###` is invalid.
+
+This grammar describes this as best possible:
+
+ R -> 'r' S
+ S -> '"' B '"'
+ S -> '#' S '#'
+ B -> . B
+ B -> ε
+
+Where `.` represents any character, and `ε` the empty string. Consider the
+string `r#""#"#`. This string is not a valid raw string literal, but can be
+accepted as one by the above grammar, using the derivation:
+
+ R : #""#"#
+ S : ""#"
+ S : "#
+ B : #
+ B : ε
+
+(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the
+string.) The difficulty arises from the fact that it is fundamentally
+context-sensitive. In particular, the context needed is the number of hashes.
+
+To prove that Rust's string literals are not context-free, we will use
+the fact that context-free languages are closed under intersection with
+regular languages, and the
+[pumping lemma for context-free languages](https://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages).
+
+Consider the regular language `R = r#+""#*"#+`. If Rust's raw string literals are
+context-free, then their intersection with `R`, `R'`, should also be context-free.
+Therefore, to prove that raw string literals are not context-free,
+it is sufficient to prove that `R'` is not context-free.
+
+The language `R'` is `{r#^n""#^m"#^n | m < n}`.
+
+Assume `R'` *is* context-free. Then `R'` has some pumping length `p > 0` for which
+the pumping lemma applies. Consider the following string `s` in `R'`:
+
+`r#^p""#^{p-1}"#^p`
+
+e.g. for `p = 2`: `s = r##""#"##`
+
+Then `s = uvwxy` for some choice of `uvwxy` such that `vx` is non-empty,
+`|vwx| < p+1`, and `uv^iwx^iy` is in `R'` for all `i >= 0`.
+
+Neither `v` nor `x` can contain a `"` or `r`, as the number of these characters
+in any string in `R'` is fixed. So `v` and `x` contain only hashes.
+Consequently, of the three sequences of hashes, `v` and `x` combined
+can only pump two of them.
+If we ever choose the central sequence of hashes, then one of the outer sequences
+will not grow when we pump, leading to an imbalance between the outer sequences.
+Therefore, we must pump both outer sequences of hashes. However,
+there are `p+2` characters between these two sequences of hashes, and `|vwx|` must
+be less than `p+1`. Therefore we have a contradiction, and `R'` must not be
+context-free.
+
+Since `R'` is not context-free, it follows that the Rust's raw string literals
+must not be context-free.
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright 2015 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 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# ignore-tidy-linelength
+
+import sys
+
+import os
+import subprocess
+import argparse
+
+# usage: testparser.py [-h] [-p PARSER [PARSER ...]] -s SOURCE_DIR
+
+# Parsers should read from stdin and return exit status 0 for a
+# successful parse, and nonzero for an unsuccessful parse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('-p', '--parser', nargs='+')
+parser.add_argument('-s', '--source-dir', nargs=1, required=True)
+args = parser.parse_args(sys.argv[1:])
+
+total = 0
+ok = {}
+bad = {}
+for parser in args.parser:
+ ok[parser] = 0
+ bad[parser] = []
+devnull = open(os.devnull, 'w')
+print("\n")
+
+for base, dirs, files in os.walk(args.source_dir[0]):
+ for f in filter(lambda p: p.endswith('.rs'), files):
+ p = os.path.join(base, f)
+ parse_fail = 'parse-fail' in p
+ if sys.version_info.major == 3:
+ lines = open(p, encoding='utf-8').readlines()
+ else:
+ lines = open(p).readlines()
+ if any('ignore-test' in line or 'ignore-lexer-test' in line for line in lines):
+ continue
+ total += 1
+ for parser in args.parser:
+ if subprocess.call(parser, stdin=open(p), stderr=subprocess.STDOUT, stdout=devnull) == 0:
+ if parse_fail:
+ bad[parser].append(p)
+ else:
+ ok[parser] += 1
+ else:
+ if parse_fail:
+ ok[parser] += 1
+ else:
+ bad[parser].append(p)
+ parser_stats = ', '.join(['{}: {}'.format(parser, ok[parser]) for parser in args.parser])
+ sys.stdout.write("\033[K\r total: {}, {}, scanned {}"
+ .format(total, os.path.relpath(parser_stats), os.path.relpath(p)))
+
+devnull.close()
+
+print("\n")
+
+for parser in args.parser:
+ filename = os.path.basename(parser) + '.bad'
+ print("writing {} files that did not yield the correct result with {} to {}".format(len(bad[parser]), parser, filename))
+ with open(filename, "w") as f:
+ for p in bad[parser]:
+ f.write(p)
+ f.write("\n")
--- /dev/null
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Token {
+ SHL = 257, // Parser generators reserve 0-256 for char literals
+ SHR,
+ LE,
+ EQEQ,
+ NE,
+ GE,
+ ANDAND,
+ OROR,
+ SHLEQ,
+ SHREQ,
+ MINUSEQ,
+ ANDEQ,
+ OREQ,
+ PLUSEQ,
+ STAREQ,
+ SLASHEQ,
+ CARETEQ,
+ PERCENTEQ,
+ DOTDOT,
+ DOTDOTDOT,
+ MOD_SEP,
+ RARROW,
+ FAT_ARROW,
+ LIT_BYTE,
+ LIT_CHAR,
+ LIT_INTEGER,
+ LIT_FLOAT,
+ LIT_STR,
+ LIT_STR_RAW,
+ LIT_BYTE_STR,
+ LIT_BYTE_STR_RAW,
+ IDENT,
+ UNDERSCORE,
+ LIFETIME,
+
+ // keywords
+ SELF,
+ STATIC,
+ AS,
+ BREAK,
+ CRATE,
+ ELSE,
+ ENUM,
+ EXTERN,
+ FALSE,
+ FN,
+ FOR,
+ IF,
+ IMPL,
+ IN,
+ LET,
+ LOOP,
+ MATCH,
+ MOD,
+ MOVE,
+ MUT,
+ PRIV,
+ PUB,
+ REF,
+ RETURN,
+ STRUCT,
+ TRUE,
+ TRAIT,
+ TYPE,
+ UNSAFE,
+ USE,
+ WHILE,
+ CONTINUE,
+ PROC,
+ BOX,
+ CONST,
+ WHERE,
+ TYPEOF,
+ INNER_DOC_COMMENT,
+ OUTER_DOC_COMMENT,
+
+ SHEBANG,
+ SHEBANG_LINE,
+ STATIC_LIFETIME
+};
fn check_inline(&self, attr: &ast::Attribute, target: Target) {
if target != Target::Fn {
struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
- .span_label(attr.span, &format!("requires a function"))
+ .span_label(attr.span, "requires a function")
.emit();
}
}
_ => continue,
};
struct_span_err!(self.sess, attr.span, E0517, "{}", message)
- .span_label(attr.span, &format!("requires {}", label))
+ .span_label(attr.span, format!("requires {}", label))
.emit();
}
if conflicting_reprs > 1 {
/// to monitor future changes to `Visitor` in case a new method with a
/// new default implementation gets introduced.)
pub trait Visitor<'v> : Sized {
- /// Invokes the suitable visitor method for the given `Node`
- /// extracted from the hir map.
- fn visit_hir_map_node(&mut self, node: map::Node<'v>) {
- match node {
- map::NodeItem(a) => self.visit_item(a),
- map::NodeForeignItem(a) => self.visit_foreign_item(a),
- map::NodeTraitItem(a) => self.visit_trait_item(a),
- map::NodeImplItem(a) => self.visit_impl_item(a),
- map::NodeExpr(a) => self.visit_expr(a),
- map::NodeStmt(a) => self.visit_stmt(a),
- map::NodeTy(a) => self.visit_ty(a),
- map::NodePat(a) => self.visit_pat(a),
- map::NodeBlock(a) => self.visit_block(a),
- _ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node)
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// Nested items.
self.local_def_id(self.body_owner(id))
}
- /// Given a body owner's id, returns the `BodyId` associated with it.
- pub fn body_owned_by(&self, id: NodeId) -> BodyId {
+ /// Given a node id, returns the `BodyId` associated with it,
+ /// if the node is a body owner, otherwise returns `None`.
+ pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> {
if let Some(entry) = self.find_entry(id) {
if let Some(body_id) = entry.associated_body() {
// For item-like things and closures, the associated
// body has its own distinct id, and that is returned
// by `associated_body`.
- body_id
+ Some(body_id)
} else {
// For some expressions, the expression is its own body.
if let EntryExpr(_, expr) = entry {
- BodyId { node_id: expr.id }
+ Some(BodyId { node_id: expr.id })
} else {
- span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
+ None
}
}
} else {
}
}
+ /// Given a body owner's id, returns the `BodyId` associated with it.
+ pub fn body_owned_by(&self, id: NodeId) -> BodyId {
+ self.maybe_body_owned_by(id).unwrap_or_else(|| {
+ span_bug!(self.span(id), "body_owned_by: {} has no associated body",
+ self.node_to_string(id));
+ })
+ }
+
pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
match self.get(id) {
NodeItem(&Item { node: ItemTrait(..), .. }) => id,
}
}
- diag.span_label(span, &terr);
+ diag.span_label(span, terr.to_string());
if let Some((sp, msg)) = secondary_span {
- diag.span_label(sp, &msg);
+ diag.span_label(sp, msg);
}
self.note_error_origin(diag, &cause);
"{}({}) overruled by outer forbid({})",
level.as_str(), lint_name,
lint_name);
- diag_builder.span_label(span, &format!("overruled by previous forbid"));
+ diag_builder.span_label(span, "overruled by previous forbid");
match now_source {
LintSource::Default => &mut diag_builder,
LintSource::Node(_, forbid_source_span) => {
diag_builder.span_label(forbid_source_span,
- &format!("`forbid` level set here"))
+ "`forbid` level set here")
},
LintSource::CommandLine(_) => {
diag_builder.note("`forbid` lint level was set on command line")
{
match self.description() {
ConstEvalErrDescription::Simple(message) => {
- diag.span_label(self.span, &message);
+ diag.span_label(self.span, message);
}
}
struct_span_err!(
self.tcx.sess, span, E0133,
"{} requires unsafe function or block", description)
- .span_label(span, &description)
+ .span_label(span, description)
.emit();
}
}
} else {
struct_span_err!(ctxt.session, item.span, E0137,
"multiple functions with a #[main] attribute")
- .span_label(item.span, &format!("additional #[main] function"))
- .span_label(ctxt.attr_main_fn.unwrap().1, &format!("first #[main] function"))
+ .span_label(item.span, "additional #[main] function")
+ .span_label(ctxt.attr_main_fn.unwrap().1, "first #[main] function")
.emit();
}
},
ctxt.session, item.span, E0138,
"multiple 'start' functions")
.span_label(ctxt.start_fn.unwrap().1,
- &format!("previous `start` function here"))
- .span_label(item.span, &format!("multiple `start` functions"))
+ "previous `start` function here")
+ .span_label(item.span, "multiple `start` functions")
.emit();
}
},
struct_span_err!(self.infcx.tcx.sess, span, E0591,
"`{}` is zero-sized and can't be transmuted to `{}`",
from, to)
- .span_note(span, &format!("cast with `as` to a pointer instead"))
+ .span_note(span, "cast with `as` to a pointer instead")
.emit();
return;
}
from, skeleton_string(from, sk_from),
to, skeleton_string(to, sk_to))
.span_label(span,
- &format!("transmuting between {} and {}",
+ format!("transmuting between {} and {}",
skeleton_string(from, sk_from),
skeleton_string(to, sk_to)))
.emit();
use std::rc::Rc;
use serialize;
use syntax::codemap;
-use syntax::ast::{self, NodeId};
+use syntax::ast;
use syntax_pos::Span;
use ty::TyCtxt;
use ty::maps::Providers;
-use hir; use hir::def_id::DefId;
-use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
+use hir;
+use hir::def_id::DefId;
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
+use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
+use mir::transform::MirSource;
pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
}
}
- intravisit::walk_expr(visitor, expr);
+ match expr.node {
+ // Manually recurse over closures, because they are the only
+ // case of nested bodies that share the parent environment.
+ hir::ExprClosure(.., body, _) => {
+ let body = visitor.tcx.hir.body(body);
+ visitor.visit_body(body);
+ }
+
+ _ => intravisit::walk_expr(visitor, expr)
+ }
+
visitor.cx = prev_cx;
}
}
}
-fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, walk: F)
- where F: FnOnce(&mut RegionResolutionVisitor<'a, 'tcx>)
-{
- // Items create a new outer block scope as far as we're concerned.
- let prev_cx = visitor.cx;
- let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
- visitor.cx = Context {
- root_id: None,
- var_parent: None,
- parent: None,
- };
- walk(visitor);
- visitor.cx = prev_cx;
- visitor.terminating_scopes = prev_ts;
-}
-
-fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
- kind: FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
- body_id: hir::BodyId,
- sp: Span,
- id: ast::NodeId) {
- visitor.cx.parent = Some(visitor.new_code_extent(
- CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
-
- debug!("region::resolve_fn(id={:?}, \
- span={:?}, \
- body.id={:?}, \
- cx.parent={:?})",
- id,
- visitor.tcx.sess.codemap().span_to_string(sp),
- body_id,
- visitor.cx.parent);
-
- let fn_decl_scope = visitor.new_code_extent(
- CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
-
- if let Some(root_id) = visitor.cx.root_id {
- visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
- }
-
- let outer_cx = visitor.cx;
- let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
- visitor.terminating_scopes.insert(body_id.node_id);
-
- // The arguments and `self` are parented to the fn.
- visitor.cx = Context {
- root_id: Some(body_id.node_id),
- parent: None,
- var_parent: Some(fn_decl_scope),
- };
-
- intravisit::walk_fn_decl(visitor, decl);
- intravisit::walk_fn_kind(visitor, kind);
-
- // The body of the every fn is a root scope.
- visitor.cx = Context {
- root_id: Some(body_id.node_id),
- parent: Some(fn_decl_scope),
- var_parent: Some(fn_decl_scope),
- };
- visitor.visit_nested_body(body_id);
-
- // Restore context we had at the start.
- visitor.cx = outer_cx;
- visitor.terminating_scopes = outer_ts;
-}
-
impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
pub fn intern_code_extent(&mut self,
data: CodeExtentData,
impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.map)
+ NestedVisitorMap::None
}
fn visit_block(&mut self, b: &'tcx Block) {
resolve_block(self, b);
}
- fn visit_item(&mut self, i: &'tcx Item) {
- resolve_item_like(self, |this| intravisit::walk_item(this, i));
- }
+ fn visit_body(&mut self, body: &'tcx hir::Body) {
+ let body_id = body.id();
+ let owner_id = self.map.body_owner(body_id);
- fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
- resolve_item_like(self, |this| intravisit::walk_impl_item(this, ii));
- }
+ debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
+ owner_id,
+ self.tcx.sess.codemap().span_to_string(body.value.span),
+ body_id,
+ self.cx.parent);
- fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- resolve_item_like(self, |this| intravisit::walk_trait_item(this, ti));
- }
+ let outer_cx = self.cx;
+ let outer_ts = mem::replace(&mut self.terminating_scopes, NodeSet());
- fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
- b: hir::BodyId, s: Span, n: NodeId) {
- resolve_fn(self, fk, fd, b, s, n);
+ // Only functions have an outer terminating (drop) scope,
+ // while temporaries in constant initializers are 'static.
+ if let MirSource::Fn(_) = MirSource::from_node(self.tcx, owner_id) {
+ self.terminating_scopes.insert(body_id.node_id);
+ }
+
+ if let Some(root_id) = self.cx.root_id {
+ self.region_maps.record_fn_parent(body_id.node_id, root_id);
+ }
+ self.cx.root_id = Some(body_id.node_id);
+
+ self.cx.parent = Some(self.new_code_extent(
+ CodeExtentData::CallSiteScope { fn_id: owner_id, body_id: body_id.node_id }));
+ self.cx.parent = Some(self.new_code_extent(
+ CodeExtentData::ParameterScope { fn_id: owner_id, body_id: body_id.node_id }));
+
+ // The arguments and `self` are parented to the fn.
+ self.cx.var_parent = self.cx.parent.take();
+ for argument in &body.arguments {
+ self.visit_pat(&argument.pat);
+ }
+
+ // The body of the every fn is a root scope.
+ self.cx.parent = self.cx.var_parent;
+ self.visit_expr(&body.value);
+
+ // Restore context we had at the start.
+ self.cx = outer_cx;
+ self.terminating_scopes = outer_ts;
}
+
fn visit_arm(&mut self, a: &'tcx Arm) {
resolve_arm(self, a);
}
}
}
-fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
+fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Rc<RegionMaps<'tcx>>
{
- let closure_base_def_id = tcx.closure_base_def_id(fn_id);
- if closure_base_def_id != fn_id {
+ let closure_base_def_id = tcx.closure_base_def_id(def_id);
+ if closure_base_def_id != def_id {
return tcx.region_maps(closure_base_def_id);
}
let mut maps = RegionMaps::new();
- let fn_node_id = tcx.hir.as_local_node_id(fn_id)
- .expect("fn DefId should be for LOCAL_CRATE");
- let node = tcx.hir.get(fn_node_id);
-
- {
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
let mut visitor = RegionResolutionVisitor {
tcx: tcx,
region_maps: &mut maps,
},
terminating_scopes: NodeSet(),
};
- visitor.visit_hir_map_node(node);
+
+ visitor.visit_body(tcx.hir.body(body));
}
Rc::new(maps)
{} name that is already in scope",
shadower.kind.desc(), name, orig.kind.desc()))
};
- err.span_label(orig.span, &"first declared here");
+ err.span_label(orig.span, "first declared here");
err.span_label(shadower.span,
- &format!("lifetime {} already in scope", name));
+ format!("lifetime {} already in scope", name));
err.emit();
}
} else {
struct_span_err!(self.sess, lifetime_ref.span, E0261,
"use of undeclared lifetime name `{}`", lifetime_ref.name)
- .span_label(lifetime_ref.span, &format!("undeclared lifetime"))
+ .span_label(lifetime_ref.span, "undeclared lifetime")
.emit();
}
}
} else {
format!("expected lifetime parameter")
};
- err.span_label(span, &msg);
+ err.span_label(span, msg);
if let Some(params) = error {
if lifetime_refs.len() == 1 {
let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
"invalid lifetime parameter name: `{}`", lifetime.name);
err.span_label(lifetime.span,
- &format!("{} is a reserved lifetime name", lifetime.name));
+ format!("{} is a reserved lifetime name", lifetime.name));
err.emit();
}
}
"lifetime name `{}` declared twice in the same scope",
lifetime_j.lifetime.name)
.span_label(lifetime_j.lifetime.span,
- &format!("declared twice"))
+ "declared twice")
.span_label(lifetime_i.lifetime.span,
- &format!("previous declaration here"))
+ "previous declaration here")
.emit();
}
}
if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) {
let span = self.tcx.sess.codemap().def_span(trait_item_span);
- err.span_label(span, &format!("definition of `{}` from trait", item_name));
+ err.span_label(span, format!("definition of `{}` from trait", item_name));
}
err.span_label(
error_span,
- &format!("impl has extra requirement {}", requirement));
+ format!("impl has extra requirement {}", requirement));
if let Some(node_id) = lint_id {
self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL,
}
err.span_label(span,
- &format!("{}the trait `{}` is not implemented for `{}`",
+ format!("{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_ref,
trait_ref.self_ty()));
expected_ref,
found_ref);
- err.span_label(span, &format!("{}", type_error));
+ err.span_label(span, format!("{}", type_error));
if let Some(sp) = found_span {
- err.span_label(span, &format!("requires `{}`", found_ref));
- err.span_label(sp, &format!("implements `{}`", expected_ref));
+ err.span_label(span, format!("requires `{}`", found_ref));
+ err.span_label(sp, format!("implements `{}`", expected_ref));
}
err
if expected == 1 { "" } else { "s" },
if expected == 1 { "is" } else { "are" });
- err.span_label(span, &format!("expected {} that takes {} argument{}",
+ err.span_label(span, format!("expected {} that takes {} argument{}",
if is_closure { "closure" } else { "function" },
expected,
if expected == 1 { "" } else { "s" }));
if let Some(span) = found_span {
- err.span_label(span, &format!("takes {} argument{}",
+ err.span_label(span, format!("takes {} argument{}",
found,
if found == 1 { "" } else { "s" }));
}
let mut err = struct_span_err!(self.sess, span, E0072,
"recursive type `{}` has infinite size",
self.item_path_str(type_def_id));
- err.span_label(span, &format!("recursive type has infinite size"));
+ err.span_label(span, "recursive type has infinite size");
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
self.item_path_str(type_def_id)));
self.sess, span, E0038,
"the trait `{}` cannot be made into an object",
trait_str);
- err.span_label(span, &format!("the trait `{}` cannot be made into an object", trait_str));
+ err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
let mut reported_violations = FxHashSet();
for violation in violations {
"type annotations needed");
for (target_span, label_message) in labels {
- err.span_label(target_span, &label_message);
+ err.span_label(target_span, label_message);
}
err.emit();
let mut err =
struct_span_err!(self.sess, span, E0391,
"unsupported cyclic reference between types/traits detected");
- err.span_label(span, &format!("cyclic reference"));
+ err.span_label(span, "cyclic reference");
err.span_note(stack[0].0, &format!("the cycle begins when {}...",
stack[0].1.describe(self)));
match tcx.hir.find(id) {
Some(hir_map::NodeImplItem(ref impl_item)) => {
match impl_item.node {
- hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(..) => {
+ hir::ImplItemKind::Type(_) => {
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the impl
let impl_id = tcx.hir.get_parent(id);
impl_def_id,
Some(tcx.item_extent(id)))
}
- hir::ImplItemKind::Method(_, ref body) => {
+ hir::ImplItemKind::Const(_, body) |
+ hir::ImplItemKind::Method(_, body) => {
tcx.construct_parameter_environment(
impl_item.span,
tcx.hir.local_def_id(id),
}
Some(hir_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
- hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
- // associated types don't have their own entry (for some reason),
- // so for now just grab environment for the trait
- let trait_id = tcx.hir.get_parent(id);
- let trait_def_id = tcx.hir.local_def_id(trait_id);
+ hir::TraitItemKind::Type(..) |
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_))=> {
tcx.construct_parameter_environment(trait_item.span,
- trait_def_id,
+ tcx.hir.local_def_id(id),
Some(tcx.item_extent(id)))
}
- hir::TraitItemKind::Method(_, ref body) => {
- // Use call-site for extent (unless this is a
- // trait method with no default; then fallback
- // to the method id).
- let extent = if let hir::TraitMethod::Provided(body_id) = *body {
- // default impl: use call_site extent as free_id_outlive bound.
- tcx.call_site_extent(id, body_id.node_id)
- } else {
- // no default impl: use item extent as free_id_outlive bound.
- tcx.item_extent(id)
- };
+ hir::TraitItemKind::Const(_, Some(body)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body)) => {
tcx.construct_parameter_environment(
trait_item.span,
tcx.hir.local_def_id(id),
- Some(extent))
+ Some(tcx.call_site_extent(id, body.node_id)))
}
}
}
Some(hir_map::NodeItem(item)) => {
match item.node {
- hir::ItemFn(.., body_id) => {
- // We assume this is a function.
- let fn_def_id = tcx.hir.local_def_id(id);
-
+ hir::ItemConst(_, body) |
+ hir::ItemStatic(.., body) |
+ hir::ItemFn(.., body) => {
tcx.construct_parameter_environment(
item.span,
- fn_def_id,
- Some(tcx.call_site_extent(id, body_id.node_id)))
+ tcx.hir.local_def_id(id),
+ Some(tcx.call_site_extent(id, body.node_id)))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
- hir::ItemConst(..) |
- hir::ItemStatic(..) => {
- let def_id = tcx.hir.local_def_id(id);
- tcx.construct_parameter_environment(item.span,
- def_id,
- Some(tcx.item_extent(id)))
- }
hir::ItemTrait(..) => {
let def_id = tcx.hir.local_def_id(id);
tcx.construct_parameter_environment(item.span,
} else if let Some(r) = self.as_region() {
write!(f, "{:?}", r)
} else {
- write!(f, "<unknwon @ {:p}>", self.ptr.get() as *const ())
+ write!(f, "<unknown @ {:p}>", self.ptr.get() as *const ())
}
}
}
nl, new_loan_msg);
err.span_label(
old_loan.span,
- &format!("first mutable borrow occurs here{}", old_loan_msg));
+ format!("first mutable borrow occurs here{}", old_loan_msg));
err.span_label(
new_loan.span,
- &format!("second mutable borrow occurs here{}", new_loan_msg));
+ format!("second mutable borrow occurs here{}", new_loan_msg));
err.span_label(
previous_end_span,
- &format!("first borrow ends here"));
+ "first borrow ends here");
err
}
nl);
err.span_label(
old_loan.span,
- &format!("first closure is constructed here"));
+ "first closure is constructed here");
err.span_label(
new_loan.span,
- &format!("second closure is constructed here"));
+ "second closure is constructed here");
err.span_label(
previous_end_span,
- &format!("borrow from first closure ends here"));
+ "borrow from first closure ends here");
err
}
nl, ol_pronoun, old_loan_msg);
err.span_label(
new_loan.span,
- &format!("closure construction occurs here{}", new_loan_msg));
+ format!("closure construction occurs here{}", new_loan_msg));
err.span_label(
old_loan.span,
- &format!("borrow occurs here{}", old_loan_msg));
+ format!("borrow occurs here{}", old_loan_msg));
err.span_label(
previous_end_span,
- &format!("borrow ends here"));
+ "borrow ends here");
err
}
nl, new_loan_msg, new_loan.kind.to_user_str());
err.span_label(
new_loan.span,
- &format!("borrow occurs here{}", new_loan_msg));
+ format!("borrow occurs here{}", new_loan_msg));
err.span_label(
old_loan.span,
- &format!("closure construction occurs here{}", old_loan_msg));
+ format!("closure construction occurs here{}", old_loan_msg));
err.span_label(
previous_end_span,
- &format!("borrow from closure ends here"));
+ "borrow from closure ends here");
err
}
old_loan_msg);
err.span_label(
new_loan.span,
- &format!("{} borrow occurs here{}",
+ format!("{} borrow occurs here{}",
new_loan.kind.to_user_str(),
new_loan_msg));
err.span_label(
old_loan.span,
- &format!("{} borrow occurs here{}",
+ format!("{} borrow occurs here{}",
old_loan.kind.to_user_str(),
old_loan_msg));
err.span_label(
previous_end_span,
- &format!("{} borrow ends here",
+ format!("{} borrow ends here",
old_loan.kind.to_user_str()));
err
}
euv::ClosureCapture(span) => {
err.span_label(
span,
- &format!("borrow occurs due to use of `{}` in closure", nl));
+ format!("borrow occurs due to use of `{}` in closure", nl));
}
_ => { }
}
euv::ClosureCapture(span) => {
err.span_label(
span,
- &format!("previous borrow occurs due to use of `{}` in closure",
+ format!("previous borrow occurs due to use of `{}` in closure",
ol));
}
_ => { }
"cannot use `{}` because it was mutably borrowed",
&self.bccx.loan_path_to_string(copy_path))
.span_label(loan_span,
- &format!("borrow of `{}` occurs here",
+ format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
)
.span_label(span,
- &format!("use of borrowed `{}`",
+ format!("use of borrowed `{}`",
&self.bccx.loan_path_to_string(&loan_path)))
.emit();
}
&self.bccx.loan_path_to_string(move_path));
err.span_label(
loan_span,
- &format!("borrow of `{}` occurs here",
+ format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
);
err.span_label(
span,
- &format!("move into closure occurs here")
+ "move into closure occurs here"
);
err
}
&self.bccx.loan_path_to_string(move_path));
err.span_label(
loan_span,
- &format!("borrow of `{}` occurs here",
+ format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
);
err.span_label(
span,
- &format!("move out of `{}` occurs here",
+ format!("move out of `{}` occurs here",
&self.bccx.loan_path_to_string(move_path))
);
err
"cannot assign to `{}` because it is borrowed",
self.bccx.loan_path_to_string(loan_path))
.span_label(loan.span,
- &format!("borrow of `{}` occurs here",
+ format!("borrow of `{}` occurs here",
self.bccx.loan_path_to_string(loan_path)))
.span_label(span,
- &format!("assignment to borrowed `{}` occurs here",
+ format!("assignment to borrowed `{}` occurs here",
self.bccx.loan_path_to_string(loan_path)))
.emit();
}
}
if let NoteClosureEnv(upvar_id) = error.move_from.note {
err.span_label(bccx.tcx.hir.span(upvar_id.var_id),
- &"captured outer variable");
+ "captured outer variable");
}
err.emit();
move_from.descriptive_string(bccx.tcx));
err.span_label(
move_from.span,
- &format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
+ format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
);
err
}
"cannot move out of type `{}`, \
a non-copy array",
b.ty);
- err.span_label(move_from.span, &format!("cannot move out of here"));
+ err.span_label(move_from.span, "cannot move out of here");
err
}
(_, Kind::Pattern) => {
"cannot move out of type `{}`, \
which implements the `Drop` trait",
b.ty);
- err.span_label(move_from.span, &format!("cannot move out of here"));
+ err.span_label(move_from.span, "cannot move out of here");
err
},
_ => {
if is_first_note {
err.span_label(
move_to_span,
- &format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
+ format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
pat_name));
err
} else {
err.span_label(move_to_span,
- &format!("...and here (use `ref {0}` or `ref mut {0}`)",
+ format!("...and here (use `ref {0}` or `ref mut {0}`)",
pat_name));
err
}
"{} of possibly uninitialized variable: `{}`",
verb,
self.loan_path_to_string(lp))
- .span_label(use_span, &format!("use of possibly uninitialized `{}`",
+ .span_label(use_span, format!("use of possibly uninitialized `{}`",
self.loan_path_to_string(lp)))
.emit();
return;
err = if use_span == move_span {
err.span_label(
use_span,
- &format!("value moved{} here in previous iteration of loop",
+ format!("value moved{} here in previous iteration of loop",
move_note));
err
} else {
- err.span_label(use_span, &format!("value {} here after move", verb_participle))
- .span_label(move_span, &format!("value moved{} here", move_note));
+ err.span_label(use_span, format!("value {} here after move", verb_participle))
+ .span_label(move_span, format!("value moved{} here", move_note));
err
};
self.tcx.sess, span, E0384,
"re-assignment of immutable variable `{}`",
self.loan_path_to_string(lp));
- err.span_label(span, &format!("re-assignment of immutable variable"));
+ err.span_label(span, "re-assignment of immutable variable");
if span != assign.span {
- err.span_label(assign.span, &format!("first assignment to `{}`",
+ err.span_label(assign.span, format!("first assignment to `{}`",
self.loan_path_to_string(lp)));
}
err.emit();
let mut err = struct_span_err!(
self.tcx.sess, span, E0389,
"{} in a `&` reference", prefix);
- err.span_label(span, &"assignment into an immutable reference");
+ err.span_label(span, "assignment into an immutable reference");
err
}
};
}
db.span_label(
let_span,
- &format!("consider changing this to `mut {}`", snippet)
+ format!("consider changing this to `mut {}`", snippet)
);
}
}
if let Ok(snippet) = snippet {
db.span_label(
let_span,
- &format!("consider changing this to `{}`",
+ format!("consider changing this to `{}`",
snippet.replace("ref ", "ref mut "))
);
}
if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
if let Some(msg) =
self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
- db.span_label(local_ty.span, &msg);
+ db.span_label(local_ty.span, msg);
}
}
}
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
- db.span_label(field.ty.span, &msg);
+ db.span_label(field.ty.span, msg);
}
}
}
which is owned by the current function",
cmt_path_or_string)
.span_label(capture_span,
- &format!("{} is borrowed here",
+ format!("{} is borrowed here",
cmt_path_or_string))
.span_label(err.span,
- &format!("may outlive borrowed value {}",
+ format!("may outlive borrowed value {}",
cmt_path_or_string))
.span_suggestion(err.span,
&format!("to force the closure to take ownership of {} \
match db.span.primary_span() {
Some(primary) => {
db.span = MultiSpan::from_span(s);
- db.span_label(primary, &format!("capture occurs here"));
- db.span_label(s, &"does not live long enough");
+ db.span_label(primary, "capture occurs here");
+ db.span_label(s, "does not live long enough");
true
}
None => false
}
}
_ => {
- db.span_label(error_span, &"does not live long enough");
+ db.span_label(error_span, "does not live long enough");
false
}
};
(Some(s1), Some(s2)) if s1 == s2 => {
if !is_closure {
db.span = MultiSpan::from_span(s1);
- db.span_label(error_span, &value_msg);
+ db.span_label(error_span, value_msg);
let msg = match opt_loan_path(&err.cmt) {
None => value_kind.to_string(),
Some(lp) => {
}
};
db.span_label(s1,
- &format!("{} dropped here while still borrowed", msg));
+ format!("{} dropped here while still borrowed", msg));
} else {
- db.span_label(s1, &format!("{} dropped before borrower", value_kind));
+ db.span_label(s1, format!("{} dropped before borrower", value_kind));
}
db.note("values in a scope are dropped in the opposite order \
they are created");
}
(Some(s1), Some(s2)) if !is_closure => {
db.span = MultiSpan::from_span(s2);
- db.span_label(error_span, &value_msg);
+ db.span_label(error_span, value_msg);
let msg = match opt_loan_path(&err.cmt) {
None => value_kind.to_string(),
Some(lp) => {
format!("`{}`", self.loan_path_to_string(&lp))
}
};
- db.span_label(s2, &format!("{} dropped here while still borrowed", msg));
- db.span_label(s1, &format!("{} needs to live until here", value_kind));
+ db.span_label(s2, format!("{} dropped here while still borrowed", msg));
+ db.span_label(s1, format!("{} needs to live until here", value_kind));
}
_ => {
match sub_span {
Some(s) => {
- db.span_label(s, &format!("{} needs to live until here",
+ db.span_label(s, format!("{} needs to live until here",
value_kind));
}
None => {
}
match super_span {
Some(s) => {
- db.span_label(s, &format!("{} only lives until here", value_kind));
+ db.span_label(s, format!("{} only lives until here", value_kind));
}
None => {
self.tcx.note_and_explain_region(
}
_ => {
if let Categorization::Deref(..) = err.cmt.cat {
- db.span_label(*error_span, &"cannot borrow as mutable");
+ db.span_label(*error_span, "cannot borrow as mutable");
} else if let Categorization::Local(local_id) = err.cmt.cat {
let span = self.tcx.hir.span(local_id);
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
- db.span_label(*error_span, &format!("cannot reborrow mutably"));
- db.span_label(*error_span, &format!("try removing `&mut` here"));
+ db.span_label(*error_span, "cannot reborrow mutably");
+ db.span_label(*error_span, "try removing `&mut` here");
} else {
- db.span_label(*error_span, &format!("cannot borrow mutably"));
+ db.span_label(*error_span, "cannot borrow mutably");
}
} else {
- db.span_label(*error_span, &format!("cannot borrow mutably"));
+ db.span_label(*error_span, "cannot borrow mutably");
}
} else if let Categorization::Interior(ref cmt, _) = err.cmt.cat {
if let mc::MutabilityCategory::McImmutable = cmt.mutbl {
db.span_label(*error_span,
- &"cannot mutably borrow immutable field");
+ "cannot mutably borrow immutable field");
}
}
}
"refutable pattern in {}: `{}` not covered",
origin, pattern_string
);
- diag.span_label(pat.span, &format!("pattern `{}` not covered", pattern_string));
+ diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
diag.emit();
});
}
let span = first_pat.0.span;
struct_span_err!(cx.tcx.sess, span, E0162,
"irrefutable if-let pattern")
- .span_label(span, &format!("irrefutable pattern"))
+ .span_label(span, "irrefutable pattern")
.emit();
printed_if_let_err = true;
}
1 => {
struct_span_err!(cx.tcx.sess, span, E0165,
"irrefutable while-let pattern")
- .span_label(span, &format!("irrefutable pattern"))
+ .span_label(span, "irrefutable pattern")
.emit();
},
_ => bug!(),
diagnostic.set_span(pat.span);
// if we had a catchall pattern, hint at that
if let Some(catchall) = catchall {
- diagnostic.span_label(pat.span, &"this is an unreachable pattern");
+ diagnostic.span_label(pat.span, "this is an unreachable pattern");
diagnostic.span_note(catchall, "this pattern matches any value");
}
cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
"refutable pattern in `for` loop binding: \
`{}` not covered",
pattern_string)
- .span_label(sp, &format!("pattern `{}` not covered", pattern_string))
+ .span_label(sp, format!("pattern `{}` not covered", pattern_string))
.emit();
},
_ => {
create_e0004(cx.tcx.sess, sp,
format!("non-exhaustive patterns: {} not covered",
joined_patterns))
- .span_label(sp, &label_text)
+ .span_label(sp, label_text)
.emit();
},
}
if sub.map_or(false, |p| p.contains_bindings()) {
struct_span_err!(cx.tcx.sess, p.span, E0007,
"cannot bind by-move with sub-bindings")
- .span_label(p.span, &format!("binds an already bound by-move value by moving it"))
+ .span_label(p.span, "binds an already bound by-move value by moving it")
.emit();
} else if has_guard {
struct_span_err!(cx.tcx.sess, p.span, E0008,
"cannot bind by-move into a pattern guard")
- .span_label(p.span, &format!("moves value into pattern guard"))
+ .span_label(p.span, "moves value into pattern guard")
.emit();
} else if by_ref_span.is_some() {
struct_span_err!(cx.tcx.sess, p.span, E0009,
"cannot bind by-move and by-ref in the same pattern")
- .span_label(p.span, &format!("by-move pattern here"))
- .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used"))
+ .span_label(p.span, "by-move pattern here")
+ .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
.emit();
}
};
ty::MutBorrow => {
struct_span_err!(self.cx.tcx.sess, span, E0301,
"cannot mutably borrow in a pattern guard")
- .span_label(span, &format!("borrowed mutably in pattern guard"))
+ .span_label(span, "borrowed mutably in pattern guard")
.emit();
}
ty::ImmBorrow | ty::UniqueImmBorrow => {}
match mode {
MutateMode::JustWrite | MutateMode::WriteAndRead => {
struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
- .span_label(span, &format!("assignment in pattern guard"))
+ .span_label(span, "assignment in pattern guard")
.emit();
}
MutateMode::Init => {}
if !self.bindings_allowed {
struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
"pattern bindings are not allowed after an `@`")
- .span_label(pat.span, &format!("not allowed after `@`"))
+ .span_label(pat.span, "not allowed after `@`")
.emit();
}
/// all, and you just supplied a `Span` to create the diagnostic,
/// then the snippet will just include that `Span`, which is
/// called the primary span.
- pub fn span_label(&mut self, span: Span, label: &fmt::Display)
- -> &mut Self {
- self.span.push_span_label(span, format!("{}", label));
+ pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
+ self.span.push_span_label(span, label.into());
self
}
/// all, and you just supplied a `Span` to create the diagnostic,
/// then the snippet will just include that `Span`, which is
/// called the primary span.
- forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display)
- -> &mut Self);
+ pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
+ self.diagnostic.span_label(span, label);
+ self
+ }
forward!(pub fn note_expected_found(&mut self,
label: &fmt::Display,
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Note);
}
+ pub fn span_note_diag<'a>(&'a self,
+ sp: Span,
+ msg: &str)
+ -> DiagnosticBuilder<'a> {
+ let mut db = DiagnosticBuilder::new(self, Note, msg);
+ db.set_span(sp);
+ db
+ }
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.span_bug(sp, &format!("unimplemented {}", msg));
}
None => {
self.tcx.sess.span_fatal(
attr.span,
- &format!("missing DepNode variant"));
+ "missing DepNode variant");
}
};
self.then_this_would_need.push((attr.span,
for &(target_span, _, _, _) in then_this_would_need {
tcx.sess.span_err(
target_span,
- &format!("no #[rustc_if_this_changed] annotation detected"));
+ "no #[rustc_if_this_changed] annotation detected");
}
return;
} else {
tcx.sess.span_err(
target_span,
- &format!("OK"));
+ "OK");
}
}
}
tcx.sess.span_fatal(
attr.span,
- &format!("no cfg attribute"));
+ "no cfg attribute");
}
fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name {
}
}
+declare_lint! {
+ pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ Warn,
+ "floating-point literals cannot be used in patterns"
+}
+
+/// Checks for floating point literals in patterns.
+#[derive(Clone)]
+pub struct IllegalFloatLiteralPattern;
+
+impl LintPass for IllegalFloatLiteralPattern {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN)
+ }
+}
+
+fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
+ use self::ast::{ExprKind, LitKind};
+ match expr.node {
+ ExprKind::Lit(ref l) => {
+ match l.node {
+ LitKind::FloatUnsuffixed(..) |
+ LitKind::Float(..) => {
+ cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ l.span,
+ "floating-point literals cannot be used in patterns");
+ error!("span mc spanspam");
+ },
+ _ => (),
+ }
+ }
+ // These may occur in patterns
+ // and can maybe contain float literals
+ ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
+ // These may occur in patterns
+ // and can't contain float literals
+ ExprKind::Path(..) => (),
+ // If something unhandled is encountered, we need to expand the
+ // search or ignore more ExprKinds.
+ _ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint",
+ expr.node),
+ }
+}
+
+impl EarlyLintPass for IllegalFloatLiteralPattern {
+ fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
+ use self::ast::PatKind;
+ pat.walk(&mut |p| {
+ match p.node {
+ // Wildcard patterns and paths are uninteresting for the lint
+ PatKind::Wild |
+ PatKind::Path(..) => (),
+
+ // The walk logic recurses inside these
+ PatKind::Ident(..) |
+ PatKind::Struct(..) |
+ PatKind::Tuple(..) |
+ PatKind::TupleStruct(..) |
+ PatKind::Ref(..) |
+ PatKind::Box(..) |
+ PatKind::Slice(..) => (),
+
+ // Extract the expressions and check them
+ PatKind::Lit(ref e) => fl_lit_check_expr(cx, e),
+ PatKind::Range(ref st, ref en, _) => {
+ fl_lit_check_expr(cx, st);
+ fl_lit_check_expr(cx, en);
+ },
+
+ PatKind::Mac(_) => bug!("lint must run post-expansion"),
+ }
+ true
+ });
+ }
+}
+
declare_lint! {
pub UNCONDITIONAL_RECURSION,
Warn,
UnusedParens,
UnusedImportBraces,
AnonymousParameters,
+ IllegalFloatLiteralPattern,
);
add_early_builtin_with_new!(sess,
id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN),
reference: "issue #36890 <https://github.com/rust-lang/rust/issues/36890>",
},
+ FutureIncompatibleInfo {
+ id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
+ reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+ },
FutureIncompatibleInfo {
id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
reference: "issue #36891 <https://github.com/rust-lang/rust/issues/36891>",
let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
"unnecessary `unsafe` block");
- db.span_label(blk.span, &"unnecessary `unsafe` block");
+ db.span_label(blk.span, "unnecessary `unsafe` block");
if let Some((kind, id)) = is_enclosed(cx, blk.id) {
db.span_note(cx.tcx.hir.span(id),
&format!("because it's nested under this `unsafe` {}", kind));
Some(span) => {
struct_span_err!(sess, span, E0454,
"#[link(name = \"\")] given with empty name")
- .span_label(span, &format!("empty name given"))
+ .span_label(span, "empty name given")
.emit();
}
None => {
Some(k) => {
struct_span_err!(self.sess, m.span, E0458,
"unknown kind: `{}`", k)
- .span_label(m.span, &format!("unknown kind")).emit();
+ .span_label(m.span, "unknown kind").emit();
cstore::NativeUnknown
}
None => cstore::NativeUnknown
None => {
struct_span_err!(self.sess, m.span, E0459,
"#[link(...)] specified without `name = \"foo\"`")
- .span_label(m.span, &format!("missing `name` argument")).emit();
+ .span_label(m.span, "missing `name` argument").emit();
Symbol::intern("foo")
}
};
&& self.triple != config::host_triple() {
err.note(&format!("the `{}` target may not be installed", self.triple));
}
- err.span_label(self.span, &format!("can't find crate"));
+ err.span_label(self.span, "can't find crate");
err
};
to the crate attributes to enable");
} else {
self.find_drop_implementation_method_span()
- .map(|span| err.span_label(span, &format!("destructor defined here")));
+ .map(|span| err.span_label(span, "destructor defined here"));
- err.span_label(self.span, &format!("constants cannot have destructors"));
+ err.span_label(self.span, "constants cannot have destructors");
}
err.emit();
"cannot refer to statics by value, use a constant instead"
};
struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg)
- .span_label(self.span, &format!("referring to another static by value"))
- .note(&format!("use the address-of operator or a constant instead"))
+ .span_label(self.span, "referring to another static by value")
+ .note("use the address-of operator or a constant instead")
.emit();
// Replace STATIC with NOT_CONST to avoid further errors.
"raw pointers cannot be dereferenced in {}s",
this.mode)
.span_label(this.span,
- &format!("dereference of raw pointer in constant"))
+ "dereference of raw pointer in constant")
.emit();
}
}
struct_span_err!(self.tcx.sess, self.span, E0017,
"references in {}s may only refer \
to immutable values", self.mode)
- .span_label(self.span, &format!("{}s require immutable values",
+ .span_label(self.span, format!("{}s require immutable values",
self.mode))
.emit();
}
self.mode)
.span_label(
self.span,
- &format!("comparing raw pointers in static"))
+ "comparing raw pointers in static")
.emit();
}
}
if self.mode != Mode::Fn {
struct_span_err!(self.tcx.sess, self.span, E0010,
"allocations are not allowed in {}s", self.mode)
- .span_label(self.span, &format!("allocation not allowed in {}s", self.mode))
+ .span_label(self.span, format!("allocation not allowed in {}s", self.mode))
.emit();
}
}
use rustc::mir::*;
use rustc::mir::transform::{MirSuite, MirPassIndex, MirSource};
use rustc::ty::TyCtxt;
+use rustc::ty::item_path;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
return;
}
- let node_path = tcx.item_path_str(tcx.hir.local_def_id(source.item_id()));
+ let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
+ tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
+ });
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
disambiguator, source, mir);
for (index, promoted_mir) in mir.promoted.iter_enumerated() {
Some(ref filters) => filters,
};
let node_id = source.item_id();
- let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
+ let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
+ tcx.item_path_str(tcx.hir.local_def_id(node_id))
+ });
filters.split("&")
.any(|filter| {
filter == "all" ||
})
}
+// #41697 -- we use `with_forced_impl_filename_line()` because
+// `item_path_str()` would otherwise trigger `type_of`, and this can
+// run while we are already attempting to evaluate `type_of`.
+
fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pass_num: Option<(MirSuite, MirPassIndex)>,
pass_name: &str,
E0449,
"unnecessary visibility qualifier");
if vis == &Visibility::Public {
- err.span_label(span, &format!("`pub` not needed here"));
+ err.span_label(span, "`pub` not needed here");
}
if let Some(note) = note {
err.note(note);
Constness::Const => {
struct_span_err!(self.session, constness.span, E0379,
"trait fns cannot be declared const")
- .span_label(constness.span, &format!("trait fns cannot be const"))
+ .span_label(constness.span, "trait fns cannot be const")
.emit();
}
_ => {}
E0130,
"patterns aren't allowed in foreign function \
declarations");
- err.span_label(span, &format!("pattern not allowed in foreign function"));
+ err.span_label(span, "pattern not allowed in foreign function");
if is_recent {
err.span_note(span,
"this is a recent error, see issue #35203 for more details");
Ok(Ordering::Greater) => {
struct_span_err!(self.tcx.sess, start.span, E0030,
"lower range bound must be less than or equal to upper")
- .span_label(start.span, &format!("lower bound larger than upper bound"))
+ .span_label(start.span, "lower bound larger than upper bound")
.emit();
}
Err(ErrorReported) => {}
"`break` with value from a `{}` loop",
kind.name())
.span_label(e.span,
- &format!("can only break with a value inside `loop`"))
+ "can only break with a value inside `loop`")
.emit();
}
}
Loop(_) => {}
Closure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
- .span_label(span, &format!("cannot break inside of a closure"))
+ .span_label(span, "cannot break inside of a closure")
.emit();
}
Normal => {
struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
- .span_label(span, &format!("cannot break outside of a loop"))
+ .span_label(span, "cannot break outside of a loop")
.emit();
}
}
struct_span_err!(self.sess, span, E0590,
"`break` or `continue` with no label in the condition of a `while` loop")
.span_label(span,
- &format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
+ format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
.emit();
}
}
});
if !any_static {
struct_span_err!(self.sess, span, E0265, "recursive constant")
- .span_label(span, &format!("recursion not allowed in constant"))
+ .span_label(span, "recursion not allowed in constant")
.emit();
}
return;
if !def.is_enum() && !field.vis.is_accessible_from(self.current_item, self.tcx) {
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
- .span_label(span, &format!("field `{}` is private", field.name))
+ .span_label(span, format!("field `{}` is private", field.name))
.emit();
}
}
if self.has_pub_restricted || self.has_old_errors {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
"private type `{}` in public interface", ty);
- err.span_label(self.span, &format!("can't leak private type"));
+ err.span_label(self.span, "can't leak private type");
err.emit();
} else {
self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
if self.has_pub_restricted || self.has_old_errors {
struct_span_err!(self.tcx.sess, self.span, E0445,
"private trait `{}` in public interface", trait_ref)
- .span_label(self.span, &format!(
+ .span_label(self.span, format!(
"private trait can't be public"))
.emit();
} else {
E0401,
"can't use type parameters from outer function; \
try using a local type parameter instead");
- err.span_label(span, &format!("use of type variable from outer function"));
+ err.span_label(span, "use of type variable from outer function");
err
}
ResolutionError::OuterTypeParameterContext => {
"the name `{}` is already used for a type parameter \
in this type parameter list",
name);
- err.span_label(span, &format!("already used"));
- err.span_label(first_use_span.clone(), &format!("first use of `{}`", name));
+ err.span_label(span, "already used");
+ err.span_label(first_use_span.clone(), format!("first use of `{}`", name));
err
}
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
"method `{}` is not a member of trait `{}`",
method,
trait_);
- err.span_label(span, &format!("not a member of trait `{}`", trait_));
+ err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
"type `{}` is not a member of trait `{}`",
type_,
trait_);
- err.span_label(span, &format!("not a member of trait `{}`", trait_));
+ err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
"const `{}` is not a member of trait `{}`",
const_,
trait_);
- err.span_label(span, &format!("not a member of trait `{}`", trait_));
+ err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::VariableNotBoundInPattern(binding_error) => {
let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
for sp in target_sp {
- err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name));
+ err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
}
let origin_sp = binding_error.origin.iter().map(|x| *x).collect::<Vec<_>>();
for sp in origin_sp {
- err.span_label(sp, &"variable not in all patterns");
+ err.span_label(sp, "variable not in all patterns");
}
err
}
"variable `{}` is bound in inconsistent \
ways within the same match arm",
variable_name);
- err.span_label(span, &format!("bound in different ways"));
- err.span_label(first_binding_span, &format!("first binding"));
+ err.span_label(span, "bound in different ways");
+ err.span_label(first_binding_span, "first binding");
err
}
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
E0415,
"identifier `{}` is bound more than once in this parameter list",
identifier);
- err.span_label(span, &format!("used as parameter more than once"));
+ err.span_label(span, "used as parameter more than once");
err
}
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
E0416,
"identifier `{}` is bound more than once in the same pattern",
identifier);
- err.span_label(span, &format!("used in a pattern more than once"));
+ err.span_label(span, "used in a pattern more than once");
err
}
ResolutionError::UndeclaredLabel(name) => {
E0426,
"use of undeclared label `{}`",
name);
- err.span_label(span, &format!("undeclared label `{}`",&name));
+ err.span_label(span, format!("undeclared label `{}`", name));
err
}
ResolutionError::SelfImportsOnlyAllowedWithin => {
};
let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
if let Some((_, p)) = name {
- err.span_label(span, &p);
+ err.span_label(span, p);
}
err
}
ResolutionError::FailedToResolve(msg) => {
let mut err = struct_span_err!(resolver.session, span, E0433,
"failed to resolve. {}", msg);
- err.span_label(span, &msg);
+ err.span_label(span, msg);
err
}
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
span,
E0435,
"attempt to use a non-constant value in a constant");
- err.span_label(span, &format!("non-constant used with constant"));
+ err.span_label(span, "non-constant used with constant");
err
}
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
span,
E0530,
"{}s cannot shadow {}s", what_binding, shadows_what);
- err.span_label(span, &format!("cannot be named the same as a {}", shadows_what));
+ err.span_label(span, format!("cannot be named the same as a {}", shadows_what));
let participle = if binding.is_import() { "imported" } else { "defined" };
- let msg = &format!("a {} `{}` is {} here", shadows_what, name, participle);
+ let msg = format!("a {} `{}` is {} here", shadows_what, name, participle);
err.span_label(binding.span, msg);
err
}
let mut err = struct_span_err!(resolver.session, span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
- err.span_label(span, &format!("defaulted type parameters \
+ err.span_label(span, format!("defaulted type parameters \
cannot be forward declared"));
err
}
if is_self_type(path, ns) {
__diagnostic_used!(E0411);
err.code("E0411".into());
- err.span_label(span, &format!("`Self` is only available in traits and impls"));
+ err.span_label(span, "`Self` is only available in traits and impls");
return err;
}
if is_self_value(path, ns) {
__diagnostic_used!(E0424);
err.code("E0424".into());
- err.span_label(span, &format!("`self` value is only available in \
+ err.span_label(span, format!("`self` value is only available in \
methods with `self` parameter"));
return err;
}
let self_is_available = this.self_value_is_available(path[0].ctxt);
match candidate {
AssocSuggestion::Field => {
- err.span_label(span, &format!("did you mean `self.{}`?", path_str));
+ err.span_label(span, format!("did you mean `self.{}`?", path_str));
if !self_is_available {
- err.span_label(span, &format!("`self` value is only available in \
+ err.span_label(span, format!("`self` value is only available in \
methods with `self` parameter"));
}
}
AssocSuggestion::MethodWithSelf if self_is_available => {
- err.span_label(span, &format!("did you mean `self.{}(...)`?",
+ err.span_label(span, format!("did you mean `self.{}(...)`?",
path_str));
}
AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
- err.span_label(span, &format!("did you mean `Self::{}`?", path_str));
+ err.span_label(span, format!("did you mean `Self::{}`?", path_str));
}
}
return err;
// Try Levenshtein.
if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
- err.span_label(ident_span, &format!("did you mean `{}`?", candidate));
+ err.span_label(ident_span, format!("did you mean `{}`?", candidate));
levenshtein_worked = true;
}
if let Some(def) = def {
match (def, source) {
(Def::Macro(..), _) => {
- err.span_label(span, &format!("did you mean `{}!(...)`?", path_str));
+ err.span_label(span, format!("did you mean `{}!(...)`?", path_str));
return err;
}
(Def::TyAlias(..), PathSource::Trait) => {
- err.span_label(span, &format!("type aliases cannot be used for traits"));
+ err.span_label(span, "type aliases cannot be used for traits");
return err;
}
(Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
ExprKind::Field(_, ident) => {
- err.span_label(parent.span, &format!("did you mean `{}::{}`?",
+ err.span_label(parent.span, format!("did you mean `{}::{}`?",
path_str, ident.node));
return err;
}
ExprKind::MethodCall(ident, ..) => {
- err.span_label(parent.span, &format!("did you mean `{}::{}(...)`?",
+ err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
path_str, ident.node));
return err;
}
if let Some((ctor_def, ctor_vis))
= this.struct_constructors.get(&def_id).cloned() {
if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
- err.span_label(span, &format!("constructor is not visible \
+ err.span_label(span, format!("constructor is not visible \
here due to private fields"));
}
}
}
- err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?",
+ err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
return err;
}
// Fallback label.
if !levenshtein_worked {
- err.span_label(base_span, &fallback_label);
+ err.span_label(base_span, fallback_label);
}
err
};
},
};
- err.span_label(span, &format!("`{}` already {}", name, participle));
+ err.span_label(span, format!("`{}` already {}", name, participle));
if old_binding.span != syntax_pos::DUMMY_SP {
- err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name));
+ err.span_label(old_binding.span, format!("previous {} of `{}` here", noun, name));
}
err.emit();
self.name_already_seen.insert(name, span);
err.help(&format!("did you mean `{}`?", suggestion));
}
} else {
- err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
+ err.help("have you added the `#[macro_use]` on the module/import?");
}
}
}
Ok(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
- .span_label(directive.span, &format!("cannot be imported directly"))
+ .span_label(directive.span, "cannot be imported directly")
.emit();
// Do not import this illegal binding. Import a dummy binding and pretend
// everything is fine
} else if ns == TypeNS {
struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be reexported", ident)
- .span_label(directive.span, &format!("reexport of private `{}`", ident))
+ .span_label(directive.span, format!("reexport of private `{}`", ident))
.note(&format!("consider declaring type or module `{}` with `pub`", ident))
.emit();
} else {
let msg =
format!("a macro named `{}` has already been exported", ident);
self.session.struct_span_err(span, &msg)
- .span_label(span, &format!("`{}` already exported", ident))
+ .span_label(span, format!("`{}` already exported", ident))
.span_note(binding.span, "previous macro export here")
.emit();
}
rustc_typeck = { path = "../librustc_typeck" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
-rls-data = "0.1"
-rls-span = "0.1"
+rls-data = "0.3"
+rls-span = "0.4"
# FIXME(#40527) should move rustc serialize out of tree
rustc-serialize = "0.3"
hir::ParenthesizedParameters(..) => {
struct_span_err!(tcx.sess, span, E0214,
"parenthesized parameters may only be used with a trait")
- .span_label(span, &format!("only traits may use parentheses"))
+ .span_label(span, "only traits may use parentheses")
.emit();
return Substs::for_item(tcx, def_id, |_, _| {
struct_span_err!(tcx.sess, span, E0393,
"the type parameter `{}` must be explicitly specified",
def.name)
- .span_label(span, &format!("missing reference to `{}`", def.name))
+ .span_label(span, format!("missing reference to `{}`", def.name))
.note(&format!("because of the default `Self` reference, \
type parameters must be specified on object types"))
.emit();
let span = b.trait_ref.path.span;
struct_span_err!(self.tcx().sess, span, E0225,
"only Send/Sync traits can be used as additional traits in a trait object")
- .span_label(span, &format!("non-Send/Sync additional trait"))
+ .span_label(span, "non-Send/Sync additional trait")
.emit();
}
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name,
tcx.item_path_str(trait_def_id))
- .span_label(span, &format!(
+ .span_label(span, format!(
"missing associated type `{}` value", name))
.emit();
}
trait_str: &str,
name: &str) {
struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type")
- .span_label(span, &format!("ambiguous associated type"))
+ .span_label(span, "ambiguous associated type")
.note(&format!("specify the type using the syntax `<{} as {}>::{}`",
type_str, trait_str, name))
.emit();
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name)
- .span_label(span, &format!("associated type `{}` not found", assoc_name))
+ .span_label(span, format!("associated type `{}` not found", assoc_name))
.emit();
return Err(ErrorReported);
}
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name);
- err.span_label(span, &format!("ambiguous associated type `{}`", assoc_name));
+ err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
for bound in bounds {
let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| {
.and_then(|item| self.tcx().hir.span_if_local(item.def_id));
if let Some(span) = bound_span {
- err.span_label(span, &format!("ambiguous `{}` from `{}`",
+ err.span_label(span, format!("ambiguous `{}` from `{}`",
assoc_name,
bound));
} else {
for typ in segment.parameters.types() {
struct_span_err!(self.tcx().sess, typ.span, E0109,
"type parameters are not allowed on this type")
- .span_label(typ.span, &format!("type parameter not allowed"))
+ .span_label(typ.span, "type parameter not allowed")
.emit();
break;
}
struct_span_err!(self.tcx().sess, lifetime.span, E0110,
"lifetime parameters are not allowed on this type")
.span_label(lifetime.span,
- &format!("lifetime parameter not allowed on this type"))
+ "lifetime parameter not allowed on this type")
.emit();
break;
}
pub fn prohibit_projection(&self, span: Span) {
let mut err = struct_span_err!(self.tcx().sess, span, E0229,
"associated type bindings are not allowed here");
- err.span_label(span, &format!("associate type not allowed here")).emit();
+ err.span_label(span, "associate type not allowed here").emit();
}
// Check a type Path and convert it to a Ty.
hir::TyTypeof(ref _e) => {
struct_span_err!(tcx.sess, ast_ty.span, E0516,
"`typeof` is a reserved keyword but unimplemented")
- .span_label(ast_ty.span, &format!("reserved keyword"))
+ .span_label(ast_ty.span, "reserved keyword")
.emit();
tcx.types.err
"wrong number of type arguments: {} {}, found {}",
expected, required, supplied)
.span_label(span,
- &format!("{} {} type argument{}",
+ format!("{} {} type argument{}",
expected,
required,
arguments_plural))
expected, supplied)
.span_label(
span,
- &format!("{} type argument{}",
+ format!("{} type argument{}",
if accepted == 0 { "expected no" } else { &expected },
arguments_plural)
)
struct_span_err!(tcx.sess, span, E0107,
"wrong number of lifetime parameters: expected {}, found {}",
expected, number)
- .span_label(span, &label)
+ .span_label(span, label)
.emit();
}
struct_span_err!(tcx.sess, span, E0029,
"only char and numeric types are allowed in range patterns")
- .span_label(span, &format!("ranges require char or numeric types"))
+ .span_label(span, "ranges require char or numeric types")
.note(&format!("start type: {}", self.ty_to_string(lhs_ty)))
.note(&format!("end type: {}", self.ty_to_string(rhs_ty)))
.emit();
tcx.sess, pat.span, E0527,
"pattern requires {} elements but array has {}",
min_len, size)
- .span_label(pat.span, &format!("expected {} elements",size))
+ .span_label(pat.span, format!("expected {} elements",size))
.emit();
}
(inner_ty, tcx.types.err)
"pattern requires at least {} elements but array has {}",
min_len, size)
.span_label(pat.span,
- &format!("pattern cannot match array of {} elements", size))
+ format!("pattern cannot match array of {} elements", size))
.emit();
(inner_ty, tcx.types.err)
}
}
err.span_label( pat.span,
- &format!("pattern cannot match with input type `{}`", expected_ty)
+ format!("pattern cannot match with input type `{}`", expected_ty)
).emit();
}
(tcx.types.err, tcx.types.err)
let type_str = self.ty_to_string(expected);
struct_span_err!(self.tcx.sess, span, E0033,
"type `{}` cannot be dereferenced", type_str)
- .span_label(span, &format!("type `{}` cannot be dereferenced", type_str))
+ .span_label(span, format!("type `{}` cannot be dereferenced", type_str))
.emit();
return false
}
def.kind_name(),
hir::print::to_string(&tcx.hir, |s| s.print_qpath(qpath, false)));
struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
- .span_label(pat.span, &format!("not a tuple variant or struct")).emit();
+ .span_label(pat.span, "not a tuple variant or struct").emit();
on_error();
};
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(), subpats_ending, def.kind_name(),
variant.fields.len(), fields_ending)
- .span_label(pat.span, &format!("expected {} field{}, found {}",
+ .span_label(pat.span, format!("expected {} field{}, found {}",
variant.fields.len(), fields_ending, subpats.len()))
.emit();
on_error();
in the pattern",
field.name)
.span_label(span,
- &format!("multiple uses of `{}` in pattern", field.name))
- .span_label(*occupied.get(), &format!("first use of `{}`", field.name))
+ format!("multiple uses of `{}` in pattern", field.name))
+ .span_label(*occupied.get(), format!("first use of `{}`", field.name))
.emit();
tcx.types.err
}
tcx.item_path_str(variant.did),
field.name)
.span_label(span,
- &format!("{} `{}` does not have field `{}`",
+ format!("{} `{}` does not have field `{}`",
kind_name,
tcx.item_path_str(variant.did),
field.name))
struct_span_err!(tcx.sess, span, E0027,
"pattern does not mention field `{}`",
field.name)
- .span_label(span, &format!("missing field `{}`", field.name))
+ .span_label(span, format!("missing field `{}`", field.name))
.emit();
}
}
E0055,
"reached the recursion limit while auto-dereferencing {:?}",
self.cur_ty)
- .span_label(self.span, &format!("deref recursion limit reached"))
+ .span_label(self.span, "deref recursion limit reached")
.help(&format!(
"consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit))
pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefId) {
if tcx.lang_items.drop_trait() == Some(trait_id) {
struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method")
- .span_label(span, &format!("explicit destructor calls not allowed"))
+ .span_label(span, "explicit destructor calls not allowed")
.emit();
}
}
},
self.expr_ty);
err.span_label(error_span,
- &format!("cannot cast `{}` as `{}`",
+ format!("cannot cast `{}` as `{}`",
fcx.ty_to_string(self.expr_ty),
cast_ty));
if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
}
CastError::CastToBool => {
struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`")
- .span_label(self.span, &format!("unsupported cast"))
+ .span_label(self.span, "unsupported cast")
.help("compare with zero instead")
.emit();
}
(sig, kind)
}
ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
+ ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)),
_ => (None, None),
}
}
db = struct_span_err!(
fcx.tcx.sess, cause.span, E0069,
"`return;` in a function whose return type is not `()`");
- db.span_label(cause.span, &format!("return type is not ()"));
+ db.span_label(cause.span, "return type is not ()");
}
_ => {
db = fcx.report_mismatched_types(cause, expected, found, err);
"lifetime parameters or bounds on method `{}` do not match the \
trait declaration",
impl_m.name)
- .span_label(span, &format!("lifetimes do not match trait"))
+ .span_label(span, "lifetimes do not match trait")
.emit();
return Err(ErrorReported);
}
not in the trait",
trait_m.name,
self_descr);
- err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr));
+ err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
- err.span_label(span, &format!("trait declared without `{}`", self_descr));
+ err.span_label(span, format!("trait declared without `{}`", self_descr));
}
err.emit();
return Err(ErrorReported);
trait_m.name,
self_descr);
err.span_label(impl_m_span,
- &format!("expected `{}` in impl", self_descr));
+ format!("expected `{}` in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
- err.span_label(span, &format!("`{}` used in trait", self_descr));
+ err.span_label(span, format!("`{}` used in trait", self_descr));
}
err.emit();
return Err(ErrorReported);
if let Some(span) = trait_item_span {
err.span_label(span,
- &format!("expected {}",
+ format!("expected {}",
&if num_trait_m_type_params != 1 {
format!("{} type parameters", num_trait_m_type_params)
} else {
}
err.span_label(span,
- &format!("found {}{}",
+ format!("found {}{}",
&if num_impl_m_type_params != 1 {
format!("{} type parameters", num_impl_m_type_params)
} else {
trait_number_args);
if let Some(trait_span) = trait_span {
err.span_label(trait_span,
- &format!("trait requires {}",
+ format!("trait requires {}",
&if trait_number_args != 1 {
format!("{} parameters", trait_number_args)
} else {
}));
}
err.span_label(impl_span,
- &format!("expected {}, found {}",
+ format!("expected {}, found {}",
&if trait_number_args != 1 {
format!("{} parameters", trait_number_args)
} else {
"intrinsic has wrong number of type \
parameters: found {}, expected {}",
i_n_tps, n_tps)
- .span_label(span, &format!("expected {} type parameter", n_tps))
+ .span_label(span, format!("expected {} type parameter", n_tps))
.emit();
} else {
require_same_types(tcx,
op => {
struct_span_err!(tcx.sess, it.span, E0092,
"unrecognized atomic operation function: `{}`", op)
- .span_label(it.span, &format!("unrecognized atomic operation"))
+ .span_label(it.span, "unrecognized atomic operation")
.emit();
return;
}
struct_span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`",
*other)
- .span_label(it.span, &format!("unrecognized intrinsic"))
+ .span_label(it.span, "unrecognized intrinsic")
.emit();
return;
}
}
}
_ => simple_error(&format!("`{}`", t),
- &format!("tuple")),
+ "tuple"),
}
}
}
self.span,
E0035,
"does not take type parameters")
- .span_label(self.span, &"called with unneeded type parameters")
+ .span_label(self.span, "called with unneeded type parameters")
.emit();
} else {
struct_span_err!(self.tcx.sess,
num_method_types,
num_supplied_types)
.span_label(self.span,
- &format!("Passed {} type argument{}, expected {}",
+ format!("Passed {} type argument{}, expected {}",
num_supplied_types,
if num_supplied_types != 1 { "s" } else { "" },
num_method_types))
for (i, &expr) in exprs.iter().rev().enumerate() {
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
- // Fix up the adjustment.
- let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
- Some(&mut Adjustment {
- kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target
- }) => {
- if let &mut Some(AutoBorrow::Ref(_, ref mut mutbl)) = autoref {
- *mutbl = hir::Mutability::MutMutable;
- *target = match target.sty {
- ty::TyRef(r, ty::TypeAndMut { ty, .. }) =>
- self.tcx.mk_ref(r, ty::TypeAndMut { ty, mutbl: *mutbl }),
- _ => span_bug!(expr.span, "AutoBorrow::Ref resulted in non-ref {:?}",
- target)
- };
- }
- autoderefs
- }
+ // Fix up the autoderefs. Autorefs can only occur immediately preceding
+ // overloaded lvalue ops, and will be fixed by them in order to get
+ // the correct region.
+ let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
+ Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
Some(_) | None => 0
};
let method = self.try_overloaded_lvalue_op(
expr.span, None, base_ty, arg_tys, PreferMutLvalue, op);
- let ok = method.expect("re-trying op failed");
+ let ok = match method {
+ Some(method) => method,
+ None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
+ };
let method = self.register_infer_ok_obligations(ok);
debug!("convert_lvalue_op_to_mutable: method={:?}", method);
self.tables.borrow_mut().method_map.insert(method_call, method);
+
+ // Convert the autoref in the base expr to mutable with the correct
+ // region and mutability.
+ if let Some(&mut Adjustment {
+ ref mut target, kind: Adjust::DerefRef {
+ autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
+ }
+ }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
+ debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
+
+ // extract method return type, which will be &mut T;
+ // all LB regions should have been instantiated during method lookup
+ let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap();
+
+ *target = method_sig.inputs()[0];
+ if let ty::TyRef(r_, mt) = target.sty {
+ *r = r_;
+ *mutbl = mt.mutbl;
+ } else {
+ span_bug!(expr.span, "input to lvalue op is not a ref?");
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
expr_string,
item_name));
}
- err.span_label(span, &"field, not a method");
+ err.span_label(span, "field, not a method");
} else {
- err.span_label(span, &"private field, not a method");
+ err.span_label(span, "private field, not a method");
}
break;
}
span,
E0034,
"multiple applicable items in scope");
- err.span_label(span, &format!("multiple `{}` found", item_name));
+ err.span_label(span, format!("multiple `{}` found", item_name));
report_candidates(&mut err, sources);
err.emit();
struct_span_err!(
tcx.sess, attr.span, E0232,
"this attribute must have a value")
- .span_label(attr.span, &format!("attribute requires a value"))
+ .span_label(attr.span, "attribute requires a value")
.note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
.emit();
}
"`{}` specializes an item from a parent `impl`, but \
that item is not marked `default`",
impl_item.name);
- err.span_label(impl_item.span, &format!("cannot specialize default item `{}`",
+ err.span_label(impl_item.span, format!("cannot specialize default item `{}`",
impl_item.name));
match tcx.span_of_impl(parent_impl) {
Ok(span) => {
- err.span_label(span, &"parent `impl` is here");
+ err.span_label(span, "parent `impl` is here");
err.note(&format!("to specialize, `{}` in the parent `impl` must be marked `default`",
impl_item.name));
}
which doesn't match its trait `{}`",
ty_impl_item.name,
impl_trait_ref);
- err.span_label(impl_item.span, &format!("does not match trait"));
+ err.span_label(impl_item.span, "does not match trait");
// We can only get the spans from local trait definition
// Same for E0324 and E0325
if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
- err.span_label(trait_span, &format!("item in trait"));
+ err.span_label(trait_span, "item in trait");
}
err.emit()
}
which doesn't match its trait `{}`",
ty_impl_item.name,
impl_trait_ref);
- err.span_label(impl_item.span, &format!("does not match trait"));
+ err.span_label(impl_item.span, "does not match trait");
if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
- err.span_label(trait_span, &format!("item in trait"));
+ err.span_label(trait_span, "item in trait");
}
err.emit()
}
which doesn't match its trait `{}`",
ty_impl_item.name,
impl_trait_ref);
- err.span_label(impl_item.span, &format!("does not match trait"));
+ err.span_label(impl_item.span, "does not match trait");
if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
- err.span_label(trait_span, &format!("item in trait"));
+ err.span_label(trait_span, "item in trait");
}
err.emit()
}
missing_items.iter()
.map(|trait_item| trait_item.name.to_string())
.collect::<Vec<_>>().join("`, `"));
- err.span_label(impl_span, &format!("missing `{}` in implementation",
+ err.span_label(impl_span, format!("missing `{}` in implementation",
missing_items.iter()
.map(|trait_item| trait_item.name.to_string())
.collect::<Vec<_>>().join("`, `")));
for trait_item in missing_items {
if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
- err.span_label(span, &format!("`{}` from trait", trait_item.name));
+ err.span_label(span, format!("`{}` from trait", trait_item.name));
} else {
err.note(&format!("`{}` from trait: `{}`",
trait_item.name,
Representability::SelfRecursive(spans) => {
let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
for span in spans {
- err.span_label(span, &"recursive without indirection");
+ err.span_label(span, "recursive without indirection");
}
err.emit();
return false
let e = fields[0].ty(tcx, substs);
if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
- .span_label(sp, &format!("SIMD elements must have the same type"))
+ .span_label(sp, "SIMD elements must have the same type")
.emit();
return;
}
struct_span_err!(
tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum")
- .span_label(sp, &format!("unsupported enum representation"))
+ .span_label(sp, "unsupported enum representation")
.emit();
}
};
struct_span_err!(tcx.sess, span, E0081,
"discriminant value `{}` already exists", disr_vals[i])
- .span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
- .span_label(span , &format!("enum already has `{}`", disr_vals[i]))
+ .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
+ .span_label(span , format!("enum already has `{}`", disr_vals[i]))
.emit();
}
disr_vals.push(discr);
if arg_count == 1 {" was"} else {"s were"}),
error_code);
- err.span_label(sp, &format!("expected {}{} parameter{}",
+ err.span_label(sp, format!("expected {}{} parameter{}",
if variadic {"at least "} else {""},
expected_count,
if expected_count == 1 {""} else {"s"}));
if let Some(def_s) = def_span {
- err.span_label(def_s, &format!("defined here"));
+ err.span_label(def_s, "defined here");
}
err.emit();
}
if let Some(suggested_field_name) =
Self::suggest_field_name(def.struct_variant(), field, vec![]) {
err.span_label(field.span,
- &format!("did you mean `{}`?", suggested_field_name));
+ format!("did you mean `{}`?", suggested_field_name));
} else {
err.span_label(field.span,
- &format!("unknown field"));
+ "unknown field");
};
}
ty::TyRawPtr(..) => {
&field.name,
skip_fields.collect()) {
err.span_label(field.name.span,
- &format!("field does not exist - did you mean `{}`?", field_name));
+ format!("field does not exist - did you mean `{}`?", field_name));
} else {
match ty.sty {
ty::TyAdt(adt, ..) if adt.is_enum() => {
- err.span_label(field.name.span, &format!("`{}::{}` does not have this field",
+ err.span_label(field.name.span, format!("`{}::{}` does not have this field",
ty, variant.name));
}
_ => {
- err.span_label(field.name.span, &format!("`{}` does not have this field", ty));
+ err.span_label(field.name.span, format!("`{}` does not have this field", ty));
}
}
};
"field `{}` specified more than once",
field.name.node);
- err.span_label(field.name.span, &format!("used more than once"));
+ err.span_label(field.name.span, "used more than once");
if let Some(prev_span) = seen_fields.get(&field.name.node) {
- err.span_label(*prev_span, &format!("first use of `{}`", field.name.node));
+ err.span_label(*prev_span, format!("first use of `{}`", field.name.node));
}
err.emit();
remaining_fields_names,
truncated_fields_error,
adt_ty)
- .span_label(span, &format!("missing {}{}",
+ .span_label(span, format!("missing {}{}",
remaining_fields_names,
truncated_fields_error))
.emit();
struct_span_err!(self.tcx.sess, path_span, E0071,
"expected struct, variant or union type, found {}",
ty.sort_string(self.tcx))
- .span_label(path_span, &format!("not a struct"))
+ .span_label(path_span, "not a struct")
.emit();
None
}
"invalid left-hand side expression")
.span_label(
expr.span,
- &format!("left-hand of expression not valid"))
+ "left-hand of expression not valid")
.emit();
}
"too many lifetime parameters provided: \
expected at most {}, found {}",
expected_text, actual_text)
- .span_label(span, &format!("expected {}", expected_text))
+ .span_label(span, format!("expected {}", expected_text))
.emit();
} else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
let expected_text = count_lifetime_params(lifetime_defs.len());
"too few lifetime parameters provided: \
expected {}, found {}",
expected_text, actual_text)
- .span_label(span, &format!("expected {}", expected_text))
+ .span_label(span, format!("expected {}", expected_text))
.emit();
}
"too many type parameters provided: \
expected at most {}, found {}",
expected_text, actual_text)
- .span_label(span, &format!("expected {}", expected_text))
+ .span_label(span, format!("expected {}", expected_text))
.emit();
// To prevent derived errors to accumulate due to extra
"too few type parameters provided: \
expected {}, found {}",
expected_text, actual_text)
- .span_label(span, &format!("expected {}", expected_text))
+ .span_label(span, format!("expected {}", expected_text))
.emit();
}
struct_span_err!(tcx.sess, param.span, E0091,
"type parameter `{}` is unused",
param.name)
- .span_label(param.span, &format!("unused type parameter"))
+ .span_label(param.span, "unused type parameter")
.emit();
}
}
E0067, "invalid left-hand side expression")
.span_label(
lhs_expr.span,
- &format!("invalid expression for left-hand side"))
+ "invalid expression for left-hand side")
.emit();
}
ty
op.node.as_str(),
lhs_ty)
.span_label(lhs_expr.span,
- &format!("cannot use `{}=` on type `{}`",
+ format!("cannot use `{}=` on type `{}`",
op.node.as_str(), lhs_ty))
.emit();
} else {
if let TyRef(_, r_ty) = rhs_ty.sty {
if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
err.span_label(expr.span,
- &"`+` can't be used to concatenate two `&str` strings");
+ "`+` can't be used to concatenate two `&str` strings");
let codemap = self.tcx.sess.codemap();
let suggestion =
match codemap.span_to_snippet(lhs_expr.span) {
-> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(tcx.sess, span, E0392,
"parameter `{}` is never used", param_name);
- err.span_label(span, &format!("unused type parameter"));
+ err.span_label(span, "unused type parameter");
err
}
struct_span_err!(tcx.sess, span, E0194,
"type parameter `{}` shadows another type parameter of the same name",
name)
- .span_label(span, &format!("shadows another type parameter"))
- .span_label(trait_decl_span, &format!("first `{}` declared here", name))
+ .span_label(span, "shadows another type parameter")
+ .span_label(trait_decl_span, format!("first `{}` declared here", name))
.emit();
}
E0120,
"the Drop trait may only be implemented on \
structures")
- .span_label(span, &format!("implementing Drop requires a struct"))
+ .span_label(span, "implementing Drop requires a struct")
.emit();
}
_ => {
"the trait `Copy` may not be implemented for this type")
.span_label(
tcx.def_span(field.did),
- &"this field does not implement `Copy`")
+ "this field does not implement `Copy`")
.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
span,
E0206,
"the trait `Copy` may not be implemented for this type")
- .span_label(span, &format!("type is not a structure or enumeration"))
+ .span_label(span, "type is not a structure or enumeration")
.emit();
}
Err(CopyImplementationError::HasDestructor) => {
E0184,
"the trait `Copy` may not be implemented for this type; the \
type has a destructor")
- .span_label(span, &format!("Copy not allowed on types with destructors"))
+ .span_label(span, "Copy not allowed on types with destructors")
.emit();
}
}
})
.collect::<Vec<_>>()
.join(", ")));
- err.span_label(span, &format!("requires multiple coercions"));
+ err.span_label(span, "requires multiple coercions");
err.emit();
return err_info;
}
ty.span,
E0118,
"no base type found for inherent implementation")
- .span_label(ty.span, &format!("impl requires a base type"))
+ .span_label(ty.span, "impl requires a base type")
.note(&format!("either implement a trait on it or create a newtype \
to wrap it instead"))
.emit();
"cannot define inherent `impl` for a type outside of the crate \
where the type is defined")
.span_label(item.span,
- &format!("impl for type defined outside of crate."))
+ "impl for type defined outside of crate.")
.note("define and implement a trait or new type instead")
.emit();
}
"duplicate definitions with name `{}`",
name)
.span_label(self.tcx.span_of_impl(item1).unwrap(),
- &format!("duplicate definitions for `{}`", name))
+ format!("duplicate definitions for `{}`", name))
.span_label(self.tcx.span_of_impl(item2).unwrap(),
- &format!("other definition for `{}`", name))
+ format!("other definition for `{}`", name))
.emit();
}
}
span,
E0322,
"explicit impls for the `Sized` trait are not permitted")
- .span_label(span, &format!("impl of 'Sized' not allowed"))
+ .span_label(span, "impl of 'Sized' not allowed")
.emit();
return;
}
E0117,
"only traits defined in the current crate can be \
implemented for arbitrary types")
- .span_label(item.span, &format!("impl doesn't use types inside crate"))
+ .span_label(item.span, "impl doesn't use types inside crate")
.note(&format!("the impl does not reference any types defined in \
this crate"))
.note("define and implement a trait or new type instead")
"cannot create default implementations for traits outside \
the crate they're defined in; define a new trait instead")
.span_label(item_trait_ref.path.span,
- &format!("`{}` trait not defined in this crate",
+ format!("`{}` trait not defined in this crate",
self.tcx.hir.node_to_pretty_string(item_trait_ref.ref_id)))
.emit();
return;
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
- err.span_label(span, &format!("first implementation here"));
+ err.span_label(span, "first implementation here");
err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
- &format!("conflicting implementation{}",
+ format!("conflicting implementation{}",
overlap.self_desc
.map_or(String::new(),
|ty| format!(" for `{}`", ty))));
span,
E0121,
"the type placeholder `_` is not allowed within types on item signatures"
- ).span_label(span, &format!("not allowed in type signatures"))
+ ).span_label(span, "not allowed in type signatures")
.emit();
self.tcx().types.err
}
} else {
struct_span_err!(tcx.sess, variant.span, E0370,
"enum discriminant overflowed")
- .span_label(variant.span, &format!("overflowed on value after {}",
+ .span_label(variant.span, format!("overflowed on value after {}",
prev_discr.unwrap()))
.note(&format!("explicitly set `{} = {}` if that is desired outcome",
variant.node.name, wrapped_discr))
struct_span_err!(tcx.sess, f.span, E0124,
"field `{}` is already declared",
f.name)
- .span_label(f.span, &"field already declared")
- .span_label(prev_span, &format!("`{}` first declared here", f.name))
+ .span_label(f.span, "field already declared")
+ .span_label(prev_span, format!("`{}` first declared here", f.name))
.emit();
} else {
seen_fields.insert(f.name, f.span);
"the {} parameter `{}` is not constrained by the \
impl trait, self type, or predicates",
kind, name)
- .span_label(span, &format!("unconstrained {} parameter", kind))
+ .span_label(span, format!("unconstrained {} parameter", kind))
.emit();
}
"duplicate definitions with name `{}`:",
impl_item.name);
err.span_label(*entry.get(),
- &format!("previous definition of `{}` here",
+ format!("previous definition of `{}` here",
impl_item.name));
- err.span_label(impl_item.span, &format!("duplicate definition"));
+ err.span_label(impl_item.span, "duplicate definition");
err.emit();
}
Vacant(entry) => {
if decl.variadic && abi != Abi::C {
let mut err = struct_span_err!(tcx.sess, span, E0045,
"variadic function must have C calling convention");
- err.span_label(span, &("variadics require C calling conventions").to_string())
+ err.span_label(span, "variadics require C calling conventions")
.emit();
}
}
struct_span_err!(tcx.sess, generics.span, E0131,
"main function is not allowed to have type parameters")
.span_label(generics.span,
- &format!("main cannot have type parameters"))
+ "main cannot have type parameters")
.emit();
return;
}
struct_span_err!(tcx.sess, ps.span, E0132,
"start function is not allowed to have type parameters")
.span_label(ps.span,
- &format!("start function cannot have type parameters"))
+ "start function cannot have type parameters")
.emit();
return;
}
}
}
clean::Vector(ref t) if is_not_debug => {
- primitive_link(f, PrimitiveType::Slice, &format!("["))?;
+ primitive_link(f, PrimitiveType::Slice, "[")?;
fmt::Display::fmt(t, f)?;
- primitive_link(f, PrimitiveType::Slice, &format!("]"))
+ primitive_link(f, PrimitiveType::Slice, "]")
}
clean::Vector(ref t) => write!(f, "[{:?}]", t),
clean::FixedVector(ref t, ref s) if is_not_debug => {
let tmpdir = tmpdir();
let unicode = tmpdir.path();
- let unicode = unicode.join(&format!("test-각丁ー再见"));
+ let unicode = unicode.join("test-각丁ー再见");
check!(fs::create_dir(&unicode));
assert!(unicode.exists());
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
} else {
struct_span_err!(diag, attr.span, E0558,
"export_name attribute has invalid format")
- .span_label(attr.span,
- &format!("did you mean #[export_name=\"*\"]?"))
+ .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
.emit();
None
}
use symbol::Symbol;
use util::small_vector::SmallVector;
+use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;
use std::default::Default;
pub resolver: &'a mut Resolver,
pub resolve_err_count: usize,
pub current_expansion: ExpansionData,
+ pub expansions: HashMap<Span, Vec<String>>,
}
impl<'a> ExtCtxt<'a> {
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
directory_ownership: DirectoryOwnership::Owned,
},
+ expansions: HashMap::new(),
}
}
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.parse_sess.span_diagnostic.span_bug(sp, msg);
}
+ pub fn trace_macros_diag(&self) {
+ for (sp, notes) in self.expansions.iter() {
+ let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, &"trace_macro");
+ for note in notes {
+ db.note(¬e);
+ }
+ db.emit();
+ }
+ }
pub fn bug(&self, msg: &str) -> ! {
self.parse_sess.span_diagnostic.bug(msg);
}
},
_ => unreachable!(),
};
-
+ self.cx.trace_macros_diag();
krate
}
use tokenstream::{TokenStream, TokenTree};
use std::cell::RefCell;
-use std::collections::{HashMap};
-use std::collections::hash_map::{Entry};
+use std::collections::HashMap;
+use std::collections::hash_map::Entry;
use std::rc::Rc;
pub struct ParserAnyMacro<'a> {
}
/// Given `lhses` and `rhses`, this is the new macro we create
-fn generic_extension<'cx>(cx: &'cx ExtCtxt,
+fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
sp: Span,
name: ast::Ident,
arg: TokenStream,
rhses: &[quoted::TokenTree])
-> Box<MacResult+'cx> {
if cx.trace_macros() {
- println!("{}! {{ {} }}", name, arg);
+ let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
+ let mut values: &mut Vec<String> = cx.expansions.entry(sp).or_insert(vec![]);
+ values.push(format!("expands to `{}! {{ {} }}`", name, arg));
}
// Which arm's failure should we report? (the one furthest along)
self.bump();
// line comments starting with "///" or "//!" are doc-comments
- let doc_comment = self.ch_is('/') || self.ch_is('!');
+ let doc_comment = (self.ch_is('/') && !self.nextch_is('/')) || self.ch_is('!');
let start_bpos = self.pos - BytePos(2);
while !self.is_eof() {
label_sp
};
if self.span.contains(sp) {
- err.span_label(self.span, &label_exp);
+ err.span_label(self.span, label_exp);
} else {
- err.span_label(sp, &label_exp);
- err.span_label(self.span, &"unexpected token");
+ err.span_label(sp, label_exp);
+ err.span_label(self.span, "unexpected token");
}
Err(err)
}
err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens);
}
TyKind::Ptr(..) | TyKind::BareFn(..) => {
- err.span_label(sum_span, &"perhaps you forgot parentheses?");
+ err.span_label(sum_span, "perhaps you forgot parentheses?");
}
_ => {
- err.span_label(sum_span, &"expected a path");
+ err.span_label(sum_span, "expected a path");
},
}
err.emit();
let fstr = n.as_str();
let mut err = self.diagnostic().struct_span_err(self.prev_span,
&format!("unexpected token: `{}`", n));
- err.span_label(self.prev_span, &"unexpected token");
+ err.span_label(self.prev_span, "unexpected token");
if fstr.chars().all(|x| "0123456789.".contains(x)) {
let float = match fstr.parse::<f64>().ok() {
Some(f) => f,
let span_of_tilde = lo;
let mut err = self.diagnostic().struct_span_err(span_of_tilde,
"`~` can not be used as a unary operator");
- err.span_label(span_of_tilde, &"did you mean `!`?");
+ err.span_label(span_of_tilde, "did you mean `!`?");
err.help("use `!` instead of `~` if you meant to perform bitwise negation");
err.emit();
(span, self.mk_unary(UnOp::Not, e))
sp,
&format!("missing `fn`, `type`, or `const` for {}-item declaration",
item_type));
- err.span_label(sp, &"missing `fn`, `type`, or `const`");
+ err.span_label(sp, "missing `fn`, `type`, or `const`");
err
}
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+ let mut a = 0u8;
+ let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+ //~^ ERROR mismatched types
+}
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+ let b = 0u8;
+ let bar: fn() -> u8 = || { b };
+ //~^ ERROR mismatched types
+}
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+ let b = 0u8;
+ let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
+ //~^ ERROR non-scalar cast
+}
+++ /dev/null
-// Copyright 2017 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Ensure that capturing closures are never coerced to fns
-// Especially interesting as non-capturing closures can be.
-
-fn main() {
- let mut a = 0u8;
- let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
- //~^ ERROR mismatched types
- let b = 0u8;
- let bar: fn() -> u8 = || { b };
- //~^ ERROR mismatched types
- let baz: fn() -> u8 = || { b } as fn() -> u8;
- //~^ ERROR mismatched types
- //~^^ ERROR non-scalar cast
-}
#![feature(closure_to_fn_coercion)]
fn main() {
- let bar: fn(&mut u32) = |_| {}; //~ ERROR mismatched types
- //~| expected concrete lifetime, found bound lifetime parameter
+ let bar: fn(&mut u32) = |_| {};
fn foo(x: Box<Fn(&i32)>) {}
let bar = Box::new(|x: &i32| {}) as Box<Fn(_)>;
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Matching against float literals should result in a linter error
+
+#![feature(slice_patterns)]
+#![feature(exclusive_range_pattern)]
+#![allow(unused)]
+#![forbid(illegal_floating_point_literal_pattern)]
+
+fn main() {
+ let x = 42.0;
+ match x {
+ 5.0 => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ 5.0f32 => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ -5.0 => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ 1.0 .. 33.0 => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ //~| ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ 39.0 ... 70.0 => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ //~| ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ _ => {},
+ };
+ let y = 5.0;
+ // Same for tuples
+ match (x, 5) {
+ (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ //~| ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ _ => {},
+ }
+ // Or structs
+ struct Foo { x: f32 };
+ match (Foo { x }) {
+ Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ //~| ERROR floating-point literals cannot be used
+ //~| WARNING hard error
+ _ => {},
+ }
+}
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+fn main() {
+ let things: HashMap<String, Vec<String>> = HashMap::new();
+ for src in things.keys() {
+ things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
+ }
+}
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::{Index, IndexMut};
+
+struct S;
+struct H;
+
+impl S {
+ fn f(&mut self) {}
+}
+
+impl Index<u32> for H {
+ type Output = S;
+ fn index(&self, index: u32) -> &S {
+ unimplemented!()
+ }
+}
+
+impl IndexMut<u32> for H {
+ fn index_mut(&mut self, index: u32) -> &mut S {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ H["?"].f(); //~ ERROR mismatched types
+}
// except according to those terms.
#![feature(slice_patterns)]
+#![allow(illegal_floating_point_literal_pattern)]
enum t { a, b, }
--- /dev/null
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that we link regions in mutable lvalue ops correctly - issue #41774
+
+struct Data(i32);
+
+trait OhNo {
+ fn oh_no(&mut self, other: &Vec<Data>) { loop {} }
+}
+
+impl OhNo for Data {}
+impl OhNo for [Data] {}
+
+fn main() {
+ let mut v = vec![Data(0)];
+ v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
+ (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
+}
//~^^ ERROR: bare CR not allowed in block doc-comment
fn main() {
+ //! doc comment with bare CR: '\r'
+ //~^ ERROR: bare CR not allowed in doc-comment
+
+ /*! block doc comment with bare CR: '\r' */
+ //~^ ERROR: bare CR not allowed in block doc-comment
+
// the following string literal has a bare CR in it
let _s = "foo\rbar"; //~ ERROR: bare CR not allowed in string
+++ /dev/null
-# This test verifies that "-Z trace-macros" works as it should. The traditional
-# "hello world" program provides a small example of this as not only println! is
-# listed, but also print! (since println! expands to this)
-
--include ../tools.mk
-
-all:
- $(RUSTC) -Z trace-macros hello.rs > $(TMPDIR)/hello.out
- diff -u $(TMPDIR)/hello.out hello.trace
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- println!("Hello, World!");
-}
+++ /dev/null
-println! { "Hello, World!" }
-print! { concat ! ( "Hello, World!" , "\n" ) }
const X: i32 = 97;
}
+struct Proxy<T>(T);
+
+impl<T: Foo> Foo for Proxy<T> {
+ const X: i32 = T::X;
+}
+
fn sub<A: Foo, B: Foo>() -> i32 {
A::X - B::X
}
assert_eq!(97, Def::get_x());
assert_eq!(-86, sub::<Abc, Def>());
assert_eq!(86, sub::<Def, Abc>());
+ assert_eq!(-86, sub::<Proxy<Abc>, Def>());
+ assert_eq!(-86, sub::<Abc, Proxy<Def>>());
+ assert_eq!(86, sub::<Proxy<Def>, Proxy<Abc>>());
}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+// Ensure that we deduce expected argument types when a `fn()` type is expected (#41755)
+
+#![feature(closure_to_fn_coercion)]
+fn foo(f: fn(Vec<u32>) -> usize) { }
+
+fn main() {
+ foo(|x| x.len())
+}
--- /dev/null
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Zdump-mir=NEVER_MATCHED
+
+// Regression test for #41697. Using dump-mir was triggering
+// artificial cycles: during type-checking, we had to get the MIR for
+// the constant expressions in `[u8; 2]`, which in turn would trigger
+// an attempt to get the item-path, which in turn would request the
+// types of the impl, which would trigger a cycle. We supressed this
+// cycle now by forcing mir-dump to avoid asking for types of an impl.
+
+#![feature(rustc_attrs)]
+
+use std::sync::Arc;
+
+trait Foo {
+ fn get(&self) -> [u8; 2];
+}
+
+impl Foo for [u8; 2] {
+ fn get(&self) -> [u8; 2] {
+ *self
+ }
+}
+
+struct Bar<T: ?Sized>(T);
+
+fn unsize_fat_ptr<'a>(x: &'a Bar<Foo + Send + 'a>) -> &'a Bar<Foo + 'a> {
+ x
+}
+
+fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> {
+ x
+}
+
+fn main() {
+ let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2]));
+ assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]);
+
+ let x: Arc<Foo + Send> = Arc::new([3, 4]);
+ assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]);
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-cr
+
+// nondoc comment with bare CR: '\r'
+//// nondoc comment with bare CR: '\r'
+/* block nondoc comment with bare CR: '\r' */
+
+fn main() {
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z trace-macros
+
+fn main() {
+ println!("Hello, World!");
+}
--- /dev/null
+note: trace_macro
+ --> $DIR/trace-macro.rs:14:5
+ |
+14 | println!("Hello, World!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: expands to `println! { "Hello, World!" }`
+ = note: expands to `print! { concat ! ( "Hello, World!" , "/n" ) }`
+