mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Make Windows use wWinMain always. Support /SUBSYSTEM:WINDOWS
This commit is contained in:
committed by
Christoffer Lerno
parent
f89bf9ea2f
commit
5ea15eb708
156
lib/std/core/private/main_stub.c3
Normal file
156
lib/std/core/private/main_stub.c3
Normal file
@@ -0,0 +1,156 @@
|
||||
module std::core::main_stub;
|
||||
|
||||
private macro usz _strlen(ptr)
|
||||
{
|
||||
usz len = 0;
|
||||
while (ptr[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
macro int @main_to_err_main(#m, int, char**) => catch(#m()) ? 1 : 0;
|
||||
macro int @main_to_int_main(#m, int, char**) => #m();
|
||||
macro int @main_to_void_main(#m, int, char**)
|
||||
{
|
||||
#m();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private macro String[] args_to_strings(int argc, char** argv)
|
||||
{
|
||||
String *list = malloc(String.sizeof * argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
char* arg = argv[i];
|
||||
usz len = 0;
|
||||
list[i] = arg[:_strlen(arg)];
|
||||
}
|
||||
return list[:argc];
|
||||
}
|
||||
|
||||
|
||||
macro int @main_to_err_main_args(#m, int argc, char** argv)
|
||||
{
|
||||
String[] list = args_to_strings(argc, argv);
|
||||
defer free(list.ptr);
|
||||
return catch(#m(list)) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @main_to_int_main_args(#m, int argc, char** argv)
|
||||
{
|
||||
String[] list = args_to_strings(argc, argv);
|
||||
defer free(list.ptr);
|
||||
return #m(list);
|
||||
}
|
||||
|
||||
macro int @main_to_void_main_args(#m, int argc, char** argv)
|
||||
{
|
||||
String[] list = args_to_strings(argc, argv);
|
||||
defer free(list.ptr);
|
||||
#m(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
|
||||
extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @extname("CommandLineToArgvW");
|
||||
|
||||
private macro String[] win_command_line_to_strings(ushort* cmd_line)
|
||||
{
|
||||
int argc;
|
||||
Char16** argv = _win_command_line_to_argv_w(cmd_line, &argc);
|
||||
return wargs_strings(argc, argv);
|
||||
}
|
||||
|
||||
private macro String[] wargs_strings(int argc, Char16** argv)
|
||||
{
|
||||
String *list = malloc(String.sizeof * argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
Char16* arg = argv[i];
|
||||
Char16[] argstring = arg[:_strlen(arg)];
|
||||
list[i] = str::utf16to8(argstring) ?? str::copy("?");
|
||||
}
|
||||
return list[:argc];
|
||||
}
|
||||
|
||||
private macro void release_wargs(String[] list)
|
||||
{
|
||||
foreach (s : list) free(s.ptr);
|
||||
free(list.ptr);
|
||||
}
|
||||
|
||||
macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => catch(#m()) ? 1 : 0;
|
||||
macro int @win_to_int_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => #m();
|
||||
macro int @win_to_void_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
#m();
|
||||
return 0;
|
||||
}
|
||||
|
||||
macro int @win_to_err_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return catch(#m(args)) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @win_to_int_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return #m(args);
|
||||
}
|
||||
|
||||
macro int @win_to_void_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
#m(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
macro int @win_to_err_main(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return catch(#m(handle, args, show_cmd)) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @win_to_int_main(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return #m(handle, args, show_cmd);
|
||||
}
|
||||
|
||||
macro int @win_to_void_main(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
#m(handle, args, show_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
macro int @wmain_to_err_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
return catch(#m(args)) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @wmain_to_int_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
return #m(args);
|
||||
}
|
||||
|
||||
macro int @wmain_to_void_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
#m(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$endif;
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::runtime;
|
||||
module std::core::runtime;
|
||||
|
||||
struct VirtualAny
|
||||
{
|
||||
@@ -87,7 +87,7 @@ fn void random_fasta(String symb, double[] probability, int n)
|
||||
if (i % LINELEN != 0) io::putchar('\n');
|
||||
}
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
fn int main(int argc, char **argv)
|
||||
{
|
||||
int n = 1000;
|
||||
if (argc > 1) n = libc::atoi(argv[1]);
|
||||
@@ -101,4 +101,5 @@ fn void main(int argc, char **argv)
|
||||
io::printf(">THREE Homo sapiens frequency\n");
|
||||
random_fasta(homosapiens, homosapiens_p, n * 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ extern fn int atoi(char *s);
|
||||
extern fn int printf(char *s, ...);
|
||||
extern fn void putchar(int c);
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
fn int main(int argc, char **argv)
|
||||
{
|
||||
int w = atoi(argv[1]);
|
||||
int h = w;
|
||||
@@ -55,4 +55,5 @@ fn void main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ static void usage(void)
|
||||
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
|
||||
OUTPUT(" --forcelinker - Force built in linker usage when doing non-cross linking.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --gui - Build a 'gui' variant of the executable (e.g. '/SUBSYSTEM:WINDOWS' on Win32).");
|
||||
OUTPUT(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE.");
|
||||
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, native, mmx, sse, avx, avx512.");
|
||||
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
|
||||
@@ -532,6 +533,11 @@ static void parse_option(BuildOptions *options)
|
||||
options->symtab_size = next_highest_power_of_2(symtab);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("gui"))
|
||||
{
|
||||
options->gui = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("forcelinker"))
|
||||
{
|
||||
options->force_linker = true;
|
||||
|
||||
@@ -290,6 +290,7 @@ typedef struct BuildOptions_
|
||||
bool no_stdlib;
|
||||
bool no_entry;
|
||||
bool no_libc;
|
||||
bool gui;
|
||||
bool force_linker;
|
||||
bool read_stdin;
|
||||
bool print_output;
|
||||
@@ -374,6 +375,7 @@ typedef struct
|
||||
bool emit_asm;
|
||||
bool no_stdlib;
|
||||
bool no_libc;
|
||||
bool gui;
|
||||
bool emit_object_files;
|
||||
bool force_linker;
|
||||
bool benchmarking;
|
||||
|
||||
@@ -233,6 +233,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
target->panicfn = options->panicfn;
|
||||
target->benchmarking = options->benchmarking;
|
||||
target->testing = options->testing;
|
||||
if (options->gui) target->gui = true;
|
||||
if (options->macos.sdk) target->macos.sdk = options->macos.sdk;
|
||||
if (options->win.sdk) target->win.sdk = options->win.sdk;
|
||||
if (options->macos.min_version) target->macos.min_version = options->macos.min_version;
|
||||
|
||||
@@ -362,6 +362,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
// nolibc
|
||||
target->no_libc = get_valid_bool(json, "nolibc", type, target->no_libc);
|
||||
|
||||
// gui
|
||||
target->gui = get_valid_bool(json, "gui", type, target->gui);
|
||||
|
||||
// no-entry
|
||||
target->no_entry = get_valid_bool(json, "no-entry", type, target->no_entry);
|
||||
|
||||
|
||||
@@ -1902,6 +1902,8 @@ extern const char *kw_pure;
|
||||
extern const char *kw_return;
|
||||
extern const char *kw_std;
|
||||
extern const char *kw_type;
|
||||
extern const char *kw_winmain;
|
||||
extern const char *kw_wmain;
|
||||
extern ArchOsTarget default_target;
|
||||
|
||||
ARENA_DEF(chars, char)
|
||||
|
||||
@@ -992,3 +992,13 @@ typedef enum
|
||||
COND_TYPE_UNWRAP,
|
||||
COND_TYPE_EVALTYPE_VALUE,
|
||||
} CondType;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MAIN_TYPE_ERROR,
|
||||
MAIN_TYPE_RAW,
|
||||
MAIN_TYPE_NO_ARGS,
|
||||
MAIN_TYPE_ARGS,
|
||||
MAIN_TYPE_WIN,
|
||||
} MainType;
|
||||
@@ -77,6 +77,7 @@ static const char *string_esc(const char *str)
|
||||
}
|
||||
static void linker_setup_windows(const char ***args_ref, LinkerType linker_type)
|
||||
{
|
||||
add_arg(active_target.gui ? "/SUBSYSTEM:WINDOWS" : "/SUBSYSTEM:CONSOLE");
|
||||
if (linker_type == LINKER_CC) return;
|
||||
//add_arg("/MACHINE:X64");
|
||||
bool is_debug = false;
|
||||
@@ -145,6 +146,7 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type)
|
||||
add_arg("kernel32.lib");
|
||||
add_arg("ntdll.lib");
|
||||
add_arg("user32.lib");
|
||||
add_arg("shell32.lib");
|
||||
add_arg("legacy_stdio_definitions.lib");
|
||||
|
||||
if (active_target.win.crt_linking == WIN_CRT_STATIC)
|
||||
|
||||
@@ -1881,6 +1881,285 @@ ADDED:;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline MainType sema_find_main_type(SemaContext *context, Signature *sig)
|
||||
{
|
||||
Decl **params = sig->params;
|
||||
unsigned param_count = vec_size(params);
|
||||
bool is_win32 = platform_target.os == OS_TYPE_WIN32;
|
||||
Type *arg_type, *arg_type2;
|
||||
switch (param_count)
|
||||
{
|
||||
case 0:
|
||||
return MAIN_TYPE_NO_ARGS;
|
||||
break;
|
||||
case 1:
|
||||
arg_type = type_flatten_distinct(params[0]->type);
|
||||
if (arg_type == type_get_subarray(type_get_subarray(type_char))) return MAIN_TYPE_ARGS;
|
||||
SEMA_ERROR(params[0], "Expected a parameter of type 'String[]'.");
|
||||
return MAIN_TYPE_ERROR;
|
||||
case 2:
|
||||
arg_type = type_flatten_distinct(params[0]->type);
|
||||
arg_type2 = type_flatten_distinct(params[1]->type);
|
||||
if (arg_type != type_cint)
|
||||
{
|
||||
SEMA_ERROR(params[0],
|
||||
"Expected a parameter of type %s for a C-style main.",
|
||||
type_quoted_error_string(type_cint));
|
||||
return MAIN_TYPE_ERROR;
|
||||
}
|
||||
if (arg_type2 != type_get_ptr(type_get_ptr(type_char)))
|
||||
{
|
||||
SEMA_ERROR(params[1], "Expected a parameter of type 'char**' for a C-style main.");
|
||||
return MAIN_TYPE_ERROR;
|
||||
}
|
||||
return MAIN_TYPE_RAW;
|
||||
case 3:
|
||||
if (!is_win32) break;
|
||||
arg_type = type_flatten_distinct(params[0]->type);
|
||||
arg_type2 = type_flatten_distinct(params[1]->type);
|
||||
if (arg_type != type_voidptr)
|
||||
{
|
||||
SEMA_ERROR(params[0], "Expected a parameter of type 'void*' (HINSTANCE)");
|
||||
return MAIN_TYPE_ERROR;
|
||||
}
|
||||
if (arg_type2 != type_get_subarray(type_get_subarray(type_char)))
|
||||
{
|
||||
SEMA_ERROR(params[1], "Expected a parameter of type 'String[]'.");
|
||||
return MAIN_TYPE_ERROR;
|
||||
}
|
||||
if (type_flatten_distinct(params[2]->type) != type_cint)
|
||||
{
|
||||
SEMA_ERROR(params[2], "Expected a parameter of type %s for the 'showCmd' parameter.",
|
||||
type_quoted_error_string(type_cint));
|
||||
return MAIN_TYPE_ERROR;
|
||||
}
|
||||
return MAIN_TYPE_WIN;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SEMA_ERROR(params[0], is_win32
|
||||
? "Expected zero, 1 or 3 parameters for main."
|
||||
: "Expected zero or 1 parameters for main.");
|
||||
return MAIN_TYPE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
static inline Decl *sema_create_synthetic_main(SemaContext *context, Decl *decl, MainType main, bool int_return, bool err_return)
|
||||
{
|
||||
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
|
||||
function->name = kw_mainstub;
|
||||
function->unit = decl->unit;
|
||||
function->extname = kw_main;
|
||||
function->has_extname = true;
|
||||
function->func_decl.signature.rtype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.vararg_index = 2;
|
||||
Decl *param1 = decl_new_generated_var(type_cint, VARDECL_PARAM, decl->span);
|
||||
Decl *param2 = decl_new_generated_var(type_get_ptr(type_get_ptr(type_char)), VARDECL_PARAM, decl->span);
|
||||
Decl **main_params = NULL;
|
||||
vec_add(main_params, param1);
|
||||
vec_add(main_params, param2);
|
||||
function->func_decl.signature.params = main_params;
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, decl->span);
|
||||
AstId *next = &body->compound_stmt.first_stmt;
|
||||
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
|
||||
int type = int_return ? 1 : (err_return ? 2 : 0);
|
||||
const char *main_invoker;
|
||||
switch (main)
|
||||
{
|
||||
case MAIN_TYPE_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@main_to_void_main_args"; goto NEXT;
|
||||
case 1 : main_invoker = "@main_to_int_main_args"; goto NEXT;
|
||||
case 2 : main_invoker = "@main_to_err_main_args"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
case MAIN_TYPE_NO_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@main_to_void_main"; goto NEXT;
|
||||
case 1 : main_invoker = "@main_to_int_main"; goto NEXT;
|
||||
case 2 : main_invoker = "@main_to_err_main"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
NEXT:;
|
||||
const char *kw_main_invoker = symtab_preset(main_invoker, TOKEN_AT_IDENT);
|
||||
Decl *d = sema_find_symbol(context, kw_main_invoker);
|
||||
if (!d)
|
||||
{
|
||||
SEMA_ERROR(decl, "Missing main forwarding function '%s'.", kw_main_invoker);
|
||||
return poisoned_decl;
|
||||
}
|
||||
Expr *invoker = expr_new(EXPR_IDENTIFIER, decl->span);
|
||||
invoker->identifier_expr.decl = d;
|
||||
invoker->resolve_status = RESOLVE_DONE;
|
||||
invoker->type = decl->type;
|
||||
Expr *call = expr_new(EXPR_CALL, decl->span);
|
||||
Expr *fn_ref = expr_variable(decl);
|
||||
vec_add(call->call_expr.arguments, fn_ref);
|
||||
vec_add(call->call_expr.arguments, expr_variable(param1));
|
||||
vec_add(call->call_expr.arguments, expr_variable(param2));
|
||||
call->call_expr.function = exprid(invoker);
|
||||
param1->resolve_status = RESOLVE_NOT_DONE;
|
||||
param2->resolve_status = RESOLVE_NOT_DONE;
|
||||
ast_append(&next, ret_stmt);
|
||||
ret_stmt->return_stmt.expr = call;
|
||||
function->func_decl.body = astid(body);
|
||||
function->is_synthetic = true;
|
||||
return function;
|
||||
}
|
||||
|
||||
static inline Decl *sema_create_synthetic_wmain(SemaContext *context, Decl *decl, MainType main, bool int_return, bool err_return)
|
||||
{
|
||||
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
|
||||
function->name = kw_mainstub;
|
||||
function->unit = decl->unit;
|
||||
function->extname = kw_wmain;
|
||||
function->has_extname = true;
|
||||
function->func_decl.signature.rtype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.vararg_index = 2;
|
||||
Decl *param1 = decl_new_generated_var(type_cint, VARDECL_PARAM, decl->span);
|
||||
Decl *param2 = decl_new_generated_var(type_get_ptr(type_get_ptr(type_ushort)), VARDECL_PARAM, decl->span);
|
||||
Decl **main_params = NULL;
|
||||
vec_add(main_params, param1);
|
||||
vec_add(main_params, param2);
|
||||
function->func_decl.signature.params = main_params;
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, decl->span);
|
||||
AstId *next = &body->compound_stmt.first_stmt;
|
||||
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
|
||||
int type = int_return ? 1 : (err_return ? 2 : 0);
|
||||
const char *main_invoker;
|
||||
switch (main)
|
||||
{
|
||||
case MAIN_TYPE_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@wmain_to_void_main_args"; goto NEXT;
|
||||
case 1 : main_invoker = "@wmain_to_int_main_args"; goto NEXT;
|
||||
case 2 : main_invoker = "@wmain_to_err_main_args"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
case MAIN_TYPE_NO_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@main_to_void_main"; goto NEXT;
|
||||
case 1 : main_invoker = "@main_to_int_main"; goto NEXT;
|
||||
case 2 : main_invoker = "@main_to_err_main"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
NEXT:;
|
||||
const char *kw_main_invoker = symtab_preset(main_invoker, TOKEN_AT_IDENT);
|
||||
Decl *d = sema_find_symbol(context, kw_main_invoker);
|
||||
if (!d)
|
||||
{
|
||||
SEMA_ERROR(decl, "Missing main forwarding function '%s'.", kw_main_invoker);
|
||||
return poisoned_decl;
|
||||
}
|
||||
Expr *invoker = expr_new(EXPR_IDENTIFIER, decl->span);
|
||||
invoker->identifier_expr.decl = d;
|
||||
invoker->resolve_status = RESOLVE_DONE;
|
||||
invoker->type = decl->type;
|
||||
Expr *call = expr_new(EXPR_CALL, decl->span);
|
||||
Expr *fn_ref = expr_variable(decl);
|
||||
vec_add(call->call_expr.arguments, fn_ref);
|
||||
vec_add(call->call_expr.arguments, expr_variable(param1));
|
||||
vec_add(call->call_expr.arguments, expr_variable(param2));
|
||||
call->call_expr.function = exprid(invoker);
|
||||
param1->resolve_status = RESOLVE_NOT_DONE;
|
||||
param2->resolve_status = RESOLVE_NOT_DONE;
|
||||
ast_append(&next, ret_stmt);
|
||||
ret_stmt->return_stmt.expr = call;
|
||||
function->func_decl.body = astid(body);
|
||||
function->is_synthetic = true;
|
||||
return function;
|
||||
}
|
||||
|
||||
static inline Decl *sema_create_synthetic_win_main(SemaContext *context, Decl *decl, MainType main, bool int_return, bool err_return)
|
||||
{
|
||||
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
|
||||
function->name = kw_mainstub;
|
||||
function->unit = decl->unit;
|
||||
function->extname = kw_winmain;
|
||||
function->has_extname = true;
|
||||
function->func_decl.signature.rtype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.vararg_index = 3;
|
||||
Decl *param1 = decl_new_generated_var(type_voidptr, VARDECL_PARAM, decl->span);
|
||||
Decl *param2 = decl_new_generated_var(type_get_ptr(type_ushort), VARDECL_PARAM, decl->span);
|
||||
Decl *param3 = decl_new_generated_var(type_cint, VARDECL_PARAM, decl->span);
|
||||
Decl **main_params = NULL;
|
||||
vec_add(main_params, param1);
|
||||
vec_add(main_params, param2);
|
||||
vec_add(main_params, param3);
|
||||
function->func_decl.signature.params = main_params;
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, decl->span);
|
||||
AstId *next = &body->compound_stmt.first_stmt;
|
||||
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
|
||||
int type = int_return ? 1 : (err_return ? 2 : 0);
|
||||
const char *main_invoker;
|
||||
switch (main)
|
||||
{
|
||||
case MAIN_TYPE_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@win_to_void_main_args"; goto NEXT;
|
||||
case 1 : main_invoker = "@win_to_int_main_args"; goto NEXT;
|
||||
case 2 : main_invoker = "@win_to_err_main_args"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
case MAIN_TYPE_NO_ARGS:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@win_to_void_main_noargs"; goto NEXT;
|
||||
case 1 : main_invoker = "@win_to_int_main_noargs"; goto NEXT;
|
||||
case 2 : main_invoker = "@win_to_err_main_noargs"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
case MAIN_TYPE_WIN:
|
||||
switch (type)
|
||||
{
|
||||
case 0 : main_invoker = "@win_to_void_main"; goto NEXT;
|
||||
case 1 : main_invoker = "@win_to_int_main"; goto NEXT;
|
||||
case 2 : main_invoker = "@win_to_err_main"; goto NEXT;
|
||||
default: UNREACHABLE
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
NEXT:;
|
||||
const char *kw_main_invoker = symtab_preset(main_invoker, TOKEN_AT_IDENT);
|
||||
Decl *d = sema_find_symbol(context, kw_main_invoker);
|
||||
if (!d)
|
||||
{
|
||||
SEMA_ERROR(decl, "Missing main forwarding macro '%s'.", kw_main_invoker);
|
||||
return poisoned_decl;
|
||||
}
|
||||
Expr *invoker = expr_new(EXPR_IDENTIFIER, decl->span);
|
||||
invoker->identifier_expr.decl = d;
|
||||
invoker->resolve_status = RESOLVE_DONE;
|
||||
invoker->type = decl->type;
|
||||
Expr *call = expr_new(EXPR_CALL, decl->span);
|
||||
Expr *fn_ref = expr_variable(decl);
|
||||
vec_add(call->call_expr.arguments, fn_ref);
|
||||
vec_add(call->call_expr.arguments, expr_variable(param1));
|
||||
vec_add(call->call_expr.arguments, expr_variable(param2));
|
||||
vec_add(call->call_expr.arguments, expr_variable(param3));
|
||||
call->call_expr.function = exprid(invoker);
|
||||
param1->resolve_status = RESOLVE_NOT_DONE;
|
||||
param2->resolve_status = RESOLVE_NOT_DONE;
|
||||
param3->resolve_status = RESOLVE_NOT_DONE;
|
||||
ast_append(&next, ret_stmt);
|
||||
ret_stmt->return_stmt.expr = call;
|
||||
function->func_decl.body = astid(body);
|
||||
function->is_synthetic = true;
|
||||
return function;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
{
|
||||
assert(decl != context->unit->main_function);
|
||||
@@ -1914,40 +2193,8 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
return false;
|
||||
}
|
||||
// At this point the style is either MAIN_INT_VOID, MAIN_VOID_VOID or MAIN_ERR_VOID
|
||||
Decl **params = signature->params;
|
||||
unsigned param_count = vec_size(params);
|
||||
bool subarray_param = false;
|
||||
bool cparam = false;
|
||||
switch (param_count)
|
||||
{
|
||||
case 0:
|
||||
// This is the default style already set
|
||||
break;
|
||||
case 1:
|
||||
if (type_flatten_distinct(params[0]->type) != type_get_subarray(type_get_subarray(type_char)))
|
||||
{
|
||||
SEMA_ERROR(params[0], "Expected a parameter of type 'char[][]'");
|
||||
return false;
|
||||
}
|
||||
subarray_param = true;
|
||||
break;
|
||||
case 2:
|
||||
if (type_flatten_distinct(params[0]->type) != type_cint)
|
||||
{
|
||||
SEMA_ERROR(params[0], "Expected a parameter of type %s for a C-style main.", type_quoted_error_string(type_cint));
|
||||
return false;
|
||||
}
|
||||
if (type_flatten_distinct(params[1]->type) != type_get_ptr(type_get_ptr(type_char)))
|
||||
{
|
||||
SEMA_ERROR(params[1], "Expected a parameter of type 'char**' for a C-style main.");
|
||||
return false;
|
||||
}
|
||||
cparam = true;
|
||||
break;
|
||||
default:
|
||||
SEMA_ERROR(params[0], "Expected zero, 1 or 2 parameters for main.");
|
||||
return false;
|
||||
}
|
||||
MainType type = sema_find_main_type(context, signature);
|
||||
if (type == MAIN_TYPE_ERROR) return false;
|
||||
if (active_target.type == TARGET_TYPE_TEST) return true;
|
||||
Decl *function;
|
||||
if (active_target.no_entry)
|
||||
@@ -1955,73 +2202,29 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
function = decl;
|
||||
goto REGISTER_MAIN;
|
||||
}
|
||||
if (!subarray_param && is_int_return)
|
||||
if (type == MAIN_TYPE_RAW && !is_int_return)
|
||||
{
|
||||
SEMA_ERROR(rtype_info, "Int return is required for C style main.");
|
||||
return false;
|
||||
}
|
||||
if ((type == MAIN_TYPE_RAW || type == MAIN_TYPE_NO_ARGS) && is_int_return && !active_target.gui)
|
||||
{
|
||||
// Int return is pass-through at the moment.
|
||||
decl->visibility = VISIBLE_EXTERN;
|
||||
function = decl;
|
||||
goto REGISTER_MAIN;
|
||||
}
|
||||
function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
|
||||
function->name = kw_mainstub;
|
||||
function->unit = decl->unit;
|
||||
function->extname = kw_main;
|
||||
function->has_extname = true;
|
||||
function->func_decl.signature.rtype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.vararg_index = 2;
|
||||
Decl *param1 = decl_new_generated_var(type_cint, VARDECL_PARAM, decl->span);
|
||||
Decl *param2 = decl_new_generated_var(type_get_ptr(type_get_ptr(type_char)), VARDECL_PARAM, decl->span);
|
||||
Decl **main_params = NULL;
|
||||
vec_add(main_params, param1);
|
||||
vec_add(main_params, param2);
|
||||
function->func_decl.signature.params = main_params;
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, decl->span);
|
||||
AstId *next = &body->compound_stmt.first_stmt;
|
||||
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
|
||||
Expr *call = expr_new(EXPR_CALL, decl->span);
|
||||
call->call_expr.function = exprid(expr_variable(decl));
|
||||
if (subarray_param)
|
||||
if (platform_target.os == OS_TYPE_WIN32)
|
||||
{
|
||||
Expr *subarray = expr_new(EXPR_ARGV_TO_SUBARRAY, decl->span);
|
||||
subarray->argv_expr.argc = param1;
|
||||
subarray->argv_expr.argv = param2;
|
||||
vec_add(call->call_expr.arguments, subarray);
|
||||
}
|
||||
else if (cparam)
|
||||
{
|
||||
vec_add(call->call_expr.arguments, expr_variable(param1));
|
||||
vec_add(call->call_expr.arguments, expr_variable(param2));
|
||||
}
|
||||
// Unresolve them or the params cannot be resolved later.
|
||||
param1->resolve_status = RESOLVE_NOT_DONE;
|
||||
param2->resolve_status = RESOLVE_NOT_DONE;
|
||||
if (is_int_return)
|
||||
{
|
||||
ret_stmt->return_stmt.expr = call;
|
||||
}
|
||||
else if (is_err_return)
|
||||
{
|
||||
Expr *try_expr = expr_new(EXPR_TRY, decl->span);
|
||||
try_expr->inner_expr = call;
|
||||
Expr *not_expr = expr_new(EXPR_UNARY, decl->span);
|
||||
not_expr->unary_expr.expr = try_expr;
|
||||
not_expr->unary_expr.operator = UNARYOP_NOT;
|
||||
Expr *cast_expr = expr_new(EXPR_CAST, decl->span);
|
||||
cast_expr->cast_expr.expr = exprid(not_expr);
|
||||
cast_expr->cast_expr.type_info = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
ret_stmt->return_stmt.expr = cast_expr;
|
||||
function = active_target.gui
|
||||
? sema_create_synthetic_win_main(context, decl, type, is_int_return, is_err_return)
|
||||
: sema_create_synthetic_wmain(context, decl, type, is_int_return, is_err_return);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ast *stmt = new_ast(AST_EXPR_STMT, decl->span);
|
||||
stmt->expr_stmt = call;
|
||||
ast_append(&next, stmt);
|
||||
ret_stmt->expr_stmt = expr_new_const_int(decl->span, type_cint, 0, true);
|
||||
function = sema_create_synthetic_main(context, decl, type, is_int_return, is_err_return);
|
||||
}
|
||||
ast_append(&next, ret_stmt);
|
||||
assert(body);
|
||||
function->func_decl.body = astid(body);
|
||||
function->is_synthetic = true;
|
||||
if (!decl_ok(function)) return false;
|
||||
REGISTER_MAIN:
|
||||
context->unit->main_function = function;
|
||||
if (global_context.main)
|
||||
|
||||
@@ -82,6 +82,8 @@ const char *kw_std__core__types;
|
||||
const char *kw___run_default_test_runner;
|
||||
const char *kw_type;
|
||||
const char *kw_typekind;
|
||||
const char *kw_winmain;
|
||||
const char *kw_wmain;
|
||||
|
||||
void symtab_destroy()
|
||||
{
|
||||
@@ -162,6 +164,8 @@ void symtab_init(uint32_t capacity)
|
||||
kw_std__core__types = KW_DEF("std::core::types");
|
||||
kw___run_default_test_runner = KW_DEF("__run_default_test_runner");
|
||||
kw_type = KW_DEF("type");
|
||||
kw_winmain = KW_DEF("wWinMain");
|
||||
kw_wmain = KW_DEF("wmain");
|
||||
|
||||
type_property_list[TYPE_PROPERTY_MAX] = builtin_list[BUILTIN_MAX] = KW_DEF("max");
|
||||
type_property_list[TYPE_PROPERTY_MIN] = builtin_list[BUILTIN_MIN] = KW_DEF("min");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.28"
|
||||
#define COMPILER_VERSION "0.4.29"
|
||||
@@ -89,7 +89,7 @@ fn void random_fasta(char[] symb, double[] probability, int n)
|
||||
if (i % LINELEN != 0) putchar('\n');
|
||||
}
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
fn int main(int argc, char **argv)
|
||||
{
|
||||
int n = 1000;
|
||||
if (argc > 1) n = atoi(argv[1]);
|
||||
@@ -103,6 +103,7 @@ fn void main(int argc, char **argv)
|
||||
printf(">THREE Homo sapiens frequency\n");
|
||||
random_fasta(homosapiens, homosapiens_p, n * 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: fasta.ll
|
||||
@@ -326,7 +327,7 @@ if.exit14: ; preds = %if.then13, %loop.ex
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @fasta_main(i32 %0, ptr %1) #0 {
|
||||
define i32 @main(i32 %0, ptr %1) #0 {
|
||||
entry:
|
||||
%n = alloca i32, align 4
|
||||
store i32 1000, ptr %n, align 4
|
||||
@@ -363,11 +364,5 @@ if.exit: ; preds = %if.then, %entry
|
||||
%9 = load i32, ptr %n, align 4
|
||||
%mul10 = mul i32 %9, 5
|
||||
call void @fasta_random_fasta(ptr %lo6, i64 %hi7, ptr %lo8, i64 %hi9, i32 %mul10)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, ptr %1) #0 {
|
||||
entry:
|
||||
call void @fasta_main(i32 %0, ptr %1)
|
||||
ret i32 0
|
||||
}
|
||||
@@ -106,21 +106,18 @@ define i32 @main(i32 %0, ptr %1) #0 {
|
||||
entry:
|
||||
%2 = call i64 @foo_main()
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
br i1 %not_err, label %after_check, label %error_block
|
||||
br i1 %not_err, label %after_check, label %assign_optional
|
||||
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %2, ptr %error_var, align 8
|
||||
br label %noerr_block
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %noerr_block
|
||||
|
||||
noerr_block: ; preds = %after_check
|
||||
br label %phi_trycatch_block
|
||||
|
||||
error_block: ; preds = %entry
|
||||
br label %phi_trycatch_block
|
||||
|
||||
phi_trycatch_block: ; preds = %error_block, %noerr_block
|
||||
%val = phi i8 [ 1, %noerr_block ], [ 0, %error_block ]
|
||||
%3 = trunc i8 %val to i1
|
||||
%not = xor i1 %3, true
|
||||
%boolsi = zext i1 %not to i32
|
||||
ret i32 %boolsi
|
||||
}
|
||||
noerr_block: ; preds = %after_check, %assign_optional
|
||||
%3 = load i64, ptr %error_var, align 8
|
||||
%neq = icmp ne i64 %3, 0
|
||||
%ternary = select i1 %neq, i32 1, i32 0
|
||||
ret i32 %ternary
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ fn void random_fasta(char[] symb, double[] probability, int n)
|
||||
if (i % LINELEN != 0) putchar('\n');
|
||||
}
|
||||
|
||||
fn void main(int argc, char **argv)
|
||||
fn int main(int argc, char **argv)
|
||||
{
|
||||
int n = 1000;
|
||||
if (argc > 1) n = atoi(argv[1]);
|
||||
@@ -102,7 +102,7 @@ fn void main(int argc, char **argv)
|
||||
|
||||
printf(">THREE Homo sapiens frequency\n");
|
||||
random_fasta(homosapiens, homosapiens_p, n * 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: fasta.ll
|
||||
@@ -329,7 +329,7 @@ if.exit15: ; preds = %if.then14, %loop.ex
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @fasta_main(i32 %0, i8** %1) #0 {
|
||||
define i32 @main(i32 %0, i8** %1) #0 {
|
||||
entry:
|
||||
%n = alloca i32, align 4
|
||||
store i32 1000, i32* %n, align 4
|
||||
@@ -366,11 +366,5 @@ if.exit: ; preds = %if.then, %entry
|
||||
%9 = load i32, i32* %n, align 4
|
||||
%mul10 = mul i32 %9, 5
|
||||
call void @fasta_random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, i8** %1) #0 {
|
||||
entry:
|
||||
call void @fasta_main(i32 %0, i8** %1)
|
||||
ret i32 0
|
||||
}
|
||||
@@ -106,21 +106,18 @@ define i32 @main(i32 %0, i8** %1) #0 {
|
||||
entry:
|
||||
%2 = call i64 @foo_main()
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
br i1 %not_err, label %after_check, label %error_block
|
||||
br i1 %not_err, label %after_check, label %assign_optional
|
||||
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %2, i64* %error_var, align 8
|
||||
br label %noerr_block
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %noerr_block
|
||||
|
||||
noerr_block: ; preds = %after_check
|
||||
br label %phi_trycatch_block
|
||||
|
||||
error_block: ; preds = %entry
|
||||
br label %phi_trycatch_block
|
||||
|
||||
phi_trycatch_block: ; preds = %error_block, %noerr_block
|
||||
%val = phi i8 [ 1, %noerr_block ], [ 0, %error_block ]
|
||||
%3 = trunc i8 %val to i1
|
||||
%not = xor i1 %3, true
|
||||
%boolsi = zext i1 %not to i32
|
||||
ret i32 %boolsi
|
||||
noerr_block: ; preds = %after_check, %assign_optional
|
||||
%3 = load i64, i64* %error_var, align 8
|
||||
%neq = icmp ne i64 %3, 0
|
||||
%ternary = select i1 %neq, i32 1, i32 0
|
||||
ret i32 %ternary
|
||||
}
|
||||
Reference in New Issue
Block a user