2011-12-20 07:55:15 +01:00
import std ::{ fs , io } ;
2012-01-11 15:15:54 +01:00
import io ::writer_util ;
2011-05-20 21:06:05 -04:00
2011-09-19 21:57:43 -07:00
import rustc ::syntax ::{ ast , ast_util , fold , visit , codemap } ;
2011-07-12 11:49:04 -07:00
import rustc ::syntax ::parse ::parser ;
2011-07-10 16:03:01 -07:00
import rustc ::syntax ::print ::pprust ;
2012-01-13 17:33:16 -08:00
import rustc ::driver ::diagnostic ;
2011-07-10 16:03:01 -07:00
2012-01-19 18:46:53 -08:00
enum test_mode { tm_converge , tm_run , }
2011-09-23 23:23:04 -07:00
type context = { mode : test_mode } ; // + rng
2011-09-12 11:27:30 +02:00
fn write_file ( filename : str , content : str ) {
2011-10-28 21:19:59 -07:00
result ::get (
io ::file_writer ( filename , [ io ::create , io ::truncate ] ) )
. write_str ( content ) ;
2011-07-13 17:12:38 -07:00
}
2011-09-12 11:27:30 +02:00
fn contains ( haystack : str , needle : str ) -> bool {
2011-09-01 17:27:58 -07:00
str ::find ( haystack , needle ) ! = - 1
2011-07-27 14:19:39 +02:00
}
2011-07-12 11:49:04 -07:00
2011-09-12 12:39:38 +02:00
fn find_rust_files ( & files : [ str ] , path : str ) {
2012-01-08 19:24:24 -08:00
if str ::ends_with ( path , " .rs " ) & & ! contains ( path , " utf8 " ) {
// ignoring "utf8" tests: https://github.com/graydon/rust/pull/1470 ?
2011-09-23 23:23:04 -07:00
files + = [ path ] ;
2011-12-16 17:32:09 -05:00
} else if fs ::path_is_dir ( path )
2011-09-23 23:23:04 -07:00
& & ! contains ( path , " compile-fail " )
& & ! contains ( path , " build " ) {
2011-08-31 15:09:08 -07:00
for p in fs ::list_dir ( path ) {
find_rust_files ( files , p ) ;
2011-08-24 16:00:26 -07:00
}
2011-07-10 16:03:01 -07:00
}
}
2011-09-20 12:04:12 -07:00
fn common_exprs ( ) -> [ ast ::expr ] {
fn dse ( e : ast ::expr_ ) -> ast ::expr {
{ id : 0 , node : e , span : ast_util ::dummy_sp ( ) }
}
fn dsl ( l : ast ::lit_ ) -> ast ::lit {
{ node : l , span : ast_util ::dummy_sp ( ) }
}
[ dse ( ast ::expr_break ) ,
dse ( ast ::expr_cont ) ,
dse ( ast ::expr_fail ( option ::none ) ) ,
dse ( ast ::expr_fail ( option ::some ( @ dse ( ast ::expr_lit ( @ dsl ( ast ::lit_str ( " boo " ) ) ) ) ) ) ) ,
dse ( ast ::expr_ret ( option ::none ) ) ,
dse ( ast ::expr_lit ( @ dsl ( ast ::lit_nil ) ) ) ,
dse ( ast ::expr_lit ( @ dsl ( ast ::lit_bool ( false ) ) ) ) ,
2011-09-20 16:32:27 -07:00
dse ( ast ::expr_lit ( @ dsl ( ast ::lit_bool ( true ) ) ) ) ,
2011-09-23 23:23:04 -07:00
dse ( ast ::expr_unary ( ast ::box ( ast ::imm ) , @ dse ( ast ::expr_lit ( @ dsl ( ast ::lit_bool ( true ) ) ) ) ) ) ,
dse ( ast ::expr_unary ( ast ::uniq ( ast ::imm ) , @ dse ( ast ::expr_lit ( @ dsl ( ast ::lit_bool ( true ) ) ) ) ) )
2011-09-20 12:04:12 -07:00
]
}
2011-09-23 23:23:04 -07:00
pure fn safe_to_steal_expr ( e : @ ast ::expr , tm : test_mode ) -> bool {
safe_to_use_expr ( * e , tm )
}
2011-07-27 14:19:39 +02:00
2011-09-23 23:23:04 -07:00
pure fn safe_to_use_expr ( e : ast ::expr , tm : test_mode ) -> bool {
alt tm {
2012-01-18 22:37:22 -08:00
tm_converge {
2011-09-23 23:23:04 -07:00
alt e . node {
// If the fuzzer moves a block-ending-in-semicolon into callee position,
// the pretty-printer can't preserve this even by parenthesizing!!
// See email to marijn.
ast ::expr_if ( _ , _ , _ ) { false }
ast ::expr_if_check ( _ , _ , _ ) { false }
ast ::expr_block ( _ ) { false }
ast ::expr_alt ( _ , _ ) { false }
ast ::expr_for ( _ , _ , _ ) { false }
ast ::expr_while ( _ , _ ) { false }
2011-09-09 22:31:26 -07:00
2011-09-23 23:23:04 -07:00
// https://github.com/graydon/rust/issues/955
ast ::expr_do_while ( _ , _ ) { false }
2011-08-19 15:16:48 -07:00
2011-09-23 23:23:04 -07:00
// https://github.com/graydon/rust/issues/929
ast ::expr_cast ( _ , _ ) { false }
ast ::expr_assert ( _ ) { false }
ast ::expr_binary ( _ , _ , _ ) { false }
ast ::expr_assign ( _ , _ ) { false }
ast ::expr_assign_op ( _ , _ , _ ) { false }
2011-07-27 14:19:39 +02:00
2012-01-18 22:37:22 -08:00
ast ::expr_fail ( option ::none ) { false }
ast ::expr_ret ( option ::none ) { false }
2011-09-16 10:44:58 -07:00
2011-09-23 23:23:04 -07:00
// https://github.com/graydon/rust/issues/953
ast ::expr_fail ( option ::some ( _ ) ) { false }
2011-08-19 15:16:48 -07:00
2011-09-23 23:23:04 -07:00
// https://github.com/graydon/rust/issues/927
//ast::expr_assert(_) { false }
ast ::expr_check ( _ , _ ) { false }
// https://github.com/graydon/rust/issues/928
//ast::expr_cast(_, _) { false }
2012-01-08 19:24:24 -08:00
// https://github.com/graydon/rust/issues/1458
ast ::expr_call ( _ , _ , _ ) { false }
2011-09-23 23:23:04 -07:00
_ { true }
}
}
2012-01-18 22:37:22 -08:00
tm_run { true }
2011-07-12 11:49:04 -07:00
}
}
2011-09-23 23:23:04 -07:00
fn safe_to_steal_ty ( t : @ ast ::ty , tm : test_mode ) -> bool {
alt t . node {
// https://github.com/graydon/rust/issues/971
ast ::ty_constr ( _ , _ ) { false }
// Other restrictions happen to be the same.
_ { safe_to_replace_ty ( t . node , tm ) }
}
2011-09-10 18:55:09 -07:00
}
2011-09-10 14:51:33 -07:00
// Not type-parameterized: https://github.com/graydon/rust/issues/898
2012-01-12 15:38:44 -08:00
fn stash_expr_if ( c : fn @ ( @ ast ::expr , test_mode ) ->bool ,
es : @ mutable [ ast ::expr ] ,
e : @ ast ::expr ,
tm : test_mode ) {
2011-09-23 23:23:04 -07:00
if c ( e , tm ) {
2011-09-10 14:51:33 -07:00
* es + = [ * e ] ;
} else { /* now my indices are wrong :( */ }
}
2012-01-12 15:38:44 -08:00
fn stash_ty_if ( c : fn @ ( @ ast ::ty , test_mode ) ->bool ,
es : @ mutable [ ast ::ty ] ,
e : @ ast ::ty ,
tm : test_mode ) {
2011-09-23 23:23:04 -07:00
if c ( e , tm ) {
2011-09-10 18:55:09 -07:00
* es + = [ * e ] ;
} else { /* now my indices are wrong :( */ }
}
type stolen_stuff = { exprs : [ ast ::expr ] , tys : [ ast ::ty ] } ;
2011-09-23 23:23:04 -07:00
fn steal ( crate : ast ::crate , tm : test_mode ) -> stolen_stuff {
2011-09-10 18:55:09 -07:00
let exprs = @ mutable [ ] ;
let tys = @ mutable [ ] ;
2011-09-10 14:51:33 -07:00
let v = visit ::mk_simple_visitor ( @ {
2011-09-23 23:23:04 -07:00
visit_expr : bind stash_expr_if ( safe_to_steal_expr , exprs , _ , tm ) ,
visit_ty : bind stash_ty_if ( safe_to_steal_ty , tys , _ , tm )
2011-09-10 14:51:33 -07:00
with * visit ::default_simple_visitor ( )
} ) ;
2011-09-10 18:55:09 -07:00
visit ::visit_crate ( crate , ( ) , v ) ;
{ exprs : * exprs , tys : * tys }
2011-07-10 16:03:01 -07:00
}
2012-01-08 19:24:24 -08:00
2011-09-23 23:23:04 -07:00
fn safe_to_replace_expr ( e : ast ::expr_ , _tm : test_mode ) -> bool {
2011-07-27 14:19:39 +02:00
alt e {
2012-01-08 19:24:24 -08:00
// https://github.com/graydon/rust/issues/652
2011-07-27 14:19:39 +02:00
ast ::expr_if ( _ , _ , _ ) { false }
ast ::expr_block ( _ ) { false }
2012-01-08 19:24:24 -08:00
// expr_call is also missing a constraint
ast ::expr_fn_block ( _ , _ ) { false }
2011-07-27 14:19:39 +02:00
_ { true }
2011-07-10 16:03:01 -07:00
}
}
2011-09-23 23:23:04 -07:00
fn safe_to_replace_ty ( t : ast ::ty_ , _tm : test_mode ) -> bool {
2011-09-10 18:55:09 -07:00
alt t {
2012-01-19 01:03:57 -08:00
ast ::ty_infer { false } // always implicit, always top level
2012-01-18 22:37:22 -08:00
ast ::ty_bot { false } // in source, can only appear as the out type of a function
2011-09-10 18:55:09 -07:00
ast ::ty_mac ( _ ) { false }
_ { true }
}
}
2011-07-10 16:03:01 -07:00
// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
2011-09-23 23:23:04 -07:00
fn replace_expr_in_crate ( crate : ast ::crate , i : uint , newexpr : ast ::expr , tm : test_mode ) ->
2011-07-27 14:19:39 +02:00
ast ::crate {
let j : @ mutable uint = @ mutable 0 u ;
2011-09-12 11:27:30 +02:00
fn fold_expr_rep ( j_ : @ mutable uint , i_ : uint , newexpr_ : ast ::expr_ ,
2011-09-23 23:23:04 -07:00
original : ast ::expr_ , fld : fold ::ast_fold , tm_ : test_mode ) ->
2011-07-27 14:19:39 +02:00
ast ::expr_ {
* j_ + = 1 u ;
2011-09-23 23:23:04 -07:00
if i_ + 1 u = = * j_ & & safe_to_replace_expr ( original , tm_ ) {
2011-07-27 14:19:39 +02:00
newexpr_
2011-09-16 10:44:58 -07:00
} else {
2012-01-08 19:24:24 -08:00
fold ::noop_fold_expr ( original , fld )
2011-09-16 10:44:58 -07:00
}
2011-07-10 16:03:01 -07:00
}
2011-07-27 14:19:39 +02:00
let afp =
2012-01-22 17:30:07 -07:00
{ fold_expr : fold ::wrap ( bind fold_expr_rep ( j , i , newexpr . node , _ , _ , tm ) )
2011-09-10 18:55:09 -07:00
with * fold ::default_ast_fold ( ) } ;
let af = fold ::make_fold ( afp ) ;
let crate2 : @ ast ::crate = @ af . fold_crate ( crate ) ;
* crate2
}
2011-09-19 21:57:43 -07:00
2011-09-10 18:55:09 -07:00
// Replace the |i|th ty (in fold order) of |crate| with |newty|.
2011-09-23 23:23:04 -07:00
fn replace_ty_in_crate ( crate : ast ::crate , i : uint , newty : ast ::ty , tm : test_mode ) ->
2011-09-10 18:55:09 -07:00
ast ::crate {
let j : @ mutable uint = @ mutable 0 u ;
2011-09-12 11:27:30 +02:00
fn fold_ty_rep ( j_ : @ mutable uint , i_ : uint , newty_ : ast ::ty_ ,
2011-09-23 23:23:04 -07:00
original : ast ::ty_ , fld : fold ::ast_fold , tm_ : test_mode ) ->
2011-09-10 18:55:09 -07:00
ast ::ty_ {
* j_ + = 1 u ;
2011-09-23 23:23:04 -07:00
if i_ + 1 u = = * j_ & & safe_to_replace_ty ( original , tm_ ) {
2011-09-10 18:55:09 -07:00
newty_
} else { fold ::noop_fold_ty ( original , fld ) }
}
let afp =
2012-01-22 17:30:07 -07:00
{ fold_ty : fold ::wrap ( bind fold_ty_rep ( j , i , newty . node , _ , _ , tm ) )
2011-07-27 14:19:39 +02:00
with * fold ::default_ast_fold ( ) } ;
let af = fold ::make_fold ( afp ) ;
let crate2 : @ ast ::crate = @ af . fold_crate ( crate ) ;
2011-07-10 16:03:01 -07:00
* crate2
}
2012-01-23 14:59:00 -08:00
fn under ( n : uint , it : fn ( uint ) ) {
2011-07-27 14:19:39 +02:00
let i : uint = 0 u ;
2011-10-21 13:14:28 +02:00
while i < n { it ( i ) ; i + = 1 u ; }
2011-07-27 14:19:39 +02:00
}
2011-07-10 16:03:01 -07:00
2012-01-11 15:15:54 +01:00
fn devnull ( ) -> io ::writer { io ::mem_buffer_writer ( io ::mk_mem_buffer ( ) ) }
2011-07-10 16:03:01 -07:00
2011-10-18 15:07:40 -07:00
fn as_str ( f : fn @ ( io ::writer ) ) -> str {
2012-01-11 15:15:54 +01:00
let buf = io ::mk_mem_buffer ( ) ;
f ( io ::mem_buffer_writer ( buf ) ) ;
io ::mem_buffer_str ( buf )
2011-07-25 17:10:00 -07:00
}
2011-07-12 11:49:04 -07:00
2011-09-12 11:27:30 +02:00
fn check_variants_of_ast ( crate : ast ::crate , codemap : codemap ::codemap ,
2011-09-23 23:23:04 -07:00
filename : str , cx : context ) {
let stolen = steal ( crate , cx . mode ) ;
2011-12-16 06:27:50 -08:00
let extra_exprs = vec ::filter ( common_exprs ( ) ,
bind safe_to_use_expr ( _ , cx . mode ) ) ;
2011-09-23 23:23:04 -07:00
check_variants_T ( crate , codemap , filename , " expr " , extra_exprs + stolen . exprs , pprust ::expr_to_str , replace_expr_in_crate , cx ) ;
check_variants_T ( crate , codemap , filename , " ty " , stolen . tys , pprust ::ty_to_str , replace_ty_in_crate , cx ) ;
2011-09-10 18:55:09 -07:00
}
2012-01-05 15:35:37 +01:00
fn check_variants_T < T : copy > (
2011-09-12 11:27:30 +02:00
crate : ast ::crate ,
codemap : codemap ::codemap ,
filename : str ,
thing_label : str ,
2011-09-10 18:55:09 -07:00
things : [ T ] ,
2012-01-12 15:38:44 -08:00
stringifier : fn @ ( @ T ) -> str ,
replacer : fn @ ( ast ::crate , uint , T , test_mode ) -> ast ::crate ,
2011-09-23 23:23:04 -07:00
cx : context
2011-09-10 18:55:09 -07:00
) {
2011-12-22 14:42:52 -08:00
#error ( " %s contains %u %s objects " , filename , vec ::len ( things ) , thing_label ) ;
2011-09-10 18:55:09 -07:00
let L = vec ::len ( things ) ;
if L < 100 u {
2012-01-05 17:11:34 +01:00
under ( math ::min ( L , 20 u ) ) { | i |
2011-12-22 17:53:53 -08:00
log ( error , " Replacing... # " + uint ::str ( i ) ) ;
2012-01-05 17:11:34 +01:00
under ( math ::min ( L , 30 u ) ) { | j |
2011-12-22 17:53:53 -08:00
log ( error , " With... " + stringifier ( @ things [ j ] ) ) ;
2011-09-23 23:23:04 -07:00
let crate2 = @ replacer ( crate , i , things [ j ] , cx . mode ) ;
2011-07-28 00:29:24 -07:00
// It would be best to test the *crate* for stability, but testing the
// string for stability is easier and ok for now.
2011-08-19 15:16:48 -07:00
let str3 =
2012-01-13 17:33:16 -08:00
as_str ( bind pprust ::print_crate (
codemap ,
2012-01-13 23:27:28 -08:00
diagnostic ::mk_handler ( codemap , none ) ,
2012-01-13 17:33:16 -08:00
crate2 ,
filename ,
io ::string_reader ( " " ) , _ ,
pprust ::no_ann ( ) ) ) ;
2011-09-23 23:23:04 -07:00
alt cx . mode {
2012-01-18 22:37:22 -08:00
tm_converge {
2011-09-23 23:23:04 -07:00
check_roundtrip_convergence ( str3 , 1 u ) ;
}
2012-01-18 22:37:22 -08:00
tm_run {
2011-09-23 23:23:04 -07:00
let file_label = #fmt ( " rusttmp/%s_%s_%u_%u " , last_part ( filename ) , thing_label , i , j ) ;
let safe_to_run = ! ( content_is_dangerous_to_run ( str3 ) | | has_raw_pointers ( * crate2 ) ) ;
check_whole_compiler ( str3 , file_label , safe_to_run ) ;
}
}
2011-10-21 14:12:12 +02:00
}
}
2011-05-20 21:06:05 -04:00
}
2011-07-08 02:16:46 -07:00
}
2011-05-20 21:06:05 -04:00
2011-09-12 11:27:30 +02:00
fn last_part ( filename : str ) -> str {
2011-09-10 00:51:07 -07:00
let ix = str ::rindex ( filename , 47 u8 /* ' / ' */ ) ;
assert ix > = 0 ;
str ::slice ( filename , ix as uint + 1 u , str ::byte_len ( filename ) - 3 u )
}
2012-01-19 18:46:53 -08:00
enum happiness { passed , cleanly_rejected ( str ) , known_bug ( str ) , failed ( str ) , }
2011-09-10 00:51:07 -07:00
2011-07-28 21:18:07 -07:00
// We'd find more bugs if we could take an AST here, but
// - that would find many "false positives" or unimportant bugs
// - that would be tricky, requiring use of tasks or serialization or randomness.
// This seems to find plenty of bugs as it is :)
2011-09-19 21:57:43 -07:00
fn check_whole_compiler ( code : str , suggested_filename_prefix : str , allow_running : bool ) {
let filename = suggested_filename_prefix + " .rs " ;
2011-07-28 21:18:07 -07:00
write_file ( filename , code ) ;
2011-09-19 21:57:43 -07:00
let compile_result = check_compiling ( filename ) ;
let run_result = alt ( compile_result , allow_running ) {
2012-01-18 22:37:22 -08:00
( passed , true ) { check_running ( suggested_filename_prefix ) }
2011-09-19 21:57:43 -07:00
( h , _ ) { h }
} ;
alt run_result {
2012-01-18 22:37:22 -08:00
passed | cleanly_rejected ( _ ) | known_bug ( _ ) {
2011-09-19 21:57:43 -07:00
removeIfExists ( suggested_filename_prefix ) ;
removeIfExists ( suggested_filename_prefix + " .rs " ) ;
removeDirIfExists ( suggested_filename_prefix + " .dSYM " ) ;
2011-09-10 00:51:07 -07:00
}
failed ( s ) {
2011-12-22 17:53:53 -08:00
log ( error , " check_whole_compiler failure: " + s ) ;
log ( error , " Saved as: " + filename ) ;
2011-09-10 00:51:07 -07:00
}
}
}
2011-09-19 21:57:43 -07:00
fn removeIfExists ( filename : str ) {
// So sketchy!
assert ! contains ( filename , " " ) ;
std ::run ::program_output ( " bash " , [ " -c " , " rm " + filename ] ) ;
}
fn removeDirIfExists ( filename : str ) {
// So sketchy!
assert ! contains ( filename , " " ) ;
std ::run ::program_output ( " bash " , [ " -c " , " rm -r " + filename ] ) ;
}
fn check_running ( exe_filename : str ) -> happiness {
let p = std ::run ::program_output ( " /Users/jruderman/scripts/timed_run_rust_program.py " , [ exe_filename ] ) ;
let comb = p . out + " \n " + p . err ;
if str ::byte_len ( comb ) > 1 u {
2011-12-22 17:53:53 -08:00
log ( error , " comb comb comb: " + comb ) ;
2011-09-19 21:57:43 -07:00
}
2012-01-08 19:24:24 -08:00
if contains ( comb , " Assertion failed: " ) {
2011-09-19 21:57:43 -07:00
failed ( " C++ assertion failure " )
2011-09-23 23:23:04 -07:00
} else if contains ( comb , " leaked memory in rust main loop " ) {
// might also use exit code 134
//failed("Leaked")
known_bug ( " https://github.com/graydon/rust/issues/910 " )
2011-09-20 12:04:12 -07:00
} else if contains ( comb , " src/rt/ " ) {
failed ( " Mentioned src/rt/ " )
2011-09-19 21:57:43 -07:00
} else if contains ( comb , " malloc " ) {
2012-01-08 19:24:24 -08:00
//failed("Mentioned malloc")
known_bug ( " https://github.com/graydon/rust/issues/1461 " )
2011-09-19 21:57:43 -07:00
} else {
alt p . status {
0 { passed }
100 { cleanly_rejected ( " running: explicit fail " ) }
101 | 247 { cleanly_rejected ( " running: timed out " ) }
2012-01-08 19:24:24 -08:00
245 | 246 | 138 | 252 { known_bug ( " https://github.com/graydon/rust/issues/1466 " ) }
2011-09-20 12:04:12 -07:00
136 | 248 { known_bug ( " SIGFPE - https://github.com/graydon/rust/issues/944 " ) }
rc { failed ( " Rust program ran but exited with status " + int ::str ( rc ) ) }
2011-09-19 21:57:43 -07:00
}
}
}
fn check_compiling ( filename : str ) -> happiness {
2011-09-10 00:51:07 -07:00
let p = std ::run ::program_output (
2012-01-08 19:24:24 -08:00
" /Users/jruderman/code/rust/build/x86_64-apple-darwin/stage1/bin/rustc " ,
[ filename ] ) ;
2011-08-19 15:16:48 -07:00
2011-12-22 14:42:52 -08:00
//#error("Status: %d", p.status);
2011-09-02 15:34:58 -07:00
if p . err ! = " " {
2011-09-23 23:23:04 -07:00
if contains ( p . err , " Ptr must be a pointer to Val type " ) {
known_bug ( " https://github.com/graydon/rust/issues/897 " )
2012-01-08 19:24:24 -08:00
} else if contains ( p . err , " Assertion failed: ((i >= FTy->getNumParams() || FTy->getParamType(i) == Args[i]->getType()) && \" Calling a function with a bad signature! \" ), function init " ) {
known_bug ( " https://github.com/graydon/rust/issues/1459 " )
2011-07-28 21:18:07 -07:00
} else {
2011-12-22 17:53:53 -08:00
log ( error , " Stderr: " + p . err ) ;
2011-09-10 00:51:07 -07:00
failed ( " Unfamiliar error message " )
2011-07-28 21:18:07 -07:00
}
2011-09-10 00:51:07 -07:00
} else if p . status = = 0 {
2011-09-19 21:57:43 -07:00
passed
2011-09-16 10:44:58 -07:00
} else if contains ( p . out , " Out of stack space, sorry " ) {
known_bug ( " Recursive types - https://github.com/graydon/rust/issues/742 " )
} else if contains ( p . out , " Assertion " ) & & contains ( p . out , " failed " ) {
2011-12-22 17:53:53 -08:00
log ( error , " Stdout: " + p . out ) ;
2011-09-16 10:44:58 -07:00
failed ( " Looks like an llvm assertion failure " )
2012-01-08 19:24:24 -08:00
} else if contains ( p . out , " upcall fail 'option none' " ) {
known_bug ( " https://github.com/graydon/rust/issues/1463 " )
} else if contains ( p . out , " upcall fail 'non-exhaustive match failure', ../src/comp/middle/typeck.rs:1554 " ) {
known_bug ( " https://github.com/graydon/rust/issues/1462 " )
} else if contains ( p . out , " upcall fail 'Assertion cx.fcx.llupvars.contains_key(did.node) failed' " ) {
known_bug ( " https://github.com/graydon/rust/issues/1467 " )
} else if contains ( p . out , " Taking the value of a method does not work yet (issue #435) " ) {
known_bug ( " https://github.com/graydon/rust/issues/435 " )
2011-09-16 10:44:58 -07:00
} else if contains ( p . out , " internal compiler error bit_num: asked for pred constraint, found an init constraint " ) {
known_bug ( " https://github.com/graydon/rust/issues/933 " )
2012-01-08 19:24:24 -08:00
} else if contains ( p . out , " internal compiler error " ) & & contains ( p . out , " called on non-fn type " ) {
known_bug ( " https://github.com/graydon/rust/issues/1460 " )
} else if contains ( p . out , " internal compiler error fail called with unsupported type _|_ " ) {
known_bug ( " https://github.com/graydon/rust/issues/1465 " )
2011-09-16 10:44:58 -07:00
} else if contains ( p . out , " internal compiler error unimplemented " ) {
known_bug ( " Something unimplemented " )
} else if contains ( p . out , " internal compiler error " ) {
2011-12-22 17:53:53 -08:00
log ( error , " Stdout: " + p . out ) ;
2011-09-16 10:44:58 -07:00
failed ( " internal compiler error " )
} else if contains ( p . out , " error: " ) {
2011-09-19 21:57:43 -07:00
cleanly_rejected ( " rejected with span_error " )
2011-09-10 00:51:07 -07:00
} else {
2011-12-22 17:53:53 -08:00
log ( error , p . status ) ;
log ( error , " !Stdout: " + p . out ) ;
2011-09-16 10:44:58 -07:00
failed ( " What happened? " )
2011-09-10 00:51:07 -07:00
}
2011-07-28 21:18:07 -07:00
}
2011-09-10 00:51:07 -07:00
2011-09-12 11:27:30 +02:00
fn parse_and_print ( code : str ) -> str {
2011-09-02 15:34:58 -07:00
let filename = " tmp.rs " ;
2012-01-13 17:33:16 -08:00
let cm = codemap ::new_codemap ( ) ;
let sess = @ {
cm : cm ,
mutable next_id : 0 ,
2012-01-22 17:24:55 -07:00
diagnostic : diagnostic ::mk_handler ( cm , none ) ,
mutable chpos : 0 u ,
mutable byte_pos : 0 u
2012-01-13 17:33:16 -08:00
} ;
2011-09-23 23:23:04 -07:00
write_file ( filename , code ) ;
2011-08-27 00:43:22 -07:00
let crate = parser ::parse_crate_from_source_str (
2011-08-31 15:09:08 -07:00
filename , code , [ ] , sess ) ;
2012-01-13 17:33:16 -08:00
ret as_str ( bind pprust ::print_crate ( sess . cm ,
sess . diagnostic ,
crate ,
2011-08-31 15:09:08 -07:00
filename ,
io ::string_reader ( code ) , _ ,
2011-07-27 14:19:39 +02:00
pprust ::no_ann ( ) ) ) ;
2011-07-25 17:10:00 -07:00
}
2011-09-19 21:57:43 -07:00
fn has_raw_pointers ( c : ast ::crate ) -> bool {
let has_rp = @ mutable false ;
fn visit_ty ( flag : @ mutable bool , t : @ ast ::ty ) {
alt t . node {
ast ::ty_ptr ( _ ) { * flag = true ; }
_ { }
}
}
let v =
visit ::mk_simple_visitor ( @ { visit_ty : bind visit_ty ( has_rp , _ )
with * visit ::default_simple_visitor ( ) } ) ;
visit ::visit_crate ( c , ( ) , v ) ;
ret * has_rp ;
}
fn content_is_dangerous_to_run ( code : str ) -> bool {
let dangerous_patterns =
2011-09-23 23:23:04 -07:00
[ " xfail-test " ,
" -> ! " , // https://github.com/graydon/rust/issues/897
" import " , // espeically fs, run
2011-09-19 21:57:43 -07:00
" native " ,
2011-09-20 12:04:12 -07:00
" unsafe " ,
2011-09-23 23:23:04 -07:00
" log " ] ; // python --> rust pipe deadlock?
2011-09-19 21:57:43 -07:00
for p : str in dangerous_patterns { if contains ( code , p ) { ret true ; } }
ret false ;
}
2011-09-23 23:23:04 -07:00
fn content_is_dangerous_to_compile ( code : str ) -> bool {
2011-08-19 15:16:48 -07:00
let dangerous_patterns =
2011-09-23 23:23:04 -07:00
[ " xfail-test " ,
" -> ! " , // https://github.com/graydon/rust/issues/897
2012-01-19 16:21:33 -08:00
" enum " , // typeck hang with ty variants: https://github.com/graydon/rust/issues/742 (from dup #900)
2012-01-08 19:24:24 -08:00
" with " , // tstate hang with expr variants: https://github.com/graydon/rust/issues/948
" import comm " // mysterious hang: https://github.com/graydon/rust/issues/1464
2011-09-23 23:23:04 -07:00
] ;
2011-07-28 00:29:24 -07:00
2011-09-02 15:34:58 -07:00
for p : str in dangerous_patterns { if contains ( code , p ) { ret true ; } }
2011-07-28 00:29:24 -07:00
ret false ;
}
2011-09-23 23:23:04 -07:00
fn content_might_not_converge ( code : str ) -> bool {
2011-08-19 15:16:48 -07:00
let confusing_patterns =
2011-09-23 23:23:04 -07:00
[ " xfail-test " ,
" xfail-pretty " ,
" self " , // crazy rules enforced by parser rather than typechecker?
" spawn " , // precedence issues?
2011-09-09 22:31:26 -07:00
" bind " , // precedence issues?
2011-09-23 23:23:04 -07:00
" be " , // don't want to replace its child with a non-call: "Non-call expression in tail call"
2011-09-09 22:31:26 -07:00
" \n \n \n \n \n " // https://github.com/graydon/rust/issues/850
] ;
2011-07-28 00:29:24 -07:00
2011-09-02 15:34:58 -07:00
for p : str in confusing_patterns { if contains ( code , p ) { ret true ; } }
2011-07-25 17:10:00 -07:00
ret false ;
}
2011-09-23 23:23:04 -07:00
fn file_might_not_converge ( filename : str ) -> bool {
2012-01-08 19:24:24 -08:00
let confusing_files = [
" expr-alt.rs " , // pretty-printing "(a = b) = c" vs "a = b = c" and wrapping
" block-arg-in-ternary.rs " , // wrapping
" move-3-unique.rs " , // 0 becomes (0), but both seem reasonable. wtf?
2012-01-08 19:34:02 -08:00
" move-3.rs " // 0 becomes (0), but both seem reasonable. wtf?
2012-01-08 19:24:24 -08:00
] ;
2011-07-25 17:10:00 -07:00
2011-07-28 00:29:24 -07:00
for f in confusing_files { if contains ( filename , f ) { ret true ; } }
2011-07-25 17:10:00 -07:00
ret false ;
}
2011-09-12 11:27:30 +02:00
fn check_roundtrip_convergence ( code : str , maxIters : uint ) {
2011-07-25 17:10:00 -07:00
2011-07-28 00:29:24 -07:00
let i = 0 u ;
2011-07-27 14:19:39 +02:00
let new = code ;
let old = code ;
2011-07-25 17:10:00 -07:00
2011-07-28 00:29:24 -07:00
while i < maxIters {
2011-07-25 17:10:00 -07:00
old = new ;
2011-09-23 23:23:04 -07:00
if content_might_not_converge ( old ) { ret ; }
2011-07-25 17:10:00 -07:00
new = parse_and_print ( old ) ;
2011-07-28 00:29:24 -07:00
if old = = new { break ; }
i + = 1 u ;
2011-07-25 17:10:00 -07:00
}
2011-07-28 00:29:24 -07:00
if old = = new {
2011-12-22 14:42:52 -08:00
#error ( " Converged after %u iterations " , i ) ;
2011-07-28 00:29:24 -07:00
} else {
2011-12-22 14:42:52 -08:00
#error ( " Did not converge after %u iterations! " , i ) ;
2011-09-02 15:34:58 -07:00
write_file ( " round-trip-a.rs " , old ) ;
write_file ( " round-trip-b.rs " , new ) ;
std ::run ::run_program ( " diff " ,
[ " -w " , " -u " , " round-trip-a.rs " ,
" round-trip-b.rs " ] ) ;
2011-07-25 17:10:00 -07:00
fail " Mismatch " ;
}
2011-07-12 11:49:04 -07:00
}
2011-07-28 00:29:24 -07:00
2011-09-12 11:27:30 +02:00
fn check_convergence ( files : [ str ] ) {
2011-12-22 14:42:52 -08:00
#error ( " pp convergence tests: %u files " , vec ::len ( files ) ) ;
2011-07-28 00:29:24 -07:00
for file in files {
2011-09-23 23:23:04 -07:00
if ! file_might_not_converge ( file ) {
2011-10-28 21:19:59 -07:00
let s = result ::get ( io ::read_whole_file_str ( file ) ) ;
2011-09-23 23:23:04 -07:00
if ! content_might_not_converge ( s ) {
2011-12-22 14:42:52 -08:00
#error ( " pp converge: %s " , file ) ;
2011-09-09 22:31:26 -07:00
// Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed
2011-07-28 00:29:24 -07:00
check_roundtrip_convergence ( s , 7 u ) ;
}
2011-07-12 11:49:04 -07:00
}
2011-07-28 00:29:24 -07:00
}
}
2011-07-25 17:10:00 -07:00
2011-09-23 23:23:04 -07:00
fn check_variants ( files : [ str ] , cx : context ) {
2011-07-28 00:29:24 -07:00
for file in files {
2011-09-23 23:23:04 -07:00
if cx . mode = = tm_converge & & file_might_not_converge ( file ) {
2012-01-08 19:24:24 -08:00
#error ( " Skipping convergence test based on file_might_not_converge " ) ;
2011-09-23 23:23:04 -07:00
cont ;
}
2011-10-28 21:19:59 -07:00
let s = result ::get ( io ::read_whole_file_str ( file ) ) ;
2011-09-23 23:23:04 -07:00
if contains ( s , " # " ) {
cont ; // Macros are confusing
2011-07-28 00:29:24 -07:00
}
2011-09-23 23:23:04 -07:00
if cx . mode = = tm_converge & & content_might_not_converge ( s ) {
cont ;
}
if cx . mode = = tm_run & & content_is_dangerous_to_compile ( s ) {
cont ;
}
2011-12-22 17:53:53 -08:00
log ( error , " check_variants: " + file ) ;
2012-01-13 17:33:16 -08:00
let cm = codemap ::new_codemap ( ) ;
let sess = @ {
cm : cm ,
mutable next_id : 0 ,
2012-01-22 17:24:55 -07:00
diagnostic : diagnostic ::mk_handler ( cm , none ) ,
mutable chpos : 0 u ,
mutable byte_pos : 0 u
2012-01-13 17:33:16 -08:00
} ;
2011-09-23 23:23:04 -07:00
let crate =
parser ::parse_crate_from_source_str (
file ,
s , [ ] , sess ) ;
2011-12-22 16:13:40 -08:00
#error ( " %s " ,
2012-01-13 17:33:16 -08:00
as_str ( bind pprust ::print_crate ( sess . cm ,
sess . diagnostic ,
crate ,
2011-12-22 16:13:40 -08:00
file ,
io ::string_reader ( s ) , _ ,
pprust ::no_ann ( ) ) ) ) ;
2011-09-23 23:23:04 -07:00
check_variants_of_ast ( * crate , sess . cm , file , cx ) ;
2011-07-08 02:16:46 -07:00
}
2011-07-27 14:19:39 +02:00
}
2011-07-26 15:38:48 -07:00
2011-09-02 15:34:58 -07:00
fn main ( args : [ str ] ) {
2011-08-15 16:38:23 -07:00
if vec ::len ( args ) ! = 2 u {
2011-12-22 14:42:52 -08:00
#error ( " usage: %s <testdir> " , args [ 0 ] ) ;
2011-07-26 15:38:48 -07:00
ret ;
}
2011-08-19 15:16:48 -07:00
let files = [ ] ;
let root = args [ 1 ] ;
2011-07-26 15:38:48 -07:00
find_rust_files ( files , root ) ;
2012-01-08 19:24:24 -08:00
#error ( " == check_convergence == " ) ;
2011-07-26 15:38:48 -07:00
check_convergence ( files ) ;
2012-01-08 19:24:24 -08:00
#error ( " == check_variants: converge == " ) ;
2011-09-23 23:23:04 -07:00
check_variants ( files , { mode : tm_converge } ) ;
2012-01-08 19:24:24 -08:00
#error ( " == check_variants: run == " ) ;
2011-09-23 23:23:04 -07:00
check_variants ( files , { mode : tm_run } ) ;
2011-09-16 10:44:58 -07:00
2011-12-22 14:42:52 -08:00
#error ( " Fuzzer done " ) ;
2011-05-20 21:06:05 -04:00
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: