Auto merge of #41717 - frewsxcv:rollup, r=frewsxcv

Rollup of 7 pull requests

- Successful merges: #41217, #41625, #41640, #41653, #41656, #41657, #41705
- Failed merges:
This commit is contained in:
bors
2017-05-03 03:24:35 +00:00
74 changed files with 1361 additions and 5529 deletions
-4
View File
@@ -1,4 +0,0 @@
verify
*.class
*.java
*.tokens
-33
View File
@@ -1,33 +0,0 @@
# Reference grammar.
Uses [antlr4](http://www.antlr.org/) and a custom Rust tool to compare
ASTs/token streams generated. You can use the `make check-lexer` target to
run all of the available tests.
The build of the rust part is included with `make tidy` and can be run with `make check-build-lexer-verifier`.
# Manual build
To use manually, assuming antlr4 is installed at `/usr/share/java/antlr-complete.jar`:
```
antlr4 RustLexer.g4
javac -classpath /usr/share/java/antlr-complete.jar *.java
rustc -O verify.rs
for file in ../*/**.rs; do
echo $file;
grun RustLexer tokens -tokens < "$file" | ./verify "$file" RustLexer.tokens || break
done
```
Note that the `../*/**.rs` glob will match every `*.rs` file in the above
directory and all of its recursive children. This is a Zsh extension.
## Cleanup
To cleanup you can use a command like this:
```bash
rm -f verify *.class *.java *.tokens
```
-197
View File
@@ -1,197 +0,0 @@
lexer grammar RustLexer;
@lexer::members {
public boolean is_at(int pos) {
return _input.index() == pos;
}
}
tokens {
EQ, LT, LE, EQEQ, NE, GE, GT, ANDAND, OROR, NOT, TILDE, PLUS,
MINUS, STAR, SLASH, PERCENT, CARET, AND, OR, SHL, SHR, BINOP,
BINOPEQ, LARROW, AT, DOT, DOTDOT, DOTDOTDOT, COMMA, SEMI, COLON,
MOD_SEP, RARROW, FAT_ARROW, LPAREN, RPAREN, LBRACKET, RBRACKET,
LBRACE, RBRACE, POUND, DOLLAR, UNDERSCORE, LIT_CHAR, LIT_BYTE,
LIT_INTEGER, LIT_FLOAT, LIT_STR, LIT_STR_RAW, LIT_BYTE_STR,
LIT_BYTE_STR_RAW, QUESTION, IDENT, LIFETIME, WHITESPACE, DOC_COMMENT,
COMMENT, SHEBANG, UTF8_BOM
}
import xidstart , xidcontinue;
/* Expression-operator symbols */
EQ : '=' ;
LT : '<' ;
LE : '<=' ;
EQEQ : '==' ;
NE : '!=' ;
GE : '>=' ;
GT : '>' ;
ANDAND : '&&' ;
OROR : '||' ;
NOT : '!' ;
TILDE : '~' ;
PLUS : '+' ;
MINUS : '-' ;
STAR : '*' ;
SLASH : '/' ;
PERCENT : '%' ;
CARET : '^' ;
AND : '&' ;
OR : '|' ;
SHL : '<<' ;
SHR : '>>' ;
LARROW : '<-' ;
BINOP
: PLUS
| SLASH
| MINUS
| STAR
| PERCENT
| CARET
| AND
| OR
| SHL
| SHR
| LARROW
;
BINOPEQ : BINOP EQ ;
/* "Structural symbols" */
AT : '@' ;
DOT : '.' ;
DOTDOT : '..' ;
DOTDOTDOT : '...' ;
COMMA : ',' ;
SEMI : ';' ;
COLON : ':' ;
MOD_SEP : '::' ;
RARROW : '->' ;
FAT_ARROW : '=>' ;
LPAREN : '(' ;
RPAREN : ')' ;
LBRACKET : '[' ;
RBRACKET : ']' ;
LBRACE : '{' ;
RBRACE : '}' ;
POUND : '#';
DOLLAR : '$' ;
UNDERSCORE : '_' ;
// Literals
fragment HEXIT
: [0-9a-fA-F]
;
fragment CHAR_ESCAPE
: [nrt\\'"0]
| [xX] HEXIT HEXIT
| 'u' HEXIT HEXIT HEXIT HEXIT
| 'U' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT
| 'u{' HEXIT '}'
| 'u{' HEXIT HEXIT '}'
| 'u{' HEXIT HEXIT HEXIT '}'
| 'u{' HEXIT HEXIT HEXIT HEXIT '}'
| 'u{' HEXIT HEXIT HEXIT HEXIT HEXIT '}'
| 'u{' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT '}'
;
fragment SUFFIX
: IDENT
;
fragment INTEGER_SUFFIX
: { _input.LA(1) != 'e' && _input.LA(1) != 'E' }? SUFFIX
;
LIT_CHAR
: '\'' ( '\\' CHAR_ESCAPE
| ~[\\'\n\t\r]
| '\ud800' .. '\udbff' '\udc00' .. '\udfff'
)
'\'' SUFFIX?
;
LIT_BYTE
: 'b\'' ( '\\' ( [xX] HEXIT HEXIT
| [nrt\\'"0] )
| ~[\\'\n\t\r] '\udc00'..'\udfff'?
)
'\'' SUFFIX?
;
LIT_INTEGER
: [0-9][0-9_]* INTEGER_SUFFIX?
| '0b' [01_]+ INTEGER_SUFFIX?
| '0o' [0-7_]+ INTEGER_SUFFIX?
| '0x' [0-9a-fA-F_]+ INTEGER_SUFFIX?
;
LIT_FLOAT
: [0-9][0-9_]* ('.' {
/* dot followed by another dot is a range, not a float */
_input.LA(1) != '.' &&
/* dot followed by an identifier is an integer with a function call, not a float */
_input.LA(1) != '_' &&
!(_input.LA(1) >= 'a' && _input.LA(1) <= 'z') &&
!(_input.LA(1) >= 'A' && _input.LA(1) <= 'Z')
}? | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?)
;
LIT_STR
: '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"' SUFFIX?
;
LIT_BYTE_STR : 'b' LIT_STR ;
LIT_BYTE_STR_RAW : 'b' LIT_STR_RAW ;
/* this is a bit messy */
fragment LIT_STR_RAW_INNER
: '"' .*? '"'
| LIT_STR_RAW_INNER2
;
fragment LIT_STR_RAW_INNER2
: POUND LIT_STR_RAW_INNER POUND
;
LIT_STR_RAW
: 'r' LIT_STR_RAW_INNER SUFFIX?
;
QUESTION : '?';
IDENT : XID_Start XID_Continue* ;
fragment QUESTION_IDENTIFIER : QUESTION? IDENT;
LIFETIME : '\'' IDENT ;
WHITESPACE : [ \r\n\t]+ ;
UNDOC_COMMENT : '////' ~[\n]* -> type(COMMENT) ;
YESDOC_COMMENT : '///' ~[\r\n]* -> type(DOC_COMMENT) ;
OUTER_DOC_COMMENT : '//!' ~[\r\n]* -> type(DOC_COMMENT) ;
LINE_COMMENT : '//' ( ~[/\n] ~[\n]* )? -> type(COMMENT) ;
DOC_BLOCK_COMMENT
: ('/**' ~[*] | '/*!') (DOC_BLOCK_COMMENT | .)*? '*/' -> type(DOC_COMMENT)
;
BLOCK_COMMENT : '/*' (BLOCK_COMMENT | .)*? '*/' -> type(COMMENT) ;
/* these appear at the beginning of a file */
SHEBANG : '#!' { is_at(2) && _input.LA(1) != '[' }? ~[\r\n]* -> type(SHEBANG) ;
UTF8_BOM : '\ufeff' { is_at(1) }? -> skip ;
-52
View File
@@ -1,52 +0,0 @@
#!/bin/sh
# ignore-license
# Run the reference lexer against libsyntax and compare the tokens and spans.
# If "// ignore-lexer-test" is present in the file, it will be ignored.
# Argument $1 is the file to check, $2 is the classpath to use, $3 is the path
# to the grun binary, $4 is the path to the verify binary, $5 is the path to
# RustLexer.tokens
if [ "${VERBOSE}" == "1" ]; then
set -x
fi
passed=0
failed=0
skipped=0
check() {
grep --silent "// ignore-lexer-test" "$1";
# if it is *not* found...
if [ $? -eq 1 ]; then
cd $2 # This `cd` is so java will pick up RustLexer.class. I could not
# figure out how to wrangle the CLASSPATH, just adding build/grammar
# did not seem to have any effect.
if $3 RustLexer tokens -tokens < $1 | $4 $1 $5; then
echo "pass: $1"
passed=`expr $passed + 1`
else
echo "fail: $1"
failed=`expr $failed + 1`
fi
else
echo "skip: $1"
skipped=`expr $skipped + 1`
fi
}
for file in $(find $1 -iname '*.rs' ! -path '*/test/compile-fail*'); do
check "$file" $2 $3 $4 $5
done
printf "\ntest result: "
if [ $failed -eq 0 ]; then
printf "ok. $passed passed; $failed failed; $skipped skipped\n\n"
else
printf "failed. $passed passed; $failed failed; $skipped skipped\n\n"
exit 1
fi
-343
View File
@@ -1,343 +0,0 @@
%{
// 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; }
%%
-203
View File
@@ -1,203 +0,0 @@
// 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);
}
-1945
View File
@@ -1,1945 +0,0 @@
// 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("]")));
}
;
@@ -1,64 +0,0 @@
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.
-76
View File
@@ -1,76 +0,0 @@
#!/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")
-91
View File
@@ -1,91 +0,0 @@
// 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
};
-361
View File
@@ -1,361 +0,0 @@
// 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.
#![feature(plugin, rustc_private)]
extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
#[macro_use]
extern crate log;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufRead, Read};
use std::path::Path;
use syntax::parse::lexer;
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::middle::cstore::DummyCrateStore;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap;
use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token};
use syntax::parse::lexer::TokenAndSpan;
use syntax_pos::Pos;
use syntax::symbol::{Symbol, keywords};
fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
fn id() -> token::Token {
Token::Ident(ast::Ident::with_empty_ctxt(keywords::Invalid.name()))
}
let mut res = HashMap::new();
res.insert("-1".to_string(), Token::Eof);
for line in file.split('\n') {
let eq = match line.trim().rfind('=') {
Some(val) => val,
None => continue
};
let val = &line[..eq];
let num = &line[eq + 1..];
let tok = match val {
"SHR" => Token::BinOp(BinOpToken::Shr),
"DOLLAR" => Token::Dollar,
"LT" => Token::Lt,
"STAR" => Token::BinOp(BinOpToken::Star),
"FLOAT_SUFFIX" => id(),
"INT_SUFFIX" => id(),
"SHL" => Token::BinOp(BinOpToken::Shl),
"LBRACE" => Token::OpenDelim(DelimToken::Brace),
"RARROW" => Token::RArrow,
"LIT_STR" => Token::Literal(Lit::Str_(keywords::Invalid.name()), None),
"DOTDOT" => Token::DotDot,
"MOD_SEP" => Token::ModSep,
"DOTDOTDOT" => Token::DotDotDot,
"NOT" => Token::Not,
"AND" => Token::BinOp(BinOpToken::And),
"LPAREN" => Token::OpenDelim(DelimToken::Paren),
"ANDAND" => Token::AndAnd,
"AT" => Token::At,
"LBRACKET" => Token::OpenDelim(DelimToken::Bracket),
"LIT_STR_RAW" => Token::Literal(Lit::StrRaw(keywords::Invalid.name(), 0), None),
"RPAREN" => Token::CloseDelim(DelimToken::Paren),
"SLASH" => Token::BinOp(BinOpToken::Slash),
"COMMA" => Token::Comma,
"LIFETIME" => Token::Lifetime(
ast::Ident::with_empty_ctxt(keywords::Invalid.name())),
"CARET" => Token::BinOp(BinOpToken::Caret),
"TILDE" => Token::Tilde,
"IDENT" => id(),
"PLUS" => Token::BinOp(BinOpToken::Plus),
"LIT_CHAR" => Token::Literal(Lit::Char(keywords::Invalid.name()), None),
"LIT_BYTE" => Token::Literal(Lit::Byte(keywords::Invalid.name()), None),
"EQ" => Token::Eq,
"RBRACKET" => Token::CloseDelim(DelimToken::Bracket),
"COMMENT" => Token::Comment,
"DOC_COMMENT" => Token::DocComment(keywords::Invalid.name()),
"DOT" => Token::Dot,
"EQEQ" => Token::EqEq,
"NE" => Token::Ne,
"GE" => Token::Ge,
"PERCENT" => Token::BinOp(BinOpToken::Percent),
"RBRACE" => Token::CloseDelim(DelimToken::Brace),
"BINOP" => Token::BinOp(BinOpToken::Plus),
"POUND" => Token::Pound,
"OROR" => Token::OrOr,
"LIT_INTEGER" => Token::Literal(Lit::Integer(keywords::Invalid.name()), None),
"BINOPEQ" => Token::BinOpEq(BinOpToken::Plus),
"LIT_FLOAT" => Token::Literal(Lit::Float(keywords::Invalid.name()), None),
"WHITESPACE" => Token::Whitespace,
"UNDERSCORE" => Token::Underscore,
"MINUS" => Token::BinOp(BinOpToken::Minus),
"SEMI" => Token::Semi,
"COLON" => Token::Colon,
"FAT_ARROW" => Token::FatArrow,
"OR" => Token::BinOp(BinOpToken::Or),
"GT" => Token::Gt,
"LE" => Token::Le,
"LIT_BINARY" => Token::Literal(Lit::ByteStr(keywords::Invalid.name()), None),
"LIT_BINARY_RAW" => Token::Literal(
Lit::ByteStrRaw(keywords::Invalid.name(), 0), None),
"QUESTION" => Token::Question,
"SHEBANG" => Token::Shebang(keywords::Invalid.name()),
_ => continue,
};
res.insert(num.to_string(), tok);
}
debug!("Token map: {:?}", res);
res
}
fn str_to_binop(s: &str) -> token::BinOpToken {
match s {
"+" => BinOpToken::Plus,
"/" => BinOpToken::Slash,
"-" => BinOpToken::Minus,
"*" => BinOpToken::Star,
"%" => BinOpToken::Percent,
"^" => BinOpToken::Caret,
"&" => BinOpToken::And,
"|" => BinOpToken::Or,
"<<" => BinOpToken::Shl,
">>" => BinOpToken::Shr,
_ => panic!("Bad binop str `{}`", s),
}
}
/// Assuming a string/byte string literal, strip out the leading/trailing
/// hashes and surrounding quotes/raw/byte prefix.
fn fix(mut lit: &str) -> ast::Name {
let prefix: Vec<char> = lit.chars().take(2).collect();
if prefix[0] == 'r' {
if prefix[1] == 'b' {
lit = &lit[2..]
} else {
lit = &lit[1..];
}
} else if prefix[0] == 'b' {
lit = &lit[1..];
}
let leading_hashes = count(lit);
// +1/-1 to adjust for single quotes
Symbol::intern(&lit[leading_hashes + 1..lit.len() - leading_hashes - 1])
}
/// Assuming a char/byte literal, strip the 'b' prefix and the single quotes.
fn fixchar(mut lit: &str) -> ast::Name {
let prefix = lit.chars().next().unwrap();
if prefix == 'b' {
lit = &lit[1..];
}
Symbol::intern(&lit[1..lit.len() - 1])
}
fn count(lit: &str) -> usize {
lit.chars().take_while(|c| *c == '#').count()
}
fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>, surrogate_pairs_pos: &[usize],
has_bom: bool)
-> TokenAndSpan {
// old regex:
// \[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]
let start = s.find("[@").unwrap();
let comma = start + s[start..].find(",").unwrap();
let colon = comma + s[comma..].find(":").unwrap();
let content_start = colon + s[colon..].find("='").unwrap();
// Use rfind instead of find, because we don't want to stop at the content
let content_end = content_start + s[content_start..].rfind("',<").unwrap();
let toknum_end = content_end + s[content_end..].find(">,").unwrap();
let start = &s[comma + 1 .. colon];
let end = &s[colon + 1 .. content_start];
let content = &s[content_start + 2 .. content_end];
let toknum = &s[content_end + 3 .. toknum_end];
let not_found = format!("didn't find token {:?} in the map", toknum);
let proto_tok = tokens.get(toknum).expect(&not_found);
let nm = Symbol::intern(content);
debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok);
let real_tok = match *proto_tok {
Token::BinOp(..) => Token::BinOp(str_to_binop(content)),
Token::BinOpEq(..) => Token::BinOpEq(str_to_binop(&content[..content.len() - 1])),
Token::Literal(Lit::Str_(..), n) => Token::Literal(Lit::Str_(fix(content)), n),
Token::Literal(Lit::StrRaw(..), n) => Token::Literal(Lit::StrRaw(fix(content),
count(content)), n),
Token::Literal(Lit::Char(..), n) => Token::Literal(Lit::Char(fixchar(content)), n),
Token::Literal(Lit::Byte(..), n) => Token::Literal(Lit::Byte(fixchar(content)), n),
Token::DocComment(..) => Token::DocComment(nm),
Token::Literal(Lit::Integer(..), n) => Token::Literal(Lit::Integer(nm), n),
Token::Literal(Lit::Float(..), n) => Token::Literal(Lit::Float(nm), n),
Token::Literal(Lit::ByteStr(..), n) => Token::Literal(Lit::ByteStr(nm), n),
Token::Literal(Lit::ByteStrRaw(..), n) => Token::Literal(Lit::ByteStrRaw(fix(content),
count(content)), n),
Token::Ident(..) => Token::Ident(ast::Ident::with_empty_ctxt(nm)),
Token::Lifetime(..) => Token::Lifetime(ast::Ident::with_empty_ctxt(nm)),
ref t => t.clone()
};
let start_offset = if real_tok == Token::Eof {
1
} else {
0
};
let offset = if has_bom { 1 } else { 0 };
let mut lo = start.parse::<u32>().unwrap() - start_offset - offset;
let mut hi = end.parse::<u32>().unwrap() + 1 - offset;
// Adjust the span: For each surrogate pair already encountered, subtract one position.
lo -= surrogate_pairs_pos.binary_search(&(lo as usize)).unwrap_or_else(|x| x) as u32;
hi -= surrogate_pairs_pos.binary_search(&(hi as usize)).unwrap_or_else(|x| x) as u32;
let sp = syntax_pos::Span {
lo: syntax_pos::BytePos(lo),
hi: syntax_pos::BytePos(hi),
expn_id: syntax_pos::NO_EXPANSION
};
TokenAndSpan {
tok: real_tok,
sp: sp
}
}
fn tok_cmp(a: &token::Token, b: &token::Token) -> bool {
match a {
&Token::Ident(id) => match b {
&Token::Ident(id2) => id == id2,
_ => false
},
_ => a == b
}
}
fn span_cmp(antlr_sp: codemap::Span, rust_sp: codemap::Span, cm: &codemap::CodeMap) -> bool {
antlr_sp.expn_id == rust_sp.expn_id &&
antlr_sp.lo.to_usize() == cm.bytepos_to_file_charpos(rust_sp.lo).to_usize() &&
antlr_sp.hi.to_usize() == cm.bytepos_to_file_charpos(rust_sp.hi).to_usize()
}
fn main() {
fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
use syntax::parse::lexer::Reader;
r.next_token()
}
let mut args = env::args().skip(1);
let filename = args.next().unwrap();
if filename.find("parse-fail").is_some() {
return;
}
// Rust's lexer
let mut code = String::new();
File::open(&Path::new(&filename)).unwrap().read_to_string(&mut code).unwrap();
let surrogate_pairs_pos: Vec<usize> = code.chars().enumerate()
.filter(|&(_, c)| c as usize > 0xFFFF)
.map(|(n, _)| n)
.enumerate()
.map(|(x, n)| x + n)
.collect();
let has_bom = code.starts_with("\u{feff}");
debug!("Pairs: {:?}", surrogate_pairs_pos);
let options = config::basic_options();
let session = session::build_session(options, &DepGraph::new(false), None,
syntax::errors::registry::Registry::new(&[]),
Rc::new(DummyCrateStore));
let filemap = session.parse_sess.codemap()
.new_filemap("<n/a>".to_string(), code);
let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);
let cm = session.codemap();
// ANTLR
let mut token_file = File::open(&Path::new(&args.next().unwrap())).unwrap();
let mut token_list = String::new();
token_file.read_to_string(&mut token_list).unwrap();
let token_map = parse_token_list(&token_list);
let stdin = std::io::stdin();
let lock = stdin.lock();
let lines = lock.lines();
let antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().trim(),
&token_map,
&surrogate_pairs_pos,
has_bom));
for antlr_tok in antlr_tokens {
let rustc_tok = next(&mut lexer);
if rustc_tok.tok == Token::Eof && antlr_tok.tok == Token::Eof {
continue
}
assert!(span_cmp(antlr_tok.sp, rustc_tok.sp, cm), "{:?} and {:?} have different spans",
rustc_tok,
antlr_tok);
macro_rules! matches {
( $($x:pat),+ ) => (
match rustc_tok.tok {
$($x => match antlr_tok.tok {
$x => {
if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
// FIXME #15677: needs more robust escaping in
// antlr
warn!("Different names for {:?} and {:?}", rustc_tok, antlr_tok);
}
}
_ => panic!("{:?} is not {:?}", antlr_tok, rustc_tok)
},)*
ref c => assert!(c == &antlr_tok.tok, "{:?} is not {:?}", antlr_tok, rustc_tok)
}
)
}
matches!(
Token::Literal(Lit::Byte(..), _),
Token::Literal(Lit::Char(..), _),
Token::Literal(Lit::Integer(..), _),
Token::Literal(Lit::Float(..), _),
Token::Literal(Lit::Str_(..), _),
Token::Literal(Lit::StrRaw(..), _),
Token::Literal(Lit::ByteStr(..), _),
Token::Literal(Lit::ByteStrRaw(..), _),
Token::Ident(..),
Token::Lifetime(..),
Token::Interpolated(..),
Token::DocComment(..),
Token::Shebang(..)
);
}
}
-473
View File
@@ -1,473 +0,0 @@
lexer grammar Xidcontinue;
fragment XID_Continue:
'\u0030' .. '\u0039'
| '\u0041' .. '\u005a'
| '\u005f'
| '\u0061' .. '\u007a'
| '\u00aa'
| '\u00b5'
| '\u00b7'
| '\u00ba'
| '\u00c0' .. '\u00d6'
| '\u00d8' .. '\u00f6'
| '\u00f8' .. '\u0236'
| '\u0250' .. '\u02c1'
| '\u02c6' .. '\u02d1'
| '\u02e0' .. '\u02e4'
| '\u02ee'
| '\u0300' .. '\u0357'
| '\u035d' .. '\u036f'
| '\u0386'
| '\u0388' .. '\u038a'
| '\u038c'
| '\u038e' .. '\u03a1'
| '\u03a3' .. '\u03ce'
| '\u03d0' .. '\u03f5'
| '\u03f7' .. '\u03fb'
| '\u0400' .. '\u0481'
| '\u0483' .. '\u0486'
| '\u048a' .. '\u04ce'
| '\u04d0' .. '\u04f5'
| '\u04f8' .. '\u04f9'
| '\u0500' .. '\u050f'
| '\u0531' .. '\u0556'
| '\u0559'
| '\u0561' .. '\u0587'
| '\u0591' .. '\u05a1'
| '\u05a3' .. '\u05b9'
| '\u05bb' .. '\u05bd'
| '\u05bf'
| '\u05c1' .. '\u05c2'
| '\u05c4'
| '\u05d0' .. '\u05ea'
| '\u05f0' .. '\u05f2'
| '\u0610' .. '\u0615'
| '\u0621' .. '\u063a'
| '\u0640' .. '\u0658'
| '\u0660' .. '\u0669'
| '\u066e' .. '\u06d3'
| '\u06d5' .. '\u06dc'
| '\u06df' .. '\u06e8'
| '\u06ea' .. '\u06fc'
| '\u06ff'
| '\u0710' .. '\u074a'
| '\u074d' .. '\u074f'
| '\u0780' .. '\u07b1'
| '\u0901' .. '\u0939'
| '\u093c' .. '\u094d'
| '\u0950' .. '\u0954'
| '\u0958' .. '\u0963'
| '\u0966' .. '\u096f'
| '\u0981' .. '\u0983'
| '\u0985' .. '\u098c'
| '\u098f' .. '\u0990'
| '\u0993' .. '\u09a8'
| '\u09aa' .. '\u09b0'
| '\u09b2'
| '\u09b6' .. '\u09b9'
| '\u09bc' .. '\u09c4'
| '\u09c7' .. '\u09c8'
| '\u09cb' .. '\u09cd'
| '\u09d7'
| '\u09dc' .. '\u09dd'
| '\u09df' .. '\u09e3'
| '\u09e6' .. '\u09f1'
| '\u0a01' .. '\u0a03'
| '\u0a05' .. '\u0a0a'
| '\u0a0f' .. '\u0a10'
| '\u0a13' .. '\u0a28'
| '\u0a2a' .. '\u0a30'
| '\u0a32' .. '\u0a33'
| '\u0a35' .. '\u0a36'
| '\u0a38' .. '\u0a39'
| '\u0a3c'
| '\u0a3e' .. '\u0a42'
| '\u0a47' .. '\u0a48'
| '\u0a4b' .. '\u0a4d'
| '\u0a59' .. '\u0a5c'
| '\u0a5e'
| '\u0a66' .. '\u0a74'
| '\u0a81' .. '\u0a83'
| '\u0a85' .. '\u0a8d'
| '\u0a8f' .. '\u0a91'
| '\u0a93' .. '\u0aa8'
| '\u0aaa' .. '\u0ab0'
| '\u0ab2' .. '\u0ab3'
| '\u0ab5' .. '\u0ab9'
| '\u0abc' .. '\u0ac5'
| '\u0ac7' .. '\u0ac9'
| '\u0acb' .. '\u0acd'
| '\u0ad0'
| '\u0ae0' .. '\u0ae3'
| '\u0ae6' .. '\u0aef'
| '\u0b01' .. '\u0b03'
| '\u0b05' .. '\u0b0c'
| '\u0b0f' .. '\u0b10'
| '\u0b13' .. '\u0b28'
| '\u0b2a' .. '\u0b30'
| '\u0b32' .. '\u0b33'
| '\u0b35' .. '\u0b39'
| '\u0b3c' .. '\u0b43'
| '\u0b47' .. '\u0b48'
| '\u0b4b' .. '\u0b4d'
| '\u0b56' .. '\u0b57'
| '\u0b5c' .. '\u0b5d'
| '\u0b5f' .. '\u0b61'
| '\u0b66' .. '\u0b6f'
| '\u0b71'
| '\u0b82' .. '\u0b83'
| '\u0b85' .. '\u0b8a'
| '\u0b8e' .. '\u0b90'
| '\u0b92' .. '\u0b95'
| '\u0b99' .. '\u0b9a'
| '\u0b9c'
| '\u0b9e' .. '\u0b9f'
| '\u0ba3' .. '\u0ba4'
| '\u0ba8' .. '\u0baa'
| '\u0bae' .. '\u0bb5'
| '\u0bb7' .. '\u0bb9'
| '\u0bbe' .. '\u0bc2'
| '\u0bc6' .. '\u0bc8'
| '\u0bca' .. '\u0bcd'
| '\u0bd7'
| '\u0be7' .. '\u0bef'
| '\u0c01' .. '\u0c03'
| '\u0c05' .. '\u0c0c'
| '\u0c0e' .. '\u0c10'
| '\u0c12' .. '\u0c28'
| '\u0c2a' .. '\u0c33'
| '\u0c35' .. '\u0c39'
| '\u0c3e' .. '\u0c44'
| '\u0c46' .. '\u0c48'
| '\u0c4a' .. '\u0c4d'
| '\u0c55' .. '\u0c56'
| '\u0c60' .. '\u0c61'
| '\u0c66' .. '\u0c6f'
| '\u0c82' .. '\u0c83'
| '\u0c85' .. '\u0c8c'
| '\u0c8e' .. '\u0c90'
| '\u0c92' .. '\u0ca8'
| '\u0caa' .. '\u0cb3'
| '\u0cb5' .. '\u0cb9'
| '\u0cbc' .. '\u0cc4'
| '\u0cc6' .. '\u0cc8'
| '\u0cca' .. '\u0ccd'
| '\u0cd5' .. '\u0cd6'
| '\u0cde'
| '\u0ce0' .. '\u0ce1'
| '\u0ce6' .. '\u0cef'
| '\u0d02' .. '\u0d03'
| '\u0d05' .. '\u0d0c'
| '\u0d0e' .. '\u0d10'
| '\u0d12' .. '\u0d28'
| '\u0d2a' .. '\u0d39'
| '\u0d3e' .. '\u0d43'
| '\u0d46' .. '\u0d48'
| '\u0d4a' .. '\u0d4d'
| '\u0d57'
| '\u0d60' .. '\u0d61'
| '\u0d66' .. '\u0d6f'
| '\u0d82' .. '\u0d83'
| '\u0d85' .. '\u0d96'
| '\u0d9a' .. '\u0db1'
| '\u0db3' .. '\u0dbb'
| '\u0dbd'
| '\u0dc0' .. '\u0dc6'
| '\u0dca'
| '\u0dcf' .. '\u0dd4'
| '\u0dd6'
| '\u0dd8' .. '\u0ddf'
| '\u0df2' .. '\u0df3'
| '\u0e01' .. '\u0e3a'
| '\u0e40' .. '\u0e4e'
| '\u0e50' .. '\u0e59'
| '\u0e81' .. '\u0e82'
| '\u0e84'
| '\u0e87' .. '\u0e88'
| '\u0e8a'
| '\u0e8d'
| '\u0e94' .. '\u0e97'
| '\u0e99' .. '\u0e9f'
| '\u0ea1' .. '\u0ea3'
| '\u0ea5'
| '\u0ea7'
| '\u0eaa' .. '\u0eab'
| '\u0ead' .. '\u0eb9'
| '\u0ebb' .. '\u0ebd'
| '\u0ec0' .. '\u0ec4'
| '\u0ec6'
| '\u0ec8' .. '\u0ecd'
| '\u0ed0' .. '\u0ed9'
| '\u0edc' .. '\u0edd'
| '\u0f00'
| '\u0f18' .. '\u0f19'
| '\u0f20' .. '\u0f29'
| '\u0f35'
| '\u0f37'
| '\u0f39'
| '\u0f3e' .. '\u0f47'
| '\u0f49' .. '\u0f6a'
| '\u0f71' .. '\u0f84'
| '\u0f86' .. '\u0f8b'
| '\u0f90' .. '\u0f97'
| '\u0f99' .. '\u0fbc'
| '\u0fc6'
| '\u1000' .. '\u1021'
| '\u1023' .. '\u1027'
| '\u1029' .. '\u102a'
| '\u102c' .. '\u1032'
| '\u1036' .. '\u1039'
| '\u1040' .. '\u1049'
| '\u1050' .. '\u1059'
| '\u10a0' .. '\u10c5'
| '\u10d0' .. '\u10f8'
| '\u1100' .. '\u1159'
| '\u115f' .. '\u11a2'
| '\u11a8' .. '\u11f9'
| '\u1200' .. '\u1206'
| '\u1208' .. '\u1246'
| '\u1248'
| '\u124a' .. '\u124d'
| '\u1250' .. '\u1256'
| '\u1258'
| '\u125a' .. '\u125d'
| '\u1260' .. '\u1286'
| '\u1288'
| '\u128a' .. '\u128d'
| '\u1290' .. '\u12ae'
| '\u12b0'
| '\u12b2' .. '\u12b5'
| '\u12b8' .. '\u12be'
| '\u12c0'
| '\u12c2' .. '\u12c5'
| '\u12c8' .. '\u12ce'
| '\u12d0' .. '\u12d6'
| '\u12d8' .. '\u12ee'
| '\u12f0' .. '\u130e'
| '\u1310'
| '\u1312' .. '\u1315'
| '\u1318' .. '\u131e'
| '\u1320' .. '\u1346'
| '\u1348' .. '\u135a'
| '\u1369' .. '\u1371'
| '\u13a0' .. '\u13f4'
| '\u1401' .. '\u166c'
| '\u166f' .. '\u1676'
| '\u1681' .. '\u169a'
| '\u16a0' .. '\u16ea'
| '\u16ee' .. '\u16f0'
| '\u1700' .. '\u170c'
| '\u170e' .. '\u1714'
| '\u1720' .. '\u1734'
| '\u1740' .. '\u1753'
| '\u1760' .. '\u176c'
| '\u176e' .. '\u1770'
| '\u1772' .. '\u1773'
| '\u1780' .. '\u17b3'
| '\u17b6' .. '\u17d3'
| '\u17d7'
| '\u17dc' .. '\u17dd'
| '\u17e0' .. '\u17e9'
| '\u180b' .. '\u180d'
| '\u1810' .. '\u1819'
| '\u1820' .. '\u1877'
| '\u1880' .. '\u18a9'
| '\u1900' .. '\u191c'
| '\u1920' .. '\u192b'
| '\u1930' .. '\u193b'
| '\u1946' .. '\u196d'
| '\u1970' .. '\u1974'
| '\u1d00' .. '\u1d6b'
| '\u1e00' .. '\u1e9b'
| '\u1ea0' .. '\u1ef9'
| '\u1f00' .. '\u1f15'
| '\u1f18' .. '\u1f1d'
| '\u1f20' .. '\u1f45'
| '\u1f48' .. '\u1f4d'
| '\u1f50' .. '\u1f57'
| '\u1f59'
| '\u1f5b'
| '\u1f5d'
| '\u1f5f' .. '\u1f7d'
| '\u1f80' .. '\u1fb4'
| '\u1fb6' .. '\u1fbc'
| '\u1fbe'
| '\u1fc2' .. '\u1fc4'
| '\u1fc6' .. '\u1fcc'
| '\u1fd0' .. '\u1fd3'
| '\u1fd6' .. '\u1fdb'
| '\u1fe0' .. '\u1fec'
| '\u1ff2' .. '\u1ff4'
| '\u1ff6' .. '\u1ffc'
| '\u203f' .. '\u2040'
| '\u2054'
| '\u2071'
| '\u207f'
| '\u20d0' .. '\u20dc'
| '\u20e1'
| '\u20e5' .. '\u20ea'
| '\u2102'
| '\u2107'
| '\u210a' .. '\u2113'
| '\u2115'
| '\u2118' .. '\u211d'
| '\u2124'
| '\u2126'
| '\u2128'
| '\u212a' .. '\u2131'
| '\u2133' .. '\u2139'
| '\u213d' .. '\u213f'
| '\u2145' .. '\u2149'
| '\u2160' .. '\u2183'
| '\u3005' .. '\u3007'
| '\u3021' .. '\u302f'
| '\u3031' .. '\u3035'
| '\u3038' .. '\u303c'
| '\u3041' .. '\u3096'
| '\u3099' .. '\u309a'
| '\u309d' .. '\u309f'
| '\u30a1' .. '\u30ff'
| '\u3105' .. '\u312c'
| '\u3131' .. '\u318e'
| '\u31a0' .. '\u31b7'
| '\u31f0' .. '\u31ff'
| '\u3400' .. '\u4db5'
| '\u4e00' .. '\u9fa5'
| '\ua000' .. '\ua48c'
| '\uac00' .. '\ud7a3'
| '\uf900' .. '\ufa2d'
| '\ufa30' .. '\ufa6a'
| '\ufb00' .. '\ufb06'
| '\ufb13' .. '\ufb17'
| '\ufb1d' .. '\ufb28'
| '\ufb2a' .. '\ufb36'
| '\ufb38' .. '\ufb3c'
| '\ufb3e'
| '\ufb40' .. '\ufb41'
| '\ufb43' .. '\ufb44'
| '\ufb46' .. '\ufbb1'
| '\ufbd3' .. '\ufc5d'
| '\ufc64' .. '\ufd3d'
| '\ufd50' .. '\ufd8f'
| '\ufd92' .. '\ufdc7'
| '\ufdf0' .. '\ufdf9'
| '\ufe00' .. '\ufe0f'
| '\ufe20' .. '\ufe23'
| '\ufe33' .. '\ufe34'
| '\ufe4d' .. '\ufe4f'
| '\ufe71'
| '\ufe73'
| '\ufe77'
| '\ufe79'
| '\ufe7b'
| '\ufe7d'
| '\ufe7f' .. '\ufefc'
| '\uff10' .. '\uff19'
| '\uff21' .. '\uff3a'
| '\uff3f'
| '\uff41' .. '\uff5a'
| '\uff65' .. '\uffbe'
| '\uffc2' .. '\uffc7'
| '\uffca' .. '\uffcf'
| '\uffd2' .. '\uffd7'
| '\uffda' .. '\uffdc'
| '\ud800' '\udc00' .. '\udc0a'
| '\ud800' '\udc0d' .. '\udc25'
| '\ud800' '\udc28' .. '\udc39'
| '\ud800' '\udc3c' .. '\udc3c'
| '\ud800' '\udc3f' .. '\udc4c'
| '\ud800' '\udc50' .. '\udc5c'
| '\ud800' '\udc80' .. '\udcf9'
| '\ud800' '\udf00' .. '\udf1d'
| '\ud800' '\udf30' .. '\udf49'
| '\ud800' '\udf80' .. '\udf9c'
| '\ud801' '\ue000' .. '\ue09c'
| '\ud801' '\ue0a0' .. '\ue0a8'
| '\ud802' '\ue400' .. '\ue404'
| '\ud802' '\u0808'
| '\ud802' '\ue40a' .. '\ue434'
| '\ud802' '\ue437' .. '\ue437'
| '\ud802' '\u083c'
| '\ud802' '\u083f'
| '\ud834' '\uad65' .. '\uad68'
| '\ud834' '\uad6d' .. '\uad71'
| '\ud834' '\uad7b' .. '\uad81'
| '\ud834' '\uad85' .. '\uad8a'
| '\ud834' '\uadaa' .. '\uadac'
| '\ud835' '\ub000' .. '\ub053'
| '\ud835' '\ub056' .. '\ub09b'
| '\ud835' '\ub09e' .. '\ub09e'
| '\ud835' '\ud4a2'
| '\ud835' '\ub0a5' .. '\ub0a5'
| '\ud835' '\ub0a9' .. '\ub0ab'
| '\ud835' '\ub0ae' .. '\ub0b8'
| '\ud835' '\ud4bb'
| '\ud835' '\ub0bd' .. '\ub0c2'
| '\ud835' '\ub0c5' .. '\ub104'
| '\ud835' '\ub107' .. '\ub109'
| '\ud835' '\ub10d' .. '\ub113'
| '\ud835' '\ub116' .. '\ub11b'
| '\ud835' '\ub11e' .. '\ub138'
| '\ud835' '\ub13b' .. '\ub13d'
| '\ud835' '\ub140' .. '\ub143'
| '\ud835' '\ud546'
| '\ud835' '\ub14a' .. '\ub14f'
| '\ud835' '\ub152' .. '\ub2a2'
| '\ud835' '\ub2a8' .. '\ub2bf'
| '\ud835' '\ub2c2' .. '\ub2d9'
| '\ud835' '\ub2dc' .. '\ub2f9'
| '\ud835' '\ub2fc' .. '\ub313'
| '\ud835' '\ub316' .. '\ub333'
| '\ud835' '\ub336' .. '\ub34d'
| '\ud835' '\ub350' .. '\ub36d'
| '\ud835' '\ub370' .. '\ub387'
| '\ud835' '\ub38a' .. '\ub3a7'
| '\ud835' '\ub3aa' .. '\ub3c1'
| '\ud835' '\ub3c4' .. '\ub3c8'
| '\ud835' '\ub3ce' .. '\ub3fe'
| '\ud840' '\udc00' .. '\udffe'
| '\ud841' '\ue000' .. '\ue3fe'
| '\ud842' '\ue400' .. '\ue7fe'
| '\ud843' '\ue800' .. '\uebfe'
| '\ud844' '\uec00' .. '\ueffe'
| '\ud845' '\uf000' .. '\uf3fe'
| '\ud846' '\uf400' .. '\uf7fe'
| '\ud847' '\uf800' .. '\ufbfe'
| '\ud848' '\ufc00' .. '\ufffe'
| '\ud849' '\u0000' .. '\u03fe'
| '\ud84a' '\u0400' .. '\u07fe'
| '\ud84b' '\u0800' .. '\u0bfe'
| '\ud84c' '\u0c00' .. '\u0ffe'
| '\ud84d' '\u1000' .. '\u13fe'
| '\ud84e' '\u1400' .. '\u17fe'
| '\ud84f' '\u1800' .. '\u1bfe'
| '\ud850' '\u1c00' .. '\u1ffe'
| '\ud851' '\u2000' .. '\u23fe'
| '\ud852' '\u2400' .. '\u27fe'
| '\ud853' '\u2800' .. '\u2bfe'
| '\ud854' '\u2c00' .. '\u2ffe'
| '\ud855' '\u3000' .. '\u33fe'
| '\ud856' '\u3400' .. '\u37fe'
| '\ud857' '\u3800' .. '\u3bfe'
| '\ud858' '\u3c00' .. '\u3ffe'
| '\ud859' '\u4000' .. '\u43fe'
| '\ud85a' '\u4400' .. '\u47fe'
| '\ud85b' '\u4800' .. '\u4bfe'
| '\ud85c' '\u4c00' .. '\u4ffe'
| '\ud85d' '\u5000' .. '\u53fe'
| '\ud85e' '\u5400' .. '\u57fe'
| '\ud85f' '\u5800' .. '\u5bfe'
| '\ud860' '\u5c00' .. '\u5ffe'
| '\ud861' '\u6000' .. '\u63fe'
| '\ud862' '\u6400' .. '\u67fe'
| '\ud863' '\u6800' .. '\u6bfe'
| '\ud864' '\u6c00' .. '\u6ffe'
| '\ud865' '\u7000' .. '\u73fe'
| '\ud866' '\u7400' .. '\u77fe'
| '\ud867' '\u7800' .. '\u7bfe'
| '\ud868' '\u7c00' .. '\u7ffe'
| '\ud869' '\u8000' .. '\u82d5'
| '\ud87e' '\ud400' .. '\ud61c'
| '\udb40' '\udd00' .. '\uddee'
;
-379
View File
@@ -1,379 +0,0 @@
lexer grammar Xidstart;
fragment XID_Start :
'\u0041' .. '\u005a'
| '_'
| '\u0061' .. '\u007a'
| '\u00aa'
| '\u00b5'
| '\u00ba'
| '\u00c0' .. '\u00d6'
| '\u00d8' .. '\u00f6'
| '\u00f8' .. '\u0236'
| '\u0250' .. '\u02c1'
| '\u02c6' .. '\u02d1'
| '\u02e0' .. '\u02e4'
| '\u02ee'
| '\u0386'
| '\u0388' .. '\u038a'
| '\u038c'
| '\u038e' .. '\u03a1'
| '\u03a3' .. '\u03ce'
| '\u03d0' .. '\u03f5'
| '\u03f7' .. '\u03fb'
| '\u0400' .. '\u0481'
| '\u048a' .. '\u04ce'
| '\u04d0' .. '\u04f5'
| '\u04f8' .. '\u04f9'
| '\u0500' .. '\u050f'
| '\u0531' .. '\u0556'
| '\u0559'
| '\u0561' .. '\u0587'
| '\u05d0' .. '\u05ea'
| '\u05f0' .. '\u05f2'
| '\u0621' .. '\u063a'
| '\u0640' .. '\u064a'
| '\u066e' .. '\u066f'
| '\u0671' .. '\u06d3'
| '\u06d5'
| '\u06e5' .. '\u06e6'
| '\u06ee' .. '\u06ef'
| '\u06fa' .. '\u06fc'
| '\u06ff'
| '\u0710'
| '\u0712' .. '\u072f'
| '\u074d' .. '\u074f'
| '\u0780' .. '\u07a5'
| '\u07b1'
| '\u0904' .. '\u0939'
| '\u093d'
| '\u0950'
| '\u0958' .. '\u0961'
| '\u0985' .. '\u098c'
| '\u098f' .. '\u0990'
| '\u0993' .. '\u09a8'
| '\u09aa' .. '\u09b0'
| '\u09b2'
| '\u09b6' .. '\u09b9'
| '\u09bd'
| '\u09dc' .. '\u09dd'
| '\u09df' .. '\u09e1'
| '\u09f0' .. '\u09f1'
| '\u0a05' .. '\u0a0a'
| '\u0a0f' .. '\u0a10'
| '\u0a13' .. '\u0a28'
| '\u0a2a' .. '\u0a30'
| '\u0a32' .. '\u0a33'
| '\u0a35' .. '\u0a36'
| '\u0a38' .. '\u0a39'
| '\u0a59' .. '\u0a5c'
| '\u0a5e'
| '\u0a72' .. '\u0a74'
| '\u0a85' .. '\u0a8d'
| '\u0a8f' .. '\u0a91'
| '\u0a93' .. '\u0aa8'
| '\u0aaa' .. '\u0ab0'
| '\u0ab2' .. '\u0ab3'
| '\u0ab5' .. '\u0ab9'
| '\u0abd'
| '\u0ad0'
| '\u0ae0' .. '\u0ae1'
| '\u0b05' .. '\u0b0c'
| '\u0b0f' .. '\u0b10'
| '\u0b13' .. '\u0b28'
| '\u0b2a' .. '\u0b30'
| '\u0b32' .. '\u0b33'
| '\u0b35' .. '\u0b39'
| '\u0b3d'
| '\u0b5c' .. '\u0b5d'
| '\u0b5f' .. '\u0b61'
| '\u0b71'
| '\u0b83'
| '\u0b85' .. '\u0b8a'
| '\u0b8e' .. '\u0b90'
| '\u0b92' .. '\u0b95'
| '\u0b99' .. '\u0b9a'
| '\u0b9c'
| '\u0b9e' .. '\u0b9f'
| '\u0ba3' .. '\u0ba4'
| '\u0ba8' .. '\u0baa'
| '\u0bae' .. '\u0bb5'
| '\u0bb7' .. '\u0bb9'
| '\u0c05' .. '\u0c0c'
| '\u0c0e' .. '\u0c10'
| '\u0c12' .. '\u0c28'
| '\u0c2a' .. '\u0c33'
| '\u0c35' .. '\u0c39'
| '\u0c60' .. '\u0c61'
| '\u0c85' .. '\u0c8c'
| '\u0c8e' .. '\u0c90'
| '\u0c92' .. '\u0ca8'
| '\u0caa' .. '\u0cb3'
| '\u0cb5' .. '\u0cb9'
| '\u0cbd'
| '\u0cde'
| '\u0ce0' .. '\u0ce1'
| '\u0d05' .. '\u0d0c'
| '\u0d0e' .. '\u0d10'
| '\u0d12' .. '\u0d28'
| '\u0d2a' .. '\u0d39'
| '\u0d60' .. '\u0d61'
| '\u0d85' .. '\u0d96'
| '\u0d9a' .. '\u0db1'
| '\u0db3' .. '\u0dbb'
| '\u0dbd'
| '\u0dc0' .. '\u0dc6'
| '\u0e01' .. '\u0e30'
| '\u0e32'
| '\u0e40' .. '\u0e46'
| '\u0e81' .. '\u0e82'
| '\u0e84'
| '\u0e87' .. '\u0e88'
| '\u0e8a'
| '\u0e8d'
| '\u0e94' .. '\u0e97'
| '\u0e99' .. '\u0e9f'
| '\u0ea1' .. '\u0ea3'
| '\u0ea5'
| '\u0ea7'
| '\u0eaa' .. '\u0eab'
| '\u0ead' .. '\u0eb0'
| '\u0eb2'
| '\u0ebd'
| '\u0ec0' .. '\u0ec4'
| '\u0ec6'
| '\u0edc' .. '\u0edd'
| '\u0f00'
| '\u0f40' .. '\u0f47'
| '\u0f49' .. '\u0f6a'
| '\u0f88' .. '\u0f8b'
| '\u1000' .. '\u1021'
| '\u1023' .. '\u1027'
| '\u1029' .. '\u102a'
| '\u1050' .. '\u1055'
| '\u10a0' .. '\u10c5'
| '\u10d0' .. '\u10f8'
| '\u1100' .. '\u1159'
| '\u115f' .. '\u11a2'
| '\u11a8' .. '\u11f9'
| '\u1200' .. '\u1206'
| '\u1208' .. '\u1246'
| '\u1248'
| '\u124a' .. '\u124d'
| '\u1250' .. '\u1256'
| '\u1258'
| '\u125a' .. '\u125d'
| '\u1260' .. '\u1286'
| '\u1288'
| '\u128a' .. '\u128d'
| '\u1290' .. '\u12ae'
| '\u12b0'
| '\u12b2' .. '\u12b5'
| '\u12b8' .. '\u12be'
| '\u12c0'
| '\u12c2' .. '\u12c5'
| '\u12c8' .. '\u12ce'
| '\u12d0' .. '\u12d6'
| '\u12d8' .. '\u12ee'
| '\u12f0' .. '\u130e'
| '\u1310'
| '\u1312' .. '\u1315'
| '\u1318' .. '\u131e'
| '\u1320' .. '\u1346'
| '\u1348' .. '\u135a'
| '\u13a0' .. '\u13f4'
| '\u1401' .. '\u166c'
| '\u166f' .. '\u1676'
| '\u1681' .. '\u169a'
| '\u16a0' .. '\u16ea'
| '\u16ee' .. '\u16f0'
| '\u1700' .. '\u170c'
| '\u170e' .. '\u1711'
| '\u1720' .. '\u1731'
| '\u1740' .. '\u1751'
| '\u1760' .. '\u176c'
| '\u176e' .. '\u1770'
| '\u1780' .. '\u17b3'
| '\u17d7'
| '\u17dc'
| '\u1820' .. '\u1877'
| '\u1880' .. '\u18a8'
| '\u1900' .. '\u191c'
| '\u1950' .. '\u196d'
| '\u1970' .. '\u1974'
| '\u1d00' .. '\u1d6b'
| '\u1e00' .. '\u1e9b'
| '\u1ea0' .. '\u1ef9'
| '\u1f00' .. '\u1f15'
| '\u1f18' .. '\u1f1d'
| '\u1f20' .. '\u1f45'
| '\u1f48' .. '\u1f4d'
| '\u1f50' .. '\u1f57'
| '\u1f59'
| '\u1f5b'
| '\u1f5d'
| '\u1f5f' .. '\u1f7d'
| '\u1f80' .. '\u1fb4'
| '\u1fb6' .. '\u1fbc'
| '\u1fbe'
| '\u1fc2' .. '\u1fc4'
| '\u1fc6' .. '\u1fcc'
| '\u1fd0' .. '\u1fd3'
| '\u1fd6' .. '\u1fdb'
| '\u1fe0' .. '\u1fec'
| '\u1ff2' .. '\u1ff4'
| '\u1ff6' .. '\u1ffc'
| '\u2071'
| '\u207f'
| '\u2102'
| '\u2107'
| '\u210a' .. '\u2113'
| '\u2115'
| '\u2118' .. '\u211d'
| '\u2124'
| '\u2126'
| '\u2128'
| '\u212a' .. '\u2131'
| '\u2133' .. '\u2139'
| '\u213d' .. '\u213f'
| '\u2145' .. '\u2149'
| '\u2160' .. '\u2183'
| '\u3005' .. '\u3007'
| '\u3021' .. '\u3029'
| '\u3031' .. '\u3035'
| '\u3038' .. '\u303c'
| '\u3041' .. '\u3096'
| '\u309d' .. '\u309f'
| '\u30a1' .. '\u30fa'
| '\u30fc' .. '\u30ff'
| '\u3105' .. '\u312c'
| '\u3131' .. '\u318e'
| '\u31a0' .. '\u31b7'
| '\u31f0' .. '\u31ff'
| '\u3400' .. '\u4db5'
| '\u4e00' .. '\u9fa5'
| '\ua000' .. '\ua48c'
| '\uac00' .. '\ud7a3'
| '\uf900' .. '\ufa2d'
| '\ufa30' .. '\ufa6a'
| '\ufb00' .. '\ufb06'
| '\ufb13' .. '\ufb17'
| '\ufb1d'
| '\ufb1f' .. '\ufb28'
| '\ufb2a' .. '\ufb36'
| '\ufb38' .. '\ufb3c'
| '\ufb3e'
| '\ufb40' .. '\ufb41'
| '\ufb43' .. '\ufb44'
| '\ufb46' .. '\ufbb1'
| '\ufbd3' .. '\ufc5d'
| '\ufc64' .. '\ufd3d'
| '\ufd50' .. '\ufd8f'
| '\ufd92' .. '\ufdc7'
| '\ufdf0' .. '\ufdf9'
| '\ufe71'
| '\ufe73'
| '\ufe77'
| '\ufe79'
| '\ufe7b'
| '\ufe7d'
| '\ufe7f' .. '\ufefc'
| '\uff21' .. '\uff3a'
| '\uff41' .. '\uff5a'
| '\uff66' .. '\uff9d'
| '\uffa0' .. '\uffbe'
| '\uffc2' .. '\uffc7'
| '\uffca' .. '\uffcf'
| '\uffd2' .. '\uffd7'
| '\uffda' .. '\uffdc'
| '\ud800' '\udc00' .. '\udc0a'
| '\ud800' '\udc0d' .. '\udc25'
| '\ud800' '\udc28' .. '\udc39'
| '\ud800' '\udc3c' .. '\udc3c'
| '\ud800' '\udc3f' .. '\udc4c'
| '\ud800' '\udc50' .. '\udc5c'
| '\ud800' '\udc80' .. '\udcf9'
| '\ud800' '\udf00' .. '\udf1d'
| '\ud800' '\udf30' .. '\udf49'
| '\ud800' '\udf80' .. '\udf9c'
| '\ud801' '\ue000' .. '\ue09c'
| '\ud802' '\ue400' .. '\ue404'
| '\ud802' '\u0808'
| '\ud802' '\ue40a' .. '\ue434'
| '\ud802' '\ue437' .. '\ue437'
| '\ud802' '\u083c'
| '\ud802' '\u083f'
| '\ud835' '\ub000' .. '\ub053'
| '\ud835' '\ub056' .. '\ub09b'
| '\ud835' '\ub09e' .. '\ub09e'
| '\ud835' '\ud4a2'
| '\ud835' '\ub0a5' .. '\ub0a5'
| '\ud835' '\ub0a9' .. '\ub0ab'
| '\ud835' '\ub0ae' .. '\ub0b8'
| '\ud835' '\ud4bb'
| '\ud835' '\ub0bd' .. '\ub0c2'
| '\ud835' '\ub0c5' .. '\ub104'
| '\ud835' '\ub107' .. '\ub109'
| '\ud835' '\ub10d' .. '\ub113'
| '\ud835' '\ub116' .. '\ub11b'
| '\ud835' '\ub11e' .. '\ub138'
| '\ud835' '\ub13b' .. '\ub13d'
| '\ud835' '\ub140' .. '\ub143'
| '\ud835' '\ud546'
| '\ud835' '\ub14a' .. '\ub14f'
| '\ud835' '\ub152' .. '\ub2a2'
| '\ud835' '\ub2a8' .. '\ub2bf'
| '\ud835' '\ub2c2' .. '\ub2d9'
| '\ud835' '\ub2dc' .. '\ub2f9'
| '\ud835' '\ub2fc' .. '\ub313'
| '\ud835' '\ub316' .. '\ub333'
| '\ud835' '\ub336' .. '\ub34d'
| '\ud835' '\ub350' .. '\ub36d'
| '\ud835' '\ub370' .. '\ub387'
| '\ud835' '\ub38a' .. '\ub3a7'
| '\ud835' '\ub3aa' .. '\ub3c1'
| '\ud835' '\ub3c4' .. '\ub3c8'
| '\ud840' '\udc00' .. '\udffe'
| '\ud841' '\ue000' .. '\ue3fe'
| '\ud842' '\ue400' .. '\ue7fe'
| '\ud843' '\ue800' .. '\uebfe'
| '\ud844' '\uec00' .. '\ueffe'
| '\ud845' '\uf000' .. '\uf3fe'
| '\ud846' '\uf400' .. '\uf7fe'
| '\ud847' '\uf800' .. '\ufbfe'
| '\ud848' '\ufc00' .. '\ufffe'
| '\ud849' '\u0000' .. '\u03fe'
| '\ud84a' '\u0400' .. '\u07fe'
| '\ud84b' '\u0800' .. '\u0bfe'
| '\ud84c' '\u0c00' .. '\u0ffe'
| '\ud84d' '\u1000' .. '\u13fe'
| '\ud84e' '\u1400' .. '\u17fe'
| '\ud84f' '\u1800' .. '\u1bfe'
| '\ud850' '\u1c00' .. '\u1ffe'
| '\ud851' '\u2000' .. '\u23fe'
| '\ud852' '\u2400' .. '\u27fe'
| '\ud853' '\u2800' .. '\u2bfe'
| '\ud854' '\u2c00' .. '\u2ffe'
| '\ud855' '\u3000' .. '\u33fe'
| '\ud856' '\u3400' .. '\u37fe'
| '\ud857' '\u3800' .. '\u3bfe'
| '\ud858' '\u3c00' .. '\u3ffe'
| '\ud859' '\u4000' .. '\u43fe'
| '\ud85a' '\u4400' .. '\u47fe'
| '\ud85b' '\u4800' .. '\u4bfe'
| '\ud85c' '\u4c00' .. '\u4ffe'
| '\ud85d' '\u5000' .. '\u53fe'
| '\ud85e' '\u5400' .. '\u57fe'
| '\ud85f' '\u5800' .. '\u5bfe'
| '\ud860' '\u5c00' .. '\u5ffe'
| '\ud861' '\u6000' .. '\u63fe'
| '\ud862' '\u6400' .. '\u67fe'
| '\ud863' '\u6800' .. '\u6bfe'
| '\ud864' '\u6c00' .. '\u6ffe'
| '\ud865' '\u7000' .. '\u73fe'
| '\ud866' '\u7400' .. '\u77fe'
| '\ud867' '\u7800' .. '\u7bfe'
| '\ud868' '\u7c00' .. '\u7ffe'
| '\ud869' '\u8000' .. '\u82d5'
| '\ud87e' '\ud400' .. '\ud61c'
;
+52 -3
View File
@@ -1573,12 +1573,30 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// An atomic fence.
///
/// A fence 'A' which has [`Release`] ordering semantics, synchronizes with a
/// fence 'B' with (at least) [`Acquire`] semantics, if and only if there exists
/// atomic operations X and Y, both operating on some atomic object 'M' such
/// Depending on the specified order, a fence prevents the compiler and CPU from
/// reordering certain types of memory operations around it.
/// That creates synchronizes-with relationships between it and atomic operations
/// or fences in other threads.
///
/// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes
/// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there
/// exist operations X and Y, both operating on some atomic object 'M' such
/// that A is sequenced before X, Y is synchronized before B and Y observes
/// the change to M. This provides a happens-before dependence between A and B.
///
/// ```text
/// Thread 1 Thread 2
///
/// fence(Release); A --------------
/// x.store(3, Relaxed); X --------- |
/// | |
/// | |
/// -------------> Y if x.load(Relaxed) == 3 {
/// |-------> B fence(Acquire);
/// ...
/// }
/// ```
///
/// Atomic operations with [`Release`] or [`Acquire`] semantics can also synchronize
/// with a fence.
///
@@ -1592,6 +1610,37 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
///
/// Panics if `order` is [`Relaxed`].
///
/// # Examples
///
/// ```
/// use std::sync::atomic::AtomicBool;
/// use std::sync::atomic::fence;
/// use std::sync::atomic::Ordering;
///
/// // A mutual exclusion primitive based on spinlock.
/// pub struct Mutex {
/// flag: AtomicBool,
/// }
///
/// impl Mutex {
/// pub fn new() -> Mutex {
/// Mutex {
/// flag: AtomicBool::new(false),
/// }
/// }
///
/// pub fn lock(&self) {
/// while !self.flag.compare_and_swap(false, true, Ordering::Relaxed) {}
/// // This fence syncronizes-with store in `unlock`.
/// fence(Ordering::Acquire);
/// }
///
/// pub fn unlock(&self) {
/// self.flag.store(false, Ordering::Release);
/// }
/// }
/// ```
///
/// [`Ordering`]: enum.Ordering.html
/// [`Acquire`]: enum.Ordering.html#variant.Acquire
/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst
+6
View File
@@ -76,6 +76,7 @@ pub enum DepNode<D: Clone + Debug> {
BorrowCheck(D),
RvalueCheck(D),
Reachability,
MirKeys,
LateLintCheck,
TransCrateItem(D),
TransInlinedItem(D),
@@ -151,6 +152,8 @@ pub enum DepNode<D: Clone + Debug> {
DescribeDef(D),
DefSpan(D),
Stability(D),
Deprecation(D),
}
impl<D: Clone + Debug> DepNode<D> {
@@ -202,6 +205,7 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
Variance => Some(Variance),
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
Reachability => Some(Reachability),
MirKeys => Some(MirKeys),
LateLintCheck => Some(LateLintCheck),
TransWriteMetadata => Some(TransWriteMetadata),
@@ -258,6 +262,8 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
}
DescribeDef(ref d) => op(d).map(DescribeDef),
DefSpan(ref d) => op(d).map(DefSpan),
Stability(ref d) => op(d).map(Stability),
Deprecation(ref d) => op(d).map(Deprecation),
}
}
}
-1
View File
@@ -28,6 +28,5 @@
pub use self::query::DepGraphQuery;
pub use self::safe::AssertDepGraphSafe;
pub use self::safe::DepGraphSafe;
pub use self::visit::visit_all_bodies_in_krate;
pub use self::visit::visit_all_item_likes_in_krate;
pub use self::raii::DepTask;
+6
View File
@@ -50,6 +50,12 @@ impl<A, B> DepGraphSafe for (A, B)
{
}
/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe.
impl<'a, A> DepGraphSafe for &'a A
where A: DepGraphSafe,
{
}
/// No data here! :)
impl DepGraphSafe for () {
}
-12
View File
@@ -75,15 +75,3 @@ fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
krate.visit_all_item_likes(&mut tracking_visitor)
}
pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C)
where C: Fn(/* body_owner */
DefId,
/* body id */
hir::BodyId)
{
let krate = tcx.hir.krate();
for &body_id in &krate.body_ids {
let body_owner_def_id = tcx.hir.body_owner_def_id(body_id);
callback(body_owner_def_id, body_id);
}
}
+1 -1
View File
@@ -455,7 +455,7 @@ pub fn body_owned_by(&self, id: NodeId) -> BodyId {
if let EntryExpr(_, expr) = entry {
BodyId { node_id: expr.id }
} else {
span_bug!(self.span(id), "id `{}` has no associated body", id);
span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
}
}
} else {
+3
View File
@@ -43,6 +43,9 @@
#![feature(unboxed_closures)]
#![feature(discriminant_value)]
#![feature(sort_unstable)]
#![feature(trace_macros)]
#![recursion_limit="128"]
extern crate arena;
extern crate core;
-5
View File
@@ -38,7 +38,6 @@
use std::path::PathBuf;
use std::rc::Rc;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos::Span;
@@ -180,8 +179,6 @@ pub trait CrateStore {
fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
// item info
fn stability(&self, def: DefId) -> Option<attr::Stability>;
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
fn visibility(&self, def: DefId) -> ty::Visibility;
fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
@@ -306,8 +303,6 @@ impl CrateStore for DummyCrateStore {
fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
{ bug!("crate_data_as_rc_any") }
// item info
fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>> {
bug!("visible_parent_map")
+2 -2
View File
@@ -636,7 +636,7 @@ fn lookup_stability_uncached(self, id: DefId) -> Option<&'gcx Stability> {
if id.is_local() {
None // The stability cache is filled partially lazily
} else {
self.sess.cstore.stability(id).map(|st| self.intern_stability(st))
self.stability(id).map(|st| self.intern_stability(st))
}
}
@@ -645,7 +645,7 @@ fn lookup_deprecation_uncached(self, id: DefId) -> Option<DeprecationEntry> {
if id.is_local() {
None // The stability cache is filled partially lazily
} else {
self.sess.cstore.deprecation(id).map(DeprecationEntry::external)
self.deprecation(id).map(DeprecationEntry::external)
}
}
}
+90
View File
@@ -0,0 +1,90 @@
# MIR definition and pass system
This file contains the definition of the MIR datatypes along with the
various types for the "MIR Pass" system, which lets you easily
register and define new MIR transformations and analyses.
Most of the code that operates on MIR can be found in the
`librustc_mir` crate or other crates. The code found here in
`librustc` is just the datatype definitions, alonging the functions
which operate on MIR to be placed everywhere else.
## MIR Data Types and visitor
The main MIR data type is `rustc::mir::Mir`, defined in `mod.rs`.
There is also the MIR visitor (in `visit.rs`) which allows you to walk
the MIR and override what actions will be taken at various points (you
can visit in either shared or mutable mode; the latter allows changing
the MIR in place). Finally `traverse.rs` contains various traversal
routines for visiting the MIR CFG in [different standard orders][traversal]
(e.g. pre-order, reverse post-order, and so forth).
[traversal]: https://en.wikipedia.org/wiki/Tree_traversal
## MIR pass suites and their integration into the query system
As a MIR *consumer*, you are expected to use one of the queries that
returns a "final MIR". As of the time of this writing, there is only
one: `optimized_mir(def_id)`, but more are expected to come in the
future. For foreign def-ids, we simply read the MIR from the other
crate's metadata. But for local query, this query will construct the
MIR and then iteratively optimize it by putting it through various
pipeline stages. This section describes those pipeline stages and how
you can extend them.
To produce the `optimized_mir(D)` for a given def-id `D`, the MIR
passes through several suites of optimizations, each represented by a
query. Each suite consists of multiple optimizations and
transformations. These suites represent useful intermediate points
where we want to access the MIR for type checking or other purposes:
- `mir_build(D)` -- not a query, but this constructs the initial MIR
- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation;
- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking;
- `optimized_mir(D)` -- the final state, after all optimizations have been performed.
### Stealing
The intermediate queries `mir_const()` and `mir_validated()` yield up
a `&'tcx Steal<Mir<'tcx>>`, allocated using
`tcx.alloc_steal_mir()`. This indicates that the result may be
**stolen** by the next suite of optimizations -- this is an
optimization to avoid cloning the MIR. Attempting to use a stolen
result will cause a panic in the compiler. Therefore, it is important
that you not read directly from these intermediate queries except as
part of the MIR processing pipeline.
Because of this stealing mechanism, some care must also be taken to
ensure that, before the MIR at a particular phase in the processing
pipeline is stolen, anyone who may want to read from it has already
done so. Concretely, this means that if you have some query `foo(D)`
that wants to access the result of `mir_const(D)` or
`mir_validated(D)`, you need to have the successor pass either "force"
`foo(D)` using `ty::queries::foo::force(...)`. This will force a query
to execute even though you don't directly require its result.
As an example, consider MIR const qualification. It wants to read the
result produced by the `mir_const()` suite. However, that result will
be **stolen** by the `mir_validated()` suite. If nothing was done,
then `mir_const_qualif(D)` would succeed if it came before
`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)`
will **force** `mir_const_qualif` before it actually steals, thus
ensuring that the reads have already happened:
```
mir_const(D) --read-by--> mir_const_qualif(D)
| ^
stolen-by |
| (forces)
v |
mir_validated(D) ------------+
```
### Implementing and registering a pass
To create a new MIR pass, you simply implement the `MirPass` trait for
some fresh singleton type `Foo`. Once you have implemented a trait for
your type `Foo`, you then have to insert `Foo` into one of the suites;
this is done in `librustc_driver/driver.rs` by invoking `push_pass(S,
Foo)` with the appropriate suite substituted for `S`.
+2
View File
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! MIR datatypes and passes. See [the README](README.md) for details.
use graphviz::IntoCow;
use middle::const_val::ConstVal;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
+90 -97
View File
@@ -8,16 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::DepNode;
//! See [the README](README.md) for details on writing your own pass.
use hir;
use hir::def_id::DefId;
use hir::map::DefPathData;
use mir::{Mir, Promoted};
use ty::TyCtxt;
use std::rc::Rc;
use syntax::ast::NodeId;
use util::common::time;
use std::borrow::Cow;
use std::fmt;
/// Where a specific Mir comes from.
#[derive(Debug, Copy, Clone)]
@@ -36,6 +37,11 @@ pub enum MirSource {
}
impl<'a, 'tcx> MirSource {
pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource {
let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
Self::from_node(tcx, id)
}
pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
use hir::*;
@@ -70,124 +76,111 @@ pub fn item_id(&self) -> NodeId {
}
}
/// Various information about pass.
pub trait Pass {
// fn should_run(Session) to check if pass should run?
fn name<'a>(&self) -> Cow<'static, str> {
let name = unsafe { ::std::intrinsics::type_name::<Self>() };
if let Some(tail) = name.rfind(":") {
Cow::from(&name[tail+1..])
} else {
Cow::from(name)
}
/// Generates a default name for the pass based on the name of the
/// type `T`.
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
let name = unsafe { ::std::intrinsics::type_name::<T>() };
if let Some(tail) = name.rfind(":") {
Cow::from(&name[tail+1..])
} else {
Cow::from(name)
}
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { None }
}
/// A pass which inspects the whole Mir map.
pub trait MirMapPass<'tcx>: Pass {
fn run_pass<'a>(
&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>]);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MirSuite(pub usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MirPassIndex(pub usize);
/// A pass hook is invoked both before and after each pass executes.
/// This is primarily used to dump MIR for debugging.
///
/// You can tell whether this is before or after by inspecting the
/// `mir` parameter -- before the pass executes, it will be `None` (in
/// which case you can inspect the MIR from previous pass by executing
/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
/// `Some()` with the result of the pass (in which case the output
/// from the previous pass is most likely stolen, so you would not
/// want to try and access it). If the pass is interprocedural, then
/// the hook will be invoked once per output.
pub trait PassHook {
fn on_mir_pass<'a, 'tcx: 'a>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
suite: MirSuite,
pass_num: MirPassIndex,
pass_name: &str,
source: MirSource,
mir: &Mir<'tcx>,
is_after: bool);
}
pub trait MirPassHook<'tcx>: Pass {
fn on_mir_pass<'a>(
&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &Mir<'tcx>,
pass: &Pass,
is_after: bool
);
}
/// The full suite of types that identifies a particular
/// application of a pass to a def-id.
pub type PassId = (MirSuite, MirPassIndex, DefId);
/// A pass which inspects Mir of functions in isolation.
pub trait MirPass<'tcx>: Pass {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>);
}
impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
fn run_pass<'a>(&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>])
{
let def_ids = tcx.maps.mir.borrow().keys();
for def_id in def_ids {
if !def_id.is_local() {
continue;
}
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
tcx.dep_graph.write(DepNode::Mir(def_id));
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, false);
}
MirPass::run_pass(self, tcx, src, mir);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, true);
}
for (i, mir) in mir.promoted.iter_enumerated_mut() {
let src = MirSource::Promoted(id, i);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, false);
}
MirPass::run_pass(self, tcx, src, mir);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, true);
}
}
}
/// A streamlined trait that you can implement to create a pass; the
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
pub trait MirPass {
fn name<'a>(&'a self) -> Cow<'a, str> {
default_name::<Self>()
}
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>);
}
/// A manager for MIR passes.
///
/// FIXME(#41712) -- it is unclear whether we should have this struct.
#[derive(Clone)]
pub struct Passes {
passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
pass_hooks: Vec<Rc<PassHook>>,
suites: Vec<Vec<Rc<MirPass>>>,
}
/// The number of "pass suites" that we have:
///
/// - ready for constant evaluation
/// - unopt
/// - optimized
pub const MIR_SUITES: usize = 3;
/// Run the passes we need to do constant qualification and evaluation.
pub const MIR_CONST: MirSuite = MirSuite(0);
/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
pub const MIR_VALIDATED: MirSuite = MirSuite(1);
/// Run the passes we need to consider the MIR *optimized*.
pub const MIR_OPTIMIZED: MirSuite = MirSuite(2);
impl<'a, 'tcx> Passes {
pub fn new() -> Passes {
let passes = Passes {
passes: Vec::new(),
Passes {
pass_hooks: Vec::new(),
plugin_passes: Vec::new()
};
passes
}
pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self;
for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) {
time(tcx.sess.time_passes(), &*pass.name(),
|| pass.run_pass(tcx, pass_hooks));
suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(),
}
}
/// Pushes a built-in pass.
pub fn push_pass(&mut self, pass: Box<for<'b> MirMapPass<'b>>) {
self.passes.push(pass);
pub fn push_pass<T: MirPass + 'static>(&mut self, suite: MirSuite, pass: T) {
self.suites[suite.0].push(Rc::new(pass));
}
/// Pushes a pass hook.
pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
self.pass_hooks.push(hook);
pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
self.pass_hooks.push(Rc::new(hook));
}
}
/// Copies the plugin passes.
impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
self.plugin_passes.extend(it);
pub fn passes(&self, suite: MirSuite) -> &[Rc<MirPass>] {
&self.suites[suite.0]
}
pub fn hooks(&self) -> &[Rc<PassHook>] {
&self.pass_hooks
}
}
+2
View File
@@ -1003,6 +1003,8 @@ fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) ->
"dump MIR state at various points in translation"),
dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"the directory the MIR is dumped into"),
dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
"if set, exclude the pass number when dumping MIR (used in tests)"),
perf_stats: bool = (false, parse_bool, [UNTRACKED],
"print some performance-related statistics"),
hir_stats: bool = (false, parse_bool, [UNTRACKED],
-3
View File
@@ -21,7 +21,6 @@
use ty::tls;
use util::nodemap::{FxHashMap, FxHashSet};
use util::common::duration_to_secs_str;
use mir::transform as mir_pass;
use syntax::ast::NodeId;
use errors::{self, DiagnosticBuilder};
@@ -85,7 +84,6 @@ pub struct Session {
/// redundantly verbose output (Issue #24690).
pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Span, String)>>,
pub plugin_llvm_passes: RefCell<Vec<String>>,
pub mir_passes: RefCell<mir_pass::Passes>,
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>,
@@ -670,7 +668,6 @@ pub fn build_session_(sopts: config::Options,
lints: RefCell::new(lint::LintTable::new()),
one_time_diagnostics: RefCell::new(FxHashSet()),
plugin_llvm_passes: RefCell::new(Vec::new()),
mir_passes: RefCell::new(mir_pass::Passes::new()),
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FxHashMap()),
+18 -4
View File
@@ -25,6 +25,7 @@
use middle::resolve_lifetime;
use middle::stability;
use mir::Mir;
use mir::transform::Passes;
use ty::subst::{Kind, Substs};
use ty::ReprOptions;
use traits;
@@ -39,6 +40,7 @@
use ty::layout::{Layout, TargetDataLayout};
use ty::inhabitedness::DefIdForest;
use ty::maps;
use ty::steal::Steal;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -47,11 +49,12 @@
use rustc_data_structures::indexed_vec::IndexVec;
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::iter;
use std::cmp::Ordering;
use std::rc::Rc;
use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
@@ -68,7 +71,8 @@ pub struct GlobalArenas<'tcx> {
generics: TypedArena<ty::Generics>,
trait_def: TypedArena<ty::TraitDef>,
adt_def: TypedArena<ty::AdtDef>,
mir: TypedArena<RefCell<Mir<'tcx>>>,
steal_mir: TypedArena<Steal<Mir<'tcx>>>,
mir: TypedArena<Mir<'tcx>>,
tables: TypedArena<ty::TypeckTables<'tcx>>,
}
@@ -79,6 +83,7 @@ pub fn new() -> GlobalArenas<'tcx> {
generics: TypedArena::new(),
trait_def: TypedArena::new(),
adt_def: TypedArena::new(),
steal_mir: TypedArena::new(),
mir: TypedArena::new(),
tables: TypedArena::new(),
}
@@ -443,8 +448,11 @@ pub struct GlobalCtxt<'tcx> {
pub named_region_map: resolve_lifetime::NamedRegionMap,
pub hir: hir_map::Map<'tcx>,
pub maps: maps::Maps<'tcx>,
pub mir_passes: Rc<Passes>,
// Records the free variables refrenced by every closure
// expression. Do not track deps for this, just recompute it from
// scratch every time.
@@ -619,8 +627,12 @@ pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
self.global_arenas.generics.alloc(generics)
}
pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx RefCell<Mir<'gcx>> {
self.global_arenas.mir.alloc(RefCell::new(mir))
pub fn alloc_steal_mir(self, mir: Mir<'gcx>) -> &'gcx Steal<Mir<'gcx>> {
self.global_arenas.steal_mir.alloc(Steal::new(mir))
}
pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx Mir<'gcx> {
self.global_arenas.mir.alloc(mir)
}
pub fn alloc_tables(self, tables: ty::TypeckTables<'gcx>) -> &'gcx ty::TypeckTables<'gcx> {
@@ -714,6 +726,7 @@ fn is_global(self) -> bool {
pub fn create_and_enter<F, R>(s: &'tcx Session,
local_providers: ty::maps::Providers<'tcx>,
extern_providers: ty::maps::Providers<'tcx>,
mir_passes: Rc<Passes>,
arenas: &'tcx GlobalArenas<'tcx>,
arena: &'tcx DroplessArena,
resolutions: ty::Resolutions,
@@ -748,6 +761,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
fulfilled_predicates: RefCell::new(fulfilled_predicates),
hir: hir,
maps: maps::Maps::new(dep_graph, providers),
mir_passes,
freevars: RefCell::new(resolutions.freevars),
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
rcache: RefCell::new(FxHashMap()),
+207 -26
View File
@@ -16,22 +16,27 @@
use middle::privacy::AccessLevels;
use middle::region::RegionMaps;
use mir;
use mir::transform::{MirSuite, MirPassIndex};
use session::CompileResult;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::item_path;
use ty::steal::Steal;
use ty::subst::Substs;
use util::nodemap::NodeSet;
use util::nodemap::{DefIdSet, NodeSet};
use rustc_data_structures::indexed_vec::IndexVec;
use std::cell::{RefCell, RefMut};
use std::fmt::Debug;
use std::hash::Hash;
use std::mem;
use std::collections::BTreeMap;
use std::ops::Deref;
use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
use syntax::attr;
use syntax::symbol::Symbol;
trait Key {
pub trait Key: Clone + Hash + Eq + Debug {
fn map_crate(&self) -> CrateNum;
fn default_span(&self, tcx: TyCtxt) -> Span;
}
@@ -101,6 +106,24 @@ fn default_span(&self, tcx: TyCtxt) -> Span {
}
}
impl Key for (MirSuite, DefId) {
fn map_crate(&self) -> CrateNum {
self.1.map_crate()
}
fn default_span(&self, tcx: TyCtxt) -> Span {
self.1.default_span(tcx)
}
}
impl Key for (MirSuite, MirPassIndex, DefId) {
fn map_crate(&self) -> CrateNum {
self.2.map_crate()
}
fn default_span(&self, tcx: TyCtxt) -> Span {
self.2.default_span(tcx)
}
}
trait Value<'tcx>: Sized {
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
}
@@ -270,8 +293,13 @@ fn describe(_: TyCtxt, _: CrateNum) -> String {
impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String {
format!("const-evaluating `{}`",
tcx.item_path_str(def_id))
format!("const-evaluating `{}`", tcx.item_path_str(def_id))
}
}
impl<'tcx> QueryDescription for queries::mir_keys<'tcx> {
fn describe(_: TyCtxt, _: CrateNum) -> String {
format!("getting a list of all mir_keys")
}
}
@@ -293,6 +321,19 @@ fn describe(_: TyCtxt, _: DefId) -> String {
}
}
impl<'tcx> QueryDescription for queries::stability<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("stability")
}
}
impl<'tcx> QueryDescription for queries::deprecation<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("deprecation")
}
}
impl<'tcx> QueryDescription for queries::item_body_nested_bodies<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("nested item bodies of `{}`", tcx.item_path_str(def_id))
@@ -306,7 +347,7 @@ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
}
}
impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> {
impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("checking if item is mir available: `{}`",
tcx.item_path_str(def_id))
@@ -316,11 +357,10 @@ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
macro_rules! define_maps {
(<$tcx:tt>
$($(#[$attr:meta])*
[$($pub:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty,)*) => {
pub struct Maps<$tcx> {
providers: IndexVec<CrateNum, Providers<$tcx>>,
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
$($(#[$attr])* $($pub)* $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
[$($modifiers:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty,)*) => {
define_map_struct! {
tcx: $tcx,
input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
}
impl<$tcx> Maps<$tcx> {
@@ -400,7 +440,7 @@ fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
provider(tcx.global_tcx(), key)
})?;
Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
Ok(f(tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
}
pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
@@ -461,25 +501,153 @@ pub fn $name(self, key: $K) -> $V {
})*
}
pub struct Providers<$tcx> {
$(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),*
define_provider_struct! {
tcx: $tcx,
input: ($(([$($modifiers)*] [$name] [$K] [$V]))*),
output: ()
}
impl<$tcx> Copy for Providers<$tcx> {}
impl<$tcx> Clone for Providers<$tcx> {
fn clone(&self) -> Self { *self }
}
}
}
macro_rules! define_map_struct {
// Initial state
(tcx: $tcx:tt,
input: $input:tt) => {
define_map_struct! {
tcx: $tcx,
input: $input,
output: ()
}
};
// Final output
(tcx: $tcx:tt,
input: (),
output: ($($output:tt)*)) => {
pub struct Maps<$tcx> {
providers: IndexVec<CrateNum, Providers<$tcx>>,
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
$($output)*
}
};
// Field recognized and ready to shift into the output
(tcx: $tcx:tt,
ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]),
input: $input:tt,
output: ($($output:tt)*)) => {
define_map_struct! {
tcx: $tcx,
input: $input,
output: ($($output)*
$(#[$attr])* $($pub)* $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>,)
}
};
// Detect things with the `pub` modifier
(tcx: $tcx:tt,
input: (([pub $($other_modifiers:tt)*] $attrs:tt $name:tt) $($input:tt)*),
output: $output:tt) => {
define_map_struct! {
tcx: $tcx,
ready: ([pub] $attrs $name),
input: ($($input)*),
output: $output
}
};
// No modifiers left? This is a private item.
(tcx: $tcx:tt,
input: (([] $attrs:tt $name:tt) $($input:tt)*),
output: $output:tt) => {
define_map_struct! {
tcx: $tcx,
ready: ([pub] $attrs $name),
input: ($($input)*),
output: $output
}
};
// Skip other modifiers
(tcx: $tcx:tt,
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
output: $output:tt) => {
define_map_struct! {
tcx: $tcx,
input: (([$($modifiers)*] $($fields)*) $($input)*),
output: $output
}
};
}
macro_rules! define_provider_struct {
// Initial state:
(tcx: $tcx:tt, input: $input:tt) => {
define_provider_struct! {
tcx: $tcx,
input: $input,
output: ()
}
};
// Final state:
(tcx: $tcx:tt,
input: (),
output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => {
pub struct Providers<$tcx> {
$(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)*
}
impl<$tcx> Default for Providers<$tcx> {
fn default() -> Self {
$(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V {
$(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R {
bug!("tcx.maps.{}({:?}) unsupported by its crate",
stringify!($name), key);
})*
Providers { $($name),* }
}
}
}
};
// Something ready to shift:
(tcx: $tcx:tt,
ready: ($name:tt $K:tt $V:tt),
input: $input:tt,
output: ($($output:tt)*)) => {
define_provider_struct! {
tcx: $tcx,
input: $input,
output: ($($output)* ($name $K $V))
}
};
// Regular queries produce a `V` only.
(tcx: $tcx:tt,
input: (([] $name:tt $K:tt $V:tt) $($input:tt)*),
output: $output:tt) => {
define_provider_struct! {
tcx: $tcx,
ready: ($name $K $V),
input: ($($input)*),
output: $output
}
};
// Skip modifiers.
(tcx: $tcx:tt,
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
output: $output:tt) => {
define_provider_struct! {
tcx: $tcx,
input: (([$($modifiers)*] $($fields)*) $($input)*),
output: $output
}
};
}
// Each of these maps also corresponds to a method on a
@@ -537,20 +705,28 @@ fn default() -> Self {
/// Methods in these implementations don't need to be exported.
[] inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
/// Maps from the def-id of a function/method or const/static
/// to its MIR. Mutation is done at an item granularity to
/// allow MIR optimization passes to function and still
/// access cross-crate MIR (e.g. inlining or const eval).
///
/// Note that cross-crate MIR appears to be always borrowed
/// (in the `RefCell` sense) to prevent accidental mutation.
[pub] mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
/// Set of all the def-ids in this crate that have MIR associated with
/// them. This includes all the body owners, but also things like struct
/// constructors.
[] mir_keys: mir_keys(CrateNum) -> Rc<DefIdSet>,
/// Maps DefId's that have an associated Mir to the result
/// of the MIR qualify_consts pass. The actual meaning of
/// the value isn't known except to the pass itself.
[] mir_const_qualif: Mir(DefId) -> u8,
/// Fetch the MIR for a given def-id up till the point where it is
/// ready for const evaluation.
///
/// See the README for the `mir` module for details.
[] mir_const: Mir(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
[] mir_validated: Mir(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
/// MIR after our optimization passes have run. This is MIR that is ready
/// for trans. This is also the only query that can fetch non-local MIR, at present.
[] optimized_mir: Mir(DefId) -> &'tcx mir::Mir<'tcx>,
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
[] closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
@@ -598,17 +774,18 @@ fn default() -> Self {
/// fn item.
[] region_maps: RegionMaps(DefId) -> Rc<RegionMaps<'tcx>>,
[] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>,
[] def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
[] symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName,
[] describe_def: DescribeDef(DefId) -> Option<Def>,
[] def_span: DefSpan(DefId) -> Span,
[] stability: Stability(DefId) -> Option<attr::Stability>,
[] deprecation: Deprecation(DefId) -> Option<attr::Deprecation>,
[] item_body_nested_bodies: metadata_dep_node(DefId) -> Rc<BTreeMap<hir::BodyId, hir::Body>>,
[] const_is_rvalue_promotable_to_static: metadata_dep_node(DefId) -> bool,
[] is_item_mir_available: metadata_dep_node(DefId) -> bool,
[] is_mir_available: metadata_dep_node(DefId) -> bool,
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -644,3 +821,7 @@ fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
DepNode::ConstEval(def_id)
}
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
DepNode::MirKeys
}
+28 -29
View File
@@ -35,7 +35,7 @@
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
use serialize::{self, Encodable, Encoder};
use std::cell::{Cell, RefCell, Ref};
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::cmp;
use std::fmt;
@@ -96,6 +96,7 @@
pub mod maps;
pub mod outlives;
pub mod relate;
pub mod steal;
pub mod subst;
pub mod trait_def;
pub mod walk;
@@ -2049,6 +2050,16 @@ pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> {
self.typeck_tables_of(self.hir.body_owner_def_id(body))
}
/// Returns an iterator of the def-ids for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir.krate().body_ids.iter()`.
pub fn body_owners(self) -> impl Iterator<Item = DefId> + 'a {
self.hir.krate()
.body_ids
.iter()
.map(move |&body_id| self.hir.body_owner_def_id(body_id))
}
pub fn expr_span(self, id: NodeId) -> Span {
match self.hir.find(id) {
Some(hir_map::NodeExpr(e)) => {
@@ -2313,33 +2324,32 @@ pub fn item_name(self, id: DefId) -> ast::Name {
}
}
/// Given the did of an item, returns its MIR, borrowed immutably.
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
self.mir(did).borrow()
}
/// Return the possibly-auto-generated MIR of a (DefId, Subst) pair.
pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>)
-> Ref<'gcx, Mir<'gcx>>
-> &'gcx Mir<'gcx>
{
match instance {
ty::InstanceDef::Item(did) if true => self.item_mir(did),
_ => self.mir_shims(instance).borrow(),
ty::InstanceDef::Item(did) => {
self.optimized_mir(did)
}
ty::InstanceDef::Intrinsic(..) |
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::DropGlue(..) => {
self.mir_shims(instance)
}
}
}
/// Given the DefId of an item, returns its MIR, borrowed immutably.
/// Returns None if there is no MIR for the DefId
pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
if did.is_local() && !self.maps.mir.borrow().contains_key(&did) {
return None;
pub fn maybe_optimized_mir(self, did: DefId) -> Option<&'gcx Mir<'gcx>> {
if self.is_mir_available(did) {
Some(self.optimized_mir(did))
} else {
None
}
if !did.is_local() && !self.is_item_mir_available(did) {
return None;
}
Some(self.item_mir(did))
}
/// Get the attributes of a definition.
@@ -2541,17 +2551,6 @@ pub fn visit_all_item_likes_in_krate<V,F>(self,
dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
}
/// Invokes `callback` for each body in the krate. This will
/// create a read edge from `DepNode::Krate` to the current task;
/// it is meant to be run in the context of some global task like
/// `BorrowckCrate`. The callback would then create a task like
/// `BorrowckBody(DefId)` to process each individual item.
pub fn visit_all_bodies_in_krate<C>(self, callback: C)
where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId),
{
dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback)
}
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
/// with the name of the crate containing the impl.
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2012-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.
use std::cell::{Ref, RefCell};
use std::mem;
/// The `Steal` struct is intended to used as the value for a query.
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
/// where we create a large, complex value that we want to iteratively
/// update (e.g., optimize). We could clone the value for each
/// optimization, but that'd be expensive. And yet we don't just want
/// to mutate it in place, because that would spoil the idea that
/// queries are these pure functions that produce an immutable value
/// (since if you did the query twice, you could observe the
/// mutations). So instead we have the query produce a `&'tcx
/// Steal<Mir<'tcx>>` (to be very specific). Now we can read from this
/// as much as we want (using `borrow()`), but you can also
/// `steal()`. Once you steal, any further attempt to read will panic.
/// Therefore we know that -- assuming no ICE -- nobody is observing
/// the fact that the MIR was updated.
///
/// Obviously, whenever you have a query that yields a `Steal` value,
/// you must treat it with caution, and make sure that you know that
/// -- once the value is stolen -- it will never be read from again.
///
/// FIXME(#41710) -- what is the best way to model linear queries?
pub struct Steal<T> {
value: RefCell<Option<T>>
}
impl<T> Steal<T> {
pub fn new(value: T) -> Self {
Steal {
value: RefCell::new(Some(value))
}
}
pub fn borrow(&self) -> Ref<T> {
Ref::map(self.value.borrow(), |opt| match *opt {
None => bug!("attempted to read from stolen value"),
Some(ref v) => v
})
}
pub fn steal(&self) -> T {
let value_ref = &mut *self.value.borrow_mut();
let value = mem::replace(value_ref, None);
value.expect("attempt to read from stolen value")
}
}
@@ -13,7 +13,8 @@
pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.features = "+v7,+vfp3,+d16".to_string();
// https://developer.android.com/ndk/guides/abis.html#armeabi
base.features = "+v5te".to_string();
base.max_atomic_width = Some(64);
Ok(Target {
@@ -18,6 +18,8 @@ pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args
.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
Ok(Target {
llvm_target: "armv7-none-linux-android".to_string(),
@@ -73,9 +73,16 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec<Move
let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
let mut is_first_note = true;
match error.move_to_places.get(0) {
Some(&MovePlace { pat_source: PatternSource::LetDecl(_), .. }) => {
Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => {
// ignore patterns that are found at the top-level of a `let`;
// see `get_pattern_source()` for details
let initializer =
e.init.as_ref().expect("should have an initializer to get an error");
if let Ok(snippet) = bccx.tcx.sess.codemap().span_to_snippet(initializer.span) {
err.span_suggestion(initializer.span,
"consider using a reference instead",
format!("&{}", snippet));
}
}
_ => {
for move_to in &error.move_to_places {
@@ -16,7 +16,7 @@
use super::MoveDataParamEnv;
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
use rustc::mir::transform::{Pass, MirPass, MirSource};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::middle::const_val::ConstVal;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -32,9 +32,11 @@
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>)
impl MirPass for ElaborateDrops {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &mut Mir<'tcx>)
{
debug!("elaborate_drops({:?} @ {:?})", src, mir.span);
match src {
@@ -74,8 +76,6 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
impl Pass for ElaborateDrops {}
/// Return the set of basic blocks whose unwind edges are known
/// to not be reachable, because they are `drop` terminators
/// that can't drop anything.
+4 -1
View File
@@ -61,7 +61,10 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
let def_id = tcx.hir.local_def_id(id);
debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
let mir = &tcx.item_mir(def_id);
// It is safe for us to borrow `mir_validated()`: `optimized_mir`
// steals it, but it forces the `borrowck` query.
let mir = &tcx.mir_validated(def_id).borrow();
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
+25 -2
View File
@@ -63,9 +63,9 @@
pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
for body_owner_def_id in tcx.body_owners() {
tcx.borrowck(body_owner_def_id);
});
}
}
pub fn provide(providers: &mut Providers) {
@@ -86,6 +86,19 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
match tcx.hir.get(owner_id) {
hir_map::NodeStructCtor(_) |
hir_map::NodeVariant(_) => {
// We get invoked with anything that has MIR, but some of
// those things (notably the synthesized constructors from
// tuple structs/variants) do not have an associated body
// and do not need borrowchecking.
return;
}
_ => { }
}
let body_id = tcx.hir.body_owned_by(owner_id);
let attributes = tcx.get_attrs(owner_def_id);
let tables = tcx.typeck_tables_of(owner_def_id);
@@ -96,6 +109,16 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") {
mir::borrowck_mir(bccx, owner_id, &attributes);
} else {
// Eventually, borrowck will always read the MIR, but at the
// moment we do not. So, for now, we always force MIR to be
// constructed for a given fn, since this may result in errors
// being reported and we want that to happen.
//
// Note that `mir_validated` is a "stealable" result; the
// thief, `optimized_mir()`, forces borrowck, so we know that
// is not yet stolen.
tcx.mir_validated(owner_def_id).borrow();
}
let cfg = cfg::CFG::new(bccx.tcx, &body);
+37 -63
View File
@@ -20,6 +20,7 @@
use rustc::lint;
use rustc::middle::{self, dependency_format, stability, reachable};
use rustc::middle::privacy::AccessLevels;
use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc::util::common::time;
use rustc::util::nodemap::NodeSet;
@@ -35,8 +36,7 @@
use rustc_privacy;
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
use rustc_passes::{ast_validation, no_asm, loops, consts,
static_recursion, hir_stats, mir_stats};
use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
use rustc_const_eval::{self, check_match};
use super::Compilation;
@@ -903,9 +903,44 @@ macro_rules! try_with_f {
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
rustc_const_eval::provide(&mut extern_providers);
// Setup the MIR passes that we want to run.
let mut passes = Passes::new();
passes.push_hook(mir::transform::dump_mir::DumpMir);
// What we need to do constant evaluation.
passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial"));
passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
// What we need to run borrowck etc.
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(MIR_VALIDATED,
mir::transform::simplify_branches::SimplifyBranches::new("initial"));
passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
// Optimizations begin.
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(MIR_OPTIMIZED, borrowck::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
// No lifetime analysis based on borrowing can be done from here on out.
passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
TyCtxt::create_and_enter(sess,
local_providers,
extern_providers,
Rc::new(passes),
arenas,
arena,
resolutions,
@@ -962,30 +997,6 @@ macro_rules! try_with_f {
"liveness checking",
|| middle::liveness::check_crate(tcx));
time(time_passes,
"MIR dump",
|| mir::mir_map::build_mir_for_crate(tcx));
if sess.opts.debugging_opts.mir_stats {
mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS");
}
time(time_passes, "MIR cleanup and validation", || {
let mut passes = sess.mir_passes.borrow_mut();
// Push all the built-in validation passes.
// NB: if youre adding an *optimisation* it ought to go to another set of passes
// in stage 4 below.
passes.push_hook(box mir::transform::dump_mir::DumpMir);
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
passes.push_pass(box mir::transform::type_check::TypeckMir);
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(
box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
// And run everything.
passes.run_passes(tcx);
});
time(time_passes,
"borrow checking",
|| borrowck::check_crate(tcx));
@@ -1034,43 +1045,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
"resolving dependency formats",
|| dependency_format::calculate(&tcx.sess));
if tcx.sess.opts.debugging_opts.mir_stats {
mir_stats::print_mir_stats(tcx, "PRE OPTIMISATION MIR STATS");
}
// Run the passes that transform the MIR into a more suitable form for translation to LLVM
// code.
time(time_passes, "MIR optimisations", || {
let mut passes = ::rustc::mir::transform::Passes::new();
passes.push_hook(box mir::transform::dump_mir::DumpMir);
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
// From here on out, regions are gone.
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(box borrowck::ElaborateDrops);
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
// No lifetime analysis based on borrowing can be done from here on out.
passes.push_pass(box mir::transform::inline::Inline);
passes.push_pass(box mir::transform::instcombine::InstCombine::new());
passes.push_pass(box mir::transform::deaggregator::Deaggregator);
passes.push_pass(box mir::transform::copy_prop::CopyPropagation);
passes.push_pass(box mir::transform::simplify::SimplifyLocals);
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans"));
passes.run_passes(tcx);
});
if tcx.sess.opts.debugging_opts.mir_stats {
mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS");
}
let translation =
time(time_passes,
"translation",
+4 -13
View File
@@ -41,7 +41,6 @@
use std::cell::Cell;
use std::fs::File;
use std::io::{self, Write};
use std::iter;
use std::option;
use std::path::Path;
use std::str::FromStr;
@@ -999,22 +998,14 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
if let Some(nodeid) = nodeid {
let def_id = tcx.hir.local_def_id(nodeid);
match ppm {
PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mut out),
PpmMirCFG => write_mir_graphviz(tcx, iter::once(def_id), &mut out),
PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out),
PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out),
_ => unreachable!(),
}?;
} else {
match ppm {
PpmMir => {
write_mir_pretty(tcx,
tcx.maps.mir.borrow().keys().into_iter(),
&mut out)
}
PpmMirCFG => {
write_mir_graphviz(tcx,
tcx.maps.mir.borrow().keys().into_iter(),
&mut out)
}
PpmMir => write_mir_pretty(tcx, None, &mut out),
PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
_ => unreachable!(),
}?;
}
+2
View File
@@ -27,6 +27,7 @@
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc_metadata::cstore::CStore;
use rustc::hir::map as hir_map;
use rustc::mir::transform::Passes;
use rustc::session::{self, config};
use std::rc::Rc;
use syntax::ast;
@@ -141,6 +142,7 @@ fn test_env<F>(source_string: &str,
TyCtxt::create_and_enter(&sess,
ty::maps::Providers::default(),
ty::maps::Providers::default(),
Rc::new(Passes::new()),
&arenas,
&arena,
resolutions,
+6 -18
View File
@@ -30,7 +30,6 @@
use rustc_back::PanicStrategy;
use std::any::Any;
use std::mem;
use std::rc::Rc;
use syntax::ast;
@@ -95,16 +94,13 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
mir => {
let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
bug!("get_item_mir: missing MIR for `{:?}`", def_id)
optimized_mir => {
let mir = cdata.maybe_get_optimized_mir(tcx, def_id.index).unwrap_or_else(|| {
bug!("get_optimized_mir: missing MIR for `{:?}`", def_id)
});
let mir = tcx.alloc_mir(mir);
// Perma-borrow MIR from extern crates to prevent mutation.
mem::forget(mir.borrow());
mir
}
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
@@ -115,6 +111,8 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
describe_def => { cdata.get_def(def_id.index) }
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
stability => { cdata.get_stability(def_id.index) }
deprecation => { cdata.get_deprecation(def_id.index) }
item_body_nested_bodies => {
let map: BTreeMap<_, _> = cdata.entry(def_id.index).ast.into_iter().flat_map(|ast| {
ast.decode(cdata).nested_bodies.decode(cdata).map(|body| (body.id(), body))
@@ -126,7 +124,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
cdata.entry(def_id.index).ast.expect("const item missing `ast`")
.decode(cdata).rvalue_promotable_to_static
}
is_item_mir_available => {
is_mir_available => {
!cdata.is_proc_macro(def_id.index) &&
cdata.maybe_entry(def_id.index).and_then(|item| item.decode(cdata).mir).is_some()
}
@@ -137,16 +135,6 @@ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any> {
self.get_crate_data(krate)
}
fn stability(&self, def: DefId) -> Option<attr::Stability> {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_stability(def.index)
}
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_deprecation(def.index)
}
fn visibility(&self, def: DefId) -> ty::Visibility {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_visibility(def.index)
+4 -4
View File
@@ -779,10 +779,10 @@ pub fn item_body_tables(&self,
tcx.alloc_tables(ast.tables.decode((self, tcx)))
}
pub fn maybe_get_item_mir(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex)
-> Option<Mir<'tcx>> {
pub fn maybe_get_optimized_mir(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex)
-> Option<Mir<'tcx>> {
match self.is_proc_macro(id) {
true => None,
false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))),
+16 -11
View File
@@ -295,7 +295,7 @@ fn encode_enum_variant_info(&mut self,
predicates: Some(self.encode_predicates(def_id)),
ast: None,
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@@ -433,7 +433,7 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
predicates: Some(self.encode_predicates(def_id)),
ast: None,
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@@ -528,7 +528,7 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
} else {
None
},
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@@ -598,7 +598,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
predicates: Some(self.encode_predicates(def_id)),
ast: ast.map(|body| self.encode_body(body)),
mir: if mir { self.encode_mir(def_id) } else { None },
mir: if mir { self.encode_optimized_mir(def_id) } else { None },
}
}
@@ -619,9 +619,14 @@ fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
self.lazy_seq(names.iter().map(|name| name.node))
}
fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
fn encode_optimized_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
debug!("EntryBuilder::encode_mir({:?})", def_id);
self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
let mir = self.tcx.optimized_mir(def_id);
Some(self.lazy(&mir))
} else {
None
}
}
// Encodes the inherent implementations of a structure, enumeration, or trait.
@@ -856,15 +861,15 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
},
mir: match item.node {
hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
self.encode_mir(def_id)
self.encode_optimized_mir(def_id)
}
hir::ItemConst(..) => self.encode_mir(def_id),
hir::ItemConst(..) => self.encode_optimized_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let tps_len = generics.ty_params.len();
let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
if needs_inline || constness == hir::Constness::Const || always_encode_mir {
self.encode_mir(def_id)
self.encode_optimized_mir(def_id)
} else {
None
}
@@ -1161,7 +1166,7 @@ fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
predicates: None,
ast: None,
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@@ -1187,7 +1192,7 @@ fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> {
predicates: Some(self.encode_predicates(def_id)),
ast: Some(self.encode_body(body)),
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
+1 -1
View File
@@ -18,7 +18,7 @@
use hair::*;
use rustc::mir::*;
pub trait EvalInto<'tcx> {
pub(in build) trait EvalInto<'tcx> {
fn eval_into<'a, 'gcx>(self,
builder: &mut Builder<'a, 'gcx, 'tcx>,
destination: &Lvalue<'tcx>,
+217 -16
View File
@@ -8,24 +8,225 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use build;
use hair::cx::Cx;
use hair::Pattern;
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::util::nodemap::NodeMap;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use shim;
use std::mem;
use std::u32;
use syntax::abi::Abi;
use syntax::ast;
use syntax::symbol::keywords;
use syntax_pos::Span;
use util as mir_util;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
/// Construct the MIR for a given def-id.
pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'tcx> {
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let unsupported = || {
span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
};
use std::u32;
// Figure out what primary body this item has.
let body_id = match tcx.hir.get(id) {
hir::map::NodeItem(item) => {
match item.node {
hir::ItemConst(_, body) |
hir::ItemStatic(_, _, body) |
hir::ItemFn(.., body) => body,
_ => unsupported()
}
}
hir::map::NodeTraitItem(item) => {
match item.node {
hir::TraitItemKind::Const(_, Some(body)) |
hir::TraitItemKind::Method(_,
hir::TraitMethod::Provided(body)) => body,
_ => unsupported()
}
}
hir::map::NodeImplItem(item) => {
match item.node {
hir::ImplItemKind::Const(_, body) |
hir::ImplItemKind::Method(_, body) => body,
_ => unsupported()
}
}
hir::map::NodeExpr(expr) => {
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in a constant position.
// Assume that everything other than closures
// is a constant "initializer" expression.
match expr.node {
hir::ExprClosure(_, _, body, _) => body,
_ => hir::BodyId { node_id: expr.id }
}
}
hir::map::NodeVariant(variant) =>
return create_constructor_shim(tcx, id, &variant.node.data),
hir::map::NodeStructCtor(ctor) =>
return create_constructor_shim(tcx, id, ctor),
_ => unsupported()
};
pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
let src = MirSource::from_node(tcx, id);
tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
let cx = Cx::new(&infcx, src);
let mut mir = if cx.tables().tainted_by_errors {
build::construct_error(cx, body_id)
} else if let MirSource::Fn(id) = src {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
let ty = tcx.type_of(tcx.hir.local_def_id(id));
let mut abi = fn_sig.abi;
let implicit_argument = if let ty::TyClosure(..) = ty.sty {
// HACK(eddyb) Avoid having RustCall on closures,
// as it adds unnecessary (and wrong) auto-tupling.
abi = Abi::Rust;
Some((closure_self_ty(tcx, id, body_id), None))
} else {
None
};
let body = tcx.hir.body(body_id);
let explicit_arguments =
body.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
});
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
} else {
build::construct_const(cx, body_id)
};
// Convert the Mir to global types.
let mut globalizer = GlobalizeMir {
tcx: tcx,
span: mir.span
};
globalizer.visit_mir(&mut mir);
let mir = unsafe {
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
mir
})
}
/// A pass to lift all the types and substitutions in a Mir
/// to the global tcx. Sadly, we don't have a "folder" that
/// can change 'tcx so we have to transmute afterwards.
struct GlobalizeMir<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
span: Span
}
impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
if let Some(lifted) = self.tcx.lift(ty) {
*ty = lifted;
} else {
span_bug!(self.span,
"found type `{:?}` with inference types/regions in MIR",
ty);
}
}
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
if let Some(lifted) = self.tcx.lift(substs) {
*substs = lifted;
} else {
span_bug!(self.span,
"found substs `{:?}` with inference types/regions in MIR",
substs);
}
}
}
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor_id: ast::NodeId,
v: &'tcx hir::VariantData)
-> Mir<'tcx>
{
let span = tcx.hir.span(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
let (mut mir, src) =
shim::build_adt_ctor(&infcx, ctor_id, fields, span);
// Convert the Mir to global types.
let tcx = infcx.tcx.global_tcx();
let mut globalizer = GlobalizeMir {
tcx: tcx,
span: mir.span
};
globalizer.visit_mir(&mut mir);
let mir = unsafe {
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
mir
})
} else {
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
}
}
///////////////////////////////////////////////////////////////////////////
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
closure_expr_id: ast::NodeId,
body_id: hir::BodyId)
-> Ty<'tcx> {
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
let region = ty::ReFree(ty::FreeRegion {
scope: Some(tcx.item_extent(body_id.node_id)),
bound_region: ty::BoundRegion::BrEnv,
});
let region = tcx.mk_region(region);
match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
ty::ClosureKind::Fn =>
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutImmutable }),
ty::ClosureKind::FnMut =>
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutMutable }),
ty::ClosureKind::FnOnce =>
closure_ty
}
}
struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
hir: Cx<'a, 'gcx, 'tcx>,
cfg: CFG<'tcx>,
@@ -82,7 +283,7 @@ fn index(self) -> usize {
/// convenient.
#[must_use] // if you don't use one of these results, you're leaving a dangling edge
pub struct BlockAnd<T>(BasicBlock, T);
struct BlockAnd<T>(BasicBlock, T);
trait BlockAndExtension {
fn and<T>(self, v: T) -> BlockAnd<T>;
@@ -121,13 +322,13 @@ macro_rules! unpack {
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
arguments: A,
abi: Abi,
return_ty: Ty<'gcx>,
body: &'gcx hir::Body)
-> Mir<'tcx>
fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
arguments: A,
abi: Abi,
return_ty: Ty<'gcx>,
body: &'gcx hir::Body)
-> Mir<'tcx>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
let arguments: Vec<_> = arguments.collect();
-252
View File
@@ -1,252 +0,0 @@
// 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.
//! MIR-based callgraph.
//!
//! This only considers direct calls
use rustc::hir::def_id::DefId;
use rustc_data_structures::graph;
use rustc::mir::*;
use rustc::mir::visit::*;
use rustc::ty;
use rustc::util::nodemap::DefIdMap;
pub struct CallGraph {
node_map: DefIdMap<graph::NodeIndex>,
graph: graph::Graph<DefId, ()>
}
impl CallGraph {
// FIXME: allow for construction of a callgraph that inspects
// cross-crate MIRs if available.
pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph {
let def_ids = tcx.maps.mir.borrow().keys();
let mut callgraph = CallGraph {
node_map: DefIdMap(),
graph: graph::Graph::new()
};
for def_id in def_ids {
if !def_id.is_local() { continue; }
let idx = callgraph.add_node(def_id);
let mut call_visitor = CallVisitor {
caller: idx,
graph: &mut callgraph
};
let mir = tcx.item_mir(def_id);
call_visitor.visit_mir(&mir);
}
callgraph
}
// Iterate over the strongly-connected components of the graph
pub fn scc_iter(&self) -> SCCIterator {
SCCIterator::new(&self.graph)
}
// Get the def_id for the given graph node
pub fn def_id(&self, node: graph::NodeIndex) -> DefId {
*self.graph.node_data(node)
}
fn add_node(&mut self, id: DefId) -> graph::NodeIndex {
let graph = &mut self.graph;
*self.node_map.entry(id).or_insert_with(|| {
graph.add_node(id)
})
}
}
struct CallVisitor<'a> {
caller: graph::NodeIndex,
graph: &'a mut CallGraph
}
impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> {
fn visit_terminator_kind(&mut self, _block: BasicBlock,
kind: &TerminatorKind<'tcx>, _loc: Location) {
if let TerminatorKind::Call {
func: Operand::Constant(ref f)
, .. } = *kind {
if let ty::TyFnDef(def_id, _, _) = f.ty.sty {
let callee = self.graph.add_node(def_id);
self.graph.graph.add_edge(self.caller, callee, ());
}
}
}
}
struct StackElement<'g> {
node: graph::NodeIndex,
lowlink: usize,
children: graph::AdjacentTargets<'g, DefId, ()>
}
/**
* Iterator over strongly-connected-components using Tarjan's algorithm[1]
*
* [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
*/
pub struct SCCIterator<'g> {
graph: &'g graph::Graph<DefId, ()>,
index: usize,
node_indices: Vec<Option<usize>>,
scc_stack: Vec<graph::NodeIndex>,
current_scc: Vec<graph::NodeIndex>,
visit_stack: Vec<StackElement<'g>>,
}
impl<'g> SCCIterator<'g> {
pub fn new(graph: &'g graph::Graph<DefId, ()>) -> SCCIterator<'g> {
if graph.len_nodes() == 0 {
return SCCIterator {
graph: graph,
index: 0,
node_indices: Vec::new(),
scc_stack: Vec::new(),
current_scc: Vec::new(),
visit_stack: Vec::new()
};
}
let first = graph::NodeIndex(0);
SCCIterator::with_entry(graph, first)
}
pub fn with_entry(graph: &'g graph::Graph<DefId, ()>,
entry: graph::NodeIndex) -> SCCIterator<'g> {
let mut iter = SCCIterator {
graph: graph,
index: 0,
node_indices: Vec::with_capacity(graph.len_nodes()),
scc_stack: Vec::new(),
current_scc: Vec::new(),
visit_stack: Vec::new()
};
iter.visit_one(entry);
iter
}
fn get_next(&mut self) {
self.current_scc.clear();
while !self.visit_stack.is_empty() {
self.visit_children();
let node = self.visit_stack.pop().unwrap();
if let Some(last) = self.visit_stack.last_mut() {
if last.lowlink > node.lowlink {
last.lowlink = node.lowlink;
}
}
debug!("TarjanSCC: Popped node {:?} : lowlink = {:?}; index = {:?}",
node.node, node.lowlink, self.node_index(node.node).unwrap());
if node.lowlink != self.node_index(node.node).unwrap() {
continue;
}
loop {
let n = self.scc_stack.pop().unwrap();
self.current_scc.push(n);
self.set_node_index(n, !0);
if n == node.node { return; }
}
}
}
fn visit_one(&mut self, node: graph::NodeIndex) {
self.index += 1;
let idx = self.index;
self.set_node_index(node, idx);
self.scc_stack.push(node);
self.visit_stack.push(StackElement {
node: node,
lowlink: self.index,
children: self.graph.successor_nodes(node)
});
debug!("TarjanSCC: Node {:?} : index = {:?}", node, idx);
}
fn visit_children(&mut self) {
while let Some(child) = self.visit_stack.last_mut().unwrap().children.next() {
if let Some(child_num) = self.node_index(child) {
let cur = self.visit_stack.last_mut().unwrap();
if cur.lowlink > child_num {
cur.lowlink = child_num;
}
} else {
self.visit_one(child);
}
}
}
fn node_index(&self, node: graph::NodeIndex) -> Option<usize> {
self.node_indices.get(node.node_id()).and_then(|&idx| idx)
}
fn set_node_index(&mut self, node: graph::NodeIndex, idx: usize) {
let i = node.node_id();
if i >= self.node_indices.len() {
self.node_indices.resize(i + 1, None);
}
self.node_indices[i] = Some(idx);
}
}
impl<'g> Iterator for SCCIterator<'g> {
type Item = Vec<graph::NodeIndex>;
fn next(&mut self) -> Option<Vec<graph::NodeIndex>> {
self.get_next();
if self.current_scc.is_empty() {
// Try a new root for the next SCC, if the node_indices
// map is doesn't contain all nodes, use the smallest one
// with no entry, otherwise find the first empty node.
//
// FIXME: This should probably use a set of precomputed
// roots instead
if self.node_indices.len() < self.graph.len_nodes() {
let idx = graph::NodeIndex(self.node_indices.len());
self.visit_one(idx);
} else {
for idx in 0..self.node_indices.len() {
if self.node_indices[idx].is_none() {
let idx = graph::NodeIndex(idx);
self.visit_one(idx);
break;
}
}
}
self.get_next();
}
if self.current_scc.is_empty() {
None
} else {
Some(self.current_scc.clone())
}
}
}
+1 -5
View File
@@ -26,7 +26,7 @@
use rustc::infer::InferCtxt;
use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty, TyCtxt};
use syntax::symbol::{Symbol, InternedString};
use syntax::symbol::Symbol;
use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize};
use std::rc::Rc;
@@ -103,10 +103,6 @@ pub fn unit_ty(&mut self) -> Ty<'tcx> {
self.tcx.mk_nil()
}
pub fn str_literal(&mut self, value: InternedString) -> Literal<'tcx> {
Literal::Value { value: ConstVal::Str(value) }
}
pub fn true_literal(&mut self) -> Literal<'tcx> {
Literal::Value { value: ConstVal::Bool(true) }
}
+2 -5
View File
@@ -46,18 +46,15 @@
pub mod diagnostics;
pub mod build;
pub mod callgraph;
mod build;
mod hair;
mod shim;
pub mod mir_map;
pub mod transform;
pub mod util;
use rustc::ty::maps::Providers;
pub fn provide(providers: &mut Providers) {
mir_map::provide(providers);
shim::provide(providers);
transform::qualify_consts::provide(providers);
transform::provide(providers);
}
-273
View File
@@ -1,273 +0,0 @@
// 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.
//! An experimental pass that scources for `#[rustc_mir]` attributes,
//! builds the resulting MIR, and dumps it out into a file for inspection.
//!
//! The attribute formats that are currently accepted are:
//!
//! - `#[rustc_mir(graphviz="file.gv")]`
//! - `#[rustc_mir(pretty="file.mir")]`
use build;
use rustc::hir::def_id::DefId;
use rustc::dep_graph::DepNode;
use rustc::mir::Mir;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor;
use shim;
use hair::cx::Cx;
use util as mir_util;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::subst::Substs;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use syntax::abi::Abi;
use syntax::ast;
use syntax_pos::Span;
use std::cell::RefCell;
use std::mem;
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task);
fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
tcx.item_mir(body_owner_def_id);
});
// Tuple struct/variant constructors don't have a BodyId, so we need
// to build them separately.
struct GatherCtors<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>
}
impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
fn visit_variant_data(&mut self,
v: &'tcx hir::VariantData,
_: ast::Name,
_: &'tcx hir::Generics,
_: ast::NodeId,
_: Span) {
if let hir::VariantData::Tuple(_, node_id) = *v {
self.tcx.item_mir(self.tcx.hir.local_def_id(node_id));
}
intravisit::walk_struct_def(self, v)
}
fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
NestedVisitorMap::None
}
}
tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
tcx: tcx
}.as_deep_visitor());
}
}
pub fn provide(providers: &mut Providers) {
providers.mir = build_mir;
}
fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> &'tcx RefCell<Mir<'tcx>> {
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let unsupported = || {
span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
};
// Figure out what primary body this item has.
let body_id = match tcx.hir.get(id) {
hir::map::NodeItem(item) => {
match item.node {
hir::ItemConst(_, body) |
hir::ItemStatic(_, _, body) |
hir::ItemFn(.., body) => body,
_ => unsupported()
}
}
hir::map::NodeTraitItem(item) => {
match item.node {
hir::TraitItemKind::Const(_, Some(body)) |
hir::TraitItemKind::Method(_,
hir::TraitMethod::Provided(body)) => body,
_ => unsupported()
}
}
hir::map::NodeImplItem(item) => {
match item.node {
hir::ImplItemKind::Const(_, body) |
hir::ImplItemKind::Method(_, body) => body,
_ => unsupported()
}
}
hir::map::NodeExpr(expr) => {
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in a constant position.
// Assume that everything other than closures
// is a constant "initializer" expression.
match expr.node {
hir::ExprClosure(_, _, body, _) => body,
_ => hir::BodyId { node_id: expr.id }
}
}
hir::map::NodeVariant(variant) =>
return create_constructor_shim(tcx, id, &variant.node.data),
hir::map::NodeStructCtor(ctor) =>
return create_constructor_shim(tcx, id, ctor),
_ => unsupported()
};
let src = MirSource::from_node(tcx, id);
tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
let cx = Cx::new(&infcx, src);
let mut mir = if cx.tables().tainted_by_errors {
build::construct_error(cx, body_id)
} else if let MirSource::Fn(id) = src {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
let ty = tcx.type_of(tcx.hir.local_def_id(id));
let mut abi = fn_sig.abi;
let implicit_argument = if let ty::TyClosure(..) = ty.sty {
// HACK(eddyb) Avoid having RustCall on closures,
// as it adds unnecessary (and wrong) auto-tupling.
abi = Abi::Rust;
Some((closure_self_ty(tcx, id, body_id), None))
} else {
None
};
let body = tcx.hir.body(body_id);
let explicit_arguments =
body.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
});
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
} else {
build::construct_const(cx, body_id)
};
// Convert the Mir to global types.
let mut globalizer = GlobalizeMir {
tcx: tcx,
span: mir.span
};
globalizer.visit_mir(&mut mir);
let mir = unsafe {
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
mir_util::dump_mir(tcx, "mir_map", &0, src, &mir);
tcx.alloc_mir(mir)
})
}
/// A pass to lift all the types and substitutions in a Mir
/// to the global tcx. Sadly, we don't have a "folder" that
/// can change 'tcx so we have to transmute afterwards.
struct GlobalizeMir<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
span: Span
}
impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
if let Some(lifted) = self.tcx.lift(ty) {
*ty = lifted;
} else {
span_bug!(self.span,
"found type `{:?}` with inference types/regions in MIR",
ty);
}
}
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
if let Some(lifted) = self.tcx.lift(substs) {
*substs = lifted;
} else {
span_bug!(self.span,
"found substs `{:?}` with inference types/regions in MIR",
substs);
}
}
}
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor_id: ast::NodeId,
v: &'tcx hir::VariantData)
-> &'tcx RefCell<Mir<'tcx>>
{
let span = tcx.hir.span(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
let (mut mir, src) =
shim::build_adt_ctor(&infcx, ctor_id, fields, span);
// Convert the Mir to global types.
let tcx = infcx.tcx.global_tcx();
let mut globalizer = GlobalizeMir {
tcx: tcx,
span: mir.span
};
globalizer.visit_mir(&mut mir);
let mir = unsafe {
mem::transmute::<Mir, Mir<'tcx>>(mir)
};
mir_util::dump_mir(tcx, "mir_map", &0, src, &mir);
tcx.alloc_mir(mir)
})
} else {
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
}
}
///////////////////////////////////////////////////////////////////////////
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
closure_expr_id: ast::NodeId,
body_id: hir::BodyId)
-> Ty<'tcx> {
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
let region = ty::ReFree(ty::FreeRegion {
scope: Some(tcx.item_extent(body_id.node_id)),
bound_region: ty::BoundRegion::BrEnv,
});
let region = tcx.mk_region(region);
match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
ty::ClosureKind::Fn =>
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutImmutable }),
ty::ClosureKind::FnMut =>
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutMutable }),
ty::ClosureKind::FnOnce =>
closure_ty
}
}
+2 -7
View File
@@ -24,10 +24,8 @@
use syntax::ast;
use syntax_pos::Span;
use std::cell::RefCell;
use std::fmt;
use std::iter;
use std::mem;
use transform::{add_call_guards, no_landing_pads, simplify};
use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
@@ -39,7 +37,7 @@ pub fn provide(providers: &mut Providers) {
fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
instance: ty::InstanceDef<'tcx>)
-> &'tcx RefCell<Mir<'tcx>>
-> &'tcx Mir<'tcx>
{
debug!("make_shim({:?})", instance);
let did = instance.def_id();
@@ -116,10 +114,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
add_call_guards::add_call_guards(&mut result);
debug!("make_shim({:?}) = {:?}", instance, result);
let result = tcx.alloc_mir(result);
// Perma-borrow MIR from shims to prevent mutation.
mem::forget(result.borrow());
result
tcx.alloc_mir(result)
}
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -10,7 +10,7 @@
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
pub struct AddCallGuards;
@@ -35,8 +35,11 @@
*
*/
impl<'tcx> MirPass<'tcx> for AddCallGuards {
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for AddCallGuards {
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
add_call_guards(mir);
}
}
@@ -82,5 +85,3 @@ pub fn add_call_guards(mir: &mut Mir) {
mir.basic_blocks_mut().extend(new_blocks);
}
impl Pass for AddCallGuards {}
+6 -8
View File
@@ -30,7 +30,7 @@
//! future.
use rustc::mir::{Constant, Local, LocalKind, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
use util::def_use::DefUseAnalysis;
@@ -38,13 +38,11 @@
pub struct CopyPropagation;
impl Pass for CopyPropagation {}
impl<'tcx> MirPass<'tcx> for CopyPropagation {
fn run_pass<'a>(&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
impl MirPass for CopyPropagation {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
match source {
MirSource::Const(_) => {
// Don't run on constants, because constant qualification might reject the
+6 -6
View File
@@ -10,16 +10,16 @@
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc_data_structures::indexed_vec::Idx;
pub struct Deaggregator;
impl Pass for Deaggregator {}
impl<'tcx> MirPass<'tcx> for Deaggregator {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for Deaggregator {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
let node_id = source.item_id();
let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
debug!("running on: {:?}", node_path);
+36 -40
View File
@@ -10,70 +10,66 @@
//! This pass just dumps MIR at a specified point.
use std::borrow::Cow;
use std::fmt;
use std::fs::File;
use std::io;
use rustc::mir::Mir;
use rustc::mir::transform::{MirPass, MirPassIndex, MirSource, MirSuite, PassHook};
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource};
use util as mir_util;
pub struct Marker<'a>(pub &'a str);
pub struct Marker(pub &'static str);
impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> {
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource, _mir: &mut Mir<'tcx>)
{}
impl MirPass for Marker {
fn name<'a>(&'a self) -> Cow<'a, str> {
Cow::Borrowed(self.0)
}
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_source: MirSource,
_mir: &mut Mir<'tcx>)
{
}
}
impl<'b> Pass for Marker<'b> {
fn name(&self) -> ::std::borrow::Cow<'static, str> { String::from(self.0).into() }
}
pub struct Disambiguator<'a> {
pass: &'a Pass,
pub struct Disambiguator {
is_after: bool
}
impl<'a> fmt::Display for Disambiguator<'a> {
impl fmt::Display for Disambiguator {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let title = if self.is_after { "after" } else { "before" };
if let Some(fmt) = self.pass.disambiguator() {
write!(formatter, "{}-{}", fmt, title)
} else {
write!(formatter, "{}", title)
}
write!(formatter, "{}", title)
}
}
pub struct DumpMir;
impl<'tcx> MirPassHook<'tcx> for DumpMir {
fn on_mir_pass<'a>(
&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &Mir<'tcx>,
pass: &Pass,
is_after: bool)
impl PassHook for DumpMir {
fn on_mir_pass<'a, 'tcx: 'a>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
suite: MirSuite,
pass_num: MirPassIndex,
pass_name: &str,
source: MirSource,
mir: &Mir<'tcx>,
is_after: bool)
{
mir_util::dump_mir(
tcx,
&*pass.name(),
&Disambiguator {
pass: pass,
is_after: is_after
},
src,
mir
);
if mir_util::dump_enabled(tcx, pass_name, source) {
mir_util::dump_mir(tcx,
Some((suite, pass_num)),
pass_name,
&Disambiguator { is_after },
source,
mir);
}
}
}
impl<'b> Pass for DumpMir {}
pub fn emit_mir<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
outputs: &OutputFilenames)
@@ -81,6 +77,6 @@ pub fn emit_mir<'a, 'tcx>(
{
let path = outputs.path(OutputType::Mir);
let mut f = File::create(&path)?;
mir_util::write_mir_pretty(tcx, tcx.maps.mir.borrow().keys().into_iter(), &mut f)?;
mir_util::write_mir_pretty(tcx, None, &mut f)?;
Ok(())
}
+6 -6
View File
@@ -16,7 +16,7 @@
use rustc::ty::{Ty, TyCtxt, ClosureSubsts};
use rustc::mir::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -69,11 +69,11 @@ fn visit_closure_substs(&mut self,
pub struct EraseRegions;
impl Pass for EraseRegions {}
impl<'tcx> MirPass<'tcx> for EraseRegions {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for EraseRegions {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}
+77 -189
View File
@@ -14,24 +14,20 @@
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::graph;
use rustc::dep_graph::DepNode;
use rustc::mir::*;
use rustc::mir::transform::{MirMapPass, MirPassHook, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::*;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Subst,Substs};
use rustc::util::nodemap::{DefIdSet};
use std::collections::VecDeque;
use super::simplify::{remove_dead_blocks, CfgSimplifier};
use syntax::{attr};
use syntax::abi::Abi;
use callgraph;
const DEFAULT_THRESHOLD: usize = 50;
const HINT_THRESHOLD: usize = 100;
@@ -42,135 +38,65 @@
pub struct Inline;
impl<'tcx> MirMapPass<'tcx> for Inline {
fn run_pass<'a>(
&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>]) {
if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; }
let _ignore = tcx.dep_graph.in_ignore();
let callgraph = callgraph::CallGraph::build(tcx);
let mut inliner = Inliner {
tcx: tcx,
};
let def_ids = tcx.maps.mir.borrow().keys();
for &def_id in &def_ids {
if !def_id.is_local() { continue; }
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let mut mir = if let Some(mir) = tcx.maps.mir.borrow().get(&def_id) {
mir.borrow_mut()
} else {
continue;
};
tcx.dep_graph.write(DepNode::Mir(def_id));
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, &mut mir, self, false);
}
}
for scc in callgraph.scc_iter() {
inliner.inline_scc(&callgraph, &scc);
}
for def_id in def_ids {
if !def_id.is_local() { continue; }
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let mut mir = tcx.maps.mir.borrow()[&def_id].borrow_mut();
tcx.dep_graph.write(DepNode::Mir(def_id));
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, &mut mir, self, true);
}
}
}
}
impl<'tcx> Pass for Inline { }
struct Inliner<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
#[derive(Copy, Clone)]
struct CallSite<'tcx> {
caller: DefId,
callee: DefId,
substs: &'tcx Substs<'tcx>,
bb: BasicBlock,
location: SourceInfo,
}
impl<'a, 'tcx> Inliner<'a, 'tcx> {
fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool {
let mut callsites = Vec::new();
let mut in_scc = DefIdSet();
let mut inlined_into = DefIdSet();
for &node in scc {
let def_id = callgraph.def_id(node);
// Don't inspect functions from other crates
let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
id
} else {
continue;
};
let src = MirSource::from_node(self.tcx, id);
if let MirSource::Fn(_) = src {
if let Some(mir) = self.tcx.maybe_item_mir(def_id) {
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
// Don't inline calls that are in cleanup blocks.
if bb_data.is_cleanup { continue; }
// Only consider direct calls to functions
let terminator = bb_data.terminator();
if let TerminatorKind::Call {
func: Operand::Constant(ref f), .. } = terminator.kind {
if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
callsites.push(CallSite {
caller: def_id,
callee: callee_def_id,
substs: substs,
bb: bb,
location: terminator.source_info
});
}
}
}
in_scc.insert(def_id);
}
}
impl MirPass for Inline {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
Inliner { tcx, source }.run_pass(mir);
}
}
}
// Move callsites that are in the the SCC to the end so
// they're inlined after calls to outside the SCC
let mut first_call_in_scc = callsites.len();
struct Inliner<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
}
let mut i = 0;
while i < first_call_in_scc {
let f = callsites[i].caller;
if in_scc.contains(&f) {
first_call_in_scc -= 1;
callsites.swap(i, first_call_in_scc);
} else {
i += 1;
impl<'a, 'tcx> Inliner<'a, 'tcx> {
fn run_pass(&self, caller_mir: &mut Mir<'tcx>) {
// Keep a queue of callsites to try inlining on. We take
// advantage of the fact that queries detect cycles here to
// allow us to try and fetch the fully optimized MIR of a
// call; if it succeeds, we can inline it and we know that
// they do not call us. Otherwise, we just don't try to
// inline.
//
// We use a queue so that we inline "broadly" before we inline
// in depth. It is unclear if this is the best heuristic,
// really, but that's true of all the heuristics in this
// file. =)
let mut callsites = VecDeque::new();
// Only do inlining into fn bodies.
if let MirSource::Fn(_) = self.source {
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() {
// Don't inline calls that are in cleanup blocks.
if bb_data.is_cleanup { continue; }
// Only consider direct calls to functions
let terminator = bb_data.terminator();
if let TerminatorKind::Call {
func: Operand::Constant(ref f), .. } = terminator.kind {
if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
callsites.push_back(CallSite {
callee: callee_def_id,
substs: substs,
bb: bb,
location: terminator.source_info
});
}
}
}
}
@@ -179,41 +105,27 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
loop {
local_change = false;
let mut csi = 0;
while csi < callsites.len() {
let callsite = callsites[csi];
csi += 1;
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
self.tcx.dep_graph.write(DepNode::Mir(callsite.caller));
let callee_mir = {
if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) {
if !self.should_inline(callsite, &callee_mir) {
continue;
}
while let Some(callsite) = callsites.pop_front() {
if !self.tcx.is_mir_available(callsite.callee) {
continue;
}
let callee_mir = match ty::queries::optimized_mir::try_get(self.tcx,
callsite.location.span,
callsite.callee) {
Ok(ref callee_mir) if self.should_inline(callsite, callee_mir) => {
callee_mir.subst(self.tcx, callsite.substs)
} else {
continue;
}
};
let mut caller_mir = {
let map = self.tcx.maps.mir.borrow();
let mir = map.get(&callsite.caller).unwrap();
mir.borrow_mut()
_ => continue,
};
let start = caller_mir.basic_blocks().len();
if !self.inline_call(callsite, &mut caller_mir, callee_mir) {
if !self.inline_call(callsite, caller_mir, callee_mir) {
continue;
}
inlined_into.insert(callsite.caller);
// Add callsites from inlined function
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) {
// Only consider direct calls to functions
@@ -223,8 +135,7 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
// Don't inline the same function multiple times.
if callsite.callee != callee_def_id {
callsites.push(CallSite {
caller: callsite.caller,
callsites.push_back(CallSite {
callee: callee_def_id,
substs: substs,
bb: bb,
@@ -235,13 +146,6 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
}
}
csi -= 1;
if scc.len() == 1 {
callsites.swap_remove(csi);
} else {
callsites.remove(csi);
}
local_change = true;
changed = true;
}
@@ -251,27 +155,19 @@ fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeInd
}
}
// Simplify functions we inlined into.
for def_id in inlined_into {
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id));
self.tcx.dep_graph.write(DepNode::Mir(def_id));
let mut caller_mir = {
let map = self.tcx.maps.mir.borrow();
let mir = map.get(&def_id).unwrap();
mir.borrow_mut()
};
debug!("Running simplify cfg on {:?}", def_id);
CfgSimplifier::new(&mut caller_mir).simplify();
remove_dead_blocks(&mut caller_mir);
// Simplify if we inlined anything.
if changed {
debug!("Running simplify cfg on {:?}", self.source);
CfgSimplifier::new(caller_mir).simplify();
remove_dead_blocks(caller_mir);
}
changed
}
fn should_inline(&self, callsite: CallSite<'tcx>,
callee_mir: &'a Mir<'tcx>) -> bool {
fn should_inline(&self,
callsite: CallSite<'tcx>,
callee_mir: &Mir<'tcx>)
-> bool
{
let tcx = self.tcx;
// Don't inline closures that have captures
@@ -323,8 +219,7 @@ fn should_inline(&self, callsite: CallSite<'tcx>,
// FIXME: Give a bonus to functions with only a single caller
let id = tcx.hir.as_local_node_id(callsite.caller).expect("Caller not local");
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let param_env = ty::ParameterEnvironment::for_item(tcx, self.source.item_id());
let mut first_block = true;
let mut cost = 0;
@@ -423,22 +318,15 @@ fn should_inline(&self, callsite: CallSite<'tcx>,
}
}
fn inline_call(&self, callsite: CallSite<'tcx>,
caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool {
// Don't inline a function into itself
if callsite.caller == callsite.callee { return false; }
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
fn inline_call(&self,
callsite: CallSite<'tcx>,
caller_mir: &mut Mir<'tcx>,
mut callee_mir: Mir<'tcx>) -> bool {
let terminator = caller_mir[callsite.bb].terminator.take().unwrap();
match terminator.kind {
// FIXME: Handle inlining of diverging calls
TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller);
debug!("Inlined {:?} into {:?}", callsite.callee, self.source);
let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn();
+16 -24
View File
@@ -11,32 +11,20 @@
//! Performs various peephole optimizations.
use rustc::mir::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::{MutVisitor, Visitor};
use rustc::ty::TyCtxt;
use rustc::util::nodemap::FxHashSet;
use rustc_data_structures::indexed_vec::Idx;
use std::mem;
pub struct InstCombine {
optimizations: OptimizationList,
}
pub struct InstCombine;
impl InstCombine {
pub fn new() -> InstCombine {
InstCombine {
optimizations: OptimizationList::default(),
}
}
}
impl Pass for InstCombine {}
impl<'tcx> MirPass<'tcx> for InstCombine {
fn run_pass<'a>(&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
impl MirPass for InstCombine {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
// We only run when optimizing MIR (at any level).
if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
return
@@ -45,18 +33,22 @@ fn run_pass<'a>(&mut self,
// First, find optimization opportunities. This is done in a pre-pass to keep the MIR
// read-only so that we can do global analyses on the MIR in the process (e.g.
// `Lvalue::ty()`).
{
let optimizations = {
let mut optimization_finder = OptimizationFinder::new(mir, tcx);
optimization_finder.visit_mir(mir);
self.optimizations = optimization_finder.optimizations
}
optimization_finder.optimizations
};
// Then carry out those optimizations.
MutVisitor::visit_mir(&mut *self, mir);
MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir);
}
}
impl<'tcx> MutVisitor<'tcx> for InstCombine {
pub struct InstCombineVisitor {
optimizations: OptimizationList,
}
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor {
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
if self.optimizations.and_stars.remove(&location) {
debug!("Replacing `&*`: {:?}", rvalue);
+127
View File
@@ -8,6 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use build;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::Mir;
use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource,
MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED};
use rustc::ty::{self, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
use std::rc::Rc;
use syntax::ast;
use syntax_pos::{DUMMY_SP, Span};
use transform;
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
@@ -21,3 +37,114 @@
pub mod instcombine;
pub mod copy_prop;
pub mod inline;
pub(crate) fn provide(providers: &mut Providers) {
self::qualify_consts::provide(providers);
*providers = Providers {
mir_keys,
mir_const,
mir_validated,
optimized_mir,
is_mir_available,
..*providers
};
}
fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
tcx.mir_keys(def_id.krate).contains(&def_id)
}
/// Finds the full set of def-ids within the current crate that have
/// MIR associated with them.
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
-> Rc<DefIdSet> {
assert_eq!(krate, LOCAL_CRATE);
let mut set = DefIdSet();
// All body-owners have MIR associated with them.
set.extend(tcx.body_owners());
// Additionally, tuple struct/variant constructors have MIR, but
// they don't have a BodyId, so we need to build them separately.
struct GatherCtors<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
set: &'a mut DefIdSet,
}
impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
fn visit_variant_data(&mut self,
v: &'tcx hir::VariantData,
_: ast::Name,
_: &'tcx hir::Generics,
_: ast::NodeId,
_: Span) {
if let hir::VariantData::Tuple(_, node_id) = *v {
self.set.insert(self.tcx.hir.local_def_id(node_id));
}
intravisit::walk_struct_def(self, v)
}
fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
NestedVisitorMap::None
}
}
tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
tcx: tcx,
set: &mut set,
}.as_deep_visitor());
Rc::new(set)
}
fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
let mut mir = build::mir_build(tcx, def_id);
let source = MirSource::from_local_def_id(tcx, def_id);
transform::run_suite(tcx, source, MIR_CONST, &mut mir);
tcx.alloc_steal_mir(mir)
}
fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
let source = MirSource::from_local_def_id(tcx, def_id);
if let MirSource::Const(_) = source {
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result. We don't
// directly need the result or `mir_const_qualif`, so we can just force it.
ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, def_id);
}
let mut mir = tcx.mir_const(def_id).steal();
transform::run_suite(tcx, source, MIR_VALIDATED, &mut mir);
tcx.alloc_steal_mir(mir)
}
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
// Borrowck uses `mir_validated`, so we have to force it to
// execute before we can steal.
ty::queries::borrowck::force(tcx, DUMMY_SP, def_id);
let mut mir = tcx.mir_validated(def_id).steal();
let source = MirSource::from_local_def_id(tcx, def_id);
transform::run_suite(tcx, source, MIR_OPTIMIZED, &mut mir);
tcx.alloc_mir(mir)
}
fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
suite: MirSuite,
mir: &mut Mir<'tcx>)
{
let passes = tcx.mir_passes.passes(suite);
for (pass, index) in passes.iter().zip(0..) {
let pass_num = MirPassIndex(index);
for hook in tcx.mir_passes.hooks() {
hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false);
}
pass.run_pass(tcx, source, mir);
for hook in tcx.mir_passes.hooks() {
hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true);
}
}
}
+16 -16
View File
@@ -14,10 +14,25 @@
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::{Pass, MirPass, MirSource};
use rustc::mir::transform::{MirPass, MirSource};
pub struct NoLandingPads;
impl MirPass for NoLandingPads {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
no_landing_pads(tcx, mir)
}
}
pub fn no_landing_pads<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) {
if tcx.sess.no_landing_pads() {
NoLandingPads.visit_mir(mir);
}
}
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
fn visit_terminator(&mut self,
bb: BasicBlock,
@@ -41,18 +56,3 @@ fn visit_terminator(&mut self,
self.super_terminator(bb, terminator, location);
}
}
pub fn no_landing_pads<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) {
if tcx.sess.no_landing_pads() {
NoLandingPads.visit_mir(mir);
}
}
impl<'tcx> MirPass<'tcx> for NoLandingPads {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource, mir: &mut Mir<'tcx>) {
no_landing_pads(tcx, mir)
}
}
impl Pass for NoLandingPads {}
+19 -46
View File
@@ -16,7 +16,6 @@
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
@@ -27,7 +26,7 @@
use rustc::ty::maps::Providers;
use rustc::mir::*;
use rustc::mir::traversal::ReversePostorder;
use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc::middle::lang_items;
use syntax::abi::Abi;
@@ -919,13 +918,21 @@ fn visit_terminator(&mut self,
}
pub fn provide(providers: &mut Providers) {
providers.mir_const_qualif = qualify_const_item;
*providers = Providers {
mir_const_qualif,
..*providers
};
}
fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> u8 {
let mir = &tcx.item_mir(def_id);
fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> u8 {
// NB: This `borrow()` is guaranteed to be valid (i.e., the value
// cannot yet be stolen), because `mir_validated()`, which steals
// from `mir_const(), forces this query to execute before
// performing the steal.
let mir = &tcx.mir_const(def_id).borrow();
if mir.return_ty.references_error() {
return Qualif::NOT_CONST.bits();
}
@@ -939,45 +946,11 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub struct QualifyAndPromoteConstants;
impl Pass for QualifyAndPromoteConstants {}
impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
fn run_pass<'a>(&mut self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>])
{
let def_ids = tcx.maps.mir.borrow().keys();
for def_id in def_ids {
if !def_id.is_local() {
continue;
}
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let src = MirSource::from_node(tcx, id);
if let MirSource::Const(_) = src {
tcx.mir_const_qualif(def_id);
continue;
}
let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
tcx.dep_graph.write(DepNode::Mir(def_id));
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, false);
}
self.run_pass(tcx, src, mir);
for hook in &mut *hooks {
hook.on_mir_pass(tcx, src, mir, self, true);
}
}
}
}
impl<'tcx> QualifyAndPromoteConstants {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for QualifyAndPromoteConstants {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &mut Mir<'tcx>) {
let id = src.item_id();
let def_id = tcx.hir.local_def_id(id);
let mode = match src {
+20 -23
View File
@@ -41,15 +41,15 @@
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::{MutVisitor, Visitor, LvalueContext};
use std::fmt;
use std::borrow::Cow;
pub struct SimplifyCfg<'a> { label: &'a str }
pub struct SimplifyCfg { label: String }
impl<'a> SimplifyCfg<'a> {
pub fn new(label: &'a str) -> Self {
SimplifyCfg { label: label }
impl SimplifyCfg {
pub fn new(label: &str) -> Self {
SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
}
}
@@ -61,22 +61,20 @@ pub fn simplify_cfg(mir: &mut Mir) {
mir.basic_blocks_mut().raw.shrink_to_fit();
}
impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> {
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for SimplifyCfg {
fn name<'a>(&'a self) -> Cow<'a, str> {
Cow::Borrowed(&self.label)
}
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir);
simplify_cfg(mir);
}
}
impl<'l> Pass for SimplifyCfg<'l> {
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> {
Some(Box::new(self.label))
}
// avoid calling `type_name` - it contains `<'static>`
fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyCfg".into() }
}
pub struct CfgSimplifier<'a, 'tcx: 'a> {
basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
pred_count: IndexVec<BasicBlock, u32>
@@ -315,12 +313,11 @@ pub fn remove_dead_blocks(mir: &mut Mir) {
pub struct SimplifyLocals;
impl Pass for SimplifyLocals {
fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyLocals".into() }
}
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for SimplifyLocals {
fn run_pass<'a, 'tcx>(&self,
_: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) };
marker.visit_mir(mir);
// Return pointer and arguments are always live
+15 -16
View File
@@ -12,21 +12,28 @@
use rustc::ty::TyCtxt;
use rustc::middle::const_val::ConstVal;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::*;
use std::fmt;
use std::borrow::Cow;
pub struct SimplifyBranches<'a> { label: &'a str }
pub struct SimplifyBranches { label: String }
impl<'a> SimplifyBranches<'a> {
pub fn new(label: &'a str) -> Self {
SimplifyBranches { label: label }
impl SimplifyBranches {
pub fn new(label: &str) -> Self {
SimplifyBranches { label: format!("SimplifyBranches-{}", label) }
}
}
impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> {
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for SimplifyBranches {
fn name<'a>(&'a self) -> Cow<'a, str> {
Cow::Borrowed(&self.label)
}
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
for block in mir.basic_blocks_mut() {
let terminator = block.terminator_mut();
terminator.kind = match terminator.kind {
@@ -60,11 +67,3 @@ fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &
}
}
impl<'l> Pass for SimplifyBranches<'l> {
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> {
Some(Box::new(self.label))
}
// avoid calling `type_name` - it contains `<'static>`
fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyBranches".into() }
}
+6 -7
View File
@@ -18,7 +18,7 @@
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::tcx::LvalueTy;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::Visitor;
use std::fmt;
use syntax::ast;
@@ -737,9 +737,11 @@ pub fn new() -> Self {
}
}
impl<'tcx> MirPass<'tcx> for TypeckMir {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
impl MirPass for TypeckMir {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &mut Mir<'tcx>) {
let item_id = src.item_id();
let def_id = tcx.hir.local_def_id(item_id);
debug!("run_pass: {}", tcx.item_path_str(def_id));
@@ -765,6 +767,3 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
});
}
}
impl Pass for TypeckMir {
}
+9 -7
View File
@@ -18,16 +18,18 @@
use rustc_data_structures::indexed_vec::Idx;
use super::pretty::dump_mir_def_ids;
/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
iter: I,
w: &mut W)
-> io::Result<()>
where W: Write, I: Iterator<Item=DefId>
pub fn write_mir_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
single: Option<DefId>,
w: &mut W)
-> io::Result<()>
where W: Write
{
for def_id in iter {
for def_id in dump_mir_def_ids(tcx, single) {
let nodeid = tcx.hir.as_local_node_id(def_id).unwrap();
let mir = &tcx.item_mir(def_id);
let mir = &tcx.optimized_mir(def_id);
writeln!(w, "digraph Mir_{} {{", nodeid)?;
+1 -1
View File
@@ -15,6 +15,6 @@
mod graphviz;
mod pretty;
pub use self::pretty::{dump_mir, write_mir_pretty};
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
pub use self::graphviz::{write_mir_graphviz};
pub use self::graphviz::write_node_label as write_graphviz_node_label;
+69 -30
View File
@@ -9,9 +9,9 @@
// except according to those terms.
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::mir::transform::{MirSuite, MirPassIndex, MirSource};
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
@@ -28,7 +28,7 @@
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
@@ -39,64 +39,95 @@
/// that can appear in the pass-name or the `item_path_str` for the given
/// node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pass_num: Option<(MirSuite, MirPassIndex)>,
pass_name: &str,
disambiguator: &Display,
src: MirSource,
source: MirSource,
mir: &Mir<'tcx>) {
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
None => return,
Some(ref filters) => filters,
};
let node_id = src.item_id();
let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
let is_matched =
filters.split("&")
.any(|filter| {
filter == "all" ||
pass_name.contains(filter) ||
node_path.contains(filter)
});
if !is_matched {
if !dump_enabled(tcx, pass_name, source) {
return;
}
let promotion_id = match src {
let node_path = 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() {
let promoted_source = MirSource::Promoted(source.item_id(), index);
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
promoted_source, promoted_mir);
}
}
pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pass_name: &str,
source: MirSource)
-> bool {
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
None => return false,
Some(ref filters) => filters,
};
let node_id = source.item_id();
let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
filters.split("&")
.any(|filter| {
filter == "all" ||
pass_name.contains(filter) ||
node_path.contains(filter)
})
}
fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pass_num: Option<(MirSuite, MirPassIndex)>,
pass_name: &str,
node_path: &str,
disambiguator: &Display,
source: MirSource,
mir: &Mir<'tcx>) {
let promotion_id = match source {
MirSource::Promoted(_, id) => format!("-{:?}", id),
_ => String::new()
};
let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
format!("")
} else {
match pass_num {
None => format!(".-------"),
Some((suite, pass_num)) => format!(".{:03}-{:03}", suite.0, pass_num.0),
}
};
let mut file_path = PathBuf::new();
if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
let p = Path::new(file_dir);
file_path.push(p);
};
let file_name = format!("rustc.node{}{}.{}.{}.mir",
node_id, promotion_id, pass_name, disambiguator);
let file_name = format!("rustc.node{}{}{}.{}.{}.mir",
source.item_id(), promotion_id, pass_num, pass_name, disambiguator);
file_path.push(&file_name);
let _ = fs::File::create(&file_path).and_then(|mut file| {
writeln!(file, "// MIR for `{}`", node_path)?;
writeln!(file, "// node_id = {}", node_id)?;
writeln!(file, "// source = {:?}", source)?;
writeln!(file, "// pass_name = {}", pass_name)?;
writeln!(file, "// disambiguator = {}", disambiguator)?;
writeln!(file, "")?;
write_mir_fn(tcx, src, mir, &mut file)?;
write_mir_fn(tcx, source, mir, &mut file)?;
Ok(())
});
}
/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
iter: I,
w: &mut Write)
-> io::Result<()>
where I: Iterator<Item=DefId>, 'tcx: 'a
pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
single: Option<DefId>,
w: &mut Write)
-> io::Result<()>
{
writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;
let mut first = true;
for def_id in iter.filter(DefId::is_local) {
let mir = &tcx.item_mir(def_id);
for def_id in dump_mir_def_ids(tcx, single) {
let mir = &tcx.optimized_mir(def_id);
if first {
first = false;
@@ -312,3 +343,11 @@ fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
Ok(())
}
pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
if let Some(i) = single {
vec![i]
} else {
tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect()
}
}
+4 -4
View File
@@ -13,6 +13,7 @@
// completely accurate (some things might be counted twice, others missed).
use rustc_const_math::{ConstUsize};
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::middle::const_val::{ConstVal};
use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
use rustc::mir::{Constant, Literal, Location, LocalDecl};
@@ -44,10 +45,9 @@ pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) {
// For debugging instrumentation like this, we don't need to worry
// about maintaining the dep graph.
let _ignore = tcx.dep_graph.in_ignore();
let mir_map = tcx.maps.mir.borrow();
for def_id in mir_map.keys() {
let mir = mir_map.get(&def_id).unwrap();
collector.visit_mir(&mir.borrow());
for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
let mir = tcx.optimized_mir(def_id);
collector.visit_mir(&mir);
}
collector.print(title);
}
+1 -1
View File
@@ -659,7 +659,7 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan
// in this crate
false
} else {
if !tcx.is_item_mir_available(def_id) {
if !tcx.is_mir_available(def_id) {
bug!("Cannot create local trans-item for {:?}", def_id)
}
true
+2 -2
View File
@@ -640,9 +640,9 @@ pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> CompileResult {
debug_assert!(crate_num == LOCAL_CRATE);
tcx.sess.track_errors(|| {
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
for body_owner_def_id in tcx.body_owners() {
tcx.typeck_tables_of(body_owner_def_id);
});
}
})
}
+2 -2
View File
@@ -36,7 +36,7 @@ fn main() {
}
// END RUST SOURCE
// START rustc.node4.SimplifyCfg.initial-after.mir
// START rustc.node4.SimplifyCfg-initial.after.mir
// bb0: {
// StorageLive(_1);
// _1 = const false;
@@ -82,4 +82,4 @@ fn main() {
// StorageDead(_1);
// return;
// }
// END rustc.node4.SimplifyCfg.initial-after.mir
// END rustc.node4.SimplifyCfg-initial.after.mir
+2 -2
View File
@@ -21,7 +21,7 @@ fn main() {
}
// END RUST SOURCE
// START rustc.node4.SimplifyCfg.initial-after.mir
// START rustc.node4.SimplifyCfg-initial.after.mir
// bb0: {
// StorageLive(_1);
// _1 = const false;
@@ -48,4 +48,4 @@ fn main() {
// _2 = ();
// goto -> bb1;
// }
// END rustc.node4.SimplifyCfg.initial-after.mir
// END rustc.node4.SimplifyCfg-initial.after.mir
+4 -4
View File
@@ -15,13 +15,13 @@ fn main() {
}
// END RUST SOURCE
// START rustc.node4.SimplifyBranches.initial-before.mir
// START rustc.node4.SimplifyBranches-initial.before.mir
// bb0: {
// switchInt(const false) -> [0u8: bb2, otherwise: bb1];
// }
// END rustc.node4.SimplifyBranches.initial-before.mir
// START rustc.node4.SimplifyBranches.initial-after.mir
// END rustc.node4.SimplifyBranches-initial.before.mir
// START rustc.node4.SimplifyBranches-initial.after.mir
// bb0: {
// goto -> bb2;
// }
// END rustc.node4.SimplifyBranches.initial-after.mir
// END rustc.node4.SimplifyBranches-initial.after.mir
@@ -2,7 +2,10 @@ error[E0507]: cannot move out of indexed content
--> $DIR/issue-40402-1.rs:19:13
|
19 | let e = f.v[0];
| ^^^^^^ cannot move out of indexed content
| ^^^^^^
| |
| help: consider using a reference instead `&f.v[0]`
| cannot move out of indexed content
error: aborting due to previous error
+4 -6
View File
@@ -1402,18 +1402,16 @@ fn make_compile_args(&self,
}
}
MirOpt => {
args.extend(["-Z",
"dump-mir=all",
"-Z",
"mir-opt-level=3",
"-Z"]
args.extend(["-Zdump-mir=all",
"-Zmir-opt-level=3",
"-Zdump-mir-exclude-pass-number"]
.iter()
.map(|s| s.to_string()));
let mir_dump_dir = self.get_mir_dump_dir();
create_dir_all(mir_dump_dir.as_path()).unwrap();
let mut dir_opt = "dump-mir-dir=".to_string();
let mut dir_opt = "-Zdump-mir-dir=".to_string();
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
debug!("dir_opt: {:?}", dir_opt);