Parses attribute defines. Removal of incremental array parsing. Labels in macros should now work correctly. Volatile and attribute are no longer keywords. Checked a few todos. On test failure, return -1

This commit is contained in:
Christoffer Lerno
2021-11-18 10:59:49 +01:00
committed by Christoffer Lerno
parent bfde58b9a5
commit 4d4bbbdebc
27 changed files with 486 additions and 204 deletions

View File

@@ -33,7 +33,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c build --debug-log
- name: run compiler tests
run: |
@@ -65,7 +65,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c build --debug-log
- name: run compiler tests
run: |
@@ -93,7 +93,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c build
../../build/c3c build --debug-log
- name: run compiler tests
run: |

View File

@@ -49,8 +49,6 @@ const char *decl_to_name(Decl *decl)
return "compile time if";
case DECL_CT_SWITCH:
return "compile time switch";
case DECL_ARRAY_VALUE:
UNREACHABLE;
case DECL_IMPORT:
return "import";
case DECL_LABEL:
@@ -165,7 +163,6 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
case DECL_VAR:
case DECL_ENUM_CONSTANT:
case DECL_ERRVALUE:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENERIC:

View File

@@ -325,7 +325,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
AlignSize type_alloca_alignment(Type *type)
{
if (platform_target.abi == ABI_X64)
if (platform_target.abi == ABI_X64 || platform_target.abi == ABI_WIN64)
{
type = type_lowering(type);
if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16;

View File

@@ -156,7 +156,6 @@ static void register_generic_decls(Module *module, Decl **decls)
switch (decl->decl_kind)
{
case DECL_POISONED:
case DECL_ARRAY_VALUE:
case DECL_ENUM_CONSTANT:
case DECL_ERRVALUE:
case DECL_IMPORT:

View File

@@ -524,6 +524,7 @@ typedef enum
DEFINE_TYPE_GENERIC,
DEFINE_IDENT_ALIAS,
DEFINE_IDENT_GENERIC,
DEFINE_ATTRIBUTE,
} DefineType;
typedef struct
@@ -531,6 +532,11 @@ typedef struct
DefineType define_kind: 5;
union
{
struct
{
Decl **params;
Attr **attrs;
} attributes;
struct
{
union
@@ -625,7 +631,6 @@ typedef struct Decl_
CtCaseDecl ct_case_decl;
Ast *ct_assert_decl;
Decl** ct_else_decl;
Expr *incr_array_decl;
};
} Decl;
@@ -1174,7 +1179,6 @@ typedef struct
bool is_volatile : 1;
bool is_inline : 1;
bool is_goto : 1;
AsmParams *params;
Expr *body;
} AstAsmStmt;
@@ -1368,7 +1372,6 @@ typedef struct Context_
Decl **methods;
Decl **macro_methods;
Decl **vars;
Decl **incr_array;
Decl **ct_ifs;
Decl **ct_asserts;
Decl *active_function_for_analysis;
@@ -1393,7 +1396,6 @@ typedef struct Context_
Ast **returns_cache;
};
Type *rtype;
int in_volatile_section;
MacroScope macro_scope;
struct {
STable external_symbols;

View File

@@ -196,9 +196,6 @@ void context_register_global_decl(Context *context, Decl *decl)
vec_add(context->enums, decl);
decl_set_external_name(decl);
break;
case DECL_ARRAY_VALUE:
vec_add(context->incr_array, decl);
return;
case DECL_ERRVALUE:
case DECL_ENUM_CONSTANT:
case DECL_IMPORT:

View File

@@ -13,7 +13,7 @@ Expr **copy_expr_list(Expr **expr_list)
static inline Decl *decl_copy_label_from_macro(Decl *to_copy, Ast *ast)
{
if (!to_copy) return NULL;
to_copy = decl_copy_local_from_macro(to_copy);
to_copy = copy_decl(to_copy);
to_copy->label.parent = astid(ast);
return to_copy;
}
@@ -241,12 +241,14 @@ Ast *copy_ast(Ast *source)
case AST_POISONED:
return ast;
case AST_ASM_STMT:
TODO
MACRO_COPY_EXPR(ast->asm_stmt.body);
return ast;
case AST_ASSERT_STMT:
MACRO_COPY_EXPR(ast->ct_assert_stmt.expr);
MACRO_COPY_EXPR(ast->ct_assert_stmt.message);
return ast;
case AST_BREAK_STMT:
case AST_CONTINUE_STMT:
return ast;
case AST_CASE_STMT:
MACRO_COPY_AST(ast->case_stmt.body);
@@ -258,8 +260,6 @@ Ast *copy_ast(Ast *source)
case AST_CT_COMPOUND_STMT:
MACRO_COPY_AST_LIST(ast->ct_compound_stmt);
return ast;
case AST_CONTINUE_STMT:
TODO
case AST_CT_ASSERT:
MACRO_COPY_EXPR(ast->ct_assert_stmt.message);
MACRO_COPY_EXPR(ast->ct_assert_stmt.expr);
@@ -327,8 +327,15 @@ Ast *copy_ast(Ast *source)
MACRO_COPY_AST(ast->if_stmt.then_body);
return ast;
case AST_NEXT_STMT:
MACRO_COPY_EXPR(ast->next_stmt.switch_expr);
TODO
if (ast->next_stmt.is_type)
{
MACRO_COPY_TYPE(ast->next_stmt.type_info);
}
else
{
MACRO_COPY_EXPR(ast->next_stmt.target);
}
return ast;
case AST_NOP_STMT:
return ast;
case AST_RETURN_STMT:
@@ -345,9 +352,6 @@ Ast *copy_ast(Ast *source)
return ast;
case AST_UNREACHABLE_STMT:
return ast;
case AST_VOLATILE_STMT:
TODO
return ast;
case AST_WHILE_STMT:
copy_flow(ast);
MACRO_COPY_EXPR(ast->while_stmt.cond);
@@ -409,7 +413,6 @@ TypeInfo *copy_type_info(TypeInfo *source)
copy->array.len = copy_expr(source->array.len);
copy->array.base = copy_type_info(source->array.base);
return copy;
case TYPE_INFO_INC_ARRAY:
case TYPE_INFO_INFERRED_ARRAY:
case TYPE_INFO_SUBARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
@@ -498,8 +501,8 @@ Decl *copy_decl(Decl *decl)
}
break;
case DECL_LABEL:
TODO
break;
// Note that the ast id should be patched by the parent.
return copy;
case DECL_ENUM_CONSTANT:
MACRO_COPY_EXPR(copy->enum_constant.expr);
MACRO_COPY_EXPR_LIST(copy->enum_constant.args);
@@ -543,8 +546,6 @@ Decl *copy_decl(Decl *decl)
break;
case DECL_IMPORT:
break;
case DECL_ARRAY_VALUE:
TODO
case DECL_GENERIC:
case DECL_MACRO:
MACRO_COPY_TYPE(decl->macro_decl.type_parent);
@@ -565,6 +566,10 @@ Decl *copy_decl(Decl *decl)
break;
case DEFINE_IDENT_ALIAS:
break;
case DEFINE_ATTRIBUTE:
decl->define_decl.attributes.attrs = copy_attributes(decl->define_decl.attributes.attrs);
MACRO_COPY_DECL_LIST(decl->define_decl.attributes.params);
break;
}
break;
}

