mirror of https://github.com/rust-lang/rust.git
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:
commit
146dc670cf
|
@ -1,4 +0,0 @@
|
|||
verify
|
||||
*.class
|
||||
*.java
|
||||
*.tokens
|
|
@ -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
|
||||
```
|
|
@ -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 ;
|
|
@ -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
|
|
@ -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; }
|
||||
|
||||
%%
|
|
@ -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
|
@ -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.
|
|
@ -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")
|
|
@ -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
|
||||
};
|
|
@ -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(¬_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(..)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
;
|
|
@ -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'
|
||||
;
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 () {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::mem;
|
||||
|
||||
/// The `Steal` struct is intended to used as the value for a query.
|
||||
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
|
||||
/// where we create a large, complex value that we want to iteratively
|
||||
/// update (e.g., optimize). We could clone the value for each
|
||||
/// optimization, but that'd be expensive. And yet we don't just want
|
||||
/// to mutate it in place, because that would spoil the idea that
|
||||
/// queries are these pure functions that produce an immutable value
|
||||
/// (since if you did the query twice, you could observe the
|
||||
/// mutations). So instead we have the query produce a `&'tcx
|
||||
/// Steal<Mir<'tcx>>` (to be very specific). Now we can read from this
|
||||
/// as much as we want (using `borrow()`), but you can also
|
||||
/// `steal()`. Once you steal, any further attempt to read will panic.
|
||||
/// Therefore we know that -- assuming no ICE -- nobody is observing
|
||||
/// the fact that the MIR was updated.
|
||||
///
|
||||
/// Obviously, whenever you have a query that yields a `Steal` value,
|
||||
/// you must treat it with caution, and make sure that you know that
|
||||
/// -- once the value is stolen -- it will never be read from again.
|
||||
///
|
||||
/// FIXME(#41710) -- what is the best way to model linear queries?
|
||||
pub struct Steal<T> {
|
||||
value: RefCell<Option<T>>
|
||||
}
|
||||
|
||||
impl<T> Steal<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Steal {
|
||||
value: RefCell::new(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow(&self) -> Ref<T> {
|
||||
Ref::map(self.value.borrow(), |opt| match *opt {
|
||||
None => bug!("attempted to read from stolen value"),
|
||||
Some(ref v) => v
|
||||
})
|
||||
}
|
||||
|
||||
pub fn steal(&self) -> T {
|
||||
let value_ref = &mut *self.value.borrow_mut();
|
||||
let value = mem::replace(value_ref, None);
|
||||
value.expect("attempt to read from stolen value")
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@ 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 {
|
||||
|
|
|
@ -18,6 +18,8 @@ pub fn target() -> TargetResult {
|
|||
let mut base = super::android_base::opts();
|
||||
base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.pre_link_args
|
||||
.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-none-linux-android".to_string(),
|
||||
|
|
|
@ -73,9 +73,16 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec<Move
|
|||
let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
|
||||
let mut is_first_note = true;
|
||||
match error.move_to_places.get(0) {
|
||||
Some(&MovePlace { pat_source: PatternSource::LetDecl(_), .. }) => {
|
||||
Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => {
|
||||
// ignore patterns that are found at the top-level of a `let`;
|
||||
// see `get_pattern_source()` for details
|
||||
let initializer =
|
||||
e.init.as_ref().expect("should have an initializer to get an error");
|
||||
if let Ok(snippet) = bccx.tcx.sess.codemap().span_to_snippet(initializer.span) {
|
||||
err.span_suggestion(initializer.span,
|
||||
"consider using a reference instead",
|
||||
format!("&{}", snippet));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
for move_to in &error.move_to_places {
|
||||
|
|
|
@ -16,7 +16,7 @@ use super::{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.
|
||||
|
|
|
@ -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, ¶m_env);
|
||||
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 you’re 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",
|
||||
|
|
|
@ -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!(),
|
||||
}?;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)]
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,13 +15,13 @@ fn main() {
|
|||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.node4.SimplifyBranches.initial-before.mir
|
||||
// START rustc.node4.SimplifyBranches-initial.before.mir
|
||||
// bb0: {
|
||||
// switchInt(const false) -> [0u8: bb2, otherwise: bb1];
|
||||
// }
|
||||
// END rustc.node4.SimplifyBranches.initial-before.mir
|
||||
// START rustc.node4.SimplifyBranches.initial-after.mir
|
||||
// END rustc.node4.SimplifyBranches-initial.before.mir
|
||||
// START rustc.node4.SimplifyBranches-initial.after.mir
|
||||
// bb0: {
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// END rustc.node4.SimplifyBranches.initial-after.mir
|
||||
// END rustc.node4.SimplifyBranches-initial.after.mir
|
||||
|
|
|
@ -2,7 +2,10 @@ error[E0507]: cannot move out of indexed content
|
|||
--> $DIR/issue-40402-1.rs:19:13
|
||||
|
|
||||
19 | let e = f.v[0];
|
||||
| ^^^^^^ cannot move out of indexed content
|
||||
| ^^^^^^
|
||||
| |
|
||||
| help: consider using a reference instead `&f.v[0]`
|
||||
| cannot move out of indexed content
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue