Make errors usable from other units. Order subarray elements correctly. Correct subarray -> pointer cast. Prevent unwrapping of catch in switch.

This commit is contained in:
Christoffer Lerno
2021-08-31 18:12:30 +02:00
parent 2ff5acc2a1
commit bb9e84d329
16 changed files with 820 additions and 151 deletions

View File

@@ -1,5 +1,9 @@
module std::io;
errtype IoError
{
FILE_NOT_FOUND
}
/*
extern File *stdin @cname(__stdinp);
extern File *stdout @cname(__stdoutp);

View File

@@ -714,6 +714,29 @@ void llvm_codegen_setup()
intrinsics_setup = true;
}
static void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
{
if (decl->module != c->code_module)
{
LLVMSetLinkage(value, LLVMLinkOnceODRLinkage);
LLVMSetVisibility(value, LLVMDefaultVisibility);
return;
}
switch (decl->visibility)
{
case VISIBLE_MODULE:
case VISIBLE_PUBLIC:
LLVMSetLinkage(value, LLVMLinkOnceODRLinkage);
LLVMSetVisibility(value, LLVMDefaultVisibility);
break;
case VISIBLE_EXTERN:
case VISIBLE_LOCAL:
LLVMSetVisibility(value, LLVMHiddenVisibility);
LLVMSetLinkage(value, LLVMLinkerPrivateLinkage);
break;
}
}
void gencontext_emit_introspection_type(GenContext *c, Decl *decl)
{
llvm_get_type(c, decl->type);
@@ -739,6 +762,7 @@ void gencontext_emit_introspection_type(GenContext *c, Decl *decl)
scratch_buffer_append("$elements");
LLVMValueRef enum_elements = LLVMAddGlobal(c->module, elements_type, scratch_buffer_to_string());
LLVMSetGlobalConstant(enum_elements, 1);
llvm_set_linkage(c, decl, enum_elements);
LLVMSetInitializer(enum_elements, LLVMConstNull(elements_type));
for (unsigned i = 0; i < elements; i++)
{
@@ -750,20 +774,8 @@ void gencontext_emit_introspection_type(GenContext *c, Decl *decl)
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(c, type_char), 1, false));
decl->type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
llvm_set_linkage(c, decl, global_name);
switch (decl->visibility)
{
case VISIBLE_MODULE:
case VISIBLE_PUBLIC:
LLVMSetLinkage(global_name, LLVMLinkOnceODRLinkage);
LLVMSetVisibility(global_name, LLVMDefaultVisibility);
break;
case VISIBLE_EXTERN:
case VISIBLE_LOCAL:
LLVMSetVisibility(global_name, LLVMHiddenVisibility);
LLVMSetLinkage(global_name, LLVMLinkerPrivateLinkage);
break;
}
}

View File

@@ -578,8 +578,8 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
if (offset < 16) return abi_type_new_plain(type_voidptr);
break;
case TYPE_SUBARRAY:
if (offset < 8) return abi_type_new_plain(type_ulong);
if (offset < 16) return abi_type_new_plain(type_voidptr);
if (offset < 8) return abi_type_new_plain(type_voidptr);
if (offset < 16) return abi_type_new_plain(type_ulong);
break;
case TYPE_ARRAY:
{

View File

@@ -578,12 +578,10 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
llvm_emit_arr_to_subarray_cast(c, value, to_type);
break;
case CAST_SAPTR:
llvm_value_fold_failable(c, value);
if (llvm_value_is_addr(value))
{
llvm_value_fold_failable(c, value);
value->value = llvm_emit_load_aligned(c, llvm_get_type(c, to_type),
LLVMBuildStructGEP(c->builder, value->value, 0, ""),
value->alignment, "");
value->value = LLVMBuildStructGEP(c->builder, value->value, 0, "");
}
else
{
@@ -2675,6 +2673,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
case CONST_ERR:
{
Decl *decl = expr->const_expr.err_val;
LLVMValueRef value;
if (decl)
{
@@ -2796,9 +2795,9 @@ void llvm_emit_subarray_pointer(GenContext *c, BEValue *subarray, BEValue *point
{
llvm_value_addr(c, subarray);
unsigned alignment = 0;
LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c, subarray->value, llvm_get_type(c, subarray->type), 0, subarray->alignment,
0, &alignment);
llvm_value_set_address_align(pointer, len_addr, type_get_ptr(subarray->type->array.base), alignment);
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c, subarray->value, llvm_get_type(c, subarray->type), 0, subarray->alignment,
0, &alignment);
llvm_value_set_address_align(pointer, pointer_addr, type_get_ptr(subarray->type->array.base), alignment);
}

View File

@@ -647,7 +647,10 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
// TODO // Fix typeid
break;
case DECL_ENUM:
llvm_emit_methods(context, decl->methods);
break;
case DECL_ERRTYPE:
gencontext_emit_introspection_type(context, decl);
llvm_emit_methods(context, decl->methods);
// TODO // Fix typeid
return;

View File

@@ -225,6 +225,7 @@ void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTy
void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignment, LLVMTypeRef coerced, LLVMValueRef value, LLVMTypeRef target_type);
void llvm_emit_function_body(GenContext *context, Decl *decl);
void llvm_emit_function_decl(GenContext *c, Decl *decl);
void gencontext_emit_introspection_type(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_call_intrinsic(GenContext *c, unsigned intrinsic_id, LLVMTypeRef *types, unsigned type_count, LLVMValueRef *values, unsigned arg_count);
void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type);
void llvm_emit_cond_br(GenContext *context, BEValue *value, LLVMBasicBlockRef then_block, LLVMBasicBlockRef else_block);

View File

@@ -2240,43 +2240,45 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T
}
break;
case DECL_ERRTYPE:
if (type == TOKEN_CONST_IDENT)
context_register_external_symbol(context, decl);
if (type == TOKEN_CONST_IDENT)
{
if (!sema_expr_analyse_enum_constant(expr, identifier_token, decl))
{
if (!sema_expr_analyse_enum_constant(expr, identifier_token, decl))
{
SEMA_ERROR(expr, "'%s' has no error value '%s'.", decl->name, name);
return false;
}
SEMA_ERROR(expr, "'%s' has no error value '%s'.", decl->name, name);
return false;
}
return true;
}
if (name == kw_elements)
{
expr_rewrite_to_int_const(expr, type_compint, vec_size(decl->enums.values));
return true;
}
if (name == kw_max)
{
Expr *max = enum_minmax_value(decl, BINARYOP_GT);
if (!max)
{
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
return true;
}
if (name == kw_elements)
expr_replace(expr, max);
return true;
}
if (name == kw_min)
{
Expr *min = enum_minmax_value(decl, BINARYOP_LT);
if (!min)
{
expr_rewrite_to_int_const(expr, type_compint, vec_size(decl->enums.values));
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
return true;
}
if (name == kw_max)
{
Expr *max = enum_minmax_value(decl, BINARYOP_GT);
if (!max)
{
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
return true;
}
expr_replace(expr, max);
return true;
}
if (name == kw_min)
{
Expr *min = enum_minmax_value(decl, BINARYOP_LT);
if (!min)
{
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
return true;
}
expr_replace(expr, min);
return true;
}
break;
expr_replace(expr, min);
return true;
}
break;
case DECL_UNION:
case DECL_STRUCT:
case DECL_DISTINCT:

View File

@@ -395,13 +395,23 @@ static void sema_remove_unwraps_from_try(Context *c, Expr *cond)
}
}
static inline bool sema_analyse_last_cond(Context *context, Expr *expr)
static inline bool sema_analyse_last_cond(Context *context, Expr *expr, bool may_unwrap)
{
switch (expr->expr_kind)
{
case EXPR_TRY_UNWRAP_CHAIN:
if (!may_unwrap)
{
SEMA_ERROR(expr, "Try unwrapping is only allowed inside of a 'while' or 'if' conditional.");
return false;
}
return sema_analyse_try_unwrap_chain(context, expr);
case EXPR_CATCH_UNWRAP:
if (!may_unwrap)
{
SEMA_ERROR(expr, "Catch unwrapping is only allowed inside of a 'while' or 'if' conditional, maybe catch(...) will do what you need?");
return false;
}
return sema_analyse_catch_unwrap(context, expr);
default:
return sema_analyse_expr(context, NULL, expr);
@@ -435,7 +445,7 @@ static inline bool sema_analyse_cond_list(Context *context, Expr *expr, bool may
if (!sema_analyse_expr(context, NULL, dexprs[i])) return false;
}
if (!sema_analyse_last_cond(context, dexprs[entries - 1])) return false;
if (!sema_analyse_last_cond(context, dexprs[entries - 1], may_unwrap)) return false;
expr_set_type(expr, dexprs[entries - 1]->type);
expr->resolve_status = RESOLVE_DONE;
@@ -454,12 +464,12 @@ static inline bool sema_analyse_cond_list(Context *context, Expr *expr, bool may
* @param cast_to_bool if the result is to be cast to bool after
* @return true if it passes analysis.
*/
static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_bool)
static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_bool, bool may_unwrap)
{
assert(expr->expr_kind == EXPR_COND && "Conditional expressions should always be of type EXPR_DECL_LIST");
// 1. Analyse the declaration list.
if (!sema_analyse_cond_list(context, expr, true)) return false;
if (!sema_analyse_cond_list(context, expr, may_unwrap)) return false;
// 2. If we get "void", either through a void call or an empty list,
// signal that.
@@ -537,7 +547,7 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
SCOPE_START_WITH_LABEL(statement->while_stmt.flow.label)
// 2. Analyze the condition
if (!sema_analyse_cond(context, cond, true))
if (!sema_analyse_cond(context, cond, true, true))
{
// 2a. In case of error, pop context and exit.
return SCOPE_POP_ERROR();
@@ -1320,7 +1330,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
Expr *cond = statement->if_stmt.cond;
SCOPE_OUTER_START
bool cast_to_bool = statement->if_stmt.then_body->ast_kind != AST_IF_CATCH_SWITCH_STMT;
success = sema_analyse_cond(context, cond, cast_to_bool);
success = sema_analyse_cond(context, cond, cast_to_bool, true);
Ast *then = statement->if_stmt.then_body;
bool then_has_braces = then->ast_kind == AST_COMPOUND_STMT || then->ast_kind == AST_IF_CATCH_SWITCH_STMT;
@@ -1966,7 +1976,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
if (statement->ast_kind == AST_SWITCH_STMT)
{
if (!sema_analyse_cond(context, cond, false)) return false;
if (!sema_analyse_cond(context, cond, false, false)) return false;
switch_type = VECLAST(cond->cond_expr)->type->canonical;
}
else

View File

@@ -0,0 +1,89 @@
// #target: x64-darwin
module defer1;
import std::io;
func void test(int x)
{
defer io::println();
defer io::print("A");
if (x == 1) return;
{
defer io::print("B");
if (x == 0) return;
}
io::print("!");
}
func void main()
{
test(1); // Prints "A"
test(0); // Prints "BA"
test(10); // Prints "B!A"
}
// #expect: defer1.ll
define void @defer1.test(i32 %0) #0 {
entry:
%x = alloca i32, align 4
store i32 %0, i32* %x, align 4
%1 = load i32, i32* %x, align 4
%eq = icmp eq i32 %1, 1
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
%2 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0))
br label %exit
exit: ; preds = %if.then
%3 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.1, i32 0, i32 0)) #1
br label %exit1
exit1: ; preds = %exit
ret void
if.exit: ; preds = %entry
%4 = load i32, i32* %x, align 4
%eq2 = icmp eq i32 %4, 0
br i1 %eq2, label %if.then3, label %if.exit7
if.then3: ; preds = %if.exit
%5 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.2, i32 0, i32 0))
br label %exit4
exit4: ; preds = %if.then3
%6 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
br label %exit5
exit5: ; preds = %exit4
%7 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i32 0, i32 0)) #1
br label %exit6
exit6: ; preds = %exit5
ret void
if.exit7: ; preds = %if.exit
%8 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
br label %exit8
exit8: ; preds = %if.exit7
%9 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
%10 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.7, i32 0, i32 0))
br label %exit9
exit9: ; preds = %exit8
%11 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.8, i32 0, i32 0)) #1
br label %exit10
exit10: ; preds = %exit9
ret void
}
; Function Attrs: nounwind
define void @main() #0 {
entry:
call void @defer1.test(i32 1)
call void @defer1.test(i32 0)
call void @defer1.test(i32 10)
ret void
}