View File

@@ -75,7 +75,6 @@ typedef enum
AST_SWITCH_STMT,
AST_NEXT_STMT,
AST_UNREACHABLE_STMT,
AST_VOLATILE_STMT,
AST_WHILE_STMT,
AST_SCOPED_STMT,
} AstKind;
@@ -120,6 +119,7 @@ typedef enum
CAST_STST,
CAST_PTRANY,
CAST_ANYPTR,
CAST_VECARR,
} CastKind;
@@ -127,7 +127,6 @@ typedef enum
{
DECL_POISONED = 0,
DECL_ATTRIBUTE,
DECL_ARRAY_VALUE,
DECL_BITSTRUCT,
DECL_CT_CASE,
DECL_CT_ELIF,
@@ -152,7 +151,7 @@ typedef enum
DECL_VAR,
} DeclKind;
#define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \
#define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \
case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC
@@ -285,7 +284,6 @@ typedef enum
TYPE_INFO_EXPRESSION,
TYPE_INFO_ARRAY,
TYPE_INFO_VECTOR,
TYPE_INFO_INC_ARRAY,
TYPE_INFO_INFERRED_ARRAY,
TYPE_INFO_SUBARRAY,
TYPE_INFO_POINTER,
@@ -422,7 +420,6 @@ typedef enum
TOKEN_AS,
TOKEN_ASSERT,
TOKEN_ASM,
TOKEN_ATTRIBUTE,
TOKEN_BITSTRUCT,
TOKEN_BREAK,
TOKEN_CASE,
@@ -461,7 +458,6 @@ typedef enum
TOKEN_UNION,
TOKEN_VAR, // Reserved
TOKEN_VIRTUAL,
TOKEN_VOLATILE,
TOKEN_WHILE,
TOKEN_CT_ALIGNOF, // $alignof

View File

@@ -1129,6 +1129,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
// This is a no op.
assert(type_lowering(to_type) == type_lowering(from_type));
break;
case CAST_VECARR:
TODO
case CAST_EUER:
TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type);
case CAST_ERBOOL:

View File

@@ -1355,8 +1355,6 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_UNREACHABLE_STMT:
gencontext_emit_unreachable_stmt(c, ast);
break;
case AST_VOLATILE_STMT:
TODO
}
}

View File

