@@ -37,6 +37,79 @@ fn stmt_str_literal(stmt: &rustc_hir::Stmt) -> Option<String> {
3737 }
3838}
3939
40+
41+ fn is_annotated_as_extern_spec_fn_impl ( tcx : & TyCtxt , local_def_id : & LocalDefId ) -> bool {
42+ tcx. get_attrs_by_path (
43+ local_def_id. to_def_id ( ) ,
44+ & analyze:: annot:: extern_spec_fn_path ( ) ,
45+ )
46+ . next ( )
47+ . is_some ( )
48+ }
49+
50+ /// Extract the target DefId from `#[thrust::extern_spec_fn]` function.
51+ ///
52+ /// The target is identified as the tail call expression (last expression without
53+ /// semicolon) in the function body block.
54+ fn extern_spec_fn_target_def_id_impl < ' tcx > ( tcx : & TyCtxt < ' tcx > , local_def_id : & LocalDefId , mir_body : & Body < ' tcx > ) -> DefId {
55+ let hir_node = tcx. hir_node_by_def_id ( * local_def_id) ;
56+ let hir_body_id = match hir_node {
57+ rustc_hir:: Node :: Item ( item) => {
58+ let rustc_hir:: ItemKind :: Fn { body : body_id, .. } = item. kind else {
59+ panic ! ( "extern_spec_fn must be a function" ) ;
60+ } ;
61+ body_id
62+ }
63+ rustc_hir:: Node :: ImplItem ( impl_item) => {
64+ let rustc_hir:: ImplItemKind :: Fn ( _, body_id) = impl_item. kind else {
65+ panic ! ( "extern_spec_fn must be a function" ) ;
66+ } ;
67+ body_id
68+ }
69+ rustc_hir:: Node :: TraitItem ( trait_item) => {
70+ let rustc_hir:: TraitItemKind :: Fn ( _, rustc_hir:: TraitFn :: Provided ( body_id) ) =
71+ trait_item. kind
72+ else {
73+ panic ! ( "extern_spec_fn must be a function with a body" ) ;
74+ } ;
75+ body_id
76+ }
77+ _ => panic ! ( "extern_spec_fn must be a function item or impl item" ) ,
78+ } ;
79+
80+ let hir_body = tcx. hir_body ( hir_body_id) ;
81+
82+ // The body is a block; the tail expression is the function call to the target.
83+ let rustc_hir:: ExprKind :: Block ( block, _) = & hir_body. value . kind else {
84+ panic ! ( "extern_spec_fn body must be a block" ) ;
85+ } ;
86+ let tail_expr = block
87+ . expr
88+ . expect ( "extern_spec_fn block must end with a tail call expression" ) ;
89+
90+ let rustc_hir:: ExprKind :: Call ( func_expr, _) = & tail_expr. kind else {
91+ panic ! ( "extern_spec_fn tail expression must be a function call" ) ;
92+ } ;
93+ let rustc_hir:: ExprKind :: Path ( qpath) = & func_expr. kind else {
94+ panic ! ( "extern_spec_fn call must be a path expression" ) ;
95+ } ;
96+
97+ let typeck_result = tcx. typeck ( local_def_id) ;
98+ let hir_id = func_expr. hir_id ;
99+ let rustc_hir:: def:: Res :: Def ( _, def_id) = typeck_result. qpath_res ( qpath, hir_id) else {
100+ panic ! ( "extern_spec_fn call must resolve to a definition" ) ;
101+ } ;
102+
103+ let args = typeck_result. node_args ( hir_id) ;
104+ let typing_env = mir_body. typing_env ( * tcx) ;
105+ let instance = mir_ty:: Instance :: try_resolve ( * tcx, typing_env, def_id, args) . unwrap ( ) ;
106+ if let Some ( instance) = instance {
107+ instance. def_id ( )
108+ } else {
109+ def_id
110+ }
111+ }
112+
40113/// An implementation of the typing of local definitions.
41114///
42115/// The current implementation only applies to function definitions. The entry point is
@@ -46,6 +119,7 @@ pub struct Analyzer<'tcx, 'ctx> {
46119 tcx : TyCtxt < ' tcx > ,
47120
48121 local_def_id : LocalDefId ,
122+ pub owner_fn_id : DefId ,
49123
50124 body : Body < ' tcx > ,
51125 /// to substitute HIR types during translation in [`crate::analyze::annot_fn`]
@@ -201,13 +275,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
201275 }
202276
203277 pub fn is_annotated_as_extern_spec_fn ( & self ) -> bool {
204- self . tcx
205- . get_attrs_by_path (
206- self . local_def_id . to_def_id ( ) ,
207- & analyze:: annot:: extern_spec_fn_path ( ) ,
208- )
209- . next ( )
210- . is_some ( )
278+ is_annotated_as_extern_spec_fn_impl ( & self . tcx , & self . local_def_id )
211279 }
212280
213281 pub fn is_annotated_as_predicate ( & self ) -> bool {
@@ -358,13 +426,15 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
358426 & param_resolver,
359427 self_type_name. clone ( ) ,
360428 self . generic_args ,
429+ self . owner_fn_id ,
361430 ) ;
362431
363432 let mut ensure_annot = self . ctx . extract_ensure_annot (
364433 self . local_def_id ,
365434 & result_param_resolver,
366435 self_type_name. clone ( ) ,
367436 self . generic_args ,
437+ self . owner_fn_id ,
368438 ) ;
369439
370440 if let Some ( trait_item_id) = self . local_trait_item_id ( ) {
@@ -374,12 +444,14 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
374444 & param_resolver,
375445 self_type_name. clone ( ) ,
376446 self . generic_args ,
447+ self . owner_fn_id ,
377448 ) ;
378449 let trait_ensure_annot = self . ctx . extract_ensure_annot (
379450 trait_item_id,
380451 & result_param_resolver,
381452 self_type_name. clone ( ) ,
382453 self . generic_args ,
454+ self . owner_fn_id ,
383455 ) ;
384456
385457 assert ! ( require_annot. is_none( ) || trait_require_annot. is_none( ) ) ;
@@ -447,62 +519,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
447519 /// The target is identified as the tail call expression (last expression without
448520 /// semicolon) in the function body block.
449521 pub fn extern_spec_fn_target_def_id ( & self ) -> DefId {
450- let node = self . tcx . hir_node_by_def_id ( self . local_def_id ) ;
451- let body_id = match node {
452- rustc_hir:: Node :: Item ( item) => {
453- let rustc_hir:: ItemKind :: Fn { body : body_id, .. } = item. kind else {
454- panic ! ( "extern_spec_fn must be a function" ) ;
455- } ;
456- body_id
457- }
458- rustc_hir:: Node :: ImplItem ( impl_item) => {
459- let rustc_hir:: ImplItemKind :: Fn ( _, body_id) = impl_item. kind else {
460- panic ! ( "extern_spec_fn must be a function" ) ;
461- } ;
462- body_id
463- }
464- rustc_hir:: Node :: TraitItem ( trait_item) => {
465- let rustc_hir:: TraitItemKind :: Fn ( _, rustc_hir:: TraitFn :: Provided ( body_id) ) =
466- trait_item. kind
467- else {
468- panic ! ( "extern_spec_fn must be a function with a body" ) ;
469- } ;
470- body_id
471- }
472- _ => panic ! ( "extern_spec_fn must be a function item or impl item" ) ,
473- } ;
474-
475- let body = self . tcx . hir_body ( body_id) ;
476-
477- // The body is a block; the tail expression is the function call to the target.
478- let rustc_hir:: ExprKind :: Block ( block, _) = & body. value . kind else {
479- panic ! ( "extern_spec_fn body must be a block" ) ;
480- } ;
481- let tail_expr = block
482- . expr
483- . expect ( "extern_spec_fn block must end with a tail call expression" ) ;
484-
485- let rustc_hir:: ExprKind :: Call ( func_expr, _) = & tail_expr. kind else {
486- panic ! ( "extern_spec_fn tail expression must be a function call" ) ;
487- } ;
488- let rustc_hir:: ExprKind :: Path ( qpath) = & func_expr. kind else {
489- panic ! ( "extern_spec_fn call must be a path expression" ) ;
490- } ;
491-
492- let typeck_result = self . tcx . typeck ( self . local_def_id ) ;
493- let hir_id = func_expr. hir_id ;
494- let rustc_hir:: def:: Res :: Def ( _, def_id) = typeck_result. qpath_res ( qpath, hir_id) else {
495- panic ! ( "extern_spec_fn call must resolve to a definition" ) ;
496- } ;
497-
498- let args = typeck_result. node_args ( hir_id) ;
499- let typing_env = self . body . typing_env ( self . tcx ) ;
500- let instance = mir_ty:: Instance :: try_resolve ( self . tcx , typing_env, def_id, args) . unwrap ( ) ;
501- if let Some ( instance) = instance {
502- instance. def_id ( )
503- } else {
504- def_id
505- }
522+ extern_spec_fn_target_def_id_impl ( & self . tcx , & self . local_def_id , & self . body )
506523 }
507524
508525 fn is_mut_param ( & self , param_idx : rty:: FunctionParamIdx ) -> bool {
@@ -973,12 +990,18 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
973990 let tcx = ctx. tcx ;
974991 let body = tcx. optimized_mir ( local_def_id. to_def_id ( ) ) . clone ( ) ;
975992 let drop_points = Default :: default ( ) ;
976- let type_builder = ctx. type_builder ( ctx. def_ids ( ) , local_def_id. to_def_id ( ) ) ;
993+ let owner_fn_id = if is_annotated_as_extern_spec_fn_impl ( & tcx, & local_def_id) {
994+ extern_spec_fn_target_def_id_impl ( & tcx, & local_def_id, & body)
995+ } else {
996+ local_def_id. to_def_id ( )
997+ } ;
998+ let type_builder = ctx. type_builder ( ctx. def_ids ( ) , owner_fn_id) ;
977999 let generic_args = tcx. mk_args ( & [ ] ) ;
9781000 Self {
9791001 ctx,
9801002 tcx,
9811003 local_def_id,
1004+ owner_fn_id,
9821005 body,
9831006 generic_args,
9841007 drop_points,
0 commit comments