c variadic calls
This commit is contained in:
@@ -130,6 +130,7 @@ Function :: struct {
|
||||
c_abi: bool,
|
||||
imported: bool,
|
||||
has_body: bool,
|
||||
variadic: bool,
|
||||
params: []Param,
|
||||
result: Type_Syntax,
|
||||
body: []Stmt_Id,
|
||||
|
||||
@@ -454,7 +454,7 @@ add_unsupported_type_diagnostic :: proc(
|
||||
}
|
||||
|
||||
function_signatures_equal :: proc(left, right: ast.Function) -> bool {
|
||||
if left.result != right.result || len(left.params) != len(right.params) {
|
||||
if left.result != right.result || left.variadic != right.variadic || len(left.params) != len(right.params) {
|
||||
return false
|
||||
}
|
||||
for param, index in left.params {
|
||||
@@ -465,6 +465,17 @@ function_signatures_equal :: proc(left, right: ast.Function) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
valid_call_arity :: proc(function: ast.Function, count: int) -> bool {
|
||||
return count >= len(function.params) if function.variadic else count == len(function.params)
|
||||
}
|
||||
|
||||
call_arg_expected :: proc(function: ast.Function, index: int) -> types.Type {
|
||||
if index < 0 || index >= len(function.params) {
|
||||
return types.INVALID
|
||||
}
|
||||
return type_from_syntax(function.params[index].type)
|
||||
}
|
||||
|
||||
contains_name :: proc(names: []symbol.Id, name: symbol.Id) -> bool {
|
||||
for existing in names {
|
||||
if existing == name {
|
||||
@@ -566,6 +577,14 @@ validate_declarations :: proc(checker: ^Checker) {
|
||||
symbol_text(checker, function.name),
|
||||
)
|
||||
}
|
||||
if function.variadic && (!function.c_abi || function.has_body) {
|
||||
checker.template_diagnostics[function_id] = source.addf(
|
||||
checker.diagnostics,
|
||||
function.span,
|
||||
"variadic function '%s' must be a bodyless 'c_func' declaration",
|
||||
symbol_text(checker, function.name),
|
||||
)
|
||||
}
|
||||
if !function.has_body && function.c_abi {
|
||||
for param in function.params {
|
||||
if add_unsupported_type_diagnostic(checker, param.span, type_from_syntax(param.type)) !=
|
||||
@@ -1029,11 +1048,12 @@ infer_expr :: proc(
|
||||
}
|
||||
}
|
||||
function := checker.ast_module.functions[frame.template]
|
||||
if can_specialize(checker, function, stack[frame_index].args) {
|
||||
if valid_call_arity(function, len(expr.args)) &&
|
||||
can_specialize(checker, function, stack[frame_index].args) {
|
||||
spec := INVALID_SPEC
|
||||
if demanded == nil {
|
||||
spec = ensure_spec(checker, frame.template, stack[frame_index].args)
|
||||
} else if len(expr.args) == len(function.params) {
|
||||
} else {
|
||||
spec = find_spec(checker, frame.template, stack[frame_index].args)
|
||||
mark_spec_demanded(checker, spec, demanded)
|
||||
}
|
||||
@@ -1317,6 +1337,32 @@ coerce_expr :: proc(
|
||||
return invalid_hir_expr(checker, span, id, expected)
|
||||
}
|
||||
|
||||
promote_c_vararg_expr :: proc(checker: ^Checker, expr_id: hir.Expr_Id, span: source.Span) -> hir.Expr_Id {
|
||||
actual := checker.module.exprs[expr_id].type
|
||||
if !types.is_c_vararg_type(actual, &checker.module.types) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
span,
|
||||
"C variadic argument must be a concrete scalar or pointer, got %s",
|
||||
types.name(actual),
|
||||
)
|
||||
return invalid_hir_expr(checker, span, id, types.C_INT)
|
||||
}
|
||||
promoted := types.c_vararg_promotion(actual, checker.target)
|
||||
if types.equal(actual, promoted) {
|
||||
return expr_id
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.C_Vararg_Promote,
|
||||
span=span,
|
||||
type=promoted,
|
||||
left=expr_id,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
|
||||
build_constant_expr :: proc(
|
||||
checker: ^Checker,
|
||||
expr: ast.Expr,
|
||||
@@ -1891,13 +1937,16 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if len(expr.args) != len(checker.ast_module.functions[template].params) {
|
||||
function := checker.ast_module.functions[template]
|
||||
if !valid_call_arity(function, len(expr.args)) {
|
||||
message := "function '%s' expects at least %d arguments, got %d" if function.variadic else
|
||||
"function '%s' expects %d arguments, got %d"
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"function '%s' expects %d arguments, got %d",
|
||||
message,
|
||||
symbol_text(checker, expr.name),
|
||||
len(checker.ast_module.functions[template].params),
|
||||
len(function.params),
|
||||
len(expr.args),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
@@ -1909,7 +1958,7 @@ build_expr :: proc(
|
||||
stack[frame_index].arg_types = make([]types.Type, len(expr.args), checker.allocator)
|
||||
stack[frame_index].stage = 3
|
||||
if len(expr.args) > 0 {
|
||||
arg_expected := type_from_syntax(checker.ast_module.functions[template].params[0].type)
|
||||
arg_expected := call_arg_expected(function, 0)
|
||||
if !is_runtime_type(checker, arg_expected) {
|
||||
arg_expected = types.INVALID
|
||||
}
|
||||
@@ -1980,7 +2029,7 @@ build_expr :: proc(
|
||||
stack[frame_index].arg_index += 1
|
||||
if frame.arg_index+1 < len(expr.args) {
|
||||
next := frame.arg_index+1
|
||||
arg_expected := type_from_syntax(checker.ast_module.functions[frame.template].params[next].type)
|
||||
arg_expected := call_arg_expected(checker.ast_module.functions[frame.template], next)
|
||||
if !is_runtime_type(checker, arg_expected) {
|
||||
arg_expected = types.INVALID
|
||||
}
|
||||
@@ -2004,7 +2053,8 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
for _, index in stack[frame_index].built_args {
|
||||
fixed_count := len(checker.ast_module.functions[frame.template].params)
|
||||
for index in 0..<fixed_count {
|
||||
stack[frame_index].built_args[index] = coerce_expr(
|
||||
checker,
|
||||
stack[frame_index].built_args[index],
|
||||
@@ -2012,6 +2062,14 @@ build_expr :: proc(
|
||||
checker.module.exprs[stack[frame_index].built_args[index]].span,
|
||||
)
|
||||
}
|
||||
for index in fixed_count..<len(stack[frame_index].built_args) {
|
||||
arg := stack[frame_index].built_args[index]
|
||||
stack[frame_index].built_args[index] = promote_c_vararg_expr(
|
||||
checker,
|
||||
arg,
|
||||
checker.module.exprs[arg].span,
|
||||
)
|
||||
}
|
||||
function_id := checker.specs[spec].hir_id
|
||||
assert(function_id != hir.INVALID_FUNCTION)
|
||||
add_unique_function(calls, function_id)
|
||||
@@ -2128,6 +2186,7 @@ build_function :: proc(checker: ^Checker, id: Spec_Id) {
|
||||
implementation = .Declaration,
|
||||
linkage = .External if function.c_abi else .Internal,
|
||||
is_main = function.pkg == 0 && function.name == checker.main_symbol,
|
||||
variadic = function.variadic,
|
||||
params = params[:],
|
||||
result = spec.result,
|
||||
locals = hir_locals[:],
|
||||
@@ -2524,6 +2583,7 @@ build_function :: proc(checker: ^Checker, id: Spec_Id) {
|
||||
implementation = .Definition,
|
||||
linkage = .External if function.c_abi || (function.pkg == 0 && function.name == checker.main_symbol) else .Internal,
|
||||
is_main = function.pkg == 0 && function.name == checker.main_symbol,
|
||||
variadic = function.variadic,
|
||||
params = params[:],
|
||||
result = spec.result,
|
||||
locals = hir_locals[:],
|
||||
|
||||
@@ -46,10 +46,11 @@ Alias :: struct {
|
||||
}
|
||||
|
||||
Function :: struct {
|
||||
name: string,
|
||||
params: []Type_Id,
|
||||
result: Type_Id,
|
||||
reason: string,
|
||||
name: string,
|
||||
params: []Type_Id,
|
||||
result: Type_Id,
|
||||
variadic: bool,
|
||||
reason: string,
|
||||
}
|
||||
|
||||
Unsupported :: struct {
|
||||
|
||||
@@ -338,9 +338,8 @@ visit_cursor :: proc "c"(cursor, parent: CXCursor, client_data: rawptr) -> i32 {
|
||||
linkage := ctx.api.get_cursor_linkage(cursor)
|
||||
if linkage != CXLinkage_External {
|
||||
reason = "static and non-external C functions are not supported"
|
||||
} else if ctx.api.cursor_is_variadic(cursor) != 0 {
|
||||
reason = "C variadic functions are not supported"
|
||||
}
|
||||
variadic := ctx.api.cursor_is_variadic(cursor) != 0
|
||||
function_type := ctx.api.get_cursor_type(cursor)
|
||||
result_type := translate_type(ctx, ctx.api.get_result_type(function_type))
|
||||
if result_type == INVALID_TYPE && len(reason) == 0 {
|
||||
@@ -364,6 +363,7 @@ visit_cursor :: proc "c"(cursor, parent: CXCursor, client_data: rawptr) -> i32 {
|
||||
name=fmt.aprintf("%s", name, allocator=ctx.allocator),
|
||||
params=params[:],
|
||||
result=result_type,
|
||||
variadic=variadic,
|
||||
reason=fmt.aprintf("%s", reason, allocator=ctx.allocator),
|
||||
})
|
||||
case CXCursor_TypedefDecl:
|
||||
|
||||
@@ -93,6 +93,7 @@ Expr_Kind :: enum u8 {
|
||||
Unwrap,
|
||||
Orelse,
|
||||
Widen,
|
||||
C_Vararg_Promote,
|
||||
Weaken_Pointer,
|
||||
Negate,
|
||||
Add,
|
||||
@@ -144,6 +145,7 @@ Function :: struct {
|
||||
implementation: Implementation,
|
||||
linkage: Linkage,
|
||||
is_main: bool,
|
||||
variadic: bool,
|
||||
params: []Local_Id,
|
||||
result: types.Type,
|
||||
locals: []Local,
|
||||
|
||||
@@ -87,6 +87,7 @@ Opcode :: enum u8 {
|
||||
Orelse_Begin,
|
||||
Orelse,
|
||||
Widen,
|
||||
C_Vararg_Promote,
|
||||
Weaken_Pointer,
|
||||
Neg_Checked,
|
||||
Add_Checked,
|
||||
@@ -115,6 +116,7 @@ Function :: struct {
|
||||
implementation: Implementation,
|
||||
linkage: Linkage,
|
||||
is_main: bool,
|
||||
variadic: bool,
|
||||
param_types: []types.Type,
|
||||
result: types.Type,
|
||||
instructions: []Instruction,
|
||||
|
||||
@@ -119,7 +119,12 @@ lex :: proc(
|
||||
cursor += 1
|
||||
if cursor < len(bytes) && bytes[cursor] == '.' {
|
||||
cursor += 1
|
||||
append_token(&stream, source_file, .Range, start, cursor)
|
||||
if cursor < len(bytes) && bytes[cursor] == '.' {
|
||||
cursor += 1
|
||||
append_token(&stream, source_file, .Ellipsis, start, cursor)
|
||||
} else {
|
||||
append_token(&stream, source_file, .Range, start, cursor)
|
||||
}
|
||||
} else {
|
||||
append_token(&stream, source_file, .Dot, start, cursor)
|
||||
}
|
||||
|
||||
+63
-7
@@ -112,7 +112,7 @@ valid_value :: proc(
|
||||
switch instructions[value_id].op {
|
||||
case .Param, .Const, .String, .Aggregate, .None, .Optional_Some,
|
||||
.Load_Global, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr, .Unwrap, .Orelse,
|
||||
.Widen, .Weaken_Pointer, .Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
|
||||
.Widen, .C_Vararg_Promote, .Weaken_Pointer, .Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
|
||||
return true
|
||||
case .Address_Global, .Alloca, .Index_Address, .Field_Address, .Orelse_Begin,
|
||||
.Store, .Trap, .Return, .Return_Void:
|
||||
@@ -275,14 +275,16 @@ emit_call_args :: proc(
|
||||
if index > 0 {
|
||||
strings.write_string(builder, ", ")
|
||||
}
|
||||
fmt.sbprintf(builder, "%s ", llvm_type(param_types[index], store))
|
||||
if c_abi {
|
||||
extension := c_abi_extension(param_types[index], store.selected)
|
||||
arg_type := param_types[index] if index < len(param_types) && valid_instruction(instructions, arg) else
|
||||
(instructions[arg].type if valid_instruction(instructions, arg) else types.INVALID)
|
||||
fmt.sbprintf(builder, "%s ", llvm_type(arg_type, store))
|
||||
if c_abi && index < len(param_types) {
|
||||
extension := c_abi_extension(arg_type, store.selected)
|
||||
if len(extension) > 0 {
|
||||
fmt.sbprintf(builder, "%s ", extension)
|
||||
}
|
||||
}
|
||||
write_operand(builder, instructions, arg, param_types[index], store)
|
||||
write_operand(builder, instructions, arg, arg_type, store)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,6 +709,31 @@ emit_instruction_stream :: proc(
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
|
||||
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
|
||||
case .C_Vararg_Promote:
|
||||
if !valid_instruction(instructions, instruction.a) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid C variadic promotion operand")
|
||||
continue
|
||||
}
|
||||
from_type := instructions[instruction.a].type
|
||||
if types.equal(from_type, instruction.type) ||
|
||||
!types.equal(types.c_vararg_promotion(from_type, emitter.module.target), instruction.type) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid C variadic promotion operand")
|
||||
continue
|
||||
}
|
||||
if types.bits(from_type, emitter.module.target) == types.bits(instruction.type, emitter.module.target) {
|
||||
type_name := llvm_type(instruction.type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, %s ", instruction_index, type_name)
|
||||
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", %s ", type_name)
|
||||
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
|
||||
strings.write_string(&emitter.builder, "\n")
|
||||
continue
|
||||
}
|
||||
operation := "fpext" if types.is_float(from_type, emitter.module.target) else
|
||||
("sext" if types.is_signed(from_type, emitter.module.target) else "zext")
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
|
||||
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
|
||||
case .Weaken_Pointer:
|
||||
if !valid_instruction(instructions, instruction.a) ||
|
||||
!types.can_weaken_pointer(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
|
||||
@@ -806,10 +833,20 @@ emit_instruction_stream :: proc(
|
||||
continue
|
||||
}
|
||||
target := emitter.module.functions[function_id]
|
||||
valid_args := len(instruction.args) == len(target.param_types)
|
||||
valid_args := (len(instruction.args) >= len(target.param_types) if target.variadic else
|
||||
len(instruction.args) == len(target.param_types)) &&
|
||||
(!target.variadic || target.calling_convention == .C)
|
||||
if valid_args {
|
||||
for arg, index in instruction.args {
|
||||
if !valid_value(instructions, arg, target.param_types[index], &emitter.module.types) {
|
||||
expected := target.param_types[index] if index < len(target.param_types) && valid_instruction(instructions, arg) else
|
||||
(instructions[arg].type if valid_instruction(instructions, arg) else types.INVALID)
|
||||
if index >= len(target.param_types) &&
|
||||
(!types.is_c_vararg_type(expected, &emitter.module.types) ||
|
||||
!types.equal(types.c_vararg_promotion(expected, emitter.module.target), expected)) {
|
||||
valid_args = false
|
||||
break
|
||||
}
|
||||
if !valid_value(instructions, arg, expected, &emitter.module.types) {
|
||||
valid_args = false
|
||||
break
|
||||
}
|
||||
@@ -833,6 +870,19 @@ emit_instruction_stream :: proc(
|
||||
strings.write_string(&emitter.builder, "fastcc ")
|
||||
}
|
||||
emit_function_result(&emitter.builder, target, &emitter.module.types)
|
||||
if target.variadic {
|
||||
strings.write_string(&emitter.builder, " (")
|
||||
for param_type, index in target.param_types {
|
||||
if index > 0 {
|
||||
strings.write_string(&emitter.builder, ", ")
|
||||
}
|
||||
strings.write_string(&emitter.builder, llvm_type(param_type, &emitter.module.types))
|
||||
}
|
||||
if len(target.param_types) > 0 {
|
||||
strings.write_string(&emitter.builder, ", ")
|
||||
}
|
||||
strings.write_string(&emitter.builder, "...)")
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " @%s(", target.link_name)
|
||||
emit_call_args(
|
||||
&emitter.builder, instructions, instruction.args, target.param_types,
|
||||
@@ -1037,6 +1087,12 @@ emit_functions :: proc(emitter: ^Emitter) {
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d", index)
|
||||
}
|
||||
}
|
||||
if function.variadic {
|
||||
if len(function.param_types) > 0 {
|
||||
strings.write_string(&emitter.builder, ", ")
|
||||
}
|
||||
strings.write_string(&emitter.builder, "...")
|
||||
}
|
||||
if function.implementation == .Declaration {
|
||||
strings.write_string(&emitter.builder, ")\n\n")
|
||||
continue
|
||||
|
||||
@@ -177,8 +177,8 @@ translate_c_type :: proc(
|
||||
return translated
|
||||
}
|
||||
|
||||
function_signatures_equal :: proc(left: ast.Function, params: []ast.Param, result: types.Type) -> bool {
|
||||
if left.result != result || len(left.params) != len(params) {
|
||||
function_signatures_equal :: proc(left: ast.Function, params: []ast.Param, result: types.Type, variadic: bool) -> bool {
|
||||
if left.result != result || left.variadic != variadic || len(left.params) != len(params) {
|
||||
return false
|
||||
}
|
||||
for param, index in params {
|
||||
@@ -282,7 +282,7 @@ load_header :: proc(state: ^State, path: string, import_span: source.Span) -> as
|
||||
continue
|
||||
}
|
||||
duplicate = true
|
||||
if !function_signatures_equal(existing, params, function_result) && len(existing.unsupported_reason) == 0 {
|
||||
if !function_signatures_equal(existing, params, function_result, function.variadic) && len(existing.unsupported_reason) == 0 {
|
||||
existing.unsupported_reason = fmt.aprintf(
|
||||
"conflicting C declarations for '%s'",
|
||||
function.name,
|
||||
@@ -303,6 +303,7 @@ load_header :: proc(state: ^State, path: string, import_span: source.Span) -> as
|
||||
c_abi=true,
|
||||
imported=true,
|
||||
has_body=false,
|
||||
variadic=function.variadic,
|
||||
params=params,
|
||||
result=function_result,
|
||||
unsupported_reason=strings.clone(unsupported_reason, state.allocator),
|
||||
|
||||
@@ -324,7 +324,7 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
})
|
||||
}
|
||||
_ = pop(&stack)
|
||||
case .Widen, .Weaken_Pointer:
|
||||
case .Widen, .C_Vararg_Promote, .Weaken_Pointer:
|
||||
stack[frame_index].stage = 1
|
||||
append(&stack, Lower_Expr_Frame{expr=expr.left})
|
||||
case .Negate:
|
||||
@@ -358,7 +358,8 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
}
|
||||
if frame.stage == 1 {
|
||||
last = append_instruction(state, ir.Instruction{
|
||||
op=.Weaken_Pointer if expr.kind == .Weaken_Pointer else .Widen,
|
||||
op=.Weaken_Pointer if expr.kind == .Weaken_Pointer else
|
||||
(.C_Vararg_Promote if expr.kind == .C_Vararg_Promote else .Widen),
|
||||
span=expr.span, type=expr.type, target=ir.INVALID_REF,
|
||||
a=last, b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
@@ -611,6 +612,7 @@ lower :: proc(hir_module: ^hir.Module, allocator := context.allocator) -> ir.Mod
|
||||
implementation=.Declaration if function.implementation == .Declaration else .Definition,
|
||||
linkage=.External if function.linkage == .External else .Internal,
|
||||
is_main=function.is_main,
|
||||
variadic=function.variadic,
|
||||
param_types=param_types,
|
||||
result=function.result,
|
||||
instructions=nil if function.implementation == .Declaration else lower_body(hir_module, function, allocator),
|
||||
|
||||
@@ -889,11 +889,27 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
return id
|
||||
}
|
||||
|
||||
parse_params :: proc(parser: ^Parser) -> []ast.Param {
|
||||
parse_params :: proc(parser: ^Parser) -> ([]ast.Param, bool) {
|
||||
params: [dynamic]ast.Param
|
||||
params.allocator = parser.module.allocator
|
||||
variadic := false
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Paren && current(parser).kind != .Eof {
|
||||
if current(parser).kind == .Ellipsis {
|
||||
marker := advance(parser)
|
||||
if variadic {
|
||||
source.add(parser.diagnostics, marker.span, "duplicate variadic marker")
|
||||
}
|
||||
variadic = true
|
||||
skip_newlines(parser)
|
||||
if _, ok := allow(parser, .Comma); ok {
|
||||
skip_newlines(parser)
|
||||
}
|
||||
if current(parser).kind != .Right_Paren {
|
||||
source.add(parser.diagnostics, current(parser).span, "variadic marker must be the final parameter")
|
||||
}
|
||||
continue
|
||||
}
|
||||
names: [dynamic]token.Token
|
||||
names.allocator = parser.module.allocator
|
||||
for {
|
||||
@@ -923,7 +939,7 @@ parse_params :: proc(parser: ^Parser) -> []ast.Param {
|
||||
}
|
||||
break
|
||||
}
|
||||
return params[:]
|
||||
return params[:], variadic
|
||||
}
|
||||
|
||||
parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
|
||||
@@ -931,7 +947,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
|
||||
if _, ok := allow(parser, .Left_Paren); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected '(' after 'func'")
|
||||
}
|
||||
params := parse_params(parser)
|
||||
params, variadic := parse_params(parser)
|
||||
if _, ok := allow(parser, .Right_Paren); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ')' after parameters")
|
||||
}
|
||||
@@ -954,6 +970,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
|
||||
file=parser.file,
|
||||
c_abi=c_abi,
|
||||
has_body=false,
|
||||
variadic=variadic,
|
||||
params=params,
|
||||
result=result,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
@@ -991,6 +1008,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
|
||||
file=parser.file,
|
||||
c_abi=c_abi,
|
||||
has_body=true,
|
||||
variadic=variadic,
|
||||
params=params,
|
||||
result=result,
|
||||
body=body[:],
|
||||
|
||||
@@ -19,6 +19,7 @@ Kind :: enum u8 {
|
||||
Minus,
|
||||
Dot,
|
||||
Range,
|
||||
Ellipsis,
|
||||
At,
|
||||
Star,
|
||||
Ampersand,
|
||||
|
||||
@@ -432,6 +432,34 @@ is_c_signature_type :: proc(value: Type, store: ^Store, allow_void := false) ->
|
||||
return is_concrete_scalar(value) || is_pointer(value, store) || is_optional_pointer(value, store)
|
||||
}
|
||||
|
||||
is_c_integer_promotion_candidate :: proc(value: Type) -> bool {
|
||||
return value >= C_CHAR && value <= C_USHORT
|
||||
}
|
||||
|
||||
c_vararg_promotion :: proc(value: Type, selected := target.DEFAULT) -> Type {
|
||||
if !is_concrete_scalar(value) {
|
||||
return value
|
||||
}
|
||||
if is_float(value, selected) && bits(value, selected) < bits(C_DOUBLE, selected) {
|
||||
return C_DOUBLE
|
||||
}
|
||||
if is_concrete_integer(value) {
|
||||
value_bits := bits(value, selected)
|
||||
int_bits := bits(C_INT, selected)
|
||||
if value_bits < int_bits {
|
||||
return C_INT
|
||||
}
|
||||
if is_c_integer_promotion_candidate(value) && value_bits == int_bits {
|
||||
return C_INT if is_signed(value, selected) else C_UINT
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
is_c_vararg_type :: proc(value: Type, store: ^Store) -> bool {
|
||||
return is_concrete_scalar(value) || is_pointer(value, store) || is_optional_pointer(value, store)
|
||||
}
|
||||
|
||||
child_type :: proc(value: Type, store: ^Store) -> Type {
|
||||
item, ok := node(store, value)
|
||||
return item.child if ok else INVALID
|
||||
|
||||
Reference in New Issue
Block a user