| ... | @@ -254,11 +254,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -254,11 +254,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 254 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); | 254 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); |
| 255 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); | 255 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); |
| 256 | var scope = &c.global_scope.base; | 256 | var scope = &c.global_scope.base; |
| | 257 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); |
| | 258 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); |
| 257 | const decl_ctx = FnDeclContext{ | 259 | const decl_ctx = FnDeclContext{ |
| 258 | .fn_name = fn_name, | 260 | .fn_name = fn_name, |
| 259 | .has_body = ZigClangFunctionDecl_hasBody(fn_decl), | 261 | .has_body = has_body, |
| 260 | .storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl), | 262 | .storage_class = storage_class, |
| 261 | .scope = &scope, | 263 | .scope = &scope, |
| | 264 | .is_export = switch (storage_class) { |
| | 265 | .None => has_body, |
| | 266 | .Extern, .Static => false, |
| | 267 | .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern"), |
| | 268 | .Auto => unreachable, // Not legal on functions |
| | 269 | .Register => unreachable, // Not legal on functions |
| | 270 | }, |
| 262 | }; | 271 | }; |
| 263 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { | 272 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 264 | .FunctionProto => blk: { | 273 | .FunctionProto => blk: { |
| ... | @@ -270,7 +279,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -270,7 +279,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 270 | error.OutOfMemory => return error.OutOfMemory, | 279 | error.OutOfMemory => return error.OutOfMemory, |
| 271 | }; | 280 | }; |
| 272 | }, | 281 | }, |
| 273 | .FunctionNoProto => return failDecl(c, fn_decl_loc, fn_name, "TODO support functions with no prototype"), | 282 | .FunctionNoProto => blk: { |
| | 283 | const fn_no_proto_type = @ptrCast(*const ZigClangFunctionType, fn_type); |
| | 284 | break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) { |
| | 285 | error.UnsupportedType => { |
| | 286 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); |
| | 287 | }, |
| | 288 | error.OutOfMemory => return error.OutOfMemory, |
| | 289 | }; |
| | 290 | }, |
| 274 | else => unreachable, | 291 | else => unreachable, |
| 275 | }; | 292 | }; |
| 276 | | 293 | |
| ... | @@ -432,8 +449,22 @@ const FnDeclContext = struct { | ... | @@ -432,8 +449,22 @@ const FnDeclContext = struct { |
| 432 | has_body: bool, | 449 | has_body: bool, |
| 433 | storage_class: ZigClangStorageClass, | 450 | storage_class: ZigClangStorageClass, |
| 434 | scope: **Scope, | 451 | scope: **Scope, |
| | 452 | is_export: bool, |
| 435 | }; | 453 | }; |
| 436 | | 454 | |
| | 455 | fn transCC( |
| | 456 | rp: RestorePoint, |
| | 457 | fn_ty: *const ZigClangFunctionType, |
| | 458 | source_loc: ZigClangSourceLocation, |
| | 459 | ) !CallingConvention { |
| | 460 | const clang_cc = ZigClangFunctionType_getCallConv(fn_ty); |
| | 461 | switch (clang_cc) { |
| | 462 | .C => return CallingConvention.C, |
| | 463 | .X86StdCall => return CallingConvention.Stdcall, |
| | 464 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: {}", @tagName(clang_cc)), |
| | 465 | } |
| | 466 | } |
| | 467 | |
| 437 | fn transFnProto( | 468 | fn transFnProto( |
| 438 | rp: RestorePoint, | 469 | rp: RestorePoint, |
| 439 | fn_proto_ty: *const ZigClangFunctionProtoType, | 470 | fn_proto_ty: *const ZigClangFunctionProtoType, |
| ... | @@ -441,52 +472,44 @@ fn transFnProto( | ... | @@ -441,52 +472,44 @@ fn transFnProto( |
| 441 | fn_decl_context: ?FnDeclContext, | 472 | fn_decl_context: ?FnDeclContext, |
| 442 | ) !*ast.Node.FnProto { | 473 | ) !*ast.Node.FnProto { |
| 443 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); | 474 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); |
| 444 | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { | 475 | const cc = try transCC(rp, fn_ty, source_loc); |
| 445 | .C => CallingConvention.C, | | |
| 446 | .X86StdCall => CallingConvention.Stdcall, | | |
| 447 | .X86FastCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 fastcall"), | | |
| 448 | .X86ThisCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 thiscall"), | | |
| 449 | .X86VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 vectorcall"), | | |
| 450 | .X86Pascal => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 pascal"), | | |
| 451 | .Win64 => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: win64"), | | |
| 452 | .X86_64SysV => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 64sysv"), | | |
| 453 | .X86RegCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 reg"), | | |
| 454 | .AAPCS => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs"), | | |
| 455 | .AAPCS_VFP => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs-vfp"), | | |
| 456 | .IntelOclBicc => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: intel_ocl_bicc"), | | |
| 457 | .SpirFunction => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: SPIR function"), | | |
| 458 | .OpenCLKernel => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: OpenCLKernel"), | | |
| 459 | .Swift => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: Swift"), | | |
| 460 | .PreserveMost => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveMost"), | | |
| 461 | .PreserveAll => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveAll"), | | |
| 462 | .AArch64VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: AArch64VectorCall"), | | |
| 463 | }; | | |
| 464 | | | |
| 465 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); | 476 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 466 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); | 477 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); |
| 467 | var i: usize = 0; | 478 | var i: usize = 0; |
| 468 | while (i < param_count) : (i += 1) { | 479 | while (i < param_count) : (i += 1) { |
| 469 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); | 480 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); |
| 470 | } | 481 | } |
| | 482 | |
| | 483 | return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); |
| | 484 | } |
| | 485 | |
| | 486 | fn transFnNoProto( |
| | 487 | rp: RestorePoint, |
| | 488 | fn_ty: *const ZigClangFunctionType, |
| | 489 | source_loc: ZigClangSourceLocation, |
| | 490 | fn_decl_context: ?FnDeclContext, |
| | 491 | ) !*ast.Node.FnProto { |
| | 492 | const cc = try transCC(rp, fn_ty, source_loc); |
| | 493 | const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true; |
| | 494 | return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); |
| | 495 | } |
| | 496 | |
| | 497 | fn finishTransFnProto( |
| | 498 | rp: RestorePoint, |
| | 499 | fn_ty: *const ZigClangFunctionType, |
| | 500 | source_loc: ZigClangSourceLocation, |
| | 501 | fn_decl_context: ?FnDeclContext, |
| | 502 | is_var_args: bool, |
| | 503 | cc: CallingConvention, |
| | 504 | ) !*ast.Node.FnProto { |
| | 505 | const is_export = if (fn_decl_context) |ctx| ctx.is_export else false; |
| | 506 | |
| 471 | // TODO check for always_inline attribute | 507 | // TODO check for always_inline attribute |
| 472 | // TODO check for align attribute | 508 | // TODO check for align attribute |
| 473 | | 509 | |
| 474 | // pub extern fn name(...) T | 510 | // pub extern fn name(...) T |
| 475 | const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub"); | 511 | const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub"); |
| 476 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; | 512 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; |
| 477 | const is_export = exp: { | | |
| 478 | const decl_ctx = fn_decl_context orelse break :exp false; | | |
| 479 | break :exp switch (decl_ctx.storage_class) { | | |
| 480 | .None => switch (rp.c.mode) { | | |
| 481 | .import => false, | | |
| 482 | .translate => decl_ctx.has_body, | | |
| 483 | }, | | |
| 484 | .Extern, .Static => false, | | |
| 485 | .PrivateExtern => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported storage class: private extern"), | | |
| 486 | .Auto => unreachable, // Not legal on functions | | |
| 487 | .Register => unreachable, // Not legal on functions | | |
| 488 | }; | | |
| 489 | }; | | |
| 490 | const extern_export_inline_tok = if (is_export) | 513 | const extern_export_inline_tok = if (is_export) |
| 491 | try appendToken(rp.c, .Keyword_export, "export") | 514 | try appendToken(rp.c, .Keyword_export, "export") |
| 492 | else if (cc == .C) | 515 | else if (cc == .C) |
| ... | @@ -527,7 +550,7 @@ fn transFnProto( | ... | @@ -527,7 +550,7 @@ fn transFnProto( |
| 527 | .name_token = name_tok, | 550 | .name_token = name_tok, |
| 528 | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), | 551 | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), |
| 529 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, | 552 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 530 | .var_args_token = var_args_tok, | 553 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 531 | .extern_export_inline_token = extern_export_inline_tok, | 554 | .extern_export_inline_token = extern_export_inline_tok, |
| 532 | .cc_token = cc_tok, | 555 | .cc_token = cc_tok, |
| 533 | .async_attr = null, | 556 | .async_attr = null, |
| ... | @@ -536,6 +559,19 @@ fn transFnProto( | ... | @@ -536,6 +559,19 @@ fn transFnProto( |
| 536 | .align_expr = null, | 559 | .align_expr = null, |
| 537 | .section_expr = null, | 560 | .section_expr = null, |
| 538 | }; | 561 | }; |
| | 562 | if (is_var_args) { |
| | 563 | const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl); |
| | 564 | var_arg_node.* = ast.Node.ParamDecl{ |
| | 565 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| | 566 | .doc_comments = null, |
| | 567 | .comptime_token = null, |
| | 568 | .noalias_token = null, |
| | 569 | .name_token = null, |
| | 570 | .type_node = undefined, |
| | 571 | .var_args_token = var_args_tok, |
| | 572 | }; |
| | 573 | try fn_proto.params.push(&var_arg_node.base); |
| | 574 | } |
| 539 | return fn_proto; | 575 | return fn_proto; |
| 540 | } | 576 | } |
| 541 | | 577 | |