Browse Source

Promote types in `#c_varargs` according to C rules

Laytan Laats 1 year ago
parent
commit
f6f3a760bc
2 changed files with 48 additions and 2 deletions
  1. 2 2
      src/llvm_backend_proc.cpp
  2. 46 0
      src/types.cpp

+ 2 - 2
src/llvm_backend_proc.cpp

@@ -3361,9 +3361,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
 					for (Ast *var_arg : variadic) {
 						lbValue arg = lb_build_expr(p, var_arg);
 						if (is_type_any(elem_type)) {
-							array_add(&args, lb_emit_conv(p, arg, default_type(arg.type)));
+							array_add(&args, lb_emit_conv(p, arg, c_vararg_promote_type(default_type(arg.type))));
 						} else {
-							array_add(&args, lb_emit_conv(p, arg, elem_type));
+							array_add(&args, lb_emit_conv(p, arg, c_vararg_promote_type(elem_type)));
 						}
 					}
 					break;

+ 46 - 0
src/types.cpp

@@ -548,6 +548,14 @@ gb_global Type *t_f16             = &basic_types[Basic_f16];
 gb_global Type *t_f32             = &basic_types[Basic_f32];
 gb_global Type *t_f64             = &basic_types[Basic_f64];
 
+gb_global Type *t_f16be           = &basic_types[Basic_f16be];
+gb_global Type *t_f32be           = &basic_types[Basic_f32be];
+gb_global Type *t_f64be           = &basic_types[Basic_f64be];
+
+gb_global Type *t_f16le           = &basic_types[Basic_f16le];
+gb_global Type *t_f32le           = &basic_types[Basic_f32le];
+gb_global Type *t_f64le           = &basic_types[Basic_f64le];
+
 gb_global Type *t_complex32       = &basic_types[Basic_complex32];
 gb_global Type *t_complex64       = &basic_types[Basic_complex64];
 gb_global Type *t_complex128      = &basic_types[Basic_complex128];
@@ -2795,6 +2803,44 @@ gb_internal Type *default_type(Type *type) {
 	return type;
 }
 
+// See https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions
+gb_internal Type *c_vararg_promote_type(Type *type) {
+	GB_ASSERT(type != nullptr);
+
+	Type *core = core_type(type);
+	if (core->kind == Type_Basic) {
+		switch (core->Basic.kind) {
+		case Basic_f32:
+		case Basic_UntypedFloat:
+			return t_f64;
+		case Basic_f32le:
+			return t_f64le;
+		case Basic_f32be:
+			return t_f64be;
+
+		case Basic_UntypedBool:
+		case Basic_bool:
+		case Basic_b8:
+		case Basic_b16:
+		case Basic_i8:
+		case Basic_i16:
+		case Basic_u8:
+		case Basic_u16:
+			return t_i32;
+
+		case Basic_i16le:
+		case Basic_u16le:
+			return t_i32le;
+
+		case Basic_i16be:
+		case Basic_u16be:
+			return t_i32be;
+		}
+	}
+
+	return type;
+}
+
 gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
 	if (are_types_identical(v, vt)) {
 		return true;