View File

@@ -0,0 +1,245 @@
// #target: x64-darwin
module examples;
import std::io;
func void example_for()
{
// the for-loop is the same as C99.
for (int i = 0; i < 10; i++)
{
io::printf("%d\n", i);
}
// also equal
for (;;)
{
// ..
}
}
enum Height : uint
{
LOW = 0,
MEDIUM,
HIGH,
}
func void demo_enum(Height h)
{
switch (h)
{
case LOW:
case MEDIUM:
io::println("Not high");
// Implicit break.
case HIGH:
io::println("High");
}
// This also works
switch (h)
{
case LOW:
case MEDIUM:
io::println("Not high");
// Implicit break.
case Height.HIGH:
io::println("High");
}
// Completely empty cases are not allowed.
switch (h)
{
case LOW:
break; // Explicit break required, since switches can't be empty.
case MEDIUM:
io::println("Medium");
case HIGH:
break;
}
// special checking of switching on enum types
switch (h)
{
case LOW:
case MEDIUM:
case HIGH:
break;
default: // warning: default label in switch which covers all enumeration value
break;
}
// Using "nextcase" will fallthrough to the next case statement,
// and each case statement starts its own scope.
switch (h)
{
case LOW:
int a = 1;
io::println("A");
nextcase;
case MEDIUM:
int a = 2;
io::println("B");
nextcase;
case HIGH:
// a is not defined here
io::println("C");
}
}
// #expect: examples.ll
define void @examples.example_for() #0 {
entry:
%i = alloca i32, align 4
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%0 = load i32, i32* %i, align 4
%lt = icmp slt i32 %0, 10
br i1 %lt, label %for.body, label %for.exit
for.body: ; preds = %for.cond
%1 = load i32, i32* %i, align 4
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %1)
br label %for.inc
for.inc: ; preds = %for.body
%3 = load i32, i32* %i, align 4
%add = add i32 %3, 1
store i32 %add, i32* %i, align 4
br label %for.cond
for.exit: ; preds = %for.cond
br label %infiniteloop
infiniteloop: ; preds = %infiniteloop, %for.exit
br label %infiniteloop
}
; Function Attrs: nounwind
define void @examples.demo_enum(i32 %0) #0 {
entry:
%h = alloca i32, align 4
%switch = alloca i32, align 4
%switch2 = alloca i32, align 4
%switch7 = alloca i32, align 4
%switch13 = alloca i32, align 4
%switch17 = alloca i32, align 4
%a = alloca i32, align 4
%a21 = alloca i32, align 4
store i32 %0, i32* %h, align 4
%1 = load i32, i32* %h, align 4
store i32 %1, i32* %switch, align 4
br label %switch.entry
switch.entry: ; preds = %entry
%2 = load i32, i32* %switch, align 4
switch i32 %2, label %switch.exit [
i32 0, label %switch.case
i32 1, label %switch.case
i32 2, label %switch.case1
]
switch.case: ; preds = %switch.entry, %switch.entry
%3 = call i32 @"std::io.println"(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0)) #1
br label %switch.exit
switch.case1: ; preds = %switch.entry
%4 = call i32 @"std::io.println"(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0)) #1
br label %switch.exit
switch.exit: ; preds = %switch.case1, %switch.case, %switch.entry
%5 = load i32, i32* %h, align 4
store i32 %5, i32* %switch2, align 4
br label %switch.entry3
switch.entry3: ; preds = %switch.exit
%6 = load i32, i32* %switch2, align 4
switch i32 %6, label %switch.exit6 [
i32 0, label %switch.case4
i32 1, label %switch.case4
i32 2, label %switch.case5
]
switch.case4: ; preds = %switch.entry3, %switch.entry3
%7 = call i32 @"std::io.println"(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.3, i32 0, i32 0)) #1
br label %switch.exit6
switch.case5: ; preds = %switch.entry3
%8 = call i32 @"std::io.println"(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i32 0, i32 0)) #1
br label %switch.exit6
switch.exit6: ; preds = %switch.case5, %switch.case4, %switch.entry3
%9 = load i32, i32* %h, align 4
store i32 %9, i32* %switch7, align 4
br label %switch.entry8
switch.entry8: ; preds = %switch.exit6
%10 = load i32, i32* %switch7, align 4
switch i32 %10, label %switch.exit12 [
i32 0, label %switch.case9
i32 1, label %switch.case10
i32 2, label %switch.case11
]
switch.case9: ; preds = %switch.entry8
br label %switch.exit12
switch.case10: ; preds = %switch.entry8
%11 = call i32 @"std::io.println"(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0)) #1
br label %switch.exit12
switch.case11: ; preds = %switch.entry8
br label %switch.exit12
switch.exit12: ; preds = %switch.case11, %switch.case10, %switch.case9, %switch.entry8
%12 = load i32, i32* %h, align 4
store i32 %12, i32* %switch13, align 4
br label %switch.entry14
switch.entry14: ; preds = %switch.exit12
%13 = load i32, i32* %switch13, align 4
switch i32 %13, label %switch.default [
i32 0, label %switch.case15
i32 1, label %switch.case15
i32 2, label %switch.case15
]
switch.case15: ; preds = %switch.entry14, %switch.entry14, %switch.entry14
br label %switch.exit16
switch.default: ; preds = %switch.entry14
br label %switch.exit16
switch.exit16: ; preds = %switch.default, %switch.case15
%14 = load i32, i32* %h, align 4
store i32 %14, i32* %switch17, align 4
br label %switch.entry18
switch.entry18: ; preds = %switch.exit16
%15 = load i32, i32* %switch17, align 4
switch i32 %15, label %switch.exit23 [
i32 0, label %switch.case19
i32 1, label %switch.case20
i32 2, label %switch.case22
]
switch.case19: ; preds = %switch.entry18
store i32 1, i32* %a, align 4
%16 = call i32 @"std::io.println"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0)) #1
br label %switch.case20
switch.case20: ; preds = %switch.entry18, %switch.case19
store i32 2, i32* %a21, align 4
%17 = call i32 @"std::io.println"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.7, i32 0, i32 0)) #1
br label %switch.case22
switch.case22: ; preds = %switch.entry18, %switch.case20
%18 = call i32 @"std::io.println"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.8, i32 0, i32 0)) #1
br label %switch.exit23
switch.exit23: ; preds = %switch.case22, %switch.entry18
ret void
}

