mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Adding $unreachable
This commit is contained in:
committed by
Christoffer Lerno
parent
009ccfd730
commit
31d2c15dba
@@ -2,19 +2,18 @@ module baz;
|
||||
import gen;
|
||||
|
||||
extern func int printf(char *hello, ...);
|
||||
extern func void blurg();
|
||||
|
||||
public func void runBaz()
|
||||
{
|
||||
int x = printf("Baz func\n");
|
||||
int y = printf("FOek");
|
||||
|
||||
assert(x > 0 && y > 0);
|
||||
int i = printf("hello");
|
||||
|
||||
int z = printf("Foefe\n");
|
||||
x = printf("Baz func\n");
|
||||
y = printf("FOek");
|
||||
if (i > 0) blurg();
|
||||
|
||||
assert(x > 0 && y > 0 && printf("Fejei") > 0);
|
||||
if (i > 0) return;
|
||||
|
||||
$unreachable;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1085,6 +1085,9 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
|
||||
case AST_NOP_STMT:
|
||||
DUMP("(nop)");
|
||||
return;
|
||||
case AST_UNREACHABLE_STMT:
|
||||
DUMP("(unreachable)");
|
||||
return;
|
||||
case AST_VOLATILE_STMT:
|
||||
DUMP("(volatile");
|
||||
DUMPAST(ast->volatile_stmt);
|
||||
|
||||
@@ -76,6 +76,7 @@ typedef enum
|
||||
AST_RETURN_STMT,
|
||||
AST_SWITCH_STMT,
|
||||
AST_NEXT_STMT,
|
||||
AST_UNREACHABLE_STMT,
|
||||
AST_VOLATILE_STMT,
|
||||
AST_WHILE_STMT,
|
||||
AST_SCOPED_STMT,
|
||||
@@ -412,6 +413,7 @@ typedef enum
|
||||
TOKEN_TRY,
|
||||
TOKEN_TYPEDEF,
|
||||
TOKEN_UNION,
|
||||
TOKEN_CT_UNREACHABLE,
|
||||
TOKEN_UNTIL,
|
||||
TOKEN_VAR, // Reserved
|
||||
TOKEN_VOLATILE,
|
||||
|
||||
@@ -847,6 +847,17 @@ static inline void gencontext_emit_assert_stmt(GenContext *context, Ast *ast)
|
||||
gencontext_emit_assume(context, ast->assert_stmt.expr);
|
||||
}
|
||||
|
||||
static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
// TODO emit message
|
||||
gencontext_emit_call_intrinsic(context, trap_intrinsic_id, NULL, 0, NULL, 0);
|
||||
LLVMBuildUnreachable(context->builder);
|
||||
LLVMBasicBlockRef block = gencontext_create_free_block(context, "unreachable_block");
|
||||
context->current_block = NULL;
|
||||
context->current_block_is_target = false;
|
||||
gencontext_emit_block(context, block);
|
||||
}
|
||||
|
||||
void gencontext_emit_expr_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
if (ast->expr_stmt->failable)
|
||||
@@ -1003,13 +1014,15 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_CT_ELSE_STMT:
|
||||
case AST_CT_FOR_STMT:
|
||||
case AST_CT_SWITCH_STMT:
|
||||
case AST_CASE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
UNREACHABLE
|
||||
case AST_SWITCH_STMT:
|
||||
gencontext_emit_switch(context, ast);
|
||||
break;
|
||||
case AST_CASE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
TODO
|
||||
case AST_UNREACHABLE_STMT:
|
||||
gencontext_emit_unreachable_stmt(context, ast);
|
||||
break;
|
||||
case AST_VOLATILE_STMT:
|
||||
TODO
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "parser_internal.h"
|
||||
|
||||
|
||||
Ast *parse_unreachable_stmt(Context *context);
|
||||
|
||||
#pragma mark --- Internal functions
|
||||
|
||||
|
||||
@@ -913,6 +915,8 @@ Ast *parse_stmt(Context *context)
|
||||
return parse_ct_for_stmt(context);
|
||||
case TOKEN_VOLATILE:
|
||||
return parse_volatile_stmt(context);
|
||||
case TOKEN_CT_UNREACHABLE:
|
||||
return parse_unreachable_stmt(context);
|
||||
case TOKEN_STAR:
|
||||
case TOKEN_AMP:
|
||||
case TOKEN_INTEGER:
|
||||
@@ -1034,6 +1038,14 @@ Ast *parse_stmt(Context *context)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
Ast *parse_unreachable_stmt(Context *context)
|
||||
{
|
||||
Ast *ast = AST_NEW_TOKEN(AST_UNREACHABLE_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_CT_UNREACHABLE);
|
||||
TRY_CONSUME_EOS_OR(poisoned_ast);
|
||||
return ast;
|
||||
}
|
||||
|
||||
Ast *parse_jump_stmt_no_eos(Context *context)
|
||||
{
|
||||
switch (context->tok.type)
|
||||
|
||||
@@ -3395,6 +3395,8 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source)
|
||||
MACRO_COPY_EXPR(ast->try_stmt.decl_expr);
|
||||
MACRO_COPY_AST(ast->try_stmt.body);
|
||||
return ast;
|
||||
case AST_UNREACHABLE_STMT:
|
||||
return ast;
|
||||
case AST_VOLATILE_STMT:
|
||||
TODO
|
||||
return ast;
|
||||
|
||||
@@ -178,6 +178,12 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_unreachable_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
context->current_scope->jump_end = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_DECL_LIST);
|
||||
@@ -1286,6 +1292,11 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
|
||||
}
|
||||
if (context->current_scope->jump_end && !context->current_scope->allow_dead_code)
|
||||
{
|
||||
if (statement->ast_kind == AST_UNREACHABLE_STMT)
|
||||
{
|
||||
context->current_scope->allow_dead_code = true;
|
||||
return true;
|
||||
}
|
||||
//SEMA_ERROR(statement, "This code will never execute.");
|
||||
context->current_scope->allow_dead_code = true;
|
||||
//return false;
|
||||
@@ -1341,10 +1352,13 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
|
||||
return sema_analyse_switch_stmt(context, statement);
|
||||
case AST_NEXT_STMT:
|
||||
return sema_analyse_next_stmt(context, statement);
|
||||
case AST_UNREACHABLE_STMT:
|
||||
return sema_analyse_unreachable_stmt(context, statement);
|
||||
case AST_VOLATILE_STMT:
|
||||
return sema_analyse_volatile_stmt(context, statement);
|
||||
case AST_WHILE_STMT:
|
||||
return sema_analyse_while_stmt(context, statement);
|
||||
|
||||
case AST_CT_ELIF_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -344,6 +344,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$if";
|
||||
case TOKEN_CT_SWITCH:
|
||||
return "$switch";
|
||||
case TOKEN_CT_UNREACHABLE:
|
||||
return "$unreachable";
|
||||
case TOKEN_EOF:
|
||||
return "EOF";
|
||||
|
||||
|
||||
36
test/test_suite/assert/unreachable.c3t
Normal file
36
test/test_suite/assert/unreachable.c3t
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
public func int foo()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public func void test()
|
||||
{
|
||||
int x = foo();
|
||||
if (x > 0) return;
|
||||
$unreachable;
|
||||
x++;
|
||||
}
|
||||
|
||||
|
||||
// #expect: unreachable.ll
|
||||
|
||||
%x = alloca i32
|
||||
%0 = call i32 @unreachable.foo()
|
||||
store i32 %0, i32* %x
|
||||
%1 = load i32, i32* %x
|
||||
%gt = icmp sgt i32 %1, 0
|
||||
br i1 %gt, label %if.then, label %if.exit
|
||||
|
||||
if.then:
|
||||
ret void
|
||||
|
||||
if.exit:
|
||||
call void @llvm.trap()
|
||||
unreachable
|
||||
|
||||
unreachable_block:
|
||||
%2 = load i32, i32* %x
|
||||
%add = add nsw i32 %2, 1
|
||||
store i32 %add, i32* %x
|
||||
ret void
|
||||
Reference in New Issue
Block a user