@@ -84,6 +84,7 @@ use self::TupleArgumentsFlag::*;
84
84
use astconv:: { self , ast_region_to_region, ast_ty_to_ty, AstConv , PathParamMode } ;
85
85
use check:: _match:: pat_ctxt;
86
86
use fmt_macros:: { Parser , Piece , Position } ;
87
+ use intrinsics;
87
88
use middle:: astconv_util:: { check_path_args, NO_TPS , NO_REGIONS } ;
88
89
use middle:: def;
89
90
use middle:: infer;
@@ -109,7 +110,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
109
110
use util:: lev_distance:: lev_distance;
110
111
111
112
use std:: cell:: { Cell , Ref , RefCell } ;
112
- use std:: collections:: HashSet ;
113
+ use std:: collections:: { HashSet , HashMap } ;
113
114
use std:: iter;
114
115
use std:: mem:: replace;
115
116
use std:: slice;
@@ -5386,16 +5387,18 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
5386
5387
( 0 , vec ! [ tcx. mk_fn( None , fn_ty) , mut_u8] , mut_u8)
5387
5388
}
5388
5389
5389
- name if name. starts_with ( "x86_" ) ||
5390
- name. starts_with ( "arm_" ) ||
5391
- name. starts_with ( "aarch64_" ) => {
5392
- // FIXME: skip checking these for now
5393
- return
5394
- }
5395
5390
ref other => {
5396
- span_err ! ( tcx. sess, it. span, E0093 ,
5397
- "unrecognized intrinsic function: `{}`" , * other) ;
5398
- return ;
5391
+ match intrinsics:: Intrinsic :: find ( tcx, other) {
5392
+ Some ( intr) => {
5393
+ check_platform_intrinsic_type ( ccx, intr, it) ;
5394
+ return
5395
+ }
5396
+ None => {
5397
+ span_err ! ( tcx. sess, it. span, E0093 ,
5398
+ "unrecognized intrinsic function: `{}`" , * other) ;
5399
+ return ;
5400
+ }
5401
+ }
5399
5402
}
5400
5403
} ;
5401
5404
( n_tps, inputs, ty:: FnConverging ( output) )
@@ -5429,3 +5432,97 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
5429
5432
} ) ;
5430
5433
}
5431
5434
}
5435
+
5436
+ fn check_platform_intrinsic_type ( ccx : & CrateCtxt ,
5437
+ expected : intrinsics:: Intrinsic , it : & ast:: ForeignItem ) {
5438
+ let tcx = ccx. tcx ;
5439
+ let i_ty = tcx. lookup_item_type ( local_def ( it. id ) ) ;
5440
+ let i_n_tps = i_ty. generics . types . len ( subst:: FnSpace ) ;
5441
+ if i_n_tps != 0 {
5442
+ tcx. sess . span_err ( it. span ,
5443
+ & format ! ( "intrinsic has wrong number of type parameters: \
5444
+ found {}, expected 0",
5445
+ i_n_tps) ) ;
5446
+ return
5447
+ }
5448
+
5449
+ let mut structural_to_nomimal = HashMap :: new ( ) ;
5450
+
5451
+ let sig = tcx. no_late_bound_regions ( i_ty. ty . fn_sig ( ) ) . unwrap ( ) ;
5452
+ for ( i, ( expected_arg, arg) ) in expected. inputs . iter ( ) . zip ( & sig. inputs ) . enumerate ( ) {
5453
+ match_types ( tcx, & format ! ( "argument {}" , i + 1 ) , it. span ,
5454
+ & mut structural_to_nomimal, expected_arg, arg) ;
5455
+ }
5456
+ match_types ( tcx, "return value" , it. span , & mut structural_to_nomimal,
5457
+ & expected. output , sig. output . unwrap ( ) ) ;
5458
+
5459
+ // walk the expected type and the actual type in lock step, checking they're
5460
+ // the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
5461
+ // exactly the right element type
5462
+ fn match_types < ' tcx , ' a > ( tcx : & ty:: ctxt < ' tcx > ,
5463
+ position : & str ,
5464
+ span : Span ,
5465
+ structural_to_nominal : & mut HashMap < & ' a intrinsics:: Type ,
5466
+ ty:: Ty < ' tcx > > ,
5467
+ expected : & ' a intrinsics:: Type , t : ty:: Ty < ' tcx > ) {
5468
+ use intrinsics:: Type :: * ;
5469
+ match * expected {
5470
+ Integer ( bits) => match ( bits, & t. sty ) {
5471
+ ( 8 , & ty:: TyInt ( ast:: TyI8 ) ) | ( 8 , & ty:: TyUint ( ast:: TyU8 ) ) |
5472
+ ( 16 , & ty:: TyInt ( ast:: TyI16 ) ) | ( 16 , & ty:: TyUint ( ast:: TyU16 ) ) |
5473
+ ( 32 , & ty:: TyInt ( ast:: TyI32 ) ) | ( 32 , & ty:: TyUint ( ast:: TyU32 ) ) |
5474
+ ( 64 , & ty:: TyInt ( ast:: TyI64 ) ) | ( 64 , & ty:: TyUint ( ast:: TyU64 ) ) => { } ,
5475
+ _ => tcx. sess . span_err ( span,
5476
+ & format ! ( "intrinsic {} has wrong type: found `{}`, \
5477
+ expected `i{n}` or `u{n}`",
5478
+ position,
5479
+ t, n = bits) ) ,
5480
+ } ,
5481
+ Float ( bits) => match ( bits, & t. sty ) {
5482
+ ( 32 , & ty:: TyFloat ( ast:: TyF32 ) ) |
5483
+ ( 64 , & ty:: TyFloat ( ast:: TyF64 ) ) => { } ,
5484
+ _ => tcx. sess . span_err ( span,
5485
+ & format ! ( "intrinsic {} has wrong type: found `{}`, \
5486
+ expected `f{n}`",
5487
+ position,
5488
+ t, n = bits) ) ,
5489
+ } ,
5490
+ Pointer ( _) => unimplemented ! ( ) ,
5491
+ Vector ( ref inner_expected, len) => {
5492
+ if t. is_simd ( tcx) {
5493
+ let t_len = t. simd_size ( tcx) ;
5494
+ if len as usize != t_len {
5495
+ tcx. sess . span_err ( span,
5496
+ & format ! ( "intrinsic {} has wrong type: found \
5497
+ vector with length {}, expected length {}",
5498
+ position,
5499
+ t_len, len) ) ;
5500
+ return ;
5501
+ }
5502
+ let t_ty = t. simd_type ( tcx) ;
5503
+ {
5504
+ let previous = structural_to_nominal. entry ( expected) . or_insert ( t) ;
5505
+ if * previous != t {
5506
+ tcx. sess . span_err ( span,
5507
+ & format ! ( "intrinsic {} has wrong type: found `{}`, \
5508
+ but already seen this vector type as `{}`",
5509
+ position, t, previous) ) ;
5510
+ return ;
5511
+ }
5512
+ }
5513
+ match_types ( tcx,
5514
+ position,
5515
+ span,
5516
+ structural_to_nominal,
5517
+ inner_expected,
5518
+ t_ty)
5519
+ } else {
5520
+ tcx. sess . span_err ( span,
5521
+ & format ! ( "intrinsic {} has wrong type: found non-simd type {}, \
5522
+ expected simd type",
5523
+ position, t) ) ;
5524
+ }
5525
+ }
5526
+ }
5527
+ }
5528
+ }
0 commit comments