View File

@@ -0,0 +1,37 @@
// #target: x64-darwin
module demo;
define Callback = func int(char* text, int value);
func int my_callback(char* text, int value)
{
return 0;
}
Callback cb = &my_callback;
func void main()
{
int result = cb("demo", 123);
// ..
}
// #expect: demo.ll
define i32 @demo.my_callback(i8* %0, i32 %1) #0 {
entry:
%text = alloca i8*, align 8
%value = alloca i32, align 4
store i8* %0, i8** %text, align 8
store i32 %1, i32* %value, align 4
ret i32 0
}
define void @main() #0 {
entry:
%result = alloca i32, align 4
%0 = load i32 (i8*, i32)*, i32 (i8*, i32)** @demo.cb, align 8
%1 = call i32 %0(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), i32 123)
store i32 %1, i32* %result, align 4
ret void
}

View File

@@ -0,0 +1,176 @@
// #target: x64-darwin
module demo;
import std::io;
errtype MathError
{
DIVISION_BY_ZERO
}
func int foo() { return 123; }
func int bar() { return 0; }
func double! divide(int a, int b)
{
if (b == 0) return MathError.DIVISION_BY_ZERO!;
return (double)(a) / (double)(b);
}
// Rethrowing an error uses "!!" suffix
func void! testMayError()
{
divide(foo(), bar())!!;
}
func void main()
{
// ratio has a failable type.
double! ratio = divide(foo(), bar());
// Handle the error
if (catch err = ratio)
{
case MathError.DIVISION_BY_ZERO:
io::printf("Division by zero\n");
return;
default:
io::printf("Unexpected error!");
return;
}
// Flow typing makes "ratio"
// have the type double here.
io::printf("Ratio was %f\n", ratio);
}
// #expect: demo.ll
define i64 @demo.divide(double* %0, i32 %1, i32 %2) #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%reterr = alloca i64, align 8
%reterr1 = alloca i64, align 8
store i32 %1, i32* %a, align 4
store i32 %2, i32* %b, align 4
%3 = load i32, i32* %b, align 4
%eq = icmp eq i32 %3, 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
%4 = load i64, i64* %reterr, align 8
ret i64 %4
if.exit: ; preds = %entry
%5 = load i32, i32* %a, align 4
%sifp = sitofp i32 %5 to double
%6 = load i32, i32* %b, align 4
%sifp2 = sitofp i32 %6 to double
%fdiv = fdiv double %sifp, %sifp2
store double %fdiv, double* %0, align 8
ret i64 0
}
define i64 @demo.testMayError() #0 {
entry:
%error_var = alloca i64, align 8
%retparam = alloca double, align 8
%0 = call i32 @demo.foo()
%1 = call i32 @demo.bar()
%2 = call i64 @demo.divide(double* %retparam, i32 %0, i32 %1)
%not_err = icmp eq i64 %2, 0
br i1 %not_err, label %after.errcheck, label %error
error: ; preds = %entry
store i64 %2, i64* %error_var, align 8
br label %guard_block
after.errcheck: ; preds = %entry
%3 = load double, double* %retparam, align 8
br label %noerr_block
guard_block: ; preds = %error
%4 = load i64, i64* %error_var, align 8
ret i64 %4
noerr_block: ; preds = %after.errcheck
ret i64 0
}
define void @main() #0 {
entry:
%ratio = alloca double, align 8
%ratio.f = alloca i64, align 8
%retparam = alloca double, align 8
%err = alloca i64, align 8
%switch = 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)
%not_err = icmp eq i64 %2, 0
br i1 %not_err, label %after.errcheck, label %error
error: ; preds = %entry
store i64 %2, i64* %ratio.f, align 8
br label %after_assign
after.errcheck: ; preds = %entry
%3 = load double, double* %retparam, align 8
store double %3, double* %ratio, align 8
store i64 0, i64* %ratio.f, align 8
br label %after_assign
after_assign: ; preds = %after.errcheck, %error
br label %testblock
testblock: ; preds = %after_assign
%4 = load i64, i64* %ratio.f, align 8
%not_err1 = icmp eq i64 %4, 0
br i1 %not_err1, label %after_check, label %error2
error2: ; preds = %testblock
store i64 %4, i64* %err, align 8
br label %end_block
after_check: ; preds = %testblock
store i64 0, i64* %err, align 8
br label %end_block
end_block: ; preds = %after_check, %error2
%5 = load i64, i64* %err, align 8
%neq = icmp ne i64 %5, 0
br i1 %neq, label %if.then, label %if.exit
if.then: ; preds = %end_block
store i64 %5, i64* %switch, align 8
br label %switch.entry
switch.entry: ; preds = %if.then
%6 = load i64, i64* %switch, align 8
%eq = icmp eq i64 ptrtoint ([1 x i8*]* @"demo.MathError$elements" to i64), %6
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str, i32 0, i32 0))
ret void
next_if: ; preds = %switch.entry
br label %switch.default
switch.default: ; preds = %next_if
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.1, i32 0, i32 0))
ret void
if.exit: ; preds = %end_block
%9 = load double, double* %ratio, align 8
%10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2, i32 0, i32 0), double %9)
ret void
}