@@ -77,7 +77,6 @@ void recover_top_level(Context *context)
case TOKEN_EXTERN:
case TOKEN_ENUM:
case TOKEN_GENERIC:
case TOKEN_ATTRIBUTE:
case TOKEN_DEFINE:
case TOKEN_ERRTYPE:
return;
@@ -620,7 +619,6 @@ static inline TypeInfo *parse_base_type(Context *context)
* array_type_index
* : '[' constant_expression ']'
* | '[' ']'
* | '[' '+' ']'
* | '[' '*' ']'
* ;
*
@@ -632,14 +630,6 @@ static inline TypeInfo *parse_array_type_index(Context *context, TypeInfo *type)
assert(type_info_ok(type));
advance_and_verify(context, TOKEN_LBRACKET);
if (try_consume(context, TOKEN_PLUS))
{
CONSUME_OR(TOKEN_RBRACKET, poisoned_type_info);
TypeInfo *incr_array = type_info_new(TYPE_INFO_INC_ARRAY, type->span);
incr_array->array.base = type;
RANGE_EXTEND_PREV(incr_array);
return incr_array;
}
if (try_consume(context, TOKEN_STAR))
{
CONSUME_OR(TOKEN_RBRACKET, poisoned_type_info);
@@ -886,26 +876,6 @@ static inline bool is_function_start(Context *context)
}
static inline Decl *parse_incremental_array(Context *context)
{
Token name = context->tok;
advance_and_verify(context, TOKEN_IDENT);
if (!try_consume(context, TOKEN_PLUS_ASSIGN))
{
SEMA_TOKEN_ERROR(name, "Did you miss a declaration before the variable name?");
return poisoned_decl;
}
Decl *decl = decl_new(DECL_ARRAY_VALUE, name.id, VISIBLE_LOCAL);
ASSIGN_EXPR_ELSE(decl->incr_array_decl, parse_initializer(context), poisoned_decl);
TRY_CONSUME_EOS_OR(poisoned_decl);
return decl;
}
bool parse_next_is_decl(Context *context)
{
TokenType next_tok = context->next_tok.type;
@@ -1691,11 +1661,67 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility)
TRY_CONSUME_EOS_OR(poisoned_decl);
return decl;
}
/**
* define_attribute ::= 'define' '@' IDENT '(' parameter_list ')' ('=' (void | attribute_list))?
*/
static inline Decl *parse_define_attribute(Context *context, Visibility visibility)
{
// 1. Store the beginning of the define.
TokenId start = context->tok.id;
advance_and_verify(context, TOKEN_DEFINE);
advance_and_verify(context, TOKEN_AT);
TokenType alias_type = context->tok.type;
if (alias_type != TOKEN_TYPE_IDENT)
{
if (token_is_some_ident(alias_type) || token_is_keyword(alias_type))
{
SEMA_TOKEN_ERROR(context->tok, "A user defined attribute must start with an uppercase character, followed by at least one lower case.");
return false;
}
SEMA_TOKEN_ERROR(context->tok, "The attribute name was expected here.");
return false;
}
Decl *decl = decl_new(DECL_DEFINE, context->tok.id, visibility);
advance_and_verify(context, TOKEN_TYPE_IDENT);
Decl **parameters = NULL;
if (try_consume(context, TOKEN_LPAREN))
{
if (!parse_parameters(context, visibility, &parameters)) return false;
CONSUME_OR(TOKEN_RPAREN, poisoned_decl);
}
Attr **attributes = NULL;
if (try_consume(context, TOKEN_EQ))
{
if (try_consume(context, TOKEN_VOID))
{
if (!parse_attributes(context, &attributes)) return false;
}
}
decl->define_decl.define_kind = DEFINE_ATTRIBUTE;
decl->define_decl.attributes.attrs = attributes;
decl->define_decl.attributes.params = parameters;
// 3. Set up the define.
decl->span.loc = start;
RANGE_EXTEND_PREV(decl);
return decl;
}
/**
* define_decl ::= DEFINE define_type_body |
*/
static inline Decl *parse_define(Context *context, Visibility visibility)
{
if (context->next_tok.type == TOKEN_AT)
{
// define @foo = @inline, @noreturn
return parse_define_attribute(context, visibility);
}
if (context->next_tok.type == TOKEN_TYPE_IDENT)
{
return parse_define_type(context, visibility);
@@ -2258,9 +2284,6 @@ Decl *parse_top_level_statement(Context *context)
ASSIGN_DECL_ELSE(decl, parse_define(context, visibility), poisoned_decl);
break;
}
case TOKEN_ATTRIBUTE:
TODO
break;
case TOKEN_FUNC:
case TOKEN_FN:
{
@@ -2335,20 +2358,7 @@ Decl *parse_top_level_statement(Context *context)
break;
}
case TOKEN_IDENT:
if (context->next_tok.type == TOKEN_SCOPE)
{
ASSIGN_DECL_ELSE(decl, parse_global_declaration(context, visibility), poisoned_decl);
break;
}
if (!check_no_visibility_before(context, visibility)) return poisoned_decl;
ASSIGN_DECL_ELSE(decl, parse_incremental_array(context), poisoned_decl);
if (docs)
{
SEMA_ERROR(docs,
"Unexpected doc comment before incremental array, did you mean to use a regular comment?");
return poisoned_decl;
}
break;
return parse_global_declaration(context, visibility);
case TOKEN_EOF:
SEMA_TOKID_ERROR(context->prev_tok, "Expected a top level declaration");
return poisoned_decl;

View File

@@ -58,7 +58,7 @@ static inline Ast* parse_asm_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_ASM_STMT, context->tok);
advance_and_verify(context, TOKEN_ASM);
ast->asm_stmt.is_volatile = try_consume(context, TOKEN_VOLATILE);
// TODO use attributes, like volatile
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
ASSIGN_EXPR_ELSE(ast->asm_stmt.body, parse_expr(context), poisoned_ast);
ast->asm_stmt.is_volatile = true;
@@ -655,16 +655,6 @@ static inline Ast *parse_return(Context *context)
/**
* volatile_stmt
* : VOLATILE compound_stmt
*/
static Ast *parse_volatile_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_VOLATILE_STMT, context->tok);
ASSIGN_AST_ELSE(ast->volatile_stmt, parse_compound_stmt(context), poisoned_ast);
return ast;
}
@@ -862,8 +852,6 @@ Ast *parse_stmt(Context *context)
return parse_ct_switch_stmt(context);
case TOKEN_CT_FOR:
return parse_ct_for_stmt(context);
case TOKEN_VOLATILE:
return parse_volatile_stmt(context);
case TOKEN_CT_UNREACHABLE:
return parse_unreachable_stmt(context);
case TOKEN_STAR:
@@ -954,7 +942,6 @@ Ast *parse_stmt(Context *context)
case TOKEN_STRUCT:
case TOKEN_ERRTYPE:
case TOKEN_UNION:
case TOKEN_ATTRIBUTE:
case TOKEN_DEFINE:
case TOKEN_DOCS_START:
case TOKEN_DOCS_END:

View File

