mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix in nested block handling. @maydiscard and @nodiscard annotations. If the common type of int[x] and int[y] is int[]
This commit is contained in:
committed by
Christoffer Lerno
parent
4beb7eff8f
commit
6cf3c9f46b
@@ -208,14 +208,14 @@ fn void DynamicArenaAllocator.destroy(DynamicArenaAllocator* this)
|
|||||||
while (page)
|
while (page)
|
||||||
{
|
{
|
||||||
DynamicArenaPage* next_page = page.prev_arena;
|
DynamicArenaPage* next_page = page.prev_arena;
|
||||||
this.backing_allocator.free(page);
|
this.backing_allocator.free(page)!!;
|
||||||
page = next_page;
|
page = next_page;
|
||||||
}
|
}
|
||||||
page = this.unused_page;
|
page = this.unused_page;
|
||||||
while (page)
|
while (page)
|
||||||
{
|
{
|
||||||
DynamicArenaPage* next_page = page.prev_arena;
|
DynamicArenaPage* next_page = page.prev_arena;
|
||||||
this.backing_allocator.free(page);
|
this.backing_allocator.free(page)!!;
|
||||||
page = next_page;
|
page = next_page;
|
||||||
}
|
}
|
||||||
this.page = null;
|
this.page = null;
|
||||||
@@ -297,7 +297,7 @@ private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, u
|
|||||||
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
|
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
|
||||||
if (catch err = page)
|
if (catch err = page)
|
||||||
{
|
{
|
||||||
this.backing_allocator.free(mem);
|
this.backing_allocator.free(mem)?;
|
||||||
return err!;
|
return err!;
|
||||||
}
|
}
|
||||||
page.memory = mem;
|
page.memory = mem;
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ fn void String.destroy(String* str)
|
|||||||
if (!*str) return;
|
if (!*str) return;
|
||||||
StringData* data = str.data();
|
StringData* data = str.data();
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
data.allocator.free(data);
|
data.allocator.free(data)!!;
|
||||||
*str = (String)null;
|
*str = (String)null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ private fn void! etoa(PrintParam* param, FloatType value)
|
|||||||
if (minwidth)
|
if (minwidth)
|
||||||
{
|
{
|
||||||
// output the exponential symbol
|
// output the exponential symbol
|
||||||
param.out(param.flags.uppercase ? 'E' : 'e');
|
param.out(param.flags.uppercase ? 'E' : 'e')?;
|
||||||
// output the exponent value
|
// output the exponent value
|
||||||
param.flags = { .zeropad = true, .plus = true };
|
param.flags = { .zeropad = true, .plus = true };
|
||||||
param.width = minwidth - 1;
|
param.width = minwidth - 1;
|
||||||
@@ -653,7 +653,7 @@ private fn NtoaType int_from_variant(variant arg, bool *is_neg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn usize! printf(char[] format, args...)
|
fn usize! printf(char[] format, args...) @maydiscard
|
||||||
{
|
{
|
||||||
return vsnprintf(&out_putchar_fn, " ", format, args);
|
return vsnprintf(&out_putchar_fn, " ", format, args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -458,6 +458,8 @@ typedef struct
|
|||||||
bool attr_noinline : 1;
|
bool attr_noinline : 1;
|
||||||
bool attr_extname : 1;
|
bool attr_extname : 1;
|
||||||
bool attr_naked : 1;
|
bool attr_naked : 1;
|
||||||
|
bool attr_nodiscard : 1;
|
||||||
|
bool attr_maydiscard: 1;
|
||||||
};
|
};
|
||||||
TypeInfoId type_parent;
|
TypeInfoId type_parent;
|
||||||
FunctionSignature function_signature;
|
FunctionSignature function_signature;
|
||||||
@@ -498,6 +500,8 @@ typedef struct
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
bool attr_noreturn : 1;
|
bool attr_noreturn : 1;
|
||||||
|
bool attr_nodiscard : 1;
|
||||||
|
bool attr_maydiscard : 1;
|
||||||
};
|
};
|
||||||
TypeInfoId type_parent; // May be 0
|
TypeInfoId type_parent; // May be 0
|
||||||
TypeInfoId rtype; // May be 0
|
TypeInfoId rtype; // May be 0
|
||||||
@@ -687,6 +691,7 @@ typedef struct
|
|||||||
bool is_builtin : 1;
|
bool is_builtin : 1;
|
||||||
bool is_func_ref : 1;
|
bool is_func_ref : 1;
|
||||||
bool attr_pure : 1;
|
bool attr_pure : 1;
|
||||||
|
bool result_unused : 1;
|
||||||
AstId body;
|
AstId body;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -808,16 +813,27 @@ typedef struct
|
|||||||
} ExprBodyExpansion;
|
} ExprBodyExpansion;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void *block_return_exit;
|
||||||
|
void *block_failable_exit;
|
||||||
|
void *block_error_var;
|
||||||
|
void *block_return_out;
|
||||||
|
} BlockExit;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
AstId first_stmt;
|
AstId first_stmt;
|
||||||
|
BlockExit **block_exit_ref;
|
||||||
} ExprFuncBlock;
|
} ExprFuncBlock;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
AstId first_stmt;
|
AstId first_stmt;
|
||||||
Expr **args;
|
Expr **args;
|
||||||
Decl **params;
|
Decl **params;
|
||||||
|
BlockExit **block_exit;
|
||||||
} ExprMacroBlock;
|
} ExprMacroBlock;
|
||||||
|
|
||||||
|
|
||||||
@@ -982,6 +998,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
Expr *expr; // May be NULL
|
Expr *expr; // May be NULL
|
||||||
AstId cleanup;
|
AstId cleanup;
|
||||||
|
BlockExit** block_exit_ref; // For block exits
|
||||||
} AstReturnStmt;
|
} AstReturnStmt;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -1412,6 +1429,7 @@ typedef struct SemaContext_
|
|||||||
uint32_t original_inline_line;
|
uint32_t original_inline_line;
|
||||||
Decl **yield_params;
|
Decl **yield_params;
|
||||||
Ast *yield_body;
|
Ast *yield_body;
|
||||||
|
BlockExit** block_exit_ref;
|
||||||
Type *expected_block_type;
|
Type *expected_block_type;
|
||||||
Ast **returns;
|
Ast **returns;
|
||||||
// Reusable returns cache.
|
// Reusable returns cache.
|
||||||
|
|||||||
@@ -701,6 +701,8 @@ typedef enum
|
|||||||
ATTRIBUTE_OPERATOR,
|
ATTRIBUTE_OPERATOR,
|
||||||
ATTRIBUTE_PURE,
|
ATTRIBUTE_PURE,
|
||||||
ATTRIBUTE_REFLECT,
|
ATTRIBUTE_REFLECT,
|
||||||
|
ATTRIBUTE_MAYDISCARD,
|
||||||
|
ATTRIBUTE_NODISCARD,
|
||||||
ATTRIBUTE_NONE,
|
ATTRIBUTE_NONE,
|
||||||
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
|
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
|
||||||
} AttributeType;
|
} AttributeType;
|
||||||
|
|||||||
@@ -65,6 +65,20 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type)
|
|||||||
{
|
{
|
||||||
if (linker_type == LINKER_CC) return;
|
if (linker_type == LINKER_CC) return;
|
||||||
//add_arg("/MACHINE:X64");
|
//add_arg("/MACHINE:X64");
|
||||||
|
switch (active_target.debug_info)
|
||||||
|
{
|
||||||
|
case DEBUG_INFO_NOT_SET:
|
||||||
|
break;
|
||||||
|
case DEBUG_INFO_NONE:
|
||||||
|
add_arg("/DEBUG:NONE");
|
||||||
|
break;
|
||||||
|
case DEBUG_INFO_LINE_TABLES:
|
||||||
|
case DEBUG_INFO_FULL:
|
||||||
|
add_arg("/DEBUG:FULL");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
if (active_target.win.sdk)
|
if (active_target.win.sdk)
|
||||||
{
|
{
|
||||||
add_arg(str_printf("/LIBPATH:%s", active_target.win.sdk));
|
add_arg(str_printf("/LIBPATH:%s", active_target.win.sdk));
|
||||||
|
|||||||
@@ -4943,7 +4943,7 @@ static inline void gencontext_emit_expression_list_expr(GenContext *context, BEV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, AstId current)
|
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit)
|
||||||
{
|
{
|
||||||
// First case - an empty block
|
// First case - an empty block
|
||||||
if (!current)
|
if (!current)
|
||||||
@@ -4954,25 +4954,26 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
|||||||
|
|
||||||
Type *type_lowered = type_lowering(type);
|
Type *type_lowered = type_lowering(type);
|
||||||
LLVMValueRef old_ret_out = context->return_out;
|
LLVMValueRef old_ret_out = context->return_out;
|
||||||
LLVMBasicBlockRef saved_block_return_exit = context->block_return_exit;
|
|
||||||
LLVMBasicBlockRef saved_block_failable_exit = context->block_failable_exit;
|
|
||||||
LLVMValueRef saved_block_error = context->block_error_var;
|
|
||||||
context->in_block++;
|
context->in_block++;
|
||||||
|
|
||||||
LLVMBasicBlockRef expr_block = llvm_basic_block_new(context, "expr_block.exit");
|
|
||||||
context->block_return_exit = expr_block;
|
|
||||||
|
|
||||||
LLVMValueRef return_out = NULL;
|
|
||||||
LLVMValueRef error_out = context->error_var;
|
LLVMValueRef error_out = context->error_var;
|
||||||
LLVMBasicBlockRef error_block = context->catch_block;
|
LLVMBasicBlockRef error_block = context->catch_block;
|
||||||
|
LLVMValueRef return_out = NULL;
|
||||||
|
LLVMBasicBlockRef expr_block = llvm_basic_block_new(context, "expr_block.exit");
|
||||||
|
|
||||||
|
BlockExit exit = {
|
||||||
|
.block_return_exit = expr_block,
|
||||||
|
.block_failable_exit = error_block,
|
||||||
|
.block_error_var = error_out,
|
||||||
|
.block_return_out = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
*block_exit= &exit;
|
||||||
|
|
||||||
if (type_no_fail(type_lowered) != type_void)
|
if (type_no_fail(type_lowered) != type_void)
|
||||||
{
|
{
|
||||||
return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
|
exit.block_return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
|
||||||
}
|
}
|
||||||
context->block_error_var = error_out;
|
|
||||||
context->block_failable_exit = error_block;
|
|
||||||
context->return_out = return_out;
|
|
||||||
context->error_var = NULL;
|
context->error_var = NULL;
|
||||||
context->catch_block = NULL;
|
context->catch_block = NULL;
|
||||||
|
|
||||||
@@ -5013,7 +5014,7 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
|||||||
// Optimization, emit directly to value
|
// Optimization, emit directly to value
|
||||||
llvm_emit_expr(context, be_value, ret_expr);
|
llvm_emit_expr(context, be_value, ret_expr);
|
||||||
// And remove the alloca
|
// And remove the alloca
|
||||||
LLVMInstructionEraseFromParent(context->return_out);
|
LLVMInstructionEraseFromParent(exit.block_return_out);
|
||||||
goto DONE;
|
goto DONE;
|
||||||
|
|
||||||
} while (0);
|
} while (0);
|
||||||
@@ -5034,9 +5035,9 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
|||||||
// Emit the exit block.
|
// Emit the exit block.
|
||||||
llvm_emit_block(context, expr_block);
|
llvm_emit_block(context, expr_block);
|
||||||
|
|
||||||
if (return_out)
|
if (exit.block_return_out)
|
||||||
{
|
{
|
||||||
llvm_value_set_address_abi_aligned(be_value, return_out, type_lowered);
|
llvm_value_set_address_abi_aligned(be_value, exit.block_return_out, type_lowered);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -5047,16 +5048,13 @@ DONE:
|
|||||||
context->return_out = old_ret_out;
|
context->return_out = old_ret_out;
|
||||||
context->catch_block = error_block;
|
context->catch_block = error_block;
|
||||||
context->error_var = error_out;
|
context->error_var = error_out;
|
||||||
context->block_return_exit = saved_block_return_exit;
|
|
||||||
context->block_failable_exit = saved_block_failable_exit;
|
|
||||||
context->block_error_var = saved_block_error;
|
|
||||||
context->in_block--;
|
context->in_block--;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr)
|
static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr)
|
||||||
{
|
{
|
||||||
llvm_emit_return_block(context, be_value, expr->type, expr->expr_block.first_stmt);
|
llvm_emit_return_block(context, be_value, expr->type, expr->expr_block.first_stmt, expr->expr_block.block_exit_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value, Expr *expr)
|
static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value, Expr *expr)
|
||||||
@@ -5098,7 +5096,8 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
|||||||
llvm_emit_expr(context, &value, expr->macro_block.args[i]);
|
llvm_emit_expr(context, &value, expr->macro_block.args[i]);
|
||||||
llvm_store_decl_raw(context, decl, llvm_load_value_store(context, &value));
|
llvm_store_decl_raw(context, decl, llvm_load_value_store(context, &value));
|
||||||
}
|
}
|
||||||
llvm_emit_return_block(context, be_value, expr->type, expr->macro_block.first_stmt);
|
|
||||||
|
llvm_emit_return_block(context, be_value, expr->type, expr->macro_block.first_stmt, expr->macro_block.block_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMValueRef llvm_emit_call_intrinsic(GenContext *context, unsigned intrinsic, LLVMTypeRef *types, unsigned type_count,
|
LLVMValueRef llvm_emit_call_intrinsic(GenContext *context, unsigned intrinsic, LLVMTypeRef *types, unsigned type_count,
|
||||||
|
|||||||
@@ -437,7 +437,6 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
|
|||||||
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry");
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry");
|
||||||
c->current_block = entry;
|
c->current_block = entry;
|
||||||
c->current_block_is_target = true;
|
c->current_block_is_target = true;
|
||||||
c->block_return_exit = NULL;
|
|
||||||
c->in_block = 0;
|
c->in_block = 0;
|
||||||
c->builder = LLVMCreateBuilderInContext(c->context);
|
c->builder = LLVMCreateBuilderInContext(c->context);
|
||||||
LLVMPositionBuilderAtEnd(c->builder, entry);
|
LLVMPositionBuilderAtEnd(c->builder, entry);
|
||||||
|
|||||||
@@ -99,9 +99,6 @@ typedef struct
|
|||||||
Module *code_module;
|
Module *code_module;
|
||||||
LLVMValueRef return_out;
|
LLVMValueRef return_out;
|
||||||
LLVMValueRef failable_out;
|
LLVMValueRef failable_out;
|
||||||
LLVMBasicBlockRef block_return_exit;
|
|
||||||
LLVMBasicBlockRef block_failable_exit;
|
|
||||||
LLVMValueRef block_error_var;
|
|
||||||
BEValue retval;
|
BEValue retval;
|
||||||
int in_block;
|
int in_block;
|
||||||
bool current_block_is_target : 1;
|
bool current_block_is_target : 1;
|
||||||
|
|||||||
@@ -228,8 +228,9 @@ static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast)
|
|||||||
|
|
||||||
LLVMBasicBlockRef error_return_block = NULL;
|
LLVMBasicBlockRef error_return_block = NULL;
|
||||||
LLVMValueRef error_out = NULL;
|
LLVMValueRef error_out = NULL;
|
||||||
c->error_var = c->block_error_var;
|
BlockExit *exit = *ast->return_stmt.block_exit_ref;
|
||||||
c->catch_block = c->block_failable_exit;
|
c->error_var = exit->block_error_var;
|
||||||
|
c->catch_block = exit->block_failable_exit;
|
||||||
|
|
||||||
LLVMBasicBlockRef err_cleanup_block = NULL;
|
LLVMBasicBlockRef err_cleanup_block = NULL;
|
||||||
Expr *ret_expr = ast->return_stmt.expr;
|
Expr *ret_expr = ast->return_stmt.expr;
|
||||||
@@ -250,21 +251,21 @@ static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast)
|
|||||||
POP_ERROR();
|
POP_ERROR();
|
||||||
|
|
||||||
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
||||||
if (c->return_out && return_value.value)
|
if (exit->block_return_out && return_value.value)
|
||||||
{
|
{
|
||||||
llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type));
|
llvm_store_value_aligned(c, exit->block_return_out, &return_value, type_alloca_alignment(return_value.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err_cleanup_block)
|
if (err_cleanup_block)
|
||||||
{
|
{
|
||||||
llvm_emit_br(c, c->block_return_exit);
|
llvm_emit_br(c, exit->block_return_exit);
|
||||||
llvm_emit_block(c, err_cleanup_block);
|
llvm_emit_block(c, err_cleanup_block);
|
||||||
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
|
||||||
llvm_emit_jmp(c, c->block_failable_exit);
|
llvm_emit_jmp(c, exit->block_failable_exit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
llvm_emit_jmp(c, c->block_return_exit);
|
llvm_emit_jmp(c, exit->block_return_exit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1163,6 +1163,8 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
|||||||
ATTR_MEMBER,
|
ATTR_MEMBER,
|
||||||
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
|
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
|
||||||
[ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL,
|
[ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL,
|
||||||
|
[ATTRIBUTE_NODISCARD] = ATTR_FUNC | ATTR_MACRO,
|
||||||
|
[ATTRIBUTE_MAYDISCARD] = ATTR_FUNC | ATTR_MACRO,
|
||||||
[ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT,
|
[ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT,
|
||||||
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
|
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
|
||||||
[ATTRIBUTE_USED] = (AttributeDomain)~ATTR_CALL,
|
[ATTRIBUTE_USED] = (AttributeDomain)~ATTR_CALL,
|
||||||
@@ -1340,6 +1342,22 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
|||||||
decl->func_decl.attr_noinline = true;
|
decl->func_decl.attr_noinline = true;
|
||||||
decl->func_decl.attr_inline = false;
|
decl->func_decl.attr_inline = false;
|
||||||
break;
|
break;
|
||||||
|
case ATTRIBUTE_NODISCARD:
|
||||||
|
if (domain == ATTR_MACRO)
|
||||||
|
{
|
||||||
|
decl->macro_decl.attr_nodiscard = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
decl->func_decl.attr_nodiscard = true;
|
||||||
|
break;
|
||||||
|
case ATTRIBUTE_MAYDISCARD:
|
||||||
|
if (domain == ATTR_MACRO)
|
||||||
|
{
|
||||||
|
decl->macro_decl.attr_maydiscard = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
decl->func_decl.attr_maydiscard = true;
|
||||||
|
break;
|
||||||
case ATTRIBUTE_INLINE:
|
case ATTRIBUTE_INLINE:
|
||||||
decl->func_decl.attr_inline = true;
|
decl->func_decl.attr_inline = true;
|
||||||
decl->func_decl.attr_noinline = false;
|
decl->func_decl.attr_noinline = false;
|
||||||
@@ -1689,9 +1707,27 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
|||||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FUNC)) return decl_poison(decl);
|
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FUNC)) return decl_poison(decl);
|
||||||
|
|
||||||
Type *func_type = sema_analyse_function_signature(context, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true);
|
Type *func_type = sema_analyse_function_signature(context, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true);
|
||||||
|
|
||||||
decl->type = func_type;
|
decl->type = func_type;
|
||||||
if (!func_type) return decl_poison(decl);
|
if (!func_type) return decl_poison(decl);
|
||||||
|
TypeInfo *rtype_info = type_infoptr(decl->func_decl.function_signature.returntype);
|
||||||
|
assert(rtype_info);
|
||||||
|
Type *rtype = rtype_info->type->canonical;
|
||||||
|
if (decl->func_decl.attr_nodiscard)
|
||||||
|
{
|
||||||
|
if (rtype == type_void)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on functions returning 'void'.");
|
||||||
|
return decl_poison(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (decl->func_decl.attr_maydiscard)
|
||||||
|
{
|
||||||
|
if (!type_is_failable(rtype))
|
||||||
|
{
|
||||||
|
SEMA_ERROR(rtype_info, "@maydiscard can only be used on functions returning optional values.");
|
||||||
|
return decl_poison(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (decl->func_decl.type_parent)
|
if (decl->func_decl.type_parent)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_method(context, decl)) return decl_poison(decl);
|
if (!sema_analyse_method(context, decl)) return decl_poison(decl);
|
||||||
@@ -1749,9 +1785,28 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
|||||||
|
|
||||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_MACRO)) return decl_poison(decl);
|
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_MACRO)) return decl_poison(decl);
|
||||||
|
|
||||||
|
if (decl->macro_decl.rtype)
|
||||||
TypeInfo *rtype = type_infoptr(decl->macro_decl.rtype);
|
{
|
||||||
if (decl->macro_decl.rtype && !sema_resolve_type_info(context, rtype)) return decl_poison(decl);
|
TypeInfo *rtype_info = type_infoptr(decl->macro_decl.rtype);
|
||||||
|
if (!sema_resolve_type_info(context, rtype_info)) return decl_poison(decl);
|
||||||
|
Type *rtype = rtype_info->type;
|
||||||
|
if (decl->macro_decl.attr_nodiscard)
|
||||||
|
{
|
||||||
|
if (rtype == type_void)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on macros returning 'void'.");
|
||||||
|
return decl_poison(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (decl->macro_decl.attr_maydiscard)
|
||||||
|
{
|
||||||
|
if (!type_is_failable(rtype))
|
||||||
|
{
|
||||||
|
SEMA_ERROR(rtype_info, "@maydiscard can only be used on macros returning optional values.");
|
||||||
|
return decl_poison(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
decl->macro_decl.unit = context->unit;
|
decl->macro_decl.unit = context->unit;
|
||||||
Decl **parameters = decl->macro_decl.parameters;
|
Decl **parameters = decl->macro_decl.parameters;
|
||||||
unsigned param_count = vec_size(parameters);
|
unsigned param_count = vec_size(parameters);
|
||||||
|
|||||||
@@ -1611,10 +1611,26 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Funct
|
|||||||
SEMA_ERROR(expr, "Only '@pure' functions may be called, you can override this with an attribute.");
|
SEMA_ERROR(expr, "Only '@pure' functions may be called, you can override this with an attribute.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_unused = expr->call_expr.result_unused;
|
||||||
if (!sema_expr_analyse_call_invocation(context, expr, callee, &failable)) return false;
|
if (!sema_expr_analyse_call_invocation(context, expr, callee, &failable)) return false;
|
||||||
|
|
||||||
Type *rtype = prototype->rtype;
|
Type *rtype = prototype->rtype;
|
||||||
|
|
||||||
|
if (is_unused && rtype != type_void && decl && decl->decl_kind == DECL_FUNC)
|
||||||
|
{
|
||||||
|
if (decl->func_decl.attr_nodiscard)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(expr, "The result of the function must be used.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (type_is_failable(rtype) && !decl->func_decl.attr_maydiscard)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(expr, "The optional result of the macro must be used.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
expr->type = type_get_opt_fail(rtype, failable);
|
expr->type = type_get_opt_fail(rtype, failable);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1882,6 +1898,9 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
|||||||
macro_context.yield_context = context;
|
macro_context.yield_context = context;
|
||||||
macro_context.original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row;
|
macro_context.original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row;
|
||||||
|
|
||||||
|
BlockExit** block_exit_ref = MALLOCS(BlockExit*);
|
||||||
|
macro_context.block_exit_ref = block_exit_ref;
|
||||||
|
|
||||||
VECEACH(params, i)
|
VECEACH(params, i)
|
||||||
{
|
{
|
||||||
Decl *param = params[i];
|
Decl *param = params[i];
|
||||||
@@ -1944,7 +1963,32 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
|||||||
if (!sum_returns) return SCOPE_POP_ERROR();
|
if (!sum_returns) return SCOPE_POP_ERROR();
|
||||||
call_expr->type = type_get_opt_fail(sum_returns, failable);
|
call_expr->type = type_get_opt_fail(sum_returns, failable);
|
||||||
}
|
}
|
||||||
if (vec_size(macro_context.returns) == 1)
|
|
||||||
|
if (call_expr->call_expr.result_unused)
|
||||||
|
{
|
||||||
|
Type *type = call_expr->type;
|
||||||
|
if (type != type_void)
|
||||||
|
{
|
||||||
|
if (decl->macro_decl.attr_nodiscard)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(call_expr, "The result of the macro must be used.");
|
||||||
|
return SCOPE_POP_ERROR();
|
||||||
|
}
|
||||||
|
if (type_is_failable(type) && !decl->macro_decl.attr_maydiscard)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(call_expr, "The optional result of the macro must be used.");
|
||||||
|
return SCOPE_POP_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned returns_found = vec_size(macro_context.returns);
|
||||||
|
// We may have zero normal macro returns but the active scope still has a "jump end".
|
||||||
|
// In this case it is triggered by the @body()
|
||||||
|
if (!returns_found && macro_context.active_scope.jump_end)
|
||||||
|
{
|
||||||
|
is_no_return = true;
|
||||||
|
}
|
||||||
|
if (returns_found == 1)
|
||||||
{
|
{
|
||||||
Ast *ret = macro_context.returns[0];
|
Ast *ret = macro_context.returns[0];
|
||||||
Expr *result = ret ? ret->return_stmt.expr : NULL;
|
Expr *result = ret ? ret->return_stmt.expr : NULL;
|
||||||
@@ -1962,6 +2006,7 @@ 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.first_stmt = body->compound_stmt.first_stmt;
|
||||||
call_expr->macro_block.params = params;
|
call_expr->macro_block.params = params;
|
||||||
call_expr->macro_block.args = args;
|
call_expr->macro_block.args = args;
|
||||||
|
call_expr->macro_block.block_exit = block_exit_ref;
|
||||||
EXIT:
|
EXIT:
|
||||||
assert(context->active_scope.defer_last == context->active_scope.defer_start);
|
assert(context->active_scope.defer_last == context->active_scope.defer_start);
|
||||||
context->active_scope = old_scope;
|
context->active_scope = old_scope;
|
||||||
@@ -2107,7 +2152,6 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
|||||||
SemaContext *context = macro_context->yield_context;
|
SemaContext *context = macro_context->yield_context;
|
||||||
Decl **params = macro_context->yield_params;
|
Decl **params = macro_context->yield_params;
|
||||||
|
|
||||||
|
|
||||||
Expr *func_expr = exprptr(call_expr->function);
|
Expr *func_expr = exprptr(call_expr->function);
|
||||||
assert(func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION);
|
assert(func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION);
|
||||||
expr_replace(call, func_expr);
|
expr_replace(call, func_expr);
|
||||||
@@ -2115,6 +2159,7 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
|||||||
call->body_expansion_expr.declarations = macro_context->yield_params;
|
call->body_expansion_expr.declarations = macro_context->yield_params;
|
||||||
AstId last_defer = context->active_scope.defer_last;
|
AstId last_defer = context->active_scope.defer_last;
|
||||||
bool success;
|
bool success;
|
||||||
|
bool ends_in_jump;
|
||||||
SCOPE_START
|
SCOPE_START
|
||||||
|
|
||||||
if (macro_defer)
|
if (macro_defer)
|
||||||
@@ -2133,15 +2178,20 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
|||||||
Decl *param = params[i];
|
Decl *param = params[i];
|
||||||
if (!sema_add_local(context, param)) return SCOPE_POP_ERROR();
|
if (!sema_add_local(context, param)) return SCOPE_POP_ERROR();
|
||||||
}
|
}
|
||||||
call->body_expansion_expr.ast = ast_macro_copy(macro_context->yield_body);
|
Ast *ast = call->body_expansion_expr.ast = ast_macro_copy(macro_context->yield_body);
|
||||||
success = sema_analyse_statement(context, call->body_expansion_expr.ast);
|
success = sema_analyse_statement(context, ast);
|
||||||
|
assert(ast->ast_kind == AST_COMPOUND_STMT);
|
||||||
|
if (context->active_scope.jump_end)
|
||||||
|
{
|
||||||
|
macro_context->active_scope.jump_end = true;
|
||||||
|
}
|
||||||
if (first_defer)
|
if (first_defer)
|
||||||
{
|
{
|
||||||
first_defer->defer_stmt.prev_defer = 0;
|
first_defer->defer_stmt.prev_defer = 0;
|
||||||
context->active_scope.defer_last = last_defer;
|
context->active_scope.defer_last = last_defer;
|
||||||
}
|
}
|
||||||
SCOPE_END;
|
SCOPE_END;
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3473,6 +3523,7 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr)
|
|||||||
if (parent->expr_kind != EXPR_TYPEINFO)
|
if (parent->expr_kind != EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "'typeid' can only be used with types, not values");
|
SEMA_ERROR(expr, "'typeid' can only be used with types, not values");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr->type = type_typeid;
|
expr->type = type_typeid;
|
||||||
@@ -6439,6 +6490,10 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
|
|||||||
Ast **saved_returns = context_push_returns(context);
|
Ast **saved_returns = context_push_returns(context);
|
||||||
Type *stored_block_type = context->expected_block_type;
|
Type *stored_block_type = context->expected_block_type;
|
||||||
context->expected_block_type = infer_type;
|
context->expected_block_type = infer_type;
|
||||||
|
BlockExit **ref = MALLOCS(BlockExit*);
|
||||||
|
BlockExit **stored_block_exit = context->block_exit_ref;
|
||||||
|
context->block_exit_ref = ref;
|
||||||
|
expr->expr_block.block_exit_ref = ref;
|
||||||
SCOPE_START_WITH_FLAGS(SCOPE_EXPR_BLOCK)
|
SCOPE_START_WITH_FLAGS(SCOPE_EXPR_BLOCK)
|
||||||
|
|
||||||
context->block_return_defer = context->active_scope.defer_last;
|
context->block_return_defer = context->active_scope.defer_last;
|
||||||
@@ -6487,6 +6542,7 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
|
|||||||
context_pop_defers(context, &stmt->next);
|
context_pop_defers(context, &stmt->next);
|
||||||
SCOPE_END;
|
SCOPE_END;
|
||||||
context->expected_block_type = stored_block_type;
|
context->expected_block_type = stored_block_type;
|
||||||
|
context->block_exit_ref = stored_block_exit;
|
||||||
context_pop_returns(context, saved_returns);
|
context_pop_returns(context, saved_returns);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
statement->return_stmt.block_exit_ref = context->block_exit_ref;
|
||||||
statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, context->block_return_defer);
|
statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, context->block_return_defer);
|
||||||
vec_add(context->returns, statement);
|
vec_add(context->returns, statement);
|
||||||
return true;
|
return true;
|
||||||
@@ -706,10 +707,28 @@ static inline bool sema_analyse_declare_stmt(SemaContext *context, Ast *statemen
|
|||||||
return sema_analyse_var_decl(context, statement->declare_stmt, true);
|
return sema_analyse_var_decl(context, statement->declare_stmt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool expr_is_assign(Expr *expr)
|
||||||
|
{
|
||||||
|
switch (expr->expr_kind)
|
||||||
|
{
|
||||||
|
case EXPR_DECL:
|
||||||
|
case EXPR_BITASSIGN:
|
||||||
|
case EXPR_SLICE_ASSIGN:
|
||||||
|
return true;
|
||||||
|
case EXPR_BINARY:
|
||||||
|
return expr->binary_expr.operator >= BINARYOP_ASSIGN;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement)
|
static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, statement->expr_stmt)) return false;
|
Expr *expr = statement->expr_stmt;
|
||||||
return true;
|
if (expr->expr_kind == EXPR_CALL)
|
||||||
|
{
|
||||||
|
expr->call_expr.result_unused = true;
|
||||||
|
}
|
||||||
|
return sema_analyse_expr(context, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body)
|
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body)
|
||||||
|
|||||||
@@ -230,6 +230,8 @@ void symtab_init(uint32_t capacity)
|
|||||||
attribute_list[ATTRIBUTE_PURE] = kw_at_pure;
|
attribute_list[ATTRIBUTE_PURE] = kw_at_pure;
|
||||||
attribute_list[ATTRIBUTE_REFLECT] = KW_DEF("@reflect");
|
attribute_list[ATTRIBUTE_REFLECT] = KW_DEF("@reflect");
|
||||||
attribute_list[ATTRIBUTE_AUTOIMPORT] = KW_DEF("@autoimport");
|
attribute_list[ATTRIBUTE_AUTOIMPORT] = KW_DEF("@autoimport");
|
||||||
|
attribute_list[ATTRIBUTE_MAYDISCARD] = KW_DEF("@maydiscard");
|
||||||
|
attribute_list[ATTRIBUTE_NODISCARD] = KW_DEF("@nodiscard");
|
||||||
|
|
||||||
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1501,6 +1501,14 @@ Type *type_find_max_type(Type *type, Type *other)
|
|||||||
{
|
{
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
if (other->type_kind == TYPE_POINTER)
|
||||||
|
{
|
||||||
|
Type *other_pointer = other->pointer;
|
||||||
|
if (other_pointer->type_kind == TYPE_ARRAY && other_pointer->array.base->canonical == array_base)
|
||||||
|
{
|
||||||
|
return type_get_subarray(array_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (type->pointer->type_kind == TYPE_VECTOR)
|
if (type->pointer->type_kind == TYPE_VECTOR)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ fn void Summary.print(Summary *s, CFile out)
|
|||||||
// We don't have a native printf in C3 yet, so use libc,
|
// We don't have a native printf in C3 yet, so use libc,
|
||||||
// which is not all that nice for the strings but...
|
// which is not all that nice for the strings but...
|
||||||
char[] title = s.title ? *s.title : "missing";
|
char[] title = s.title ? *s.title : "missing";
|
||||||
libc::fprintf(out, "Summary({ .title = %.*s, .ok = %s})", (int)title.len, title.ptr, s.ok ? "true" : "false");
|
libc::fprintf(out, "Summary({ .title = %.*s, .ok = %s})", (int)title.len, title.ptr, s.ok ? (char*)"true" : (char*)"false");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool contains(char[] haystack, char[] needle)
|
fn bool contains(char[] haystack, char[] needle)
|
||||||
@@ -144,7 +144,7 @@ fn void main()
|
|||||||
bool! has_title = readWhetherTitleNonEmpty(url);
|
bool! has_title = readWhetherTitleNonEmpty(url);
|
||||||
// This looks a bit less than elegant, but as you see it's mostly due to having to
|
// This looks a bit less than elegant, but as you see it's mostly due to having to
|
||||||
// use printf here.
|
// use printf here.
|
||||||
libc::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? nameFromError(catch(has_title)), (has_title ?? false) ? "true" : "false");
|
libc::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? nameFromError(catch(has_title)), (has_title ?? false) ? (char*)"true" : (char*)"false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,8 +757,9 @@ err_retblock: ; preds = %error3, %error
|
|||||||
define i8* @test.bool_to_string(i8 zeroext %0) #0 {
|
define i8* @test.bool_to_string(i8 zeroext %0) #0 {
|
||||||
entry:
|
entry:
|
||||||
%1 = trunc i8 %0 to i1
|
%1 = trunc i8 %0 to i1
|
||||||
%ternary = select i1 %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.7, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.8, i32 0, i32 0)
|
%ternary = select i1 %1, %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.7, i32 0, i32 0), i64 4 }, %"char[]" { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.8, i32 0, i32 0), i64 5 }
|
||||||
ret i8* %ternary
|
%2 = extractvalue %"char[]" %ternary, 0
|
||||||
|
ret i8* %2
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ struct Bar
|
|||||||
int x;
|
int x;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! test1()
|
fn void! test1() @maydiscard
|
||||||
{
|
{
|
||||||
Bar! x = Foo.MY_VAL1!;
|
Bar! x = Foo.MY_VAL1!;
|
||||||
Bar y = x?;
|
Bar y = x?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! test2()
|
fn void! test2() @maydiscard
|
||||||
{
|
{
|
||||||
Bar! x = {};
|
Bar! x = {};
|
||||||
Bar y = x?;
|
Bar y = x?;
|
||||||
|
|||||||
@@ -87,17 +87,17 @@ loop.exit: ; preds = %loop.body
|
|||||||
br label %loop.body2
|
br label %loop.body2
|
||||||
|
|
||||||
loop.body2: ; preds = %loop.exit
|
loop.body2: ; preds = %loop.exit
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.13, i32 0, i32 0))
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.10, i32 0, i32 0))
|
||||||
store i32 3, i32* %i3, align 4
|
store i32 3, i32* %i3, align 4
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.14, i32 0, i32 0))
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.11, i32 0, i32 0))
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.15, i32 0, i32 0))
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.12, i32 0, i32 0))
|
||||||
%3 = load i32, i32* %i3, align 4
|
%3 = load i32, i32* %i3, align 4
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.16, i32 0, i32 0), i32 %3)
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.13, i32 0, i32 0), i32 %3)
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0))
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.14, i32 0, i32 0))
|
||||||
ret i64 0
|
ret i64 0
|
||||||
|
|
||||||
loop.exit4: ; No predecessors!
|
loop.exit4: ; No predecessors!
|
||||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.21, i32 0, i32 0))
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.15, i32 0, i32 0))
|
||||||
ret i64 0
|
ret i64 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,13 +13,13 @@ struct Bar
|
|||||||
int x;
|
int x;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! test1()
|
fn void! test1() @maydiscard
|
||||||
{
|
{
|
||||||
Bar! x = Foo.MY_VAL1!;
|
Bar! x = Foo.MY_VAL1!;
|
||||||
Bar y = x?;
|
Bar y = x?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! test2()
|
fn void! test2() @maydiscard
|
||||||
{
|
{
|
||||||
Bar! x = {};
|
Bar! x = {};
|
||||||
Bar y = x?;
|
Bar y = x?;
|
||||||
|
|||||||
@@ -87,17 +87,17 @@ loop.exit: ; preds = %loop.body
|
|||||||
br label %loop.body2
|
br label %loop.body2
|
||||||
|
|
||||||
loop.body2: ; preds = %loop.exit
|
loop.body2: ; preds = %loop.exit
|
||||||
call void (ptr, ...) @printf(ptr @.str.13)
|
call void (ptr, ...) @printf(ptr @.str.10)
|
||||||
store i32 3, ptr %i3, align 4
|
store i32 3, ptr %i3, align 4
|
||||||
call void (ptr, ...) @printf(ptr @.str.14)
|
call void (ptr, ...) @printf(ptr @.str.11)
|
||||||
call void (ptr, ...) @printf(ptr @.str.15)
|
call void (ptr, ...) @printf(ptr @.str.12)
|
||||||
%3 = load i32, ptr %i3, align 4
|
%3 = load i32, ptr %i3, align 4
|
||||||
call void (ptr, ...) @printf(ptr @.str.16, i32 %3)
|
call void (ptr, ...) @printf(ptr @.str.13, i32 %3)
|
||||||
call void (ptr, ...) @printf(ptr @.str.17)
|
call void (ptr, ...) @printf(ptr @.str.14)
|
||||||
ret i64 0
|
ret i64 0
|
||||||
|
|
||||||
loop.exit4: ; No predecessors!
|
loop.exit4: ; No predecessors!
|
||||||
call void (ptr, ...) @printf(ptr @.str.21)
|
call void (ptr, ...) @printf(ptr @.str.15)
|
||||||
ret i64 0
|
ret i64 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user