| ... | ... | @@ -254,11 +254,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 254 | 254 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); |
| 255 | 255 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); |
| 256 | 256 | var scope = &c.global_scope.base; |
| 257 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); |
| 258 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); |
| 257 | 259 | const decl_ctx = FnDeclContext{ |
| 258 | 260 | .fn_name = fn_name, |
| 259 | | .has_body = ZigClangFunctionDecl_hasBody(fn_decl), |
| 260 | | .storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl), |
| 261 | .has_body = has_body, |
| 262 | .storage_class = storage_class, |
| 261 | 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 | 272 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 264 | 273 | .FunctionProto => blk: { |
| ... | ... | @@ -270,7 +279,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 270 | 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 | 291 | else => unreachable, |
| 275 | 292 | }; |
| 276 | 293 | |
| ... | ... | @@ -432,8 +449,22 @@ const FnDeclContext = struct { |
| 432 | 449 | has_body: bool, |
| 433 | 450 | storage_class: ZigClangStorageClass, |
| 434 | 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 | 468 | fn transFnProto( |
| 438 | 469 | rp: RestorePoint, |
| 439 | 470 | fn_proto_ty: *const ZigClangFunctionProtoType, |
| ... | ... | @@ -441,52 +472,44 @@ fn transFnProto( |
| 441 | 472 | fn_decl_context: ?FnDeclContext, |
| 442 | 473 | ) !*ast.Node.FnProto { |
| 443 | 474 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); |
| 444 | | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { |
| 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 | | |
| 475 | const cc = try transCC(rp, fn_ty, source_loc); |
| 465 | 476 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 466 | 477 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); |
| 467 | 478 | var i: usize = 0; |
| 468 | 479 | while (i < param_count) : (i += 1) { |
| 469 | 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 | 507 | // TODO check for always_inline attribute |
| 472 | 508 | // TODO check for align attribute |
| 473 | 509 | |
| 474 | 510 | // pub extern fn name(...) T |
| 475 | 511 | const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub"); |
| 476 | 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 | 513 | const extern_export_inline_tok = if (is_export) |
| 491 | 514 | try appendToken(rp.c, .Keyword_export, "export") |
| 492 | 515 | else if (cc == .C) |
| ... | ... | @@ -527,7 +550,7 @@ fn transFnProto( |
| 527 | 550 | .name_token = name_tok, |
| 528 | 551 | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), |
| 529 | 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 | 554 | .extern_export_inline_token = extern_export_inline_tok, |
| 532 | 555 | .cc_token = cc_tok, |
| 533 | 556 | .async_attr = null, |
| ... | ... | @@ -536,6 +559,19 @@ fn transFnProto( |
| 536 | 559 | .align_expr = null, |
| 537 | 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 | 575 | return fn_proto; |
| 540 | 576 | } |
| 541 | 577 | |