diff --git a/rapx/src/analysis/core/alias_analysis/default/alias.rs b/rapx/src/analysis/core/alias_analysis/default/alias.rs index 02cd3d71..b8aad0c3 100644 --- a/rapx/src/analysis/core/alias_analysis/default/alias.rs +++ b/rapx/src/analysis/core/alias_analysis/default/alias.rs @@ -584,8 +584,6 @@ impl<'tcx> MopGraph<'tcx> { } pub fn is_no_alias_intrinsic(def_id: DefId) -> bool { - if def_id == call_mut() || def_id == clone() || def_id == take() { - return true; - } - return false; + let v = [call_mut_opt(), clone_opt(), take_opt()]; + contains(&v, def_id) } diff --git a/rapx/src/analysis/core/alias_analysis/default/graph.rs b/rapx/src/analysis/core/alias_analysis/default/graph.rs index f8daa2a0..2bb20c70 100644 --- a/rapx/src/analysis/core/alias_analysis/default/graph.rs +++ b/rapx/src/analysis/core/alias_analysis/default/graph.rs @@ -423,13 +423,7 @@ impl<'tcx> MopGraph<'tcx> { } => { if let Operand::Constant(c) = func { if let &ty::FnDef(id, ..) = c.ty().kind() { - // for no_std crates without using alloc, - // dealloc will be never found, thus call dealloc_opt here - if id == drop() - || id == drop_in_place() - || id == manually_drop() - || dealloc_opt().map(|f| f == id).unwrap_or(false) - { + if is_drop_fn(id) { cur_bb.terminator = Term::Drop(terminator.clone()); } else { cur_bb.terminator = Term::Call(terminator.clone()); diff --git a/rapx/src/analysis/core/alias_analysis/default/mod.rs b/rapx/src/analysis/core/alias_analysis/default/mod.rs index 9f29b56a..f0036cb9 100644 --- a/rapx/src/analysis/core/alias_analysis/default/mod.rs +++ b/rapx/src/analysis/core/alias_analysis/default/mod.rs @@ -233,14 +233,14 @@ impl<'tcx> AliasAnalyzer<'tcx> { fn handle_conor_cases(&mut self) { let cases = [ - copy_from_nonoverlapping(), - copy_to_nonoverlapping(), - copy_to(), - copy_from(), + copy_from_nonoverlapping_opt(), + copy_to_nonoverlapping_opt(), + copy_to_opt(), + copy_from_opt(), ]; let alias = MopAliasPair::new(1, true, true, 2, true, true); for (key, value) in self.fn_map.iter_mut() { - if cases.iter().any(|lock| lock == key) { + if contains(&cases, *key) { value.alias_set.clear(); value.alias_set.insert(alias.clone()); } diff --git a/rapx/src/analysis/utils/fn_info.rs b/rapx/src/analysis/utils/fn_info.rs index 32c0eb13..032d673a 100644 --- a/rapx/src/analysis/utils/fn_info.rs +++ b/rapx/src/analysis/utils/fn_info.rs @@ -1418,16 +1418,11 @@ pub fn generate_mir_cfg_dot<'tcx>( is_drop_related = true; } TerminatorKind::Call { func, .. } => { - if let Operand::Constant(c) = func { - if let ty::FnDef(def_id, _) = *c.ty().kind() { - if def_id == drop() - || def_id == drop_in_place() - || def_id == manually_drop() - || dealloc_opt().map(|f| f == def_id).unwrap_or(false) - { - is_drop_related = true; - } - } + if let Operand::Constant(c) = func + && let ty::FnDef(def_id, _) = *c.ty().kind() + && is_drop_fn(def_id) + { + is_drop_related = true; } } _ => {} diff --git a/rapx/src/def_id.rs b/rapx/src/def_id.rs index 72a4bed9..c927c86d 100644 --- a/rapx/src/def_id.rs +++ b/rapx/src/def_id.rs @@ -79,12 +79,16 @@ macro_rules! intrinsics { ($( $id:ident : $paths:expr ,)+ ) => { const INTRINSICS: &[&[&str]] = &[$( $paths ,)+]; $( - pub fn $id() -> DefId { - ${concat($id, _opt)} ().unwrap_or_else(|| - panic!("Failed to retrieve the DefId of {:#?}.", $paths) - ) - } + // Retrieved the fn DefId. Panic if the fn doesn't exist. + // pub fn $id() -> DefId { + // ${concat($id, _opt)} ().unwrap_or_else(|| + // panic!("Failed to retrieve the DefId of {:#?}.", $paths) + // ) + // } + // Retrieved the fn DefId. Returns None if the fn doesn't exist. + // This is preferred especially RAPx is used to compile nostd crates or build-std, + // where the fn is likely absent. pub fn ${concat($id, _opt)} () -> Option { let map = &INIT.get().expect("Intrinsics DefIds haven't been initialized.").map; for path in $paths { @@ -168,3 +172,20 @@ intrinsics! { pub fn to_internal(val: &T, tcx: TyCtxt) -> DefId { rustc_internal::internal(tcx, val.def_id()) } + +/// Find any drop fn. Any of these drop fns can be missing, e.g. for crates like no_std without +/// using alloc, dealloc doesn't exist. +pub fn is_drop_fn(target: DefId) -> bool { + let drop_fn = [ + drop_opt(), + drop_in_place_opt(), + manually_drop_opt(), + dealloc_opt(), + ]; + contains(&drop_fn, target) +} + +/// Is the targe DefId in the given array. +pub fn contains(v: &[Option], target: DefId) -> bool { + v.contains(&Some(target)) +} diff --git a/rapx/src/lib.rs b/rapx/src/lib.rs index 01d05d1f..29c7466b 100644 --- a/rapx/src/lib.rs +++ b/rapx/src/lib.rs @@ -145,11 +145,18 @@ impl Callbacks for RapCallback { fn after_crate_root_parsing( &mut self, - _compiler: &interface::Compiler, + compiler: &interface::Compiler, krate: &mut ast::Crate, ) -> Compilation { - preprocess::dummy_fns::create_dummy_fns(krate); - preprocess::ssa_preprocess::create_ssa_struct(krate); + let build_std = compiler + .sess + .opts + .crate_name + .as_deref() + .map(|s| matches!(s, "core" | "std")) + .unwrap_or(false); + preprocess::dummy_fns::create_dummy_fns(krate, build_std); + preprocess::ssa_preprocess::create_ssa_struct(krate, build_std); Compilation::Continue } fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation { diff --git a/rapx/src/preprocess/dummy_fns.rs b/rapx/src/preprocess/dummy_fns.rs index 2a1145a0..26d04e2d 100644 --- a/rapx/src/preprocess/dummy_fns.rs +++ b/rapx/src/preprocess/dummy_fns.rs @@ -1,4 +1,4 @@ -use super::doc_attr; +use super::set_attrs; use rustc_ast::*; use rustc_span::{DUMMY_SP, symbol::Ident}; use thin_vec::ThinVec; @@ -31,7 +31,7 @@ fn make_dummy_block() -> Block { } } -fn make_dummy_fn(ident_name: &str) -> Box { +fn make_dummy_fn(ident_name: &str, build_std: bool) -> Box { let ident = Ident::from_str(ident_name); let fn_ast = Fn { @@ -45,7 +45,7 @@ fn make_dummy_fn(ident_name: &str) -> Box { }; Box::new(Item { - attrs: ThinVec::from([doc_attr()]), + attrs: set_attrs(build_std), id: DUMMY_NODE_ID, kind: ItemKind::Fn(Box::new(fn_ast)), vis: Visibility { @@ -58,8 +58,8 @@ fn make_dummy_fn(ident_name: &str) -> Box { }) } -pub(crate) fn create_dummy_fns(krate: &mut Crate) { - let raw_ptr_fn = make_dummy_fn("__raw_ptr_deref_dummy"); +pub(crate) fn create_dummy_fns(krate: &mut Crate, build_std: bool) { + let raw_ptr_fn = make_dummy_fn("__raw_ptr_deref_dummy", build_std); //let static_mut_fn = make_dummy_fn("__static_mut_deref_dummy"); krate.items.push(raw_ptr_fn); diff --git a/rapx/src/preprocess/mod.rs b/rapx/src/preprocess/mod.rs index 00a8592b..6803b43c 100644 --- a/rapx/src/preprocess/mod.rs +++ b/rapx/src/preprocess/mod.rs @@ -1,12 +1,17 @@ pub mod dummy_fns; pub mod ssa_preprocess; -use rustc_ast::{token::CommentKind, *}; -use rustc_span::{DUMMY_SP, symbol::Symbol}; +use rustc_ast::{ + token::{CommentKind, Delimiter, Lit, Token, TokenKind}, + tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}, + *, +}; +use rustc_span::{DUMMY_SP, Ident, symbol::Symbol}; +use thin_vec::ThinVec; /// Empty `#[doc]` on the struct. /// cc https://github.com/Artisan-Lab/RAPx/issues/184 -pub fn doc_attr() -> Attribute { +fn doc_attr() -> Attribute { Attribute { kind: AttrKind::DocComment(CommentKind::Line, Symbol::intern("doc")), id: AttrId::ZERO, @@ -14,3 +19,46 @@ pub fn doc_attr() -> Attribute { span: DUMMY_SP, } } + +// #[stable(feature = "foo", since = "1.93")] +fn stability_attr() -> Attribute { + let mut attr = NormalAttr::from_ident(Ident::from_str("stable")); + let tokens: Vec<_> = { + let feature = Token::from_ast_ident(Ident::from_str("feature")); + let eq = Token::new(TokenKind::Eq, DUMMY_SP); + let feature_val = Token::new( + TokenKind::Literal(Lit::new(token::LitKind::Str, Symbol::intern("foo"), None)), + DUMMY_SP, + ); + let comma = Token::new(TokenKind::Comma, DUMMY_SP); + let since = Token::from_ast_ident(Ident::from_str("since")); + let since_val = Token::new( + TokenKind::Literal(Lit::new(token::LitKind::Str, Symbol::intern("1.93"), None)), + DUMMY_SP, + ); + [feature, eq, feature_val, comma, since, eq, since_val] + .into_iter() + .map(|t| TokenTree::Token(t, Spacing::Alone)) + .collect() + }; + attr.item.args = AttrArgs::Delimited(DelimArgs { + dspan: DelimSpan::dummy(), + delim: Delimiter::Parenthesis, + tokens: TokenStream::new(tokens), + }); + Attribute { + kind: AttrKind::Normal(attr.into()), + id: AttrId::ZERO, + style: AttrStyle::Outer, + span: DUMMY_SP, + } +} + +fn set_attrs(build_std: bool) -> ThinVec { + let mut v = ThinVec::with_capacity(2); + v.push(doc_attr()); + if build_std { + v.push(stability_attr()); + } + v +} diff --git a/rapx/src/preprocess/ssa_preprocess.rs b/rapx/src/preprocess/ssa_preprocess.rs index 76e407c8..93a88f93 100644 --- a/rapx/src/preprocess/ssa_preprocess.rs +++ b/rapx/src/preprocess/ssa_preprocess.rs @@ -1,4 +1,4 @@ -use super::doc_attr; +use super::set_attrs; use rustc_ast::*; use rustc_span::{ DUMMY_SP, @@ -6,7 +6,7 @@ use rustc_span::{ }; use thin_vec::ThinVec; -pub(crate) fn create_ssa_struct(_krate: &mut Crate) { +pub(crate) fn create_ssa_struct(_krate: &mut Crate, build_std: bool) { rap_debug!("[CALLBACK] Injecting new structs into the AST..."); let ssa_struct = create_struct( @@ -23,6 +23,7 @@ pub(crate) fn create_ssa_struct(_krate: &mut Crate) { ("para9", Symbol::intern("i128")), ("para10", Symbol::intern("i128")), ], + build_std, ); let essa_struct = create_struct( @@ -32,6 +33,7 @@ pub(crate) fn create_ssa_struct(_krate: &mut Crate) { ("op2", Symbol::intern("i128")), ("cmp", Symbol::intern("i128")), ], + build_std, ); _krate.items.push(ssa_struct); @@ -39,11 +41,15 @@ pub(crate) fn create_ssa_struct(_krate: &mut Crate) { // println!("[CALLBACK] Injection complete. Continuing compilation..."); } -pub(crate) fn create_struct(name: &str, fields_def: Vec<(&str, Symbol)>) -> Box { +pub(crate) fn create_struct( + name: &str, + fields_def: Vec<(&str, Symbol)>, + build_std: bool, +) -> Box { let fields: ThinVec = fields_def .into_iter() .map(|(fname, fty)| FieldDef { - attrs: ThinVec::from([doc_attr()]), + attrs: set_attrs(build_std), vis: Visibility { span: DUMMY_SP, kind: VisibilityKind::Public, @@ -76,7 +82,7 @@ pub(crate) fn create_struct(name: &str, fields_def: Vec<(&str, Symbol)>) -> Box< let item_kind = ItemKind::Struct(ident, Generics::default(), variant_data); Box::new(Item { - attrs: ThinVec::from([doc_attr()]), + attrs: set_attrs(build_std), id: NodeId::from_u32(0), kind: item_kind, vis: Visibility {