forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#103464 - JakobDegen:mir-parsing, r=oli-obk
Add support for custom mir This implements rust-lang/compiler-team#564 . Details about the design, motivation, etc. can be found in there. r? ``@oli-obk``
- Loading branch information
Showing
23 changed files
with
921 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//! Provides the implementation of the `custom_mir` attribute. | ||
//! | ||
//! Up until MIR building, this attribute has absolutely no effect. The `mir!` macro is a normal | ||
//! decl macro that expands like any other, and the code goes through parsing, name resolution and | ||
//! type checking like all other code. In MIR building we finally detect whether this attribute is | ||
//! present, and if so we branch off into this module, which implements the attribute by | ||
//! implementing a custom lowering from THIR to MIR. | ||
//! | ||
//! The result of this lowering is returned "normally" from the `mir_built` query, with the only | ||
//! notable difference being that the `injected` field in the body is set. Various components of the | ||
//! MIR pipeline, like borrowck and the pass manager will then consult this field (via | ||
//! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user | ||
//! specified. | ||
//! | ||
//! This file defines the general framework for the custom parsing. The parsing for all the | ||
//! "top-level" constructs can be found in the `parse` submodule, while the parsing for statements, | ||
//! terminators, and everything below can be found in the `parse::instruction` submodule. | ||
//! | ||
|
||
use rustc_ast::Attribute; | ||
use rustc_data_structures::fx::FxHashMap; | ||
use rustc_hir::def_id::DefId; | ||
use rustc_index::vec::IndexVec; | ||
use rustc_middle::{ | ||
mir::*, | ||
thir::*, | ||
ty::{Ty, TyCtxt}, | ||
}; | ||
use rustc_span::Span; | ||
|
||
mod parse; | ||
|
||
pub(super) fn build_custom_mir<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
did: DefId, | ||
thir: &Thir<'tcx>, | ||
expr: ExprId, | ||
params: &IndexVec<ParamId, Param<'tcx>>, | ||
return_ty: Ty<'tcx>, | ||
return_ty_span: Span, | ||
span: Span, | ||
attr: &Attribute, | ||
) -> Body<'tcx> { | ||
let mut body = Body { | ||
basic_blocks: BasicBlocks::new(IndexVec::new()), | ||
source: MirSource::item(did), | ||
phase: MirPhase::Built, | ||
source_scopes: IndexVec::new(), | ||
generator: None, | ||
local_decls: LocalDecls::new(), | ||
user_type_annotations: IndexVec::new(), | ||
arg_count: params.len(), | ||
spread_arg: None, | ||
var_debug_info: Vec::new(), | ||
span, | ||
required_consts: Vec::new(), | ||
is_polymorphic: false, | ||
tainted_by_errors: None, | ||
injection_phase: None, | ||
pass_count: 1, | ||
}; | ||
|
||
body.local_decls.push(LocalDecl::new(return_ty, return_ty_span)); | ||
body.basic_blocks_mut().push(BasicBlockData::new(None)); | ||
body.source_scopes.push(SourceScopeData { | ||
span, | ||
parent_scope: None, | ||
inlined: None, | ||
inlined_parent_scope: None, | ||
local_data: ClearCrossCrate::Clear, | ||
}); | ||
body.injection_phase = Some(parse_attribute(attr)); | ||
|
||
let mut pctxt = ParseCtxt { | ||
tcx, | ||
thir, | ||
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, | ||
body: &mut body, | ||
local_map: FxHashMap::default(), | ||
block_map: FxHashMap::default(), | ||
}; | ||
|
||
let res = (|| { | ||
pctxt.parse_args(¶ms)?; | ||
pctxt.parse_body(expr) | ||
})(); | ||
if let Err(err) = res { | ||
tcx.sess.diagnostic().span_fatal( | ||
err.span, | ||
format!("Could not parse {}, found: {:?}", err.expected, err.item_description), | ||
) | ||
} | ||
|
||
body | ||
} | ||
|
||
fn parse_attribute(attr: &Attribute) -> MirPhase { | ||
let meta_items = attr.meta_item_list().unwrap(); | ||
let mut dialect: Option<String> = None; | ||
let mut phase: Option<String> = None; | ||
|
||
for nested in meta_items { | ||
let name = nested.name_or_empty(); | ||
let value = nested.value_str().unwrap().as_str().to_string(); | ||
match name.as_str() { | ||
"dialect" => { | ||
assert!(dialect.is_none()); | ||
dialect = Some(value); | ||
} | ||
"phase" => { | ||
assert!(phase.is_none()); | ||
phase = Some(value); | ||
} | ||
other => { | ||
panic!("Unexpected key {}", other); | ||
} | ||
} | ||
} | ||
|
||
let Some(dialect) = dialect else { | ||
assert!(phase.is_none()); | ||
return MirPhase::Built; | ||
}; | ||
|
||
MirPhase::parse(dialect, phase) | ||
} | ||
|
||
struct ParseCtxt<'tcx, 'body> { | ||
tcx: TyCtxt<'tcx>, | ||
thir: &'body Thir<'tcx>, | ||
source_info: SourceInfo, | ||
|
||
body: &'body mut Body<'tcx>, | ||
local_map: FxHashMap<LocalVarId, Local>, | ||
block_map: FxHashMap<LocalVarId, BasicBlock>, | ||
} | ||
|
||
struct ParseError { | ||
span: Span, | ||
item_description: String, | ||
expected: String, | ||
} | ||
|
||
impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { | ||
fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError { | ||
let expr = &self.thir[expr]; | ||
ParseError { | ||
span: expr.span, | ||
item_description: format!("{:?}", expr.kind), | ||
expected: expected.to_string(), | ||
} | ||
} | ||
} | ||
|
||
type PResult<T> = Result<T, ParseError>; |
Oops, something went wrong.