mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Removal of "or_else jump". Fixes to defer & macros/blocks, optimized failable return. @noscope macros removed. Disallow meaningless defer.
Correctly show error on return or rethrow inside of a defer. Fix copying an access expression. Removing scoped expr.
This commit is contained in:
committed by
Christoffer Lerno
parent
bbfc2fc8ab
commit
b31629c5e8
@@ -270,7 +270,6 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_COND:
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_DECL:
|
||||
case EXPR_OR_ERROR:
|
||||
case EXPR_EXPR_BLOCK:
|
||||
case EXPR_FAILABLE:
|
||||
case EXPR_RETHROW:
|
||||
@@ -281,7 +280,6 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_SCOPED_EXPR:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
@@ -330,7 +328,6 @@ bool expr_is_simple(Expr *expr)
|
||||
case EXPR_GROUP:
|
||||
expr = expr->inner_expr;
|
||||
goto RETRY;
|
||||
case EXPR_OR_ERROR:
|
||||
case EXPR_TERNARY:
|
||||
return false;
|
||||
case EXPR_RETHROW:
|
||||
@@ -401,6 +398,7 @@ BinaryOp binary_op[TOKEN_LAST + 1] = {
|
||||
[TOKEN_SHR] = BINARYOP_SHR,
|
||||
[TOKEN_AND] = BINARYOP_AND,
|
||||
[TOKEN_OR] = BINARYOP_OR,
|
||||
[TOKEN_QUESTQUEST] = BINARYOP_OR_ERR,
|
||||
[TOKEN_AMP] = BINARYOP_BIT_AND,
|
||||
[TOKEN_BIT_OR] = BINARYOP_BIT_OR,
|
||||
[TOKEN_BIT_XOR] = BINARYOP_BIT_XOR,
|
||||
|
||||
@@ -581,8 +581,6 @@ typedef struct Decl_
|
||||
bool is_packed : 1;
|
||||
bool is_substruct : 1;
|
||||
bool has_variable_array : 1;
|
||||
bool no_scope : 1;
|
||||
bool escaping : 1;
|
||||
bool is_value : 1;
|
||||
bool is_autoimport : 1;
|
||||
bool has_extname : 1;
|
||||
@@ -650,18 +648,6 @@ typedef struct Decl_
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_jump : 1;
|
||||
bool widen : 1;
|
||||
Expr *expr;
|
||||
union
|
||||
{
|
||||
Expr *or_error_expr;
|
||||
Ast *or_error_stmt;
|
||||
};
|
||||
} ExprOrError;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
@@ -826,11 +812,6 @@ typedef struct
|
||||
Ast *ast;
|
||||
} ExprBodyExpansion;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
AstId defer_stmts;
|
||||
} ExprScope;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -839,7 +820,6 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool no_scope;
|
||||
AstId first_stmt;
|
||||
Expr **args;
|
||||
Decl **params;
|
||||
@@ -956,7 +936,6 @@ struct Expr_
|
||||
ExprArgv argv_expr; // 16
|
||||
ExprGuard rethrow_expr; // 16
|
||||
Decl *decl_expr; // 8
|
||||
ExprOrError or_error_expr; // 24
|
||||
ExprSliceAssign slice_assign_expr; // 8
|
||||
ExprBinary binary_expr; // 12
|
||||
ExprTernary ternary_expr; // 16
|
||||
@@ -982,7 +961,6 @@ struct Expr_
|
||||
Expr** expression_list; // 8
|
||||
Expr** initializer_list; // 8
|
||||
Expr** designated_init_list; // 8
|
||||
ExprScope expr_scope; // 16
|
||||
ExprFuncBlock expr_block; // 4
|
||||
ExprMacroBlock macro_block; // 24
|
||||
Expr** cond_expr; // 8
|
||||
@@ -1425,7 +1403,6 @@ typedef struct SemaContext_
|
||||
Ast *yield_body;
|
||||
Type *expected_block_type;
|
||||
Ast **returns;
|
||||
bool expr_failable_return;
|
||||
// Reusable returns cache.
|
||||
Ast **returns_cache;
|
||||
};
|
||||
|
||||
@@ -237,17 +237,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_COND:
|
||||
MACRO_COPY_EXPR_LIST(expr->cond_expr);
|
||||
return expr;
|
||||
case EXPR_OR_ERROR:
|
||||
MACRO_COPY_EXPR(expr->or_error_expr.expr);
|
||||
if (expr->or_error_expr.is_jump)
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->or_error_expr.or_error_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_AST(expr->or_error_expr.or_error_stmt);
|
||||
}
|
||||
return expr;
|
||||
case EXPR_MACRO_BLOCK:
|
||||
UNREACHABLE
|
||||
case EXPR_COMPOUND_LITERAL:
|
||||
@@ -288,6 +277,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
MACRO_COPY_EXPRID(expr->call_expr.function);
|
||||
}
|
||||
MACRO_COPY_ASTID(expr->call_expr.body);
|
||||
@@ -302,6 +292,14 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_BITACCESS:
|
||||
case EXPR_ACCESS:
|
||||
MACRO_COPY_EXPR(expr->access_expr.parent);
|
||||
if (expr->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
fixup_decl(c, &expr->access_expr.ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->access_expr.child);
|
||||
}
|
||||
return expr;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
MACRO_COPY_EXPR_LIST(expr->initializer_list);
|
||||
@@ -316,11 +314,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
MACRO_COPY_EXPRID(expr->cast_expr.expr);
|
||||
MACRO_COPY_TYPEID(expr->cast_expr.type_info);
|
||||
return expr;
|
||||
case EXPR_SCOPED_EXPR:
|
||||
SCOPE_FIXUP_START
|
||||
MACRO_COPY_EXPR(expr->expr_scope.expr);
|
||||
SCOPE_FIXUP_END;
|
||||
return expr;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef enum
|
||||
BINARYOP_BIT_AND,
|
||||
BINARYOP_AND,
|
||||
BINARYOP_OR,
|
||||
BINARYOP_OR_ERR,
|
||||
// Don't change the ordering for GT to EQ or things will break
|
||||
BINARYOP_GT,
|
||||
BINARYOP_GE,
|
||||
@@ -189,7 +190,6 @@ typedef enum
|
||||
EXPR_COND,
|
||||
EXPR_DECL,
|
||||
EXPR_DESIGNATOR,
|
||||
EXPR_OR_ERROR,
|
||||
EXPR_EXPR_BLOCK,
|
||||
EXPR_EXPRESSION_LIST,
|
||||
EXPR_FAILABLE,
|
||||
@@ -207,7 +207,6 @@ typedef enum
|
||||
EXPR_LEN,
|
||||
EXPR_PTR,
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_SCOPED_EXPR,
|
||||
EXPR_SLICE,
|
||||
EXPR_SLICE_ASSIGN,
|
||||
EXPR_SUBSCRIPT,
|
||||
@@ -665,8 +664,6 @@ typedef enum
|
||||
ATTRIBUTE_UNUSED,
|
||||
ATTRIBUTE_USED,
|
||||
ATTRIBUTE_NAKED,
|
||||
ATTRIBUTE_NOSCOPE,
|
||||
ATTRIBUTE_ESCAPING,
|
||||
ATTRIBUTE_CDECL,
|
||||
ATTRIBUTE_STDCALL,
|
||||
ATTRIBUTE_VECCALL,
|
||||
|
||||
@@ -1083,17 +1083,6 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_
|
||||
gencontext_emit_member_addr(context, be_value, type_lowering(parent->type)->decl, member);
|
||||
}
|
||||
|
||||
static void llvm_emit_scoped_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
llvm_emit_expr(c, value, expr->expr_scope.expr);
|
||||
AstId current = expr->expr_scope.defer_stmts;
|
||||
while (current)
|
||||
{
|
||||
Ast *ast = astptr(current);
|
||||
llvm_emit_stmt(c, ast);
|
||||
current = ast->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void llvm_emit_initialize_reference(GenContext *c, BEValue *value, Expr *expr);
|
||||
@@ -3058,9 +3047,86 @@ void llvm_emit_comparison(GenContext *c, BEValue *be_value, BEValue *lhs, BEValu
|
||||
}
|
||||
TODO
|
||||
}
|
||||
|
||||
static void gencontext_emit_or_error(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
LLVMBasicBlockRef else_block = llvm_basic_block_new(c, "else_block");
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_block");
|
||||
|
||||
// Store catch/error var
|
||||
PUSH_ERROR();
|
||||
|
||||
// Set the catch/error var
|
||||
c->error_var = NULL;
|
||||
c->catch_block = else_block;
|
||||
|
||||
BEValue normal_value;
|
||||
llvm_emit_exprid(c, &normal_value, expr->binary_expr.left);
|
||||
llvm_value_rvalue(c, &normal_value);
|
||||
|
||||
// Restore.
|
||||
POP_ERROR();
|
||||
|
||||
// Emit success and jump to phi.
|
||||
LLVMBasicBlockRef success_end_block = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
if (success_end_block) llvm_emit_br(c, phi_block);
|
||||
|
||||
// Emit else
|
||||
llvm_emit_block(c, else_block);
|
||||
|
||||
BEValue else_value;
|
||||
llvm_emit_exprid(c, &else_value, expr->binary_expr.right);
|
||||
llvm_value_rvalue(c, &else_value);
|
||||
|
||||
LLVMBasicBlockRef else_block_exit = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
if (else_block_exit) llvm_emit_br(c, phi_block);
|
||||
|
||||
llvm_emit_block(c, phi_block);
|
||||
|
||||
if (!else_block_exit)
|
||||
{
|
||||
*be_value = normal_value;
|
||||
return;
|
||||
}
|
||||
if (!success_end_block)
|
||||
{
|
||||
*be_value = else_value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
{
|
||||
|
||||
}
|
||||
LLVMValueRef logic_values[2] = { normal_value.value, else_value.value };
|
||||
LLVMBasicBlockRef blocks[2] = { success_end_block, else_block_exit };
|
||||
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set_bool(be_value, phi);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set(be_value, phi, expr->type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_loaded, BinaryOp binary_op)
|
||||
{
|
||||
|
||||
if (binary_op == BINARYOP_OR_ERR)
|
||||
{
|
||||
gencontext_emit_or_error(c, be_value, expr);
|
||||
return;
|
||||
}
|
||||
if (binary_op == BINARYOP_AND || binary_op == BINARYOP_OR)
|
||||
{
|
||||
gencontext_emit_logical_and_or(c, be_value, expr, binary_op);
|
||||
@@ -3098,6 +3164,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
|
||||
switch (binary_op)
|
||||
{
|
||||
case BINARYOP_ERROR:
|
||||
case BINARYOP_OR_ERR:
|
||||
UNREACHABLE
|
||||
case BINARYOP_MULT:
|
||||
if (is_float)
|
||||
@@ -3439,113 +3506,7 @@ void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
llvm_value_set(value, phi, expr->type);
|
||||
}
|
||||
|
||||
static inline void gencontext_emit_else_jump_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
LLVMBasicBlockRef else_block = llvm_basic_block_new(c, "else_block");
|
||||
LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block");
|
||||
|
||||
// Store catch/error var
|
||||
PUSH_ERROR();
|
||||
|
||||
// Set the catch/error var
|
||||
c->error_var = NULL;
|
||||
c->catch_block = else_block;
|
||||
|
||||
|
||||
llvm_emit_expr(c, be_value, expr->or_error_expr.expr);
|
||||
llvm_value_rvalue(c, be_value);
|
||||
|
||||
// Restore.
|
||||
POP_ERROR();
|
||||
|
||||
// Emit success and to end.
|
||||
llvm_emit_br(c, no_err_block);
|
||||
|
||||
// Emit else
|
||||
llvm_emit_block(c, else_block);
|
||||
llvm_emit_stmt(c, expr->or_error_expr.or_error_stmt);
|
||||
llvm_emit_br(c, no_err_block);
|
||||
|
||||
llvm_emit_block(c, no_err_block);
|
||||
}
|
||||
|
||||
|
||||
static void gencontext_emit_or_error(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
if (expr->or_error_expr.is_jump)
|
||||
{
|
||||
gencontext_emit_else_jump_expr(c, be_value, expr);
|
||||
return;
|
||||
}
|
||||
LLVMBasicBlockRef else_block = llvm_basic_block_new(c, "else_block");
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_block");
|
||||
|
||||
// Store catch/error var
|
||||
PUSH_ERROR();
|
||||
|
||||
// Set the catch/error var
|
||||
c->error_var = NULL;
|
||||
c->catch_block = else_block;
|
||||
|
||||
BEValue normal_value;
|
||||
llvm_emit_expr(c, &normal_value, expr->or_error_expr.expr);
|
||||
llvm_value_rvalue(c, &normal_value);
|
||||
|
||||
// Restore.
|
||||
POP_ERROR();
|
||||
|
||||
// Emit success and jump to phi.
|
||||
LLVMBasicBlockRef success_end_block = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
if (success_end_block) llvm_emit_br(c, phi_block);
|
||||
|
||||
// Emit else
|
||||
llvm_emit_block(c, else_block);
|
||||
|
||||
BEValue else_value;
|
||||
llvm_emit_expr(c, &else_value, expr->or_error_expr.or_error_expr);
|
||||
llvm_value_rvalue(c, &else_value);
|
||||
|
||||
LLVMBasicBlockRef else_block_exit = llvm_get_current_block_if_in_use(c);
|
||||
|
||||
if (else_block_exit) llvm_emit_br(c, phi_block);
|
||||
|
||||
llvm_emit_block(c, phi_block);
|
||||
|
||||
if (!else_block_exit)
|
||||
{
|
||||
*be_value = normal_value;
|
||||
return;
|
||||
}
|
||||
if (!success_end_block)
|
||||
{
|
||||
*be_value = else_value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
{
|
||||
|
||||
}
|
||||
LLVMValueRef logic_values[2] = { normal_value.value, else_value.value };
|
||||
LLVMBasicBlockRef blocks[2] = { success_end_block, else_block_exit };
|
||||
|
||||
|
||||
if (expr->type->type_kind == TYPE_BOOL)
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set_bool(be_value, phi);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
llvm_value_set(be_value, phi, expr->type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the foo? instruction.
|
||||
@@ -5036,7 +4997,7 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
LLVMValueRef error_out = context->error_var;
|
||||
LLVMBasicBlockRef error_block = context->catch_block;
|
||||
|
||||
if (type_lowered != type_void)
|
||||
if (type_no_fail(type_lowered) != type_void)
|
||||
{
|
||||
return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
|
||||
}
|
||||
@@ -5095,7 +5056,6 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
||||
if (llvm_basic_block_is_unused(expr_block))
|
||||
{
|
||||
// Skip the expr block.
|
||||
assert(!context->return_out);
|
||||
llvm_value_set(be_value, NULL, type_void);
|
||||
goto DONE;
|
||||
}
|
||||
@@ -5169,16 +5129,6 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
||||
llvm_emit_expr(context, &value, expr->macro_block.args[i]);
|
||||
llvm_store_decl_raw(context, decl, llvm_load_value_store(context, &value));
|
||||
}
|
||||
if (expr->macro_block.no_scope)
|
||||
{
|
||||
AstId current = expr->macro_block.first_stmt;
|
||||
while (current)
|
||||
{
|
||||
llvm_emit_stmt(context, ast_next(¤t));
|
||||
}
|
||||
llvm_value_set(be_value, NULL, type_void);
|
||||
return;
|
||||
}
|
||||
llvm_emit_return_block(context, be_value, expr->type, expr->macro_block.first_stmt);
|
||||
}
|
||||
|
||||
@@ -5595,9 +5545,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
case EXPR_NOP:
|
||||
llvm_value_set(value, NULL, type_void);
|
||||
return;
|
||||
case EXPR_OR_ERROR:
|
||||
gencontext_emit_or_error(c, value, expr);
|
||||
return;
|
||||
case EXPR_MACRO_BLOCK:
|
||||
llvm_emit_macro_block(c, value, expr);
|
||||
return;
|
||||
@@ -5610,9 +5557,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
case EXPR_EXPR_BLOCK:
|
||||
llvm_emit_expr_block(c, value, expr);
|
||||
return;
|
||||
case EXPR_SCOPED_EXPR:
|
||||
llvm_emit_scoped_expr(c, value, expr);
|
||||
return;
|
||||
case EXPR_UNARY:
|
||||
gencontext_emit_unary_expr(c, value, expr);
|
||||
return;
|
||||
|
||||
@@ -152,6 +152,16 @@ static inline void llvm_emit_return(GenContext *c, Ast *ast)
|
||||
|
||||
PUSH_ERROR();
|
||||
|
||||
Expr *expr = ast->return_stmt.expr;
|
||||
if (expr && expr->expr_kind == EXPR_FAILABLE)
|
||||
{
|
||||
BEValue be_value;
|
||||
llvm_emit_expr(c, &be_value, expr->inner_expr);
|
||||
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
||||
llvm_emit_return_abi(c, NULL, &be_value);
|
||||
return;
|
||||
}
|
||||
|
||||
LLVMBasicBlockRef error_return_block = NULL;
|
||||
LLVMValueRef error_out = NULL;
|
||||
if (type_is_failable(c->cur_func_decl->type->func.prototype->rtype))
|
||||
@@ -208,10 +218,18 @@ static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast)
|
||||
c->error_var = c->block_error_var;
|
||||
c->catch_block = c->block_failable_exit;
|
||||
|
||||
bool has_return_value = ast->return_stmt.expr != NULL;
|
||||
LLVMBasicBlockRef err_cleanup_block = NULL;
|
||||
Expr *ret_expr = ast->return_stmt.expr;
|
||||
|
||||
BEValue return_value = { 0 };
|
||||
if (has_return_value)
|
||||
if (ret_expr)
|
||||
{
|
||||
if (ast->return_stmt.cleanup && IS_FAILABLE(ret_expr))
|
||||
{
|
||||
assert(c->catch_block);
|
||||
err_cleanup_block = llvm_basic_block_new(c, "opt_block_cleanup");
|
||||
c->catch_block = err_cleanup_block;
|
||||
}
|
||||
llvm_emit_expr(c, &return_value, ast->return_stmt.expr);
|
||||
llvm_value_fold_failable(c, &return_value);
|
||||
}
|
||||
@@ -219,12 +237,22 @@ static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast)
|
||||
POP_ERROR();
|
||||
|
||||
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
||||
|
||||
if (c->return_out)
|
||||
if (c->return_out && return_value.value)
|
||||
{
|
||||
llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type));
|
||||
}
|
||||
llvm_emit_jmp(c, c->block_return_exit);
|
||||
|
||||
if (err_cleanup_block)
|
||||
{
|
||||
llvm_emit_br(c, c->block_return_exit);
|
||||
llvm_emit_block(c, err_cleanup_block);
|
||||
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
||||
llvm_emit_jmp(c, c->block_failable_exit);
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm_emit_jmp(c, c->block_return_exit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,19 +27,9 @@ inline Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, P
|
||||
{
|
||||
TokenType tok = c->tok;
|
||||
Precedence token_precedence = rules[tok].precedence;
|
||||
bool special_question = false;
|
||||
if (tok == TOKEN_QUESTION)
|
||||
{
|
||||
ParseRule rule = rules[peek(c)];
|
||||
if (!rule.prefix)
|
||||
{
|
||||
token_precedence = PREC_CALL;
|
||||
special_question = true;
|
||||
}
|
||||
}
|
||||
if (precedence > token_precedence) break;
|
||||
if (!expr_ok(left_side)) return left_side;
|
||||
ParseFn infix_rule = special_question ? &parse_rethrow_expr : rules[tok].infix;
|
||||
ParseFn infix_rule = rules[tok].infix;
|
||||
if (!infix_rule)
|
||||
{
|
||||
SEMA_ERROR_HERE("An expression was expected.");
|
||||
@@ -521,6 +511,13 @@ static Expr *parse_ternary_expr(ParseContext *c, Expr *left_side)
|
||||
else
|
||||
{
|
||||
advance_and_verify(c, TOKEN_QUESTION);
|
||||
if (!rules[c->tok].prefix)
|
||||
{
|
||||
expr_ternary->expr_kind = EXPR_RETHROW;
|
||||
expr_ternary->rethrow_expr.inner = left_side;
|
||||
RANGE_EXTEND_PREV(expr_ternary);
|
||||
return expr_ternary;
|
||||
}
|
||||
ASSIGN_EXPR_OR_RET(Expr * true_expr, parse_precedence(c, PREC_TERNARY + 1), poisoned_expr);
|
||||
expr_ternary->ternary_expr.then_expr = exprid(true_expr);
|
||||
CONSUME_OR_RET(TOKEN_COLON, poisoned_expr);
|
||||
@@ -1072,14 +1069,6 @@ static Expr *parse_try_expr(ParseContext *c, Expr *left)
|
||||
return try_expr;
|
||||
}
|
||||
|
||||
static Expr *parse_rethrow_expr(ParseContext *c, Expr *left)
|
||||
{
|
||||
Expr *rethrow_expr = EXPR_NEW_EXPR(EXPR_RETHROW, left);
|
||||
advance(c);
|
||||
rethrow_expr->rethrow_expr.inner = left;
|
||||
RANGE_EXTEND_PREV(rethrow_expr);
|
||||
return rethrow_expr;
|
||||
}
|
||||
|
||||
static Expr *parse_force_unwrap_expr(ParseContext *c, Expr *left)
|
||||
{
|
||||
@@ -1090,36 +1079,6 @@ static Expr *parse_force_unwrap_expr(ParseContext *c, Expr *left)
|
||||
return force_unwrap_expr;
|
||||
}
|
||||
|
||||
static Expr *parse_or_error_expr(ParseContext *c, Expr *left)
|
||||
{
|
||||
Expr *else_expr = EXPR_NEW_TOKEN(EXPR_OR_ERROR);
|
||||
advance_and_verify(c, TOKEN_QUESTQUEST);
|
||||
else_expr->or_error_expr.expr = left;
|
||||
switch (c->tok)
|
||||
{
|
||||
case TOKEN_RETURN:
|
||||
case TOKEN_BREAK:
|
||||
case TOKEN_CONTINUE:
|
||||
case TOKEN_NEXTCASE:
|
||||
{
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_jump_stmt_no_eos(c), poisoned_expr);
|
||||
else_expr->or_error_expr.is_jump = true;
|
||||
else_expr->or_error_expr.or_error_stmt = ast;
|
||||
if (!tok_is(c, TOKEN_EOS))
|
||||
{
|
||||
SEMA_ERROR(ast, "An else jump statement must end with a ';'");
|
||||
return poisoned_expr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(else_expr->or_error_expr.or_error_expr, parse_precedence(c, PREC_ASSIGNMENT), poisoned_expr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return else_expr;
|
||||
}
|
||||
|
||||
static Expr *parse_builtin(ParseContext *c, Expr *left)
|
||||
{
|
||||
@@ -1757,7 +1716,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_VARIANT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||
|
||||
[TOKEN_QUESTION] = { NULL, parse_ternary_expr, PREC_TERNARY },
|
||||
[TOKEN_QUESTQUEST] = { NULL, parse_or_error_expr, PREC_TERNARY},
|
||||
[TOKEN_QUESTQUEST] = { NULL, parse_binary, PREC_TERNARY},
|
||||
[TOKEN_ELVIS] = { NULL, parse_ternary_expr, PREC_TERNARY },
|
||||
[TOKEN_PLUSPLUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },
|
||||
[TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },
|
||||
|
||||
@@ -703,6 +703,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case BINARYOP_ADD:
|
||||
case BINARYOP_DIV:
|
||||
case BINARYOP_MOD:
|
||||
case BINARYOP_OR_ERR:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_float(exprptr(expr->binary_expr.left), type);
|
||||
if (res) return res;
|
||||
@@ -757,13 +758,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case EXPR_RETVAL:
|
||||
if (type_size(expr->type) > type_size(type)) return expr;
|
||||
return NULL;
|
||||
case EXPR_OR_ERROR:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_float(expr->or_error_expr.expr, type);
|
||||
if (res) return res;
|
||||
if (expr->or_error_expr.is_jump) return NULL;
|
||||
return recursive_may_narrow_float(expr->or_error_expr.or_error_expr, type);
|
||||
}
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
return recursive_may_narrow_float(VECLAST(expr->expression_list), type);
|
||||
case EXPR_GROUP:
|
||||
@@ -820,8 +814,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_float(expr->unary_expr.expr, type);
|
||||
case EXPR_SCOPED_EXPR:
|
||||
return recursive_may_narrow_float(expr->expr_scope.expr, type);
|
||||
case EXPR_TRY:
|
||||
return recursive_may_narrow_float(expr->inner_expr, type);
|
||||
case EXPR_UNARY:
|
||||
@@ -869,6 +861,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case BINARYOP_BIT_OR:
|
||||
case BINARYOP_BIT_XOR:
|
||||
case BINARYOP_BIT_AND:
|
||||
case BINARYOP_OR_ERR:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_int(exprptr(expr->binary_expr.left), type);
|
||||
if (res) return res;
|
||||
@@ -923,13 +916,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case EXPR_LEN:
|
||||
if (type_size(type) < type_size(type_cint)) return expr;
|
||||
return NULL;
|
||||
case EXPR_OR_ERROR:
|
||||
{
|
||||
Expr *res = recursive_may_narrow_int(expr->or_error_expr.expr, type);
|
||||
if (res) return res;
|
||||
if (expr->or_error_expr.is_jump) return NULL;
|
||||
return recursive_may_narrow_int(expr->or_error_expr.or_error_expr, type);
|
||||
}
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
return recursive_may_narrow_int(VECLAST(expr->expression_list), type);
|
||||
case EXPR_RETHROW:
|
||||
@@ -981,8 +967,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_int(expr->unary_expr.expr, type);
|
||||
case EXPR_SCOPED_EXPR:
|
||||
return recursive_may_narrow_int(expr->expr_scope.expr, type);
|
||||
case EXPR_TRY:
|
||||
case EXPR_CATCH:
|
||||
case EXPR_GROUP:
|
||||
|
||||
@@ -1183,8 +1183,6 @@ AttributeType sema_analyse_attribute(SemaContext *context, Attr *attr, Attribute
|
||||
[ATTRIBUTE_REGCALL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_FASTCALL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT,
|
||||
[ATTRIBUTE_NOSCOPE] = ATTR_MACRO,
|
||||
[ATTRIBUTE_ESCAPING] = ATTR_MACRO,
|
||||
[ATTRIBUTE_AUTOIMPORT] = ATTR_MACRO | ATTR_FUNC,
|
||||
[ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC,
|
||||
};
|
||||
@@ -1683,14 +1681,6 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
had = decl->operator > 0;
|
||||
decl->operator = attr->operator;
|
||||
break;
|
||||
case ATTRIBUTE_NOSCOPE:
|
||||
had = decl->no_scope;
|
||||
decl->no_scope = true;
|
||||
break;
|
||||
case ATTRIBUTE_ESCAPING:
|
||||
had = decl->escaping;
|
||||
decl->escaping = true;
|
||||
break;
|
||||
case ATTRIBUTE_AUTOIMPORT:
|
||||
decl->is_autoimport = true;
|
||||
break;
|
||||
|
||||
@@ -338,10 +338,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_DESIGNATOR:
|
||||
expr = expr->designator_expr.value;
|
||||
goto RETRY;
|
||||
case EXPR_OR_ERROR:
|
||||
if (expr->or_error_expr.is_jump) return false;
|
||||
assert(!expr_is_constant_eval(expr->or_error_expr.expr, eval_kind));
|
||||
return false;
|
||||
case EXPR_EXPR_BLOCK:
|
||||
case EXPR_DECL:
|
||||
case EXPR_CALL:
|
||||
@@ -350,7 +346,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_SCOPED_EXPR:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_MACRO_BLOCK:
|
||||
case EXPR_RETHROW:
|
||||
@@ -1655,10 +1650,17 @@ static inline Type *unify_returns(SemaContext *context)
|
||||
bool all_returns_need_casts = false;
|
||||
Type *common_type = NULL;
|
||||
|
||||
bool only_has_rethrow = true;
|
||||
// 1. Loop through the returns.
|
||||
VECEACH(context->returns, i)
|
||||
{
|
||||
Ast *return_stmt = context->returns[i];
|
||||
if (!return_stmt)
|
||||
{
|
||||
common_type = common_type ? type_find_max_type(common_type, type_anyfail) : type_anyfail;
|
||||
continue;
|
||||
}
|
||||
only_has_rethrow = false;
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
Type *rtype = ret_expr ? ret_expr->type : type_void;
|
||||
|
||||
@@ -1689,12 +1691,16 @@ static inline Type *unify_returns(SemaContext *context)
|
||||
all_returns_need_casts = true;
|
||||
}
|
||||
|
||||
// If we have no return and only rethrows, then the type is "void!"
|
||||
if (common_type == type_anyfail && only_has_rethrow) common_type = type_get_failable(type_void);
|
||||
|
||||
// 7. Insert casts.
|
||||
if (all_returns_need_casts)
|
||||
{
|
||||
VECEACH(context->returns, i)
|
||||
{
|
||||
Ast *return_stmt = context->returns[i];
|
||||
if (!return_stmt) continue;
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
// 8. All casts should work.
|
||||
if (!cast_implicit(ret_expr, type_no_fail(common_type)))
|
||||
@@ -1826,34 +1832,22 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
|
||||
Ast *body = ast_macro_copy(astptr(decl->macro_decl.body));
|
||||
|
||||
bool no_scope = decl->no_scope;
|
||||
bool escaping = decl->escaping;
|
||||
|
||||
DynamicScope old_scope = context->active_scope;
|
||||
if (!no_scope)
|
||||
{
|
||||
context_change_scope_with_flags(context, SCOPE_NONE);
|
||||
}
|
||||
context_change_scope_with_flags(context, SCOPE_NONE);
|
||||
|
||||
SemaContext macro_context;
|
||||
|
||||
Type *rtype = NULL;
|
||||
if (no_scope)
|
||||
{
|
||||
sema_context_init(¯o_context, decl->macro_decl.unit);
|
||||
macro_context.compilation_unit = context->unit;
|
||||
macro_context.current_function = context->current_function;
|
||||
rtype = decl->macro_decl.rtype ? type_infoptr(decl->macro_decl.rtype)->type : NULL;
|
||||
macro_context.expected_block_type = rtype;
|
||||
|
||||
context_change_scope_with_flags(¯o_context, SCOPE_MACRO);
|
||||
|
||||
macro_context.block_return_defer = macro_context.active_scope.defer_last;
|
||||
|
||||
macro_context = *context;
|
||||
macro_context.unit = decl->macro_decl.unit;
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_context_init(¯o_context, decl->macro_decl.unit);
|
||||
macro_context.compilation_unit = context->unit;
|
||||
macro_context.current_function = context->current_function;
|
||||
rtype = decl->macro_decl.rtype ? type_infoptr(decl->macro_decl.rtype)->type : NULL;
|
||||
macro_context.expected_block_type = rtype;
|
||||
context_change_scope_with_flags(¯o_context, SCOPE_MACRO);
|
||||
macro_context.block_return_defer = macro_context.active_scope.defer_last;
|
||||
}
|
||||
macro_context.current_macro = decl;
|
||||
AstId body_id = call_expr->call_expr.body;
|
||||
macro_context.yield_body = body_id ? astptr(body_id) : NULL;
|
||||
@@ -1875,68 +1869,62 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
|
||||
bool is_no_return = decl->macro_decl.attr_noreturn;
|
||||
|
||||
if (no_scope)
|
||||
if (!vec_size(macro_context.returns))
|
||||
{
|
||||
call_expr->type = type_void;
|
||||
if (rtype && type_no_fail(rtype) != type_void)
|
||||
{
|
||||
SEMA_ERROR(decl,
|
||||
"Missing return in macro that should evaluate to %s.",
|
||||
type_quoted_error_string(rtype));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
}
|
||||
else if (is_no_return)
|
||||
{
|
||||
SEMA_ERROR(context->returns[0], "Return used despite macro being marked '@noreturn'.");
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
|
||||
if (rtype)
|
||||
{
|
||||
VECEACH(macro_context.returns, i)
|
||||
{
|
||||
Ast *return_stmt = macro_context.returns[i];
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
if (!ret_expr)
|
||||
{
|
||||
if (rtype == type_void) continue;
|
||||
SEMA_ERROR(return_stmt, "Expected returning a value of type %s.", type_quoted_error_string(rtype));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
Type *type = ret_expr->type;
|
||||
if (!cast_may_implicit(type, rtype, true, true))
|
||||
{
|
||||
SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype),
|
||||
type_quoted_error_string(type));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
bool success = cast_implicit(ret_expr, rtype);
|
||||
assert(success);
|
||||
}
|
||||
call_expr->type = type_get_opt_fail(rtype, failable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vec_size(macro_context.returns))
|
||||
Type *sum_returns = unify_returns(¯o_context);
|
||||
if (!sum_returns) return SCOPE_POP_ERROR();
|
||||
call_expr->type = type_get_opt_fail(sum_returns, failable);
|
||||
}
|
||||
if (vec_size(macro_context.returns) == 1)
|
||||
{
|
||||
Ast *ret = macro_context.returns[0];
|
||||
Expr *result = ret ? ret->return_stmt.expr : NULL;
|
||||
if (result && expr_is_constant_eval(result, CONSTANT_EVAL_ANY))
|
||||
{
|
||||
if (rtype && type_no_fail(rtype) != type_void)
|
||||
if (sema_check_stmt_compile_time(¯o_context, body))
|
||||
{
|
||||
SEMA_ERROR(decl,
|
||||
"Missing return in macro that should evaluate to %s.",
|
||||
type_quoted_error_string(rtype));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
}
|
||||
else if (is_no_return)
|
||||
{
|
||||
SEMA_ERROR(context->returns[0], "Return used despite macro being marked '@noreturn'.");
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
|
||||
if (rtype)
|
||||
{
|
||||
VECEACH(macro_context.returns, i)
|
||||
{
|
||||
Ast *return_stmt = macro_context.returns[i];
|
||||
Expr *ret_expr = return_stmt->return_stmt.expr;
|
||||
if (!ret_expr)
|
||||
{
|
||||
if (rtype == type_void) continue;
|
||||
SEMA_ERROR(return_stmt, "Expected returning a value of type %s.", type_quoted_error_string(rtype));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
Type *type = ret_expr->type;
|
||||
if (!cast_may_implicit(type, rtype, true, true))
|
||||
{
|
||||
SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype),
|
||||
type_quoted_error_string(type));
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
bool success = cast_implicit(ret_expr, rtype);
|
||||
assert(success);
|
||||
}
|
||||
call_expr->type = type_get_opt_fail(rtype, failable);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type *sum_returns = unify_returns(¯o_context);
|
||||
if (!sum_returns) return SCOPE_POP_ERROR();
|
||||
call_expr->type = type_get_opt_fail(sum_returns, failable);
|
||||
}
|
||||
if (vec_size(macro_context.returns) == 1)
|
||||
{
|
||||
Expr *result = macro_context.returns[0]->return_stmt.expr;
|
||||
if (result && expr_is_constant_eval(result, CONSTANT_EVAL_ANY))
|
||||
{
|
||||
if (sema_check_stmt_compile_time(¯o_context, body))
|
||||
{
|
||||
expr_replace(call_expr, result);
|
||||
goto EXIT;
|
||||
}
|
||||
expr_replace(call_expr, result);
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1945,20 +1933,9 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
call_expr->macro_block.first_stmt = body->compound_stmt.first_stmt;
|
||||
call_expr->macro_block.params = params;
|
||||
call_expr->macro_block.args = args;
|
||||
call_expr->macro_block.no_scope = no_scope;
|
||||
EXIT:
|
||||
if (no_scope)
|
||||
{
|
||||
context->active_scope.jump_end = macro_context.active_scope.jump_end;
|
||||
context->active_scope.defer_last = macro_context.active_scope.defer_last;
|
||||
context->active_scope.defer_start = macro_context.active_scope.defer_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_pop_defers_and_replace_expr(¯o_context, call_expr);
|
||||
assert(context->active_scope.defer_last == context->active_scope.defer_start);
|
||||
context->active_scope = old_scope;
|
||||
}
|
||||
assert(context->active_scope.defer_last == context->active_scope.defer_start);
|
||||
context->active_scope = old_scope;
|
||||
if (is_no_return) context->active_scope.jump_end = true;
|
||||
return true;
|
||||
EXIT_FAIL:
|
||||
@@ -5848,8 +5825,63 @@ static inline bool sema_expr_analyse_bitassign(SemaContext *context, Expr *expr)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
|
||||
{
|
||||
Expr *lhs = exprptr(expr->binary_expr.left);
|
||||
Expr *rhs = exprptr(expr->binary_expr.right);
|
||||
if (lhs->expr_kind == EXPR_TERNARY || rhs->expr_kind == EXPR_TERNARY)
|
||||
{
|
||||
SEMA_ERROR(expr, "Unclear precedence using ternary with ??, please use () to remove ambiguity.");
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr(context, lhs)) return false;
|
||||
|
||||
if (expr->binary_expr.widen && !sema_widen_top_down(lhs, expr->type)) return false;
|
||||
|
||||
Type *type = lhs->type;
|
||||
if (!type_is_failable(type))
|
||||
{
|
||||
SEMA_ERROR(lhs, "No failable to use '\?\?' with, please remove the '\?\?'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// First we analyse the "else" and try to implictly cast.
|
||||
if (!sema_analyse_expr(context, rhs)) return false;
|
||||
if (expr->binary_expr.widen && !sema_widen_top_down(rhs, expr->type)) return false;
|
||||
|
||||
|
||||
// Here we might need to insert casts.
|
||||
Type *else_type = rhs->type;
|
||||
|
||||
type = type_is_failable_any(type) ? else_type : type->failable;
|
||||
|
||||
if (else_type->type_kind == TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(rhs, "The default value may not be a failable.");
|
||||
return false;
|
||||
}
|
||||
Type *common = type_find_max_type(type, else_type);
|
||||
if (!common)
|
||||
{
|
||||
SEMA_ERROR(rhs, "Cannot find a common type for %s and %s.", type_quoted_error_string(type),
|
||||
type_quoted_error_string(else_type));
|
||||
return false;
|
||||
}
|
||||
if (!cast_implicit(lhs, common)) return false;
|
||||
if (!cast_implicit(rhs, common)) return false;
|
||||
if (IS_FAILABLE(rhs))
|
||||
{
|
||||
SEMA_ERROR(rhs, "The expression must be a non-failable.");
|
||||
return false;
|
||||
}
|
||||
expr->type = common;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr)
|
||||
{
|
||||
if (expr->binary_expr.operator == BINARYOP_OR_ERR) return sema_expr_analyse_or_error(context, expr);
|
||||
assert(expr->resolve_status == RESOLVE_RUNNING);
|
||||
Expr *left = exprptr(expr->binary_expr.left);
|
||||
Expr *right = exprptr(expr->binary_expr.right);
|
||||
@@ -5861,6 +5893,8 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr)
|
||||
}
|
||||
switch (expr->binary_expr.operator)
|
||||
{
|
||||
case BINARYOP_OR_ERR:
|
||||
UNREACHABLE // Handled previously
|
||||
case BINARYOP_ASSIGN:
|
||||
return sema_expr_analyse_assign(context, expr, left, right);
|
||||
case BINARYOP_MULT:
|
||||
@@ -5973,69 +6007,21 @@ static inline bool sema_expr_analyse_catch(SemaContext *context, Expr *expr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
|
||||
{
|
||||
Expr *inner = expr->or_error_expr.expr;
|
||||
if (inner->expr_kind == EXPR_TERNARY || expr->or_error_expr.or_error_expr->expr_kind == EXPR_TERNARY)
|
||||
{
|
||||
SEMA_ERROR(expr, "Unclear precedence using ternary with ??, please use () to remove ambiguity.");
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr(context, inner)) return false;
|
||||
|
||||
if (expr->or_error_expr.widen && !sema_widen_top_down(inner, expr->type)) return false;
|
||||
|
||||
Type *type = inner->type;
|
||||
if (type->type_kind != TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(inner, "No failable to use '\?\?' with, please remove the '\?\?'.");
|
||||
return false;
|
||||
}
|
||||
type = type->failable;
|
||||
if (expr->or_error_expr.is_jump)
|
||||
{
|
||||
if (!sema_analyse_statement(context, expr->or_error_expr.or_error_stmt)) return false;
|
||||
expr->type = inner->type;
|
||||
return true;
|
||||
}
|
||||
|
||||
// First we analyse the "else" and try to implictly cast.
|
||||
Expr *else_expr = expr->or_error_expr.or_error_expr;
|
||||
if (!sema_analyse_expr(context, else_expr)) return false;
|
||||
if (expr->or_error_expr.widen && !sema_widen_top_down(else_expr, expr->type)) return false;
|
||||
|
||||
// Here we might need to insert casts.
|
||||
Type *else_type = else_expr->type;
|
||||
if (else_type->type_kind == TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(else_expr, "The default value may not be a failable.");
|
||||
return false;
|
||||
}
|
||||
Type *common = type_find_max_type(type, else_type);
|
||||
if (!common)
|
||||
{
|
||||
SEMA_ERROR(else_expr, "Cannot find a common type for %s and %s.", type_quoted_error_string(type),
|
||||
type_quoted_error_string(else_type));
|
||||
return false;
|
||||
}
|
||||
if (!cast_implicit(inner, common)) return false;
|
||||
if (!cast_implicit(else_expr, common)) return false;
|
||||
if (IS_FAILABLE(else_expr))
|
||||
{
|
||||
SEMA_ERROR(else_expr, "The expression must be a non-failable.");
|
||||
return false;
|
||||
}
|
||||
expr->type = common;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr)
|
||||
{
|
||||
if (!context->current_function)
|
||||
{
|
||||
SEMA_ERROR(expr, "Rethrow cannot be used outside of a function.");
|
||||
return false;
|
||||
}
|
||||
Expr *inner = expr->rethrow_expr.inner;
|
||||
if (!sema_analyse_expr(context, inner)) return false;
|
||||
|
||||
REMINDER("Return defers must be work with blocks");
|
||||
if (context->active_scope.in_defer)
|
||||
{
|
||||
SEMA_ERROR(expr, "Returns are not allowed inside of defers.");
|
||||
return false;
|
||||
}
|
||||
expr->rethrow_expr.cleanup = context_get_defers(context, context->active_scope.defer_last, 0);
|
||||
if (inner->type == type_anyfail)
|
||||
{
|
||||
@@ -6050,12 +6036,17 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->rtype->type_kind != TYPE_FAILABLE)
|
||||
if (context->rtype && context->rtype->type_kind != TYPE_FAILABLE)
|
||||
{
|
||||
SEMA_ERROR(expr, "This expression implicitly returns with a failable result, but the function does not allow failable results. Did you mean to use 'else' instead?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
|
||||
{
|
||||
vec_add(context->returns, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6098,7 +6089,6 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
|
||||
{
|
||||
bool success = true;
|
||||
expr->type = type_void;
|
||||
bool saved_expr_failable_return = context->expr_failable_return;
|
||||
Ast **saved_returns = context_push_returns(context);
|
||||
Type *stored_block_type = context->expected_block_type;
|
||||
context->expected_block_type = infer_type;
|
||||
@@ -6144,7 +6134,6 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
|
||||
SCOPE_END;
|
||||
context->expected_block_type = stored_block_type;
|
||||
context_pop_returns(context, saved_returns);
|
||||
context->expr_failable_return = saved_expr_failable_return;
|
||||
|
||||
return success;
|
||||
}
|
||||
@@ -6897,7 +6886,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
// Created during semantic analysis
|
||||
UNREACHABLE
|
||||
case EXPR_MACRO_BLOCK:
|
||||
case EXPR_SCOPED_EXPR:
|
||||
UNREACHABLE
|
||||
case EXPR_TYPEINFO:
|
||||
expr->type = type_typeinfo;
|
||||
@@ -6910,8 +6898,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
return sema_expr_analyse_try(context, expr);
|
||||
case EXPR_CATCH:
|
||||
return sema_expr_analyse_catch(context, expr);
|
||||
case EXPR_OR_ERROR:
|
||||
return sema_expr_analyse_or_error(context, expr);
|
||||
case EXPR_COMPOUND_LITERAL:
|
||||
return sema_expr_analyse_compound_literal(context, expr);
|
||||
case EXPR_EXPR_BLOCK:
|
||||
@@ -7213,6 +7199,7 @@ void insert_widening_type(Expr *expr, Type *infer_type)
|
||||
case BINARYOP_BIT_OR:
|
||||
case BINARYOP_BIT_XOR:
|
||||
case BINARYOP_BIT_AND:
|
||||
case BINARYOP_OR_ERR:
|
||||
if (!expr_is_simple(exprptr(expr->binary_expr.left)) || !expr_is_simple(exprptr(expr->binary_expr.right))) return;
|
||||
expr->type = infer_type;
|
||||
expr->binary_expr.widen = true;
|
||||
@@ -7220,12 +7207,6 @@ void insert_widening_type(Expr *expr, Type *infer_type)
|
||||
default:
|
||||
return;
|
||||
}
|
||||
case EXPR_OR_ERROR:
|
||||
if (!expr_is_simple(expr->or_error_expr.expr)) return;
|
||||
if (!expr->or_error_expr.is_jump && !expr_is_simple(expr->or_error_expr.or_error_expr)) return;
|
||||
expr->type = infer_type;
|
||||
expr->or_error_expr.widen = true;
|
||||
return;
|
||||
case EXPR_GROUP:
|
||||
insert_widening_type(expr->inner_expr, infer_type);
|
||||
return;
|
||||
|
||||
@@ -36,8 +36,7 @@ do { \
|
||||
|
||||
AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom);
|
||||
void context_pop_defers(SemaContext *context, AstId *next);
|
||||
Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr);
|
||||
void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr);
|
||||
|
||||
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
|
||||
void context_change_scope_for_label(SemaContext *context, Decl *label);
|
||||
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
|
||||
|
||||
@@ -145,6 +145,12 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state
|
||||
*/
|
||||
static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
if (context->active_scope.in_defer)
|
||||
{
|
||||
SEMA_ERROR(statement, "Return is not allowed inside of a defer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// This might be a return in a function block or a macro which must be treated differently.
|
||||
if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
|
||||
{
|
||||
@@ -710,6 +716,11 @@ static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement)
|
||||
|
||||
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body)
|
||||
{
|
||||
if (body->ast_kind == AST_DEFER_STMT)
|
||||
{
|
||||
SEMA_ERROR(body, "A defer may not have a body consisting of a raw 'defer', this looks like a mistake.");
|
||||
return false;
|
||||
}
|
||||
// TODO special parsing of "catch"
|
||||
bool success;
|
||||
SCOPE_START
|
||||
@@ -729,7 +740,7 @@ bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *bod
|
||||
POP_BREAKCONT();
|
||||
POP_NEXT();
|
||||
|
||||
context_pop_defers_and_replace_ast(context, body);
|
||||
// We should never need to replace any defers here.
|
||||
|
||||
SCOPE_END;
|
||||
|
||||
@@ -765,8 +776,6 @@ static inline bool sema_analyse_for_cond(SemaContext *context, ExprId *cond_ref,
|
||||
if (!sema_analyse_cond_expr(context, cond)) return false;
|
||||
}
|
||||
|
||||
cond = context_pop_defers_and_wrap_expr(context, cond);
|
||||
|
||||
// If this is const true, then set this to infinite and remove the expression.
|
||||
Expr *cond_last = cond->expr_kind == EXPR_COND ? VECLAST(cond->cond_expr) : cond;
|
||||
assert(cond_last);
|
||||
@@ -790,6 +799,18 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
|
||||
bool success = true;
|
||||
bool is_infinite = false;
|
||||
|
||||
Ast *body = astptr(statement->for_stmt.body);
|
||||
assert(body);
|
||||
if (body->ast_kind == AST_DEFER_STMT)
|
||||
{
|
||||
SEMA_ERROR(body, "Looping over a raw 'defer' is not allowed, was this a mistake?");
|
||||
return false;
|
||||
}
|
||||
bool do_loop = statement->for_stmt.flow.skip_first;
|
||||
if (body->ast_kind != AST_COMPOUND_STMT && do_loop)
|
||||
{
|
||||
SEMA_ERROR(body, "A do loop must use { } around its body.");
|
||||
}
|
||||
// Enter for scope
|
||||
SCOPE_OUTER_START
|
||||
|
||||
@@ -801,7 +822,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
|
||||
// Conditional scope start
|
||||
SCOPE_START_WITH_LABEL(statement->for_stmt.flow.label)
|
||||
|
||||
if (!statement->for_stmt.flow.skip_first)
|
||||
if (!do_loop)
|
||||
{
|
||||
if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success)
|
||||
{
|
||||
@@ -810,8 +831,6 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
|
||||
}
|
||||
}
|
||||
|
||||
assert(statement->for_stmt.body);
|
||||
Ast *body = astptr(statement->for_stmt.body);
|
||||
|
||||
PUSH_BREAKCONT(statement);
|
||||
success = sema_analyse_statement(context, body);
|
||||
@@ -838,9 +857,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
// Incr scope start
|
||||
SCOPE_START
|
||||
Expr *incr = exprptr(statement->for_stmt.incr);
|
||||
success = sema_analyse_expr(context, incr);
|
||||
statement->for_stmt.incr = exprid(context_pop_defers_and_wrap_expr(context, incr));
|
||||
success = sema_analyse_expr(context, exprptr(statement->for_stmt.incr));
|
||||
// Incr scope end
|
||||
SCOPE_END;
|
||||
}
|
||||
@@ -951,9 +968,6 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
|
||||
// Pop any possible defers.
|
||||
enumerator = context_pop_defers_and_wrap_expr(context, enumerator);
|
||||
|
||||
// And pop the cond scope.
|
||||
SCOPE_END;
|
||||
|
||||
@@ -1211,6 +1225,11 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
|
||||
|
||||
Expr *cond = exprptr(statement->if_stmt.cond);
|
||||
Ast *then = astptr(statement->if_stmt.then_body);
|
||||
if (then->ast_kind == AST_DEFER_STMT)
|
||||
{
|
||||
SEMA_ERROR(then, "An 'if' statement may not be followed by a raw 'defer' statement, this looks like a mistake.");
|
||||
return false;
|
||||
}
|
||||
AstId else_id = statement->if_stmt.else_body;
|
||||
Ast *else_body = else_id ? astptr(else_id) : NULL;
|
||||
SCOPE_OUTER_START
|
||||
|
||||
@@ -42,6 +42,11 @@ void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags)
|
||||
assert(parent_defer < 1000000);
|
||||
// Defer and expression blocks introduce their own return/break/continue
|
||||
// otherwise just merge with the old flags.
|
||||
if (flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
|
||||
{
|
||||
previous_defer = 0;
|
||||
parent_defer = 0;
|
||||
}
|
||||
if (!(flags & SCOPE_EXPR_BLOCK))
|
||||
{
|
||||
flags = context->active_scope.flags | flags;
|
||||
@@ -110,35 +115,6 @@ void context_pop_defers(SemaContext *context, AstId *next)
|
||||
}
|
||||
|
||||
|
||||
Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr)
|
||||
{
|
||||
AstId defer_first = 0;
|
||||
context_pop_defers(context, &defer_first);
|
||||
if (defer_first)
|
||||
{
|
||||
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
|
||||
wrap->type = expr->type;
|
||||
wrap->resolve_status = RESOLVE_DONE;
|
||||
wrap->expr_scope.expr = expr;
|
||||
wrap->expr_scope.defer_stmts = defer_first;
|
||||
return wrap;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr)
|
||||
{
|
||||
AstId defer_first = 0;
|
||||
context_pop_defers(context, &defer_first);
|
||||
if (defer_first)
|
||||
{
|
||||
Expr *inner = expr_copy(expr);
|
||||
expr->expr_kind = EXPR_SCOPED_EXPR;
|
||||
expr->expr_scope.expr = inner;
|
||||
expr->expr_scope.defer_stmts = defer_first;
|
||||
}
|
||||
}
|
||||
|
||||
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast)
|
||||
{
|
||||
AstId defer_first = 0;
|
||||
|
||||
@@ -207,8 +207,6 @@ void symtab_init(uint32_t capacity)
|
||||
attribute_list[ATTRIBUTE_UNUSED] = KW_DEF("unused");
|
||||
attribute_list[ATTRIBUTE_USED] = KW_DEF("used");
|
||||
attribute_list[ATTRIBUTE_NAKED] = KW_DEF("naked");
|
||||
attribute_list[ATTRIBUTE_NOSCOPE] = KW_DEF("noscope");
|
||||
attribute_list[ATTRIBUTE_ESCAPING] = KW_DEF("escaping");
|
||||
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("cdecl");
|
||||
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
|
||||
attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("veccall");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "PRE.28"
|
||||
#define COMPILER_VERSION "PRE.29"
|
||||
40
test/test_suite/defer/defer_and_expr_block.c3t
Normal file
40
test/test_suite/defer/defer_and_expr_block.c3t
Normal file
@@ -0,0 +1,40 @@
|
||||
// #target: x64-darwin
|
||||
module foo;
|
||||
extern fn void printf(char*,...);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
defer printf("On exit\n");
|
||||
{|
|
||||
defer printf("Baz\n");
|
||||
defer {|
|
||||
defer printf("Hello!\n");
|
||||
defer printf("1\n");
|
||||
if (true) return 12;
|
||||
defer printf("2\n");
|
||||
return 34;
|
||||
|};
|
||||
|};
|
||||
defer printf("On 2\n");
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
define void @foo.main() #0 {
|
||||
entry:
|
||||
%blockret = alloca i32, align 4
|
||||
br label %if.then
|
||||
|
||||
if.then: ; preds = %entry
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0))
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0))
|
||||
store i32 12, i32* %blockret, align 4
|
||||
br label %expr_block.exit
|
||||
|
||||
expr_block.exit: ; preds = %if.then
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i32 0, i32 0))
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.7, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
|
||||
41
test/test_suite/defer/defer_single_stmt.c3
Normal file
41
test/test_suite/defer/defer_single_stmt.c3
Normal file
@@ -0,0 +1,41 @@
|
||||
fn void test1()
|
||||
{
|
||||
while (1) defer foo(); // #error: Looping over a raw 'defer'
|
||||
}
|
||||
|
||||
fn void test1a()
|
||||
{
|
||||
while (1) { defer foo(); }
|
||||
}
|
||||
|
||||
fn void test2()
|
||||
{
|
||||
if (1) defer foo(); // #error: An 'if' statement may not be followed by a raw 'defer'
|
||||
}
|
||||
|
||||
fn void test2a()
|
||||
{
|
||||
if (1) { defer foo(); }
|
||||
}
|
||||
|
||||
fn void test3()
|
||||
{
|
||||
defer defer foo(); // #error: A defer may not have a body consisting of a raw 'defer'
|
||||
}
|
||||
|
||||
fn void test3a()
|
||||
{
|
||||
defer { defer foo(); }
|
||||
}
|
||||
|
||||
fn void test4()
|
||||
{
|
||||
for (;;) defer foo(); // #error: Looping over a raw 'defer'
|
||||
}
|
||||
|
||||
fn void test4a()
|
||||
{
|
||||
for(;;) { defer foo(); }
|
||||
}
|
||||
|
||||
fn void foo() {}
|
||||
14
test/test_suite/defer/defer_with_rethrow.c3
Normal file
14
test/test_suite/defer/defer_with_rethrow.c3
Normal file
@@ -0,0 +1,14 @@
|
||||
fn int! foo()
|
||||
{ return 1; }
|
||||
|
||||
|
||||
fn int! bar()
|
||||
{
|
||||
defer {
|
||||
{|
|
||||
foo()?;
|
||||
|};
|
||||
}
|
||||
defer foo()?; // #error: Returns are not allowed inside of defers.
|
||||
return 1;
|
||||
}
|
||||
10
test/test_suite/defer/defer_with_return.c3
Normal file
10
test/test_suite/defer/defer_with_return.c3
Normal file
@@ -0,0 +1,10 @@
|
||||
fn int! bar()
|
||||
{
|
||||
defer {
|
||||
{|
|
||||
return 4;
|
||||
|};
|
||||
}
|
||||
defer return 3; // #error: Return is not allowed inside of a defer
|
||||
return 1;
|
||||
}
|
||||
@@ -29,16 +29,7 @@ fn void main()
|
||||
; Function Attrs: nounwind
|
||||
define i64 @anyerr_void.errorThing() #0 {
|
||||
entry:
|
||||
%reterr = alloca i64, align 8
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64), i64* %reterr, align 8
|
||||
br label %err_retblock
|
||||
|
||||
postfailed: ; No predecessors!
|
||||
ret i64 0
|
||||
|
||||
err_retblock: ; preds = %entry
|
||||
%0 = load i64, i64* %reterr, align 8
|
||||
ret i64 %0
|
||||
ret i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"anyerr_void.MyError$elements", i64 0, i64 1) to i64)
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
|
||||
@@ -266,39 +266,37 @@ define i64 @test.readDoc(%Doc* %0, i8* %1, i64 %2) #0 {
|
||||
entry:
|
||||
%url = alloca %"char[]", align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%reterr = alloca i64, align 8
|
||||
%taddr5 = alloca %"char[]", align 8
|
||||
%reterr9 = alloca i64, align 8
|
||||
%reterr = alloca i64, align 8
|
||||
%literal = alloca %Doc, align 8
|
||||
%taddr13 = alloca %"char[]", align 8
|
||||
%reterr17 = alloca i64, align 8
|
||||
%literal18 = alloca %Doc, align 8
|
||||
%taddr12 = alloca %"char[]", align 8
|
||||
%reterr16 = alloca i64, align 8
|
||||
%literal17 = alloca %Doc, align 8
|
||||
%error_var = alloca i64, align 8
|
||||
%value = alloca %Head, align 8
|
||||
%literal19 = alloca %Head, align 8
|
||||
%literal18 = alloca %Head, align 8
|
||||
%temp = alloca %Head*, align 8
|
||||
%taddr26 = alloca %"char[]", align 8
|
||||
%reterr30 = alloca i64, align 8
|
||||
%literal31 = alloca %Doc, align 8
|
||||
%error_var32 = alloca i64, align 8
|
||||
%value33 = alloca %Head, align 8
|
||||
%literal34 = alloca %Head, align 8
|
||||
%error_var35 = alloca i64, align 8
|
||||
%value36 = alloca %"char[]", align 8
|
||||
%temp37 = alloca %"char[]"*, align 8
|
||||
%temp45 = alloca %Head*, align 8
|
||||
%taddr24 = alloca %"char[]", align 8
|
||||
%reterr28 = alloca i64, align 8
|
||||
%literal29 = alloca %Doc, align 8
|
||||
%error_var30 = alloca i64, align 8
|
||||
%value31 = alloca %Head, align 8
|
||||
%literal32 = alloca %Head, align 8
|
||||
%error_var33 = alloca i64, align 8
|
||||
%value34 = alloca %"char[]", align 8
|
||||
%temp35 = alloca %"char[]"*, align 8
|
||||
%temp42 = alloca %Head*, align 8
|
||||
%len = alloca i32, align 4
|
||||
%str = alloca i8*, align 8
|
||||
%reterr56 = alloca i64, align 8
|
||||
%reterr63 = alloca i64, align 8
|
||||
%literal64 = alloca %Doc, align 8
|
||||
%error_var65 = alloca i64, align 8
|
||||
%value66 = alloca %Head, align 8
|
||||
%literal67 = alloca %Head, align 8
|
||||
%error_var68 = alloca i64, align 8
|
||||
%value69 = alloca %"char[]", align 8
|
||||
%temp70 = alloca %"char[]"*, align 8
|
||||
%temp78 = alloca %Head*, align 8
|
||||
%literal57 = alloca %Doc, align 8
|
||||
%error_var58 = alloca i64, align 8
|
||||
%value59 = alloca %Head, align 8
|
||||
%literal60 = alloca %Head, align 8
|
||||
%error_var61 = alloca i64, align 8
|
||||
%value62 = alloca %"char[]", align 8
|
||||
%temp63 = alloca %"char[]"*, align 8
|
||||
%temp70 = alloca %Head*, align 8
|
||||
%pair = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0
|
||||
store i8* %1, i8** %3, align 8
|
||||
@@ -320,281 +318,263 @@ entry:
|
||||
br i1 %12, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %entry
|
||||
store i64 ptrtoint ([2 x i8*]* @"test.ReadError$elements" to i64), i64* %reterr, align 8
|
||||
br label %err_retblock
|
||||
|
||||
postfailed: ; No predecessors!
|
||||
store %Doc undef, %Doc* %0, align 8
|
||||
ret i64 0
|
||||
|
||||
err_retblock: ; preds = %if.then
|
||||
%13 = load i64, i64* %reterr, align 8
|
||||
ret i64 %13
|
||||
ret i64 ptrtoint ([2 x i8*]* @"test.ReadError$elements" to i64)
|
||||
|
||||
if.exit: ; preds = %entry
|
||||
%14 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %14, i32 0, i32 0
|
||||
%lo3 = load i8*, i8** %15, align 8
|
||||
%16 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %14, i32 0, i32 1
|
||||
%hi4 = load i64, i64* %16, align 8
|
||||
%13 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%14 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 0
|
||||
%lo3 = load i8*, i8** %14, align 8
|
||||
%15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 1
|
||||
%hi4 = load i64, i64* %15, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.1, i32 0, i32 0), i64 12 }, %"char[]"* %taddr5, align 8
|
||||
%17 = bitcast %"char[]"* %taddr5 to { i8*, i64 }*
|
||||
%18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %17, i32 0, i32 0
|
||||
%lo6 = load i8*, i8** %18, align 8
|
||||
%19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %17, i32 0, i32 1
|
||||
%hi7 = load i64, i64* %19, align 8
|
||||
%20 = call i8 @test.contains(i8* %lo3, i64 %hi4, i8* %lo6, i64 %hi7)
|
||||
%21 = trunc i8 %20 to i1
|
||||
br i1 %21, label %if.then8, label %if.exit10
|
||||
%16 = bitcast %"char[]"* %taddr5 to { i8*, i64 }*
|
||||
%17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 0
|
||||
%lo6 = load i8*, i8** %17, align 8
|
||||
%18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 1
|
||||
%hi7 = load i64, i64* %18, align 8
|
||||
%19 = call i8 @test.contains(i8* %lo3, i64 %hi4, i8* %lo6, i64 %hi7)
|
||||
%20 = trunc i8 %19 to i1
|
||||
br i1 %20, label %if.then8, label %if.exit9
|
||||
|
||||
if.then8: ; preds = %if.exit
|
||||
%22 = getelementptr inbounds %Doc, %Doc* %literal, i32 0, i32 0
|
||||
store %Head* null, %Head** %22, align 8
|
||||
%23 = bitcast %Doc* %0 to i8*
|
||||
%24 = bitcast %Doc* %literal to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %23, i8* align 8 %24, i32 8, i1 false)
|
||||
%21 = getelementptr inbounds %Doc, %Doc* %literal, i32 0, i32 0
|
||||
store %Head* null, %Head** %21, align 8
|
||||
%22 = bitcast %Doc* %0 to i8*
|
||||
%23 = bitcast %Doc* %literal to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 %23, i32 8, i1 false)
|
||||
ret i64 0
|
||||
|
||||
if.exit10: ; preds = %if.exit
|
||||
%25 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 0
|
||||
%lo11 = load i8*, i8** %26, align 8
|
||||
%27 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 1
|
||||
%hi12 = load i64, i64* %27, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2, i32 0, i32 0), i64 13 }, %"char[]"* %taddr13, align 8
|
||||
%28 = bitcast %"char[]"* %taddr13 to { i8*, i64 }*
|
||||
%29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %28, i32 0, i32 0
|
||||
%lo14 = load i8*, i8** %29, align 8
|
||||
%30 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %28, i32 0, i32 1
|
||||
%hi15 = load i64, i64* %30, align 8
|
||||
%31 = call i8 @test.contains(i8* %lo11, i64 %hi12, i8* %lo14, i64 %hi15)
|
||||
%32 = trunc i8 %31 to i1
|
||||
br i1 %32, label %if.then16, label %if.exit23
|
||||
if.exit9: ; preds = %if.exit
|
||||
%24 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%25 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 0
|
||||
%lo10 = load i8*, i8** %25, align 8
|
||||
%26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 1
|
||||
%hi11 = load i64, i64* %26, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2, i32 0, i32 0), i64 13 }, %"char[]"* %taddr12, align 8
|
||||
%27 = bitcast %"char[]"* %taddr12 to { i8*, i64 }*
|
||||
%28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 0
|
||||
%lo13 = load i8*, i8** %28, align 8
|
||||
%29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 1
|
||||
%hi14 = load i64, i64* %29, align 8
|
||||
%30 = call i8 @test.contains(i8* %lo10, i64 %hi11, i8* %lo13, i64 %hi14)
|
||||
%31 = trunc i8 %30 to i1
|
||||
br i1 %31, label %if.then15, label %if.exit21
|
||||
|
||||
if.then16: ; preds = %if.exit10
|
||||
%33 = getelementptr inbounds %Doc, %Doc* %literal18, i32 0, i32 0
|
||||
%34 = getelementptr inbounds %Head, %Head* %literal19, i32 0, i32 0
|
||||
store %"char[]"* null, %"char[]"** %34, align 8
|
||||
%35 = load %Head, %Head* %literal19, align 8
|
||||
store %Head %35, %Head* %value, align 8
|
||||
%36 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr = bitcast i8* %36 to %Head*
|
||||
if.then15: ; preds = %if.exit9
|
||||
%32 = getelementptr inbounds %Doc, %Doc* %literal17, i32 0, i32 0
|
||||
%33 = getelementptr inbounds %Head, %Head* %literal18, i32 0, i32 0
|
||||
store %"char[]"* null, %"char[]"** %33, align 8
|
||||
%34 = load %Head, %Head* %literal18, align 8
|
||||
store %Head %34, %Head* %value, align 8
|
||||
%35 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr = bitcast i8* %35 to %Head*
|
||||
store %Head* %ptrptr, %Head** %temp, align 8
|
||||
%37 = load %Head*, %Head** %temp, align 8
|
||||
%not = icmp eq %Head* %37, null
|
||||
br i1 %not, label %if.then20, label %if.exit22
|
||||
%36 = load %Head*, %Head** %temp, align 8
|
||||
%not = icmp eq %Head* %36, null
|
||||
br i1 %not, label %if.then19, label %if.exit20
|
||||
|
||||
if.then20: ; preds = %if.then16
|
||||
if.then19: ; preds = %if.then15
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var, align 8
|
||||
br label %guard_block
|
||||
|
||||
if.exit22: ; preds = %if.then16
|
||||
%38 = load %Head*, %Head** %temp, align 8
|
||||
%39 = bitcast %Head* %38 to i8*
|
||||
%40 = bitcast %Head* %value to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %39, i8* align 8 %40, i32 8, i1 false)
|
||||
if.exit20: ; preds = %if.then15
|
||||
%37 = load %Head*, %Head** %temp, align 8
|
||||
%38 = bitcast %Head* %37 to i8*
|
||||
%39 = bitcast %Head* %value to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %38, i8* align 8 %39, i32 8, i1 false)
|
||||
br label %noerr_block
|
||||
|
||||
guard_block: ; preds = %if.then20
|
||||
%41 = load i64, i64* %error_var, align 8
|
||||
ret i64 %41
|
||||
guard_block: ; preds = %if.then19
|
||||
%40 = load i64, i64* %error_var, align 8
|
||||
ret i64 %40
|
||||
|
||||
noerr_block: ; preds = %if.exit22
|
||||
%42 = load %Head*, %Head** %temp, align 8
|
||||
store %Head* %42, %Head** %33, align 8
|
||||
%43 = bitcast %Doc* %0 to i8*
|
||||
%44 = bitcast %Doc* %literal18 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %43, i8* align 8 %44, i32 8, i1 false)
|
||||
noerr_block: ; preds = %if.exit20
|
||||
%41 = load %Head*, %Head** %temp, align 8
|
||||
store %Head* %41, %Head** %32, align 8
|
||||
%42 = bitcast %Doc* %0 to i8*
|
||||
%43 = bitcast %Doc* %literal17 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %42, i8* align 8 %43, i32 8, i1 false)
|
||||
ret i64 0
|
||||
|
||||
if.exit23: ; preds = %if.exit10
|
||||
%45 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %45, i32 0, i32 0
|
||||
%lo24 = load i8*, i8** %46, align 8
|
||||
%47 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %45, i32 0, i32 1
|
||||
%hi25 = load i64, i64* %47, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.3, i32 0, i32 0), i64 11 }, %"char[]"* %taddr26, align 8
|
||||
%48 = bitcast %"char[]"* %taddr26 to { i8*, i64 }*
|
||||
%49 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %48, i32 0, i32 0
|
||||
%lo27 = load i8*, i8** %49, align 8
|
||||
%50 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %48, i32 0, i32 1
|
||||
%hi28 = load i64, i64* %50, align 8
|
||||
%51 = call i8 @test.contains(i8* %lo24, i64 %hi25, i8* %lo27, i64 %hi28)
|
||||
%52 = trunc i8 %51 to i1
|
||||
br i1 %52, label %if.then29, label %if.exit53
|
||||
if.exit21: ; preds = %if.exit9
|
||||
%44 = bitcast %"char[]"* %url to { i8*, i64 }*
|
||||
%45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 0
|
||||
%lo22 = load i8*, i8** %45, align 8
|
||||
%46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 1
|
||||
%hi23 = load i64, i64* %46, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.3, i32 0, i32 0), i64 11 }, %"char[]"* %taddr24, align 8
|
||||
%47 = bitcast %"char[]"* %taddr24 to { i8*, i64 }*
|
||||
%48 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 0
|
||||
%lo25 = load i8*, i8** %48, align 8
|
||||
%49 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 1
|
||||
%hi26 = load i64, i64* %49, align 8
|
||||
%50 = call i8 @test.contains(i8* %lo22, i64 %hi23, i8* %lo25, i64 %hi26)
|
||||
%51 = trunc i8 %50 to i1
|
||||
br i1 %51, label %if.then27, label %if.exit49
|
||||
|
||||
if.then29: ; preds = %if.exit23
|
||||
%53 = getelementptr inbounds %Doc, %Doc* %literal31, i32 0, i32 0
|
||||
%54 = bitcast %Head* %literal34 to %"char[]"**
|
||||
store %"char[]"* null, %"char[]"** %54, align 8
|
||||
%55 = getelementptr inbounds %Head, %Head* %literal34, i32 0, i32 0
|
||||
store %"char[]" { i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i32 0, i32 0), i64 0 }, %"char[]"* %value36, align 8
|
||||
%56 = call i8* @"std::mem.alloc"(i64 16, i64 1) #2
|
||||
%ptrptr38 = bitcast i8* %56 to %"char[]"*
|
||||
store %"char[]"* %ptrptr38, %"char[]"** %temp37, align 8
|
||||
%57 = load %"char[]"*, %"char[]"** %temp37, align 8
|
||||
%not39 = icmp eq %"char[]"* %57, null
|
||||
br i1 %not39, label %if.then40, label %if.exit42
|
||||
if.then27: ; preds = %if.exit21
|
||||
%52 = getelementptr inbounds %Doc, %Doc* %literal29, i32 0, i32 0
|
||||
%53 = bitcast %Head* %literal32 to %"char[]"**
|
||||
store %"char[]"* null, %"char[]"** %53, align 8
|
||||
%54 = getelementptr inbounds %Head, %Head* %literal32, i32 0, i32 0
|
||||
store %"char[]" { i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i32 0, i32 0), i64 0 }, %"char[]"* %value34, align 8
|
||||
%55 = call i8* @"std::mem.alloc"(i64 16, i64 1) #2
|
||||
%ptrptr36 = bitcast i8* %55 to %"char[]"*
|
||||
store %"char[]"* %ptrptr36, %"char[]"** %temp35, align 8
|
||||
%56 = load %"char[]"*, %"char[]"** %temp35, align 8
|
||||
%not37 = icmp eq %"char[]"* %56, null
|
||||
br i1 %not37, label %if.then38, label %if.exit39
|
||||
|
||||
if.then40: ; preds = %if.then29
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var35, align 8
|
||||
br label %guard_block43
|
||||
if.then38: ; preds = %if.then27
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var33, align 8
|
||||
br label %guard_block40
|
||||
|
||||
if.exit42: ; preds = %if.then29
|
||||
%58 = load %"char[]"*, %"char[]"** %temp37, align 8
|
||||
%59 = bitcast %"char[]"* %58 to i8*
|
||||
%60 = bitcast %"char[]"* %value36 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %59, i8* align 8 %60, i32 16, i1 false)
|
||||
br label %noerr_block44
|
||||
if.exit39: ; preds = %if.then27
|
||||
%57 = load %"char[]"*, %"char[]"** %temp35, align 8
|
||||
%58 = bitcast %"char[]"* %57 to i8*
|
||||
%59 = bitcast %"char[]"* %value34 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %58, i8* align 8 %59, i32 16, i1 false)
|
||||
br label %noerr_block41
|
||||
|
||||
guard_block43: ; preds = %if.then40
|
||||
%61 = load i64, i64* %error_var35, align 8
|
||||
ret i64 %61
|
||||
guard_block40: ; preds = %if.then38
|
||||
%60 = load i64, i64* %error_var33, align 8
|
||||
ret i64 %60
|
||||
|
||||
noerr_block44: ; preds = %if.exit42
|
||||
%62 = load %"char[]"*, %"char[]"** %temp37, align 8
|
||||
store %"char[]"* %62, %"char[]"** %55, align 8
|
||||
%63 = load %Head, %Head* %literal34, align 8
|
||||
store %Head %63, %Head* %value33, align 8
|
||||
%64 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr46 = bitcast i8* %64 to %Head*
|
||||
store %Head* %ptrptr46, %Head** %temp45, align 8
|
||||
%65 = load %Head*, %Head** %temp45, align 8
|
||||
%not47 = icmp eq %Head* %65, null
|
||||
br i1 %not47, label %if.then48, label %if.exit50
|
||||
noerr_block41: ; preds = %if.exit39
|
||||
%61 = load %"char[]"*, %"char[]"** %temp35, align 8
|
||||
store %"char[]"* %61, %"char[]"** %54, align 8
|
||||
%62 = load %Head, %Head* %literal32, align 8
|
||||
store %Head %62, %Head* %value31, align 8
|
||||
%63 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr43 = bitcast i8* %63 to %Head*
|
||||
store %Head* %ptrptr43, %Head** %temp42, align 8
|
||||
%64 = load %Head*, %Head** %temp42, align 8
|
||||
%not44 = icmp eq %Head* %64, null
|
||||
br i1 %not44, label %if.then45, label %if.exit46
|
||||
|
||||
if.then48: ; preds = %noerr_block44
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var32, align 8
|
||||
br label %guard_block51
|
||||
if.then45: ; preds = %noerr_block41
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var30, align 8
|
||||
br label %guard_block47
|
||||
|
||||
if.exit50: ; preds = %noerr_block44
|
||||
%66 = load %Head*, %Head** %temp45, align 8
|
||||
%67 = bitcast %Head* %66 to i8*
|
||||
%68 = bitcast %Head* %value33 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %67, i8* align 8 %68, i32 8, i1 false)
|
||||
br label %noerr_block52
|
||||
if.exit46: ; preds = %noerr_block41
|
||||
%65 = load %Head*, %Head** %temp42, align 8
|
||||
%66 = bitcast %Head* %65 to i8*
|
||||
%67 = bitcast %Head* %value31 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %66, i8* align 8 %67, i32 8, i1 false)
|
||||
br label %noerr_block48
|
||||
|
||||
guard_block51: ; preds = %if.then48
|
||||
%69 = load i64, i64* %error_var32, align 8
|
||||
ret i64 %69
|
||||
guard_block47: ; preds = %if.then45
|
||||
%68 = load i64, i64* %error_var30, align 8
|
||||
ret i64 %68
|
||||
|
||||
noerr_block52: ; preds = %if.exit50
|
||||
%70 = load %Head*, %Head** %temp45, align 8
|
||||
store %Head* %70, %Head** %53, align 8
|
||||
%71 = bitcast %Doc* %0 to i8*
|
||||
%72 = bitcast %Doc* %literal31 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %71, i8* align 8 %72, i32 8, i1 false)
|
||||
noerr_block48: ; preds = %if.exit46
|
||||
%69 = load %Head*, %Head** %temp42, align 8
|
||||
store %Head* %69, %Head** %52, align 8
|
||||
%70 = bitcast %Doc* %0 to i8*
|
||||
%71 = bitcast %Doc* %literal29 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %70, i8* align 8 %71, i32 8, i1 false)
|
||||
ret i64 0
|
||||
|
||||
if.exit53: ; preds = %if.exit23
|
||||
%73 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1
|
||||
%74 = load i64, i64* %73, align 8
|
||||
%uisitrunc = trunc i64 %74 to i32
|
||||
%75 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0
|
||||
%76 = load i8*, i8** %75, align 8
|
||||
%77 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.5, i32 0, i32 0), i32 %uisitrunc, i8* %76)
|
||||
store i32 %77, i32* %len, align 4
|
||||
%78 = load i32, i32* %len, align 4
|
||||
%siuiext = sext i32 %78 to i64
|
||||
if.exit49: ; preds = %if.exit21
|
||||
%72 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1
|
||||
%73 = load i64, i64* %72, align 8
|
||||
%uisitrunc = trunc i64 %73 to i32
|
||||
%74 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0
|
||||
%75 = load i8*, i8** %74, align 8
|
||||
%76 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.5, i32 0, i32 0), i32 %uisitrunc, i8* %75)
|
||||
store i32 %76, i32* %len, align 4
|
||||
%77 = load i32, i32* %len, align 4
|
||||
%siuiext = sext i32 %77 to i64
|
||||
%add = add i64 %siuiext, 1
|
||||
%79 = call i8* @"std::mem.alloc"(i64 %add, i64 1) #2
|
||||
store i8* %79, i8** %str, align 8
|
||||
%78 = call i8* @"std::mem.alloc"(i64 %add, i64 1) #2
|
||||
store i8* %78, i8** %str, align 8
|
||||
%79 = load i8*, i8** %str, align 8
|
||||
%not50 = icmp eq i8* %79, null
|
||||
br i1 %not50, label %if.then51, label %if.exit52
|
||||
|
||||
if.then51: ; preds = %if.exit49
|
||||
ret i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64)
|
||||
|
||||
if.exit52: ; preds = %if.exit49
|
||||
%80 = load i8*, i8** %str, align 8
|
||||
%not54 = icmp eq i8* %80, null
|
||||
br i1 %not54, label %if.then55, label %if.exit59
|
||||
|
||||
if.then55: ; preds = %if.exit53
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %reterr56, align 8
|
||||
br label %err_retblock58
|
||||
|
||||
postfailed57: ; No predecessors!
|
||||
store %Doc undef, %Doc* %0, align 8
|
||||
ret i64 0
|
||||
|
||||
err_retblock58: ; preds = %if.then55
|
||||
%81 = load i64, i64* %reterr56, align 8
|
||||
ret i64 %81
|
||||
|
||||
if.exit59: ; preds = %if.exit53
|
||||
%82 = load i8*, i8** %str, align 8
|
||||
%83 = load i32, i32* %len, align 4
|
||||
%siuiext60 = sext i32 %83 to i64
|
||||
%add61 = add i64 %siuiext60, 1
|
||||
%84 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1
|
||||
%85 = load i64, i64* %84, align 8
|
||||
%uisitrunc62 = trunc i64 %85 to i32
|
||||
%86 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0
|
||||
%87 = load i8*, i8** %86, align 8
|
||||
%88 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %82, i64 %add61, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.6, i32 0, i32 0), i32 %uisitrunc62, i8* %87)
|
||||
%89 = getelementptr inbounds %Doc, %Doc* %literal64, i32 0, i32 0
|
||||
%90 = bitcast %Head* %literal67 to %"char[]"**
|
||||
store %"char[]"* null, %"char[]"** %90, align 8
|
||||
%91 = getelementptr inbounds %Head, %Head* %literal67, i32 0, i32 0
|
||||
%92 = load i8*, i8** %str, align 8
|
||||
%93 = load i32, i32* %len, align 4
|
||||
%sub = sub i32 %93, 1
|
||||
%81 = load i32, i32* %len, align 4
|
||||
%siuiext53 = sext i32 %81 to i64
|
||||
%add54 = add i64 %siuiext53, 1
|
||||
%82 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1
|
||||
%83 = load i64, i64* %82, align 8
|
||||
%uisitrunc55 = trunc i64 %83 to i32
|
||||
%84 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0
|
||||
%85 = load i8*, i8** %84, align 8
|
||||
%86 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %80, i64 %add54, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.6, i32 0, i32 0), i32 %uisitrunc55, i8* %85)
|
||||
%87 = getelementptr inbounds %Doc, %Doc* %literal57, i32 0, i32 0
|
||||
%88 = bitcast %Head* %literal60 to %"char[]"**
|
||||
store %"char[]"* null, %"char[]"** %88, align 8
|
||||
%89 = getelementptr inbounds %Head, %Head* %literal60, i32 0, i32 0
|
||||
%90 = load i8*, i8** %str, align 8
|
||||
%91 = load i32, i32* %len, align 4
|
||||
%sub = sub i32 %91, 1
|
||||
%sisiext = sext i32 %sub to i64
|
||||
%94 = add i64 %sisiext, 1
|
||||
%size = sub i64 %94, 0
|
||||
%ptroffset = getelementptr inbounds i8, i8* %92, i64 0
|
||||
%95 = insertvalue %"char[]" undef, i8* %ptroffset, 0
|
||||
%96 = insertvalue %"char[]" %95, i64 %size, 1
|
||||
store %"char[]" %96, %"char[]"* %value69, align 8
|
||||
%97 = call i8* @"std::mem.alloc"(i64 16, i64 1) #2
|
||||
%ptrptr71 = bitcast i8* %97 to %"char[]"*
|
||||
store %"char[]"* %ptrptr71, %"char[]"** %temp70, align 8
|
||||
%98 = load %"char[]"*, %"char[]"** %temp70, align 8
|
||||
%not72 = icmp eq %"char[]"* %98, null
|
||||
br i1 %not72, label %if.then73, label %if.exit75
|
||||
%92 = add i64 %sisiext, 1
|
||||
%size = sub i64 %92, 0
|
||||
%ptroffset = getelementptr inbounds i8, i8* %90, i64 0
|
||||
%93 = insertvalue %"char[]" undef, i8* %ptroffset, 0
|
||||
%94 = insertvalue %"char[]" %93, i64 %size, 1
|
||||
store %"char[]" %94, %"char[]"* %value62, align 8
|
||||
%95 = call i8* @"std::mem.alloc"(i64 16, i64 1) #2
|
||||
%ptrptr64 = bitcast i8* %95 to %"char[]"*
|
||||
store %"char[]"* %ptrptr64, %"char[]"** %temp63, align 8
|
||||
%96 = load %"char[]"*, %"char[]"** %temp63, align 8
|
||||
%not65 = icmp eq %"char[]"* %96, null
|
||||
br i1 %not65, label %if.then66, label %if.exit67
|
||||
|
||||
if.then73: ; preds = %if.exit59
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var68, align 8
|
||||
br label %guard_block76
|
||||
if.then66: ; preds = %if.exit52
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var61, align 8
|
||||
br label %guard_block68
|
||||
|
||||
if.exit75: ; preds = %if.exit59
|
||||
%99 = load %"char[]"*, %"char[]"** %temp70, align 8
|
||||
%100 = bitcast %"char[]"* %99 to i8*
|
||||
%101 = bitcast %"char[]"* %value69 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %100, i8* align 8 %101, i32 16, i1 false)
|
||||
br label %noerr_block77
|
||||
if.exit67: ; preds = %if.exit52
|
||||
%97 = load %"char[]"*, %"char[]"** %temp63, align 8
|
||||
%98 = bitcast %"char[]"* %97 to i8*
|
||||
%99 = bitcast %"char[]"* %value62 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %98, i8* align 8 %99, i32 16, i1 false)
|
||||
br label %noerr_block69
|
||||
|
||||
guard_block76: ; preds = %if.then73
|
||||
%102 = load i64, i64* %error_var68, align 8
|
||||
ret i64 %102
|
||||
guard_block68: ; preds = %if.then66
|
||||
%100 = load i64, i64* %error_var61, align 8
|
||||
ret i64 %100
|
||||
|
||||
noerr_block77: ; preds = %if.exit75
|
||||
%103 = load %"char[]"*, %"char[]"** %temp70, align 8
|
||||
store %"char[]"* %103, %"char[]"** %91, align 8
|
||||
%104 = load %Head, %Head* %literal67, align 8
|
||||
store %Head %104, %Head* %value66, align 8
|
||||
%105 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr79 = bitcast i8* %105 to %Head*
|
||||
store %Head* %ptrptr79, %Head** %temp78, align 8
|
||||
%106 = load %Head*, %Head** %temp78, align 8
|
||||
%not80 = icmp eq %Head* %106, null
|
||||
br i1 %not80, label %if.then81, label %if.exit83
|
||||
noerr_block69: ; preds = %if.exit67
|
||||
%101 = load %"char[]"*, %"char[]"** %temp63, align 8
|
||||
store %"char[]"* %101, %"char[]"** %89, align 8
|
||||
%102 = load %Head, %Head* %literal60, align 8
|
||||
store %Head %102, %Head* %value59, align 8
|
||||
%103 = call i8* @"std::mem.alloc"(i64 8, i64 1) #2
|
||||
%ptrptr71 = bitcast i8* %103 to %Head*
|
||||
store %Head* %ptrptr71, %Head** %temp70, align 8
|
||||
%104 = load %Head*, %Head** %temp70, align 8
|
||||
%not72 = icmp eq %Head* %104, null
|
||||
br i1 %not72, label %if.then73, label %if.exit74
|
||||
|
||||
if.then81: ; preds = %noerr_block77
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var65, align 8
|
||||
br label %guard_block84
|
||||
if.then73: ; preds = %noerr_block69
|
||||
store i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"test.ReadError$elements", i64 0, i64 1) to i64), i64* %error_var58, align 8
|
||||
br label %guard_block75
|
||||
|
||||
if.exit83: ; preds = %noerr_block77
|
||||
%107 = load %Head*, %Head** %temp78, align 8
|
||||
%108 = bitcast %Head* %107 to i8*
|
||||
%109 = bitcast %Head* %value66 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %108, i8* align 8 %109, i32 8, i1 false)
|
||||
br label %noerr_block85
|
||||
if.exit74: ; preds = %noerr_block69
|
||||
%105 = load %Head*, %Head** %temp70, align 8
|
||||
%106 = bitcast %Head* %105 to i8*
|
||||
%107 = bitcast %Head* %value59 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %106, i8* align 8 %107, i32 8, i1 false)
|
||||
br label %noerr_block76
|
||||
|
||||
guard_block84: ; preds = %if.then81
|
||||
%110 = load i64, i64* %error_var65, align 8
|
||||
ret i64 %110
|
||||
guard_block75: ; preds = %if.then73
|
||||
%108 = load i64, i64* %error_var58, align 8
|
||||
ret i64 %108
|
||||
|
||||
noerr_block85: ; preds = %if.exit83
|
||||
%111 = load %Head*, %Head** %temp78, align 8
|
||||
store %Head* %111, %Head** %89, align 8
|
||||
%112 = bitcast %Doc* %0 to i8*
|
||||
%113 = bitcast %Doc* %literal64 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %112, i8* align 8 %113, i32 8, i1 false)
|
||||
noerr_block76: ; preds = %if.exit74
|
||||
%109 = load %Head*, %Head** %temp70, align 8
|
||||
store %Head* %109, %Head** %87, align 8
|
||||
%110 = bitcast %Doc* %0 to i8*
|
||||
%111 = bitcast %Doc* %literal57 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %110, i8* align 8 %111, i32 8, i1 false)
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
@@ -693,10 +673,8 @@ phi_block: ; preds = %else_block, %after.
|
||||
define i64 @test.isTitleNonEmpty(i8* %0, %Head* %1) #0 {
|
||||
entry:
|
||||
%doc = alloca %Doc, align 8
|
||||
%reterr = alloca i64, align 8
|
||||
%head = alloca %"char[]"*, align 8
|
||||
%reterr3 = alloca i64, align 8
|
||||
%reterr7 = alloca i64, align 8
|
||||
%reterr = alloca i64, align 8
|
||||
%2 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0
|
||||
store %Head* %1, %Head** %2, align 8
|
||||
%3 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0
|
||||
@@ -705,46 +683,28 @@ entry:
|
||||
br i1 %not, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %entry
|
||||
store i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64), i64* %reterr, align 8
|
||||
br label %err_retblock
|
||||
|
||||
postfailed: ; No predecessors!
|
||||
store i8 undef, i8* %0, align 1
|
||||
ret i64 0
|
||||
|
||||
err_retblock: ; preds = %if.then
|
||||
%5 = load i64, i64* %reterr, align 8
|
||||
ret i64 %5
|
||||
ret i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64)
|
||||
|
||||
if.exit: ; preds = %entry
|
||||
%6 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0
|
||||
%7 = load %Head*, %Head** %6, align 8
|
||||
%8 = getelementptr inbounds %Head, %Head* %7, i32 0, i32 0
|
||||
%9 = load %"char[]"*, %"char[]"** %8, align 8
|
||||
store %"char[]"* %9, %"char[]"** %head, align 8
|
||||
%10 = load %"char[]"*, %"char[]"** %head, align 8
|
||||
%not1 = icmp eq %"char[]"* %10, null
|
||||
br i1 %not1, label %if.then2, label %if.exit6
|
||||
%5 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0
|
||||
%6 = load %Head*, %Head** %5, align 8
|
||||
%7 = getelementptr inbounds %Head, %Head* %6, i32 0, i32 0
|
||||
%8 = load %"char[]"*, %"char[]"** %7, align 8
|
||||
store %"char[]"* %8, %"char[]"** %head, align 8
|
||||
%9 = load %"char[]"*, %"char[]"** %head, align 8
|
||||
%not1 = icmp eq %"char[]"* %9, null
|
||||
br i1 %not1, label %if.then2, label %if.exit3
|
||||
|
||||
if.then2: ; preds = %if.exit
|
||||
store i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64), i64* %reterr3, align 8
|
||||
br label %err_retblock5
|
||||
ret i64 ptrtoint ([1 x i8*]* @"test.TitleResult$elements" to i64)
|
||||
|
||||
postfailed4: ; No predecessors!
|
||||
store i8 undef, i8* %0, align 1
|
||||
ret i64 0
|
||||
|
||||
err_retblock5: ; preds = %if.then2
|
||||
%11 = load i64, i64* %reterr3, align 8
|
||||
ret i64 %11
|
||||
|
||||
if.exit6: ; preds = %if.exit
|
||||
%12 = load %"char[]"*, %"char[]"** %head, align 8
|
||||
%13 = getelementptr inbounds %"char[]", %"char[]"* %12, i32 0, i32 1
|
||||
%14 = load i64, i64* %13, align 8
|
||||
%lt = icmp ult i64 0, %14
|
||||
%15 = zext i1 %lt to i8
|
||||
store i8 %15, i8* %0, align 1
|
||||
if.exit3: ; preds = %if.exit
|
||||
%10 = load %"char[]"*, %"char[]"** %head, align 8
|
||||
%11 = getelementptr inbounds %"char[]", %"char[]"* %10, i32 0, i32 1
|
||||
%12 = load i64, i64* %11, align 8
|
||||
%lt = icmp ult i64 0, %12
|
||||
%13 = zext i1 %lt to i8
|
||||
store i8 %13, i8* %0, align 1
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: x64-darwin
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
|
||||
53
test/test_suite/errors/macro_err.c3t
Normal file
53
test/test_suite/errors/macro_err.c3t
Normal file
@@ -0,0 +1,53 @@
|
||||
// #target: x64-darwin
|
||||
module test;
|
||||
fn int! abc()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
macro test()
|
||||
{
|
||||
return abc()?;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
libc::printf("%d\n", @test() ?? 2);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
define i64 @test.abc(i32* %0) #0 {
|
||||
entry:
|
||||
%reterr = alloca i64, align 8
|
||||
store i32 1, i32* %0, align 4
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%error_var = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%0 = call i64 @test.abc(i32* %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %error
|
||||
|
||||
error: ; preds = %entry
|
||||
store i64 %0, i64* %error_var, align 8
|
||||
br label %guard_block
|
||||
|
||||
after.errcheck: ; preds = %entry
|
||||
br label %noerr_block
|
||||
|
||||
guard_block: ; preds = %error
|
||||
ret void
|
||||
|
||||
noerr_block: ; preds = %after.errcheck
|
||||
%1 = load i32, i32* %retparam, align 4
|
||||
br label %phi_block
|
||||
|
||||
phi_block: ; preds = %noerr_block
|
||||
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %1)
|
||||
ret void
|
||||
}
|
||||
58
test/test_suite/errors/macro_err2.c3t
Normal file
58
test/test_suite/errors/macro_err2.c3t
Normal file
@@ -0,0 +1,58 @@
|
||||
// #target: x64-darwin
|
||||
module test;
|
||||
optenum Tester { FOO }
|
||||
|
||||
fn int! abc()
|
||||
{
|
||||
return Tester.FOO!;
|
||||
}
|
||||
macro test()
|
||||
{
|
||||
defer libc::printf("Test2\n");
|
||||
return abc();
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
defer libc::printf("Test1\n");
|
||||
libc::printf("%d\n", @test() ?? 2);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i64 @test.abc(i32* %0) #0 {
|
||||
entry:
|
||||
ret i64 ptrtoint ([1 x i8*]* @"test.Tester$elements" to i64)
|
||||
}
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%blockret = alloca i32, align 4
|
||||
%retparam = alloca i32, align 4
|
||||
%0 = call i64 @test.abc(i32* %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %opt_block_cleanup
|
||||
|
||||
after.errcheck: ; preds = %entry
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
|
||||
%2 = load i32, i32* %retparam, align 4
|
||||
store i32 %2, i32* %blockret, align 4
|
||||
br label %expr_block.exit
|
||||
|
||||
opt_block_cleanup: ; preds = %entry
|
||||
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.2, i32 0, i32 0))
|
||||
br label %else_block
|
||||
|
||||
expr_block.exit: ; preds = %after.errcheck
|
||||
%4 = load i32, i32* %blockret, align 4
|
||||
br label %phi_block
|
||||
|
||||
else_block: ; preds = %opt_block_cleanup
|
||||
br label %phi_block
|
||||
|
||||
phi_block: ; preds = %else_block, %expr_block.exit
|
||||
%val = phi i32 [ %4, %expr_block.exit ], [ 2, %else_block ]
|
||||
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %val)
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.3, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
36
test/test_suite/errors/macro_err3.c3t
Normal file
36
test/test_suite/errors/macro_err3.c3t
Normal file
@@ -0,0 +1,36 @@
|
||||
// #target: x64-darwin
|
||||
module test;
|
||||
optenum Tester { FOO }
|
||||
|
||||
|
||||
macro test()
|
||||
{
|
||||
defer libc::printf("Test2\n");
|
||||
return Tester.FOO!;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
defer libc::printf("Test1\n");
|
||||
libc::printf("%d\n", @test() ?? 2);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%blockret = alloca i32, align 4
|
||||
br label %opt_block_cleanup
|
||||
|
||||
opt_block_cleanup: ; preds = %entry
|
||||
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.2, i32 0, i32 0))
|
||||
br label %else_block
|
||||
|
||||
else_block: ; preds = %opt_block_cleanup
|
||||
br label %phi_block
|
||||
|
||||
phi_block: ; preds = %else_block
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 2)
|
||||
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.3, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
13
test/test_suite/errors/no_common.c3
Normal file
13
test/test_suite/errors/no_common.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
fn int! abc()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
macro test()
|
||||
{
|
||||
abc()?;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
@test() ?? 2; // #error: Cannot find a common type for 'void' and 'int'
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// #target: x64-darwin
|
||||
|
||||
module test;
|
||||
|
||||
fn void tester()
|
||||
|
||||
@@ -49,26 +49,16 @@ fn void main()
|
||||
define i64 @demo.divide(double* %0, i32 %1, i32 %2) #0 {
|
||||
entry:
|
||||
%reterr = alloca i64, align 8
|
||||
%reterr1 = alloca i64, align 8
|
||||
%eq = icmp eq i32 %2, 0
|
||||
br i1 %eq, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %entry
|
||||
store i64 ptrtoint ([1 x i8*]* @"demo.MathError$elements" to i64), i64* %reterr, align 8
|
||||
br label %err_retblock
|
||||
|
||||
postfailed: ; No predecessors!
|
||||
store double undef, double* %0, align 8
|
||||
ret i64 0
|
||||
|
||||
err_retblock: ; preds = %if.then
|
||||
%3 = load i64, i64* %reterr, align 8
|
||||
ret i64 %3
|
||||
ret i64 ptrtoint ([1 x i8*]* @"demo.MathError$elements" to i64)
|
||||
|
||||
if.exit: ; preds = %entry
|
||||
%sifp = sitofp i32 %1 to double
|
||||
%sifp2 = sitofp i32 %2 to double
|
||||
%fdiv = fdiv double %sifp, %sifp2
|
||||
%sifp1 = sitofp i32 %2 to double
|
||||
%fdiv = fdiv double %sifp, %sifp1
|
||||
store double %fdiv, double* %0, align 8
|
||||
ret i64 0
|
||||
}
|
||||
@@ -77,6 +67,7 @@ define i64 @demo.testMayError() #0 {
|
||||
entry:
|
||||
%error_var = alloca i64, align 8
|
||||
%retparam = alloca double, align 8
|
||||
%reterr = alloca i64, align 8
|
||||
%0 = call i32 @demo.foo()
|
||||
%1 = call i32 @demo.bar()
|
||||
%2 = call i64 @demo.divide(double* %retparam, i32 %0, i32 %1)
|
||||
@@ -122,6 +113,7 @@ after.errcheck: ; preds = %entry
|
||||
br label %after_assign
|
||||
|
||||
after_assign: ; preds = %after.errcheck, %error
|
||||
store i64 0, i64* %err, align 8
|
||||
br label %testblock
|
||||
|
||||
testblock: ; preds = %after_assign
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// #target: x64-darwin
|
||||
module foo;
|
||||
extern fn void puts(char *);
|
||||
|
||||
fn void foo1()
|
||||
{
|
||||
puts("foo1");
|
||||
}
|
||||
|
||||
module foo2;
|
||||
import foo;
|
||||
fn void foo2()
|
||||
{
|
||||
foo::puts("foo2");
|
||||
}
|
||||
module bar;
|
||||
import foo2;
|
||||
macro bar1(#test) @noscope
|
||||
{
|
||||
defer foo2::foo2();
|
||||
#test;
|
||||
#test;
|
||||
}
|
||||
|
||||
module baz;
|
||||
import foo;
|
||||
import bar;
|
||||
extern fn void printf(char *, ...);
|
||||
fn void main()
|
||||
{
|
||||
var $foo = 1;
|
||||
@bar::bar1(foo::foo1());
|
||||
@bar::bar1($foo += 1);
|
||||
printf("End: %d\n", $foo);
|
||||
}
|
||||
|
||||
/* #expect: baz.ll
|
||||
|
||||
declare void @foo2.foo2()
|
||||
declare void @foo.foo1()
|
||||
|
||||
define void @baz.main() #0 {
|
||||
entry:
|
||||
call void @foo.foo1()
|
||||
call void @foo.foo1()
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 3)
|
||||
call void @foo2.foo2()
|
||||
call void @foo2.foo2()
|
||||
ret void
|
||||
}
|
||||
@@ -17,7 +17,7 @@ fn void test()
|
||||
|
||||
fn void test_line()
|
||||
{
|
||||
defer defer test1();
|
||||
defer { defer test1(); }
|
||||
}
|
||||
|
||||
// #expect: defer_in_defer.ll
|
||||
|
||||
5
test/test_suite/statements/do_without_compound.c3
Normal file
5
test/test_suite/statements/do_without_compound.c3
Normal file
@@ -0,0 +1,5 @@
|
||||
fn void test1()
|
||||
{
|
||||
do test1(); while(1); // #error: A do loop must use { } around its body
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user