mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Allow any expression as default expression.
This commit is contained in:
committed by
Christoffer Lerno
parent
2698ba1a94
commit
12c17b62cf
@@ -9,6 +9,7 @@ struct File
|
||||
CFile file;
|
||||
}
|
||||
|
||||
|
||||
fn int putchar(char c) @inline
|
||||
{
|
||||
return libc::putchar(c);
|
||||
@@ -41,7 +42,6 @@ fn int println(char *message = "") @inline
|
||||
fn void! File.open(File* file, char[] filename, char[] mode)
|
||||
{
|
||||
char* filename_copy = mem::talloc(filename.len + 1)!!;
|
||||
|
||||
char* mode_copy = mem::talloc(mode.len + 1)!!;
|
||||
|
||||
mem::copy(filename_copy, (char*)(filename), filename.len);
|
||||
|
||||
@@ -349,6 +349,7 @@ typedef struct VarDecl_
|
||||
Expr *init_expr;
|
||||
Decl *alias;
|
||||
};
|
||||
struct CompilationUnit_ *unit;
|
||||
union
|
||||
{
|
||||
int32_t index;
|
||||
|
||||
@@ -563,16 +563,13 @@ static inline bool sema_analyse_function_param(SemaContext *context, Decl *param
|
||||
{
|
||||
Expr *expr = param->var.init_expr;
|
||||
|
||||
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false;
|
||||
if (IS_FAILABLE(expr))
|
||||
if (expr->expr_kind == EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(expr, "Default arguments may not be failable.");
|
||||
return false;
|
||||
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false;
|
||||
}
|
||||
if (!expr_is_constant_eval(expr, CONSTANT_EVAL_ANY))
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(expr, "Only constant expressions may be used as default values.");
|
||||
return false;
|
||||
param->var.unit = context->unit;
|
||||
}
|
||||
*has_default = true;
|
||||
}
|
||||
@@ -2099,6 +2096,16 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!context->current_function)
|
||||
{
|
||||
if (context->current_macro)
|
||||
{
|
||||
SEMA_ERROR(decl, "Macros with declarations may not be used outside of functions.");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(decl, "Variable declarations may not be used outside of functions.");
|
||||
return false;
|
||||
}
|
||||
// Add a local to the current context, will throw error on shadowing.
|
||||
if (!sema_add_local(context, decl)) return decl_poison(decl);
|
||||
}
|
||||
|
||||
@@ -1378,17 +1378,23 @@ static inline bool sema_expand_call_arguments(SemaContext *context, CalledDecl *
|
||||
|
||||
if (is_func_ptr) goto FAIL_MISSING;
|
||||
// 17b. Set the init expression.
|
||||
Expr *init_expr = params[i]->var.init_expr;
|
||||
Decl *param = params[i];
|
||||
Expr *init_expr = param->var.init_expr;
|
||||
if (init_expr)
|
||||
{
|
||||
if (callee->macro)
|
||||
Expr *arg = actual_args[i] = expr_macro_copy(init_expr);
|
||||
if (arg->resolve_status != RESOLVE_DONE)
|
||||
{
|
||||
actual_args[i] = expr_macro_copy(init_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(init_expr->resolve_status == RESOLVE_DONE);
|
||||
actual_args[i] = init_expr;
|
||||
SemaContext default_context;
|
||||
Type *rtype = NULL;
|
||||
sema_context_init(&default_context, param->var.unit);
|
||||
default_context.compilation_unit = context->unit;
|
||||
default_context.current_function = context->current_function;
|
||||
context_change_scope_with_flags(&default_context, SCOPE_NONE);
|
||||
default_context.original_inline_line = context->original_inline_line ? context->original_inline_line : init_expr->span.row;
|
||||
bool success = sema_analyse_expr_rhs(&default_context, param->type, arg, true);
|
||||
sema_context_destroy(&default_context);
|
||||
if (!success) return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@ fault MyError
|
||||
FOO,
|
||||
}
|
||||
|
||||
fn void test(int a = z) {} // #error: Only constant expressions may be used as default values
|
||||
fn void test(int a = z) {}
|
||||
|
||||
fn void test2(int b = MyError.FOO!) {} // #error: Default arguments may not be failable
|
||||
fn void test2(int b = MyError.FOO!) {}
|
||||
57
test/test_suite/functions/defered_default_arguments.c3t
Normal file
57
test/test_suite/functions/defered_default_arguments.c3t
Normal file
@@ -0,0 +1,57 @@
|
||||
module test;
|
||||
import std::io;
|
||||
import test2;
|
||||
|
||||
fn void test(int a = test2::bar(), int b = test2::foo())
|
||||
{
|
||||
io::printf("%d %d\n", a, b);
|
||||
}
|
||||
|
||||
module test2;
|
||||
|
||||
fn int foo()
|
||||
{
|
||||
static int x = 0;
|
||||
return ++x;
|
||||
}
|
||||
|
||||
macro int bar()
|
||||
{
|
||||
static int x = 0;
|
||||
return ++x;
|
||||
}
|
||||
|
||||
module test3;
|
||||
import test;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
test::test(1, 2);
|
||||
test::test(.a = 3);
|
||||
test::test(1, .b = 32);
|
||||
test::test();
|
||||
test::test();
|
||||
}
|
||||
|
||||
// #expect: test3.ll
|
||||
|
||||
entry:
|
||||
call void @test_test(i32 1, i32 2)
|
||||
%0 = call i32 @test2_foo()
|
||||
call void @test_test(i32 3, i32 %0)
|
||||
call void @test_test(i32 1, i32 32)
|
||||
%1 = load i32, i32* @"main$x", align 4
|
||||
%add = add i32 %1, 1
|
||||
store i32 %add, i32* @"main$x", align 4
|
||||
%2 = call i32 @test2_foo()
|
||||
call void @test_test(i32 %add, i32 %2)
|
||||
%3 = load i32, i32* @"main$x.1", align 4
|
||||
%add1 = add i32 %3, 1
|
||||
store i32 %add1, i32* @"main$x.1", align 4
|
||||
%4 = call i32 @test2_foo()
|
||||
call void @test_test(i32 %add1, i32 %4)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@ fault MyError
|
||||
FOO,
|
||||
}
|
||||
|
||||
fn void test(int a = z) {} // #error: Only constant expressions may be used as default values
|
||||
fn void test(int a = z) {}
|
||||
|
||||
fn void test2(int b = MyError.FOO!) {} // #error: Default arguments may not be failable
|
||||
fn void test2(int b = MyError.FOO!) {}
|
||||
57
test/test_suite2/functions/defered_default_arguments.c3t
Normal file
57
test/test_suite2/functions/defered_default_arguments.c3t
Normal file
@@ -0,0 +1,57 @@
|
||||
module test;
|
||||
import std::io;
|
||||
import test2;
|
||||
|
||||
fn void test(int a = test2::bar(), int b = test2::foo())
|
||||
{
|
||||
io::printf("%d %d\n", a, b);
|
||||
}
|
||||
|
||||
module test2;
|
||||
|
||||
fn int foo()
|
||||
{
|
||||
static int x = 0;
|
||||
return ++x;
|
||||
}
|
||||
|
||||
macro int bar()
|
||||
{
|
||||
static int x = 0;
|
||||
return ++x;
|
||||
}
|
||||
|
||||
module test3;
|
||||
import test;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
test::test(1, 2);
|
||||
test::test(.a = 3);
|
||||
test::test(1, .b = 32);
|
||||
test::test();
|
||||
test::test();
|
||||
}
|
||||
|
||||
// #expect: test3.ll
|
||||
|
||||
entry:
|
||||
call void @test_test(i32 1, i32 2)
|
||||
%0 = call i32 @test2_foo()
|
||||
call void @test_test(i32 3, i32 %0)
|
||||
call void @test_test(i32 1, i32 32)
|
||||
%1 = load i32, ptr @"main$x", align 4
|
||||
%add = add i32 %1, 1
|
||||
store i32 %add, ptr @"main$x", align 4
|
||||
%2 = call i32 @test2_foo()
|
||||
call void @test_test(i32 %add, i32 %2)
|
||||
%3 = load i32, ptr @"main$x.1", align 4
|
||||
%add1 = add i32 %3, 1
|
||||
store i32 %add1, ptr @"main$x.1", align 4
|
||||
%4 = call i32 @test2_foo()
|
||||
call void @test_test(i32 %add1, i32 %4)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user