3
3
use rustc_abi:: { BackendRepr , RegKind } ;
4
4
use rustc_hir:: CRATE_HIR_ID ;
5
5
use rustc_middle:: mir:: { self , traversal} ;
6
- use rustc_middle:: ty:: { self , Instance , InstanceKind , Ty , TyCtxt } ;
7
- use rustc_session:: lint:: builtin:: ABI_UNSUPPORTED_VECTOR_TYPES ;
6
+ use rustc_middle:: ty:: layout:: LayoutCx ;
7
+ use rustc_middle:: ty:: { self , Instance , InstanceKind , Ty , TyCtxt , TypingEnv } ;
8
+ use rustc_session:: lint:: builtin:: { ABI_UNSUPPORTED_VECTOR_TYPES , WASM_C_ABI } ;
8
9
use rustc_span:: def_id:: DefId ;
9
10
use rustc_span:: { DUMMY_SP , Span , Symbol , sym} ;
10
- use rustc_target:: callconv:: { Conv , FnAbi , PassMode } ;
11
+ use rustc_target:: callconv:: { ArgAbi , Conv , FnAbi , PassMode } ;
12
+ use rustc_target:: spec:: { HasWasmCAbiOpt , WasmCAbi } ;
11
13
12
14
use crate :: errors;
13
15
@@ -26,13 +28,15 @@ fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
26
28
/// for a certain function.
27
29
/// `is_call` indicates whether this is a call-site check or a definition-site check;
28
30
/// this is only relevant for the wording in the emitted error.
29
- fn do_check_abi < ' tcx > (
31
+ fn do_check_simd_vector_abi < ' tcx > (
30
32
tcx : TyCtxt < ' tcx > ,
31
33
abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
32
34
def_id : DefId ,
33
35
is_call : bool ,
34
36
span : impl Fn ( ) -> Span ,
35
37
) {
38
+ // We check this on all functions, including those using the "Rust" ABI.
39
+ // For the "Rust" ABI it would be a bug if the lint ever triggered, but better safe than sorry.
36
40
let feature_def = tcx. sess . target . features_for_correct_vector_abi ( ) ;
37
41
let codegen_attrs = tcx. codegen_fn_attrs ( def_id) ;
38
42
let have_feature = |feat : Symbol | {
@@ -88,6 +92,61 @@ fn do_check_abi<'tcx>(
88
92
}
89
93
}
90
94
95
+ /// Determines whether the given argument is passed the same way on the old and new wasm ABIs.
96
+ fn wasm_abi_safe < ' tcx > ( tcx : TyCtxt < ' tcx > , arg : & ArgAbi < ' tcx , Ty < ' tcx > > ) -> bool {
97
+ if matches ! ( arg. layout. backend_repr, BackendRepr :: Scalar ( _) ) {
98
+ return true ;
99
+ }
100
+
101
+ // This matches `unwrap_trivial_aggregate` in the wasm ABI logic.
102
+ if arg. layout . is_aggregate ( ) {
103
+ let cx = LayoutCx :: new ( tcx, TypingEnv :: fully_monomorphized ( ) ) ;
104
+ if let Some ( unit) = arg. layout . homogeneous_aggregate ( & cx) . ok ( ) . and_then ( |ha| ha. unit ( ) ) {
105
+ let size = arg. layout . size ;
106
+ // Ensure there's just a single `unit` element in `arg`.
107
+ if unit. size == size {
108
+ return true ;
109
+ }
110
+ }
111
+ }
112
+
113
+ false
114
+ }
115
+
116
+ /// Warns against usage of `extern "C"` on wasm32-unknown-unknown that is affected by the
117
+ /// ABI transition.
118
+ fn do_check_wasm_abi < ' tcx > (
119
+ tcx : TyCtxt < ' tcx > ,
120
+ abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
121
+ is_call : bool ,
122
+ span : impl Fn ( ) -> Span ,
123
+ ) {
124
+ // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`),
125
+ // and only proceed if `wasm_c_abi_opt` indicates we should emit the lint.
126
+ if !( tcx. sess . target . arch == "wasm32"
127
+ && tcx. sess . target . os == "unknown"
128
+ && tcx. wasm_c_abi_opt ( ) == WasmCAbi :: Legacy { with_lint : true }
129
+ && abi. conv == Conv :: C )
130
+ {
131
+ return ;
132
+ }
133
+ // Warn against all types whose ABI will change. Return values are not affected by this change.
134
+ for arg_abi in abi. args . iter ( ) {
135
+ if wasm_abi_safe ( tcx, arg_abi) {
136
+ continue ;
137
+ }
138
+ let span = span ( ) ;
139
+ tcx. emit_node_span_lint (
140
+ WASM_C_ABI ,
141
+ CRATE_HIR_ID ,
142
+ span,
143
+ errors:: WasmCAbiTransition { ty : arg_abi. layout . ty , is_call } ,
144
+ ) ;
145
+ // Let's only warn once per function.
146
+ break ;
147
+ }
148
+ }
149
+
91
150
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
92
151
/// or return values for which the corresponding target feature is not enabled.
93
152
fn check_instance_abi < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) {
@@ -98,13 +157,10 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
98
157
// function.
99
158
return ;
100
159
} ;
101
- do_check_abi (
102
- tcx,
103
- abi,
104
- instance. def_id ( ) ,
105
- /*is_call*/ false ,
106
- || tcx. def_span ( instance. def_id ( ) ) ,
107
- )
160
+ do_check_simd_vector_abi ( tcx, abi, instance. def_id ( ) , /*is_call*/ false , || {
161
+ tcx. def_span ( instance. def_id ( ) )
162
+ } ) ;
163
+ do_check_wasm_abi ( tcx, abi, /*is_call*/ false , || tcx. def_span ( instance. def_id ( ) ) ) ;
108
164
}
109
165
110
166
/// Checks that a call expression does not try to pass a vector-passed argument which requires a
@@ -141,7 +197,8 @@ fn check_call_site_abi<'tcx>(
141
197
// ABI failed to compute; this will not get through codegen.
142
198
return ;
143
199
} ;
144
- do_check_abi ( tcx, callee_abi, caller. def_id ( ) , /*is_call*/ true , || span) ;
200
+ do_check_simd_vector_abi ( tcx, callee_abi, caller. def_id ( ) , /*is_call*/ true , || span) ;
201
+ do_check_wasm_abi ( tcx, callee_abi, /*is_call*/ true , || span) ;
145
202
}
146
203
147
204
fn check_callees_abi < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > , body : & mir:: Body < ' tcx > ) {
0 commit comments