@@ -358,8 +358,6 @@ CastKind cast_to_bool_kind(Type *type)
case TYPE_DISTINCT:
case TYPE_INFERRED_ARRAY:
UNREACHABLE
case TYPE_ANY:
TODO
case TYPE_BOOL:
return CAST_BOOLBOOL;
case TYPE_ANYERR:
@@ -388,6 +386,7 @@ CastKind cast_to_bool_kind(Type *type)
case TYPE_BITSTRUCT:
case TYPE_UNTYPED_LIST:
case TYPE_FAILABLE:
case TYPE_ANY:
case TYPE_FAILABLE_ANY:
return CAST_ERROR;
}
@@ -510,44 +509,6 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability,
UNREACHABLE
}
static bool may_cast_to_virtual(Type *virtual, Type *from)
{
assert(from->canonical == from);
// 1. We need a pointer, we can't cast from a non pointer.
if (from->type_kind != TYPE_POINTER) return false;
// 2. Virtual* converts to anything, including ints
if (virtual->type_kind == TYPE_ANY) return true;
// 3. Get the data.
Decl *virtual_decl = virtual->decl;
Decl **methods = virtual_decl->interface_decl.functions;
// 4. No variables nor members? Then this is essentially a virtual*
if (!vec_size(methods) && !vec_size(virtual_decl->strukt.members)) return true;
// 5. Look at the pointer.
Type *pointee = from->pointer;
// 6. Is this an array, if so it doesn't have any functions,
// so we implicitly lower to the first element.
if (pointee->type_kind == TYPE_ARRAY)
{
pointee = pointee->array.base;
}
// Do this: create a function that returns a matching interface method.
// store this decl.
// Same with looking at members -> store the Decl.
// Later, generating the table we provide the decl backend ref and the offset.
// Note that matching types should take into account the first element.
// Also go recursively into substructs structs
// Note that this resolution cannot be cached completely due to the module import lookup
TODO;
}
bool type_may_convert_to_anyerr(Type *type)
{
if (type_is_failable_any(type)) return true;
@@ -904,6 +865,8 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
case EXPR_LEN:
case EXPR_CATCH:
case EXPR_BUILTIN:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
UNREACHABLE
case EXPR_POST_UNARY:
return recursive_may_narrow_float(expr->unary_expr.expr, type);
@@ -911,10 +874,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
return recursive_may_narrow_float(expr->expr_scope.expr, type);
case EXPR_TRY:
return recursive_may_narrow_float(expr->inner_expr, type);
case EXPR_TRY_UNWRAP:
TODO
case EXPR_TRY_UNWRAP_CHAIN:
TODO
case EXPR_UNARY:
{
switch (expr->unary_expr.operator)
@@ -1056,6 +1015,8 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
case EXPR_CT_CALL:
case EXPR_NOP:
case EXPR_BUILTIN:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
UNREACHABLE
case EXPR_POST_UNARY:
return recursive_may_narrow_int(expr->unary_expr.expr, type);
@@ -1066,10 +1027,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
case EXPR_GROUP:
case EXPR_FORCE_UNWRAP:
return recursive_may_narrow_int(expr->inner_expr, type);
case EXPR_TRY_UNWRAP:
TODO
case EXPR_TRY_UNWRAP_CHAIN:
TODO
case EXPR_UNARY:
{
switch (expr->unary_expr.operator)
@@ -1266,11 +1223,12 @@ static inline bool subarray_to_bool(Expr *expr)
return insert_cast(expr, CAST_SABOOL, type_bool);
}
static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, bool from_is_failable)
static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
{
switch (from_type->type_kind)
{
case TYPE_FAILABLE_ANY:
case TYPE_FAILABLE:
UNREACHABLE
case TYPE_VOID:
UNREACHABLE
@@ -1282,8 +1240,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, boo
UNREACHABLE
case TYPE_BITSTRUCT:
return bitstruct_cast(expr, from_type, to, to_type);
case TYPE_FAILABLE:
TODO
case TYPE_BOOL:
// Bool may convert into integers and floats but only explicitly.
if (type_is_integer(to)) return bool_to_int(expr, to, to_type);
@@ -1352,7 +1308,8 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, boo
if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr);
break;
case TYPE_VECTOR:
TODO
if (to->type_kind == TYPE_ARRAY) return insert_cast(expr, CAST_VECARR, to);
break;
}
UNREACHABLE
}
@@ -1420,7 +1377,9 @@ bool cast(Expr *expr, Type *to_type)
}
return true;
}
if (!cast_inner(expr, from_type, to, to_type, from_is_failable)) return false;
bool result = cast_inner(expr, from_type, to, to_type);
assert(result == true);
Type *result_type = expr->type;
if (from_is_failable && !type_is_failable(result_type))
{

View File

@@ -1587,6 +1587,8 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl)
name = define_type->unresolved.name_loc;
break;
}
case DEFINE_ATTRIBUTE:
TODO
default:
UNREACHABLE
}
@@ -1647,6 +1649,8 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl)
type->canonical = symbol->type->canonical;
return true;
}
case DEFINE_ATTRIBUTE:
TODO
default:
UNREACHABLE
}
@@ -1733,7 +1737,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
case DECL_POISONED:
case DECL_IMPORT:
case DECL_ENUM_CONSTANT:
case DECL_ARRAY_VALUE:
case DECL_CT_ELSE:
case DECL_CT_ELIF:
case DECL_LABEL:

View File

