Skip to content

Commit f039e11

Browse files
committed
c-variadic: make VaArgSafe a lang item
so that we can check whether a type implements the trait
1 parent 2196d4e commit f039e11

4 files changed

Lines changed: 17 additions & 8 deletions

File tree

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ language_item_table! {
221221
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
222222
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
223223

224+
VaArgSafe, sym::va_arg_safe, va_arg_safe, Target::Trait, GenericRequirement::None;
224225
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
225226

226227
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -490,21 +490,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490490

491491
// There are a few types which get autopromoted when passed via varargs
492492
// in C but we just error out instead and require explicit casts.
493+
//
494+
// We use implementations of VaArgSafe as the source of truth. On some embedded
495+
// targets, c_double is f32 and c_int/c_uing are i16/u16, and these types implement
496+
// VaArgSafe there. On all other targets, these types do not implement VaArgSafe.
497+
let trait_def_id = tcx.lang_items().va_arg_safe().unwrap();
493498
let arg_ty = self.structurally_resolve_type(arg.span, arg_ty);
499+
if self
500+
.type_implements_trait(trait_def_id, [arg_ty], self.param_env)
501+
.must_apply_modulo_regions()
502+
{
503+
continue;
504+
}
505+
494506
match arg_ty.kind() {
495507
ty::Float(ty::FloatTy::F32) => {
496508
variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
497509
}
498-
ty::Int(ty::IntTy::I8) | ty::Bool => {
499-
variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
500-
}
501-
ty::Uint(ty::UintTy::U8) => {
502-
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
503-
}
504-
ty::Int(ty::IntTy::I16) if tcx.sess.target.options.c_int_width > 16 => {
510+
ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => {
505511
variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
506512
}
507-
ty::Uint(ty::UintTy::U16) if tcx.sess.target.options.c_int_width > 16 => {
513+
ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => {
508514
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
509515
}
510516
ty::FnDef(..) => {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,6 +2176,7 @@ symbols! {
21762176
v1,
21772177
v8plus,
21782178
va_arg,
2179+
va_arg_safe,
21792180
va_copy,
21802181
va_end,
21812182
va_list,

library/core/src/ffi/va_list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ mod sealed {
306306
// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
307307
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
308308
// to accept unsupported types in the meantime.
309+
#[lang = "va_arg_safe"]
309310
pub unsafe trait VaArgSafe: sealed::Sealed {}
310311

311312
crate::cfg_select! {

0 commit comments

Comments
 (0)