From 5cf044643dc194169af7d0a743ea75454e040288 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Sun, 30 Apr 2017 14:52:29 -0300 Subject: [PATCH 01/42] Change arm-linux-androideabi to correspond to the armeabi official ABI Fixes #40941. --- src/librustc_back/target/arm_linux_androideabi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index bccd5a41ab115..6bfe90af2ca16 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -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 { From 98964832f34c56cecc4dae553466b9e4f9548b2c Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Sun, 30 Apr 2017 14:59:22 -0300 Subject: [PATCH 02/42] Add -march=armv7-a parameter to armv7 android linker --- src/librustc_back/target/armv7_linux_androideabi.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index 0c90e834006f1..b49b1d1c2138a 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -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(), From 91a9866bb33c39c2dabcc2e61ca2986a79b9a076 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 11 Apr 2017 21:45:12 +0900 Subject: [PATCH 03/42] Add an example for 'fence' --- src/libcore/sync/atomic.rs | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 0c70524ead246..53362de0d113c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1550,12 +1550,30 @@ unsafe fn atomic_xor(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. /// @@ -1569,6 +1587,37 @@ unsafe fn atomic_xor(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 From c1d97c7d5acf1a6250744a56dfd125cf534b61a4 Mon Sep 17 00:00:00 2001 From: achernyak Date: Tue, 2 May 2017 06:53:34 -0500 Subject: [PATCH 04/42] query for deprecation --- src/librustc/dep_graph/dep_node.rs | 4 ++++ src/librustc/middle/cstore.rs | 5 ----- src/librustc/middle/stability.rs | 4 ++-- src/librustc/ty/maps.rs | 17 ++++++++++++++++- src/librustc_metadata/cstore_impl.rs | 12 ++---------- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index d05ede07c3f64..0f31fae507ee4 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -151,6 +151,8 @@ pub enum DepNode { DescribeDef(D), DefSpan(D), + Stability(D), + Deprecation(D), } impl DepNode { @@ -258,6 +260,8 @@ impl DepNode { } 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), } } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 50920ca7f7ea0..303c5059e7cf3 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -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; // item info - fn stability(&self, def: DefId) -> Option; - fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; 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 { bug!("crate_data_as_rc_any") } // item info - fn stability(&self, def: DefId) -> Option { bug!("stability") } - fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { bug!("visible_parent_map") diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1ac7f4fcc95c2..198f7420f5d2b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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) } } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 3f18a480dd67c..013e1646f2cbc 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -28,6 +28,7 @@ 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 { @@ -292,6 +293,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)) @@ -599,7 +613,8 @@ define_maps! { <'tcx> [] describe_def: DescribeDef(DefId) -> Option, [] def_span: DefSpan(DefId) -> Span, - + [] stability: Stability(DefId) -> Option, + [] deprecation: Deprecation(DefId) -> Option, [] item_body_nested_bodies: metadata_dep_node(DefId) -> Rc>, [] const_is_rvalue_promotable_to_static: metadata_dep_node(DefId) -> bool, [] is_item_mir_available: metadata_dep_node(DefId) -> bool, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f5a8accea2803..3c88aa25e9886 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -115,6 +115,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)) @@ -137,16 +139,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(krate) } - fn stability(&self, def: DefId) -> Option { - self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_stability(def.index) - } - - fn deprecation(&self, def: DefId) -> Option { - 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) From 478b7d9a7a23dbbbe8972c1dd8fc4a38598f145a Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Sat, 29 Apr 2017 05:39:45 -0700 Subject: [PATCH 05/42] Adding consider changing to & suggestion for let bindings --- .../borrowck/gather_loans/move_error.rs | 12 +++++++++++- .../ui/issue-40402-ref-hints/issue-40402-1.stderr | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 9a72f3866a0e1..fba4c0340b91a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -73,9 +73,19 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec { + 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) { + if snippet.len() > 10 { + err.help(&format!("consider borrowing this with `&`")); + } else { + err.help(&format!("consider changing to `&{}`", snippet)); + } + } + } _ => { for move_to in &error.move_to_places { diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr index 5e743b6bd3fe7..c9d0f622da8af 100644 --- a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr @@ -3,6 +3,8 @@ error[E0507]: cannot move out of indexed content | 19 | let e = f.v[0]; | ^^^^^^ cannot move out of indexed content + | + = help: consider changing to `&f.v[0]` error: aborting due to previous error From 1c57bb4219523c38a2fcaf609c845ef77b6f2240 Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Mon, 1 May 2017 22:23:53 -0700 Subject: [PATCH 06/42] Using a span_suggestion to display use & hint --- .../borrowck/gather_loans/move_error.rs | 9 +++------ src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr | 7 ++++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index fba4c0340b91a..b7ce9d982331c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -79,13 +79,10 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec 10 { - err.help(&format!("consider borrowing this with `&`")); - } else { - err.help(&format!("consider changing to `&{}`", snippet)); - } + err.span_suggestion(initializer.span, + "consider using a reference instead", + format!("&{}", snippet)); } - } _ => { for move_to in &error.move_to_places { diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr index c9d0f622da8af..de110ac12b703 100644 --- a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr @@ -2,9 +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 changing to `&f.v[0]` + | ^^^^^^ + | | + | help: consider using a reference instead `&f.v[0]` + | cannot move out of indexed content error: aborting due to previous error From c3781e620084b2e2eba7e8a31b8248410ddca347 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 2 May 2017 08:34:09 -0600 Subject: [PATCH 07/42] Remove ANTLR grammar. It is unused and not maintained. --- src/grammar/.gitignore | 4 - src/grammar/README.md | 33 - src/grammar/RustLexer.g4 | 197 -- src/grammar/check.sh | 52 - src/grammar/lexer.l | 343 ---- src/grammar/parser-lalr-main.c | 203 -- src/grammar/parser-lalr.y | 1945 ------------------- src/grammar/raw-string-literal-ambiguity.md | 64 - src/grammar/testparser.py | 76 - src/grammar/tokens.h | 91 - src/grammar/verify.rs | 361 ---- src/grammar/xidcontinue.g4 | 473 ----- src/grammar/xidstart.g4 | 379 ---- 13 files changed, 4221 deletions(-) delete mode 100644 src/grammar/.gitignore delete mode 100644 src/grammar/README.md delete mode 100644 src/grammar/RustLexer.g4 delete mode 100755 src/grammar/check.sh delete mode 100644 src/grammar/lexer.l delete mode 100644 src/grammar/parser-lalr-main.c delete mode 100644 src/grammar/parser-lalr.y delete mode 100644 src/grammar/raw-string-literal-ambiguity.md delete mode 100755 src/grammar/testparser.py delete mode 100644 src/grammar/tokens.h delete mode 100644 src/grammar/verify.rs delete mode 100644 src/grammar/xidcontinue.g4 delete mode 100644 src/grammar/xidstart.g4 diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore deleted file mode 100644 index e77db28967e33..0000000000000 --- a/src/grammar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -verify -*.class -*.java -*.tokens diff --git a/src/grammar/README.md b/src/grammar/README.md deleted file mode 100644 index 83808108ff832..0000000000000 --- a/src/grammar/README.md +++ /dev/null @@ -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 -``` diff --git a/src/grammar/RustLexer.g4 b/src/grammar/RustLexer.g4 deleted file mode 100644 index a63fc59e50b07..0000000000000 --- a/src/grammar/RustLexer.g4 +++ /dev/null @@ -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 ; diff --git a/src/grammar/check.sh b/src/grammar/check.sh deleted file mode 100755 index 70a8f6fca2e5c..0000000000000 --- a/src/grammar/check.sh +++ /dev/null @@ -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 diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l deleted file mode 100644 index 77737c99496f3..0000000000000 --- a/src/grammar/lexer.l +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include -#include - -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_]* - -%% - -{ident} { BEGIN(INITIAL); } -(.|\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(); } -\n { BEGIN(INITIAL); - yyleng--; - yytext[yyleng] = 0; - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -[^\n]* { yymore(); } - -\/\/|\/\/\/\/ { BEGIN(linecomment); } -\n { BEGIN(INITIAL); } -[^\n]* { } - -\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); } -\/\* { yy_push_state(doc_block); yymore(); } -\*\/ { - yy_pop_state(); - if (yy_top_state() == doc_block) { - yymore(); - } else { - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -} -(.|\n) { yymore(); } - -\/\* { yy_push_state(blockcomment); } -\/\* { yy_push_state(blockcomment); } -\*\/ { yy_pop_state(); } -(.|\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(); } -\! { BEGIN(shebang_or_attr); yymore(); } -\[ { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; -} -[^\[\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; - } -} -. { 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(); } -static { BEGIN(INITIAL); return STATIC_LIFETIME; } -{ident} { BEGIN(INITIAL); return LIFETIME; } -\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } -\\u\{[0-9a-fA-F]?{6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } -.\x27 { BEGIN(suffix); return LIT_CHAR; } -[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } -<> { BEGIN(INITIAL); return -1; } - -b\x22 { BEGIN(bytestr); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR; } - -<> { return -1; } -\\[n\nrt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } - -br\x22 { BEGIN(rawbytestr_nohash); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -br/# { - BEGIN(rawbytestr); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} -# { - 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(); -} -\x22# { - end_hashes = 1; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - yymore(); -} -(.|\n) { - if (!saw_non_hash) { - saw_non_hash = 1; - } - if (end_hashes != 0) { - end_hashes = 0; - } - yymore(); -} -<> { return -1; } - -b\x27 { BEGIN(byte); yymore(); } -\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\u[0-9a-fA-F]{4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\U[0-9a-fA-F]{8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -.\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<> { BEGIN(INITIAL); return -1; } - -r\x22 { BEGIN(rawstr); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -r/# { - BEGIN(rawstr_esc_begin); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} - -# { - num_hashes++; - yymore(); -} -\x22 { - BEGIN(rawstr_esc_body); - yymore(); -} -(.|\n) { return -1; } - -\x22/# { - BEGIN(rawstr_esc_end); - yymore(); - } -(.|\n) { - yymore(); - } - -# { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_STR_RAW; - } - yymore(); - } -[^#] { - end_hashes = 0; - BEGIN(rawstr_esc_body); - yymore(); - } - -<> { return -1; } - -\x22 { BEGIN(str); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR; } - -<> { return -1; } -\\[n\nr\rt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\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; } - -<> { return 0; } - -%% diff --git a/src/grammar/parser-lalr-main.c b/src/grammar/parser-lalr-main.c deleted file mode 100644 index db88a1f2999aa..0000000000000 --- a/src/grammar/parser-lalr-main.c +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include -#include -#include -#include - -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(""); -} - -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); -} diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y deleted file mode 100644 index c9fcdf7647b9c..0000000000000 --- a/src/grammar/parser-lalr.y +++ /dev/null @@ -1,1945 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -%{ -#define YYERROR_VERBOSE -#define YYSTYPE struct node * -struct node; -extern int yylex(); -extern void yyerror(char const *s); -extern struct node *mk_node(char const *name, int n, ...); -extern struct node *mk_atom(char *text); -extern struct node *mk_none(); -extern struct node *ext_node(struct node *nd, int n, ...); -extern void push_back(char c); -extern char *yytext; -%} -%debug - -%token SHL -%token SHR -%token LE -%token EQEQ -%token NE -%token GE -%token ANDAND -%token OROR -%token SHLEQ -%token SHREQ -%token MINUSEQ -%token ANDEQ -%token OREQ -%token PLUSEQ -%token STAREQ -%token SLASHEQ -%token CARETEQ -%token PERCENTEQ -%token DOTDOT -%token DOTDOTDOT -%token MOD_SEP -%token RARROW -%token LARROW -%token FAT_ARROW -%token LIT_BYTE -%token LIT_CHAR -%token LIT_INTEGER -%token LIT_FLOAT -%token LIT_STR -%token LIT_STR_RAW -%token LIT_BYTE_STR -%token LIT_BYTE_STR_RAW -%token IDENT -%token UNDERSCORE -%token LIFETIME - -// keywords -%token SELF -%token STATIC -%token AS -%token BREAK -%token CRATE -%token ELSE -%token ENUM -%token EXTERN -%token FALSE -%token FN -%token FOR -%token IF -%token IMPL -%token IN -%token LET -%token LOOP -%token MATCH -%token MOD -%token MOVE -%token MUT -%token PRIV -%token PUB -%token REF -%token RETURN -%token STRUCT -%token TRUE -%token TRAIT -%token TYPE -%token UNSAFE -%token DEFAULT -%token USE -%token WHILE -%token CONTINUE -%token PROC -%token BOX -%token CONST -%token WHERE -%token TYPEOF -%token INNER_DOC_COMMENT -%token OUTER_DOC_COMMENT - -%token SHEBANG -%token SHEBANG_LINE -%token STATIC_LIFETIME - - /* - Quoting from the Bison manual: - - "Finally, the resolution of conflicts works by comparing the precedence - of the rule being considered with that of the lookahead token. If the - token's precedence is higher, the choice is to shift. If the rule's - precedence is higher, the choice is to reduce. If they have equal - precedence, the choice is made based on the associativity of that - precedence level. The verbose output file made by ā€˜-vā€™ (see Invoking - Bison) says how each conflict was resolved" - */ - -// We expect no shift/reduce or reduce/reduce conflicts in this grammar; -// all potential ambiguities are scrutinized and eliminated manually. -%expect 0 - -// fake-precedence symbol to cause '|' bars in lambda context to parse -// at low precedence, permit things like |x| foo = bar, where '=' is -// otherwise lower-precedence than '|'. Also used for proc() to cause -// things like proc() a + b to parse as proc() { a + b }. -%precedence LAMBDA - -%precedence SELF - -// MUT should be lower precedence than IDENT so that in the pat rule, -// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]" -%precedence MUT - -// IDENT needs to be lower than '{' so that 'foo {' is shifted when -// trying to decide if we've got a struct-construction expr (esp. in -// contexts like 'if foo { .') -// -// IDENT also needs to be lower precedence than '<' so that '<' in -// 'foo:bar . <' is shifted (in a trait reference occurring in a -// bounds list), parsing as foo:(bar) rather than (foo:bar). -%precedence IDENT - -// A couple fake-precedence symbols to use in rules associated with + -// and < in trailing type contexts. These come up when you have a type -// in the RHS of operator-AS, such as "foo as bar". The "<" there -// has to be shifted so the parser keeps trying to parse a type, even -// though it might well consider reducing the type "bar" and then -// going on to "<" as a subsequent binop. The "+" case is with -// trailing type-bounds ("foo as bar:A+B"), for the same reason. -%precedence SHIFTPLUS - -%precedence MOD_SEP -%precedence RARROW ':' - -// In where clauses, "for" should have greater precedence when used as -// a higher ranked constraint than when used as the beginning of a -// for_in_type (which is a ty) -%precedence FORTYPE -%precedence FOR - -// Binops & unops, and their precedences -%precedence BOX -%precedence BOXPLACE -%nonassoc DOTDOT - -// RETURN needs to be lower-precedence than tokens that start -// prefix_exprs -%precedence RETURN - -%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ -%right LARROW -%left OROR -%left ANDAND -%left EQEQ NE -%left '<' '>' LE GE -%left '|' -%left '^' -%left '&' -%left SHL SHR -%left '+' '-' -%precedence AS -%left '*' '/' '%' -%precedence '!' - -%precedence '{' '[' '(' '.' - -%precedence RANGE - -%start crate - -%% - -//////////////////////////////////////////////////////////////////////// -// Part 1: Items and attributes -//////////////////////////////////////////////////////////////////////// - -crate -: maybe_shebang inner_attrs maybe_mod_items { mk_node("crate", 2, $2, $3); } -| maybe_shebang maybe_mod_items { mk_node("crate", 1, $2); } -; - -maybe_shebang -: SHEBANG_LINE -| %empty -; - -maybe_inner_attrs -: inner_attrs -| %empty { $$ = mk_none(); } -; - -inner_attrs -: inner_attr { $$ = mk_node("InnerAttrs", 1, $1); } -| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); } -; - -inner_attr -: SHEBANG '[' meta_item ']' { $$ = mk_node("InnerAttr", 1, $3); } -| INNER_DOC_COMMENT { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); } -; - -maybe_outer_attrs -: outer_attrs -| %empty { $$ = mk_none(); } -; - -outer_attrs -: outer_attr { $$ = mk_node("OuterAttrs", 1, $1); } -| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); } -; - -outer_attr -: '#' '[' meta_item ']' { $$ = $3; } -| OUTER_DOC_COMMENT { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); } -; - -meta_item -: ident { $$ = mk_node("MetaWord", 1, $1); } -| ident '=' lit { $$ = mk_node("MetaNameValue", 2, $1, $3); } -| ident '(' meta_seq ')' { $$ = mk_node("MetaList", 2, $1, $3); } -| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); } -; - -meta_seq -: %empty { $$ = mk_none(); } -| meta_item { $$ = mk_node("MetaItems", 1, $1); } -| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); } -; - -maybe_mod_items -: mod_items -| %empty { $$ = mk_none(); } -; - -mod_items -: mod_item { $$ = mk_node("Items", 1, $1); } -| mod_items mod_item { $$ = ext_node($1, 1, $2); } -; - -attrs_and_vis -: maybe_outer_attrs visibility { $$ = mk_node("AttrsAndVis", 2, $1, $2); } -; - -mod_item -: attrs_and_vis item { $$ = mk_node("Item", 2, $1, $2); } -; - -// items that can appear outside of a fn block -item -: stmt_item -| item_macro -; - -// items that can appear in "stmts" -stmt_item -: item_static -| item_const -| item_type -| block_item -| view_item -; - -item_static -: STATIC ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $2, $4, $6); } -| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $3, $5, $7); } -; - -item_const -: CONST ident ':' ty '=' expr ';' { $$ = mk_node("ItemConst", 3, $2, $4, $6); } -; - -item_macro -: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -; - -view_item -: use_item -| extern_fn_item -| EXTERN CRATE ident ';' { $$ = mk_node("ViewItemExternCrate", 1, $3); } -| EXTERN CRATE ident AS ident ';' { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); } -; - -extern_fn_item -: EXTERN maybe_abi item_fn { $$ = mk_node("ViewItemExternFn", 2, $2, $3); } -; - -use_item -: USE view_path ';' { $$ = mk_node("ViewItemUse", 1, $2); } -; - -view_path -: path_no_types_allowed { $$ = mk_node("ViewPathSimple", 1, $1); } -| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); } -| MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); } -| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); } -| '{' '}' { $$ = mk_atom("ViewPathListEmpty"); } -| '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); } -| '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); } -| path_no_types_allowed AS ident { $$ = mk_node("ViewPathSimple", 2, $1, $3); } -; - -block_item -: item_fn -| item_unsafe_fn -| item_mod -| item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); } -| item_struct -| item_enum -| item_trait -| item_impl -; - -maybe_ty_ascription -: ':' ty_sum { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_init_expr -: '=' expr { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -// structs -item_struct -: STRUCT ident generic_params maybe_where_clause struct_decl_args -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 3, $2, $3, $4); -} -; - -struct_decl_args -: '{' struct_decl_fields '}' { $$ = $2; } -| '{' struct_decl_fields ',' '}' { $$ = $2; } -; - -struct_tuple_args -: '(' struct_tuple_fields ')' { $$ = $2; } -| '(' struct_tuple_fields ',' ')' { $$ = $2; } -; - -struct_decl_fields -: struct_decl_field { $$ = mk_node("StructFields", 1, $1); } -| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_decl_field -: attrs_and_vis ident ':' ty_sum { $$ = mk_node("StructField", 3, $1, $2, $4); } -; - -struct_tuple_fields -: struct_tuple_field { $$ = mk_node("StructFields", 1, $1); } -| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } -; - -struct_tuple_field -: attrs_and_vis ty_sum { $$ = mk_node("StructField", 2, $1, $2); } -; - -// enums -item_enum -: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node("ItemEnum", 0); } -| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); } -; - -enum_defs -: enum_def { $$ = mk_node("EnumDefs", 1, $1); } -| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -enum_def -: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); } -; - -enum_args -: '{' struct_decl_fields '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '(' maybe_ty_sums ')' { $$ = mk_node("EnumArgs", 1, $2); } -| '=' expr { $$ = mk_node("EnumArgs", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_mod -: MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); } -| MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); } -| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); } -; - -item_foreign_mod -: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 1, $4); } -| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); } -; - -maybe_abi -: str -| %empty { $$ = mk_none(); } -; - -maybe_foreign_items -: foreign_items -| %empty { $$ = mk_none(); } -; - -foreign_items -: foreign_item { $$ = mk_node("ForeignItems", 1, $1); } -| foreign_items foreign_item { $$ = ext_node($1, 1, $2); } -; - -foreign_item -: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); } -| attrs_and_vis item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $2); } -| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $3); } -; - -item_foreign_static -: maybe_mut ident ':' ty ';' { $$ = mk_node("StaticItem", 3, $1, $2, $4); } -; - -item_foreign_fn -: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); } -; - -fn_decl_allow_variadic -: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params_allow_variadic -: '(' ')' { $$ = mk_none(); } -| '(' params ')' { $$ = $2; } -| '(' params ',' ')' { $$ = $2; } -| '(' params ',' DOTDOTDOT ')' { $$ = $2; } -; - -visibility -: PUB { $$ = mk_atom("Public"); } -| %empty { $$ = mk_atom("Inherited"); } -; - -idents_or_self -: ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } -| ident_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } -| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } -; - -ident_or_self -: ident -| SELF { $$ = mk_atom(yytext); } -; - -item_type -: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); } -; - -for_sized -: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); } -| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_trait -: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}' -{ - $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9); -} -; - -maybe_trait_items -: trait_items -| %empty { $$ = mk_none(); } -; - -trait_items -: trait_item { $$ = mk_node("TraitItems", 1, $1); } -| trait_items trait_item { $$ = ext_node($1, 1, $2); } -; - -trait_item -: trait_const -| trait_type -| trait_method -; - -trait_const -: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); } -; - -maybe_const_default -: '=' expr { $$ = mk_node("ConstDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -trait_type -: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); } -; - -maybe_unsafe -: UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } -; - -maybe_default_maybe_unsafe -: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); } -| DEFAULT { $$ = mk_atom("Default"); } -| UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } - -trait_method -: type_method { $$ = mk_node("Required", 1, $1); } -| method { $$ = mk_node("Provided", 1, $1); } -; - -type_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9); -} -; - -method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -impl_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -// There are two forms of impl: -// -// impl (<...>)? TY { ... } -// impl (<...>)? TRAIT for TY { ... } -// -// Unfortunately since TY can begin with '<' itself -- as part of a -// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL: -// should we reduce one of the early rules of TY (such as maybe_once) -// or shall we continue shifting into the generic_params list for the -// impl? -// -// The production parser disambiguates a different case here by -// permitting / requiring the user to provide parens around types when -// they are ambiguous with traits. We do the same here, regrettably, -// by splitting ty into ty and ty_prim. -item_impl -: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); -} -| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); -} -; - -maybe_impl_items -: impl_items -| %empty { $$ = mk_none(); } -; - -impl_items -: impl_item { $$ = mk_node("ImplItems", 1, $1); } -| impl_item impl_items { $$ = ext_node($1, 1, $2); } -; - -impl_item -: impl_method -| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); } -| impl_const -| impl_type -; - -impl_const -: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); } -; - -impl_type -: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); } -; - -item_fn -: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6); -} -; - -item_unsafe_fn -: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7); -} -| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9); -} -; - -fn_decl -: fn_params ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self -: fn_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self_allow_anon_params -: fn_anon_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params -: '(' maybe_params ')' { $$ = $2; } -; - -fn_anon_params -: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); } -| '(' ')' { $$ = mk_none(); } -; - -fn_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -fn_anon_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_anon_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -maybe_params -: params -| params ',' -| %empty { $$ = mk_none(); } -; - -params -: param { $$ = mk_node("Args", 1, $1); } -| params ',' param { $$ = ext_node($1, 1, $3); } -; - -param -: pat ':' ty_sum { $$ = mk_node("Arg", 2, $1, $3); } -; - -inferrable_params -: inferrable_param { $$ = mk_node("InferrableParams", 1, $1); } -| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); } -; - -inferrable_param -: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); } -; - -maybe_unboxed_closure_kind -: %empty -| ':' -| '&' maybe_mut ':' -; - -maybe_comma_params -: ',' { $$ = mk_none(); } -| ',' params { $$ = $2; } -| ',' params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_comma_anon_params -: ',' { $$ = mk_none(); } -| ',' anon_params { $$ = $2; } -| ',' anon_params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_anon_params -: anon_params -| anon_params ',' -| %empty { $$ = mk_none(); } -; - -anon_params -: anon_param { $$ = mk_node("Args", 1, $1); } -| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); } -; - -// anon means it's allowed to be anonymous (type-only), but it can -// still have a name -anon_param -: named_arg ':' ty { $$ = mk_node("Arg", 2, $1, $3); } -| ty -; - -anon_params_allow_variadic_tail -: ',' DOTDOTDOT { $$ = mk_none(); } -| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); } -| %empty { $$ = mk_none(); } -; - -named_arg -: ident -| UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' ident { $$ = $2; } -| '&' UNDERSCORE { $$ = mk_atom("PatWild"); } -| ANDAND ident { $$ = $2; } -| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); } -| MUT ident { $$ = $2; } -; - -ret_ty -: RARROW '!' { $$ = mk_none(); } -| RARROW ty { $$ = mk_node("ret-ty", 1, $2); } -| %prec IDENT %empty { $$ = mk_none(); } -; - -generic_params -: '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' ty_params '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' ty_params '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| %empty { $$ = mk_none(); } -; - -maybe_where_clause -: %empty { $$ = mk_none(); } -| where_clause -; - -where_clause -: WHERE where_predicates { $$ = mk_node("WhereClause", 1, $2); } -| WHERE where_predicates ',' { $$ = mk_node("WhereClause", 1, $2); } -; - -where_predicates -: where_predicate { $$ = mk_node("WherePredicates", 1, $1); } -| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); } -; - -where_predicate -: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -; - -maybe_for_lifetimes -: FOR '<' lifetimes '>' { $$ = mk_none(); } -| %prec FORTYPE %empty { $$ = mk_none(); } - -ty_params -: ty_param { $$ = mk_node("TyParams", 1, $1); } -| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); } -; - -// A path with no type parameters; e.g. `foo::bar::Baz` -// -// These show up in 'use' view-items, because these are processed -// without respect to types. -path_no_types_allowed -: ident { $$ = mk_node("ViewPath", 1, $1); } -| MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); } -| SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } -; - -// A path with a lifetime and type parameters, with no double colons -// before the type parameters; e.g. `foo::bar<'a>::Baz` -// -// These show up in "trait references", the components of -// type-parameter bounds lists, as well as in the prefix of the -// path_generic_args_and_bounds rule, which is the full form of a -// named typed expression. -// -// They do not have (nor need) an extra '::' before '<' because -// unlike in expr context, there are no "less-than" type exprs to -// be ambiguous with. -path_generic_args_without_colons -: %prec IDENT - ident { $$ = mk_node("components", 1, $1); } -| %prec IDENT - ident generic_args { $$ = mk_node("components", 2, $1, $2); } -| %prec IDENT - ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node("components", 2, $1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); } -; - -generic_args -: '<' generic_values '>' { $$ = $2; } -| '<' generic_values SHR { push_back('>'); $$ = $2; } -| '<' generic_values GE { push_back('='); $$ = $2; } -| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -// If generic_args starts with "<<", the first arg must be a -// TyQualifiedPath because that's the only type that can start with a -// '<'. This rule parses that as the first ty_sum and then continues -// with the rest of generic_values. -| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; } -| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -; - -generic_values -: maybe_lifetimes maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 2, $1, $2); } -; - -maybe_ty_sums_and_or_bindings -: ty_sums -| ty_sums ',' -| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); } -| bindings -| bindings ',' -| %empty { $$ = mk_none(); } -; - -maybe_bindings -: ',' bindings { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 2: Patterns -//////////////////////////////////////////////////////////////////////// - -pat -: UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' pat { $$ = mk_node("PatRegion", 1, $2); } -| '&' MUT pat { $$ = mk_node("PatRegion", 1, $3); } -| ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); } -| '(' ')' { $$ = mk_atom("PatUnit"); } -| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); } -| '(' pat_tup ',' ')' { $$ = mk_node("PatTup", 1, $2); } -| '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); } -| lit_or_path -| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); } -| path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); } -| path_expr '(' DOTDOT ')' { $$ = mk_node("PatEnum", 1, $1); } -| path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); } -| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); } -| binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); } -| ident '@' pat { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); } -| binding_mode ident '@' pat { $$ = mk_node("PatIdent", 3, $1, $2, $4); } -| BOX pat { $$ = mk_node("PatUniq", 1, $2); } -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10); -} -; - -pats_or -: pat { $$ = mk_node("Pats", 1, $1); } -| pats_or '|' pat { $$ = ext_node($1, 1, $3); } -; - -binding_mode -: REF { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); } -| REF MUT { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); } -| MUT { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); } -; - -lit_or_path -: path_expr { $$ = mk_node("PatLit", 1, $1); } -| lit { $$ = mk_node("PatLit", 1, $1); } -| '-' lit { $$ = mk_node("PatLit", 1, $2); } -; - -pat_field -: ident { $$ = mk_node("PatField", 1, $1); } -| binding_mode ident { $$ = mk_node("PatField", 2, $1, $2); } -| BOX ident { $$ = mk_node("PatField", 2, mk_atom("box"), $2); } -| BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); } -| ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); } -| binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); } -; - -pat_fields -: pat_field { $$ = mk_node("PatFields", 1, $1); } -| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); } -; - -pat_struct -: pat_fields { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); } -| DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); } -; - -pat_tup -: pat { $$ = mk_node("pat_tup", 1, $1); } -| pat_tup ',' pat { $$ = ext_node($1, 1, $3); } -; - -pat_vec -: pat_vec_elts { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $5); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $5); } -| DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -| %empty { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -; - -pat_vec_elts -: pat { $$ = mk_node("PatVecElts", 1, $1); } -| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 3: Types -//////////////////////////////////////////////////////////////////////// - -ty -: ty_prim -| ty_closure -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); } -| '(' ty_sums ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ty_sums ',' ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ')' { $$ = mk_atom("TyNil"); } -; - -ty_prim -: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } -| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } -| BOX ty { $$ = mk_node("TyBox", 1, $2); } -| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } -| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } -| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } -| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } -| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } -| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } -| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } -| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } -| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } -| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } -| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } -| UNDERSCORE { $$ = mk_atom("TyInfer"); } -| ty_bare_fn -| ty_proc -| for_in_type -; - -ty_bare_fn -: FN ty_fn_decl { $$ = $2; } -| UNSAFE FN ty_fn_decl { $$ = $3; } -| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; } -| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; } -; - -ty_fn_decl -: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); } -; - -ty_closure -: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); } -| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); } -| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $3, $4); } -| OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); } -; - -ty_proc -: PROC generic_params fn_params maybe_bounds ret_ty { $$ = mk_node("TyProc", 4, $2, $3, $4, $5); } -; - -for_in_type -: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); } -; - -for_in_type_suffix -: ty_proc -| ty_bare_fn -| trait_ref -| ty_closure -; - -maybe_mut -: MUT { $$ = mk_atom("MutMutable"); } -| %prec MUT %empty { $$ = mk_atom("MutImmutable"); } -; - -maybe_mut_or_const -: MUT { $$ = mk_atom("MutMutable"); } -| CONST { $$ = mk_atom("MutImmutable"); } -| %empty { $$ = mk_atom("MutImmutable"); } -; - -ty_qualified_path_and_generic_values -: ty_qualified_path maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2); -} -| ty_qualified_path ',' ty_sums maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4); -} -; - -ty_qualified_path -: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -; - -maybe_ty_sums -: ty_sums -| ty_sums ',' -| %empty { $$ = mk_none(); } -; - -ty_sums -: ty_sum { $$ = mk_node("TySums", 1, $1); } -| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); } -; - -ty_sum -: ty { $$ = mk_node("TySum", 1, $1); } -| ty '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } -; - -ty_prim_sum -: ty_prim { $$ = mk_node("TySum", 1, $1); } -| ty_prim '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } -; - -maybe_ty_param_bounds -: ':' ty_param_bounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ty_param_bounds -: boundseq -| %empty { $$ = mk_none(); } -; - -boundseq -: polybound -| boundseq '+' polybound { $$ = ext_node($1, 1, $3); } -; - -polybound -: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); } -| bound -| '?' bound { $$ = $2; } -; - -bindings -: binding { $$ = mk_node("Bindings", 1, $1); } -| bindings ',' binding { $$ = ext_node($1, 1, $3); } -; - -binding -: ident '=' ty { mk_node("Binding", 2, $1, $3); } -; - -ty_param -: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 3, $1, $2, $3); } -| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); } -; - -maybe_bounds -: %prec SHIFTPLUS - ':' bounds { $$ = $2; } -| %prec SHIFTPLUS %empty { $$ = mk_none(); } -; - -bounds -: bound { $$ = mk_node("bounds", 1, $1); } -| bounds '+' bound { $$ = ext_node($1, 1, $3); } -; - -bound -: lifetime -| trait_ref -; - -maybe_ltbounds -: %prec SHIFTPLUS - ':' ltbounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ltbounds -: lifetime { $$ = mk_node("ltbounds", 1, $1); } -| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); } -; - -maybe_ty_default -: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_lifetimes -: lifetimes -| lifetimes ',' -| %empty { $$ = mk_none(); } -; - -lifetimes -: lifetime_and_bounds { $$ = mk_node("Lifetimes", 1, $1); } -| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); } -; - -lifetime_and_bounds -: LIFETIME maybe_ltbounds { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -lifetime -: LIFETIME { $$ = mk_node("lifetime", 1, mk_atom(yytext)); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -trait_ref -: %prec IDENT path_generic_args_without_colons -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; } -; - -//////////////////////////////////////////////////////////////////////// -// Part 4: Blocks, statements, and expressions -//////////////////////////////////////////////////////////////////////// - -inner_attrs_and_block -: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node("ExprBlock", 2, $2, $3); } -; - -block -: '{' maybe_stmts '}' { $$ = mk_node("ExprBlock", 1, $2); } -; - -maybe_stmts -: stmts -| stmts nonblock_expr { $$ = ext_node($1, 1, $2); } -| nonblock_expr -| %empty { $$ = mk_none(); } -; - -// There are two sub-grammars within a "stmts: exprs" derivation -// depending on whether each stmt-expr is a block-expr form; this is to -// handle the "semicolon rule" for stmt sequencing that permits -// writing -// -// if foo { bar } 10 -// -// as a sequence of two stmts (one if-expr stmt, one lit-10-expr -// stmt). Unfortunately by permitting juxtaposition of exprs in -// sequence like that, the non-block expr grammar has to have a -// second limited sub-grammar that excludes the prefix exprs that -// are ambiguous with binops. That is to say: -// -// {10} - 1 -// -// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that -// is to say, two statements rather than one, at least according to -// the mainline rust parser. -// -// So we wind up with a 3-way split in exprs that occur in stmt lists: -// block, nonblock-prefix, and nonblock-nonprefix. -// -// In non-stmts contexts, expr can relax this trichotomy. -// -// There is also one other expr subtype: nonparen_expr disallows exprs -// surrounded by parens (including tuple expressions), this is -// necessary for BOX (place) expressions, so a parens expr following -// the BOX is always parsed as the place. - -stmts -: stmt { $$ = mk_node("stmts", 1, $1); } -| stmts stmt { $$ = ext_node($1, 1, $2); } -; - -stmt -: let -| stmt_item -| PUB stmt_item { $$ = $2; } -| outer_attrs stmt_item { $$ = $2; } -| outer_attrs PUB stmt_item { $$ = $3; } -| full_block_expr -| block -| nonblock_expr ';' -| ';' { $$ = mk_none(); } -; - -maybe_exprs -: exprs -| exprs ',' -| %empty { $$ = mk_none(); } -; - -maybe_expr -: expr -| %empty { $$ = mk_none(); } -; - -exprs -: expr { $$ = mk_node("exprs", 1, $1); } -| exprs ',' expr { $$ = ext_node($1, 1, $3); } -; - -path_expr -: path_generic_args_with_colons -| MOD_SEP path_generic_args_with_colons { $$ = $2; } -| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); } -; - -// A path with a lifetime and type parameters with double colons before -// the type parameters; e.g. `foo::bar::<'a>::Baz::` -// -// These show up in expr context, in order to disambiguate from "less-than" -// expressions. -path_generic_args_with_colons -: ident { $$ = mk_node("components", 1, $1); } -| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } -; - -// the braces-delimited macro is a block_expr so it doesn't appear here -macro_expr -: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -; - -nonblock_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE lifetime { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } -| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonblock_expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonblock_expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonblock_expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonblock_expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonblock_expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonblock_expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonblock_expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonblock_expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonblock_expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonblock_expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonblock_expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonblock_expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonblock_expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonblock_expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonblock_expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonblock_expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonblock_expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonblock_expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonblock_expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonblock_expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonblock_expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonblock_expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonblock_expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonblock_expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonblock_expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonblock_expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonblock_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonblock_expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' nonblock_expr { $$ = mk_node("ExprBox", 2, $3, $5); } -| expr_qualified_path -| nonblock_prefix_expr -; - -expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 2, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -nonparen_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonparen_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonparen_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonparen_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonparen_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| nonparen_expr LARROW nonparen_expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| nonparen_expr '=' nonparen_expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonparen_expr SHLEQ nonparen_expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonparen_expr SHREQ nonparen_expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonparen_expr MINUSEQ nonparen_expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonparen_expr ANDEQ nonparen_expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonparen_expr OREQ nonparen_expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonparen_expr PLUSEQ nonparen_expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonparen_expr STAREQ nonparen_expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonparen_expr SLASHEQ nonparen_expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonparen_expr CARETEQ nonparen_expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonparen_expr PERCENTEQ nonparen_expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonparen_expr OROR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonparen_expr ANDAND nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonparen_expr EQEQ nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonparen_expr NE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonparen_expr '<' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonparen_expr '>' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonparen_expr LE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonparen_expr GE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonparen_expr '|' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonparen_expr '^' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonparen_expr '&' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonparen_expr SHL nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonparen_expr SHR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonparen_expr '+' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonparen_expr '-' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonparen_expr '*' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonparen_expr '/' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonparen_expr '%' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonparen_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonparen_expr DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonparen_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 1, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -expr_nostruct -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr_nostruct OREQ expr_nostruct { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr_nostruct STAREQ expr_nostruct { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr_nostruct OROR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr_nostruct ANDAND expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr_nostruct EQEQ expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr_nostruct NE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr_nostruct '<' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr_nostruct '>' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr_nostruct LE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr_nostruct GE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr_nostruct '|' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr_nostruct '^' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr_nostruct '&' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr_nostruct SHL expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr_nostruct SHR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr_nostruct '+' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr_nostruct '-' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr_nostruct '*' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr_nostruct '/' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr_nostruct '%' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr_nostruct { $$ = mk_node("ExprBox", 1, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr_nostruct -; - -nonblock_prefix_expr_nostruct -: '-' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr_nostruct -| MOVE lambda_expr_nostruct { $$ = $2; } -| proc_expr_nostruct -; - -nonblock_prefix_expr -: '-' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr -| MOVE lambda_expr { $$ = $2; } -| proc_expr -; - -expr_qualified_path -: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params -{ - $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12); -} - -maybe_qpath_params -: MOD_SEP generic_args { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_as_trait_ref -: AS trait_ref { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -lambda_expr -: %prec LAMBDA - OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $4, $5); } -| %prec LAMBDA - '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } -| %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $5, $7, $8); } -| %prec LAMBDA - '|' ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $3, $5, $6); } -; - -lambda_expr_nostruct -: %prec LAMBDA - OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } -| %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $4); } -| %prec LAMBDA - '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } -| %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $5, $7); } -| %prec LAMBDA - '|' ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $3, $5); } - -; - -proc_expr -: %prec LAMBDA - PROC '(' ')' expr { $$ = mk_node("ExprProc", 2, mk_none(), $4); } -| %prec LAMBDA - PROC '(' inferrable_params ')' expr { $$ = mk_node("ExprProc", 2, $3, $5); } -; - -proc_expr_nostruct -: %prec LAMBDA - PROC '(' ')' expr_nostruct { $$ = mk_node("ExprProc", 2, mk_none(), $4); } -| %prec LAMBDA - PROC '(' inferrable_params ')' expr_nostruct { $$ = mk_node("ExprProc", 2, $3, $5); } -; - -vec_expr -: maybe_exprs -| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); } -; - -struct_expr_fields -: field_inits -| field_inits ',' -| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } -; - -maybe_field_inits -: field_inits -| field_inits ',' -| %empty { $$ = mk_none(); } -; - -field_inits -: field_init { $$ = mk_node("FieldInits", 1, $1); } -| field_inits ',' field_init { $$ = ext_node($1, 1, $3); } -; - -field_init -: ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } -; - -default_field_init -: DOTDOT expr { $$ = mk_node("DefaultFieldInit", 1, $2); } -; - -block_expr -: expr_match -| expr_if -| expr_if_let -| expr_while -| expr_while_let -| expr_loop -| expr_for -| UNSAFE block { $$ = mk_node("UnsafeBlock", 1, $2); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); } -; - -full_block_expr -: block_expr -| full_block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| full_block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| full_block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| full_block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -; - -expr_match -: MATCH expr_nostruct '{' '}' { $$ = mk_node("ExprMatch", 1, $2); } -| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node("ExprMatch", 2, $2, $4); } -| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); } -| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); } -; - -match_clauses -: match_clause { $$ = mk_node("Arms", 1, $1); } -| match_clauses match_clause { $$ = ext_node($1, 1, $2); } -; - -match_clause -: nonblock_match_clause ',' -| block_match_clause -| block_match_clause ',' -; - -nonblock_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW full_block_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -; - -block_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -; - -maybe_guard -: IF expr_nostruct { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -expr_if -: IF expr_nostruct block { $$ = mk_node("ExprIf", 2, $2, $3); } -| IF expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIf", 3, $2, $3, $5); } -; - -expr_if_let -: IF LET pat '=' expr_nostruct block { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); } -| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); } -; - -block_or_if -: block -| expr_if -| expr_if_let -; - -expr_while -: maybe_label WHILE expr_nostruct block { $$ = mk_node("ExprWhile", 3, $1, $3, $4); } -; - -expr_while_let -: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); } -; - -expr_loop -: maybe_label LOOP block { $$ = mk_node("ExprLoop", 2, $1, $3); } -; - -expr_for -: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); } -; - -maybe_label -: lifetime ':' -| %empty { $$ = mk_none(); } -; - -let -: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 5: Macros and misc. rules -//////////////////////////////////////////////////////////////////////// - -lit -: LIT_BYTE { $$ = mk_node("LitByte", 1, mk_atom(yytext)); } -| LIT_CHAR { $$ = mk_node("LitChar", 1, mk_atom(yytext)); } -| LIT_INTEGER { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); } -| LIT_FLOAT { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); } -| TRUE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| FALSE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| str -; - -str -: LIT_STR { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); } -| LIT_STR_RAW { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); } -| LIT_BYTE_STR { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); } -| LIT_BYTE_STR_RAW { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); } -; - -maybe_ident -: %empty { $$ = mk_none(); } -| ident -; - -ident -: IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -; - -unpaired_token -: SHL { $$ = mk_atom(yytext); } -| SHR { $$ = mk_atom(yytext); } -| LE { $$ = mk_atom(yytext); } -| EQEQ { $$ = mk_atom(yytext); } -| NE { $$ = mk_atom(yytext); } -| GE { $$ = mk_atom(yytext); } -| ANDAND { $$ = mk_atom(yytext); } -| OROR { $$ = mk_atom(yytext); } -| LARROW { $$ = mk_atom(yytext); } -| SHLEQ { $$ = mk_atom(yytext); } -| SHREQ { $$ = mk_atom(yytext); } -| MINUSEQ { $$ = mk_atom(yytext); } -| ANDEQ { $$ = mk_atom(yytext); } -| OREQ { $$ = mk_atom(yytext); } -| PLUSEQ { $$ = mk_atom(yytext); } -| STAREQ { $$ = mk_atom(yytext); } -| SLASHEQ { $$ = mk_atom(yytext); } -| CARETEQ { $$ = mk_atom(yytext); } -| PERCENTEQ { $$ = mk_atom(yytext); } -| DOTDOT { $$ = mk_atom(yytext); } -| DOTDOTDOT { $$ = mk_atom(yytext); } -| MOD_SEP { $$ = mk_atom(yytext); } -| RARROW { $$ = mk_atom(yytext); } -| FAT_ARROW { $$ = mk_atom(yytext); } -| LIT_BYTE { $$ = mk_atom(yytext); } -| LIT_CHAR { $$ = mk_atom(yytext); } -| LIT_INTEGER { $$ = mk_atom(yytext); } -| LIT_FLOAT { $$ = mk_atom(yytext); } -| LIT_STR { $$ = mk_atom(yytext); } -| LIT_STR_RAW { $$ = mk_atom(yytext); } -| LIT_BYTE_STR { $$ = mk_atom(yytext); } -| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); } -| IDENT { $$ = mk_atom(yytext); } -| UNDERSCORE { $$ = mk_atom(yytext); } -| LIFETIME { $$ = mk_atom(yytext); } -| SELF { $$ = mk_atom(yytext); } -| STATIC { $$ = mk_atom(yytext); } -| AS { $$ = mk_atom(yytext); } -| BREAK { $$ = mk_atom(yytext); } -| CRATE { $$ = mk_atom(yytext); } -| ELSE { $$ = mk_atom(yytext); } -| ENUM { $$ = mk_atom(yytext); } -| EXTERN { $$ = mk_atom(yytext); } -| FALSE { $$ = mk_atom(yytext); } -| FN { $$ = mk_atom(yytext); } -| FOR { $$ = mk_atom(yytext); } -| IF { $$ = mk_atom(yytext); } -| IMPL { $$ = mk_atom(yytext); } -| IN { $$ = mk_atom(yytext); } -| LET { $$ = mk_atom(yytext); } -| LOOP { $$ = mk_atom(yytext); } -| MATCH { $$ = mk_atom(yytext); } -| MOD { $$ = mk_atom(yytext); } -| MOVE { $$ = mk_atom(yytext); } -| MUT { $$ = mk_atom(yytext); } -| PRIV { $$ = mk_atom(yytext); } -| PUB { $$ = mk_atom(yytext); } -| REF { $$ = mk_atom(yytext); } -| RETURN { $$ = mk_atom(yytext); } -| STRUCT { $$ = mk_atom(yytext); } -| TRUE { $$ = mk_atom(yytext); } -| TRAIT { $$ = mk_atom(yytext); } -| TYPE { $$ = mk_atom(yytext); } -| UNSAFE { $$ = mk_atom(yytext); } -| USE { $$ = mk_atom(yytext); } -| WHILE { $$ = mk_atom(yytext); } -| CONTINUE { $$ = mk_atom(yytext); } -| PROC { $$ = mk_atom(yytext); } -| BOX { $$ = mk_atom(yytext); } -| CONST { $$ = mk_atom(yytext); } -| WHERE { $$ = mk_atom(yytext); } -| TYPEOF { $$ = mk_atom(yytext); } -| INNER_DOC_COMMENT { $$ = mk_atom(yytext); } -| OUTER_DOC_COMMENT { $$ = mk_atom(yytext); } -| SHEBANG { $$ = mk_atom(yytext); } -| STATIC_LIFETIME { $$ = mk_atom(yytext); } -| ';' { $$ = mk_atom(yytext); } -| ',' { $$ = mk_atom(yytext); } -| '.' { $$ = mk_atom(yytext); } -| '@' { $$ = mk_atom(yytext); } -| '#' { $$ = mk_atom(yytext); } -| '~' { $$ = mk_atom(yytext); } -| ':' { $$ = mk_atom(yytext); } -| '$' { $$ = mk_atom(yytext); } -| '=' { $$ = mk_atom(yytext); } -| '?' { $$ = mk_atom(yytext); } -| '!' { $$ = mk_atom(yytext); } -| '<' { $$ = mk_atom(yytext); } -| '>' { $$ = mk_atom(yytext); } -| '-' { $$ = mk_atom(yytext); } -| '&' { $$ = mk_atom(yytext); } -| '|' { $$ = mk_atom(yytext); } -| '+' { $$ = mk_atom(yytext); } -| '*' { $$ = mk_atom(yytext); } -| '/' { $$ = mk_atom(yytext); } -| '^' { $$ = mk_atom(yytext); } -| '%' { $$ = mk_atom(yytext); } -; - -token_trees -: %empty { $$ = mk_node("TokenTrees", 0); } -| token_trees token_tree { $$ = ext_node($1, 1, $2); } -; - -token_tree -: delimited_token_trees -| unpaired_token { $$ = mk_node("TTTok", 1, $1); } -; - -delimited_token_trees -: parens_delimited_token_trees -| braces_delimited_token_trees -| brackets_delimited_token_trees -; - -parens_delimited_token_trees -: '(' token_trees ')' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("(")), - $2, - mk_node("TTTok", 1, mk_atom(")"))); -} -; - -braces_delimited_token_trees -: '{' token_trees '}' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("{")), - $2, - mk_node("TTTok", 1, mk_atom("}"))); -} -; - -brackets_delimited_token_trees -: '[' token_trees ']' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("[")), - $2, - mk_node("TTTok", 1, mk_atom("]"))); -} -; \ No newline at end of file diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md deleted file mode 100644 index c909f2333148a..0000000000000 --- a/src/grammar/raw-string-literal-ambiguity.md +++ /dev/null @@ -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. diff --git a/src/grammar/testparser.py b/src/grammar/testparser.py deleted file mode 100755 index 37be41b935f84..0000000000000 --- a/src/grammar/testparser.py +++ /dev/null @@ -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 or the MIT license -# , 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") diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h deleted file mode 100644 index 081bd05025967..0000000000000 --- a/src/grammar/tokens.h +++ /dev/null @@ -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 or the MIT license -// , 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 -}; diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs deleted file mode 100644 index 3ac043f7aa9bc..0000000000000 --- a/src/grammar/verify.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - 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 = 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, surrogate_pairs_pos: &[usize], - has_bom: bool) - -> TokenAndSpan { - // old regex: - // \[@(?P\d+),(?P\d+):(?P\d+)='(?P.+?)',<(?P-?\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::().unwrap() - start_offset - offset; - let mut hi = end.parse::().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 = 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("".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(..) - ); - } -} diff --git a/src/grammar/xidcontinue.g4 b/src/grammar/xidcontinue.g4 deleted file mode 100644 index f3a1a3b40f99a..0000000000000 --- a/src/grammar/xidcontinue.g4 +++ /dev/null @@ -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' - ; diff --git a/src/grammar/xidstart.g4 b/src/grammar/xidstart.g4 deleted file mode 100644 index 53fb50f4584d2..0000000000000 --- a/src/grammar/xidstart.g4 +++ /dev/null @@ -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' - ; From 0e5e2f36345fbf44c72c60fda0929aceba5d74dd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 25 Apr 2017 15:56:02 -0400 Subject: [PATCH 08/42] introduce `mir_keys()` Each MIR key is a DefId that has MIR associated with it --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/dep_graph/mod.rs | 1 - src/librustc/dep_graph/visit.rs | 12 ---- src/librustc/mir/transform.rs | 10 +-- src/librustc/ty/maps.rs | 20 +++++- src/librustc/ty/mod.rs | 23 +++---- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_driver/pretty.rs | 17 ++--- src/librustc_metadata/encoder.rs | 7 +- src/librustc_mir/callgraph.rs | 8 +-- src/librustc_mir/mir_map.rs | 71 ++++++++++++-------- src/librustc_mir/transform/dump_mir.rs | 2 +- src/librustc_mir/transform/inline.rs | 38 +++-------- src/librustc_mir/transform/qualify_consts.rs | 11 +-- src/librustc_mir/util/graphviz.rs | 14 ++-- src/librustc_mir/util/pretty.rs | 21 ++++-- src/librustc_passes/mir_stats.rs | 8 +-- src/librustc_typeck/check/mod.rs | 4 +- 18 files changed, 132 insertions(+), 141 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 63a4e6196a2e9..66505d9a06b59 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -76,6 +76,7 @@ pub enum DepNode { BorrowCheck(D), RvalueCheck(D), Reachability, + MirKeys, LateLintCheck, TransCrateItem(D), TransInlinedItem(D), @@ -202,6 +203,7 @@ impl DepNode { Variance => Some(Variance), PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), Reachability => Some(Reachability), + MirKeys => Some(MirKeys), LateLintCheck => Some(LateLintCheck), TransWriteMetadata => Some(TransWriteMetadata), diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a9f0a44e4208c..6cb86a30400a7 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -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; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 93f6e3a83a0c2..bf3748659fe07 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -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); - } -} diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 4cbbb67c7e43d..78a3c1919db29 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -10,6 +10,7 @@ use dep_graph::DepNode; use hir; +use hir::def_id::LOCAL_CRATE; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; @@ -114,14 +115,9 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { - let def_ids = tcx.maps.mir.borrow().keys(); - for def_id in def_ids { - if !def_id.is_local() { - continue; - } - + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut(); + let mir = &mut tcx.mir(def_id).borrow_mut(); tcx.dep_graph.write(DepNode::Mir(def_id)); let id = tcx.hir.as_local_node_id(def_id).unwrap(); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ef5dfab779ccf..ba475367bc6bb 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -20,7 +20,7 @@ use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::item_path; 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}; @@ -270,8 +270,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") } } @@ -546,6 +551,11 @@ define_maps! { <'tcx> /// (in the `RefCell` sense) to prevent accidental mutation. [pub] mir: Mir(DefId) -> &'tcx RefCell>, + /// 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, + /// 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. @@ -644,3 +654,7 @@ fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { DepNode::ConstEval(def_id) } + +fn mir_keys(_: CrateNum) -> DepNode { + DepNode::MirKeys +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c07f41fb22313..5e5dbdf20c04c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2049,6 +2049,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 + '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)) => { @@ -2331,7 +2341,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// 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>> { - if did.is_local() && !self.maps.mir.borrow().contains_key(&did) { + if did.is_local() && !self.mir_keys(LOCAL_CRATE).contains(&did) { return None; } @@ -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(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 { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e5e5045bc29f9..1259816639a1e 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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) { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 18dc504ca8aa9..d40a2ab0b5309 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -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!(), }?; } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 189b94a1b6285..2160a56257b59 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -621,7 +621,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_mir(&mut self, def_id: DefId) -> Option>> { 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.item_mir(def_id); + Some(self.lazy(&mir)) + } else { + None + } } // Encodes the inherent implementations of a structure, enumeration, or trait. diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs index 69416289d8e26..961e202ba1c6d 100644 --- a/src/librustc_mir/callgraph.rs +++ b/src/librustc_mir/callgraph.rs @@ -12,7 +12,7 @@ //! //! This only considers direct calls -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc_data_structures::graph; use rustc::mir::*; @@ -31,16 +31,12 @@ 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; } - + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { let idx = callgraph.add_node(def_id); let mut call_visitor = CallVisitor { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 1abae515ae683..353ca3bbd09e3 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -17,7 +17,7 @@ //! - `#[rustc_mir(pretty="file.mir")]` use build; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::dep_graph::DepNode; use rustc::mir::Mir; use rustc::mir::transform::MirSource; @@ -32,50 +32,67 @@ use rustc::ty::maps::Providers; use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::util::nodemap::DefIdSet; use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; use std::cell::RefCell; use std::mem; +use std::rc::Rc; 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| { + for &body_owner_def_id in tcx.mir_keys(LOCAL_CRATE).iter() { 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; + providers.mir_keys = mir_keys; +} + +fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) + -> Rc { + 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 build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 5b3113f962b2e..6895facd6af60 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -81,6 +81,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(()) } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 45bdff9195c4f..fcd5f970882d7 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -10,7 +10,7 @@ //! Inlining pass for MIR functions -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -58,24 +58,15 @@ impl<'tcx> MirMapPass<'tcx> for Inline { tcx: tcx, }; - let def_ids = tcx.maps.mir.borrow().keys(); - for &def_id in &def_ids { - if !def_id.is_local() { continue; } - + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { 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 mir = &tcx.item_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); + hook.on_mir_pass(tcx, src, mir, self, false); } } @@ -83,18 +74,15 @@ impl<'tcx> MirMapPass<'tcx> for Inline { inliner.inline_scc(&callgraph, &scc); } - for def_id in def_ids { - if !def_id.is_local() { continue; } - + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { 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 mir = &tcx.item_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); + hook.on_mir_pass(tcx, src, mir, self, true); } } } @@ -200,11 +188,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; - let mut caller_mir = { - let map = self.tcx.maps.mir.borrow(); - let mir = map.get(&callsite.caller).unwrap(); - mir.borrow_mut() - }; + let mut caller_mir = self.tcx.mir(callsite.caller).borrow_mut(); let start = caller_mir.basic_blocks().len(); @@ -256,11 +240,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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() - }; + let mut caller_mir = self.tcx.mir(def_id).borrow_mut(); debug!("Running simplify cfg on {:?}", def_id); CfgSimplifier::new(&mut caller_mir).simplify(); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index afb775aa01e70..f566229529676 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -19,7 +19,7 @@ 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; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; @@ -946,12 +946,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { - let def_ids = tcx.maps.mir.borrow().keys(); - for def_id in def_ids { - if !def_id.is_local() { - continue; - } - + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { 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); @@ -961,7 +956,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { continue; } - let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut(); + let mir = &mut tcx.mir(def_id).borrow_mut(); tcx.dep_graph.write(DepNode::Mir(def_id)); for hook in &mut *hooks { diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 91600b947c610..d3d3977a934d3 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -18,14 +18,16 @@ 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 +pub fn write_mir_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + single: Option, + 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); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index b202e1495104e..c03c9c907a335 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -9,7 +9,7 @@ // 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::ty::TyCtxt; @@ -85,17 +85,16 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// 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, 'tcx: 'a +pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + single: Option, + 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) { + for def_id in dump_mir_def_ids(tcx, single) { let mir = &tcx.item_mir(def_id); if first { @@ -312,3 +311,11 @@ fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { Ok(()) } + +pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option) -> Vec { + if let Some(i) = single { + vec![i] + } else { + tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect() + } +} diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index ce02cb0e83643..39b3b709af7ed 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -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.item_mir(def_id); + collector.visit_mir(&mir); } collector.print(title); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c401ed428e4f1..11095e70f621c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); - }); + } }) } From 11b6b0663ae0a89eea913f44aa1eb859b0ef0d3a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 25 Apr 2017 18:22:59 -0400 Subject: [PATCH 09/42] rework `MirPass` API to be stateless and extract helper fns --- src/librustc/mir/transform.rs | 70 ++++++++++++------- .../borrowck/mir/elaborate_drops.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_mir/transform/add_call_guards.rs | 2 +- src/librustc_mir/transform/copy_prop.rs | 2 +- src/librustc_mir/transform/deaggregator.rs | 2 +- src/librustc_mir/transform/dump_mir.rs | 4 +- src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_mir/transform/inline.rs | 28 ++------ src/librustc_mir/transform/instcombine.rs | 28 +++----- src/librustc_mir/transform/no_landing_pads.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_mir/transform/simplify.rs | 4 +- .../transform/simplify_branches.rs | 2 +- src/librustc_mir/transform/type_check.rs | 2 +- 15 files changed, 74 insertions(+), 82 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 78a3c1919db29..37113cee4a5ac 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -10,7 +10,7 @@ use dep_graph::DepNode; use hir; -use hir::def_id::LOCAL_CRATE; +use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; @@ -88,14 +88,14 @@ pub trait Pass { /// A pass which inspects the whole Mir map. pub trait MirMapPass<'tcx>: Pass { fn run_pass<'a>( - &mut self, + &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]); } pub trait MirPassHook<'tcx>: Pass { fn on_mir_pass<'a>( - &mut self, + &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &Mir<'tcx>, @@ -106,40 +106,58 @@ pub trait MirPassHook<'tcx>: Pass { /// 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>, + fn run_pass<'a>(&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, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &mut tcx.mir(def_id).borrow_mut(); - tcx.dep_graph.write(DepNode::Mir(def_id)); + run_hooks(tcx, hooks, self, false); + run_map_pass_task(tcx, self, def_id); + run_hooks(tcx, hooks, self, false); + } + } +} - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let src = MirSource::from_node(tcx, id); +fn run_map_pass_task<'a, 'tcx, T: MirPass<'tcx>>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass: &T, + def_id: DefId) { + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mir = &mut tcx.mir(def_id).borrow_mut(); + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); + let source = MirSource::from_node(tcx, id); + MirPass::run_pass(pass, tcx, source, mir); + + for (i, mir) in mir.promoted.iter_enumerated_mut() { + let source = MirSource::Promoted(id, i); + MirPass::run_pass(pass, tcx, source, mir); + } +} - 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); - } +/// Invokes `hooks` on all the MIR that exists. This is read-only, so +/// new new tasks need to be created. +pub fn run_hooks<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + hooks: &mut [Box MirPassHook<'s>>], + pass: &Pass, + is_after: bool) +{ + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { + let mir = tcx.item_mir(def_id); + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); + + let source = MirSource::from_node(tcx, id); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, source, &mir, pass, is_after); + } - 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); - } + for (i, mir) in mir.promoted.iter_enumerated() { + let source = MirSource::Promoted(id, i); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, source, &mir, pass, false); } } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index ca313622a3afd..106d8fe952d4f 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -33,7 +33,7 @@ use std::u32; pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", src, mir.span); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index aa33d4b553998..5d6bc235761cf 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1056,7 +1056,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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::instcombine::InstCombine); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 80b17c6a008f5..9e67beb86e65c 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -36,7 +36,7 @@ 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>) { + fn run_pass<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { add_call_guards(mir); } } diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 5d127a5aed461..b7cacfe12960d 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -41,7 +41,7 @@ pub struct CopyPropagation; impl Pass for CopyPropagation {} impl<'tcx> MirPass<'tcx> for CopyPropagation { - fn run_pass<'a>(&mut self, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, mir: &mut Mir<'tcx>) { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 3a93bef36c5f7..6d91e6fa55b62 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -18,7 +18,7 @@ pub struct Deaggregator; impl Pass for Deaggregator {} impl<'tcx> MirPass<'tcx> for Deaggregator { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&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)); diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 6895facd6af60..4c6754b88b623 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -23,7 +23,7 @@ use util as mir_util; pub struct Marker<'a>(pub &'a str); impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> { - fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, _mir: &mut Mir<'tcx>) {} } @@ -52,7 +52,7 @@ pub struct DumpMir; impl<'tcx> MirPassHook<'tcx> for DumpMir { fn on_mir_pass<'a>( - &mut self, + &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &Mir<'tcx>, diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 5cc5cf297936d..05e056ed0be21 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -72,7 +72,7 @@ pub struct EraseRegions; impl Pass for EraseRegions {} impl<'tcx> MirPass<'tcx> for EraseRegions { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { EraseRegionsVisitor::new(tcx).visit_mir(mir); } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index fcd5f970882d7..b11a3c805f9cc 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,7 @@ 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::{self, MirMapPass, MirPassHook, MirSource, Pass}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -44,7 +44,7 @@ pub struct Inline; impl<'tcx> MirMapPass<'tcx> for Inline { fn run_pass<'a>( - &mut self, + &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { @@ -58,33 +58,13 @@ impl<'tcx> MirMapPass<'tcx> for Inline { tcx: tcx, }; - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &tcx.item_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); - } - } + transform::run_hooks(tcx, hooks, self, false); for scc in callgraph.scc_iter() { inliner.inline_scc(&callgraph, &scc); } - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &tcx.item_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, true); - } - } + transform::run_hooks(tcx, hooks, self, true); } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 3f6abb31fe9d9..89ac0762fbf59 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -18,22 +18,12 @@ use rustc::util::nodemap::FxHashSet; use rustc_data_structures::indexed_vec::Idx; use std::mem; -pub struct InstCombine { - optimizations: OptimizationList, -} - -impl InstCombine { - pub fn new() -> InstCombine { - InstCombine { - optimizations: OptimizationList::default(), - } - } -} +pub struct InstCombine; impl Pass for InstCombine {} impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass<'a>(&mut self, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { @@ -45,18 +35,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); diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 3654ae6940c52..264b2ea4bb923 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -49,7 +49,7 @@ pub fn no_landing_pads<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx } impl<'tcx> MirPass<'tcx> for NoLandingPads { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { no_landing_pads(tcx, mir) } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f566229529676..e0948b75f27ba 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -942,7 +942,7 @@ pub struct QualifyAndPromoteConstants; impl Pass for QualifyAndPromoteConstants {} impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { - fn run_pass<'a>(&mut self, + fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { @@ -971,7 +971,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { } impl<'tcx> QualifyAndPromoteConstants { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&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); diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index ef7990653ba98..0881585ddfe74 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -62,7 +62,7 @@ pub fn simplify_cfg(mir: &mut Mir) { } 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>) { + fn run_pass<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir); simplify_cfg(mir); } @@ -320,7 +320,7 @@ impl Pass for SimplifyLocals { } impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { + fn run_pass<'a>(&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 diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 3d5106c4b06f7..b16ee65e918c5 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -26,7 +26,7 @@ impl<'a> SimplifyBranches<'a> { } 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>) { + fn run_pass<'a>(&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 { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index d2e4c1a964983..02e34fd7998ce 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -738,7 +738,7 @@ impl TypeckMir { } impl<'tcx> MirPass<'tcx> for TypeckMir { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn run_pass<'a>(&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); From 46b342fbc03664566d65e1b3248f89cbef93ef4c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 25 Apr 2017 18:23:33 -0400 Subject: [PATCH 10/42] simplify the MirPass traits and passes dramatically Overall goal: reduce the amount of context a mir pass needs so that it resembles a query. - The hooks are no longer "threaded down" to the pass, but rather run automatically from the top-level (we also thread down the current pass number, so that the files are sorted better). - The hook now receives a *single* callback, rather than a callback per-MIR. - The traits are no longer lifetime parameters, which moved to the methods -- given that we required `for<'tcx>` objecs, there wasn't much point to that. - Several passes now store a `String` instead of a `&'l str` (again, no point). --- src/librustc/dep_graph/safe.rs | 6 + src/librustc/mir/transform.rs | 133 ++++++++---------- src/librustc/session/config.rs | 2 + .../borrowck/mir/elaborate_drops.rs | 12 +- src/librustc_driver/driver.rs | 3 +- src/librustc_mir/mir_map.rs | 4 +- src/librustc_mir/transform/add_call_guards.rs | 11 +- src/librustc_mir/transform/copy_prop.rs | 14 +- src/librustc_mir/transform/deaggregator.rs | 12 +- src/librustc_mir/transform/dump_mir.rs | 69 ++++----- src/librustc_mir/transform/erase_regions.rs | 12 +- src/librustc_mir/transform/inline.rs | 18 +-- src/librustc_mir/transform/instcombine.rs | 14 +- src/librustc_mir/transform/no_landing_pads.rs | 32 ++--- src/librustc_mir/transform/qualify_consts.rs | 24 ++-- src/librustc_mir/transform/simplify.rs | 43 +++--- .../transform/simplify_branches.rs | 31 ++-- src/librustc_mir/transform/type_check.rs | 13 +- src/librustc_mir/util/pretty.rs | 38 +++-- src/test/mir-opt/basic_assignment.rs | 4 +- src/test/mir-opt/issue-38669.rs | 4 +- src/test/mir-opt/simplify_if.rs | 8 +- src/tools/compiletest/src/runtest.rs | 10 +- 23 files changed, 251 insertions(+), 266 deletions(-) diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs index f85f0338ed997..59dce6f6bb097 100644 --- a/src/librustc/dep_graph/safe.rs +++ b/src/librustc/dep_graph/safe.rs @@ -50,6 +50,12 @@ impl 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 () { } diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 37113cee4a5ac..89f2fb59d5187 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -18,7 +18,6 @@ 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)] @@ -73,59 +72,61 @@ 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::() }; - if let Some(tail) = name.rfind(":") { - Cow::from(&name[tail+1..]) - } else { - Cow::from(name) - } + fn name<'a>(&'a self) -> Cow<'a, str> { + default_name::() } - fn disambiguator<'a>(&'a self) -> Option> { None } + + fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>); } -/// A pass which inspects the whole Mir map. -pub trait MirMapPass<'tcx>: Pass { - fn run_pass<'a>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]); +/// Generates a default name for the pass based on the name of the +/// type `T`. +pub fn default_name() -> Cow<'static, str> { + let name = unsafe { ::std::intrinsics::type_name::() }; + if let Some(tail) = name.rfind(":") { + Cow::from(&name[tail+1..]) + } else { + Cow::from(name) + } } -pub trait MirPassHook<'tcx>: Pass { - fn on_mir_pass<'a>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - pass: &Pass, - is_after: bool - ); +pub trait PassHook { + fn on_mir_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass: &Pass, + pass_num: usize, + is_after: bool); } -/// A pass which inspects Mir of functions in isolation. -pub trait MirPass<'tcx>: Pass { - fn run_pass<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>); +/// 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::() + } + + fn run_pass<'a, 'tcx>(&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>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]) - { +impl Pass for T { + fn name<'a>(&'a self) -> Cow<'a, str> { + MirPass::name(self) + } + + fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - run_hooks(tcx, hooks, self, false); run_map_pass_task(tcx, self, def_id); - run_hooks(tcx, hooks, self, false); } } } -fn run_map_pass_task<'a, 'tcx, T: MirPass<'tcx>>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass: &T, - def_id: DefId) { +fn run_map_pass_task<'a, 'tcx, T: MirPass>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass: &T, + def_id: DefId) { let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); let mir = &mut tcx.mir(def_id).borrow_mut(); let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); @@ -138,36 +139,11 @@ fn run_map_pass_task<'a, 'tcx, T: MirPass<'tcx>>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -/// Invokes `hooks` on all the MIR that exists. This is read-only, so -/// new new tasks need to be created. -pub fn run_hooks<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>], - pass: &Pass, - is_after: bool) -{ - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let mir = tcx.item_mir(def_id); - let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); - - let source = MirSource::from_node(tcx, id); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, source, &mir, pass, is_after); - } - - for (i, mir) in mir.promoted.iter_enumerated() { - let source = MirSource::Promoted(id, i); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, source, &mir, pass, false); - } - } - } -} - /// A manager for MIR passes. pub struct Passes { - passes: Vec MirMapPass<'tcx>>>, - pass_hooks: Vec MirPassHook<'tcx>>>, - plugin_passes: Vec MirMapPass<'tcx>>> + passes: Vec>, + pass_hooks: Vec>, + plugin_passes: Vec> } impl<'a, 'tcx> Passes { @@ -181,27 +157,34 @@ impl<'a, 'tcx> 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)); + // NB: passes are numbered from 1, since "construction" is zero. + for (pass, pass_num) in self.plugin_passes.iter().chain(&self.passes).zip(1..) { + for hook in &self.pass_hooks { + hook.on_mir_pass(tcx, &**pass, pass_num, false); + } + + time(tcx.sess.time_passes(), &*pass.name(), || pass.run_pass(tcx)); + + for hook in &self.pass_hooks { + hook.on_mir_pass(tcx, &**pass, pass_num, true); + } } } /// Pushes a built-in pass. - pub fn push_pass(&mut self, pass: Box MirMapPass<'b>>) { + pub fn push_pass(&mut self, pass: Box) { self.passes.push(pass); } /// Pushes a pass hook. - pub fn push_hook(&mut self, hook: Box MirPassHook<'b>>) { + pub fn push_hook(&mut self, hook: Box) { self.pass_hooks.push(hook); } } /// Copies the plugin passes. -impl ::std::iter::Extend MirMapPass<'a>>> for Passes { - fn extend MirMapPass<'a>>>>(&mut self, it: I) { +impl ::std::iter::Extend> for Passes { + fn extend>>(&mut self, it: I) { self.plugin_passes.extend(it); } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d107e9a84856f..fdfcd83d5b435 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1003,6 +1003,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump MIR state at various points in translation"), dump_mir_dir: Option = (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], diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 106d8fe952d4f..4ae8bdc284b22 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -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>(&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. diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5d6bc235761cf..64fb2168ca1f1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -979,8 +979,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, 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_branches::SimplifyBranches::new("initial")); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); // And run everything. passes.run_passes(tcx); diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 353ca3bbd09e3..6aa7089e7a906 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -192,7 +192,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) @@ -251,7 +251,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 9e67beb86e65c..b7c7a1774dd35 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -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>(&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 {} diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index b7cacfe12960d..fbb67161bac9d 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -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>(&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 diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 6d91e6fa55b62..4309f91c635bb 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -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>(&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); diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 4c6754b88b623..528afd184c6c2 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -10,70 +10,71 @@ //! 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::hir::def_id::LOCAL_CRATE; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; -use rustc::mir::*; -use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; +use rustc::mir::transform::{Pass, PassHook, 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>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource, _mir: &mut Mir<'tcx>) - {} -} +impl Pass for Marker { + fn name<'a>(&'a self) -> Cow<'a, str> { + Cow::Borrowed(self.0) + } -impl<'b> Pass for Marker<'b> { - fn name(&self) -> ::std::borrow::Cow<'static, str> { String::from(self.0).into() } + fn run_pass<'a, 'tcx>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>) { + // no-op + } } -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>( +impl PassHook for DumpMir { + fn on_mir_pass<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, pass: &Pass, + pass_num: usize, is_after: bool) { - mir_util::dump_mir( - tcx, - &*pass.name(), - &Disambiguator { - pass: pass, - is_after: is_after - }, - src, - mir - ); + // No dump filters enabled. + if tcx.sess.opts.debugging_opts.dump_mir.is_none() { + return; + } + + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let source = MirSource::from_node(tcx, id); + let mir = tcx.item_mir(def_id); + mir_util::dump_mir( + tcx, + 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) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 05e056ed0be21..19714849b0914 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -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>(&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); } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index b11a3c805f9cc..b0a067063dd60 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -10,7 +10,7 @@ //! Inlining pass for MIR functions -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -18,7 +18,7 @@ use rustc_data_structures::graph; use rustc::dep_graph::DepNode; use rustc::mir::*; -use rustc::mir::transform::{self, MirMapPass, MirPassHook, MirSource, Pass}; +use rustc::mir::transform::{MirSource, Pass}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -42,12 +42,8 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; -impl<'tcx> MirMapPass<'tcx> for Inline { - fn run_pass<'a>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]) { - +impl Pass for Inline { + fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } let _ignore = tcx.dep_graph.in_ignore(); @@ -58,18 +54,12 @@ impl<'tcx> MirMapPass<'tcx> for Inline { tcx: tcx, }; - transform::run_hooks(tcx, hooks, self, false); - for scc in callgraph.scc_iter() { inliner.inline_scc(&callgraph, &scc); } - - transform::run_hooks(tcx, hooks, self, true); } } -impl<'tcx> Pass for Inline { } - struct Inliner<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 89ac0762fbf59..88a368077d4f5 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,7 +11,7 @@ //! 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; @@ -20,13 +20,11 @@ use std::mem; pub struct InstCombine; -impl Pass for InstCombine {} - -impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass<'a>(&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 diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 264b2ea4bb923..8595663ba18c4 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -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>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - no_landing_pads(tcx, mir) - } -} - -impl Pass for NoLandingPads {} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index e0948b75f27ba..7e7e85f2ec988 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -27,7 +27,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::{Pass, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::middle::lang_items; use syntax::abi::Abi; @@ -939,12 +939,9 @@ 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>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]) +impl Pass for QualifyAndPromoteConstants { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); @@ -959,20 +956,15 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { let mir = &mut tcx.mir(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>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) { +impl<'a, 'tcx> QualifyAndPromoteConstants { + fn run_pass(&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 { diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 0881585ddfe74..d5b79c0d1c382 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -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,20 +61,18 @@ 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>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { - debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir); - simplify_cfg(mir); +impl MirPass for SimplifyCfg { + fn name<'a>(&'a self) -> Cow<'a, str> { + Cow::Borrowed(&self.label) } -} -impl<'l> Pass for SimplifyCfg<'l> { - fn disambiguator<'a>(&'a self) -> Option> { - Some(Box::new(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); } - - // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyCfg".into() } } pub struct CfgSimplifier<'a, 'tcx: 'a> { @@ -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>(&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 diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index b16ee65e918c5..d21a6ddfdfb97 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -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>(&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> { - Some(Box::new(self.label)) - } - - // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyBranches".into() } -} diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 02e34fd7998ce..b325470ec818c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -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>(&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 { -} diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index c03c9c907a335..6c637f2b2a9d6 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -28,7 +28,7 @@ const ALIGN: usize = 40; /// representation of the mir into: /// /// ```text -/// rustc.node.. +/// rustc.node... /// ``` /// /// Output from this function is controlled by passing `-Z dump-mir=`, @@ -39,15 +39,16 @@ 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: usize, 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_id = source.item_id(); let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id)); let is_matched = filters.split("&") @@ -60,26 +61,47 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } - let promotion_id = match src { + 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); + } +} + +fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: usize, + 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 { + format!(".{:03}", pass_num) + }; + 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(()) }); } diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 9c924a23903f9..e4eb1aeaf9be2 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -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 diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index fbbffe8953b38..5a9336e96592d 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -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 diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 6e80a9174676a..cff108246a550 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -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 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 731665ce03458..a044282666da0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -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); From e9e6ccc042696e3334abff8319e769cbffa3ede8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Apr 2017 11:46:17 -0400 Subject: [PATCH 11/42] introduce `DefIdPass` and remove all impls of `Pass` but `Inline` --- src/librustc/mir/transform.rs | 80 +++++++++++++------- src/librustc/ty/maps.rs | 2 +- src/librustc_driver/driver.rs | 44 +++++------ src/librustc_mir/transform/dump_mir.rs | 8 +- src/librustc_mir/transform/qualify_consts.rs | 33 ++++---- 5 files changed, 96 insertions(+), 71 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 89f2fb59d5187..14ad413c5385e 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; use hir; use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; +use std::rc::Rc; use syntax::ast::NodeId; use util::common::time; @@ -99,51 +99,77 @@ pub trait PassHook { } /// 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 { +/// pass will be invoked to process the MIR with the given `def_id`. +/// This lets you do things before we fetch the MIR itself. You may +/// prefer `MirPass`. +pub trait DefIdPass { fn name<'a>(&'a self) -> Cow<'a, str> { default_name::() } fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &mut Mir<'tcx>); + def_id: DefId); } -impl Pass for T { +impl Pass for T { fn name<'a>(&'a self) -> Cow<'a, str> { - MirPass::name(self) + DefIdPass::name(self) } fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - run_map_pass_task(tcx, self, def_id); + DefIdPass::run_pass(self, tcx, def_id); } } } -fn run_map_pass_task<'a, 'tcx, T: MirPass>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass: &T, - def_id: DefId) { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &mut tcx.mir(def_id).borrow_mut(); +/// 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: DepGraphSafe { + fn name<'a>(&'a self) -> Cow<'a, str> { + default_name::() + } + + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>); +} + +fn for_each_assoc_mir<'a, 'tcx, OP>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + mut op: OP) + where OP: FnMut(MirSource, &mut Mir<'tcx>) +{ let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); let source = MirSource::from_node(tcx, id); - MirPass::run_pass(pass, tcx, source, mir); + let mir = &mut tcx.mir(def_id).borrow_mut(); + op(source, mir); + + for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() { + let promoted_source = MirSource::Promoted(id, promoted_index); + op(promoted_source, promoted_mir); + } +} + +impl DefIdPass for T { + fn name<'a>(&'a self) -> Cow<'a, str> { + MirPass::name(self) + } - for (i, mir) in mir.promoted.iter_enumerated_mut() { - let source = MirSource::Promoted(id, i); - MirPass::run_pass(pass, tcx, source, mir); + fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { + for_each_assoc_mir(tcx, def_id, |src, mir| MirPass::run_pass(self, tcx, src, mir)); } } /// A manager for MIR passes. +#[derive(Clone)] pub struct Passes { - passes: Vec>, - pass_hooks: Vec>, - plugin_passes: Vec> + passes: Vec>, + pass_hooks: Vec>, + plugin_passes: Vec> } impl<'a, 'tcx> Passes { @@ -172,19 +198,19 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, pass: Box) { - self.passes.push(pass); + pub fn push_pass(&mut self, pass: T) { + self.passes.push(Rc::new(pass)); } /// Pushes a pass hook. - pub fn push_hook(&mut self, hook: Box) { - self.pass_hooks.push(hook); + pub fn push_hook(&mut self, hook: T) { + self.pass_hooks.push(Rc::new(hook)); } } /// Copies the plugin passes. -impl ::std::iter::Extend> for Passes { - fn extend>>(&mut self, it: I) { +impl ::std::iter::Extend> for Passes { + fn extend>>(&mut self, it: I) { self.plugin_passes.extend(it); } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ba475367bc6bb..a9deb52efb68a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -549,7 +549,7 @@ define_maps! { <'tcx> /// /// 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(DefId) -> &'tcx RefCell>, /// 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 diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 64fb2168ca1f1..be344176fd255 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -975,12 +975,12 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // 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")); + passes.push_hook(mir::transform::dump_mir::DumpMir); + passes.push_pass(mir::transform::simplify::SimplifyCfg::new("initial")); + passes.push_pass(mir::transform::type_check::TypeckMir); + passes.push_pass(mir::transform::qualify_consts::QualifyAndPromoteConstants); + passes.push_pass(mir::transform::simplify_branches::SimplifyBranches::new("initial")); + passes.push_pass(mir::transform::simplify::SimplifyCfg::new("qualify-consts")); // And run everything. passes.run_passes(tcx); }); @@ -1041,27 +1041,27 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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")); + passes.push_hook(mir::transform::dump_mir::DumpMir); + passes.push_pass(mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(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(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")); + passes.push_pass(mir::transform::add_call_guards::AddCallGuards); + passes.push_pass(borrowck::ElaborateDrops); + passes.push_pass(mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(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); - 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.push_pass(mir::transform::inline::Inline); + passes.push_pass(mir::transform::instcombine::InstCombine); + passes.push_pass(mir::transform::deaggregator::Deaggregator); + passes.push_pass(mir::transform::copy_prop::CopyPropagation); + + passes.push_pass(mir::transform::simplify::SimplifyLocals); + passes.push_pass(mir::transform::add_call_guards::AddCallGuards); + passes.push_pass(mir::transform::dump_mir::Marker("PreTrans")); passes.run_passes(tcx); }); diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 528afd184c6c2..43fb0acf2dd86 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -15,20 +15,20 @@ use std::fmt; use std::fs::File; use std::io; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; -use rustc::mir::transform::{Pass, PassHook, MirSource}; +use rustc::mir::transform::{DefIdPass, Pass, PassHook, MirSource}; use util as mir_util; pub struct Marker(pub &'static str); -impl Pass for Marker { +impl DefIdPass 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>) { + fn run_pass<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>, _: DefId) { // no-op } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7e7e85f2ec988..80ec83fcaefb0 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -19,7 +19,7 @@ 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, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; @@ -27,7 +27,7 @@ use rustc::ty::cast::CastTy; use rustc::ty::maps::Providers; use rustc::mir::*; use rustc::mir::traversal::ReversePostorder; -use rustc::mir::transform::{Pass, MirSource}; +use rustc::mir::transform::{DefIdPass, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::middle::lang_items; use syntax::abi::Abi; @@ -939,25 +939,24 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct QualifyAndPromoteConstants; -impl Pass for QualifyAndPromoteConstants { +impl DefIdPass for QualifyAndPromoteConstants { fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) { - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - 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.mir(def_id).borrow_mut(); - tcx.dep_graph.write(DepNode::Mir(def_id)); + 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); - self.run_pass(tcx, src, mir); + if let MirSource::Const(_) = src { + tcx.mir_const_qualif(def_id); + return; } + + let mir = &mut tcx.mir(def_id).borrow_mut(); + tcx.dep_graph.write(DepNode::Mir(def_id)); + + self.run_pass(tcx, src, mir); } } From 668886a6ccaf294bf0ab3742e693997ce39b716b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Apr 2017 13:04:57 -0400 Subject: [PATCH 12/42] rewrite `Passes` to have sets of passes Also, store the completed set of passes in the tcx. --- src/librustc/mir/transform.rs | 51 +++++++++++++++--------- src/librustc/ty/context.rs | 9 ++++- src/librustc_driver/driver.rs | 74 ++++++++++++++++++----------------- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 14ad413c5385e..cfe8254d1bb62 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -167,24 +167,46 @@ impl DefIdPass for T { /// A manager for MIR passes. #[derive(Clone)] pub struct Passes { - passes: Vec>, pass_hooks: Vec>, - plugin_passes: Vec> + sets: Vec, +} + +#[derive(Clone)] +struct PassSet { + passes: Vec>, } +/// The number of "pass sets" that we have: +/// +/// - ready for constant evaluation +/// - unopt +/// - optimized +pub const MIR_PASS_SETS: usize = 3; + +/// Run the passes we need to do constant qualification and evaluation. +pub const MIR_CONST: usize = 0; + +/// Run the passes we need to consider the MIR validated and ready for borrowck etc. +pub const MIR_VALIDATED: usize = 1; + +/// Run the passes we need to consider the MIR *optimized*. +pub const MIR_OPTIMIZED: usize = 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 + sets: (0..MIR_PASS_SETS).map(|_| PassSet { passes: Vec::new() }).collect(), + } } - pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { + pub fn run_passes(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, set_index: usize) { + let set = &self.sets[set_index]; + + let start_num: usize = self.sets[..set_index].iter().map(|s| s.passes.len()).sum(); + // NB: passes are numbered from 1, since "construction" is zero. - for (pass, pass_num) in self.plugin_passes.iter().chain(&self.passes).zip(1..) { + for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) { for hook in &self.pass_hooks { hook.on_mir_pass(tcx, &**pass, pass_num, false); } @@ -198,8 +220,8 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, pass: T) { - self.passes.push(Rc::new(pass)); + pub fn push_pass(&mut self, set: usize, pass: T) { + self.sets[set].passes.push(Rc::new(pass)); } /// Pushes a pass hook. @@ -207,10 +229,3 @@ impl<'a, 'tcx> Passes { self.pass_hooks.push(Rc::new(hook)); } } - -/// Copies the plugin passes. -impl ::std::iter::Extend> for Passes { - fn extend>>(&mut self, it: I) { - self.plugin_passes.extend(it); - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6de61013dfdd3..0c189853c6195 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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; @@ -47,11 +48,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; @@ -441,8 +443,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, + // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from // scratch every time. @@ -712,6 +717,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn create_and_enter(s: &'tcx Session, local_providers: ty::maps::Providers<'tcx>, extern_providers: ty::maps::Providers<'tcx>, + mir_passes: Rc, arenas: &'tcx GlobalArenas<'tcx>, arena: &'tcx DroplessArena, resolutions: ty::Resolutions, @@ -746,6 +752,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()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index be344176fd255..89f01226113cb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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}; use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas}; use rustc::util::common::time; use rustc::util::nodemap::NodeSet; @@ -903,9 +904,43 @@ 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 = sess.mir_passes.borrow().clone(); + 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, @@ -971,18 +1006,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, } 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(mir::transform::dump_mir::DumpMir); - passes.push_pass(mir::transform::simplify::SimplifyCfg::new("initial")); - passes.push_pass(mir::transform::type_check::TypeckMir); - passes.push_pass(mir::transform::qualify_consts::QualifyAndPromoteConstants); - passes.push_pass(mir::transform::simplify_branches::SimplifyBranches::new("initial")); - passes.push_pass(mir::transform::simplify::SimplifyCfg::new("qualify-consts")); - // And run everything. - passes.run_passes(tcx); + tcx.mir_passes.run_passes(tcx, MIR_CONST); + tcx.mir_passes.run_passes(tcx, MIR_VALIDATED); }); time(time_passes, @@ -1040,30 +1065,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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(mir::transform::dump_mir::DumpMir); - passes.push_pass(mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); - - // From here on out, regions are gone. - passes.push_pass(mir::transform::erase_regions::EraseRegions); - - passes.push_pass(mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(borrowck::ElaborateDrops); - passes.push_pass(mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); - - // No lifetime analysis based on borrowing can be done from here on out. - passes.push_pass(mir::transform::inline::Inline); - passes.push_pass(mir::transform::instcombine::InstCombine); - passes.push_pass(mir::transform::deaggregator::Deaggregator); - passes.push_pass(mir::transform::copy_prop::CopyPropagation); - - passes.push_pass(mir::transform::simplify::SimplifyLocals); - passes.push_pass(mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(mir::transform::dump_mir::Marker("PreTrans")); - - passes.run_passes(tcx); + tcx.mir_passes.run_passes(tcx, MIR_OPTIMIZED); }); if tcx.sess.opts.debugging_opts.mir_stats { From f23a7bc98a221db000991f6a618602a9a4b35759 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Apr 2017 13:16:57 -0400 Subject: [PATCH 13/42] move to only def-id passes this temporary disables `inline` --- src/librustc/mir/transform.rs | 16 ++++++++++------ src/librustc_driver/driver.rs | 2 +- src/librustc_mir/transform/dump_mir.rs | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index cfe8254d1bb62..8ecfbfdb5c3ef 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -93,7 +93,7 @@ pub fn default_name() -> Cow<'static, str> { pub trait PassHook { fn on_mir_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass: &Pass, + pass_name: &str, pass_num: usize, is_after: bool); } @@ -173,7 +173,7 @@ pub struct Passes { #[derive(Clone)] struct PassSet { - passes: Vec>, + passes: Vec>, } /// The number of "pass sets" that we have: @@ -208,19 +208,23 @@ impl<'a, 'tcx> Passes { // NB: passes are numbered from 1, since "construction" is zero. for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) { for hook in &self.pass_hooks { - hook.on_mir_pass(tcx, &**pass, pass_num, false); + hook.on_mir_pass(tcx, &pass.name(), pass_num, false); } - time(tcx.sess.time_passes(), &*pass.name(), || pass.run_pass(tcx)); + time(tcx.sess.time_passes(), &*pass.name(), || { + for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { + pass.run_pass(tcx, def_id); + } + }); for hook in &self.pass_hooks { - hook.on_mir_pass(tcx, &**pass, pass_num, true); + hook.on_mir_pass(tcx, &pass.name(), pass_num, true); } } } /// Pushes a built-in pass. - pub fn push_pass(&mut self, set: usize, pass: T) { + pub fn push_pass(&mut self, set: usize, pass: T) { self.sets[set].passes.push(Rc::new(pass)); } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 89f01226113cb..4c984559428bf 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -929,7 +929,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, 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::inline::Inline); // TODO re-enable 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); diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 43fb0acf2dd86..62b480494c3ec 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -50,7 +50,7 @@ impl PassHook for DumpMir { fn on_mir_pass<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass: &Pass, + pass_name: &str, pass_num: usize, is_after: bool) { @@ -66,7 +66,7 @@ impl PassHook for DumpMir { mir_util::dump_mir( tcx, pass_num, - &*pass.name(), + &pass_name, &Disambiguator { is_after }, source, &mir From 2b32cb90c72d90c722d56324ca0ea9f748ebf4e1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 27 Apr 2017 16:48:48 -0400 Subject: [PATCH 14/42] retool MIR passes completely The new setup is as follows. There is a pipeline of MIR passes that each run **per def-id** to optimize a particular function. You are intended to request MIR at whatever stage you need it. At the moment, there is only one stage you can request: - `optimized_mir(def_id)` This yields the final product. Internally, it pulls the MIR for the given def-id through a series of steps. Right now, these are still using an "interned ref-cell" but they are intended to "steal" from one another: - `mir_build` -- performs the initial construction for local MIR - `mir_pass_set` -- performs a suite of optimizations and transformations - `mir_pass` -- an individual optimization within a suite So, to construct the optimized MIR, we invoke: mir_pass_set((MIR_OPTIMIZED, def_id)) which will build up the final MIR. --- src/librustc/mir/transform.rs | 140 +++++++++---------- src/librustc/ty/maps.rs | 68 +++++++-- src/librustc/ty/mod.rs | 16 ++- src/librustc_driver/driver.rs | 19 --- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/mir_map.rs | 14 +- src/librustc_mir/transform/dump_mir.rs | 56 ++++---- src/librustc_mir/transform/inline.rs | 15 +- src/librustc_mir/transform/mod.rs | 106 ++++++++++++++ src/librustc_mir/transform/qualify_consts.rs | 42 +++--- src/librustc_mir/util/mod.rs | 2 +- src/librustc_mir/util/pretty.rs | 48 ++++--- 13 files changed, 345 insertions(+), 185 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 8ecfbfdb5c3ef..9fab6564d9b00 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -9,13 +9,13 @@ // except according to those terms. use hir; -use hir::def_id::{DefId, LOCAL_CRATE}; +use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; +use std::cell::{Ref, RefCell}; use std::rc::Rc; use syntax::ast::NodeId; -use util::common::time; use std::borrow::Cow; @@ -90,12 +90,37 @@ pub fn default_name() -> Cow<'static, str> { } } +/// Gives you access to various bits of state during your MIR pass. +pub trait MirCtxt<'a, 'tcx: 'a> { + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; + fn def_id(&self) -> DefId; + fn pass_set(&self) -> MirPassSet; + fn pass_num(&self) -> MirPassIndex; + fn source(&self) -> MirSource; + fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>; + fn steal_previous_mir(&self) -> &'tcx RefCell>; +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct MirPassSet(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). pub trait PassHook { - fn on_mir_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - pass_num: usize, - is_after: bool); + fn on_mir_pass<'a, 'tcx: 'a>(&self, + mir_cx: &MirCtxt<'a, 'tcx>, + mir: Option<&Mir<'tcx>>); } /// A streamlined trait that you can implement to create a pass; the @@ -107,21 +132,7 @@ pub trait DefIdPass { default_name::() } - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId); -} - -impl Pass for T { - fn name<'a>(&'a self) -> Cow<'a, str> { - DefIdPass::name(self) - } - - fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - DefIdPass::run_pass(self, tcx, def_id); - } - } + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell>; } /// A streamlined trait that you can implement to create a pass; the @@ -138,29 +149,24 @@ pub trait MirPass: DepGraphSafe { mir: &mut Mir<'tcx>); } -fn for_each_assoc_mir<'a, 'tcx, OP>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mut op: OP) - where OP: FnMut(MirSource, &mut Mir<'tcx>) -{ - let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); - let source = MirSource::from_node(tcx, id); - let mir = &mut tcx.mir(def_id).borrow_mut(); - op(source, mir); - - for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() { - let promoted_source = MirSource::Promoted(id, promoted_index); - op(promoted_source, promoted_mir); - } -} - impl DefIdPass for T { fn name<'a>(&'a self) -> Cow<'a, str> { MirPass::name(self) } - fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - for_each_assoc_mir(tcx, def_id, |src, mir| MirPass::run_pass(self, tcx, src, mir)); + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + let tcx = mir_cx.tcx(); + let source = mir_cx.source(); + let mir = mir_cx.steal_previous_mir(); + MirPass::run_pass(self, tcx, source, &mut mir.borrow_mut()); + + let item_id = source.item_id(); + for (promoted_index, promoted_mir) in mir.borrow_mut().promoted.iter_enumerated_mut() { + let promoted_source = MirSource::Promoted(item_id, promoted_index); + MirPass::run_pass(self, tcx, promoted_source, promoted_mir); + } + + mir } } @@ -168,12 +174,7 @@ impl DefIdPass for T { #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, - sets: Vec, -} - -#[derive(Clone)] -struct PassSet { - passes: Vec>, + sets: Vec>>, } /// The number of "pass sets" that we have: @@ -184,52 +185,41 @@ struct PassSet { pub const MIR_PASS_SETS: usize = 3; /// Run the passes we need to do constant qualification and evaluation. -pub const MIR_CONST: usize = 0; +pub const MIR_CONST: MirPassSet = MirPassSet(0); /// Run the passes we need to consider the MIR validated and ready for borrowck etc. -pub const MIR_VALIDATED: usize = 1; +pub const MIR_VALIDATED: MirPassSet = MirPassSet(1); /// Run the passes we need to consider the MIR *optimized*. -pub const MIR_OPTIMIZED: usize = 2; +pub const MIR_OPTIMIZED: MirPassSet = MirPassSet(2); impl<'a, 'tcx> Passes { pub fn new() -> Passes { Passes { pass_hooks: Vec::new(), - sets: (0..MIR_PASS_SETS).map(|_| PassSet { passes: Vec::new() }).collect(), - } - } - - pub fn run_passes(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, set_index: usize) { - let set = &self.sets[set_index]; - - let start_num: usize = self.sets[..set_index].iter().map(|s| s.passes.len()).sum(); - - // NB: passes are numbered from 1, since "construction" is zero. - for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) { - for hook in &self.pass_hooks { - hook.on_mir_pass(tcx, &pass.name(), pass_num, false); - } - - time(tcx.sess.time_passes(), &*pass.name(), || { - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - pass.run_pass(tcx, def_id); - } - }); - - for hook in &self.pass_hooks { - hook.on_mir_pass(tcx, &pass.name(), pass_num, true); - } + sets: (0..MIR_PASS_SETS).map(|_| Vec::new()).collect(), } } /// Pushes a built-in pass. - pub fn push_pass(&mut self, set: usize, pass: T) { - self.sets[set].passes.push(Rc::new(pass)); + pub fn push_pass(&mut self, set: MirPassSet, pass: T) { + self.sets[set.0].push(Rc::new(pass)); } /// Pushes a pass hook. pub fn push_hook(&mut self, hook: T) { self.pass_hooks.push(Rc::new(hook)); } + + pub fn len_passes(&self, set: MirPassSet) -> usize { + self.sets[set.0].len() + } + + pub fn pass(&self, set: MirPassSet, pass: MirPassIndex) -> &DefIdPass { + &*self.sets[set.0][pass.0] + } + + pub fn hooks(&self) -> &[Rc] { + &self.pass_hooks + } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index a9deb52efb68a..dc70dcc81162f 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,6 +16,7 @@ use middle::const_val; use middle::privacy::AccessLevels; use middle::region::RegionMaps; use mir; +use mir::transform::{MirPassSet, MirPassIndex}; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::item_path; @@ -101,6 +102,24 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { } } +impl Key for (MirPassSet, 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 (MirPassSet, 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; } @@ -318,6 +337,18 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> { } } +impl<'tcx> QueryDescription for queries::mir_pass_set<'tcx> { + fn describe(_: TyCtxt, (pass_set, _): (MirPassSet, DefId)) -> String { + format!("MIR passes #{}.*", pass_set.0) + } +} + +impl<'tcx> QueryDescription for queries::mir_pass<'tcx> { + fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirPassSet, MirPassIndex, DefId)) -> String { + format!("MIR pass #{}.{}", pass_set.0, pass_num.0) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -542,15 +573,6 @@ define_maps! { <'tcx> /// Methods in these implementations don't need to be exported. [] inherent_impls: InherentImpls(DefId) -> Rc>, - /// 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. - [] mir: Mir(DefId) -> &'tcx RefCell>, - /// 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. @@ -561,6 +583,26 @@ define_maps! { <'tcx> /// the value isn't known except to the pass itself. [] mir_const_qualif: Mir(DefId) -> u8, + /// Performs the initial MIR construction. You almost certainly do not + /// want to use this query, because its output is intended to be stolen + /// immediately by the MIR passes below. Consider `optimized_mir` instead. + [] mir_build: Mir(DefId) -> &'tcx RefCell>, + + /// Fetch the MIR for a given def-id after the given set of passes has ben + /// applied to it. This is mostly an "intermediate" query. Normally, you would + /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all + /// optimizations and so forth. + [] mir_pass_set: mir_pass_set((MirPassSet, DefId)) -> &'tcx RefCell>, + + /// Fetch the MIR for a given def-id after a given pass has been executed. This is + /// **only** intended to be used by the `mir_pass_set` provider -- if you are using it + /// manually, you're doing it wrong. + [] mir_pass: mir_pass((MirPassSet, MirPassIndex, DefId)) -> &'tcx RefCell>, + + /// 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 RefCell>, + /// Records the type of each closure. The def ID is the ID of the /// expression defining the closure. [] closure_kind: ItemSignature(DefId) -> ty::ClosureKind, @@ -658,3 +700,11 @@ fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { fn mir_keys(_: CrateNum) -> DepNode { DepNode::MirKeys } + +fn mir_pass_set((_pass_set, def_id): (MirPassSet, DefId)) -> DepNode { + DepNode::Mir(def_id) +} + +fn mir_pass((_pass_set, _pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) -> DepNode { + DepNode::Mir(def_id) +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5e5dbdf20c04c..cf66c83800d36 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2323,9 +2323,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Given the did of an item, returns its MIR, borrowed immutably. + /// Given the did of an item, returns its (optimized) MIR, borrowed immutably. pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - self.mir(did).borrow() + self.optimized_mir(did).borrow() } /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. @@ -2333,8 +2333,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> Ref<'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.item_mir(did) + } + ty::InstanceDef::Intrinsic(..) | + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::ClosureOnceShim { .. } | + ty::InstanceDef::DropGlue(..) => { + self.mir_shims(instance).borrow() + } } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4c984559428bf..9b11d168e0077 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1005,11 +1005,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS"); } - time(time_passes, "MIR cleanup and validation", || { - tcx.mir_passes.run_passes(tcx, MIR_CONST); - tcx.mir_passes.run_passes(tcx, MIR_VALIDATED); - }); - time(time_passes, "borrow checking", || borrowck::check_crate(tcx)); @@ -1058,20 +1053,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", || { - tcx.mir_passes.run_passes(tcx, MIR_OPTIMIZED); - }); - - if tcx.sess.opts.debugging_opts.mir_stats { - mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS"); - } - let translation = time(time_passes, "translation", diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f5a8accea2803..4ecce3cc132fe 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -95,7 +95,7 @@ provide! { <'tcx> tcx, def_id, cdata bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); }) } - mir => { + optimized_mir => { let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| { bug!("get_item_mir: missing MIR for `{:?}`", def_id) }); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 8b55cdf06d208..cf6a50563a08c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -59,5 +59,5 @@ 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); } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 6aa7089e7a906..46f7c34c06e8d 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -52,8 +52,11 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } pub fn provide(providers: &mut Providers) { - providers.mir = build_mir; - providers.mir_keys = mir_keys; + *providers = Providers { + mir_build, + mir_keys, + ..*providers + }; } fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) @@ -95,8 +98,7 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) Rc::new(set) } -fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> &'tcx RefCell> { +fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell> { 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); @@ -192,7 +194,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) @@ -251,7 +253,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 62b480494c3ec..a76ba8a8b688c 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -11,14 +11,15 @@ //! This pass just dumps MIR at a specified point. use std::borrow::Cow; +use std::cell::RefCell; use std::fmt; use std::fs::File; use std::io; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; -use rustc::mir::transform::{DefIdPass, Pass, PassHook, MirSource}; +use rustc::mir::Mir; +use rustc::mir::transform::{DefIdPass, PassHook, MirCtxt}; use util as mir_util; pub struct Marker(pub &'static str); @@ -28,8 +29,8 @@ impl DefIdPass for Marker { Cow::Borrowed(self.0) } - fn run_pass<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>, _: DefId) { - // no-op + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + mir_cx.steal_previous_mir() } } @@ -47,30 +48,31 @@ impl fmt::Display for Disambiguator { pub struct DumpMir; impl PassHook for DumpMir { - fn on_mir_pass<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - pass_num: usize, - is_after: bool) + fn on_mir_pass<'a, 'tcx: 'a>(&self, + mir_cx: &MirCtxt<'a, 'tcx>, + mir: Option<&Mir<'tcx>>) { - // No dump filters enabled. - if tcx.sess.opts.debugging_opts.dump_mir.is_none() { - return; - } - - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let source = MirSource::from_node(tcx, id); - let mir = tcx.item_mir(def_id); - mir_util::dump_mir( - tcx, - pass_num, - &pass_name, - &Disambiguator { is_after }, - source, - &mir - ); + let tcx = mir_cx.tcx(); + let pass_set = mir_cx.pass_set(); + let pass_num = mir_cx.pass_num(); + let pass = tcx.mir_passes.pass(pass_set, pass_num); + let name = &pass.name(); + let source = mir_cx.source(); + if mir_util::dump_enabled(tcx, name, source) { + let previous_mir; + let mir_to_dump = match mir { + Some(m) => m, + None => { + previous_mir = mir_cx.read_previous_mir(); + &*previous_mir + } + }; + mir_util::dump_mir(tcx, + Some((pass_set, pass_num)), + name, + &Disambiguator { is_after: mir.is_some() }, + source, + mir_to_dump); } } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index b0a067063dd60..6eda2f5abb9d8 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -27,6 +27,7 @@ use rustc::util::nodemap::{DefIdSet}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; +use std::cell::{Ref, RefCell}; use syntax::{attr}; use syntax::abi::Abi; @@ -74,6 +75,14 @@ struct CallSite<'tcx> { } impl<'a, 'tcx> Inliner<'a, 'tcx> { + fn maybe_item_mir(&mut self, _def_id: DefId) -> Option>> { + panic!() // TODO -- hook up inline into the system + } + + fn mir(&mut self, _def_id: DefId) -> &'tcx RefCell> { + panic!() // TODO -- hook up inline into the system + } + fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool { let mut callsites = Vec::new(); let mut in_scc = DefIdSet(); @@ -146,7 +155,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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 let Some(callee_mir) = self.maybe_item_mir(callsite.callee) { if !self.should_inline(callsite, &callee_mir) { continue; } @@ -158,7 +167,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; - let mut caller_mir = self.tcx.mir(callsite.caller).borrow_mut(); + let mut caller_mir = self.mir(callsite.caller).borrow_mut(); let start = caller_mir.basic_blocks().len(); @@ -210,7 +219,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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 = self.tcx.mir(def_id).borrow_mut(); + let mut caller_mir = self.mir(def_id).borrow_mut(); debug!("Running simplify cfg on {:?}", def_id); CfgSimplifier::new(&mut caller_mir).simplify(); diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index cbd054a72499b..68070ded12d98 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,6 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::hir::def_id::DefId; +use rustc::mir::Mir; +use rustc::mir::transform::{MirCtxt, MirPassIndex, MirPassSet, MirSource, MIR_OPTIMIZED}; +use rustc::ty::TyCtxt; +use rustc::ty::maps::Providers; +use std::cell::{Ref, RefCell}; +use std::mem; + pub mod simplify_branches; pub mod simplify; pub mod erase_regions; @@ -21,3 +29,101 @@ pub mod deaggregator; pub mod instcombine; pub mod copy_prop; pub mod inline; + +pub fn provide(providers: &mut Providers) { + self::qualify_consts::provide(providers); + *providers = Providers { + optimized_mir, + mir_pass_set, + mir_pass, + ..*providers + }; +} + +fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell> { + let mir = tcx.mir_pass_set((MIR_OPTIMIZED, def_id)); + + // "lock" the ref cell into read mode; after this point, + // there ought to be no more changes to the MIR. + mem::drop(mir.borrow()); + + mir +} + +fn mir_pass_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (pass_set, def_id): (MirPassSet, DefId)) + -> &'tcx RefCell> +{ + let passes = &tcx.mir_passes; + let len = passes.len_passes(pass_set); + assert!(len > 0, "no passes in {:?}", pass_set); + tcx.mir_pass((pass_set, MirPassIndex(len - 1), def_id)) +} + +fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (pass_set, pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) + -> &'tcx RefCell> +{ + let passes = &tcx.mir_passes; + let pass = passes.pass(pass_set, pass_num); + let mir_ctxt = MirCtxtImpl { tcx, pass_num, pass_set, def_id }; + + for hook in passes.hooks() { + hook.on_mir_pass(&mir_ctxt, None); + } + + let mir = pass.run_pass(&mir_ctxt); + + for hook in passes.hooks() { + hook.on_mir_pass(&mir_ctxt, Some(&mir.borrow())); + } + + mir +} + +struct MirCtxtImpl<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: MirPassIndex, + pass_set: MirPassSet, + def_id: DefId +} + +impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + fn pass_set(&self) -> MirPassSet { + self.pass_set + } + + fn pass_num(&self) -> MirPassIndex { + self.pass_num + } + + fn def_id(&self) -> DefId { + self.def_id + } + + fn source(&self) -> MirSource { + let id = self.tcx.hir.as_local_node_id(self.def_id) + .expect("mir source requires local def-id"); + MirSource::from_node(self.tcx, id) + } + + fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> { + self.steal_previous_mir().borrow() + } + + fn steal_previous_mir(&self) -> &'tcx RefCell> { + let MirPassSet(pass_set) = self.pass_set; + let MirPassIndex(pass_num) = self.pass_num; + if pass_num > 0 { + self.tcx.mir_pass((MirPassSet(pass_set), MirPassIndex(pass_num - 1), self.def_id)) + } else if pass_set > 0 { + self.tcx.mir_pass_set((MirPassSet(pass_set - 1), self.def_id)) + } else { + self.tcx.mir_build(self.def_id) + } + } +} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 80ec83fcaefb0..cb002acf009d1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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,13 +26,14 @@ use rustc::ty::cast::CastTy; use rustc::ty::maps::Providers; use rustc::mir::*; use rustc::mir::traversal::ReversePostorder; -use rustc::mir::transform::{DefIdPass, MirSource}; +use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, MIR_CONST}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::middle::lang_items; use syntax::abi::Abi; use syntax::feature_gate::UnstableFeatures; use syntax_pos::{Span, DUMMY_SP}; +use std::cell::RefCell; use std::fmt; use std::usize; @@ -925,7 +925,7 @@ pub fn provide(providers: &mut Providers) { fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> u8 { - let mir = &tcx.item_mir(def_id); + let mir = &tcx.mir_pass_set((MIR_CONST, def_id)).borrow(); if mir.return_ty.references_error() { return Qualif::NOT_CONST.bits(); } @@ -940,30 +940,32 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct QualifyAndPromoteConstants; impl DefIdPass for QualifyAndPromoteConstants { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - { - 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); - return; - } - - let mir = &mut tcx.mir(def_id).borrow_mut(); - tcx.dep_graph.write(DepNode::Mir(def_id)); + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + let tcx = mir_cx.tcx(); + match mir_cx.source() { + MirSource::Const(_) => { + // Ensure that we compute the `mir_const_qualif` for + // constants at this point, before we do any further + // optimization (and before we steal the previous + // MIR). + tcx.mir_const_qualif(mir_cx.def_id()); + mir_cx.steal_previous_mir() + } - self.run_pass(tcx, src, mir); + src => { + let mir = mir_cx.steal_previous_mir(); + self.run_pass(tcx, src, &mut mir.borrow_mut()); + mir + } + } } } impl<'a, 'tcx> QualifyAndPromoteConstants { fn run_pass(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'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 { diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index cafc5bca76acd..4386bab38c039 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -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; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 6c637f2b2a9d6..e8fc70b74bcb7 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -11,7 +11,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::*; -use rustc::mir::transform::MirSource; +use rustc::mir::transform::{MirPassSet, MirPassIndex, MirSource}; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{Idx}; @@ -39,29 +39,18 @@ 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: usize, + pass_num: Option<(MirPassSet, MirPassIndex)>, pass_name: &str, disambiguator: &Display, source: MirSource, mir: &Mir<'tcx>) { - let filters = match tcx.sess.opts.debugging_opts.dump_mir { - None => return, - Some(ref filters) => filters, - }; - let node_id = source.item_id(); - let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id)); - let 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; } - dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, source, mir); + 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, @@ -69,8 +58,26 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +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: usize, + pass_num: Option<(MirPassSet, MirPassIndex)>, pass_name: &str, node_path: &str, disambiguator: &Display, @@ -84,7 +91,10 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { format!("") } else { - format!(".{:03}", pass_num) + match pass_num { + None => format!(".-------"), + Some((pass_set, pass_num)) => format!(".{:03}-{:03}", pass_set.0, pass_num.0), + } }; let mut file_path = PathBuf::new(); From e89a321dff569fcc04b9249f7dac589c307e36ed Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 04:49:09 -0400 Subject: [PATCH 15/42] rename `MirPassSet` to `MirSuite` This seems like a better noun. --- src/librustc/mir/transform.rs | 30 ++++++++++++------------ src/librustc/ty/maps.rs | 24 +++++++++---------- src/librustc_mir/transform/mod.rs | 38 +++++++++++++++---------------- src/librustc_mir/util/pretty.rs | 6 ++--- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 9fab6564d9b00..7c9b86651976c 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -94,7 +94,7 @@ pub fn default_name() -> Cow<'static, str> { pub trait MirCtxt<'a, 'tcx: 'a> { fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; fn def_id(&self) -> DefId; - fn pass_set(&self) -> MirPassSet; + fn suite(&self) -> MirSuite; fn pass_num(&self) -> MirPassIndex; fn source(&self) -> MirSource; fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>; @@ -102,7 +102,7 @@ pub trait MirCtxt<'a, 'tcx: 'a> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct MirPassSet(pub usize); +pub struct MirSuite(pub usize); #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct MirPassIndex(pub usize); @@ -174,36 +174,36 @@ impl DefIdPass for T { #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, - sets: Vec>>, + suites: Vec>>, } -/// The number of "pass sets" that we have: +/// The number of "pass suites" that we have: /// /// - ready for constant evaluation /// - unopt /// - optimized -pub const MIR_PASS_SETS: usize = 3; +pub const MIR_SUITES: usize = 3; /// Run the passes we need to do constant qualification and evaluation. -pub const MIR_CONST: MirPassSet = MirPassSet(0); +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: MirPassSet = MirPassSet(1); +pub const MIR_VALIDATED: MirSuite = MirSuite(1); /// Run the passes we need to consider the MIR *optimized*. -pub const MIR_OPTIMIZED: MirPassSet = MirPassSet(2); +pub const MIR_OPTIMIZED: MirSuite = MirSuite(2); impl<'a, 'tcx> Passes { pub fn new() -> Passes { Passes { pass_hooks: Vec::new(), - sets: (0..MIR_PASS_SETS).map(|_| Vec::new()).collect(), + suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(), } } /// Pushes a built-in pass. - pub fn push_pass(&mut self, set: MirPassSet, pass: T) { - self.sets[set.0].push(Rc::new(pass)); + pub fn push_pass(&mut self, suite: MirSuite, pass: T) { + self.suites[suite.0].push(Rc::new(pass)); } /// Pushes a pass hook. @@ -211,12 +211,12 @@ impl<'a, 'tcx> Passes { self.pass_hooks.push(Rc::new(hook)); } - pub fn len_passes(&self, set: MirPassSet) -> usize { - self.sets[set.0].len() + pub fn len_passes(&self, suite: MirSuite) -> usize { + self.suites[suite.0].len() } - pub fn pass(&self, set: MirPassSet, pass: MirPassIndex) -> &DefIdPass { - &*self.sets[set.0][pass.0] + pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass { + &*self.suites[suite.0][pass.0] } pub fn hooks(&self) -> &[Rc] { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index dc70dcc81162f..58a38cc903d3c 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,7 +16,7 @@ use middle::const_val; use middle::privacy::AccessLevels; use middle::region::RegionMaps; use mir; -use mir::transform::{MirPassSet, MirPassIndex}; +use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::item_path; @@ -102,7 +102,7 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { } } -impl Key for (MirPassSet, DefId) { +impl Key for (MirSuite, DefId) { fn map_crate(&self) -> CrateNum { self.1.map_crate() } @@ -111,7 +111,7 @@ impl Key for (MirPassSet, DefId) { } } -impl Key for (MirPassSet, MirPassIndex, DefId) { +impl Key for (MirSuite, MirPassIndex, DefId) { fn map_crate(&self) -> CrateNum { self.2.map_crate() } @@ -337,14 +337,14 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> { } } -impl<'tcx> QueryDescription for queries::mir_pass_set<'tcx> { - fn describe(_: TyCtxt, (pass_set, _): (MirPassSet, DefId)) -> String { - format!("MIR passes #{}.*", pass_set.0) +impl<'tcx> QueryDescription for queries::mir_suite<'tcx> { + fn describe(_: TyCtxt, (suite, _): (MirSuite, DefId)) -> String { + format!("MIR passes #{}.*", suite.0) } } impl<'tcx> QueryDescription for queries::mir_pass<'tcx> { - fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirPassSet, MirPassIndex, DefId)) -> String { + fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String { format!("MIR pass #{}.{}", pass_set.0, pass_num.0) } } @@ -592,12 +592,12 @@ define_maps! { <'tcx> /// applied to it. This is mostly an "intermediate" query. Normally, you would /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all /// optimizations and so forth. - [] mir_pass_set: mir_pass_set((MirPassSet, DefId)) -> &'tcx RefCell>, + [] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx RefCell>, /// Fetch the MIR for a given def-id after a given pass has been executed. This is - /// **only** intended to be used by the `mir_pass_set` provider -- if you are using it + /// **only** intended to be used by the `mir_suite` provider -- if you are using it /// manually, you're doing it wrong. - [] mir_pass: mir_pass((MirPassSet, MirPassIndex, DefId)) -> &'tcx RefCell>, + [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx RefCell>, /// 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. @@ -701,10 +701,10 @@ fn mir_keys(_: CrateNum) -> DepNode { DepNode::MirKeys } -fn mir_pass_set((_pass_set, def_id): (MirPassSet, DefId)) -> DepNode { +fn mir_suite((_suite, def_id): (MirSuite, DefId)) -> DepNode { DepNode::Mir(def_id) } -fn mir_pass((_pass_set, _pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) -> DepNode { +fn mir_pass((_suite, _pass_num, def_id): (MirSuite, MirPassIndex, DefId)) -> DepNode { DepNode::Mir(def_id) } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 68070ded12d98..49cb254cdf289 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -10,7 +10,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{MirCtxt, MirPassIndex, MirPassSet, MirSource, MIR_OPTIMIZED}; +use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED}; use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use std::cell::{Ref, RefCell}; @@ -34,14 +34,14 @@ pub fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); *providers = Providers { optimized_mir, - mir_pass_set, + mir_suite, mir_pass, ..*providers }; } fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell> { - let mir = tcx.mir_pass_set((MIR_OPTIMIZED, def_id)); + let mir = tcx.mir_suite((MIR_OPTIMIZED, def_id)); // "lock" the ref cell into read mode; after this point, // there ought to be no more changes to the MIR. @@ -50,23 +50,23 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx mir } -fn mir_pass_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - (pass_set, def_id): (MirPassSet, DefId)) - -> &'tcx RefCell> +fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (suite, def_id): (MirSuite, DefId)) + -> &'tcx RefCell> { let passes = &tcx.mir_passes; - let len = passes.len_passes(pass_set); - assert!(len > 0, "no passes in {:?}", pass_set); - tcx.mir_pass((pass_set, MirPassIndex(len - 1), def_id)) + let len = passes.len_passes(suite); + assert!(len > 0, "no passes in {:?}", suite); + tcx.mir_pass((suite, MirPassIndex(len - 1), def_id)) } fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - (pass_set, pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) + (suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId)) -> &'tcx RefCell> { let passes = &tcx.mir_passes; - let pass = passes.pass(pass_set, pass_num); - let mir_ctxt = MirCtxtImpl { tcx, pass_num, pass_set, def_id }; + let pass = passes.pass(suite, pass_num); + let mir_ctxt = MirCtxtImpl { tcx, pass_num, suite, def_id }; for hook in passes.hooks() { hook.on_mir_pass(&mir_ctxt, None); @@ -84,7 +84,7 @@ fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, struct MirCtxtImpl<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, pass_num: MirPassIndex, - pass_set: MirPassSet, + suite: MirSuite, def_id: DefId } @@ -93,8 +93,8 @@ impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { self.tcx } - fn pass_set(&self) -> MirPassSet { - self.pass_set + fn suite(&self) -> MirSuite { + self.suite } fn pass_num(&self) -> MirPassIndex { @@ -116,12 +116,12 @@ impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { } fn steal_previous_mir(&self) -> &'tcx RefCell> { - let MirPassSet(pass_set) = self.pass_set; + let MirSuite(suite) = self.suite; let MirPassIndex(pass_num) = self.pass_num; if pass_num > 0 { - self.tcx.mir_pass((MirPassSet(pass_set), MirPassIndex(pass_num - 1), self.def_id)) - } else if pass_set > 0 { - self.tcx.mir_pass_set((MirPassSet(pass_set - 1), self.def_id)) + self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), self.def_id)) + } else if suite > 0 { + self.tcx.mir_suite((MirSuite(suite - 1), self.def_id)) } else { self.tcx.mir_build(self.def_id) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index e8fc70b74bcb7..c3a30f7b88213 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -11,7 +11,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::*; -use rustc::mir::transform::{MirPassSet, MirPassIndex, 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}; @@ -39,7 +39,7 @@ 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<(MirPassSet, MirPassIndex)>, + pass_num: Option<(MirSuite, MirPassIndex)>, pass_name: &str, disambiguator: &Display, source: MirSource, @@ -77,7 +77,7 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirPassSet, MirPassIndex)>, + pass_num: Option<(MirSuite, MirPassIndex)>, pass_name: &str, node_path: &str, disambiguator: &Display, From 29263fdb541fe5d59ef116ebf3666cd573d077ab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 06:00:48 -0400 Subject: [PATCH 16/42] introduce idea of "stealable" MIR This is a more principled version of the `RefCell` we were using before. We now allocate a `Steal>` for each intermediate MIR pass; when the next pass steals the entry, any later attempts to use it will panic (there is no way to *test* if MIR is stolen, you're just supposed to *know*). --- src/librustc/mir/transform.rs | 14 ++++----- src/librustc/ty/context.rs | 13 ++++++-- src/librustc/ty/maps.rs | 19 +++++------ src/librustc/ty/mod.rs | 13 ++++---- src/librustc/ty/steal.rs | 27 ++++++++++++++++ src/librustc_metadata/cstore_impl.rs | 4 --- src/librustc_mir/mir_map.rs | 10 +++--- src/librustc_mir/shim.rs | 6 +--- src/librustc_mir/transform/dump_mir.rs | 9 +++--- src/librustc_mir/transform/mod.rs | 33 ++++++++++---------- src/librustc_mir/transform/qualify_consts.rs | 9 +++--- src/librustc_mir/util/pretty.rs | 2 +- 12 files changed, 93 insertions(+), 66 deletions(-) create mode 100644 src/librustc/ty/steal.rs diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 7c9b86651976c..80a4d9a9ff15b 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -13,7 +13,7 @@ use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; -use std::cell::{Ref, RefCell}; +use std::cell::Ref; use std::rc::Rc; use syntax::ast::NodeId; @@ -98,7 +98,7 @@ pub trait MirCtxt<'a, 'tcx: 'a> { fn pass_num(&self) -> MirPassIndex; fn source(&self) -> MirSource; fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>; - fn steal_previous_mir(&self) -> &'tcx RefCell>; + fn steal_previous_mir(&self) -> Mir<'tcx>; } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -132,7 +132,7 @@ pub trait DefIdPass { default_name::() } - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell>; + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>; } /// A streamlined trait that you can implement to create a pass; the @@ -154,14 +154,14 @@ impl DefIdPass for T { MirPass::name(self) } - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { let tcx = mir_cx.tcx(); let source = mir_cx.source(); - let mir = mir_cx.steal_previous_mir(); - MirPass::run_pass(self, tcx, source, &mut mir.borrow_mut()); + let mut mir = mir_cx.steal_previous_mir(); + MirPass::run_pass(self, tcx, source, &mut mir); let item_id = source.item_id(); - for (promoted_index, promoted_mir) in mir.borrow_mut().promoted.iter_enumerated_mut() { + for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() { let promoted_source = MirSource::Promoted(item_id, promoted_index); MirPass::run_pass(self, tcx, promoted_source, promoted_mir); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0c189853c6195..0dd23eb7e700c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -40,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; @@ -70,7 +71,8 @@ pub struct GlobalArenas<'tcx> { generics: TypedArena, trait_def: TypedArena, adt_def: TypedArena, - mir: TypedArena>>, + steal_mir: TypedArena>>, + mir: TypedArena>, tables: TypedArena>, } @@ -81,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(), } @@ -622,8 +625,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> { - self.global_arenas.mir.alloc(RefCell::new(mir)) + pub fn alloc_steal_mir(self, mir: Mir<'gcx>) -> &'gcx Steal> { + 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> { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 58a38cc903d3c..09bdca4915a18 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -20,6 +20,7 @@ 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::{DefIdSet, NodeSet}; @@ -32,7 +33,7 @@ use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use syntax::symbol::Symbol; -trait Key { +trait Key: Clone { fn map_crate(&self) -> CrateNum; fn default_span(&self, tcx: TyCtxt) -> Span; } @@ -339,13 +340,13 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> { impl<'tcx> QueryDescription for queries::mir_suite<'tcx> { fn describe(_: TyCtxt, (suite, _): (MirSuite, DefId)) -> String { - format!("MIR passes #{}.*", suite.0) + format!("MIR suite #{}.*", suite.0) } } impl<'tcx> QueryDescription for queries::mir_pass<'tcx> { - fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String { - format!("MIR pass #{}.{}", pass_set.0, pass_num.0) + fn describe(_: TyCtxt, (suite, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String { + format!("MIR pass #{}.{}", suite.0, pass_num.0) } } @@ -586,22 +587,22 @@ define_maps! { <'tcx> /// Performs the initial MIR construction. You almost certainly do not /// want to use this query, because its output is intended to be stolen /// immediately by the MIR passes below. Consider `optimized_mir` instead. - [] mir_build: Mir(DefId) -> &'tcx RefCell>, + [] mir_build: Mir(DefId) -> &'tcx Steal>, /// Fetch the MIR for a given def-id after the given set of passes has ben /// applied to it. This is mostly an "intermediate" query. Normally, you would /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all /// optimizations and so forth. - [] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx RefCell>, + [] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx Steal>, /// Fetch the MIR for a given def-id after a given pass has been executed. This is /// **only** intended to be used by the `mir_suite` provider -- if you are using it /// manually, you're doing it wrong. - [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx RefCell>, + [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, /// 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 RefCell>, + [] 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. @@ -650,7 +651,7 @@ define_maps! { <'tcx> /// fn item. [] region_maps: RegionMaps(DefId) -> Rc>, - [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell>, + [] 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, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index cf66c83800d36..537846bc0f477 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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; @@ -2324,13 +2325,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Given the did of an item, returns its (optimized) MIR, borrowed immutably. - pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - self.optimized_mir(did).borrow() + pub fn item_mir(self, did: DefId) -> &'gcx Mir<'gcx> { + self.optimized_mir(did) } /// 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) => { @@ -2341,14 +2342,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) => { - self.mir_shims(instance).borrow() + 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>> { + pub fn maybe_item_mir(self, did: DefId) -> Option<&'gcx Mir<'gcx>> { if did.is_local() && !self.mir_keys(LOCAL_CRATE).contains(&did) { return None; } diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs new file mode 100644 index 0000000000000..0da937d036648 --- /dev/null +++ b/src/librustc/ty/steal.rs @@ -0,0 +1,27 @@ +use std::cell::{Ref, RefCell}; +use std::mem; + +pub struct Steal { + value: RefCell> +} + +impl Steal { + pub fn new(value: T) -> Self { + Steal { + value: RefCell::new(Some(value)) + } + } + + pub fn borrow(&self) -> Ref { + Ref::map(self.value.borrow(), |opt| match *opt { + None => panic!("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") + } +} diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 4ecce3cc132fe..7bc27596e40e7 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -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; @@ -102,9 +101,6 @@ provide! { <'tcx> tcx, def_id, cdata 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) } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 46f7c34c06e8d..e51a7a410e026 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -29,6 +29,7 @@ use util as mir_util; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; +use rustc::ty::steal::Steal; use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -37,7 +38,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; -use std::cell::RefCell; use std::mem; use std::rc::Rc; @@ -98,7 +98,7 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) Rc::new(set) } -fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell> { +fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { 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); @@ -196,7 +196,7 @@ fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefC mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - tcx.alloc_mir(mir) + tcx.alloc_steal_mir(mir) }) } @@ -233,7 +233,7 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ctor_id: ast::NodeId, v: &'tcx hir::VariantData) - -> &'tcx RefCell> + -> &'tcx Steal> { let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { @@ -255,7 +255,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - tcx.alloc_mir(mir) + tcx.alloc_steal_mir(mir) }) } else { span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index f2a550ec23a8e..a899c69ca150a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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> + -> &'tcx Mir<'tcx> { debug!("make_shim({:?})", instance); let did = instance.def_id(); @@ -117,8 +115,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, debug!("make_shim({:?}) = {:?}", instance, result); let result = tcx.alloc_mir(result); - // Perma-borrow MIR from shims to prevent mutation. - mem::forget(result.borrow()); result } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index a76ba8a8b688c..c00817f9179a6 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -11,7 +11,6 @@ //! This pass just dumps MIR at a specified point. use std::borrow::Cow; -use std::cell::RefCell; use std::fmt; use std::fs::File; use std::io; @@ -29,7 +28,7 @@ impl DefIdPass for Marker { Cow::Borrowed(self.0) } - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { mir_cx.steal_previous_mir() } } @@ -53,9 +52,9 @@ impl PassHook for DumpMir { mir: Option<&Mir<'tcx>>) { let tcx = mir_cx.tcx(); - let pass_set = mir_cx.pass_set(); + let suite = mir_cx.suite(); let pass_num = mir_cx.pass_num(); - let pass = tcx.mir_passes.pass(pass_set, pass_num); + let pass = tcx.mir_passes.pass(suite, pass_num); let name = &pass.name(); let source = mir_cx.source(); if mir_util::dump_enabled(tcx, name, source) { @@ -68,7 +67,7 @@ impl PassHook for DumpMir { } }; mir_util::dump_mir(tcx, - Some((pass_set, pass_num)), + Some((suite, pass_num)), name, &Disambiguator { is_after: mir.is_some() }, source, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 49cb254cdf289..d30495efab571 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -11,10 +11,10 @@ use rustc::hir::def_id::DefId; use rustc::mir::Mir; use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED}; +use rustc::ty::steal::Steal; use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; -use std::cell::{Ref, RefCell}; -use std::mem; +use std::cell::Ref; pub mod simplify_branches; pub mod simplify; @@ -40,19 +40,14 @@ pub fn provide(providers: &mut Providers) { }; } -fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell> { - let mir = tcx.mir_suite((MIR_OPTIMIZED, def_id)); - - // "lock" the ref cell into read mode; after this point, - // there ought to be no more changes to the MIR. - mem::drop(mir.borrow()); - - mir +fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> { + let mir = tcx.mir_suite((MIR_OPTIMIZED, def_id)).steal(); + tcx.alloc_mir(mir) } fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (suite, def_id): (MirSuite, DefId)) - -> &'tcx RefCell> + -> &'tcx Steal> { let passes = &tcx.mir_passes; let len = passes.len_passes(suite); @@ -62,7 +57,7 @@ fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId)) - -> &'tcx RefCell> + -> &'tcx Steal> { let passes = &tcx.mir_passes; let pass = passes.pass(suite, pass_num); @@ -75,10 +70,10 @@ fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mir = pass.run_pass(&mir_ctxt); for hook in passes.hooks() { - hook.on_mir_pass(&mir_ctxt, Some(&mir.borrow())); + hook.on_mir_pass(&mir_ctxt, Some(&mir)); } - mir + tcx.alloc_steal_mir(mir) } struct MirCtxtImpl<'a, 'tcx: 'a> { @@ -112,10 +107,16 @@ impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { } fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> { - self.steal_previous_mir().borrow() + self.previous_mir().borrow() } - fn steal_previous_mir(&self) -> &'tcx RefCell> { + fn steal_previous_mir(&self) -> Mir<'tcx> { + self.previous_mir().steal() + } +} + +impl<'a, 'tcx> MirCtxtImpl<'a, 'tcx> { + fn previous_mir(&self) -> &'tcx Steal> { let MirSuite(suite) = self.suite; let MirPassIndex(pass_num) = self.pass_num; if pass_num > 0 { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cb002acf009d1..8fc264ac1d49b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -33,7 +33,6 @@ use syntax::abi::Abi; use syntax::feature_gate::UnstableFeatures; use syntax_pos::{Span, DUMMY_SP}; -use std::cell::RefCell; use std::fmt; use std::usize; @@ -925,7 +924,7 @@ pub fn provide(providers: &mut Providers) { fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> u8 { - let mir = &tcx.mir_pass_set((MIR_CONST, def_id)).borrow(); + let mir = &tcx.mir_suite((MIR_CONST, def_id)).borrow(); if mir.return_ty.references_error() { return Qualif::NOT_CONST.bits(); } @@ -940,7 +939,7 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct QualifyAndPromoteConstants; impl DefIdPass for QualifyAndPromoteConstants { - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell> { + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { let tcx = mir_cx.tcx(); match mir_cx.source() { MirSource::Const(_) => { @@ -953,8 +952,8 @@ impl DefIdPass for QualifyAndPromoteConstants { } src => { - let mir = mir_cx.steal_previous_mir(); - self.run_pass(tcx, src, &mut mir.borrow_mut()); + let mut mir = mir_cx.steal_previous_mir(); + self.run_pass(tcx, src, &mut mir); mir } } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index c3a30f7b88213..4f94c4d122bad 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -93,7 +93,7 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } else { match pass_num { None => format!(".-------"), - Some((pass_set, pass_num)) => format!(".{:03}-{:03}", pass_set.0, pass_num.0), + Some((suite, pass_num)) => format!(".{:03}-{:03}", suite.0, pass_num.0), } }; From ecc8ff9199118b88e98c903c9117fa2f0cddf8ab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 09:40:48 -0400 Subject: [PATCH 17/42] rework macro to prepare for more modifiers than just `[pub]` --- src/librustc/ty/maps.rs | 45 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 09bdca4915a18..e653392e3fb52 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -353,11 +353,11 @@ impl<'tcx> QueryDescription for queries::mir_pass<'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>, - query_stack: RefCell)>>, - $($(#[$attr])* $($pub)* $name: RefCell>>),* + [$($modifiers:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { + define_map_struct! { + tcx: $tcx, + input: ($(([$($attr)*] [$($modifiers)*] $name))*), + output: () } impl<$tcx> Maps<$tcx> { @@ -519,6 +519,41 @@ macro_rules! define_maps { } } +macro_rules! define_map_struct { + (tcx: $tcx:tt, + input: (), + output: ($($output:tt)*)) => { + pub struct Maps<$tcx> { + providers: IndexVec>, + query_stack: RefCell)>>, + $($output)* + } + }; + + // Detect things with the `pub` modifier + (tcx: $tcx:tt, + input: (([$($attr:meta)*] [pub] $name:ident) $($input:tt)*), + output: ($($output:tt)*)) => { + define_map_struct! { + tcx: $tcx, + input: ($($input)*), + output: ($($output)* + $(#[$attr])* pub $name: RefCell>>,) + } + }; + + (tcx: $tcx:tt, + input: (([$($attr:meta)*] [$($modifiers:tt)*] $name:ident) $($input:tt)*), + output: ($($output:tt)*)) => { + define_map_struct! { + tcx: $tcx, + input: ($($input)*), + output: ($($output)* + $(#[$attr])* $name: RefCell>>,) + } + }; +} + // Each of these maps also corresponds to a method on a // `Provider` trait for requesting a value of that type, // and a method on `Maps` itself for doing that in a From 3d1095c5bea7bbdc4b150425482ac4d526a4bb76 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 09:41:01 -0400 Subject: [PATCH 18/42] introduce `IntoKeyValues` trait to prepare for multi-queries The idea is that such queries will return `FxHashMap` --- src/librustc/ty/maps.rs | 42 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index e653392e3fb52..f2bfd23b18940 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,8 +24,12 @@ use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, NodeSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; +use std::fmt::Debug; +use std::hash::Hash; +use std::iter::{self, Once}; use std::mem; use std::collections::BTreeMap; use std::ops::Deref; @@ -33,7 +37,7 @@ use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use syntax::symbol::Symbol; -trait Key: Clone { +trait Key: Clone + Hash + Eq + Debug { fn map_crate(&self) -> CrateNum; fn default_span(&self, tcx: TyCtxt) -> Span; } @@ -156,6 +160,33 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { } } +trait IntoKeyValues { + type KeyValues: IntoIterator; + + fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self::KeyValues; +} + +impl IntoKeyValues for V { + type KeyValues = Once<(K, V)>; + + fn into_key_values(_: TyCtxt, key: &K, value: Self) -> Self::KeyValues { + iter::once((key.clone(), value)) + } +} + +impl IntoKeyValues for FxHashMap { + type KeyValues = Self; + + fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self { + if !value.contains_key(key) { + span_bug!(key.default_span(tcx), + "multi-generation function for `{:?}` did not generate a value for `{:?}`", + key, key) + } + value + } +} + pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -437,7 +468,14 @@ macro_rules! define_maps { provider(tcx.global_tcx(), key) })?; - Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result))) + { + let map = &mut *tcx.maps.$name.borrow_mut(); + for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(tcx, &key, result) { + map.insert(k, v); + } + } + + Ok(f(tcx.maps.$name.borrow().get(&key).expect("value just generated"))) } pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) From 1d675ce0a3e323b390bdbd7c8b5bdf80909ca6a1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 12:09:15 -0400 Subject: [PATCH 19/42] adjust the macro to allow for `multi` modifier --- src/librustc/lib.rs | 3 + src/librustc/ty/maps.rs | 129 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a3e5a14dbac7f..d3954326e7b72 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index f2bfd23b18940..dff58d78f8235 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -387,8 +387,7 @@ macro_rules! define_maps { [$($modifiers:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { define_map_struct! { tcx: $tcx, - input: ($(([$($attr)*] [$($modifiers)*] $name))*), - output: () + input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) } impl<$tcx> Maps<$tcx> { @@ -536,8 +535,10 @@ 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> {} @@ -558,6 +559,17 @@ macro_rules! define_maps { } 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)*)) => { @@ -568,26 +580,121 @@ macro_rules! define_map_struct { } }; - // Detect things with the `pub` modifier + // Field recognized and ready to shift into the output (tcx: $tcx:tt, - input: (([$($attr:meta)*] [pub] $name:ident) $($input:tt)*), + ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]), + input: $input:tt, output: ($($output:tt)*)) => { define_map_struct! { tcx: $tcx, - input: ($($input)*), + input: $input, output: ($($output)* - $(#[$attr])* pub $name: RefCell>>,) + $(#[$attr])* $($pub)* $name: RefCell>>,) } }; + // Detect things with the `pub` modifier (tcx: $tcx:tt, - input: (([$($attr:meta)*] [$($modifiers:tt)*] $name:ident) $($input:tt)*), - output: ($($output: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: ($($output:tt)*)) => { + pub struct Providers<$tcx> { + $($output)* + } + }; + + // Something ready to shift: + (tcx: $tcx:tt, + ready: ([$name:ident] [$K:ty] [$R:ty]), + input: $input:tt, + output: ($($output:tt)*)) => { + define_provider_struct! { + tcx: $tcx, + input: $input, output: ($($output)* - $(#[$attr])* $name: RefCell>>,) + pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,) + } + }; + + // The `multi` modifier indicates a **multiquery**, in which case + // the function returns a `FxHashMap` instead of just a value + // `V`. + (tcx: $tcx:tt, + input: (([multi $($other_modifiers:tt)*] $name:tt [$K:ty] [$V:ty]) $($input:tt)*), + output: $output:tt) => { + define_provider_struct! { + tcx: $tcx, + ready: ($name [$K] [FxHashMap<$K,$V>]), + input: ($($input)*), + output: $output + } + }; + + // 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 other than `multi`. + (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 } }; } From a26e966307226a62ad1e09247038182eb53053ab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 28 Apr 2017 19:29:16 -0400 Subject: [PATCH 20/42] convert the `inline` pass to use the new multi result This involves changing various details about that system, though the basic shape remains the same. --- src/librustc/mir/transform.rs | 72 +++++++++---- src/librustc/ty/maps.rs | 96 +++++++++++------ src/librustc_driver/driver.rs | 2 +- src/librustc_mir/callgraph.rs | 13 +-- src/librustc_mir/transform/dump_mir.rs | 20 ++-- src/librustc_mir/transform/inline.rs | 90 ++++++++-------- src/librustc_mir/transform/interprocedural.rs | 100 ++++++++++++++++++ src/librustc_mir/transform/mod.rs | 35 ++++-- 8 files changed, 311 insertions(+), 117 deletions(-) create mode 100644 src/librustc_mir/transform/interprocedural.rs diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 80a4d9a9ff15b..9718098aac8af 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -13,6 +13,8 @@ use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; +use ty::maps::Multi; +use ty::steal::Steal; use std::cell::Ref; use std::rc::Rc; use syntax::ast::NodeId; @@ -70,15 +72,6 @@ impl<'a, 'tcx> MirSource { } } -/// Various information about pass. -pub trait Pass { - fn name<'a>(&'a self) -> Cow<'a, str> { - default_name::() - } - - fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>); -} - /// Generates a default name for the pass based on the name of the /// type `T`. pub fn default_name() -> Cow<'static, str> { @@ -97,8 +90,20 @@ pub trait MirCtxt<'a, 'tcx: 'a> { fn suite(&self) -> MirSuite; fn pass_num(&self) -> MirPassIndex; fn source(&self) -> MirSource; + + // Get a read-only view on the MIR of this def-id from the + // previous pass. fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>; + + // Steal the MIR of this def-id from the previous pass; any future + // attempt to access the MIR from the previous pass is a bug. fn steal_previous_mir(&self) -> Mir<'tcx>; + + // Same as `read_previous_mir()`, but for any def-id you want. + fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>>; + + // Same as `steal_previous_mir()`, but for any def-id you want. + fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx>; } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -116,17 +121,35 @@ pub struct MirPassIndex(pub usize); /// `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). +/// 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, mir_cx: &MirCtxt<'a, 'tcx>, - mir: Option<&Mir<'tcx>>); + mir: Option<(DefId, &Mir<'tcx>)>); } -/// A streamlined trait that you can implement to create a pass; the -/// pass will be invoked to process the MIR with the given `def_id`. -/// This lets you do things before we fetch the MIR itself. You may -/// prefer `MirPass`. +/// The full suite of types that identifies a particular +/// application of a pass to a def-id. +pub type PassId = (MirSuite, MirPassIndex, DefId); + +/// The most generic sort of MIR pass. You only want to implement this +/// rather general trait if you are doing an interprocedural pass that +/// may inspect and affect the MIR of many def-ids. Otherwise, prefer +/// the more steamlined `DefIdPass` or `MirPass`. +pub trait Pass { + fn name<'a>(&'a self) -> Cow<'a, str> { + default_name::() + } + + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + -> Multi>>; +} + +/// A streamlined trait that you can implement to create an +/// intraprocedural pass; the pass will be invoked to process the MIR +/// with the given `def_id`. This lets you do things before we fetch +/// the MIR itself. You may prefer `MirPass`, which is even more streamlined. pub trait DefIdPass { fn name<'a>(&'a self) -> Cow<'a, str> { default_name::() @@ -135,10 +158,21 @@ pub trait DefIdPass { fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>; } +impl Pass for T { + fn name<'a>(&'a self) -> Cow<'a, str> { + DefIdPass::name(self) + } + + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + -> Multi>> { + Multi::from(mir_cx.tcx().alloc_steal_mir(DefIdPass::run_pass(self, mir_cx))) + } +} + /// 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: DepGraphSafe { +pub trait MirPass { fn name<'a>(&'a self) -> Cow<'a, str> { default_name::() } @@ -174,7 +208,7 @@ impl DefIdPass for T { #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, - suites: Vec>>, + suites: Vec>>, } /// The number of "pass suites" that we have: @@ -202,7 +236,7 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, suite: MirSuite, pass: T) { + pub fn push_pass(&mut self, suite: MirSuite, pass: T) { self.suites[suite.0].push(Rc::new(pass)); } @@ -215,7 +249,7 @@ impl<'a, 'tcx> Passes { self.suites[suite.0].len() } - pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass { + pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &Pass { &*self.suites[suite.0][pass.0] } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index dff58d78f8235..3541a19fe6b64 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,9 +24,9 @@ use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, NodeSet}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; +use std::option; use std::fmt::Debug; use std::hash::Hash; use std::iter::{self, Once}; @@ -34,10 +34,11 @@ use std::mem; use std::collections::BTreeMap; use std::ops::Deref; use std::rc::Rc; +use std::vec; use syntax_pos::{Span, DUMMY_SP}; use syntax::symbol::Symbol; -trait Key: Clone + Hash + Eq + Debug { +pub trait Key: Clone + Hash + Eq + Debug { fn map_crate(&self) -> CrateNum; fn default_span(&self, tcx: TyCtxt) -> Span; } @@ -163,27 +164,61 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { trait IntoKeyValues { type KeyValues: IntoIterator; - fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self::KeyValues; + fn into_key_values(key: &K, value: Self) -> Self::KeyValues; } impl IntoKeyValues for V { type KeyValues = Once<(K, V)>; - fn into_key_values(_: TyCtxt, key: &K, value: Self) -> Self::KeyValues { + fn into_key_values(key: &K, value: Self) -> Self::KeyValues { iter::once((key.clone(), value)) } } -impl IntoKeyValues for FxHashMap { - type KeyValues = Self; +/// Return type for a multi-query, which is a query which may (if it +/// chooses) return more than one (key, value) pair. Construct a +/// `Multi` using `Multi::from(...)`. +pub struct Multi { + single: Option, + map: Vec<(K, V)>, +} - fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self { - if !value.contains_key(key) { - span_bug!(key.default_span(tcx), - "multi-generation function for `{:?}` did not generate a value for `{:?}`", - key, key) +impl Multi { + pub fn iter<'a>(&'a self, key: &'a K) -> impl Iterator + 'a { + self.single.iter() + .map(move |v| (key, v)) + .chain(self.map.iter().map(move |&(ref k, ref v)| (k, v))) + } +} + +/// Construct a `Multi` from a single value. +impl From for Multi { + fn from(value: V) -> Self { + Multi { + single: Some(value), + map: vec![], } - value + } +} + +/// Construct a `Multi` from a hashmap of (K, V) pairs. +impl From> for Multi { + fn from(value: Vec<(K, V)>) -> Self { + Multi { + single: None, + map: value + } + } +} + +impl IntoKeyValues for Multi { + type KeyValues = iter::Chain, vec::IntoIter<(K, V)>>; + + fn into_key_values(key: &K, value: Self) -> Self::KeyValues { + value.single + .map(|v| (key.clone(), v)) + .into_iter() + .chain(value.map) } } @@ -469,7 +504,7 @@ macro_rules! define_maps { { let map = &mut *tcx.maps.$name.borrow_mut(); - for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(tcx, &key, result) { + for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(&key, result) { map.insert(k, v); } } @@ -545,16 +580,6 @@ macro_rules! define_maps { impl<$tcx> Clone for Providers<$tcx> { fn clone(&self) -> Self { *self } } - - impl<$tcx> Default for Providers<$tcx> { - fn default() -> Self { - $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V { - bug!("tcx.maps.{}({:?}) unsupported by its crate", - stringify!($name), key); - })* - Providers { $($name),* } - } - } } } @@ -642,34 +667,43 @@ macro_rules! define_provider_struct { // Final state: (tcx: $tcx:tt, input: (), - output: ($($output:tt)*)) => { + output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => { pub struct Providers<$tcx> { - $($output)* + $(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) -> $R { + bug!("tcx.maps.{}({:?}) unsupported by its crate", + stringify!($name), key); + })* + Providers { $($name),* } + } } }; // Something ready to shift: (tcx: $tcx:tt, - ready: ([$name:ident] [$K:ty] [$R:ty]), + ready: ($name:tt $K:tt $V:tt), input: $input:tt, output: ($($output:tt)*)) => { define_provider_struct! { tcx: $tcx, input: $input, - output: ($($output)* - pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,) + output: ($($output)* ($name $K $V)) } }; // The `multi` modifier indicates a **multiquery**, in which case - // the function returns a `FxHashMap` instead of just a value + // the function returns a `Multi` instead of just a value // `V`. (tcx: $tcx:tt, input: (([multi $($other_modifiers:tt)*] $name:tt [$K:ty] [$V:ty]) $($input:tt)*), output: $output:tt) => { define_provider_struct! { tcx: $tcx, - ready: ($name [$K] [FxHashMap<$K,$V>]), + ready: ($name [$K] [Multi<$K,$V>]), input: ($($input)*), output: $output } @@ -778,7 +812,7 @@ define_maps! { <'tcx> /// Fetch the MIR for a given def-id after a given pass has been executed. This is /// **only** intended to be used by the `mir_suite` provider -- if you are using it /// manually, you're doing it wrong. - [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, + [multi] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, /// 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. diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9b11d168e0077..cd6b5f62edd2c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -929,7 +929,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, 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); // TODO re-enable + 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); diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs index 961e202ba1c6d..ef271d8b836eb 100644 --- a/src/librustc_mir/callgraph.rs +++ b/src/librustc_mir/callgraph.rs @@ -22,21 +22,21 @@ use rustc::ty; use rustc::util::nodemap::DefIdMap; +use transform::interprocedural::InterproceduralCx; + pub struct CallGraph { node_map: DefIdMap, graph: graph::Graph } 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 { + pub fn build<'a, 'mir, 'tcx>(cx: &mut InterproceduralCx<'a, 'mir, 'tcx>) -> CallGraph { let mut callgraph = CallGraph { node_map: DefIdMap(), graph: graph::Graph::new() }; - for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { + for &def_id in cx.tcx.mir_keys(LOCAL_CRATE).iter() { let idx = callgraph.add_node(def_id); let mut call_visitor = CallVisitor { @@ -44,8 +44,9 @@ impl CallGraph { graph: &mut callgraph }; - let mir = tcx.item_mir(def_id); - call_visitor.visit_mir(&mir); + if let Some(mir) = cx.ensure_mir_and_read(def_id) { + call_visitor.visit_mir(mir); + } } callgraph diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index c00817f9179a6..b895a21558594 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -15,10 +15,11 @@ use std::fmt; use std::fs::File; use std::io; +use rustc::hir::def_id::DefId; +use rustc::mir::Mir; +use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, PassHook}; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; -use rustc::mir::Mir; -use rustc::mir::transform::{DefIdPass, PassHook, MirCtxt}; use util as mir_util; pub struct Marker(pub &'static str); @@ -48,19 +49,26 @@ pub struct DumpMir; impl PassHook for DumpMir { fn on_mir_pass<'a, 'tcx: 'a>(&self, - mir_cx: &MirCtxt<'a, 'tcx>, - mir: Option<&Mir<'tcx>>) + mir_cx: &MirCtxt<'a, 'tcx>, + mir: Option<(DefId, &Mir<'tcx>)>) { let tcx = mir_cx.tcx(); let suite = mir_cx.suite(); let pass_num = mir_cx.pass_num(); let pass = tcx.mir_passes.pass(suite, pass_num); let name = &pass.name(); - let source = mir_cx.source(); + let source = match mir { + None => mir_cx.source(), + Some((def_id, _)) => { + let id = tcx.hir.as_local_node_id(def_id) + .expect("mir source requires local def-id"); + MirSource::from_node(tcx, id) + } + }; if mir_util::dump_enabled(tcx, name, source) { let previous_mir; let mir_to_dump = match mir { - Some(m) => m, + Some((_, m)) => m, None => { previous_mir = mir_cx.read_previous_mir(); &*previous_mir diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 6eda2f5abb9d8..e10a91c6ec2e7 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,20 +18,22 @@ use rustc_data_structures::graph; use rustc::dep_graph::DepNode; use rustc::mir::*; -use rustc::mir::transform::{MirSource, Pass}; +use rustc::mir::transform::{MirCtxt, MirSource, Pass, PassId}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Multi; +use rustc::ty::steal::Steal; use rustc::ty::subst::{Subst,Substs}; use rustc::util::nodemap::{DefIdSet}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; -use std::cell::{Ref, RefCell}; use syntax::{attr}; use syntax::abi::Abi; use callgraph; +use transform::interprocedural::InterproceduralCx; const DEFAULT_THRESHOLD: usize = 50; const HINT_THRESHOLD: usize = 100; @@ -44,25 +46,29 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; impl Pass for Inline { - fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + -> Multi>> { + let tcx = mir_cx.tcx(); + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + return Multi::from(tcx.alloc_steal_mir(mir_cx.steal_previous_mir())); + } - let _ignore = tcx.dep_graph.in_ignore(); + let mut cx = InterproceduralCx::new(mir_cx); - let callgraph = callgraph::CallGraph::build(tcx); + let callgraph = callgraph::CallGraph::build(&mut cx); - let mut inliner = Inliner { - tcx: tcx, - }; + let mut inliner = Inliner { tcx }; for scc in callgraph.scc_iter() { - inliner.inline_scc(&callgraph, &scc); + inliner.inline_scc(&mut cx, &callgraph, &scc); } + + Multi::from(cx.into_local_mirs()) } } -struct Inliner<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct Inliner<'mir, 'tcx: 'mir> { + tcx: TyCtxt<'mir, 'tcx, 'tcx>, } #[derive(Copy, Clone)] @@ -74,16 +80,12 @@ struct CallSite<'tcx> { location: SourceInfo, } -impl<'a, 'tcx> Inliner<'a, 'tcx> { - fn maybe_item_mir(&mut self, _def_id: DefId) -> Option>> { - panic!() // TODO -- hook up inline into the system - } - - fn mir(&mut self, _def_id: DefId) -> &'tcx RefCell> { - panic!() // TODO -- hook up inline into the system - } - - fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool { +impl<'mir, 'tcx> Inliner<'mir, 'tcx> { + fn inline_scc<'a>(&mut self, + cx: &mut InterproceduralCx<'a, 'mir, 'tcx>, + callgraph: &callgraph::CallGraph, + scc: &[graph::NodeIndex]) -> bool { + let tcx = self.tcx; let mut callsites = Vec::new(); let mut in_scc = DefIdSet(); @@ -93,14 +95,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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) { + let id = if let Some(id) = tcx.hir.as_local_node_id(def_id) { id } else { continue; }; - let src = MirSource::from_node(self.tcx, id); + let src = MirSource::from_node(tcx, id); if let MirSource::Fn(_) = src { - if let Some(mir) = self.tcx.maybe_item_mir(def_id) { + if let Some(mir) = cx.ensure_mir_and_read(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; } @@ -151,27 +153,27 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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 _task = tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + tcx.dep_graph.write(DepNode::Mir(callsite.caller)); let callee_mir = { - if let Some(callee_mir) = self.maybe_item_mir(callsite.callee) { + if let Some(callee_mir) = cx.ensure_mir_and_read(callsite.callee) { if !self.should_inline(callsite, &callee_mir) { continue; } - callee_mir.subst(self.tcx, callsite.substs) + callee_mir.subst(tcx, callsite.substs) } else { continue; } }; - let mut caller_mir = self.mir(callsite.caller).borrow_mut(); + let caller_mir = cx.mir_mut(callsite.caller); 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; } @@ -216,21 +218,23 @@ 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 _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + tcx.dep_graph.write(DepNode::Mir(def_id)); - let mut caller_mir = self.mir(def_id).borrow_mut(); + let caller_mir = cx.mir_mut(def_id); debug!("Running simplify cfg on {:?}", def_id); - CfgSimplifier::new(&mut caller_mir).simplify(); - remove_dead_blocks(&mut caller_mir); + 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 @@ -382,10 +386,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - - fn inline_call(&self, callsite: CallSite<'tcx>, - caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { - + 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; } diff --git a/src/librustc_mir/transform/interprocedural.rs b/src/librustc_mir/transform/interprocedural.rs new file mode 100644 index 0000000000000..02d2b357e043e --- /dev/null +++ b/src/librustc_mir/transform/interprocedural.rs @@ -0,0 +1,100 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::def_id::DefId; +use rustc::mir::Mir; +use rustc::mir::transform::{MirCtxt, PassId}; +use rustc::ty::steal::Steal; +use rustc::ty::TyCtxt; +use rustc_data_structures::fx::FxHashMap; + +/// When writing inter-procedural analyses etc, we need to read (and +/// steal) the MIR for a number of def-ids at once, not all of which +/// are local. This little cache code attempts to remember what you've +/// stolen and so forth. It is more of a placeholder meant to get +/// inlining up and going again, and is probably going to need heavy +/// revision as we scale up to more interesting optimizations. +pub struct InterproceduralCx<'a, 'mir: 'a, 'tcx: 'mir> { + pub tcx: TyCtxt<'mir, 'tcx, 'tcx>, + pub mir_cx: &'a MirCtxt<'mir, 'tcx>, + local_cache: FxHashMap>, +} + +impl<'a, 'mir, 'tcx> InterproceduralCx<'a, 'mir, 'tcx> { + pub fn new(mir_cx: &'a MirCtxt<'mir, 'tcx>) -> Self { + InterproceduralCx { + mir_cx, + tcx: mir_cx.tcx(), + local_cache: FxHashMap::default(), + } + } + + pub fn into_local_mirs(self) -> Vec<(PassId, &'tcx Steal>)> { + let tcx = self.tcx; + let suite = self.mir_cx.suite(); + let pass_num = self.mir_cx.pass_num(); + self.local_cache.into_iter() + .map(|(def_id, mir)| { + let mir = tcx.alloc_steal_mir(mir); + ((suite, pass_num, def_id), mir) + }) + .collect() + } + + /// Ensures that the mir for `def_id` is available, if it can be + /// made available. + pub fn ensure_mir(&mut self, def_id: DefId) { + if def_id.is_local() { + self.ensure_mir_and_read(def_id); + } + } + + /// Ensures that the mir for `def_id` is available and returns it if possible; + /// returns `None` if this is a cross-crate MIR that is not + /// available from metadata. + pub fn ensure_mir_and_read(&mut self, def_id: DefId) -> Option<&Mir<'tcx>> { + if def_id.is_local() { + Some(self.mir_mut(def_id)) + } else { + self.tcx.maybe_item_mir(def_id) + } + } + + /// True if the local cache contains MIR for `def-id`. + pub fn contains_mir(&self, def_id: DefId) -> bool { + if def_id.is_local() { + self.local_cache.contains_key(&def_id) + } else { + self.tcx.is_item_mir_available(def_id) + } + } + + /// Reads the MIR for `def-id`. If the MIR is local, this will + /// panic if you have not previously invoked `ensure_mir`. + pub fn mir(&self, def_id: DefId) -> Option<&Mir<'tcx>> { + if def_id.is_local() { + match self.local_cache.get(&def_id) { + Some(p) => Some(p), + None => { + panic!("MIR for local def-id `{:?}` not previously ensured", def_id) + } + } + } else { + self.tcx.maybe_item_mir(def_id) + } + } + + pub fn mir_mut(&mut self, def_id: DefId) -> &mut Mir<'tcx> { + assert!(def_id.is_local(), "cannot get mutable mir of remote entry"); + let mir_cx = self.mir_cx; + self.local_cache.entry(def_id) + .or_insert_with(|| mir_cx.steal_previous_mir_of(def_id)) + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index d30495efab571..81af7c2396085 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -10,10 +10,10 @@ use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED}; +use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED, PassId}; use rustc::ty::steal::Steal; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::maps::{Multi, Providers}; use std::cell::Ref; pub mod simplify_branches; @@ -29,6 +29,7 @@ pub mod deaggregator; pub mod instcombine; pub mod copy_prop; pub mod inline; +pub mod interprocedural; pub fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); @@ -57,7 +58,7 @@ fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId)) - -> &'tcx Steal> + -> Multi>> { let passes = &tcx.mir_passes; let pass = passes.pass(suite, pass_num); @@ -69,11 +70,15 @@ fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mir = pass.run_pass(&mir_ctxt); + let key = &(suite, pass_num, def_id); for hook in passes.hooks() { - hook.on_mir_pass(&mir_ctxt, Some(&mir)); + for (&(_, _, k), v) in mir.iter(key) { + let v = &v.borrow(); + hook.on_mir_pass(&mir_ctxt, Some((k, v))); + } } - tcx.alloc_steal_mir(mir) + mir } struct MirCtxtImpl<'a, 'tcx: 'a> { @@ -107,24 +112,32 @@ impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { } fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> { - self.previous_mir().borrow() + self.previous_mir(self.def_id).borrow() } fn steal_previous_mir(&self) -> Mir<'tcx> { - self.previous_mir().steal() + self.previous_mir(self.def_id).steal() + } + + fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>> { + self.previous_mir(def_id).borrow() + } + + fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx> { + self.previous_mir(def_id).steal() } } impl<'a, 'tcx> MirCtxtImpl<'a, 'tcx> { - fn previous_mir(&self) -> &'tcx Steal> { + fn previous_mir(&self, def_id: DefId) -> &'tcx Steal> { let MirSuite(suite) = self.suite; let MirPassIndex(pass_num) = self.pass_num; if pass_num > 0 { - self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), self.def_id)) + self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), def_id)) } else if suite > 0 { - self.tcx.mir_suite((MirSuite(suite - 1), self.def_id)) + self.tcx.mir_suite((MirSuite(suite - 1), def_id)) } else { - self.tcx.mir_build(self.def_id) + self.tcx.mir_build(def_id) } } } From 0d045d73a75420a9a2b3e93df01aaf40a1104738 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 29 Apr 2017 04:36:55 -0400 Subject: [PATCH 21/42] add comments to `Steal` and use `bug!` --- src/librustc/ty/steal.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs index 0da937d036648..e62872477c47c 100644 --- a/src/librustc/ty/steal.rs +++ b/src/librustc/ty/steal.rs @@ -1,6 +1,24 @@ 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>` (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. pub struct Steal { value: RefCell> } @@ -14,7 +32,7 @@ impl Steal { pub fn borrow(&self) -> Ref { Ref::map(self.value.borrow(), |opt| match *opt { - None => panic!("attempted to read from stolen value"), + None => bug!("attempted to read from stolen value"), Some(ref v) => v }) } From d9c8a2b54b2eca0aaf9a0642b89a0ba1af6d8d78 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 29 Apr 2017 05:28:14 -0400 Subject: [PATCH 22/42] use `force` to ensure const-qualif has been done, not read --- src/librustc_mir/transform/qualify_consts.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8fc264ac1d49b..c2d2e113f56e4 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -946,8 +946,9 @@ impl DefIdPass for QualifyAndPromoteConstants { // Ensure that we compute the `mir_const_qualif` for // constants at this point, before we do any further // optimization (and before we steal the previous - // MIR). - tcx.mir_const_qualif(mir_cx.def_id()); + // MIR). We don't directly need the result, so we can + // just force it. + ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, mir_cx.def_id()); mir_cx.steal_previous_mir() } From 532439faa17bea59a5574e4c8379d2aad37d9967 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 29 Apr 2017 05:28:35 -0400 Subject: [PATCH 23/42] add a README describing the whole design --- src/librustc/mir/README.md | 142 ++++++++++++++++++++++++++++++++++ src/librustc/mir/mod.rs | 2 + src/librustc/mir/transform.rs | 2 + src/librustc/ty/maps.rs | 6 ++ 4 files changed, 152 insertions(+) create mode 100644 src/librustc/mir/README.md diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md new file mode 100644 index 0000000000000..143e6e70a82b3 --- /dev/null +++ b/src/librustc/mir/README.md @@ -0,0 +1,142 @@ +# 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. + +Here is a diagram showing the various MIR queries involved in producing +the final `optimized_mir()` for a single def-id `D`. The arrows here +indicate how data flows from query to query. + +``` +mir_build(D) + -> mir_pass((0,0,D)) ---+ each suite consists of many passes + -> ... | + -> mir_pass((0,N,D)) | + -> mir_suite((0,D)) ---+ ---+ there are several suites + -> ... | + -> mir_suite((M,D)) ---+ + -> mir_optimized(D) +``` + +The MIR transformation pipeline is organized into **suites**. When +you ask for `mir_optimized(D)`, it will turn around and request the +result from the final **suite** of MIR passes +(`mir_suite((M,D))`). This will in turn (eventually) trigger the MIR +to be build and then passes through each of the optimization suites. +Each suite internally triggers one query for each of its passes +(`mir_pass(...)`). + +The reason for the suites is that they represent points in the MIR +transformation pipeline where other bits of code are interested in +observing. For example, the `MIR_CONST` suite defines the point where +analysis for constant rvalues and expressions can take +place. `MIR_OPTIMIZED` naturally represents the point where we +actually generate machine code. Nobody should ever request the result +of an individual *pass*, at least outside of the transformation +pipeline: this allows us to add passes into the appropriate suite +without having to modify anything else in the compiler. + +### Stealing + +Each of these intermediate queries yields up a `&'tcx +Steal>`, allocated using `tcx.alloc_steal_mir()`. This +indicates that the result may be **stolen** by the next pass -- 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. Sometimes this requires **forcing** queries +(`ty::queries::foo::force(...)`) during an optimization pass -- this +will force a query to execute even though you don't directly require +its result. The query can then read the MIR it needs, and -- once it +is complete -- you can steal it. + +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 first pass in the next suite (that pass performs +const promotion): + +``` +mir_suite((MIR_CONST,D)) --read-by--> mir_const_qualif(D) + | + stolen-by + | + v +mir_pass((MIR_VALIDATED,0,D)) +``` + +Therefore, the const promotion pass (the `mir_pass()` in the diagram) +will **force** `mir_const_qualif` before it actually steals, thus +ensuring that the reads have already happened (and the final result is +cached). + +### Implementing and registering a pass + +To create a new MIR pass, you have to implement one of the MIR pass +traits. There are several traits, and you want to pick the most +specific one that applies to your pass. They are described here in +order of preference. 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()` with the +appropriate suite. + +**The `MirPass` trait.** For the most part, a MIR pass works by taking +as input the MIR for a single function and mutating it imperatively to +perform an optimization. To write such a pass, you can implement the +`MirPass` trait, which has a single callback that takes an `&mut Mir`. + +**The `DefIdPass` trait.** When a `MirPass` trait is executed, the +system will automatically steal the result of the previous pass and +supply it to you. (See the section on queries and stealing below.) +Sometimes you don't want to steal the result of the previous pass +right away. In such cases, you can define a `DefIdPass`, which simply +gets a callback and lets you decide when to steal the previous result. + +**The `Pass` trait.** The most primitive but flexible trait is `Pass`. +Unlike the other pass types, it returns a `Multi` result, which means +it scan be used for interprocedural passes which mutate more than one +MIR at a time (e.g., `inline`). + +### The MIR Context + +All of the passes when invoked take a `MirCtxt` object. This contains +various methods to find out (e.g.) the current pass suite and pass +index, the def-id you are operating on, and so forth. You can also +access the MIR for the current def-id using `read_previous_mir()`; the +"previous" refers to the fact that this will be the MIR that was +output by the previous pass. Finally, you can `steal_previous_mir()` +to steal the output of the current pass (in which case you get +ownership of the MIR). diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8f8af8b10366e..b517ebabbe767 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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}; diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 9718098aac8af..69dc83f6dcc84 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! See [the README](README.md) for details on writing your own pass. + use hir; use hir::def_id::DefId; use hir::map::DefPathData; diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 3541a19fe6b64..b37dbc6411baf 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -801,17 +801,23 @@ define_maps! { <'tcx> /// Performs the initial MIR construction. You almost certainly do not /// want to use this query, because its output is intended to be stolen /// immediately by the MIR passes below. Consider `optimized_mir` instead. + /// + /// See the README for the `mir` module for details. [] mir_build: Mir(DefId) -> &'tcx Steal>, /// Fetch the MIR for a given def-id after the given set of passes has ben /// applied to it. This is mostly an "intermediate" query. Normally, you would /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all /// optimizations and so forth. + /// + /// See the README for the `mir` module for details. [] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx Steal>, /// Fetch the MIR for a given def-id after a given pass has been executed. This is /// **only** intended to be used by the `mir_suite` provider -- if you are using it /// manually, you're doing it wrong. + /// + /// See the README for the `mir` module for details. [multi] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, /// MIR after our optimization passes have run. This is MIR that is ready From c1ff10464dc6b685f871d2365e3d8a39de324ba9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 11:23:53 -0400 Subject: [PATCH 24/42] rename `mir_map` to `queries` and remove `build_mir_for_crate` --- src/librustc_driver/driver.rs | 11 +---------- src/librustc_mir/lib.rs | 4 ++-- src/librustc_mir/{mir_map.rs => queries.rs} | 11 ----------- 3 files changed, 3 insertions(+), 23 deletions(-) rename src/librustc_mir/{mir_map.rs => queries.rs} (96%) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index cd6b5f62edd2c..f80d6473dcc54 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -36,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; @@ -997,14 +996,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, "borrow checking", || borrowck::check_crate(tcx)); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index cf6a50563a08c..682a5c6f8acdf 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -50,14 +50,14 @@ pub mod build; pub mod callgraph; mod hair; mod shim; -pub mod mir_map; +mod queries; pub mod transform; pub mod util; use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { - mir_map::provide(providers); + queries::provide(providers); shim::provide(providers); transform::provide(providers); } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/queries.rs similarity index 96% rename from src/librustc_mir/mir_map.rs rename to src/librustc_mir/queries.rs index e51a7a410e026..b4d752d2894b7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/queries.rs @@ -18,7 +18,6 @@ use build; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::dep_graph::DepNode; use rustc::mir::Mir; use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; @@ -41,16 +40,6 @@ use syntax_pos::Span; use std::mem; use std::rc::Rc; -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>, (): ()) { - for &body_owner_def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - tcx.item_mir(body_owner_def_id); - } - } -} - pub fn provide(providers: &mut Providers) { *providers = Providers { mir_build, From c2cfdbbdf908de88cf6d306949f81dc487d9e6b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 11:58:05 -0400 Subject: [PATCH 25/42] adjust privacy of various types in `build` --- src/librustc_mir/build/into.rs | 2 +- src/librustc_mir/build/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs index 5c133780e433b..0d912513c6c76 100644 --- a/src/librustc_mir/build/into.rs +++ b/src/librustc_mir/build/into.rs @@ -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>, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b8f1b754b48e8..94c53611e74e3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -25,7 +25,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::u32; -pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { hir: Cx<'a, 'gcx, 'tcx>, cfg: CFG<'tcx>, @@ -82,7 +82,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(BasicBlock, T); +struct BlockAnd(BasicBlock, T); trait BlockAndExtension { fn and(self, v: T) -> BlockAnd; From 69c8f9dd254982b3bf0908839bb7dc173b6cbaaa Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 14:56:26 -0400 Subject: [PATCH 26/42] move `build_mir` into `build` directory --- src/librustc_mir/build/mod.rs | 225 ++++++++++++++++++++++++++++++-- src/librustc_mir/hair/cx/mod.rs | 6 +- src/librustc_mir/queries.rs | 210 +---------------------------- 3 files changed, 217 insertions(+), 224 deletions(-) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 94c53611e74e3..f5f6c307b152a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -8,22 +8,223 @@ // 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::hir; +use rustc::hir::def_id::DefId; use rustc::middle::region::{CodeExtent, CodeExtentData}; -use rustc::ty::{self, Ty}; 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::steal::Steal; +use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; -use rustc::hir; +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}; +pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { + 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() + }; + + 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_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + + tcx.alloc_steal_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 Steal> +{ + 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_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + + tcx.alloc_steal_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>, @@ -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, Option<&'gcx hir::Pat>)> { let arguments: Vec<_> = arguments.collect(); diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3e9bcb3e18627..ee8547e5dd679 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -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) } } diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs index b4d752d2894b7..aef637fed5ee0 100644 --- a/src/librustc_mir/queries.rs +++ b/src/librustc_mir/queries.rs @@ -16,31 +16,20 @@ //! - `#[rustc_mir(graphviz="file.gv")]` //! - `#[rustc_mir(pretty="file.mir")]` -use build; -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -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::hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc::traits::Reveal; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; -use rustc::ty::steal::Steal; -use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::util::nodemap::DefIdSet; -use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; -use std::mem; use std::rc::Rc; pub fn provide(providers: &mut Providers) { + use build::mir_build; *providers = Providers { mir_build, mir_keys, @@ -86,196 +75,3 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) Rc::new(set) } - -fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { - 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_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - - tcx.alloc_steal_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 Steal> -{ - 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_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - - tcx.alloc_steal_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 - } -} From c253df5249b5f3c7d6f85e1ed28afbf0adc1390b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 12:47:00 -0400 Subject: [PATCH 27/42] remove `Pass` and (temporarily) drop `Inline` --- src/librustc/mir/transform.rs | 32 +++------------------------- src/librustc_driver/driver.rs | 2 +- src/librustc_mir/transform/inline.rs | 7 +++++- src/librustc_mir/transform/mod.rs | 8 ++----- 4 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 69dc83f6dcc84..28b34459b30f9 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -15,8 +15,6 @@ use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; -use ty::maps::Multi; -use ty::steal::Steal; use std::cell::Ref; use std::rc::Rc; use syntax::ast::NodeId; @@ -135,19 +133,6 @@ pub trait PassHook { /// application of a pass to a def-id. pub type PassId = (MirSuite, MirPassIndex, DefId); -/// The most generic sort of MIR pass. You only want to implement this -/// rather general trait if you are doing an interprocedural pass that -/// may inspect and affect the MIR of many def-ids. Otherwise, prefer -/// the more steamlined `DefIdPass` or `MirPass`. -pub trait Pass { - fn name<'a>(&'a self) -> Cow<'a, str> { - default_name::() - } - - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) - -> Multi>>; -} - /// A streamlined trait that you can implement to create an /// intraprocedural pass; the pass will be invoked to process the MIR /// with the given `def_id`. This lets you do things before we fetch @@ -160,17 +145,6 @@ pub trait DefIdPass { fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>; } -impl Pass for T { - fn name<'a>(&'a self) -> Cow<'a, str> { - DefIdPass::name(self) - } - - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) - -> Multi>> { - Multi::from(mir_cx.tcx().alloc_steal_mir(DefIdPass::run_pass(self, mir_cx))) - } -} - /// 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`. @@ -210,7 +184,7 @@ impl DefIdPass for T { #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, - suites: Vec>>, + suites: Vec>>, } /// The number of "pass suites" that we have: @@ -238,7 +212,7 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, suite: MirSuite, pass: T) { + pub fn push_pass(&mut self, suite: MirSuite, pass: T) { self.suites[suite.0].push(Rc::new(pass)); } @@ -251,7 +225,7 @@ impl<'a, 'tcx> Passes { self.suites[suite.0].len() } - pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &Pass { + pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass { &*self.suites[suite.0][pass.0] } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f80d6473dcc54..a08fd1f9bf67e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -928,7 +928,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, 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); + // TODO 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); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index e10a91c6ec2e7..2323b55951d76 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,7 @@ use rustc_data_structures::graph; use rustc::dep_graph::DepNode; use rustc::mir::*; -use rustc::mir::transform::{MirCtxt, MirSource, Pass, PassId}; +use rustc::mir::transform::{MirCtxt, MirSource, PassId}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -45,6 +45,11 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; +pub trait Pass { + fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + -> Multi>>; +} + impl Pass for Inline { fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Multi>> { diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 81af7c2396085..feef7a197c59d 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -70,15 +70,11 @@ fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mir = pass.run_pass(&mir_ctxt); - let key = &(suite, pass_num, def_id); for hook in passes.hooks() { - for (&(_, _, k), v) in mir.iter(key) { - let v = &v.borrow(); - hook.on_mir_pass(&mir_ctxt, Some((k, v))); - } + hook.on_mir_pass(&mir_ctxt, Some((def_id, &mir))); } - mir + Multi::from(tcx.alloc_steal_mir(mir)) } struct MirCtxtImpl<'a, 'tcx: 'a> { From 9c154a67bf5c6841c39afdb90388cc3ba36dc70c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 13:46:35 -0400 Subject: [PATCH 28/42] rip out everything but `MirPass`, move the logic into suites --- src/librustc/mir/transform.rs | 72 ++---------- src/librustc/ty/maps.rs | 2 +- src/librustc_mir/callgraph.rs | 2 +- src/librustc_mir/transform/dump_mir.rs | 50 +++------ src/librustc_mir/transform/inline.rs | 27 ++--- src/librustc_mir/transform/interprocedural.rs | 28 ++--- src/librustc_mir/transform/mod.rs | 106 ++++++------------ src/librustc_mir/transform/qualify_consts.rs | 35 +----- 8 files changed, 92 insertions(+), 230 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 28b34459b30f9..df6f98297d022 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -15,7 +15,6 @@ use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; -use std::cell::Ref; use std::rc::Rc; use syntax::ast::NodeId; @@ -83,29 +82,6 @@ pub fn default_name() -> Cow<'static, str> { } } -/// Gives you access to various bits of state during your MIR pass. -pub trait MirCtxt<'a, 'tcx: 'a> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; - fn def_id(&self) -> DefId; - fn suite(&self) -> MirSuite; - fn pass_num(&self) -> MirPassIndex; - fn source(&self) -> MirSource; - - // Get a read-only view on the MIR of this def-id from the - // previous pass. - fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>; - - // Steal the MIR of this def-id from the previous pass; any future - // attempt to access the MIR from the previous pass is a bug. - fn steal_previous_mir(&self) -> Mir<'tcx>; - - // Same as `read_previous_mir()`, but for any def-id you want. - fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>>; - - // Same as `steal_previous_mir()`, but for any def-id you want. - fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx>; -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct MirSuite(pub usize); @@ -125,26 +101,19 @@ pub struct MirPassIndex(pub usize); /// the hook will be invoked once per output. pub trait PassHook { fn on_mir_pass<'a, 'tcx: 'a>(&self, - mir_cx: &MirCtxt<'a, 'tcx>, - mir: Option<(DefId, &Mir<'tcx>)>); + tcx: TyCtxt<'a, 'tcx, 'tcx>, + suite: MirSuite, + pass_num: MirPassIndex, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + 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 streamlined trait that you can implement to create an -/// intraprocedural pass; the pass will be invoked to process the MIR -/// with the given `def_id`. This lets you do things before we fetch -/// the MIR itself. You may prefer `MirPass`, which is even more streamlined. -pub trait DefIdPass { - fn name<'a>(&'a self) -> Cow<'a, str> { - default_name::() - } - - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>; -} - /// 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`. @@ -159,32 +128,11 @@ pub trait MirPass { mir: &mut Mir<'tcx>); } -impl DefIdPass for T { - fn name<'a>(&'a self) -> Cow<'a, str> { - MirPass::name(self) - } - - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { - let tcx = mir_cx.tcx(); - let source = mir_cx.source(); - let mut mir = mir_cx.steal_previous_mir(); - MirPass::run_pass(self, tcx, source, &mut mir); - - let item_id = source.item_id(); - for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() { - let promoted_source = MirSource::Promoted(item_id, promoted_index); - MirPass::run_pass(self, tcx, promoted_source, promoted_mir); - } - - mir - } -} - /// A manager for MIR passes. #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, - suites: Vec>>, + suites: Vec>>, } /// The number of "pass suites" that we have: @@ -212,7 +160,7 @@ impl<'a, 'tcx> Passes { } /// Pushes a built-in pass. - pub fn push_pass(&mut self, suite: MirSuite, pass: T) { + pub fn push_pass(&mut self, suite: MirSuite, pass: T) { self.suites[suite.0].push(Rc::new(pass)); } @@ -225,7 +173,7 @@ impl<'a, 'tcx> Passes { self.suites[suite.0].len() } - pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass { + pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &MirPass { &*self.suites[suite.0][pass.0] } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b37dbc6411baf..b3ca61550d7c3 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -818,7 +818,7 @@ define_maps! { <'tcx> /// manually, you're doing it wrong. /// /// See the README for the `mir` module for details. - [multi] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, + [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, /// 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. diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs index ef271d8b836eb..977b9d2e99447 100644 --- a/src/librustc_mir/callgraph.rs +++ b/src/librustc_mir/callgraph.rs @@ -30,7 +30,7 @@ pub struct CallGraph { } impl CallGraph { - pub fn build<'a, 'mir, 'tcx>(cx: &mut InterproceduralCx<'a, 'mir, 'tcx>) -> CallGraph { + pub fn build<'a, 'tcx>(cx: &mut InterproceduralCx<'a, 'tcx>) -> CallGraph { let mut callgraph = CallGraph { node_map: DefIdMap(), graph: graph::Graph::new() diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index b895a21558594..67a3281dba48b 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -15,22 +15,24 @@ use std::fmt; use std::fs::File; use std::io; -use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, PassHook}; +use rustc::mir::transform::{MirPass, MirPassIndex, MirSource, MirSuite, PassHook}; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; use util as mir_util; pub struct Marker(pub &'static str); -impl DefIdPass for Marker { +impl MirPass for Marker { fn name<'a>(&'a self) -> Cow<'a, str> { Cow::Borrowed(self.0) } - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { - mir_cx.steal_previous_mir() + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + _mir: &mut Mir<'tcx>) + { } } @@ -49,37 +51,21 @@ pub struct DumpMir; impl PassHook for DumpMir { fn on_mir_pass<'a, 'tcx: 'a>(&self, - mir_cx: &MirCtxt<'a, 'tcx>, - mir: Option<(DefId, &Mir<'tcx>)>) + tcx: TyCtxt<'a, 'tcx, 'tcx>, + suite: MirSuite, + pass_num: MirPassIndex, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + is_after: bool) { - let tcx = mir_cx.tcx(); - let suite = mir_cx.suite(); - let pass_num = mir_cx.pass_num(); - let pass = tcx.mir_passes.pass(suite, pass_num); - let name = &pass.name(); - let source = match mir { - None => mir_cx.source(), - Some((def_id, _)) => { - let id = tcx.hir.as_local_node_id(def_id) - .expect("mir source requires local def-id"); - MirSource::from_node(tcx, id) - } - }; - if mir_util::dump_enabled(tcx, name, source) { - let previous_mir; - let mir_to_dump = match mir { - Some((_, m)) => m, - None => { - previous_mir = mir_cx.read_previous_mir(); - &*previous_mir - } - }; + if mir_util::dump_enabled(tcx, pass_name, source) { mir_util::dump_mir(tcx, Some((suite, pass_num)), - name, - &Disambiguator { is_after: mir.is_some() }, + pass_name, + &Disambiguator { is_after }, source, - mir_to_dump); + mir); } } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 2323b55951d76..caa2aa74ede19 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,7 @@ use rustc_data_structures::graph; use rustc::dep_graph::DepNode; use rustc::mir::*; -use rustc::mir::transform::{MirCtxt, MirSource, PassId}; +use rustc::mir::transform::{MirSource, PassId}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -46,19 +46,14 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; pub trait Pass { - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + fn run_pass<'a, 'tcx: 'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Multi>>; } impl Pass for Inline { - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) + fn run_pass<'a, 'tcx: 'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Multi>> { - let tcx = mir_cx.tcx(); - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { - return Multi::from(tcx.alloc_steal_mir(mir_cx.steal_previous_mir())); - } - - let mut cx = InterproceduralCx::new(mir_cx); + let mut cx = InterproceduralCx::new(tcx); let callgraph = callgraph::CallGraph::build(&mut cx); @@ -72,8 +67,8 @@ impl Pass for Inline { } } -struct Inliner<'mir, 'tcx: 'mir> { - tcx: TyCtxt<'mir, 'tcx, 'tcx>, +struct Inliner<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, } #[derive(Copy, Clone)] @@ -85,11 +80,11 @@ struct CallSite<'tcx> { location: SourceInfo, } -impl<'mir, 'tcx> Inliner<'mir, 'tcx> { - fn inline_scc<'a>(&mut self, - cx: &mut InterproceduralCx<'a, 'mir, 'tcx>, - callgraph: &callgraph::CallGraph, - scc: &[graph::NodeIndex]) -> bool { +impl<'a, 'tcx> Inliner<'a, 'tcx> { + fn inline_scc(&mut self, + cx: &mut InterproceduralCx<'a, 'tcx>, + callgraph: &callgraph::CallGraph, + scc: &[graph::NodeIndex]) -> bool { let tcx = self.tcx; let mut callsites = Vec::new(); let mut in_scc = DefIdSet(); diff --git a/src/librustc_mir/transform/interprocedural.rs b/src/librustc_mir/transform/interprocedural.rs index 02d2b357e043e..7a2645567e24e 100644 --- a/src/librustc_mir/transform/interprocedural.rs +++ b/src/librustc_mir/transform/interprocedural.rs @@ -10,7 +10,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{MirCtxt, PassId}; +use rustc::mir::transform::{PassId}; use rustc::ty::steal::Steal; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; @@ -21,31 +21,21 @@ use rustc_data_structures::fx::FxHashMap; /// stolen and so forth. It is more of a placeholder meant to get /// inlining up and going again, and is probably going to need heavy /// revision as we scale up to more interesting optimizations. -pub struct InterproceduralCx<'a, 'mir: 'a, 'tcx: 'mir> { - pub tcx: TyCtxt<'mir, 'tcx, 'tcx>, - pub mir_cx: &'a MirCtxt<'mir, 'tcx>, +pub struct InterproceduralCx<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, local_cache: FxHashMap>, } -impl<'a, 'mir, 'tcx> InterproceduralCx<'a, 'mir, 'tcx> { - pub fn new(mir_cx: &'a MirCtxt<'mir, 'tcx>) -> Self { +impl<'a, 'tcx> InterproceduralCx<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { InterproceduralCx { - mir_cx, - tcx: mir_cx.tcx(), + tcx: tcx, local_cache: FxHashMap::default(), } } pub fn into_local_mirs(self) -> Vec<(PassId, &'tcx Steal>)> { - let tcx = self.tcx; - let suite = self.mir_cx.suite(); - let pass_num = self.mir_cx.pass_num(); - self.local_cache.into_iter() - .map(|(def_id, mir)| { - let mir = tcx.alloc_steal_mir(mir); - ((suite, pass_num, def_id), mir) - }) - .collect() + unimplemented!() } /// Ensures that the mir for `def_id` is available, if it can be @@ -93,8 +83,6 @@ impl<'a, 'mir, 'tcx> InterproceduralCx<'a, 'mir, 'tcx> { pub fn mir_mut(&mut self, def_id: DefId) -> &mut Mir<'tcx> { assert!(def_id.is_local(), "cannot get mutable mir of remote entry"); - let mir_cx = self.mir_cx; - self.local_cache.entry(def_id) - .or_insert_with(|| mir_cx.steal_previous_mir_of(def_id)) + unimplemented!() } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index feef7a197c59d..dc67c6f1ef45f 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -10,11 +10,11 @@ use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED, PassId}; +use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource, MIR_VALIDATED, MIR_OPTIMIZED}; +use rustc::ty::{self, TyCtxt}; use rustc::ty::steal::Steal; -use rustc::ty::TyCtxt; -use rustc::ty::maps::{Multi, Providers}; -use std::cell::Ref; +use rustc::ty::maps::Providers; +use syntax_pos::DUMMY_SP; pub mod simplify_branches; pub mod simplify; @@ -51,6 +51,20 @@ fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> &'tcx Steal> { let passes = &tcx.mir_passes; + + if suite == MIR_VALIDATED { + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); + let source = MirSource::from_node(tcx, id); + if let MirSource::Const(_) = source { + // Ensure that we compute the `mir_const_qualif` for + // constants at this point, before we do any further + // optimization (and before we steal the previous + // MIR). We don't directly need the result, so we can + // just force it. + ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, def_id); + } + } + let len = passes.len_passes(suite); assert!(len > 0, "no passes in {:?}", suite); tcx.mir_pass((suite, MirPassIndex(len - 1), def_id)) @@ -58,82 +72,36 @@ fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId)) - -> Multi>> + -> &'tcx Steal> { let passes = &tcx.mir_passes; let pass = passes.pass(suite, pass_num); - let mir_ctxt = MirCtxtImpl { tcx, pass_num, suite, def_id }; - for hook in passes.hooks() { - hook.on_mir_pass(&mir_ctxt, None); - } + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); + let source = MirSource::from_node(tcx, id); - let mir = pass.run_pass(&mir_ctxt); + let mut mir = { + let MirSuite(suite) = suite; + let MirPassIndex(pass_num) = pass_num; + if pass_num > 0 { + tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), def_id)).steal() + } else if suite > 0 { + tcx.mir_suite((MirSuite(suite - 1), def_id)).steal() + } else { + tcx.mir_build(def_id).steal() + } + }; for hook in passes.hooks() { - hook.on_mir_pass(&mir_ctxt, Some((def_id, &mir))); - } - - Multi::from(tcx.alloc_steal_mir(mir)) -} - -struct MirCtxtImpl<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: MirPassIndex, - suite: MirSuite, - def_id: DefId -} - -impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { - self.tcx - } - - fn suite(&self) -> MirSuite { - self.suite - } - - fn pass_num(&self) -> MirPassIndex { - self.pass_num - } - - fn def_id(&self) -> DefId { - self.def_id - } - - fn source(&self) -> MirSource { - let id = self.tcx.hir.as_local_node_id(self.def_id) - .expect("mir source requires local def-id"); - MirSource::from_node(self.tcx, id) - } - - fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> { - self.previous_mir(self.def_id).borrow() + hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false); } - fn steal_previous_mir(&self) -> Mir<'tcx> { - self.previous_mir(self.def_id).steal() - } + pass.run_pass(tcx, source, &mut mir); - fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>> { - self.previous_mir(def_id).borrow() + for hook in passes.hooks() { + hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true); } - fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx> { - self.previous_mir(def_id).steal() - } + tcx.alloc_steal_mir(mir) } -impl<'a, 'tcx> MirCtxtImpl<'a, 'tcx> { - fn previous_mir(&self, def_id: DefId) -> &'tcx Steal> { - let MirSuite(suite) = self.suite; - let MirPassIndex(pass_num) = self.pass_num; - if pass_num > 0 { - self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), def_id)) - } else if suite > 0 { - self.tcx.mir_suite((MirSuite(suite - 1), def_id)) - } else { - self.tcx.mir_build(def_id) - } - } -} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index c2d2e113f56e4..cd37372c2f122 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -26,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::{DefIdPass, MirCtxt, MirSource, MIR_CONST}; +use rustc::mir::transform::{MirPass, MirSource, MIR_CONST}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::middle::lang_items; use syntax::abi::Abi; @@ -938,34 +938,11 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct QualifyAndPromoteConstants; -impl DefIdPass for QualifyAndPromoteConstants { - fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> { - let tcx = mir_cx.tcx(); - match mir_cx.source() { - MirSource::Const(_) => { - // Ensure that we compute the `mir_const_qualif` for - // constants at this point, before we do any further - // optimization (and before we steal the previous - // MIR). We don't directly need the result, so we can - // just force it. - ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, mir_cx.def_id()); - mir_cx.steal_previous_mir() - } - - src => { - let mut mir = mir_cx.steal_previous_mir(); - self.run_pass(tcx, src, &mut mir); - mir - } - } - } -} - -impl<'a, 'tcx> QualifyAndPromoteConstants { - fn run_pass(&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 { From 669d31683f97c173c404d27b841d30a6424bf639 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 14:39:48 -0400 Subject: [PATCH 29/42] simplify down to one query per pass suite --- src/librustc/mir/transform.rs | 13 ++-- src/librustc/ty/maps.rs | 42 +--------- src/librustc_mir/build/mod.rs | 10 +-- src/librustc_mir/queries.rs | 47 ++++++++++-- src/librustc_mir/transform/mod.rs | 81 ++++---------------- src/librustc_mir/transform/qualify_consts.rs | 20 +++-- 6 files changed, 87 insertions(+), 126 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index df6f98297d022..77d4eefb1def5 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -37,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::*; @@ -169,12 +174,8 @@ impl<'a, 'tcx> Passes { self.pass_hooks.push(Rc::new(hook)); } - pub fn len_passes(&self, suite: MirSuite) -> usize { - self.suites[suite.0].len() - } - - pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &MirPass { - &*self.suites[suite.0][pass.0] + pub fn passes(&self, suite: MirSuite) -> &[Rc] { + &self.suites[suite.0] } pub fn hooks(&self) -> &[Rc] { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b3ca61550d7c3..5a5dece8a94ec 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -404,18 +404,6 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> { } } -impl<'tcx> QueryDescription for queries::mir_suite<'tcx> { - fn describe(_: TyCtxt, (suite, _): (MirSuite, DefId)) -> String { - format!("MIR suite #{}.*", suite.0) - } -} - -impl<'tcx> QueryDescription for queries::mir_pass<'tcx> { - fn describe(_: TyCtxt, (suite, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String { - format!("MIR pass #{}.{}", suite.0, pass_num.0) - } -} - macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -798,27 +786,13 @@ define_maps! { <'tcx> /// the value isn't known except to the pass itself. [] mir_const_qualif: Mir(DefId) -> u8, - /// Performs the initial MIR construction. You almost certainly do not - /// want to use this query, because its output is intended to be stolen - /// immediately by the MIR passes below. Consider `optimized_mir` instead. + /// 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_build: Mir(DefId) -> &'tcx Steal>, + [] mir_const: Mir(DefId) -> &'tcx Steal>, - /// Fetch the MIR for a given def-id after the given set of passes has ben - /// applied to it. This is mostly an "intermediate" query. Normally, you would - /// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all - /// optimizations and so forth. - /// - /// See the README for the `mir` module for details. - [] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx Steal>, - - /// Fetch the MIR for a given def-id after a given pass has been executed. This is - /// **only** intended to be used by the `mir_suite` provider -- if you are using it - /// manually, you're doing it wrong. - /// - /// See the README for the `mir` module for details. - [] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal>, + [] mir_validated: Mir(DefId) -> &'tcx Steal>, /// 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. @@ -921,11 +895,3 @@ fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { fn mir_keys(_: CrateNum) -> DepNode { DepNode::MirKeys } - -fn mir_suite((_suite, def_id): (MirSuite, DefId)) -> DepNode { - DepNode::Mir(def_id) -} - -fn mir_pass((_suite, _pass_num, def_id): (MirSuite, MirPassIndex, DefId)) -> DepNode { - DepNode::Mir(def_id) -} diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index f5f6c307b152a..8c057b02df2bf 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -20,7 +20,6 @@ use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::steal::Steal; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -33,7 +32,8 @@ use syntax::symbol::keywords; use syntax_pos::Span; use util as mir_util; -pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { +/// 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); @@ -131,7 +131,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - tcx.alloc_steal_mir(mir) + mir }) } @@ -168,7 +168,7 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ctor_id: ast::NodeId, v: &'tcx hir::VariantData) - -> &'tcx Steal> + -> Mir<'tcx> { let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { @@ -190,7 +190,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); - tcx.alloc_steal_mir(mir) + mir }) } else { span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v); diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs index aef637fed5ee0..980663ec67585 100644 --- a/src/librustc_mir/queries.rs +++ b/src/librustc_mir/queries.rs @@ -16,27 +16,34 @@ //! - `#[rustc_mir(graphviz="file.gv")]` //! - `#[rustc_mir(pretty="file.mir")]` -use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; - -use rustc::ty::TyCtxt; +use build; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::mir::Mir; +use rustc::mir::transform::{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 syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; +use transform; use std::rc::Rc; pub fn provide(providers: &mut Providers) { - use build::mir_build; *providers = Providers { - mir_build, mir_keys, + mir_const, + mir_validated, + optimized_mir, ..*providers }; } +/// 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 { assert_eq!(krate, LOCAL_CRATE); @@ -75,3 +82,31 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) Rc::new(set) } + +fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { + 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> { + 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> { + 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) +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index dc67c6f1ef45f..971b0206a9ebd 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::def_id::DefId; use rustc::mir::Mir; -use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource, MIR_VALIDATED, MIR_OPTIMIZED}; -use rustc::ty::{self, TyCtxt}; -use rustc::ty::steal::Steal; +use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource}; +use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; -use syntax_pos::DUMMY_SP; pub mod simplify_branches; pub mod simplify; @@ -31,77 +28,31 @@ pub mod copy_prop; pub mod inline; pub mod interprocedural; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); *providers = Providers { - optimized_mir, - mir_suite, - mir_pass, ..*providers }; } -fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> { - let mir = tcx.mir_suite((MIR_OPTIMIZED, def_id)).steal(); - tcx.alloc_mir(mir) -} - -fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - (suite, def_id): (MirSuite, DefId)) - -> &'tcx Steal> +pub(crate) fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + suite: MirSuite, + mir: &mut Mir<'tcx>) { - let passes = &tcx.mir_passes; - - if suite == MIR_VALIDATED { - let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); - let source = MirSource::from_node(tcx, id); - if let MirSource::Const(_) = source { - // Ensure that we compute the `mir_const_qualif` for - // constants at this point, before we do any further - // optimization (and before we steal the previous - // MIR). We don't directly need the result, so we can - // just force it. - ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, def_id); - } - } - - let len = passes.len_passes(suite); - assert!(len > 0, "no passes in {:?}", suite); - tcx.mir_pass((suite, MirPassIndex(len - 1), def_id)) -} + let passes = tcx.mir_passes.passes(suite); -fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - (suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId)) - -> &'tcx Steal> -{ - let passes = &tcx.mir_passes; - let pass = passes.pass(suite, pass_num); + for (pass, index) in passes.iter().zip(0..) { + let pass_num = MirPassIndex(index); - let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); - let source = MirSource::from_node(tcx, id); - - let mut mir = { - let MirSuite(suite) = suite; - let MirPassIndex(pass_num) = pass_num; - if pass_num > 0 { - tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), def_id)).steal() - } else if suite > 0 { - tcx.mir_suite((MirSuite(suite - 1), def_id)).steal() - } else { - tcx.mir_build(def_id).steal() + for hook in tcx.mir_passes.hooks() { + hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false); } - }; - - for hook in passes.hooks() { - hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false); - } - pass.run_pass(tcx, source, &mut mir); + pass.run_pass(tcx, source, mir); - for hook in passes.hooks() { - hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true); + for hook in tcx.mir_passes.hooks() { + hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true); + } } - - tcx.alloc_steal_mir(mir) } - diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cd37372c2f122..4b1c82f383f85 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -26,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::{MirPass, MirSource, MIR_CONST}; +use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::middle::lang_items; use syntax::abi::Abi; @@ -918,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.mir_suite((MIR_CONST, def_id)).borrow(); +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(); } From 1dd9c3e52a78399ca071728c76fafcd9524f793e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 16:03:05 -0400 Subject: [PATCH 30/42] support inlining by asking for optimizer mir for callees I tested this with it enabled 100% of the time, and we were able to run mir-opt tests successfully. --- src/librustc_driver/driver.rs | 2 +- src/librustc_mir/queries.rs | 5 + src/librustc_mir/transform/inline.rs | 201 +++++++++------------------ 3 files changed, 68 insertions(+), 140 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a08fd1f9bf67e..f80d6473dcc54 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -928,7 +928,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, 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. - // TODO passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline); + 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); diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs index 980663ec67585..b9d6e527e556c 100644 --- a/src/librustc_mir/queries.rs +++ b/src/librustc_mir/queries.rs @@ -38,10 +38,15 @@ pub fn provide(providers: &mut Providers) { mir_const, mir_validated, optimized_mir, + is_item_mir_available, ..*providers }; } +fn is_item_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) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index caa2aa74ede19..614b5e2cc3f8d 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -14,27 +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::{MirSource, PassId}; +use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::*; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::maps::Multi; -use rustc::ty::steal::Steal; 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; -use transform::interprocedural::InterproceduralCx; - const DEFAULT_THRESHOLD: usize = 50; const HINT_THRESHOLD: usize = 100; @@ -45,140 +38,92 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; -pub trait Pass { - fn run_pass<'a, 'tcx: 'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Multi>>; +#[derive(Copy, Clone)] +struct CallSite<'tcx> { + callee: DefId, + substs: &'tcx Substs<'tcx>, + bb: BasicBlock, + location: SourceInfo, } -impl Pass for Inline { - fn run_pass<'a, 'tcx: 'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Multi>> { - let mut cx = InterproceduralCx::new(tcx); - - let callgraph = callgraph::CallGraph::build(&mut cx); - - let mut inliner = Inliner { tcx }; - - for scc in callgraph.scc_iter() { - inliner.inline_scc(&mut cx, &callgraph, &scc); +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); } - - Multi::from(cx.into_local_mirs()) } } 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, + source: MirSource, } impl<'a, 'tcx> Inliner<'a, 'tcx> { - fn inline_scc(&mut self, - cx: &mut InterproceduralCx<'a, 'tcx>, - callgraph: &callgraph::CallGraph, - scc: &[graph::NodeIndex]) -> bool { - let tcx = self.tcx; - 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) = tcx.hir.as_local_node_id(def_id) { - id - } else { - continue; - }; - let src = MirSource::from_node(tcx, id); - if let MirSource::Fn(_) = src { - if let Some(mir) = cx.ensure_mir_and_read(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 - }); - } - } + 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 current heuristic. + + 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 + }); } - - in_scc.insert(def_id); } } } - // 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(); - - 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; - } - } - let mut local_change; let mut changed = false; loop { local_change = false; - let mut csi = 0; - while csi < callsites.len() { - let callsite = callsites[csi]; - csi += 1; - - let _task = tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); - tcx.dep_graph.write(DepNode::Mir(callsite.caller)); - - let callee_mir = { - if let Some(callee_mir) = cx.ensure_mir_and_read(callsite.callee) { - if !self.should_inline(callsite, &callee_mir) { - continue; - } + while let Some(callsite) = callsites.pop_front() { + if !self.tcx.is_item_mir_available(callsite.callee) { + continue; + } - callee_mir.subst(tcx, callsite.substs) - } else { - 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) } + _ => continue, }; - let caller_mir = cx.mir_mut(callsite.caller); - let start = caller_mir.basic_blocks().len(); 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 @@ -188,8 +133,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, @@ -200,13 +144,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; } @@ -216,18 +153,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - // Simplify functions we inlined into. - for def_id in inlined_into { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - tcx.dep_graph.write(DepNode::Mir(def_id)); - - let caller_mir = cx.mir_mut(def_id); - - debug!("Running simplify cfg on {:?}", def_id); + // 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, @@ -286,8 +217,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; @@ -390,18 +320,11 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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)); - - 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(); From 851a880f52e3d026f4329303df26095f4e42f8f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 17:17:44 -0400 Subject: [PATCH 31/42] remove irrelevant comments --- src/librustc/mir/README.md | 132 +++++++++++-------------------------- 1 file changed, 40 insertions(+), 92 deletions(-) diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md index 143e6e70a82b3..e8ed8bf104cc8 100644 --- a/src/librustc/mir/README.md +++ b/src/librustc/mir/README.md @@ -32,111 +32,59 @@ 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. -Here is a diagram showing the various MIR queries involved in producing -the final `optimized_mir()` for a single def-id `D`. The arrows here -indicate how data flows from query to query. +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) - -> mir_pass((0,0,D)) ---+ each suite consists of many passes - -> ... | - -> mir_pass((0,N,D)) | - -> mir_suite((0,D)) ---+ ---+ there are several suites - -> ... | - -> mir_suite((M,D)) ---+ - -> mir_optimized(D) -``` - -The MIR transformation pipeline is organized into **suites**. When -you ask for `mir_optimized(D)`, it will turn around and request the -result from the final **suite** of MIR passes -(`mir_suite((M,D))`). This will in turn (eventually) trigger the MIR -to be build and then passes through each of the optimization suites. -Each suite internally triggers one query for each of its passes -(`mir_pass(...)`). - -The reason for the suites is that they represent points in the MIR -transformation pipeline where other bits of code are interested in -observing. For example, the `MIR_CONST` suite defines the point where -analysis for constant rvalues and expressions can take -place. `MIR_OPTIMIZED` naturally represents the point where we -actually generate machine code. Nobody should ever request the result -of an individual *pass*, at least outside of the transformation -pipeline: this allows us to add passes into the appropriate suite -without having to modify anything else in the compiler. +- `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 -Each of these intermediate queries yields up a `&'tcx -Steal>`, allocated using `tcx.alloc_steal_mir()`. This -indicates that the result may be **stolen** by the next pass -- 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. +The intermediate queries `mir_const()` and `mir_validated()` yield up +a `&'tcx Steal>`, 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. Sometimes this requires **forcing** queries -(`ty::queries::foo::force(...)`) during an optimization pass -- this -will force a query to execute even though you don't directly require -its result. The query can then read the MIR it needs, and -- once it -is complete -- you can steal it. +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 first pass in the next suite (that pass performs -const promotion): +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_suite((MIR_CONST,D)) --read-by--> mir_const_qualif(D) - | - stolen-by - | - v -mir_pass((MIR_VALIDATED,0,D)) +mir_const(D) --read-by--> mir_const_qualif(D) + | ^ + stolen-by | + | (forces) + v | +mir_validated(D) ------------+ ``` -Therefore, the const promotion pass (the `mir_pass()` in the diagram) -will **force** `mir_const_qualif` before it actually steals, thus -ensuring that the reads have already happened (and the final result is -cached). - ### Implementing and registering a pass -To create a new MIR pass, you have to implement one of the MIR pass -traits. There are several traits, and you want to pick the most -specific one that applies to your pass. They are described here in -order of preference. 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()` with the -appropriate suite. - -**The `MirPass` trait.** For the most part, a MIR pass works by taking -as input the MIR for a single function and mutating it imperatively to -perform an optimization. To write such a pass, you can implement the -`MirPass` trait, which has a single callback that takes an `&mut Mir`. - -**The `DefIdPass` trait.** When a `MirPass` trait is executed, the -system will automatically steal the result of the previous pass and -supply it to you. (See the section on queries and stealing below.) -Sometimes you don't want to steal the result of the previous pass -right away. In such cases, you can define a `DefIdPass`, which simply -gets a callback and lets you decide when to steal the previous result. - -**The `Pass` trait.** The most primitive but flexible trait is `Pass`. -Unlike the other pass types, it returns a `Multi` result, which means -it scan be used for interprocedural passes which mutate more than one -MIR at a time (e.g., `inline`). - -### The MIR Context - -All of the passes when invoked take a `MirCtxt` object. This contains -various methods to find out (e.g.) the current pass suite and pass -index, the def-id you are operating on, and so forth. You can also -access the MIR for the current def-id using `read_previous_mir()`; the -"previous" refers to the fact that this will be the MIR that was -output by the previous pass. Finally, you can `steal_previous_mir()` -to steal the output of the current pass (in which case you get -ownership of the MIR). +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`. + From 2fa1ba3e7ed22e9610ba06618538a7b14f61a9ff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 18:43:46 -0400 Subject: [PATCH 32/42] pacify the mercilous tidy --- src/librustc/ty/steal.rs | 10 ++++++++++ src/librustc_driver/driver.rs | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs index e62872477c47c..fd611266f0836 100644 --- a/src/librustc/ty/steal.rs +++ b/src/librustc/ty/steal.rs @@ -1,3 +1,13 @@ +// 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 or the MIT license +// , 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; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f80d6473dcc54..8350270858427 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -913,7 +913,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // 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_branches::SimplifyBranches::new("initial")); passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts")); // Optimizations begin. From 74b2783877d5f6906a2e532828203f155054d8f9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 May 2017 18:44:25 -0400 Subject: [PATCH 33/42] delete dead code --- src/librustc/ty/maps.rs | 89 +------ src/librustc_mir/callgraph.rs | 249 ------------------ src/librustc_mir/lib.rs | 3 +- src/librustc_mir/transform/interprocedural.rs | 88 ------- src/librustc_mir/transform/mod.rs | 1 - 5 files changed, 3 insertions(+), 427 deletions(-) delete mode 100644 src/librustc_mir/callgraph.rs delete mode 100644 src/librustc_mir/transform/interprocedural.rs diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 5a5dece8a94ec..cec157b03ac0a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -26,15 +26,12 @@ use util::nodemap::{DefIdSet, NodeSet}; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; -use std::option; use std::fmt::Debug; use std::hash::Hash; -use std::iter::{self, Once}; use std::mem; use std::collections::BTreeMap; use std::ops::Deref; use std::rc::Rc; -use std::vec; use syntax_pos::{Span, DUMMY_SP}; use syntax::symbol::Symbol; @@ -161,67 +158,6 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { } } -trait IntoKeyValues { - type KeyValues: IntoIterator; - - fn into_key_values(key: &K, value: Self) -> Self::KeyValues; -} - -impl IntoKeyValues for V { - type KeyValues = Once<(K, V)>; - - fn into_key_values(key: &K, value: Self) -> Self::KeyValues { - iter::once((key.clone(), value)) - } -} - -/// Return type for a multi-query, which is a query which may (if it -/// chooses) return more than one (key, value) pair. Construct a -/// `Multi` using `Multi::from(...)`. -pub struct Multi { - single: Option, - map: Vec<(K, V)>, -} - -impl Multi { - pub fn iter<'a>(&'a self, key: &'a K) -> impl Iterator + 'a { - self.single.iter() - .map(move |v| (key, v)) - .chain(self.map.iter().map(move |&(ref k, ref v)| (k, v))) - } -} - -/// Construct a `Multi` from a single value. -impl From for Multi { - fn from(value: V) -> Self { - Multi { - single: Some(value), - map: vec![], - } - } -} - -/// Construct a `Multi` from a hashmap of (K, V) pairs. -impl From> for Multi { - fn from(value: Vec<(K, V)>) -> Self { - Multi { - single: None, - map: value - } - } -} - -impl IntoKeyValues for Multi { - type KeyValues = iter::Chain, vec::IntoIter<(K, V)>>; - - fn into_key_values(key: &K, value: Self) -> Self::KeyValues { - value.single - .map(|v| (key.clone(), v)) - .into_iter() - .chain(value.map) - } -} - pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -490,14 +426,7 @@ macro_rules! define_maps { provider(tcx.global_tcx(), key) })?; - { - let map = &mut *tcx.maps.$name.borrow_mut(); - for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(&key, result) { - map.insert(k, v); - } - } - - Ok(f(tcx.maps.$name.borrow().get(&key).expect("value just generated"))) + 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) @@ -683,20 +612,6 @@ macro_rules! define_provider_struct { } }; - // The `multi` modifier indicates a **multiquery**, in which case - // the function returns a `Multi` instead of just a value - // `V`. - (tcx: $tcx:tt, - input: (([multi $($other_modifiers:tt)*] $name:tt [$K:ty] [$V:ty]) $($input:tt)*), - output: $output:tt) => { - define_provider_struct! { - tcx: $tcx, - ready: ($name [$K] [Multi<$K,$V>]), - input: ($($input)*), - output: $output - } - }; - // Regular queries produce a `V` only. (tcx: $tcx:tt, input: (([] $name:tt $K:tt $V:tt) $($input:tt)*), @@ -709,7 +624,7 @@ macro_rules! define_provider_struct { } }; - // Skip modifiers other than `multi`. + // Skip modifiers. (tcx: $tcx:tt, input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), output: $output:tt) => { diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs deleted file mode 100644 index 977b9d2e99447..0000000000000 --- a/src/librustc_mir/callgraph.rs +++ /dev/null @@ -1,249 +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 or the MIT license -// , 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, LOCAL_CRATE}; -use rustc_data_structures::graph; - -use rustc::mir::*; -use rustc::mir::visit::*; - -use rustc::ty; - -use rustc::util::nodemap::DefIdMap; - -use transform::interprocedural::InterproceduralCx; - -pub struct CallGraph { - node_map: DefIdMap, - graph: graph::Graph -} - -impl CallGraph { - pub fn build<'a, 'tcx>(cx: &mut InterproceduralCx<'a, 'tcx>) -> CallGraph { - let mut callgraph = CallGraph { - node_map: DefIdMap(), - graph: graph::Graph::new() - }; - - for &def_id in cx.tcx.mir_keys(LOCAL_CRATE).iter() { - let idx = callgraph.add_node(def_id); - - let mut call_visitor = CallVisitor { - caller: idx, - graph: &mut callgraph - }; - - if let Some(mir) = cx.ensure_mir_and_read(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, - index: usize, - node_indices: Vec>, - scc_stack: Vec, - current_scc: Vec, - visit_stack: Vec>, -} - -impl<'g> SCCIterator<'g> { - pub fn new(graph: &'g graph::Graph) -> 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, - 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 { - 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; - - fn next(&mut self) -> Option> { - 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()) - } - } -} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 682a5c6f8acdf..0213dbc730279 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,8 +46,7 @@ extern crate rustc_const_eval; pub mod diagnostics; -pub mod build; -pub mod callgraph; +mod build; mod hair; mod shim; mod queries; diff --git a/src/librustc_mir/transform/interprocedural.rs b/src/librustc_mir/transform/interprocedural.rs deleted file mode 100644 index 7a2645567e24e..0000000000000 --- a/src/librustc_mir/transform/interprocedural.rs +++ /dev/null @@ -1,88 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::hir::def_id::DefId; -use rustc::mir::Mir; -use rustc::mir::transform::{PassId}; -use rustc::ty::steal::Steal; -use rustc::ty::TyCtxt; -use rustc_data_structures::fx::FxHashMap; - -/// When writing inter-procedural analyses etc, we need to read (and -/// steal) the MIR for a number of def-ids at once, not all of which -/// are local. This little cache code attempts to remember what you've -/// stolen and so forth. It is more of a placeholder meant to get -/// inlining up and going again, and is probably going to need heavy -/// revision as we scale up to more interesting optimizations. -pub struct InterproceduralCx<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - local_cache: FxHashMap>, -} - -impl<'a, 'tcx> InterproceduralCx<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - InterproceduralCx { - tcx: tcx, - local_cache: FxHashMap::default(), - } - } - - pub fn into_local_mirs(self) -> Vec<(PassId, &'tcx Steal>)> { - unimplemented!() - } - - /// Ensures that the mir for `def_id` is available, if it can be - /// made available. - pub fn ensure_mir(&mut self, def_id: DefId) { - if def_id.is_local() { - self.ensure_mir_and_read(def_id); - } - } - - /// Ensures that the mir for `def_id` is available and returns it if possible; - /// returns `None` if this is a cross-crate MIR that is not - /// available from metadata. - pub fn ensure_mir_and_read(&mut self, def_id: DefId) -> Option<&Mir<'tcx>> { - if def_id.is_local() { - Some(self.mir_mut(def_id)) - } else { - self.tcx.maybe_item_mir(def_id) - } - } - - /// True if the local cache contains MIR for `def-id`. - pub fn contains_mir(&self, def_id: DefId) -> bool { - if def_id.is_local() { - self.local_cache.contains_key(&def_id) - } else { - self.tcx.is_item_mir_available(def_id) - } - } - - /// Reads the MIR for `def-id`. If the MIR is local, this will - /// panic if you have not previously invoked `ensure_mir`. - pub fn mir(&self, def_id: DefId) -> Option<&Mir<'tcx>> { - if def_id.is_local() { - match self.local_cache.get(&def_id) { - Some(p) => Some(p), - None => { - panic!("MIR for local def-id `{:?}` not previously ensured", def_id) - } - } - } else { - self.tcx.maybe_item_mir(def_id) - } - } - - pub fn mir_mut(&mut self, def_id: DefId) -> &mut Mir<'tcx> { - assert!(def_id.is_local(), "cannot get mutable mir of remote entry"); - unimplemented!() - } -} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 971b0206a9ebd..e835a79a8bc3a 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -26,7 +26,6 @@ pub mod deaggregator; pub mod instcombine; pub mod copy_prop; pub mod inline; -pub mod interprocedural; pub(crate) fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); From c7023d1c2fbb9e136084b0d35164aff5eb2071ae Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 06:07:54 -0400 Subject: [PATCH 34/42] run MIR borrowck on the validated, not optimized, MIR --- src/librustc/hir/map/mod.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 5 ++++- src/librustc_borrowck/borrowck/mod.rs | 13 +++++++++++++ src/librustc_mir/queries.rs | 4 ++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 48b8a819fff03..abc967dec905c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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 { diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index de5613dbfaa38..47f708bf58367 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -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 }; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 1259816639a1e..8a5f1fe3da0ac 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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); diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs index b9d6e527e556c..947b6df4bf0e8 100644 --- a/src/librustc_mir/queries.rs +++ b/src/librustc_mir/queries.rs @@ -110,6 +110,10 @@ fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx } 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); From 393fa4f1b715234bfb8a80699668dada8a3880c7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 06:08:13 -0400 Subject: [PATCH 35/42] rename from `item_mir` to `optimized_mir` --- src/librustc/ty/maps.rs | 4 ++-- src/librustc/ty/mod.rs | 21 ++++++--------------- src/librustc_metadata/cstore_impl.rs | 6 +++--- src/librustc_metadata/decoder.rs | 8 ++++---- src/librustc_metadata/encoder.rs | 22 +++++++++++----------- src/librustc_mir/queries.rs | 4 ++-- src/librustc_mir/transform/inline.rs | 2 +- src/librustc_mir/util/graphviz.rs | 2 +- src/librustc_mir/util/pretty.rs | 2 +- src/librustc_passes/mir_stats.rs | 2 +- src/librustc_trans/collector.rs | 2 +- 11 files changed, 33 insertions(+), 42 deletions(-) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index cec157b03ac0a..385abbd039e08 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -333,7 +333,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)) @@ -770,7 +770,7 @@ define_maps! { <'tcx> [] item_body_nested_bodies: metadata_dep_node(DefId) -> Rc>, [] 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 { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 537846bc0f477..8191b392de528 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2324,18 +2324,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Given the did of an item, returns its (optimized) MIR, borrowed immutably. - pub fn item_mir(self, did: DefId) -> &'gcx Mir<'gcx> { - self.optimized_mir(did) - } - /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>) -> &'gcx Mir<'gcx> { match instance { ty::InstanceDef::Item(did) => { - self.item_mir(did) + self.optimized_mir(did) } ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) | @@ -2349,16 +2344,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// 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<&'gcx Mir<'gcx>> { - if did.is_local() && !self.mir_keys(LOCAL_CRATE).contains(&did) { - return None; - } - - if !did.is_local() && !self.is_item_mir_available(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 } - - Some(self.item_mir(did)) } /// Get the attributes of a definition. diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7bc27596e40e7..872b2eb6f7113 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -95,8 +95,8 @@ provide! { <'tcx> tcx, def_id, cdata }) } optimized_mir => { - let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| { - bug!("get_item_mir: missing MIR for `{:?}`", def_id) + 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); @@ -122,7 +122,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() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5d0e78da2f8fa..ae755adcf5fbb 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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> { + pub fn maybe_get_optimized_mir(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) + -> Option> { match self.is_proc_macro(id) { true => None, false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2160a56257b59..125026b799c98 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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,10 +619,10 @@ 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>> { + fn encode_optimized_mir(&mut self, def_id: DefId) -> Option>> { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { - let mir = self.tcx.item_mir(def_id); + let mir = self.tcx.optimized_mir(def_id); Some(self.lazy(&mir)) } else { None @@ -861,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 } @@ -1166,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), } } @@ -1192,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), } } diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs index 947b6df4bf0e8..3e12221f85234 100644 --- a/src/librustc_mir/queries.rs +++ b/src/librustc_mir/queries.rs @@ -38,12 +38,12 @@ pub fn provide(providers: &mut Providers) { mir_const, mir_validated, optimized_mir, - is_item_mir_available, + is_mir_available, ..*providers }; } -fn is_item_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { +fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { tcx.mir_keys(def_id.krate).contains(&def_id) } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 614b5e2cc3f8d..3f6ce9c9446f2 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { loop { local_change = false; while let Some(callsite) = callsites.pop_front() { - if !self.tcx.is_item_mir_available(callsite.callee) { + if !self.tcx.is_mir_available(callsite.callee) { continue; } diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index d3d3977a934d3..cf13a80e677b1 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -29,7 +29,7 @@ pub fn write_mir_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { 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)?; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 4f94c4d122bad..5f51888019b9d 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -127,7 +127,7 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut first = true; for def_id in dump_mir_def_ids(tcx, single) { - let mir = &tcx.item_mir(def_id); + let mir = &tcx.optimized_mir(def_id); if first { first = false; diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 39b3b709af7ed..d9921e62330b9 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -46,7 +46,7 @@ pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) { // about maintaining the dep graph. let _ignore = tcx.dep_graph.in_ignore(); for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() { - let mir = tcx.item_mir(def_id); + let mir = tcx.optimized_mir(def_id); collector.visit_mir(&mir); } collector.print(title); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 786001161573f..6d7d95f548721 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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 From b0092e89e03bf79ed34b4c8e18d296c762ee80b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 06:32:03 -0400 Subject: [PATCH 36/42] move queries code into transform --- src/librustc_mir/lib.rs | 2 - src/librustc_mir/queries.rs | 121 ------------------------------ src/librustc_mir/transform/mod.rs | 105 ++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 129 deletions(-) delete mode 100644 src/librustc_mir/queries.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 0213dbc730279..5fa56bac1379b 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -49,14 +49,12 @@ pub mod diagnostics; mod build; mod hair; mod shim; -mod queries; pub mod transform; pub mod util; use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { - queries::provide(providers); shim::provide(providers); transform::provide(providers); } diff --git a/src/librustc_mir/queries.rs b/src/librustc_mir/queries.rs deleted file mode 100644 index 3e12221f85234..0000000000000 --- a/src/librustc_mir/queries.rs +++ /dev/null @@ -1,121 +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 or the MIT license -// , 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::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::mir::Mir; -use rustc::mir::transform::{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 syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; -use transform; - -use std::rc::Rc; - -pub fn provide(providers: &mut 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 { - 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> { - 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> { - 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) -} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index e835a79a8bc3a..fcea5d4c86047 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,10 +8,21 @@ // 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}; -use rustc::ty::TyCtxt; +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; @@ -30,14 +41,96 @@ 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 }; } -pub(crate) fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, - suite: MirSuite, - mir: &mut Mir<'tcx>) +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 { + 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> { + 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> { + 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); From 0afcfce8d85b23c85303b7184c9a3d0bb28a4f6b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 06:33:11 -0400 Subject: [PATCH 37/42] update comment about heuristics --- src/librustc_mir/transform/inline.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 3f6ce9c9446f2..f60dcbed6ba47 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -72,7 +72,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // inline. // // We use a queue so that we inline "broadly" before we inline - // in depth. It is unclear if this is the current heuristic. + // 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(); From 15bc2f4ca07106368789eb802956f7cc89da011d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 06:34:29 -0400 Subject: [PATCH 38/42] remove temporary variable --- src/librustc_mir/shim.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index a899c69ca150a..1458ea7fdd6a2 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -114,8 +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); - result + tcx.alloc_mir(result) } #[derive(Copy, Clone, Debug, PartialEq)] From e6793ac452268216b131be1a12a994f2ab87135d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 09:52:12 -0400 Subject: [PATCH 39/42] have borrowck fetch MIR, which will perform some errors --- src/librustc_borrowck/borrowck/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 8a5f1fe3da0ac..f8073455bd08a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -109,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); From afc5acd84ba97e1e767dc489ebcc07c0bfc2c5cb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 11:31:10 -0400 Subject: [PATCH 40/42] fix librustc_driver --- src/librustc_driver/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ced30fd64085c..494055634061e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -141,6 +141,7 @@ fn test_env(source_string: &str, TyCtxt::create_and_enter(&sess, ty::maps::Providers::default(), ty::maps::Providers::default(), + Rc::new(sess.mir_passes.borrow().clone()), &arenas, &arena, resolutions, From 25be7983e80bb1c370772ebbb97891d2030d68f0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 13:58:49 -0400 Subject: [PATCH 41/42] remove `mir_passes` from `Session` and add a FIXME --- src/librustc/mir/transform.rs | 2 ++ src/librustc/session/mod.rs | 3 --- src/librustc_driver/driver.rs | 4 ++-- src/librustc_driver/test.rs | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 77d4eefb1def5..aa91123ef6952 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -134,6 +134,8 @@ pub trait MirPass { } /// A manager for MIR passes. +/// +/// FIXME(#41712) -- it is unclear whether we should have this struct. #[derive(Clone)] pub struct Passes { pass_hooks: Vec>, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c8732c31663eb..ec3eaa124c307 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -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>, pub plugin_llvm_passes: RefCell>, - pub mir_passes: RefCell, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, @@ -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()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8350270858427..9f0f567b6cee1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,7 +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}; +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; @@ -904,7 +904,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_const_eval::provide(&mut extern_providers); // Setup the MIR passes that we want to run. - let mut passes = sess.mir_passes.borrow().clone(); + let mut passes = Passes::new(); passes.push_hook(mir::transform::dump_mir::DumpMir); // What we need to do constant evaluation. diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 494055634061e..8b95be00fa752 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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,7 +142,7 @@ fn test_env(source_string: &str, TyCtxt::create_and_enter(&sess, ty::maps::Providers::default(), ty::maps::Providers::default(), - Rc::new(sess.mir_passes.borrow().clone()), + Rc::new(Passes::new()), &arenas, &arena, resolutions, From 488b2a3e7b9d8a4c96f388dc7d8fdd2023ecc815 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 May 2017 13:59:15 -0400 Subject: [PATCH 42/42] add FIXME to `Steal` --- src/librustc/ty/steal.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs index fd611266f0836..0b0818888812f 100644 --- a/src/librustc/ty/steal.rs +++ b/src/librustc/ty/steal.rs @@ -29,6 +29,8 @@ use std::mem; /// 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 { value: RefCell> }