@@ -186,6 +186,7 @@ bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
case CAST_STST:
case CAST_PTRANY:
case CAST_ENUMLOW:
case CAST_VECARR:
if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false;
return expr_is_constant_eval(expr->cast_expr.expr, eval_kind);
case CAST_EUINT:
@@ -544,8 +545,6 @@ static inline bool sema_cast_ident_rvalue(Context *context, Expr *expr)
case DECL_ERRTYPE:
SEMA_ERROR(expr, "Expected errtype name followed by '.' and an error value.");
return expr_poison(expr);
case DECL_ARRAY_VALUE:
UNREACHABLE
case DECL_IMPORT:
case DECL_CT_IF:
case DECL_CT_ELSE:
@@ -1175,7 +1174,7 @@ static inline bool sema_expand_call_arguments(Context *context, CalledDecl *call
if (!variadic)
{
// 15. We have too many parameters...
SEMA_ERROR(arg, "This argument would would exceed the number of parameters, did you add to many arguments?");
SEMA_ERROR(arg, "This argument would would exceed the number of parameters, did you add too many arguments?");
return false;
}
@@ -6314,8 +6313,6 @@ static Type *sema_expr_check_type_exists(Context *context, TypeInfo *type_info)
if (!type_ok(type)) return type;
return type_get_subarray(type);
}
case TYPE_INFO_INC_ARRAY:
TODO
case TYPE_INFO_INFERRED_ARRAY:
{
// If it's an array, make sure we can resolve the length

View File

@@ -1945,13 +1945,6 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
static bool sema_analyse_volatile_stmt(Context *context, Ast *statement)
{
context->in_volatile_section++;
bool result = sema_analyse_statement(context, statement->volatile_stmt);
context->in_volatile_section--;
return result;
}
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement)
{
@@ -2154,8 +2147,6 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
return sema_analyse_nextcase_stmt(context, statement);
case AST_UNREACHABLE_STMT:
return sema_analyse_unreachable_stmt(context);
case AST_VOLATILE_STMT:
return sema_analyse_volatile_stmt(context, statement);
case AST_WHILE_STMT:
return sema_analyse_while_stmt(context, statement);
case AST_CT_SWITCH_STMT:
@@ -2235,7 +2226,6 @@ bool sema_analyse_function_body(Context *context, Decl *func)
// Clear returns
vec_resize(context->returns, 0);
context->scope_id = 0;
context->in_volatile_section = 0;
context->continue_target = 0;
context->next_target = 0;
context->next_switch = 0;

View File

@@ -155,17 +155,16 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_FUNC:
case DECL_ERRVALUE:
case DECL_ENUM_CONSTANT:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENERIC:
case DECL_LABEL:
case DECL_ATTRIBUTE:
SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "This is not a type.");
return type_info_poison(type_info);
case DECL_CT_ELSE:
case DECL_CT_IF:
case DECL_CT_ELIF:
case DECL_ATTRIBUTE:
case DECL_CT_SWITCH:
case DECL_CT_CASE:
case DECL_CT_ASSERT:
@@ -234,7 +233,6 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
switch (type_info->kind)
{
case TYPE_INFO_POISON:
case TYPE_INFO_INC_ARRAY:
UNREACHABLE
case TYPE_INFO_IDENTIFIER:
if (!sema_resolve_type_identifier(context, type_info)) return false;

View File

@@ -194,8 +194,6 @@ const char *token_type_to_string(TokenType type)
return "asm";
case TOKEN_ASSERT:
return "assert";
case TOKEN_ATTRIBUTE:
return "attribute";
case TOKEN_BITSTRUCT:
return "bitstruct";
case TOKEN_BREAK:
@@ -272,8 +270,6 @@ const char *token_type_to_string(TokenType type)
return "union";
case TOKEN_VAR:
return "var";
case TOKEN_VOLATILE:
return "volatile";
case TOKEN_WHILE:
return "while";

View File

@@ -174,36 +174,47 @@ char *read_file(const char *path, size_t *return_size)
return buffer;
}
const char *find_lib_dir(void)
static inline const char *lib_find(const char *exe_path, const char *rel_path)
{
const char *path = find_executable_path();
DEBUG_LOG("Detected executable path at %s", path);
struct stat info;
char *lib_path = NULL;
asprintf(&lib_path, "%s../lib/std", path);
asprintf(&lib_path, "%s%sstd", exe_path, rel_path);
DEBUG_LOG("Checking %s", lib_path);
int err = stat(lib_path, &info);
// Found it at ../lib/std
if (!err && S_ISDIR(info.st_mode))
{
asprintf(&lib_path, "%s../lib/", path);
return lib_path;
}
// Not a dir or had error?
if (err || !S_ISDIR(info.st_mode)) return NULL;
asprintf(&lib_path, "%slib/std", path);
err = stat(lib_path, &info);
char *check_path = NULL;
asprintf(&check_path, "%s/libc.c3", lib_path);
DEBUG_LOG("Potential lib found, sanity check for libc...");
err = stat(check_path, &info);
if (err || !S_ISREG(info.st_mode)) return NULL;
// Found it at ./lib/std
if (!err && S_ISDIR(info.st_mode))
asprintf(&lib_path, "%s%s", exe_path, rel_path);
DEBUG_LOG("Library path found at %s", lib_path);
return lib_path;
}
const char *find_lib_dir(void)
{
char *path = find_executable_path();
DEBUG_LOG("Detected executable path at %s", path);
size_t strlen_path = strlen(path);
// Remove any last path slash
if (strlen_path > 1 && (path[strlen_path - 1] == '/' || path[strlen_path - 1] == '\\'))
{
asprintf(&lib_path, "%slib/", path);
return lib_path;
path[strlen_path - 1] = '\0';
}
const char *lib_path;
if ((lib_path = lib_find(path, "/../lib/"))) return lib_path;
if ((lib_path = lib_find(path, "/lib/"))) return lib_path;
if ((lib_path = lib_find(path, "/"))) return lib_path;
if ((lib_path = lib_find(path, "/../"))) return lib_path;
if ((lib_path = lib_find(path, "/../../lib/"))) return lib_path;
DEBUG_LOG("Could not find the standard library /lib/std/");
return NULL;
@@ -272,14 +283,19 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
if (strncmp(&ent->d_name[namelen - 3], ".c3", 3) != 0)
{
char *new_path = NULL;
char *format = path_ends_with_slash ? "%s%s/" : "%s/%s/";
char *format = path_ends_with_slash ? "%s%s" : "%s/%s";
if (!asprintf(&new_path, format, path, ent->d_name))
{
error_exit("Failed to allocate path.");
}
bool is_directory;
struct stat st;
is_directory = stat(new_path, &st) == 0 && S_ISDIR(st.st_mode);
if (stat(new_path, &st))
{
DEBUG_LOG("Failed to stat %s", new_path);
continue;
}
is_directory = S_ISDIR(st.st_mode);
if (is_directory && ent->d_name[0] != '.' && recursive)
{
file_add_wildcard_files(files, new_path, recursive);
@@ -287,7 +303,7 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
free(new_path);
continue;
}
char *format = path_ends_with_slash ? "%s%s" : "%s/s";
char *format = path_ends_with_slash ? "%s%s" : "%s/%s";
vec_add(*files, strformat(format, path, ent->d_name));
}
closedir(dir);

View File

@@ -413,9 +413,10 @@ static int get_executable_path_raw(char *out, int capacity, int *dirname_length)
#endif
const char *find_executable_path(void)
char *find_executable_path(void)
{
int len = get_executable_path_raw(NULL, 0, NULL);
if (len < 0) return "";
char *path = malloc(len + 1);
get_executable_path_raw(path, len, NULL);
path[len] = '\0';

View File

@@ -4,4 +4,4 @@
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
const char *find_executable_path(void);
char *find_executable_path(void);

View File

@@ -304,5 +304,8 @@ def main():
usage()
print("Found %d tests: %.1f%% (%d / %d) passed (%d skipped)." % (conf.numtests, 100 * conf.numsuccess / max(1, conf.numtests - conf.numskipped), conf.numsuccess, conf.numtests - conf.numskipped, conf.numskipped))
if (conf.numsuccess != conf.numtests - conf.numskipped):
exit(-1)
exit(0)
main()

View File

@@ -268,7 +268,7 @@ fn Type getValue(Blob blob)
@.str.9 = private constant [10 x i8] c"b was %f\0A\00", align 1
@.str.10 = private constant [17 x i8] c"Mult int was %d\0A\00", align 1
@.str.11 = private constant [20 x i8] c"Mult double was %f\0A\00", align 1
@.__const.12 = private constant [4 x i32] [i32 1, i32 2, i32 3, i32 3], align 4
@.__const.12 = private constant [4 x i32] [i32 1, i32 2, i32 3, i32 3], align 16
@.str.13 = private constant [22 x i8] c"1Vararg4unsplatA: %d\0A\00", align 1
@.str.14 = private constant [4 x i8] c"%d\0A\00", align 1
@.__const.15 = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4
@@ -512,7 +512,7 @@ entry:
%tempcoerce = alloca i64, align 8
%ddx = alloca %Foo, align 4
%fro = alloca i32, align 4
%x = alloca [4 x i32], align 4
%x = alloca [4 x i32], align 16
%vararg = alloca %"int[]", align 8
%indirectarg = alloca %"int[]", align 8
%z = alloca %"int[]", align 8
@@ -522,7 +522,7 @@ entry:
%vararg13 = alloca %"int[]", align 8
%indirectarg14 = alloca %"int[]", align 8
%vararg15 = alloca %"int[]", align 8
%varargslots = alloca [4 x i32], align 4
%varargslots = alloca [4 x i32], align 16
%indirectarg16 = alloca %"int[]", align 8
%vararg17 = alloca %"int[]", align 8
%varargslots18 = alloca [1 x i32], align 4
@@ -628,7 +628,7 @@ for.exit9: ; preds = %for.cond2
call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false)
store i32 3, i32* %fro, align 4
%38 = bitcast [4 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %38, i8* align 4 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %38, i8* align 16 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false)
%39 = load i32, i32* %fro, align 4
%40 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1
%41 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0

View File

@@ -1,3 +1,4 @@
// #target: x64-mingw
module test;
extern fn void printf(char*, ...);

View File

@@ -0,0 +1,324 @@
module test;
extern fn void printf(char *string, ...);
macro checker(int x, $i)
{
var $indent = 3 - $i;
for (int i = 0; i < $indent; i++) printf(" ");
printf("Enter %d\n", $i);
while FOO: (x-- > 0)
{
for (int i = 0; i < $indent; i++) printf(" ");
printf("Helo %d\n", x);
$if ($i > 0):
@checker(x, $i - 1);
$endif;
if (x % 2 == 0) break FOO;
}
for (int i = 0; i < $indent; i++) printf(" ");
printf("Exit %d\n", $i);
}
fn void main()
{
int ab = 7;
@checker(ab, 3);
}
/* #expect: test.ll
define void @main() #0 {
entry:
%ab = alloca i32, align 4
%x = alloca i32, align 4
%i = alloca i32, align 4
%i1 = alloca i32, align 4
%x8 = alloca i32, align 4
%i9 = alloca i32, align 4
%i20 = alloca i32, align 4
%x27 = alloca i32, align 4
%i28 = alloca i32, align 4
%i39 = alloca i32, align 4
%x46 = alloca i32, align 4
%i47 = alloca i32, align 4
%i58 = alloca i32, align 4
%i65 = alloca i32, align 4
%i77 = alloca i32, align 4
%i89 = alloca i32, align 4
%i101 = alloca i32, align 4
store i32 7, i32* %ab, align 4
%0 = load i32, i32* %ab, align 4
store i32 %0, i32* %x, align 4
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%1 = load i32, i32* %i, align 4
%lt = icmp slt i32 %1, 0
br i1 %lt, label %for.body, label %for.exit
for.body: ; preds = %for.cond
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0))
br label %for.inc
for.inc: ; preds = %for.body
%2 = load i32, i32* %i, align 4
%add = add i32 %2, 1
store i32 %add, i32* %i, align 4
br label %for.cond
for.exit: ; preds = %for.cond
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i32 0, i32 0), i32 3)
br label %while.begin
while.begin: ; preds = %if.exit99, %for.exit
%3 = load i32, i32* %x, align 4
%sub = sub i32 %3, 1
store i32 %sub, i32* %x, align 4
%gt = icmp sgt i32 %3, 0
br i1 %gt, label %while.body, label %while.exit100
while.body: ; preds = %while.begin
store i32 0, i32* %i1, align 4
br label %for.cond2
for.cond2: ; preds = %for.inc5, %while.body
%4 = load i32, i32* %i1, align 4
%lt3 = icmp slt i32 %4, 0
br i1 %lt3, label %for.body4, label %for.exit7
for.body4: ; preds = %for.cond2
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.2, i32 0, i32 0))
br label %for.inc5
for.inc5: ; preds = %for.body4
%5 = load i32, i32* %i1, align 4
%add6 = add i32 %5, 1
store i32 %add6, i32* %i1, align 4
br label %for.cond2
for.exit7: ; preds = %for.cond2
%6 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.3, i32 0, i32 0), i32 %6)
%7 = load i32, i32* %x, align 4
store i32 %7, i32* %x8, align 4
store i32 0, i32* %i9, align 4
br label %for.cond10
for.cond10: ; preds = %for.inc13, %for.exit7
%8 = load i32, i32* %i9, align 4
%lt11 = icmp slt i32 %8, 1
br i1 %lt11, label %for.body12, label %for.exit15
for.body12: ; preds = %for.cond10
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.4, i32 0, i32 0))
br label %for.inc13
for.inc13: ; preds = %for.body12
%9 = load i32, i32* %i9, align 4
%add14 = add i32 %9, 1
store i32 %add14, i32* %i9, align 4
br label %for.cond10
for.exit15: ; preds = %for.cond10
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 2)
br label %while.begin16
while.begin16: ; preds = %if.exit87, %for.exit15
%10 = load i32, i32* %x8, align 4
%sub17 = sub i32 %10, 1
store i32 %sub17, i32* %x8, align 4
%gt18 = icmp sgt i32 %10, 0
br i1 %gt18, label %while.body19, label %while.exit88
while.body19: ; preds = %while.begin16
store i32 0, i32* %i20, align 4
br label %for.cond21
for.cond21: ; preds = %for.inc24, %while.body19
%11 = load i32, i32* %i20, align 4
%lt22 = icmp slt i32 %11, 1
br i1 %lt22, label %for.body23, label %for.exit26
for.body23: ; preds = %for.cond21
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
br label %for.inc24
for.inc24: ; preds = %for.body23
%12 = load i32, i32* %i20, align 4
%add25 = add i32 %12, 1
store i32 %add25, i32* %i20, align 4
br label %for.cond21
for.exit26: ; preds = %for.cond21
%13 = load i32, i32* %x8, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.7, i32 0, i32 0), i32 %13)
%14 = load i32, i32* %x8, align 4
store i32 %14, i32* %x27, align 4
store i32 0, i32* %i28, align 4
br label %for.cond29
for.cond29: ; preds = %for.inc32, %for.exit26
%15 = load i32, i32* %i28, align 4
%lt30 = icmp slt i32 %15, 2
br i1 %lt30, label %for.body31, label %for.exit34
for.body31: ; preds = %for.cond29
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.8, i32 0, i32 0))
br label %for.inc32
for.inc32: ; preds = %for.body31
%16 = load i32, i32* %i28, align 4
%add33 = add i32 %16, 1
store i32 %add33, i32* %i28, align 4
br label %for.cond29
for.exit34: ; preds = %for.cond29
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), i32 1)
br label %while.begin35
while.begin35: ; preds = %if.exit75, %for.exit34
%17 = load i32, i32* %x27, align 4
%sub36 = sub i32 %17, 1
store i32 %sub36, i32* %x27, align 4
%gt37 = icmp sgt i32 %17, 0
br i1 %gt37, label %while.body38, label %while.exit76
while.body38: ; preds = %while.begin35
store i32 0, i32* %i39, align 4
br label %for.cond40
for.cond40: ; preds = %for.inc43, %while.body38
%18 = load i32, i32* %i39, align 4
%lt41 = icmp slt i32 %18, 2
br i1 %lt41, label %for.body42, label %for.exit45
for.body42: ; preds = %for.cond40
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.10, i32 0, i32 0))
br label %for.inc43
for.inc43: ; preds = %for.body42
%19 = load i32, i32* %i39, align 4
%add44 = add i32 %19, 1
store i32 %add44, i32* %i39, align 4
br label %for.cond40
for.exit45: ; preds = %for.cond40
%20 = load i32, i32* %x27, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.11, i32 0, i32 0), i32 %20)
%21 = load i32, i32* %x27, align 4
store i32 %21, i32* %x46, align 4
store i32 0, i32* %i47, align 4
br label %for.cond48
for.cond48: ; preds = %for.inc51, %for.exit45
%22 = load i32, i32* %i47, align 4
%lt49 = icmp slt i32 %22, 3
br i1 %lt49, label %for.body50, label %for.exit53
for.body50: ; preds = %for.cond48
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.12, i32 0, i32 0))
br label %for.inc51
for.inc51: ; preds = %for.body50
%23 = load i32, i32* %i47, align 4
%add52 = add i32 %23, 1
store i32 %add52, i32* %i47, align 4
br label %for.cond48
for.exit53: ; preds = %for.cond48
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.13, i32 0, i32 0), i32 0)
br label %while.begin54
while.begin54: ; preds = %if.exit, %for.exit53
%24 = load i32, i32* %x46, align 4
%sub55 = sub i32 %24, 1
store i32 %sub55, i32* %x46, align 4
%gt56 = icmp sgt i32 %24, 0
br i1 %gt56, label %while.body57, label %while.exit
while.body57: ; preds = %while.begin54
store i32 0, i32* %i58, align 4
br label %for.cond59
for.cond59: ; preds = %for.inc62, %while.body57
%25 = load i32, i32* %i58, align 4
%lt60 = icmp slt i32 %25, 3
br i1 %lt60, label %for.body61, label %for.exit64
for.body61: ; preds = %for.cond59
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.14, i32 0, i32 0))
br label %for.inc62
for.inc62: ; preds = %for.body61
%26 = load i32, i32* %i58, align 4
%add63 = add i32 %26, 1
store i32 %add63, i32* %i58, align 4
br label %for.cond59
for.exit64: ; preds = %for.cond59
%27 = load i32, i32* %x46, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.15, i32 0, i32 0), i32 %27)
%28 = load i32, i32* %x46, align 4
%smod = srem i32 %28, 2
%eq = icmp eq i32 %smod, 0
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %for.exit64
br label %while.exit
if.exit: ; preds = %for.exit64
br label %while.begin54
while.exit: ; preds = %if.then, %while.begin54
store i32 0, i32* %i65, align 4
br label %for.cond66
for.cond66: ; preds = %for.inc69, %while.exit
%29 = load i32, i32* %i65, align 4
%lt67 = icmp slt i32 %29, 3
br i1 %lt67, label %for.body68, label %for.exit71
for.body68: ; preds = %for.cond66
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.16, i32 0, i32 0))
br label %for.inc69
for.inc69: ; preds = %for.body68
%30 = load i32, i32* %i65, align 4
%add70 = add i32 %30, 1
store i32 %add70, i32* %i65, align 4
br label %for.cond66
for.exit71: ; preds = %for.cond66
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.17, i32 0, i32 0), i32 0)
%31 = load i32, i32* %x27, align 4
%smod72 = srem i32 %31, 2
%eq73 = icmp eq i32 %smod72, 0
br i1 %eq73, label %if.then74, label %if.exit75
if.then74: ; preds = %for.exit71
br label %while.exit76
if.exit75: ; preds = %for.exit71
br label %while.begin35
while.exit76: ; preds = %if.then74, %while.begin35
store i32 0, i32* %i77, align 4
br label %for.cond78
for.cond78: ; preds = %for.inc81, %while.exit76
%32 = load i32, i32* %i77, align 4
%lt79 = icmp slt i32 %32, 2
br i1 %lt79, label %for.body80, label %for.exit83
for.body80: ; preds = %for.cond78
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.18, i32 0, i32 0))
br label %for.inc81
for.inc81: ; preds = %for.body80
%33 = load i32, i32* %i77, align 4
%add82 = add i32 %33, 1
store i32 %add82, i32* %i77, align 4
br label %for.cond78
for.exit83: ; preds = %for.cond78
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.19, i32 0, i32 0), i32 1)
%34 = load i32, i32* %x8, align 4
%smod84 = srem i32 %34, 2
%eq85 = icmp eq i32 %smod84, 0
br i1 %eq85, label %if.then86, label %if.exit87
if.then86: ; preds = %for.exit83
br label %while.exit88
if.exit87: ; preds = %for.exit83
br label %while.begin16
while.exit88: ; preds = %if.then86, %while.begin16
store i32 0, i32* %i89, align 4
br label %for.cond90
for.cond90: ; preds = %for.inc93, %while.exit88
%35 = load i32, i32* %i89, align 4
%lt91 = icmp slt i32 %35, 1
br i1 %lt91, label %for.body92, label %for.exit95
for.body92: ; preds = %for.cond90
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.20, i32 0, i32 0))
br label %for.inc93
for.inc93: ; preds = %for.body92
%36 = load i32, i32* %i89, align 4
%add94 = add i32 %36, 1
store i32 %add94, i32* %i89, align 4
br label %for.cond90
for.exit95: ; preds = %for.cond90
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.21, i32 0, i32 0), i32 2)
%37 = load i32, i32* %x, align 4
%smod96 = srem i32 %37, 2
%eq97 = icmp eq i32 %smod96, 0
br i1 %eq97, label %if.then98, label %if.exit99
if.then98: ; preds = %for.exit95
br label %while.exit100
if.exit99: ; preds = %for.exit95
br label %while.begin
while.exit100: ; preds = %if.then98, %while.begin
store i32 0, i32* %i101, align 4
br label %for.cond102
for.cond102: ; preds = %for.inc105, %while.exit100
%38 = load i32, i32* %i101, align 4
%lt103 = icmp slt i32 %38, 0
br i1 %lt103, label %for.body104, label %for.exit107
for.body104: ; preds = %for.cond102
call void (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.22, i32 0, i32 0))
br label %for.inc105
for.inc105: ; preds = %for.body104
%39 = load i32, i32* %i101, align 4
%add106 = add i32 %39, 1
store i32 %add106, i32* %i101, align 4
br label %for.cond102
for.exit107: ; preds = %for.cond102
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.23, i32 0, i32 0), i32 3)
ret void
}

View File

@@ -1,3 +1,4 @@
// #target: x64-darwin
module test;
extern fn void printf(char*, ...);

View File

@@ -1,4 +1,4 @@
func1 a = 1; // #error: declaration before the variable
func1 a = 1; // #error: A type name was expected
fn void func1() {}