mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
defer is broken when placed before a $foreach #1912
This commit is contained in:
@@ -19,6 +19,20 @@ struct List (Printable)
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
<*
|
||||
@param initial_capacity "The initial capacity to reserve"
|
||||
@param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
*>
|
||||
fn List* List.init(&self, usz initial_capacity = 16, Allocator allocator)
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.size = 0;
|
||||
self.capacity = 0;
|
||||
self.entries = null;
|
||||
self.reserve(initial_capacity);
|
||||
return self;
|
||||
}
|
||||
|
||||
<*
|
||||
@param initial_capacity "The initial capacity to reserve"
|
||||
@param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
@@ -40,7 +54,7 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = a
|
||||
*>
|
||||
fn List* List.temp_init(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
return self.init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
- Missing error when placing a single statement for-body on a new row #1892.
|
||||
- Fix bug where in dead code, only the first statement would be turned into a nop.
|
||||
- Remove unused $inline argument to mem::copy.
|
||||
- defer is broken when placed before a $foreach #1912.
|
||||
|
||||
### Stdlib changes
|
||||
- Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter.
|
||||
|
||||
@@ -3,10 +3,10 @@ import libc;
|
||||
import std::io;
|
||||
import std::collections::maybe;
|
||||
|
||||
def MaybeString = Maybe(<String>);
|
||||
def MaybeHead = Maybe(<Head>);
|
||||
def new_head_val = maybe::value(<Head>);
|
||||
def new_string_val = maybe::value(<String>);
|
||||
def MaybeString = Maybe<[String]>;
|
||||
def MaybeHead = Maybe<[Head]>;
|
||||
def new_head_val = maybe::value<[Head]>;
|
||||
def new_string_val = maybe::value<[String]>;
|
||||
|
||||
fault TitleResult
|
||||
{
|
||||
|
||||
@@ -342,6 +342,15 @@ bool ast_is_compile_time(Ast *ast)
|
||||
return expr_is_runtime_const(ast->return_stmt.expr);
|
||||
case AST_EXPR_STMT:
|
||||
return expr_is_runtime_const(ast->expr_stmt);
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
{
|
||||
AstId current = ast->ct_compound_stmt;
|
||||
while (current)
|
||||
{
|
||||
if (!ast_is_compile_time(ast_next(¤t))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case AST_COMPOUND_STMT:
|
||||
{
|
||||
AstId current = ast->compound_stmt.first_stmt;
|
||||
|
||||
@@ -821,6 +821,7 @@ static void c_emit_stmt(GenContext *c, Ast *stmt)
|
||||
break;
|
||||
case AST_CT_ECHO_STMT:
|
||||
break;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
break;
|
||||
case AST_CT_FOREACH_STMT:
|
||||
|
||||
@@ -1488,6 +1488,7 @@ typedef struct Ast_
|
||||
AstAssertStmt assert_stmt; // 16
|
||||
AstCaseStmt case_stmt; // 32
|
||||
AstCompoundStmt compound_stmt; // 12
|
||||
AstId ct_compound_stmt;
|
||||
AstContinueBreakStmt contbreak_stmt;// 24
|
||||
AstContractStmt contract_stmt; // 32
|
||||
AstDocFault contract_fault; // 24
|
||||
|
||||
@@ -697,6 +697,9 @@ RETRY:
|
||||
MACRO_COPY_EXPRID(ast->ct_switch_stmt.cond);
|
||||
MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body);
|
||||
break;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
MACRO_COPY_ASTID(ast->ct_compound_stmt);
|
||||
break;
|
||||
case AST_DECLARE_STMT:
|
||||
MACRO_COPY_DECL(ast->declare_stmt);
|
||||
break;
|
||||
|
||||
@@ -189,15 +189,19 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
AST_POISONED,
|
||||
AST_ASM_STMT,
|
||||
AST_ASM_BLOCK_STMT,
|
||||
AST_ASM_LABEL,
|
||||
AST_ASM_STMT,
|
||||
AST_ASSERT_STMT,
|
||||
AST_BLOCK_EXIT_STMT,
|
||||
AST_BREAK_STMT,
|
||||
AST_CASE_STMT,
|
||||
AST_COMPOUND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CONTRACT,
|
||||
AST_CONTRACT_FAULT,
|
||||
AST_CT_ASSERT,
|
||||
AST_CT_COMPOUND_STMT,
|
||||
AST_CT_ECHO_STMT,
|
||||
AST_CT_ELSE_STMT,
|
||||
AST_CT_FOREACH_STMT,
|
||||
@@ -209,17 +213,14 @@ typedef enum
|
||||
AST_DEFAULT_STMT,
|
||||
AST_DEFER_STMT,
|
||||
AST_EXPR_STMT,
|
||||
AST_FOR_STMT,
|
||||
AST_FOREACH_STMT,
|
||||
AST_FOR_STMT,
|
||||
AST_IF_CATCH_SWITCH_STMT,
|
||||
AST_IF_STMT,
|
||||
AST_NEXTCASE_STMT,
|
||||
AST_NOP_STMT,
|
||||
AST_RETURN_STMT,
|
||||
AST_BLOCK_EXIT_STMT,
|
||||
AST_SWITCH_STMT,
|
||||
AST_NEXTCASE_STMT,
|
||||
AST_CONTRACT,
|
||||
AST_CONTRACT_FAULT,
|
||||
} AstKind;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -29,6 +29,7 @@ void llvm_emit_compound_stmt(GenContext *c, Ast *ast)
|
||||
if (old_block) c->debug.block_stack = old_block;
|
||||
}
|
||||
|
||||
|
||||
void llvm_emit_local_static(GenContext *c, Decl *decl, BEValue *value)
|
||||
{
|
||||
// In defers we might already have generated this variable.
|
||||
@@ -1690,6 +1691,9 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
|
||||
case AST_BLOCK_EXIT_STMT:
|
||||
llvm_emit_block_exit_return(c, ast);
|
||||
break;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
llvm_emit_statement_chain(c, ast->ct_compound_stmt);
|
||||
break;
|
||||
case AST_COMPOUND_STMT:
|
||||
llvm_emit_compound_stmt(c, ast);
|
||||
break;
|
||||
|
||||
@@ -1100,9 +1100,9 @@ static inline Ast* parse_ct_foreach_stmt(ParseContext *c)
|
||||
TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected ':'.", poisoned_ast);
|
||||
ASSIGN_EXPRID_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, ast->span);
|
||||
Ast *body = new_ast(AST_CT_COMPOUND_STMT, ast->span);
|
||||
ast->ct_foreach_stmt.body = astid(body);
|
||||
AstId *current = &body->compound_stmt.first_stmt;
|
||||
AstId *current = &body->ct_compound_stmt;
|
||||
while (!try_consume(c, TOKEN_CT_ENDFOREACH))
|
||||
{
|
||||
ASSIGN_AST_OR_RET(Ast *stmt, parse_stmt(c), poisoned_ast);
|
||||
@@ -1140,9 +1140,9 @@ static inline Ast* parse_ct_for_stmt(ParseContext *c)
|
||||
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
|
||||
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, ast->span);
|
||||
Ast *body = new_ast(AST_CT_COMPOUND_STMT, ast->span);
|
||||
ast->for_stmt.body = astid(body);
|
||||
AstId *current = &body->compound_stmt.first_stmt;
|
||||
AstId *current = &body->ct_compound_stmt;
|
||||
while (!try_consume(c, TOKEN_CT_ENDFOR))
|
||||
{
|
||||
ASSIGN_AST_OR_RET(Ast *stmt, parse_stmt(c), poisoned_ast);
|
||||
|
||||
@@ -3763,6 +3763,78 @@ INLINE bool sema_analyse_macro_body(SemaContext *context, Decl **body_parameters
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_check_body_const(SemaContext *context, Ast *body)
|
||||
{
|
||||
while (body)
|
||||
{
|
||||
switch (body->ast_kind)
|
||||
{
|
||||
case AST_CT_ASSERT:
|
||||
case AST_CT_ECHO_STMT:
|
||||
case AST_CT_FOREACH_STMT:
|
||||
case AST_CT_FOR_STMT:
|
||||
case AST_CT_IF_STMT:
|
||||
case AST_CT_SWITCH_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
case AST_DECLARE_STMT:
|
||||
case AST_DECLS_STMT:
|
||||
case AST_NOP_STMT:
|
||||
body = astptrzero(body->next);
|
||||
continue;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
if (!sema_check_body_const(context, body)) return false;
|
||||
body = astptrzero(body->next);
|
||||
continue;
|
||||
case AST_RETURN_STMT:
|
||||
if (!body->return_stmt.expr) RETURN_SEMA_ERROR(body, "The 'return' in an `@const` must provide a value, e.g. 'return Foo.typeid;'");
|
||||
if (body->next) RETURN_SEMA_ERROR(body, "There should not be any statements after 'return'.");
|
||||
body = NULL;
|
||||
continue;
|
||||
case AST_EXPR_STMT:
|
||||
// For some cases we KNOW it's not correct.
|
||||
switch (body->expr_stmt->expr_kind)
|
||||
{
|
||||
case EXPR_IDENTIFIER:
|
||||
case EXPR_UNRESOLVED_IDENTIFIER:
|
||||
case EXPR_LAMBDA:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_ASM:
|
||||
case EXPR_EXPR_BLOCK:
|
||||
case EXPR_TERNARY:
|
||||
case EXPR_RETHROW:
|
||||
break;
|
||||
default:
|
||||
body = astptrzero(body->next);
|
||||
continue;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case AST_POISONED:
|
||||
case AST_ASM_STMT:
|
||||
case AST_ASM_LABEL:
|
||||
case AST_ASM_BLOCK_STMT:
|
||||
case AST_ASSERT_STMT:
|
||||
case AST_BREAK_STMT:
|
||||
case AST_CASE_STMT:
|
||||
case AST_COMPOUND_STMT:
|
||||
case AST_CONTINUE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
case AST_DEFER_STMT:
|
||||
case AST_FOR_STMT:
|
||||
case AST_FOREACH_STMT:
|
||||
case AST_IF_CATCH_SWITCH_STMT:
|
||||
case AST_IF_STMT:
|
||||
case AST_BLOCK_EXIT_STMT:
|
||||
case AST_SWITCH_STMT:
|
||||
case AST_NEXTCASE_STMT:
|
||||
case AST_CONTRACT:
|
||||
case AST_CONTRACT_FAULT:
|
||||
RETURN_SEMA_ERROR(body, "Only 'return' and compile time statements are allowed in an '@const' macro.");
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl)
|
||||
{
|
||||
decl->func_decl.unit = context->unit;
|
||||
@@ -3800,69 +3872,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
|
||||
ASSERT(body->ast_kind == AST_COMPOUND_STMT);
|
||||
body = astptrzero(body->compound_stmt.first_stmt);
|
||||
if (!body) RETURN_SEMA_ERROR(decl, "'@const' macros cannot have an empty body.");
|
||||
while (body)
|
||||
{
|
||||
switch (body->ast_kind)
|
||||
{
|
||||
case AST_CT_ASSERT:
|
||||
case AST_CT_ECHO_STMT:
|
||||
case AST_CT_FOREACH_STMT:
|
||||
case AST_CT_FOR_STMT:
|
||||
case AST_CT_IF_STMT:
|
||||
case AST_CT_SWITCH_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
case AST_DECLARE_STMT:
|
||||
case AST_DECLS_STMT:
|
||||
case AST_NOP_STMT:
|
||||
body = astptrzero(body->next);
|
||||
continue;
|
||||
case AST_RETURN_STMT:
|
||||
if (!body->return_stmt.expr) RETURN_SEMA_ERROR(body, "The 'return' in an `@const` must provide a value, e.g. 'return Foo.typeid;'");
|
||||
if (body->next) RETURN_SEMA_ERROR(body, "There should not be any statements after 'return'.");
|
||||
body = NULL;
|
||||
continue;
|
||||
case AST_EXPR_STMT:
|
||||
// For some cases we KNOW it's not correct.
|
||||
switch (body->expr_stmt->expr_kind)
|
||||
{
|
||||
case EXPR_IDENTIFIER:
|
||||
case EXPR_UNRESOLVED_IDENTIFIER:
|
||||
case EXPR_LAMBDA:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_ASM:
|
||||
case EXPR_EXPR_BLOCK:
|
||||
case EXPR_TERNARY:
|
||||
case EXPR_RETHROW:
|
||||
break;
|
||||
default:
|
||||
body = astptrzero(body->next);
|
||||
continue;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case AST_POISONED:
|
||||
case AST_ASM_STMT:
|
||||
case AST_ASM_LABEL:
|
||||
case AST_ASM_BLOCK_STMT:
|
||||
case AST_ASSERT_STMT:
|
||||
case AST_BREAK_STMT:
|
||||
case AST_CASE_STMT:
|
||||
case AST_COMPOUND_STMT:
|
||||
case AST_CONTINUE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
case AST_DEFER_STMT:
|
||||
case AST_FOR_STMT:
|
||||
case AST_FOREACH_STMT:
|
||||
case AST_IF_CATCH_SWITCH_STMT:
|
||||
case AST_IF_STMT:
|
||||
case AST_BLOCK_EXIT_STMT:
|
||||
case AST_SWITCH_STMT:
|
||||
case AST_NEXTCASE_STMT:
|
||||
case AST_CONTRACT:
|
||||
case AST_CONTRACT_FAULT:
|
||||
RETURN_SEMA_ERROR(body, "Only 'return' and compile time statements are allowed in an '@const' macro.");
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
sema_check_body_const(context, body);
|
||||
}
|
||||
decl->type = type_void;
|
||||
return true;
|
||||
|
||||
@@ -113,6 +113,9 @@ static void sema_trace_stmt_liveness(Ast *ast)
|
||||
case AST_NOP_STMT:
|
||||
case AST_ASM_LABEL:
|
||||
return;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
sema_trace_stmt_chain_liveness(ast->ct_compound_stmt);
|
||||
return;
|
||||
case AST_COMPOUND_STMT:
|
||||
sema_trace_stmt_chain_liveness(ast->compound_stmt.first_stmt);
|
||||
return;
|
||||
|
||||
@@ -232,6 +232,27 @@ static inline bool sema_analyse_compound_stmt(SemaContext *context, Ast *stateme
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ct compound statement
|
||||
*/
|
||||
static inline bool sema_analyse_ct_compound_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
if (!ast_ok(statement)) return false;
|
||||
AstId current = statement->ct_compound_stmt;
|
||||
Ast *ast = NULL;
|
||||
bool all_ok = true;
|
||||
while (current)
|
||||
{
|
||||
ast = ast_next(¤t);
|
||||
if (!sema_analyse_statement(context, ast))
|
||||
{
|
||||
ast_poison(ast);
|
||||
all_ok = false;
|
||||
}
|
||||
}
|
||||
return all_ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* continue and continue FOO;
|
||||
*/
|
||||
@@ -2824,13 +2845,20 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state
|
||||
index->var.init_expr = expr_new_const_int(index->span, type_int, i);
|
||||
index->type = type_int;
|
||||
}
|
||||
if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) goto FAILED;
|
||||
if (!sema_analyse_statement(context, compound_stmt)) goto FAILED;
|
||||
*current = astid(compound_stmt);
|
||||
current = &compound_stmt->next;
|
||||
}
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
statement->ast_kind = AST_COMPOUND_STMT;
|
||||
statement->compound_stmt = (AstCompoundStmt) { .first_stmt = start };
|
||||
if (!start)
|
||||
{
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
}
|
||||
else
|
||||
{
|
||||
statement->ast_kind = AST_CT_COMPOUND_STMT;
|
||||
statement->ct_compound_stmt = start;
|
||||
}
|
||||
return true;
|
||||
FAILED_NO_LIST:
|
||||
SEMA_ERROR(collection, "Expected a list to iterate over, but this was a non-list expression of type %s.",
|
||||
@@ -3046,7 +3074,7 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
Ast *compound_stmt = copy_ast_single(body);
|
||||
|
||||
// Analyse the body
|
||||
if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) goto FAILED;
|
||||
if (!sema_analyse_statement(context, compound_stmt)) goto FAILED;
|
||||
|
||||
// Append it.
|
||||
*current = astid(compound_stmt);
|
||||
@@ -3059,8 +3087,8 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
}
|
||||
}
|
||||
// Analysis is done turn the generated statements into a compound statement for lowering.
|
||||
statement->ast_kind = AST_COMPOUND_STMT;
|
||||
statement->compound_stmt = (AstCompoundStmt) { .first_stmt = start };
|
||||
statement->ast_kind = AST_CT_COMPOUND_STMT;
|
||||
statement->ct_compound_stmt = start;
|
||||
return true;
|
||||
FAILED:
|
||||
sema_context_pop_ct_stack(context, for_context);
|
||||
@@ -3091,6 +3119,8 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
|
||||
RETURN_SEMA_ERROR(statement, "Unexpected 'case' outside of switch");
|
||||
case AST_COMPOUND_STMT:
|
||||
return sema_analyse_compound_stmt(context, statement);
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
return sema_analyse_ct_compound_stmt(context, statement);
|
||||
case AST_CONTINUE_STMT:
|
||||
return sema_analyse_continue_stmt(context, statement);
|
||||
case AST_CT_ASSERT:
|
||||
|
||||
258
test/test_suite/compile_time/ct_forach_with_defer.c3t
Normal file
258
test/test_suite/compile_time/ct_forach_with_defer.c3t
Normal file
@@ -0,0 +1,258 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
// Issue #1912
|
||||
fn void test()
|
||||
{
|
||||
defer io::printn("World!");
|
||||
const HELLO = "Hello";
|
||||
$for (var $i = 0; $i < 5; $i++)
|
||||
io::printf("%c", HELLO[$i]);
|
||||
$endfor
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
defer io::printn("World!");
|
||||
|
||||
$foreach ($c : "Hello")
|
||||
io::printf("%c", $c);
|
||||
$endforeach
|
||||
io::printn();
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test.test() #0 {
|
||||
entry:
|
||||
%varargslots = alloca [1 x %any], align 16
|
||||
%taddr = alloca i8, align 1
|
||||
%retparam = alloca i64, align 8
|
||||
%varargslots1 = alloca [1 x %any], align 16
|
||||
%taddr2 = alloca i8, align 1
|
||||
%retparam3 = alloca i64, align 8
|
||||
%varargslots4 = alloca [1 x %any], align 16
|
||||
%taddr5 = alloca i8, align 1
|
||||
%retparam6 = alloca i64, align 8
|
||||
%varargslots7 = alloca [1 x %any], align 16
|
||||
%taddr8 = alloca i8, align 1
|
||||
%retparam9 = alloca i64, align 8
|
||||
%varargslots10 = alloca [1 x %any], align 16
|
||||
%taddr11 = alloca i8, align 1
|
||||
%retparam12 = alloca i64, align 8
|
||||
%len = alloca i64, align 8
|
||||
%error_var = alloca i64, align 8
|
||||
%retparam14 = alloca i64, align 8
|
||||
%error_var15 = alloca i64, align 8
|
||||
%error_var21 = alloca i64, align 8
|
||||
store i8 72, ptr %taddr, align 1
|
||||
%0 = insertvalue %any undef, ptr %taddr, 0
|
||||
%1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %1, ptr %varargslots, align 16
|
||||
%2 = call i64 @std.io.printf(ptr %retparam, ptr @.str.1, i64 2, ptr %varargslots, i64 1)
|
||||
store i8 101, ptr %taddr2, align 1
|
||||
%3 = insertvalue %any undef, ptr %taddr2, 0
|
||||
%4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %4, ptr %varargslots1, align 16
|
||||
%5 = call i64 @std.io.printf(ptr %retparam3, ptr @.str.2, i64 2, ptr %varargslots1, i64 1)
|
||||
store i8 108, ptr %taddr5, align 1
|
||||
%6 = insertvalue %any undef, ptr %taddr5, 0
|
||||
%7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %7, ptr %varargslots4, align 16
|
||||
%8 = call i64 @std.io.printf(ptr %retparam6, ptr @.str.3, i64 2, ptr %varargslots4, i64 1)
|
||||
store i8 108, ptr %taddr8, align 1
|
||||
%9 = insertvalue %any undef, ptr %taddr8, 0
|
||||
%10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %10, ptr %varargslots7, align 16
|
||||
%11 = call i64 @std.io.printf(ptr %retparam9, ptr @.str.4, i64 2, ptr %varargslots7, i64 1)
|
||||
store i8 111, ptr %taddr11, align 1
|
||||
%12 = insertvalue %any undef, ptr %taddr11, 0
|
||||
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %13, ptr %varargslots10, align 16
|
||||
%14 = call i64 @std.io.printf(ptr %retparam12, ptr @.str.5, i64 2, ptr %varargslots10, i64 1)
|
||||
%15 = call ptr @std.io.stdout()
|
||||
%16 = call i64 @std.io.File.write(ptr %retparam14, ptr %15, ptr @.str.6, i64 6)
|
||||
%not_err = icmp eq i64 %16, 0
|
||||
%17 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %17, label %after_check, label %assign_optional
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %16, ptr %error_var, align 8
|
||||
br label %guard_block
|
||||
after_check: ; preds = %entry
|
||||
br label %noerr_block
|
||||
guard_block: ; preds = %assign_optional
|
||||
br label %voiderr
|
||||
noerr_block: ; preds = %after_check
|
||||
%18 = load i64, ptr %retparam14, align 8
|
||||
store i64 %18, ptr %len, align 8
|
||||
%19 = call i64 @std.io.File.write_byte(ptr %15, i8 zeroext 10)
|
||||
%not_err16 = icmp eq i64 %19, 0
|
||||
%20 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
|
||||
br i1 %20, label %after_check18, label %assign_optional17
|
||||
assign_optional17: ; preds = %noerr_block
|
||||
store i64 %19, ptr %error_var15, align 8
|
||||
br label %guard_block19
|
||||
after_check18: ; preds = %noerr_block
|
||||
br label %noerr_block20
|
||||
guard_block19: ; preds = %assign_optional17
|
||||
br label %voiderr
|
||||
noerr_block20: ; preds = %after_check18
|
||||
%21 = call i64 @std.io.File.flush(ptr %15)
|
||||
%not_err22 = icmp eq i64 %21, 0
|
||||
%22 = call i1 @llvm.expect.i1(i1 %not_err22, i1 true)
|
||||
br i1 %22, label %after_check24, label %assign_optional23
|
||||
assign_optional23: ; preds = %noerr_block20
|
||||
store i64 %21, ptr %error_var21, align 8
|
||||
br label %guard_block25
|
||||
after_check24: ; preds = %noerr_block20
|
||||
br label %noerr_block26
|
||||
guard_block25: ; preds = %assign_optional23
|
||||
br label %voiderr
|
||||
noerr_block26: ; preds = %after_check24
|
||||
%23 = load i64, ptr %len, align 8
|
||||
%add = add i64 %23, 1
|
||||
br label %voiderr
|
||||
voiderr: ; preds = %noerr_block26, %guard_block25, %guard_block19, %guard_block
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%varargslots = alloca [1 x %any], align 16
|
||||
%taddr = alloca i8, align 1
|
||||
%retparam = alloca i64, align 8
|
||||
%varargslots1 = alloca [1 x %any], align 16
|
||||
%taddr2 = alloca i8, align 1
|
||||
%retparam3 = alloca i64, align 8
|
||||
%varargslots4 = alloca [1 x %any], align 16
|
||||
%taddr5 = alloca i8, align 1
|
||||
%retparam6 = alloca i64, align 8
|
||||
%varargslots7 = alloca [1 x %any], align 16
|
||||
%taddr8 = alloca i8, align 1
|
||||
%retparam9 = alloca i64, align 8
|
||||
%varargslots10 = alloca [1 x %any], align 16
|
||||
%taddr11 = alloca i8, align 1
|
||||
%retparam12 = alloca i64, align 8
|
||||
%len = alloca i64, align 8
|
||||
%error_var = alloca i64, align 8
|
||||
%retparam14 = alloca i64, align 8
|
||||
%error_var15 = alloca i64, align 8
|
||||
%error_var21 = alloca i64, align 8
|
||||
%len27 = alloca i64, align 8
|
||||
%error_var28 = alloca i64, align 8
|
||||
%retparam30 = alloca i64, align 8
|
||||
%error_var36 = alloca i64, align 8
|
||||
%error_var42 = alloca i64, align 8
|
||||
store i8 72, ptr %taddr, align 1
|
||||
%0 = insertvalue %any undef, ptr %taddr, 0
|
||||
%1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %1, ptr %varargslots, align 16
|
||||
%2 = call i64 @std.io.printf(ptr %retparam, ptr @.str.7, i64 2, ptr %varargslots, i64 1)
|
||||
store i8 101, ptr %taddr2, align 1
|
||||
%3 = insertvalue %any undef, ptr %taddr2, 0
|
||||
%4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %4, ptr %varargslots1, align 16
|
||||
%5 = call i64 @std.io.printf(ptr %retparam3, ptr @.str.8, i64 2, ptr %varargslots1, i64 1)
|
||||
store i8 108, ptr %taddr5, align 1
|
||||
%6 = insertvalue %any undef, ptr %taddr5, 0
|
||||
%7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %7, ptr %varargslots4, align 16
|
||||
%8 = call i64 @std.io.printf(ptr %retparam6, ptr @.str.9, i64 2, ptr %varargslots4, i64 1)
|
||||
store i8 108, ptr %taddr8, align 1
|
||||
%9 = insertvalue %any undef, ptr %taddr8, 0
|
||||
%10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %10, ptr %varargslots7, align 16
|
||||
%11 = call i64 @std.io.printf(ptr %retparam9, ptr @.str.10, i64 2, ptr %varargslots7, i64 1)
|
||||
store i8 111, ptr %taddr11, align 1
|
||||
%12 = insertvalue %any undef, ptr %taddr11, 0
|
||||
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
store %any %13, ptr %varargslots10, align 16
|
||||
%14 = call i64 @std.io.printf(ptr %retparam12, ptr @.str.11, i64 2, ptr %varargslots10, i64 1)
|
||||
%15 = call ptr @std.io.stdout()
|
||||
%16 = call i64 @std.io.File.write(ptr %retparam14, ptr %15, ptr null, i64 0)
|
||||
%not_err = icmp eq i64 %16, 0
|
||||
%17 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %17, label %after_check, label %assign_optional
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %16, ptr %error_var, align 8
|
||||
br label %guard_block
|
||||
after_check: ; preds = %entry
|
||||
br label %noerr_block
|
||||
guard_block: ; preds = %assign_optional
|
||||
br label %voiderr
|
||||
noerr_block: ; preds = %after_check
|
||||
%18 = load i64, ptr %retparam14, align 8
|
||||
store i64 %18, ptr %len, align 8
|
||||
%19 = call i64 @std.io.File.write_byte(ptr %15, i8 zeroext 10)
|
||||
%not_err16 = icmp eq i64 %19, 0
|
||||
%20 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
|
||||
br i1 %20, label %after_check18, label %assign_optional17
|
||||
assign_optional17: ; preds = %noerr_block
|
||||
store i64 %19, ptr %error_var15, align 8
|
||||
br label %guard_block19
|
||||
after_check18: ; preds = %noerr_block
|
||||
br label %noerr_block20
|
||||
guard_block19: ; preds = %assign_optional17
|
||||
br label %voiderr
|
||||
noerr_block20: ; preds = %after_check18
|
||||
%21 = call i64 @std.io.File.flush(ptr %15)
|
||||
%not_err22 = icmp eq i64 %21, 0
|
||||
%22 = call i1 @llvm.expect.i1(i1 %not_err22, i1 true)
|
||||
br i1 %22, label %after_check24, label %assign_optional23
|
||||
assign_optional23: ; preds = %noerr_block20
|
||||
store i64 %21, ptr %error_var21, align 8
|
||||
br label %guard_block25
|
||||
after_check24: ; preds = %noerr_block20
|
||||
br label %noerr_block26
|
||||
guard_block25: ; preds = %assign_optional23
|
||||
br label %voiderr
|
||||
noerr_block26: ; preds = %after_check24
|
||||
%23 = load i64, ptr %len, align 8
|
||||
%add = add i64 %23, 1
|
||||
br label %voiderr
|
||||
voiderr: ; preds = %noerr_block26, %guard_block25, %guard_block19, %guard_block
|
||||
%24 = call ptr @std.io.stdout()
|
||||
%25 = call i64 @std.io.File.write(ptr %retparam30, ptr %24, ptr @.str.12, i64 6)
|
||||
%not_err31 = icmp eq i64 %25, 0
|
||||
%26 = call i1 @llvm.expect.i1(i1 %not_err31, i1 true)
|
||||
br i1 %26, label %after_check33, label %assign_optional32
|
||||
assign_optional32: ; preds = %voiderr
|
||||
store i64 %25, ptr %error_var28, align 8
|
||||
br label %guard_block34
|
||||
after_check33: ; preds = %voiderr
|
||||
br label %noerr_block35
|
||||
guard_block34: ; preds = %assign_optional32
|
||||
br label %voiderr49
|
||||
noerr_block35: ; preds = %after_check33
|
||||
%27 = load i64, ptr %retparam30, align 8
|
||||
store i64 %27, ptr %len27, align 8
|
||||
%28 = call i64 @std.io.File.write_byte(ptr %24, i8 zeroext 10)
|
||||
%not_err37 = icmp eq i64 %28, 0
|
||||
%29 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true)
|
||||
br i1 %29, label %after_check39, label %assign_optional38
|
||||
assign_optional38: ; preds = %noerr_block35
|
||||
store i64 %28, ptr %error_var36, align 8
|
||||
br label %guard_block40
|
||||
after_check39: ; preds = %noerr_block35
|
||||
br label %noerr_block41
|
||||
guard_block40: ; preds = %assign_optional38
|
||||
br label %voiderr49
|
||||
noerr_block41: ; preds = %after_check39
|
||||
%30 = call i64 @std.io.File.flush(ptr %24)
|
||||
%not_err43 = icmp eq i64 %30, 0
|
||||
%31 = call i1 @llvm.expect.i1(i1 %not_err43, i1 true)
|
||||
br i1 %31, label %after_check45, label %assign_optional44
|
||||
assign_optional44: ; preds = %noerr_block41
|
||||
store i64 %30, ptr %error_var42, align 8
|
||||
br label %guard_block46
|
||||
after_check45: ; preds = %noerr_block41
|
||||
br label %noerr_block47
|
||||
guard_block46: ; preds = %assign_optional44
|
||||
br label %voiderr49
|
||||
noerr_block47: ; preds = %after_check45
|
||||
%32 = load i64, ptr %len27, align 8
|
||||
%add48 = add i64 %32, 1
|
||||
br label %voiderr49
|
||||
voiderr49: ; preds = %noerr_block47, %guard_block46, %guard_block40, %guard_block34
|
||||
ret void
|
||||
}
|
||||
@@ -16,15 +16,14 @@ fn void main() {
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
define void @test.foo() #0 !dbg !8 {
|
||||
entry:
|
||||
%values = alloca [1 x i32], align 4
|
||||
call void @llvm.dbg.declare(metadata ptr %values, metadata !12, metadata !DIExpression()), !dbg !17
|
||||
store i32 0, ptr %values, align 4, !dbg !17
|
||||
store i32 0, ptr %values, align 4, !dbg !18
|
||||
ret void, !dbg !18
|
||||
}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = !{i32 2, !"wchar_size", i32 4}
|
||||
@@ -43,21 +42,15 @@ entry:
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(count: 1, lowerBound: 0)
|
||||
!17 = !DILocation(line: 5, column: 10, scope: !8)
|
||||
!18 = !DILocation(line: 7, column: 18, scope: !19)
|
||||
!19 = distinct !DILexicalBlock(scope: !20, file: !7, line: 6, column: 3)
|
||||
!20 = distinct !DILexicalBlock(scope: !8, file: !7, line: 6, column: 3)
|
||||
!21 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !7, file: !7, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6)
|
||||
!22 = !DILocation(line: 12, column: 3, scope: !21)
|
||||
!23 = distinct !DISubprogram(name: "_$main", linkageName: "main", scope: !7, file: !7, line: 11, type: !24, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !11)
|
||||
!24 = !DISubroutineType(types: !25)
|
||||
!25 = !{!14, !14, !26}
|
||||
!26 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !27, size: 64, align: 64, dwarfAddressSpace: 0)
|
||||
!27 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !28, size: 64, align: 64, dwarfAddressSpace: 0)
|
||||
!28 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
|
||||
!29 = !DILocalVariable(name: ".anon", arg: 1, scope: !23, file: !7, line: 11, type: !14)
|
||||
!30 = !DILocation(line: 11, column: 9, scope: !23)
|
||||
!31 = !DILocalVariable(name: ".anon", arg: 2, scope: !23, file: !7, line: 11, type: !26)
|
||||
!32 = !DILocation(line: 18, column: 2, scope: !33, inlinedAt: !30)
|
||||
!33 = distinct !DISubprogram(name: "@main_to_void_main", linkageName: "@main_to_void_main", scope: !34, file: !34, line: 16, scopeLine: 16, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6)
|
||||
!34 = !DIFile(filename: "main_stub.c3"
|
||||
!35 = !DILocation(line: 19, column: 9, scope: !33, inlinedAt: !30)
|
||||
!18 = !DILocation(line: 7, column: 18, scope: !8)
|
||||
!19 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !7, file: !7, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6)
|
||||
!20 = !DILocation(line: 12, column: 3, scope: !19)
|
||||
!21 = distinct !DISubprogram(name: "_$main", linkageName: "main", scope: !7, file: !7, line: 11, type: !22, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !11)
|
||||
!22 = !DISubroutineType(types: !23)
|
||||
!23 = !{!14, !14, !24}
|
||||
!24 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !25, size: 64, align: 64, dwarfAddressSpace: 0)
|
||||
!25 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !26, size: 64, align: 64, dwarfAddressSpace: 0)
|
||||
!26 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
|
||||
!27 = !DILocalVariable(name: ".anon", arg: 1, scope: !21, file: !7, line: 11, type: !14)
|
||||
!28 = !DILocation(line: 11, column: 9, scope: !21)
|
||||
!29 = !DILocalVariable(name: ".anon", arg: 2, scope: !21, file: !7, line: 11, type: !24)
|
||||
|
||||
Reference in New Issue
Block a user