mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Name change, some updates using "from end" indexing.
This commit is contained in:
@@ -85,6 +85,7 @@
|
||||
- Allow enums to use a distinct type as the backing type.
|
||||
- Update addition and subtraction on enums.
|
||||
- `@ensure` checks only non-optional results.
|
||||
- `assert` may now take varargs for formatting.
|
||||
|
||||
### Stdlib changes
|
||||
- Updated posix/win32 stdlib namespacing
|
||||
|
||||
@@ -1374,6 +1374,7 @@ typedef struct
|
||||
bool is_ensure;
|
||||
ExprId message;
|
||||
ExprId expr;
|
||||
Expr **args;
|
||||
} AstAssertStmt;
|
||||
|
||||
|
||||
|
||||
@@ -586,6 +586,7 @@ RETRY:
|
||||
case AST_CT_ASSERT:
|
||||
MACRO_COPY_EXPRID(ast->assert_stmt.expr);
|
||||
MACRO_COPY_EXPRID(ast->assert_stmt.message);
|
||||
MACRO_COPY_EXPR_LIST(ast->assert_stmt.args);
|
||||
break;
|
||||
case AST_BREAK_STMT:
|
||||
case AST_CONTINUE_STMT:
|
||||
|
||||
@@ -1001,16 +1001,28 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
|
||||
llvm_emit_cond_br(c, &value, on_ok, on_fail);
|
||||
llvm_emit_block(c, on_fail);
|
||||
SourceSpan loc = assert_expr->span;
|
||||
const char *error;
|
||||
if (ast->assert_stmt.message)
|
||||
const char *error = NULL;
|
||||
Expr *message_expr = exprptrzero(ast->assert_stmt.message);
|
||||
BEValue *values = NULL;
|
||||
if (message_expr)
|
||||
{
|
||||
error = exprptr(ast->assert_stmt.message)->const_expr.string.chars;
|
||||
Expr **args = ast->assert_stmt.args;
|
||||
if (vec_size(args))
|
||||
{
|
||||
FOREACH_BEGIN(Expr *arg, args)
|
||||
BEValue var;
|
||||
llvm_emit_expr(c, &var, arg);
|
||||
llvm_emit_any_from_value(c, &var, arg->type);
|
||||
vec_add(values, var);
|
||||
FOREACH_END();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Assert violation";
|
||||
}
|
||||
llvm_emit_panic(c, error, loc, NULL, NULL);
|
||||
llvm_emit_panic(c, values ? NULL : error, loc, values ? error : NULL, values);
|
||||
llvm_emit_br(c, on_ok);
|
||||
llvm_emit_block(c, on_ok);
|
||||
}
|
||||
|
||||
@@ -1080,7 +1080,14 @@ static inline Ast *parse_assert_stmt(ParseContext *c)
|
||||
|
||||
if (try_consume(c, TOKEN_COMMA))
|
||||
{
|
||||
ASSIGN_EXPRID_OR_RET(ast->assert_stmt.message, parse_expr(c), poisoned_ast);
|
||||
Expr **args = NULL;
|
||||
ASSIGN_EXPRID_OR_RET(ast->assert_stmt.message, parse_constant_expr(c), poisoned_ast);
|
||||
while (try_consume(c, TOKEN_COMMA))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_ast);
|
||||
vec_add(args, expr);
|
||||
}
|
||||
ast->assert_stmt.args = args;
|
||||
}
|
||||
TRY_CONSUME_OR_RET(TOKEN_RPAREN, "The ending ')' was expected here.", poisoned_ast);
|
||||
return consume_eos(c, ast);
|
||||
|
||||
@@ -82,14 +82,12 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
|
||||
if (message_expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, message_expr)) return false;
|
||||
if (!expr_is_const_string(message_expr))
|
||||
{
|
||||
SEMA_ERROR(message_expr, "Expected a string as the error message.");
|
||||
return false;
|
||||
}
|
||||
if (!expr_is_const_string(message_expr)) RETURN_SEMA_ERROR(message_expr, "Expected a string as the error message.");
|
||||
FOREACH_BEGIN(Expr *e, statement->assert_stmt.args)
|
||||
if (!sema_analyse_expr(context, e)) return false;
|
||||
FOREACH_END();
|
||||
}
|
||||
|
||||
|
||||
// Handle force unwrapping using assert, e.g. assert(try x)
|
||||
if (expr->expr_kind == EXPR_TRY_UNWRAP_CHAIN)
|
||||
{
|
||||
@@ -111,7 +109,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
|
||||
// If it's ensure (and an error) we print an error.
|
||||
if (statement->assert_stmt.is_ensure)
|
||||
{
|
||||
if (message_expr)
|
||||
if (message_expr && expr_is_const(message_expr) && vec_size(statement->assert_stmt.args))
|
||||
{
|
||||
SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr));
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.538"
|
||||
#define COMPILER_VERSION "0.4.539"
|
||||
65
test/test_suite/assert/assertf.c3t
Normal file
65
test/test_suite/assert/assertf.c3t
Normal file
@@ -0,0 +1,65 @@
|
||||
// #target: macos-x64
|
||||
// #safe: yes
|
||||
module main;
|
||||
|
||||
fn void! main()
|
||||
{
|
||||
for (usz i = 0; i < 100000000; i++)
|
||||
{
|
||||
assert(i != 2, "Test %s %s", i, i * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* #expect: main.ll
|
||||
|
||||
define i64 @main.main() #0 {
|
||||
entry:
|
||||
%i = alloca i64, align 8
|
||||
%taddr = alloca i64, align 8
|
||||
%varargslots = alloca [2 x %any], align 16
|
||||
%indirectarg = alloca %"any[]", align 8
|
||||
%reterr = alloca i64, align 8
|
||||
store i64 0, ptr %i, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %assert_ok, %entry
|
||||
%0 = load i64, ptr %i, align 8
|
||||
%gt = icmp ugt i64 100000000, %0
|
||||
br i1 %gt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%1 = load i64, ptr %i, align 8
|
||||
%neq = icmp ne i64 2, %1
|
||||
br i1 %neq, label %assert_ok, label %assert_fail
|
||||
|
||||
assert_fail: ; preds = %loop.body
|
||||
%2 = insertvalue %any undef, ptr %i, 0
|
||||
%3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
|
||||
%4 = load i64, ptr %i, align 8
|
||||
%mul = mul i64 %4, 2
|
||||
store i64 %mul, ptr %taddr, align 8
|
||||
%5 = insertvalue %any undef, ptr %taddr, 0
|
||||
%6 = insertvalue %any %5, i64 ptrtoint (ptr @"$ct.long" to i64), 1
|
||||
%7 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0
|
||||
store %any %3, ptr %7, align 16
|
||||
%8 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1
|
||||
store %any %6, ptr %8, align 16
|
||||
%9 = insertvalue %"any[]" undef, ptr %varargslots, 0
|
||||
%10 = insertvalue %"any[]" %9, i64 2, 1
|
||||
store %"any[]" %10, ptr %indirectarg, align 8
|
||||
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 10, ptr @.file, i64 10, ptr @.func, i64 4, i32 7, ptr byval(%"any[]") align 8 %indirectarg)
|
||||
br label %assert_ok
|
||||
|
||||
assert_ok: ; preds = %assert_fail, %loop.body
|
||||
%11 = load i64, ptr %i, align 8
|
||||
%neq1 = icmp ne i64 2, %11
|
||||
call void @llvm.assume(i1 %neq1)
|
||||
%12 = load i64, ptr %i, align 8
|
||||
%add = add i64 %12, 1
|
||||
store i64 %add, ptr %i, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user