@@ -37,6 +37,82 @@ fn stmt_str_literal(stmt: &rustc_hir::Stmt) -> Option<String> {
3737 }
3838}
3939
40+ fn is_annotated_as_extern_spec_fn_impl ( tcx : & TyCtxt , local_def_id : & LocalDefId ) -> bool {
41+ tcx. get_attrs_by_path (
42+ local_def_id. to_def_id ( ) ,
43+ & analyze:: annot:: extern_spec_fn_path ( ) ,
44+ )
45+ . next ( )
46+ . is_some ( )
47+ }
48+
49+ /// Extract the target DefId from `#[thrust::extern_spec_fn]` function.
50+ ///
51+ /// The target is identified as the tail call expression (last expression without
52+ /// semicolon) in the function body block.
53+ fn extern_spec_fn_target_def_id_impl < ' tcx > (
54+ tcx : & TyCtxt < ' tcx > ,
55+ local_def_id : & LocalDefId ,
56+ mir_body : & Body < ' tcx > ,
57+ ) -> DefId {
58+ let hir_node = tcx. hir_node_by_def_id ( * local_def_id) ;
59+ let hir_body_id = match hir_node {
60+ rustc_hir:: Node :: Item ( item) => {
61+ let rustc_hir:: ItemKind :: Fn { body : body_id, .. } = item. kind else {
62+ panic ! ( "extern_spec_fn must be a function" ) ;
63+ } ;
64+ body_id
65+ }
66+ rustc_hir:: Node :: ImplItem ( impl_item) => {
67+ let rustc_hir:: ImplItemKind :: Fn ( _, body_id) = impl_item. kind else {
68+ panic ! ( "extern_spec_fn must be a function" ) ;
69+ } ;
70+ body_id
71+ }
72+ rustc_hir:: Node :: TraitItem ( trait_item) => {
73+ let rustc_hir:: TraitItemKind :: Fn ( _, rustc_hir:: TraitFn :: Provided ( body_id) ) =
74+ trait_item. kind
75+ else {
76+ panic ! ( "extern_spec_fn must be a function with a body" ) ;
77+ } ;
78+ body_id
79+ }
80+ _ => panic ! ( "extern_spec_fn must be a function item or impl item" ) ,
81+ } ;
82+
83+ let hir_body = tcx. hir_body ( hir_body_id) ;
84+
85+ // The body is a block; the tail expression is the function call to the target.
86+ let rustc_hir:: ExprKind :: Block ( block, _) = & hir_body. value . kind else {
87+ panic ! ( "extern_spec_fn body must be a block" ) ;
88+ } ;
89+ let tail_expr = block
90+ . expr
91+ . expect ( "extern_spec_fn block must end with a tail call expression" ) ;
92+
93+ let rustc_hir:: ExprKind :: Call ( func_expr, _) = & tail_expr. kind else {
94+ panic ! ( "extern_spec_fn tail expression must be a function call" ) ;
95+ } ;
96+ let rustc_hir:: ExprKind :: Path ( qpath) = & func_expr. kind else {
97+ panic ! ( "extern_spec_fn call must be a path expression" ) ;
98+ } ;
99+
100+ let typeck_result = tcx. typeck ( local_def_id) ;
101+ let hir_id = func_expr. hir_id ;
102+ let rustc_hir:: def:: Res :: Def ( _, def_id) = typeck_result. qpath_res ( qpath, hir_id) else {
103+ panic ! ( "extern_spec_fn call must resolve to a definition" ) ;
104+ } ;
105+
106+ let args = typeck_result. node_args ( hir_id) ;
107+ let typing_env = mir_body. typing_env ( * tcx) ;
108+ let instance = mir_ty:: Instance :: try_resolve ( * tcx, typing_env, def_id, args) . unwrap ( ) ;
109+ if let Some ( instance) = instance {
110+ instance. def_id ( )
111+ } else {
112+ def_id
113+ }
114+ }
115+
40116/// An implementation of the typing of local definitions.
41117///
42118/// The current implementation only applies to function definitions. The entry point is
@@ -46,6 +122,7 @@ pub struct Analyzer<'tcx, 'ctx> {
46122 tcx : TyCtxt < ' tcx > ,
47123
48124 local_def_id : LocalDefId ,
125+ pub owner_fn_id : DefId ,
49126
50127 body : Body < ' tcx > ,
51128 /// to substitute HIR types during translation in [`crate::analyze::annot_fn`]
@@ -201,13 +278,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
201278 }
202279
203280 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 ( )
281+ is_annotated_as_extern_spec_fn_impl ( & self . tcx , & self . local_def_id )
211282 }
212283
213284 pub fn is_annotated_as_predicate ( & self ) -> bool {
@@ -318,7 +389,8 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
318389 . associated_item ( self . local_def_id . to_def_id ( ) )
319390 . trait_item_def_id
320391 . unwrap ( ) ;
321- self . ctx . def_ty_with_args ( trait_item_did, trait_ref. args , trait_ref. def_id )
392+ self . ctx
393+ . def_ty_with_args ( trait_item_did, trait_ref. args , trait_ref. def_id )
322394 }
323395
324396 // Note that we do not expect predicate variables to be generated here
@@ -358,13 +430,15 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
358430 & param_resolver,
359431 self_type_name. clone ( ) ,
360432 self . generic_args ,
433+ self . owner_fn_id ,
361434 ) ;
362435
363436 let mut ensure_annot = self . ctx . extract_ensure_annot (
364437 self . local_def_id ,
365438 & result_param_resolver,
366439 self_type_name. clone ( ) ,
367440 self . generic_args ,
441+ self . owner_fn_id ,
368442 ) ;
369443
370444 if let Some ( trait_item_id) = self . local_trait_item_id ( ) {
@@ -374,12 +448,14 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
374448 & param_resolver,
375449 self_type_name. clone ( ) ,
376450 self . generic_args ,
451+ self . owner_fn_id ,
377452 ) ;
378453 let trait_ensure_annot = self . ctx . extract_ensure_annot (
379454 trait_item_id,
380455 & result_param_resolver,
381456 self_type_name. clone ( ) ,
382457 self . generic_args ,
458+ self . owner_fn_id ,
383459 ) ;
384460
385461 assert ! ( require_annot. is_none( ) || trait_require_annot. is_none( ) ) ;
@@ -447,62 +523,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
447523 /// The target is identified as the tail call expression (last expression without
448524 /// semicolon) in the function body block.
449525 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- }
526+ extern_spec_fn_target_def_id_impl ( & self . tcx , & self . local_def_id , & self . body )
506527 }
507528
508529 fn is_mut_param ( & self , param_idx : rty:: FunctionParamIdx ) -> bool {
@@ -973,12 +994,18 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
973994 let tcx = ctx. tcx ;
974995 let body = tcx. optimized_mir ( local_def_id. to_def_id ( ) ) . clone ( ) ;
975996 let drop_points = Default :: default ( ) ;
976- let type_builder = ctx. type_builder ( ctx. def_ids ( ) , local_def_id. to_def_id ( ) ) ;
997+ let owner_fn_id = if is_annotated_as_extern_spec_fn_impl ( & tcx, & local_def_id) {
998+ extern_spec_fn_target_def_id_impl ( & tcx, & local_def_id, & body)
999+ } else {
1000+ local_def_id. to_def_id ( )
1001+ } ;
1002+ let type_builder = ctx. type_builder ( ctx. def_ids ( ) , owner_fn_id) ;
9771003 let generic_args = tcx. mk_args ( & [ ] ) ;
9781004 Self {
9791005 ctx,
9801006 tcx,
9811007 local_def_id,
1008+ owner_fn_id,
9821009 body,
9831010 generic_args,
9841011 drop_points,
0 commit comments