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
commit 146dc670cf
74 changed files with 1361 additions and 5529 deletions

View File

@ -1,4 +0,0 @@
verify
*.class
*.java
*.tokens

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
```

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 ;

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

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; }
%%

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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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.

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")

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
};

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(..)
);
}
}

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'
;

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'
;

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

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 @@ impl<D: Clone + Debug> DepNode<D> {
Variance => Some(Variance),
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
Reachability => Some(Reachability),
MirKeys => Some(MirKeys),
LateLintCheck => Some(LateLintCheck),
TransWriteMetadata => Some(TransWriteMetadata),
@ -258,6 +262,8 @@ impl<D: Clone + Debug> DepNode<D> {
}
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),
}
}
}

View File

@ -28,6 +28,5 @@ pub use self::graph::WorkProduct;
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;

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 () {
}

View File

@ -75,15 +75,3 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
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);
}
}

View File

@ -455,7 +455,7 @@ impl<'hir> Map<'hir> {
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 {

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;

View File

@ -38,7 +38,6 @@ use std::any::Any;
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")

View File

@ -636,7 +636,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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)
}
}
}

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`.

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};

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 @@ impl<'a, 'tcx> MirSource {
}
}
/// 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
}
}

View File

@ -1003,6 +1003,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"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],

View File

@ -21,7 +21,6 @@ use session::config::DebugInfoLevel;
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()),

View File

@ -25,6 +25,7 @@ use middle::region::{CodeExtent, CodeExtentData};
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::TypeVariants::*;
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 arena::{TypedArena, DroplessArena};
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 @@ impl<'tcx> 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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()),

View File

@ -16,22 +16,27 @@ use middle::const_val;
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 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
}
}
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 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
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 @@ impl<'tcx> QueryDescription for queries::def_span<'tcx> {
}
}
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 @@ impl<'tcx> QueryDescription for queries::const_is_rvalue_promotable_to_static<'t
}
}
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 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> {
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 @@ macro_rules! define_maps {
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 @@ macro_rules! define_maps {
})*
}
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 @@ define_maps! { <'tcx>
/// 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 @@ define_maps! { <'tcx>
/// 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
}

View File

@ -35,7 +35,7 @@ use util::common::ErrorReported;
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 _match;
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
/// 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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
src/librustc/ty/steal.rs Normal file
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")
}
}

View File

@ -13,7 +13,8 @@ use target::{Target, TargetOptions, TargetResult};
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 {

View File

@ -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(),

View File

@ -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 {

View File

@ -16,7 +16,7 @@ use super::{drop_flag_effects_for_location, on_lookup_result_bits};
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 @@ use std::u32;
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 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
}
}
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.

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 };

View File

@ -63,9 +63,9 @@ pub struct LoanDataFlowOperator;
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);

View File

@ -20,6 +20,7 @@ use rustc::session::search_paths::PathKind;
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_typeck as typeck;
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 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
// 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 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
"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",

View File

@ -41,7 +41,6 @@ use graphviz as dot;
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!(),
}?;
}

View File

@ -27,6 +27,7 @@ use rustc::infer::{self, InferOk, InferResult};
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,

View File

@ -30,7 +30,6 @@ use rustc::util::nodemap::{NodeSet, DefIdMap};
use rustc_back::PanicStrategy;
use std::any::Any;
use std::mem;
use std::rc::Rc;
use syntax::ast;
@ -95,16 +94,13 @@ provide! { <'tcx> tcx, def_id, cdata
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 @@ provide! { <'tcx> tcx, def_id, cdata
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 @@ provide! { <'tcx> tcx, def_id, cdata
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 @@ impl CrateStore for cstore::CStore {
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)

View File

@ -779,10 +779,10 @@ impl<'a, 'tcx> CrateMetadata {
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))),

View File

@ -295,7 +295,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
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 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
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 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
} else {
None
},
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@ -598,7 +598,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, '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 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
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 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
},
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 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
predicates: None,
ast: None,
mir: self.encode_mir(def_id),
mir: self.encode_optimized_mir(def_id),
}
}
@ -1187,7 +1192,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, '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),
}
}

View File

@ -18,7 +18,7 @@ use build::{BlockAnd, Builder};
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>,

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 @@ impl Idx for ScopeId {
/// 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();

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())
}
}
}

View File

@ -26,7 +26,7 @@ use rustc::middle::region::RegionMaps;
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 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, '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) }
}

View File

@ -46,18 +46,15 @@ extern crate rustc_const_eval;
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);
}

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
}
}

View File

@ -24,10 +24,8 @@ use syntax::abi::Abi;
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)]

View File

@ -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 @@ pub struct AddCallGuards;
*
*/
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 {}

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 @@ use transform::qualify_consts;
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

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);

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(())
}

View File

@ -16,7 +16,7 @@ use rustc::ty::subst::Substs;
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 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
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);
}
}

View File

@ -14,24 +14,20 @@ use rustc::hir::def_id::DefId;
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 @@ const UNKNOWN_SIZE_COST: usize = 10;
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
}
}
csi -= 1;
if scc.len() == 1 {
callsites.swap_remove(csi);
} else {
callsites.remove(csi);
}
local_change = true;
changed = true;
}
@ -251,27 +155,19 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
}
}
// 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 @@ impl<'a, 'tcx> Inliner<'a, '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 @@ impl<'a, 'tcx> Inliner<'a, '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();

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 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
// 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);

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 deaggregator;
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);
}
}
}

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 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
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 {}

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::cast::CastTy;
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 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}
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 {

View File

@ -41,15 +41,15 @@ use rustc_data_structures::bitvec::BitVector;
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

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 @@ impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> {
}
}
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() }
}

View File

@ -18,7 +18,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
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 @@ impl TypeckMir {
}
}
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 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
});
}
}
impl Pass for TypeckMir {
}

View File

@ -18,16 +18,18 @@ use syntax::ast::NodeId;
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)?;

View File

@ -15,6 +15,6 @@ pub mod patch;
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;

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 @@ const ALIGN: usize = 40;
/// 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 @@ const ALIGN: usize = 40;
/// 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()
}
}

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);
}

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

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);
});
}
})
}

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

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

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

View File

@ -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

View File

@ -1402,18 +1402,16 @@ actual:\n\
}
}
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);