View File

@@ -0,0 +1,46 @@
define Callback = func int(char c);
struct Person {}
struct Company {}
enum Status : int
{
IDLE,
BUSY,
DONE,
}
struct MyData
{
char* name;
Callback open;
Callback close;
//Status status;
// named sub-structs (x.other.value)
struct other
{
int value;
int status; // ok, no name clash with other status
}
// anonymous sub-structs (x.value)
struct
{
int value;
int status; // error, name clash with other status in MyData
}
// anonymous union (x.person)
union
{
Person* person;
Company* company;
}
// named sub-unions (x.either.this)
union either
{
int this;
bool or;
char* that;
}
}

View File

@@ -33,12 +33,12 @@ func void test()
%4 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0
%5 = bitcast [3 x i32]* %varargslots to i32*
store i32* %5, i32** %4, align 8
%casttemp = bitcast %"int[]"* %vararg to { i64, i8* }*
%lo = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 0
%lo1 = load i64, i64* %lo, align 8
%hi = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 1
%hi2 = load i8*, i8** %hi, align 8
%6 = call i32 @sum_us(i64 %lo1, i8* %hi2)
%casttemp = bitcast %"int[]"* %vararg to { i8*, i64 }*
%lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0
%lo1 = load i8*, i8** %lo, align 8
%hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1
%hi2 = load i64, i64* %hi, align 8
%6 = call i32 @sum_us(i8* %lo1, i64 %hi2)
%7 = bitcast [3 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %7, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
%8 = bitcast [3 x i32]* %x to i32*
@@ -50,25 +50,26 @@ func void test()
store i64 3, i64* %11, align 8
%13 = bitcast [3 x i32]* %x to i32*
store i32* %13, i32** %12, align 8
%casttemp4 = bitcast %"int[]"* %vararg3 to { i64, i8* }*
%lo5 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp4, i32 0, i32 0
%lo6 = load i64, i64* %lo5, align 8
%hi7 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp4, i32 0, i32 1
%hi8 = load i8*, i8** %hi7, align 8
%14 = call i32 @sum_us(i64 %lo6, i8* %hi8)
%casttemp4 = bitcast %"int[]"* %vararg3 to { i8*, i64 }*
%lo5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp4, i32 0, i32 0
%lo6 = load i8*, i8** %lo5, align 8
%hi7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp4, i32 0, i32 1
%hi8 = load i64, i64* %hi7, align 8
%14 = call i32 @sum_us(i8* %lo6, i64 %hi8)
%15 = getelementptr inbounds %"int[]", %"int[]"* %vararg9, i32 0, i32 1
%16 = getelementptr inbounds %"int[]", %"int[]"* %vararg9, i32 0, i32 0
%casttemp10 = bitcast %"int[]"* %z to { i64, i8* }*
%lo11 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp10, i32 0, i32 0
%lo12 = load i64, i64* %lo11, align 8
%hi13 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp10, i32 0, i32 1
%hi14 = load i8*, i8** %hi13, align 8
%17 = call i32 @sum_us(i64 %lo12, i8* %hi14)
%casttemp10 = bitcast %"int[]"* %z to { i8*, i64 }*
%lo11 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp10, i32 0, i32 0
%lo12 = load i8*, i8** %lo11, align 8
%hi13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp10, i32 0, i32 1
%hi14 = load i64, i64* %hi13, align 8
%17 = call i32 @sum_us(i8* %lo12, i64 %hi14)
%18 = getelementptr inbounds %"int[]", %"int[]"* %vararg15, i32 0, i32 1
store i64 0, i64* %18, align 8
%casttemp16 = bitcast %"int[]"* %vararg15 to { i64, i8* }*
%lo17 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp16, i32 0, i32 0
%lo18 = load i64, i64* %lo17, align 8
%hi19 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp16, i32 0, i32 1
%hi20 = load i8*, i8** %hi19, align 8
%19 = call i32 @sum_us(i64 %lo18, i8* %hi20)
%casttemp16 = bitcast %"int[]"* %vararg15 to { i8*, i64 }*
%lo17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp16, i32 0, i32 0
%lo18 = load i8*, i8** %lo17, align 8
%hi19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp16, i32 0, i32 1
%hi20 = load i64, i64* %hi19, align 8
%19 = call i32 @sum_us(i8* %lo18, i64 %hi20)
ret void

View File

@@ -257,7 +257,7 @@ func Type getValue(Blob blob)
%"int[]" = type { i32*, i64 }
%Foo = type { i32, i32 }
define void @test.Foo2__printme(%Foo2* %0)
define void @test.Foo2__printme(%Foo2* %0) #0 {
entry:
%foo = alloca %Foo2*, align 8
store %Foo2* %0, %Foo2** %foo, align 8
@@ -268,7 +268,7 @@ entry:
ret void
}
define i32 @test.Foo2__mutate(%Foo2* %0)
define i32 @test.Foo2__mutate(%Foo2* %0) #0 {
entry:
%foo = alloca %Foo2*, align 8
store %Foo2* %0, %Foo2** %foo, align 8
@@ -281,15 +281,15 @@ entry:
ret i32 %add
}
declare i32 @printf(i8*, ...)
declare i32 @printf(i8*, ...) #0
define void @test.helloWorld()
define void @test.helloWorld() #0 {
entry:
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0))
ret void
}
define i32 @test.test_static()
define i32 @test.test_static() #0 {
entry:
%0 = load i32, i32* @test_static.x, align 4
%add = add i32 %0, 1
@@ -300,7 +300,8 @@ entry:
ret i32 %3
}
define i32 @test.helo(double %0, %Bobo* byval align 8 %1)
define i32 @test.helo(double %0, %Bobo* byval align 8 %1) #0 {
entry:
%d = alloca double, align 8
%b = alloca %Bobo, align 4
%de = alloca [3 x i32], align 4
@@ -322,7 +323,8 @@ define i32 @test.helo(double %0, %Bobo* byval align 8 %1)
ret i32 1
}
define i32 @test.test1(i32 %0, i32 %1)
define i32 @test.test1(i32 %0, i32 %1) #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 %0, i32* %a, align 4
@@ -336,34 +338,39 @@ define i32 @test.test1(i32 %0, i32 %1)
%gt = icmp sgt i32 %5, 128
br i1 %gt, label %if.then, label %if.exit
if.then: ; preds = %entry
ret i32 -1
if.exit: ; preds = %entry
%6 = load i32, i32* %a, align 4
ret i32 %6
}
declare void @test_virtual3(i64, i8*)
declare void @test_virtual3(i64, i8*) #0
declare void @test_virtual2(i8*, i8*)
declare void @test_virtual2(i8*, i8*) #0
define i32 @test.sum_us(i64 %0, i8* %1)
define i32 @test.sum_us(i8* %0, i64 %1) #0 {
entry:
%x = alloca %"int[]", align 8
%sum = alloca i32, align 4
%vararg = alloca %"int[]", align 8
%tempaddr = alloca %"int[]", align 8
%pair = bitcast %"int[]"* %x to { i64, i8* }*
%lo = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 0
store i64 %0, i64* %lo, align 8
%hi = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 1
store i8* %1, i8** %hi, align 8
%pair = bitcast %"int[]"* %x to { i8*, i64 }*
%lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0
store i8* %0, i8** %lo, align 8
%hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1
store i64 %1, i64* %hi, align 8
store i32 0, i32* %sum, align 4
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
%2 = load i64, i64* %len, align 8
%eq = icmp eq i64 %2, 0
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
ret i32 0
if.exit: ; preds = %entry
%3 = load i32, i32* %sum, align 4
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0
%saptr = load i32*, i32** %subarrayptr, align 8
@@ -381,12 +388,12 @@ define i32 @test.sum_us(i64 %0, i8* %1)
%11 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1
%12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0
store %"int[]" %10, %"int[]"* %tempaddr, align 8
%casttemp = bitcast %"int[]"* %tempaddr to { i64, i8* }*
%lo1 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 0
%lo2 = load i64, i64* %lo1, align 8
%hi3 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 1
%hi4 = load i8*, i8** %hi3, align 8
%13 = call i32 @test.sum_us(i64 %lo2, i8* %hi4)
%casttemp = bitcast %"int[]"* %tempaddr to { i8*, i64 }*
%lo1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0
%lo2 = load i8*, i8** %lo1, align 8
%hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1
%hi4 = load i64, i64* %hi3, align 8
%13 = call i32 @test.sum_us(i8* %lo2, i64 %hi4)
%add = add i32 %4, %13
%add5 = add i32 %3, %add
store i32 %add5, i32* %sum, align 4
@@ -394,19 +401,21 @@ define i32 @test.sum_us(i64 %0, i8* %1)
ret i32 %14
}
define i32 @test.sumd(i64 %0, i8* %1)
define i32 @test.sumd(i8* %0, i64 %1) #0 {
entry:
%x = alloca %"int[]", align 8
%sum = alloca i32, align 4
%i = alloca i32, align 4
%pair = bitcast %"int[]"* %x to { i64, i8* }*
%lo = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 0
store i64 %0, i64* %lo, align 8
%hi = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 1
store i8* %1, i8** %hi, align 8
%pair = bitcast %"int[]"* %x to { i8*, i64 }*
%lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0
store i8* %0, i8** %lo, align 8
%hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1
store i64 %1, i64* %hi, align 8
store i32 0, i32* %sum, align 4
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%2 = load i32, i32* %i, align 4
%sisiext = sext i32 %2 to i64
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
@@ -416,6 +425,7 @@ define i32 @test.sumd(i64 %0, i8* %1)
%siui-lt = or i1 %check, %lt
br i1 %siui-lt, label %for.body, label %for.exit
for.body: ; preds = %for.cond
%4 = load i32, i32* %sum, align 4
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0
%saptr = load i32*, i32** %subarrayptr, align 8
@@ -427,15 +437,18 @@ define i32 @test.sumd(i64 %0, i8* %1)
store i32 %add, i32* %sum, align 4
br label %for.inc
for.inc: ; preds = %for.body
%7 = load i32, i32* %i, align 4
%add2 = add i32 %7, 1
store i32 %add2, i32* %i, align 4
br label %for.cond
for.exit: ; preds = %for.cond
%8 = load i32, i32* %sum, align 4
ret i32 %8
}
define void @main()
define void @main() #0 {
entry:
%list = alloca %LinkedList, align 8
%i = alloca i32, align 4
@@ -474,12 +487,14 @@ entry:
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%4 = load i32, i32* %i, align 4
%5 = call i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList* %list)
%5 = call i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList* %list) #3
%uisitrunc = trunc i64 %5 to i32
%lt = icmp slt i32 %4, %uisitrunc
br i1 %lt, label %for.body, label %for.exit
for.body: ; preds = %for.cond
%6 = load i32, i32* %i, align 4
%7 = load i32, i32* %i, align 4
%siuiext = zext i32 %7 to i64
@@ -487,11 +502,13 @@ entry:
%9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.2, i32 0, i32 0), i32 %6, i32 %8)
br label %for.inc
for.inc: ; preds = %for.body
%10 = load i32, i32* %i, align 4
%add = add i32 %10, 1
store i32 %add, i32* %i, align 4
br label %for.cond
for.exit: ; preds = %for.cond
call void @"std::array::linkedlist.int.LinkedList__free"(%LinkedList* %list)
%11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str.3, i32 0, i32 0), i32 -5, i32 14, i32 3)
store i32 14, i32* %max, align 4
@@ -503,17 +520,19 @@ entry:
call void @"std::array::list.int.List__append"(%List* %array, i32 100)
call void @"std::array::list.int.List__append"(%List* %array, i32 200)
call void @"std::array::list.int.List__append"(%List* %array, i32 400)
call void @"std::array::list.int.List__push"(%List* %array, i32 600)
call void @"std::array::list.int.List__push"(%List* %array, i32 600) #3
call void @"std::array::list.int.List__insertAt"(%List* %array, i64 2, i32 300)
store i32 0, i32* %i1, align 4
br label %for.cond2
for.cond2: ; preds = %for.inc7, %for.exit
%14 = load i32, i32* %i1, align 4
%15 = call i64 @"std::array::list.int.List__len"(%List* %array)
%uisitrunc3 = trunc i64 %15 to i32
%lt4 = icmp slt i32 %14, %uisitrunc3
br i1 %lt4, label %for.body5, label %for.exit9
for.body5: ; preds = %for.cond2
%16 = load i32, i32* %i1, align 4
%17 = load i32, i32* %i1, align 4
%siuiext6 = zext i32 %17 to i64
@@ -521,11 +540,13 @@ entry:
%19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.5, i32 0, i32 0), i32 %16, i32 %18)
br label %for.inc7
for.inc7: ; preds = %for.body5
%20 = load i32, i32* %i1, align 4
%add8 = add i32 %20, 1
store i32 %add8, i32* %i1, align 4
br label %for.cond2
for.exit9: ; preds = %for.cond2
call void @"std::array::list.int.List__free"(%List* %array)
%21 = bitcast %Blob* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false)
@@ -558,12 +579,12 @@ entry:
store i64 4, i64* %38, align 8
%40 = bitcast [4 x i32]* %x to i32*
store i32* %40, i32** %39, align 8
%casttemp = bitcast %"int[]"* %vararg to { i64, i8* }*
%lo = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 0
%lo11 = load i64, i64* %lo, align 8
%hi = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp, i32 0, i32 1
%hi12 = load i8*, i8** %hi, align 8
%41 = call i32 @test.sum_us(i64 %lo11, i8* %hi12)
%casttemp = bitcast %"int[]"* %vararg to { i8*, i64 }*
%lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0
%lo11 = load i8*, i8** %lo, align 8
%hi = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1
%hi12 = load i64, i64* %hi, align 8
%41 = call i32 @test.sum_us(i8* %lo11, i64 %hi12)
%42 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %41)
%add13 = add i32 %37, %42
store i32 %add13, i32* %fro, align 4
@@ -580,21 +601,21 @@ entry:
store i64 4, i64* %49, align 8
%51 = bitcast [4 x i32]* %x to i32*
store i32* %51, i32** %50, align 8
%casttemp15 = bitcast %"int[]"* %vararg14 to { i64, i8* }*
%lo16 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp15, i32 0, i32 0
%lo17 = load i64, i64* %lo16, align 8
%hi18 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp15, i32 0, i32 1
%hi19 = load i8*, i8** %hi18, align 8
%52 = call i32 @test.sum_us(i64 %lo17, i8* %hi19)
%casttemp15 = bitcast %"int[]"* %vararg14 to { i8*, i64 }*
%lo16 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp15, i32 0, i32 0
%lo17 = load i8*, i8** %lo16, align 8
%hi18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp15, i32 0, i32 1
%hi19 = load i64, i64* %hi18, align 8
%52 = call i32 @test.sum_us(i8* %lo17, i64 %hi19)
%53 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %52)
%54 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 1
%55 = getelementptr inbounds %"int[]", %"int[]"* %vararg20, i32 0, i32 0
%casttemp21 = bitcast %"int[]"* %z to { i64, i8* }*
%lo22 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp21, i32 0, i32 0
%lo23 = load i64, i64* %lo22, align 8
%hi24 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp21, i32 0, i32 1
%hi25 = load i8*, i8** %hi24, align 8
%56 = call i32 @test.sum_us(i64 %lo23, i8* %hi25)
%casttemp21 = bitcast %"int[]"* %z to { i8*, i64 }*
%lo22 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp21, i32 0, i32 0
%lo23 = load i8*, i8** %lo22, align 8
%hi24 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp21, i32 0, i32 1
%hi25 = load i64, i64* %hi24, align 8
%56 = call i32 @test.sum_us(i8* %lo23, i64 %hi25)
%57 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %56)
%58 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0
store i32 1, i32* %58, align 4
@@ -609,12 +630,12 @@ entry:
%63 = getelementptr inbounds %"int[]", %"int[]"* %vararg26, i32 0, i32 0
%64 = bitcast [4 x i32]* %varargslots to i32*
store i32* %64, i32** %63, align 8
%casttemp27 = bitcast %"int[]"* %vararg26 to { i64, i8* }*
%lo28 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp27, i32 0, i32 0
%lo29 = load i64, i64* %lo28, align 8
%hi30 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp27, i32 0, i32 1
%hi31 = load i8*, i8** %hi30, align 8
%65 = call i32 @test.sum_us(i64 %lo29, i8* %hi31)
%casttemp27 = bitcast %"int[]"* %vararg26 to { i8*, i64 }*
%lo28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp27, i32 0, i32 0
%lo29 = load i8*, i8** %lo28, align 8
%hi30 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp27, i32 0, i32 1
%hi31 = load i64, i64* %hi30, align 8
%65 = call i32 @test.sum_us(i8* %lo29, i64 %hi31)
%66 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %65)
%67 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots33, i64 0, i64 0
store i32 1, i32* %67, align 4
@@ -623,28 +644,27 @@ entry:
%69 = getelementptr inbounds %"int[]", %"int[]"* %vararg32, i32 0, i32 0
%70 = bitcast [1 x i32]* %varargslots33 to i32*
store i32* %70, i32** %69, align 8
%casttemp34 = bitcast %"int[]"* %vararg32 to { i64, i8* }*
%lo35 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp34, i32 0, i32 0
%lo36 = load i64, i64* %lo35, align 8
%hi37 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp34, i32 0, i32 1
%hi38 = load i8*, i8** %hi37, align 8
%71 = call i32 @test.sum_us(i64 %lo36, i8* %hi38)
%casttemp34 = bitcast %"int[]"* %vararg32 to { i8*, i64 }*
%lo35 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp34, i32 0, i32 0
%lo36 = load i8*, i8** %lo35, align 8
%hi37 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp34, i32 0, i32 1
%hi38 = load i64, i64* %hi37, align 8
%71 = call i32 @test.sum_us(i8* %lo36, i64 %hi38)
%72 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %71)
%73 = getelementptr inbounds %"int[]", %"int[]"* %vararg39, i32 0, i32 1
store i64 0, i64* %73, align 8
%casttemp40 = bitcast %"int[]"* %vararg39 to { i64, i8* }*
%lo41 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp40, i32 0, i32 0
%lo42 = load i64, i64* %lo41, align 8
%hi43 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %casttemp40, i32 0, i32 1
%hi44 = load i8*, i8** %hi43, align 8
%74 = call i32 @test.sum_us(i64 %lo42, i8* %hi44)
%casttemp40 = bitcast %"int[]"* %vararg39 to { i8*, i64 }*
%lo41 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp40, i32 0, i32 0
%lo42 = load i8*, i8** %lo41, align 8
%hi43 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp40, i32 0, i32 1
%hi44 = load i64, i64* %hi43, align 8
%74 = call i32 @test.sum_us(i8* %lo42, i64 %hi44)
%75 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %74)
store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %a1, align 8
store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %b2, align 8
ret void
}
// #expect: hello_world.ll
define void @hello_world.hello()

View File

@@ -133,4 +133,28 @@ func void test_missing_no_cases(Baz x)
default:
break;
}
}
errtype MathError
{
DIVISION_BY_ZERO
}
// Rethrowing an error uses "!!" suffix
func void! testMayError()
{
}
func void main()
{
// Handle the error
switch (catch err = testMayError()) // #error: Catch unwrapping is only allowed
{
case MathError.DIVISION_BY_ZERO:
io::printf("Division by zero\n");
return;
default:
io::printf("Unexpected error!");
return;
}
}