Changing how defer works. Remove of undef. Simplify ensure.

This commit is contained in:
Christoffer Lerno
2022-03-05 01:44:09 +01:00
committed by Christoffer Lerno
parent 9b0dfe8ba3
commit 069a2d40cb
40 changed files with 1411 additions and 1080 deletions

View File

@@ -235,6 +235,7 @@ bool expr_is_pure(Expr *expr)
case EXPR_NOP:
case EXPR_PTR:
case EXPR_STRINGIFY:
case EXPR_RETVAL:
return true;
case EXPR_ARGV_TO_SUBARRAY:
case EXPR_BITASSIGN:
@@ -284,7 +285,6 @@ bool expr_is_pure(Expr *expr)
case EXPR_SLICE_ASSIGN:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_UNDEF:
case EXPR_TYPEINFO:
case EXPR_FORCE_UNWRAP:
return false;
@@ -489,8 +489,7 @@ bool ast_is_not_empty(Ast *ast)
{
Ast *stmt = astptr(first);
if (stmt->next) return true;
if (ast->compound_stmt.defer_list.start != ast->compound_stmt.defer_list.end) return true;
return ast_is_not_empty(stmt);
}
return ast->compound_stmt.defer_list.start != ast->compound_stmt.defer_list.end;
return false;
}

View File

@@ -49,6 +49,7 @@ typedef Type CanonicalType;
typedef unsigned AstId;
typedef unsigned ExprId;
typedef unsigned DeclId;
typedef struct Int128_
{
@@ -143,13 +144,6 @@ typedef struct
};
} ExprConst;
typedef struct
{
AstId start;
AstId end;
} DeferList;
typedef uint16_t FileId;
typedef struct
{
@@ -343,6 +337,7 @@ typedef struct VarDecl_
bool is_written : 1;
bool is_addr : 1;
bool is_threadlocal : 1;
bool no_init : 1;
TypeInfo *type_info;
union
{
@@ -689,14 +684,15 @@ typedef struct
bool force_inline : 1;
bool force_noinline : 1;
bool is_builtin : 1;
bool is_func_ref : 1;
AstId body;
union
{
Expr *function;
Decl *func_ref;
ExprId function;
DeclId func_ref;
};
Expr **arguments;
Decl **body_arguments;
Ast *body;
Attr **attributes;
} ExprCall;
@@ -709,9 +705,9 @@ typedef struct
typedef struct
{
Expr *expr;
bool start_from_back : 1;
bool end_from_back : 1;
Expr *expr;
Expr *start;
Expr *end;
} ExprSlice;
@@ -816,7 +812,7 @@ typedef struct
typedef struct
{
Expr *expr;
DeferList defers;
AstId defer_stmts;
} ExprScope;
typedef struct
@@ -849,7 +845,7 @@ typedef struct
typedef struct
{
Expr *inner;
AstId defer;
AstId cleanup;
} ExprGuard;
@@ -935,61 +931,61 @@ struct Expr_
SourceSpan span;
Type *type;
union {
ExprVariantSwitch variant_switch;
ExprLen len_expr;
ExprCast cast_expr;
TypeInfo *type_expr;
ExprConst const_expr;
ExprArgv argv_expr;
ExprGuard rethrow_expr;
Decl *decl_expr;
ExprOrError or_error_expr;
ExprSliceAssign slice_assign_expr;
ExprBinary binary_expr;
ExprTernary ternary_expr;
ExprUnary unary_expr;
Expr** try_unwrap_chain_expr;
ExprTryUnwrap try_unwrap_expr;
ExprCall call_expr;
ExprSlice slice_expr;
Expr *inner_expr;
ExprCatchUnwrap catch_unwrap_expr;
ExprSubscript subscript_expr;
ExprAccess access_expr;
ExprDesignator designator_expr;
ExprIdentifier identifier_expr;
ExprIdentifierRaw ct_ident_expr;
ExprCtCall ct_call_expr;
ExprIdentifierRaw ct_macro_ident_expr;
ExprMacroExpansion macro_expansion_expr;
ExprIdentifierRaw hash_ident_expr;
TypeInfo *typeid_expr;
ExprBodyExpansion body_expansion_expr;
ExprCompoundLiteral expr_compound_literal;
Expr** expression_list;
Expr** initializer_list;
Expr** designated_init_list;
ExprScope expr_scope;
ExprFuncBlock expr_block;
ExprMacroBlock macro_block;
Expr** cond_expr;
ExprBuiltin builtin_expr;
ExprVariantSwitch variant_switch; // 32
ExprLen len_expr; // 8
ExprCast cast_expr; // 32
TypeInfo *type_expr; // 8
ExprConst const_expr; // 32
ExprArgv argv_expr; // 16
ExprGuard rethrow_expr; // 16
Decl *decl_expr; // 8
ExprOrError or_error_expr; // 24
ExprSliceAssign slice_assign_expr; // 8
ExprBinary binary_expr; // 24
ExprTernary ternary_expr; // 32
ExprUnary unary_expr; // 16
Expr** try_unwrap_chain_expr; // 8
ExprTryUnwrap try_unwrap_expr; // 24
ExprCall call_expr; // 40
ExprSlice slice_expr; // 32
Expr *inner_expr; // 8
ExprCatchUnwrap catch_unwrap_expr; // 24
ExprSubscript subscript_expr; // 24
ExprAccess access_expr; // 16
ExprDesignator designator_expr; // 16
ExprIdentifier identifier_expr; // 32
ExprIdentifierRaw ct_ident_expr; // 24
ExprCtCall ct_call_expr; // 24
ExprIdentifierRaw ct_macro_ident_expr; // 24
ExprMacroExpansion macro_expansion_expr; // 16
ExprIdentifierRaw hash_ident_expr; // 24
TypeInfo *typeid_expr; // 8
ExprBodyExpansion body_expansion_expr; // 24
ExprCompoundLiteral expr_compound_literal; // 16
Expr** expression_list; // 8
Expr** initializer_list; // 8
Expr** designated_init_list; // 8
ExprScope expr_scope; // 16
ExprFuncBlock expr_block; // 4
ExprMacroBlock macro_block; // 24
Expr** cond_expr; // 8
ExprBuiltin builtin_expr; // 16
};
};
static_assert(sizeof(ExprCall) == 40, "Ooops");
static_assert(sizeof(Expr) == 64, "Ooops");
typedef struct
{
AstId first_stmt;
DeferList defer_list;
} AstCompoundStmt;
typedef struct
{
Expr *expr; // May be NULL
AstId defer;
AstId cleanup;
} AstReturnStmt;
typedef struct
@@ -997,45 +993,28 @@ typedef struct
bool has_break : 1;
bool no_exit : 1;
bool skip_first : 1;
bool if_chain : 1;
Decl *label;
} FlowCommon;
typedef struct
{
FlowCommon flow;
ExprId cond;
AstId body;
void *break_block;
void *continue_block;
} AstWhileStmt;
typedef struct
{
FlowCommon flow;
DeferList expr_defer;
DeferList body_defer;
union
{
struct
{
void *break_block;
void *continue_block;
ExprId cond;
AstId then_body;
AstId else_body;
};
struct
{
Expr *expr;
AstId body;
};
void *break_block;
} codegen;
};
} AstDoStmt;
typedef struct
{
FlowCommon flow;
Expr *cond;
Ast *then_body;
Ast *else_body;
void *break_block;
} AstIfStmt;
@@ -1051,15 +1030,14 @@ typedef struct
typedef struct
{
FlowCommon flow;
AstId defer;
Expr *cond;
Ast **cases;
union
{
struct
{
Ast* scope_defer;
bool if_chain;
ExprId cond;
AstId defer;
Ast **cases;
Ast *scope_defer;
};
struct
{
@@ -1073,12 +1051,21 @@ typedef struct
typedef struct
{
FlowCommon flow;
Expr *init;
Expr *cond;
Expr *incr;
AstId body;
void *continue_block;
void *exit_block;
union
{
struct
{
ExprId cond;
ExprId incr;
ExprId init;
AstId body;
};
struct
{
void *continue_block;
void *exit_block;
} codegen;
};
} AstForStmt;
typedef struct
@@ -1087,24 +1074,17 @@ typedef struct
bool index_by_ref : 1;
bool value_by_ref : 1;
bool iterator : 1;
CastKind cast;
Decl *index;
Decl *variable;
Expr *enumeration;
Ast *body;
void *continue_block;
void *exit_block;
CastKind cast : 8;
ExprId enumeration;
AstId body;
DeclId index;
DeclId variable;
} AstForeachStmt;
typedef struct
{
AstId prev_defer;
Ast *body; // Compound statement
struct
{
void *exit_block;
uint64_t exit_val;
} codegen;
AstId body; // Compound statement
} AstDeferStmt;
@@ -1117,12 +1097,6 @@ typedef struct AstCtIfStmt_
} AstCtIfStmt;
typedef struct
{
AstId stmt;
DeferList defers;
} AstScopedStmt;
typedef struct
{
Expr *cond;
@@ -1136,25 +1110,26 @@ typedef struct
const char *value_name;
SourceSpan index_span;
SourceSpan value_span;
Expr *expr;
AstId body;
ExprId expr;
} AstCtForeachStmt;
typedef struct
{
bool is_label;
bool is_label : 1;
bool is_resolved : 1;
AstId defers;
union
{
Label label;
AstId ast;
};
DeferList defers;
} AstContinueBreakStmt;
typedef struct
{
DeferList defers;
AstId defer_id;
union
{
struct
@@ -1204,7 +1179,7 @@ typedef struct
typedef struct AstDocDirective_
{
SourceSpan span;
DocDirectiveKind kind;
DocDirectiveKind kind : 4;
union
{
struct
@@ -1240,35 +1215,33 @@ typedef struct Ast_
AstKind ast_kind : 8;
union
{
FlowCommon flow; // Shared struct
AstAsmStmt asm_stmt; // 24
AstCompoundStmt compound_stmt; // 16
Decl *declare_stmt; // 8
Expr *expr_stmt; // 8
Decl *var_stmt; // 8
AstReturnStmt return_stmt; // 16
AstWhileStmt while_stmt; // 24
AstDoStmt do_stmt; // 32
AstIfStmt if_stmt; // 32
AstDeferStmt defer_stmt; // 32
AstSwitchStmt switch_stmt; // 24
AstCaseStmt case_stmt; // 32
AstCtSwitchStmt ct_switch_stmt; // 16
AstContinueBreakStmt contbreak_stmt; // 8
AstNextcaseStmt nextcase_stmt; // 16
FlowCommon flow; // Shared struct
AstAsmStmt asm_stmt; // 16
AstCompoundStmt compound_stmt; // 12
Decl *declare_stmt; // 8
Expr *expr_stmt; // 8
Decl *var_stmt; // 8
AstReturnStmt return_stmt; // 16
AstIfStmt if_stmt; // 32
AstDeferStmt defer_stmt; // 8
AstSwitchStmt switch_stmt; // 40
AstCaseStmt case_stmt; // 32
AstCtSwitchStmt ct_switch_stmt; // 16
AstContinueBreakStmt contbreak_stmt;// 24
AstNextcaseStmt nextcase_stmt; // 32
AstForStmt for_stmt; // 32
AstForeachStmt foreach_stmt;
AstForeachStmt foreach_stmt; // 40
AstCtIfStmt ct_if_stmt; // 24
AstId ct_else_stmt; // 8
AstCtForeachStmt ct_foreach_stmt; // 64
AstScopedStmt scoped_stmt; // 16
AstAssertStmt ct_assert_stmt;
AstAssertStmt assert_stmt;
AstDocDirective *directives;
AstId ct_else_stmt; // 4
AstCtForeachStmt ct_foreach_stmt; // 40
AstAssertStmt ct_assert_stmt; // 16
AstAssertStmt assert_stmt; // 16
AstDocDirective *directives; // 8
};
} Ast;
//static_assert(sizeof(AstContinueBreakStmt) == 24, "Ooops");
//static_assert(sizeof(Ast) == 56, "Oops");
typedef struct Module_
{
@@ -1409,10 +1382,12 @@ typedef struct SemaContext_
};
Decl *current_macro;
ScopeId scope_id;
bool ensures;
AstId break_target;
AstId break_defer;
AstId continue_target;
AstId continue_defer;
AstId block_return_defer;
AstId next_target;
Ast *next_switch;
AstId next_defer;
@@ -1427,7 +1402,6 @@ typedef struct SemaContext_
// Reusable returns cache.
Ast **returns_cache;
};
Decl *return_var;
Type *rtype;
struct SemaContext_ *yield_context;
Decl** locals;
@@ -2464,25 +2438,45 @@ static inline bool type_is_promotable_float(Type *type)
return type_is_float(type->canonical) && type->builtin.bytesize < type_double->builtin.bytesize;
}
#define MACRO_COPY_DECL(x) x = copy_decl(x)
#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(x)
#define MACRO_COPY_EXPR(x) x = copy_expr(x)
#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(x)
#define MACRO_COPY_TYPE(x) x = copy_type_info(x)
#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(x)
#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(x)
#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(x)
#define MACRO_COPY_AST(x) x = ast_copy_deep(x)
#define MACRO_COPY_ASTID(x) x = astid_copy_deep(x)
#define MAX_FIXUPS 0xFFFFF
Expr **copy_expr_list(Expr **expr_list);
Expr *copy_expr(Expr *source_expr);
Ast *ast_copy_deep(Ast *source);
Ast **copy_ast_list(Ast **to_copy);
Decl *decl_copy_local_from_macro(Decl *to_copy);
Decl *copy_decl(Decl *decl);
Decl **copy_decl_list(Decl **decl_list);
TypeInfo *copy_type_info(TypeInfo *source);
typedef struct
{
void *original;
void *new_ptr;
} CopyFixup;
typedef struct CopyStruct_
{
CopyFixup fixups[MAX_FIXUPS];
CopyFixup *current_fixup;
} CopyStruct;
#define MACRO_COPY_DECL(x) x = copy_decl(c, x)
#define MACRO_COPY_DECLID(x) x = declid_copy_deep(c, x)
#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(c, x)
#define MACRO_COPY_EXPR(x) x = copy_expr(c, x)
#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(c, x)
#define MACRO_COPY_TYPE(x) x = copy_type_info(c, x)
#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(c, x)
#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(c, x)
#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(c, x)
#define MACRO_COPY_AST(x) x = ast_copy_deep(c, x)
#define MACRO_COPY_ASTID(x) x = astid_copy_deep(c, x)
Expr *expr_macro_copy(Expr *source_expr);
Decl **decl_copy_list(Decl **decl_list);
Ast *ast_macro_copy(Ast *source_ast);
Expr **copy_expr_list(CopyStruct *c, Expr **expr_list);
Expr *copy_expr(CopyStruct *c, Expr *source_expr);
Ast *ast_copy_deep(CopyStruct *c, Ast *source);
Ast **copy_ast_list(CopyStruct *c, Ast **to_copy);
Decl *decl_copy_local_from_macro(CopyStruct *c, Decl *to_copy);
Decl *copy_decl(CopyStruct *c, Decl *decl);
Decl **copy_decl_list(CopyStruct *c, Decl **decl_list);
TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source);
/**
* Minimum alignment, values are either offsets or alignments.

View File

@@ -1,53 +1,114 @@
#include "compiler_internal.h"
Expr **copy_expr_list(Expr **expr_list)
#define SCOPE_FIXUP_START do { CopyFixup *current = c->current_fixup;
#define SCOPE_FIXUP_END c->current_fixup = current; } while (0)
static inline void copy_reg_ref(CopyStruct *c, void *original, void *result)
{
c->current_fixup->new_ptr = result;
c->current_fixup->original = original;
c->current_fixup++;
if (c->current_fixup == &c->fixups[MAX_FIXUPS])
{
error_exit("Too many fixups for macros.");
}
}
static inline void *fixup(CopyStruct *c, void *original)
{
CopyFixup *fixup_entry = c->current_fixup;
CopyFixup *first = &c->fixups[0];
while (fixup_entry != first)
{
fixup_entry--;
if (original == fixup_entry->original)
{
return fixup_entry->new_ptr;
}
}
return NULL;
}
INLINE void fixup_decl(CopyStruct *c, Decl **decl_ref)
{
Decl *new_decl = fixup(c, *decl_ref);
if (new_decl) *decl_ref = new_decl;
}
INLINE void fixup_declid(CopyStruct *c, DeclId *declid_ref)
{
DeclId id = *declid_ref;
if (!id) return;
Decl *decl = declptr(id);
decl = fixup(c, decl);
if (decl) *declid_ref = declid(decl);
}
INLINE void fixup_astid(CopyStruct *c, AstId *astid_ref)
{
AstId id = *astid_ref;
if (!id) return;
Ast *ast = astptr(id);
ast = fixup(c, ast);
if (ast) *astid_ref = astid(ast);
}
Expr **copy_expr_list(CopyStruct *c, Expr **expr_list)
{
Expr **result = NULL;
VECEACH(expr_list, i)
{
vec_add(result, copy_expr(expr_list[i]));
vec_add(result, copy_expr(c, expr_list[i]));
}
return result;
}
static inline Decl *decl_copy_label_from_macro(Decl *to_copy, Ast *ast)
static inline Decl *decl_copy_label_from_macro(CopyStruct *c, Decl *to_copy, Ast *ast)
{
if (!to_copy) return NULL;
to_copy = copy_decl(to_copy);
to_copy = copy_decl(c, to_copy);
to_copy->label.parent = astid(ast);
return to_copy;
}
static inline void copy_flow(Ast *ast)
static inline void copy_flow(CopyStruct *c, Ast *ast)
{
ast->flow.label = decl_copy_label_from_macro(ast->flow.label, ast);
ast->flow.label = decl_copy_label_from_macro(c, ast->flow.label, ast);
}
static TypeInfo** type_info_copy_list_from_macro(TypeInfo **to_copy)
static TypeInfo** type_info_copy_list_from_macro(CopyStruct *c, TypeInfo **to_copy)
{
TypeInfo **result = NULL;
VECEACH(to_copy, i)
{
vec_add(result, copy_type_info(to_copy[i]));
vec_add(result, copy_type_info(c, to_copy[i]));
}
return result;
}
static AstId astid_copy_deep(AstId source)
INLINE AstId astid_copy_deep(CopyStruct *c, AstId source)
{
if (!source) return 0;
return astid(ast_copy_deep(astptr(source)));
return astid(ast_copy_deep(c, astptr(source)));
}
static ExprId exprid_copy_deep(ExprId source)
INLINE ExprId exprid_copy_deep(CopyStruct *c, ExprId source)
{
if (!source) return 0;
return exprid(copy_expr(exprptr(source)));
return exprid(copy_expr(c, exprptr(source)));
}
INLINE DeclId declid_copy_deep(CopyStruct *c, DeclId source)
{
if (!source) return 0;
return declid(copy_decl(c, declptr(source)));
}
static DesignatorElement **macro_copy_designator_list(DesignatorElement **list)
static DesignatorElement **macro_copy_designator_list(CopyStruct *c, DesignatorElement **list)
{
DesignatorElement **result = NULL;
VECEACH(list, i)
@@ -74,8 +135,21 @@ static DesignatorElement **macro_copy_designator_list(DesignatorElement **list)
return result;
}
static CopyStruct copy_struct;
Expr *copy_expr(Expr *source_expr)
Ast *ast_macro_copy(Ast *source_ast)
{
copy_struct.current_fixup = copy_struct.fixups;
return ast_copy_deep(&copy_struct, source_ast);
}
Expr *expr_macro_copy(Expr *source_expr)
{
copy_struct.current_fixup = copy_struct.fixups;
return copy_expr(&copy_struct, source_expr);
}
Expr *copy_expr(CopyStruct *c, Expr *source_expr)
{
if (!source_expr) return NULL;
Expr *expr = expr_copy(source_expr);
@@ -86,9 +160,9 @@ Expr *copy_expr(Expr *source_expr)
case EXPR_ARGV_TO_SUBARRAY:
UNREACHABLE
case EXPR_FLATPATH:
case EXPR_UNDEF:
case EXPR_NOP:
case EXPR_BUILTIN:
case EXPR_RETVAL:
return expr;
case EXPR_DECL:
MACRO_COPY_DECL(expr->decl_expr);
@@ -107,16 +181,25 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_EXPR_LIST(expr->catch_unwrap_expr.exprs);
MACRO_COPY_TYPE(expr->catch_unwrap_expr.type);
return expr;
case EXPR_CT_IDENT:
case EXPR_IDENTIFIER:
if (expr->resolve_status == RESOLVE_DONE)
{
fixup_decl(c, &expr->identifier_expr.decl);
}
return expr;
case EXPR_CT_IDENT:
case EXPR_HASH_IDENT:
assert(expr->resolve_status != RESOLVE_DONE);
return expr;
case EXPR_COMPILER_CONST:
return expr;
case EXPR_MACRO_EXPANSION:
MACRO_COPY_EXPR(expr->macro_expansion_expr.inner);
SCOPE_FIXUP_START
MACRO_COPY_EXPR(expr->macro_expansion_expr.inner);
SCOPE_FIXUP_END;
return expr;
case EXPR_DESIGNATOR:
expr->designator_expr.path = macro_copy_designator_list(expr->designator_expr.path);
expr->designator_expr.path = macro_copy_designator_list(c, expr->designator_expr.path);
MACRO_COPY_EXPR(expr->designator_expr.value);
return expr;
case EXPR_TYPEINFO:
@@ -166,7 +249,7 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_TYPE(expr->expr_compound_literal.type_info);
return expr;
case EXPR_EXPR_BLOCK:
expr->expr_block.first_stmt = astid_copy_deep(expr->expr_block.first_stmt);
MACRO_COPY_ASTID(expr->expr_block.first_stmt);
return expr;
case EXPR_POISONED:
return source_expr;
@@ -193,11 +276,18 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_TYPE(expr->typeid_expr);
return expr;
case EXPR_CALL:
if (expr->resolve_status != RESOLVE_DONE || expr->call_expr.is_pointer_call)
if (expr->call_expr.is_func_ref)
{
MACRO_COPY_EXPR(expr->call_expr.function);
fixup_declid(c, &expr->call_expr.func_ref);
}
else
{
MACRO_COPY_EXPRID(expr->call_expr.function);
}
MACRO_COPY_ASTID(expr->call_expr.body);
MACRO_COPY_DECL_LIST(expr->call_expr.body_arguments);
MACRO_COPY_EXPR_LIST(expr->call_expr.arguments);
if (expr->call_expr.attributes) REMINDER("Copy attributes?");
return expr;
case EXPR_SUBSCRIPT:
case EXPR_SUBSCRIPT_ADDR:
@@ -222,13 +312,15 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_TYPE(expr->cast_expr.type_info);
return expr;
case EXPR_SCOPED_EXPR:
MACRO_COPY_EXPR(expr->expr_scope.expr);
SCOPE_FIXUP_START
MACRO_COPY_EXPR(expr->expr_scope.expr);
SCOPE_FIXUP_END;
return expr;
}
UNREACHABLE
}
AstDocDirective *doc_directive_copy(AstDocDirective *docs)
AstDocDirective *doc_directive_copy(CopyStruct *c, AstDocDirective *docs)
{
AstDocDirective *directive_new = NULL;
VECEACH(docs, i)
@@ -252,140 +344,167 @@ AstDocDirective *doc_directive_copy(AstDocDirective *docs)
return directive_new;
}
Ast *ast_copy_deep(Ast *source)
Ast *ast_copy_deep(CopyStruct *c, Ast *source)
{
if (!source) return NULL;
Ast *ast = ast_copy(source);
ast->next = astid_copy_deep(ast->next);
Ast *first_return = ast;
AstId *assign_to = NULL;
RETRY:
if (assign_to)
{
ast = ast_copy(source);
*assign_to = astid(ast);
}
switch (source->ast_kind)
{
case AST_POISONED:
return ast;
break;
case AST_ASM_STMT:
MACRO_COPY_EXPR(ast->asm_stmt.body);
return ast;
break;
case AST_ASSERT_STMT:
MACRO_COPY_EXPR(ast->ct_assert_stmt.expr);
MACRO_COPY_EXPR(ast->ct_assert_stmt.message);
return ast;
break;
case AST_BREAK_STMT:
case AST_CONTINUE_STMT:
return ast;
if (ast->contbreak_stmt.is_resolved)
{
fixup_astid(c, &ast->contbreak_stmt.ast);
}
break;
case AST_CASE_STMT:
copy_reg_ref(c, source, ast);
MACRO_COPY_AST(ast->case_stmt.body);
MACRO_COPY_EXPR(ast->case_stmt.expr);
MACRO_COPY_EXPR(ast->case_stmt.to_expr);
return ast;
break;
case AST_COMPOUND_STMT:
ast->compound_stmt.first_stmt = astid_copy_deep(ast->compound_stmt.first_stmt);
return ast;
MACRO_COPY_ASTID(ast->compound_stmt.first_stmt);
break;
case AST_CT_ASSERT:
MACRO_COPY_EXPR(ast->ct_assert_stmt.message);
MACRO_COPY_EXPR(ast->ct_assert_stmt.expr);
return ast;
break;
case AST_CT_IF_STMT:
MACRO_COPY_EXPR(ast->ct_if_stmt.expr);
MACRO_COPY_AST(ast->ct_if_stmt.elif);
MACRO_COPY_ASTID(ast->ct_if_stmt.then);
return ast;
break;
case AST_CT_ELSE_STMT:
MACRO_COPY_ASTID(ast->ct_else_stmt);
return ast;
break;
case AST_CT_FOREACH_STMT:
ast->ct_foreach_stmt.body = astid_copy_deep(ast->ct_foreach_stmt.body);
MACRO_COPY_EXPR(ast->ct_foreach_stmt.expr);
return ast;
MACRO_COPY_ASTID(ast->ct_foreach_stmt.body);
MACRO_COPY_EXPRID(ast->ct_foreach_stmt.expr);
break;
case AST_CT_SWITCH_STMT:
MACRO_COPY_EXPR(ast->ct_switch_stmt.cond);
MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body);
return ast;
break;
case AST_DECLARE_STMT:
MACRO_COPY_DECL(ast->declare_stmt);
return ast;
break;
case AST_DEFAULT_STMT:
MACRO_COPY_AST(ast->case_stmt.body);
return ast;
break;
case AST_DEFER_STMT:
assert(!ast->defer_stmt.prev_defer);
MACRO_COPY_AST(ast->defer_stmt.body);
return ast;
case AST_DO_STMT:
copy_flow(ast);
MACRO_COPY_ASTID(ast->do_stmt.body);
MACRO_COPY_EXPR(ast->do_stmt.expr);
return ast;
MACRO_COPY_ASTID(ast->defer_stmt.body);
copy_reg_ref(c, source, ast);
fixup_astid(c, &ast->defer_stmt.prev_defer);
break;
case AST_EXPR_STMT:
MACRO_COPY_EXPR(ast->expr_stmt);
return ast;
break;
case AST_FOR_STMT:
case AST_CT_FOR_STMT:
copy_flow(ast);
MACRO_COPY_EXPR(ast->for_stmt.cond);
MACRO_COPY_EXPR(ast->for_stmt.incr);
ast->for_stmt.body = astid_copy_deep(ast->for_stmt.body);
MACRO_COPY_EXPR(ast->for_stmt.init);
return ast;
copy_reg_ref(c, source, ast);
SCOPE_FIXUP_START
copy_flow(c, ast);
MACRO_COPY_EXPRID(ast->for_stmt.init);
MACRO_COPY_EXPRID(ast->for_stmt.cond);
MACRO_COPY_ASTID(ast->for_stmt.body);
MACRO_COPY_EXPRID(ast->for_stmt.incr);
SCOPE_FIXUP_END;
break;
case AST_FOREACH_STMT:
copy_flow(ast);
MACRO_COPY_DECL(ast->foreach_stmt.index);
MACRO_COPY_DECL(ast->foreach_stmt.variable);
MACRO_COPY_EXPR(ast->foreach_stmt.enumeration);
MACRO_COPY_AST(ast->foreach_stmt.body);
return ast;
copy_reg_ref(c, source, ast);
SCOPE_FIXUP_START
copy_flow(c, ast);
MACRO_COPY_EXPRID(ast->foreach_stmt.enumeration);
MACRO_COPY_DECLID(ast->foreach_stmt.index);
MACRO_COPY_DECLID(ast->foreach_stmt.variable);
MACRO_COPY_ASTID(ast->foreach_stmt.body);
SCOPE_FIXUP_END;
break;
case AST_IF_STMT:
copy_flow(ast);
MACRO_COPY_EXPR(ast->if_stmt.cond);
MACRO_COPY_AST(ast->if_stmt.else_body);
MACRO_COPY_AST(ast->if_stmt.then_body);
return ast;
// We don't scope "if" for the simple reason that it might introduce a wrapper alias.
copy_reg_ref(c, source, ast);
copy_flow(c, ast);
MACRO_COPY_EXPRID(ast->if_stmt.cond);
MACRO_COPY_ASTID(ast->if_stmt.else_body);
MACRO_COPY_ASTID(ast->if_stmt.then_body);
break;
case AST_NEXT_STMT:
MACRO_COPY_EXPR(ast->nextcase_stmt.expr);
return ast;
break;
case AST_NOP_STMT:
return ast;
break;
case AST_BLOCK_EXIT_STMT:
case AST_RETURN_STMT:
MACRO_COPY_EXPR(ast->return_stmt.expr);
return ast;
case AST_SCOPED_STMT:
ast->scoped_stmt.stmt = astid_copy_deep(ast->scoped_stmt.stmt);
return ast;
MACRO_COPY_ASTID(ast->return_stmt.cleanup);
break;
case AST_SWITCH_STMT:
case AST_IF_CATCH_SWITCH_STMT:
copy_flow(ast);
MACRO_COPY_EXPR(ast->switch_stmt.cond);
MACRO_COPY_AST_LIST(ast->switch_stmt.cases);
return ast;
case AST_WHILE_STMT:
copy_flow(ast);
MACRO_COPY_EXPRID(ast->while_stmt.cond);
MACRO_COPY_ASTID(ast->while_stmt.body);
return ast;
SCOPE_FIXUP_START
copy_flow(c, ast);
MACRO_COPY_EXPRID(ast->switch_stmt.cond);
MACRO_COPY_AST_LIST(ast->switch_stmt.cases);
SCOPE_FIXUP_END;
break;
}
UNREACHABLE;
assign_to = &ast->next;
AstId next = *assign_to;
if (!next) return first_return;
source = astptr(next);
goto RETRY;
}
Ast **copy_ast_list(Ast **to_copy)
Ast **copy_ast_list(CopyStruct *c, Ast **to_copy)
{
Ast **result = NULL;
VECEACH(to_copy, i)
{
vec_add(result, ast_copy_deep(to_copy[i]));
vec_add(result, ast_copy_deep(c, to_copy[i]));
}
return result;
}
Decl **copy_decl_list(Decl **decl_list)
Decl **decl_copy_list(Decl **decl_list)
{
copy_struct.current_fixup = copy_struct.fixups;
Decl **result = NULL;
VECEACH(decl_list, i)
{
vec_add(result, copy_decl(&copy_struct, decl_list[i]));
}
return result;
}
Decl **copy_decl_list(CopyStruct *c, Decl **decl_list)
{
Decl **result = NULL;
VECEACH(decl_list, i)
{
vec_add(result, copy_decl(decl_list[i]));
vec_add(result, copy_decl(c, decl_list[i]));
}
return result;
}
Decl *decl_copy_local_from_macro(Decl *to_copy)
Decl *decl_copy_local_from_macro(CopyStruct *c, Decl *to_copy)
{
if (!to_copy) return NULL;
assert(to_copy->decl_kind == DECL_VAR);
@@ -395,7 +514,7 @@ Decl *decl_copy_local_from_macro(Decl *to_copy)
return copy;
}
TypeInfo *copy_type_info(TypeInfo *source)
TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
{
if (!source) return NULL;
TypeInfo *copy = type_info_copy(source);
@@ -410,27 +529,27 @@ TypeInfo *copy_type_info(TypeInfo *source)
case TYPE_INFO_EVALTYPE:
case TYPE_INFO_EXPRESSION:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->unresolved_type_expr = copy_expr(source->unresolved_type_expr);
copy->unresolved_type_expr = copy_expr(c, source->unresolved_type_expr);
return copy;
case TYPE_INFO_VECTOR:
case TYPE_INFO_ARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.len = copy_expr(source->array.len);
copy->array.base = copy_type_info(source->array.base);
copy->array.len = copy_expr(c, source->array.len);
copy->array.base = copy_type_info(c, source->array.base);
return copy;
case TYPE_INFO_INFERRED_ARRAY:
case TYPE_INFO_SUBARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.base = copy_type_info(source->array.base);
copy->array.base = copy_type_info(c, source->array.base);
return copy;
case TYPE_INFO_POINTER:
copy->pointer = copy_type_info(source->pointer);
copy->pointer = copy_type_info(c, source->pointer);
return copy;
}
UNREACHABLE
}
static void copy_function_signature_deep(FunctionSignature *signature)
static void copy_function_signature_deep(CopyStruct *c, FunctionSignature *signature)
{
MACRO_COPY_DECL_LIST(signature->params);
MACRO_COPY_TYPE(signature->returntype);
@@ -446,7 +565,7 @@ void copy_decl_type(Decl *decl)
decl->type = copy;
}
static Attr **copy_attributes(Attr** attr_list)
static Attr **copy_attributes(CopyStruct *c, Attr** attr_list)
{
if (!attr_list) return attr_list;
Attr** list = NULL;
@@ -460,12 +579,13 @@ static Attr **copy_attributes(Attr** attr_list)
}
return list;
}
Decl *copy_decl(Decl *decl)
Decl *copy_decl(CopyStruct *c, Decl *decl)
{
if (!decl) return NULL;
Decl *copy = decl_copy(decl);
copy->docs = doc_directive_copy(copy->docs);
copy->attributes = copy_attributes(copy->attributes);
copy_reg_ref(c, decl, copy);
copy->docs = doc_directive_copy(c, copy->docs);
copy->attributes = copy_attributes(c, copy->attributes);
switch (decl->decl_kind)
{
case DECL_POISONED:
@@ -490,7 +610,7 @@ Decl *copy_decl(Decl *decl)
case DECL_FUNC:
MACRO_COPY_TYPE(copy->func_decl.type_parent);
copy->func_decl.annotations = NULL;
copy_function_signature_deep(&copy->func_decl.function_signature);
copy_function_signature_deep(c, &copy->func_decl.function_signature);
MACRO_COPY_AST(copy->func_decl.body);
break;
case DECL_VAR:
@@ -518,7 +638,7 @@ Decl *copy_decl(Decl *decl)
case DECL_TYPEDEF:
if (copy->typedef_decl.is_func)
{
copy_function_signature_deep(&copy->typedef_decl.function_signature);
copy_function_signature_deep(c, &copy->typedef_decl.function_signature);
break;
}
MACRO_COPY_TYPE(copy->typedef_decl.type_info);
@@ -527,7 +647,7 @@ Decl *copy_decl(Decl *decl)
MACRO_COPY_DECL_LIST(copy->methods);
if (copy->distinct_decl.typedef_decl.is_func)
{
copy_function_signature_deep(&copy->distinct_decl.typedef_decl.function_signature);
copy_function_signature_deep(c, &copy->distinct_decl.typedef_decl.function_signature);
break;
}
MACRO_COPY_TYPE(copy->distinct_decl.typedef_decl.type_info);
@@ -578,7 +698,7 @@ Decl *copy_decl(Decl *decl)
case DEFINE_IDENT_ALIAS:
break;
case DEFINE_ATTRIBUTE:
decl->define_decl.attributes.attrs = copy_attributes(decl->define_decl.attributes.attrs);
decl->define_decl.attributes.attrs = copy_attributes(c, decl->define_decl.attributes.attrs);
MACRO_COPY_DECL_LIST(decl->define_decl.attributes.params);
break;
}

View File

@@ -59,7 +59,6 @@ typedef enum
AST_DECLARE_STMT,
AST_DEFAULT_STMT,
AST_DEFER_STMT,
AST_DO_STMT,
AST_EXPR_STMT,
AST_FOR_STMT,
AST_FOREACH_STMT,
@@ -67,10 +66,9 @@ typedef enum
AST_IF_STMT,
AST_NOP_STMT,
AST_RETURN_STMT,
AST_BLOCK_EXIT_STMT,
AST_SWITCH_STMT,
AST_NEXT_STMT,
AST_WHILE_STMT,
AST_SCOPED_STMT,
} AstKind;
@@ -200,6 +198,7 @@ typedef enum
EXPR_MACRO_BLOCK,
EXPR_MACRO_EXPANSION,
EXPR_IDENTIFIER,
EXPR_RETVAL,
EXPR_FLATPATH,
EXPR_INITIALIZER_LIST,
EXPR_DESIGNATED_INITIALIZER_LIST,
@@ -221,7 +220,6 @@ typedef enum
EXPR_TYPEOFANY,
EXPR_TYPEINFO,
EXPR_UNARY,
EXPR_UNDEF,
EXPR_VARIANTSWITCH,
EXPR_NOP,
} ExprKind;

View File

@@ -1082,10 +1082,16 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_
gencontext_emit_member_addr(context, be_value, type_lowering(parent->type)->decl, member);
}
static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr)
static void llvm_emit_scoped_expr(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(context, value, expr->expr_scope.expr);
llvm_emit_defer(context, expr->expr_scope.defers.start, expr->expr_scope.defers.end);
llvm_emit_expr(c, value, expr->expr_scope.expr);
AstId current = expr->expr_scope.defer_stmts;
while (current)
{
Ast *ast = astptr(current);
llvm_emit_stmt(c, ast);
current = ast->next;
}
}
@@ -3521,7 +3527,7 @@ static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr
// Ensure we are on a branch that is non empty.
if (llvm_emit_check_block_branch(c))
{
llvm_emit_defer(c, expr->rethrow_expr.defer, 0);
llvm_emit_statement_chain(c, expr->rethrow_expr.cleanup);
BEValue value;
llvm_value_set_address_abi_aligned(&value, error_var, type_anyerr);
llvm_emit_return_abi(c, NULL, &value);
@@ -4430,7 +4436,7 @@ LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity)
void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
{
BuiltinFunction func = expr->call_expr.function->builtin_expr.builtin;
BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin;
if (func == BUILTIN_VOLATILE_STORE)
{
BEValue value;
@@ -4496,9 +4502,9 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
FunctionPrototype *prototype;
// 1. Call through a pointer.
if (expr->call_expr.is_pointer_call)
if (!expr->call_expr.is_func_ref)
{
Expr *function = expr->call_expr.function;
Expr *function = exprptr(expr->call_expr.function);
// 1a. Find the pointee type for the function pointer:
Type *type = function->type->canonical->pointer;
@@ -4508,7 +4514,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
// 1c. Evaluate the pointer expression.
BEValue func_value;
llvm_emit_expr(c, &func_value, expr->call_expr.function);
llvm_emit_expr(c, &func_value, function);
// 1d. Load it as a value
func = llvm_load_value_store(c, &func_value);
@@ -4520,7 +4526,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
{
// 2a. Get the function declaration
Decl *function_decl = expr->call_expr.func_ref;
Decl *function_decl = declptr(expr->call_expr.func_ref);
always_inline = function_decl->func_decl.attr_inline;
// 2b. Set signature, function and function type
@@ -4974,11 +4980,11 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
// Do we have a void function? That's the only
// possible case if the last statement isn't return.
if (value->ast_kind != AST_RETURN_STMT) break;
if (value->ast_kind != AST_BLOCK_EXIT_STMT) break;
// Defers? In that case we also use the default behaviour.
// We might optimize this later.
if (value->return_stmt.defer) break;
if (value->return_stmt.cleanup) break;
Expr *ret_expr = value->return_stmt.expr;
@@ -5457,6 +5463,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_COND:
case EXPR_MACRO_EXPANSION:
UNREACHABLE
case EXPR_RETVAL:
*value = c->retval;
return;
case EXPR_ARGV_TO_SUBARRAY:
llvm_emit_argv_to_subarray(c, value, expr);
return;
@@ -5469,9 +5478,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_CATCH_UNWRAP:
llvm_emit_catch_unwrap(c, value, expr);
return;
case EXPR_UNDEF:
// Should never reach this.
UNREACHABLE
case EXPR_PTR:
llvm_emit_ptr(c, value, expr);
return;
@@ -5518,7 +5524,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_expr_block(c, value, expr);
return;
case EXPR_SCOPED_EXPR:
gencontext_emit_scoped_expr(c, value, expr);
llvm_emit_scoped_expr(c, value, expr);
return;
case EXPR_UNARY:
gencontext_emit_unary_expr(c, value, expr);

View File

@@ -490,8 +490,6 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
// Insert a return (and defer) if needed.
if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block))
{
assert(!decl->func_decl.body->compound_stmt.defer_list.end);
llvm_emit_defer(context, decl->func_decl.body->compound_stmt.defer_list.start, 0);
llvm_emit_return_implicit(context);
}

View File

@@ -87,7 +87,6 @@ typedef struct
int simple_return_expressions;
unsigned pointer_alignment;
int return_expressions;
Ast **defer_stack;
DebugContext debug;
Module *code_module;
LLVMValueRef return_out;
@@ -95,6 +94,7 @@ typedef struct
LLVMBasicBlockRef block_return_exit;
LLVMBasicBlockRef block_failable_exit;
LLVMValueRef block_error_var;
BEValue retval;
int in_block;
bool current_block_is_target : 1;
bool did_call_stack_save : 1;
@@ -239,7 +239,7 @@ BEValue llvm_emit_assign_expr(GenContext *context, BEValue *ref, Expr *expr, LLV
static inline LLVMValueRef llvm_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type);
void llvm_emit_block(GenContext *c, LLVMBasicBlockRef next_block);
void llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block);
void llvm_emit_compound_stmt(GenContext *context, Ast *ast);
void llvm_emit_compound_stmt(GenContext *c, Ast *ast);
LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer);
void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type);
void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignment, LLVMTypeRef coerced, LLVMValueRef value, LLVMTypeRef target_type);
@@ -254,7 +254,7 @@ void llvm_emit_debug_location(GenContext *context, SourceSpan location);
void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index);
void llvm_emit_debug_local_var(GenContext *c, Decl *var);
void llvm_emit_debug_global_var(GenContext *c, Decl *global);
void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end);
void llvm_emit_extern_decl(GenContext *context, Decl *decl);
LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init);
void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr);
@@ -475,6 +475,14 @@ static inline void llvm_set_alignment(LLVMValueRef alloca, AlignSize alignment)
void llvm_set_error_exit(GenContext *c, LLVMBasicBlockRef block);
void llvm_set_error_exit_and_value(GenContext *c, LLVMBasicBlockRef block, LLVMValueRef value);
INLINE void llvm_emit_statement_chain(GenContext *c, AstId current)
{
while (current)
{
llvm_emit_stmt(c, ast_next(&current));
}
}
#define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0);
#define PUSH_ERROR() \

View File

@@ -7,22 +7,17 @@
static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast);
void llvm_emit_compound_stmt(GenContext *context, Ast *ast)
void llvm_emit_compound_stmt(GenContext *c, Ast *ast)
{
if (llvm_use_debug(context))
if (llvm_use_debug(c))
{
llvm_debug_push_lexical_scope(context, ast->span);
llvm_debug_push_lexical_scope(c, ast->span);
}
assert(ast->ast_kind == AST_COMPOUND_STMT);
AstId current = ast->compound_stmt.first_stmt;
while (current)
llvm_emit_statement_chain(c, ast->compound_stmt.first_stmt);
if (llvm_use_debug(c))
{
llvm_emit_stmt(context, ast_next(&current));
}
llvm_emit_defer(context, ast->compound_stmt.defer_list.start, ast->compound_stmt.defer_list.end);
if (llvm_use_debug(context))
{
llvm_debug_scope_pop(context);
llvm_debug_scope_pop(c);
}
}
@@ -67,7 +62,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
if (init)
{
// If we don't have undef, then make an assign.
if (init->expr_kind != EXPR_UNDEF)
if (!decl->var.no_init)
{
BEValue value;
llvm_value_set_decl_address(&value, decl);
@@ -152,21 +147,14 @@ void llvm_emit_jmp(GenContext *context, LLVMBasicBlockRef block)
llvm_emit_block(context, post_jump_block);
}
static inline void gencontext_emit_return(GenContext *c, Ast *ast)
static inline void llvm_emit_return(GenContext *c, Ast *ast)
{
bool in_expression_block = c->in_block > 0;
PUSH_ERROR();
LLVMBasicBlockRef error_return_block = NULL;
LLVMValueRef error_out = NULL;
if (in_expression_block)
{
c->error_var = c->block_error_var;
c->catch_block = c->block_failable_exit;
}
else if (type_is_failable(c->cur_func_decl->type->func.prototype->rtype))
if (type_is_failable(c->cur_func_decl->type->func.prototype->rtype))
{
error_return_block = llvm_basic_block_new(c, "err_retblock");
error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr");
@@ -180,23 +168,15 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast)
{
llvm_emit_expr(c, &return_value, ast->return_stmt.expr);
llvm_value_fold_failable(c, &return_value);
c->retval = return_value;
}
POP_ERROR();
llvm_emit_defer(c, ast->return_stmt.defer, 0);
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
// Are we in an expression block?
if (in_expression_block)
{
if (c->return_out)
{
llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type));
}
llvm_emit_jmp(c, c->block_return_exit);
return;
}
if (!has_return_value)
{
llvm_emit_return_implicit(c);
@@ -218,6 +198,34 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast)
llvm_emit_block(c, post_ret_block);
}
static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast)
{
PUSH_ERROR();
LLVMBasicBlockRef error_return_block = NULL;
LLVMValueRef error_out = NULL;
c->error_var = c->block_error_var;
c->catch_block = c->block_failable_exit;
bool has_return_value = ast->return_stmt.expr != NULL;
BEValue return_value = { 0 };
if (has_return_value)
{
llvm_emit_expr(c, &return_value, ast->return_stmt.expr);
llvm_value_fold_failable(c, &return_value);
}
POP_ERROR();
llvm_emit_statement_chain(c, ast->return_stmt.cleanup);
if (c->return_out)
{
llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type));
}
llvm_emit_jmp(c, c->block_return_exit);
}
/**
@@ -236,7 +244,7 @@ void llvm_emit_if(GenContext *c, Ast *ast)
LLVMBasicBlockRef then_block = exit_block;
LLVMBasicBlockRef else_block = exit_block;
Ast *then_body = ast->if_stmt.then_body;
Ast *then_body = astptr(ast->if_stmt.then_body);
// Only generate a target if
if (ast_is_not_empty(then_body))
{
@@ -244,12 +252,15 @@ void llvm_emit_if(GenContext *c, Ast *ast)
}
// We have an optional else block.
if (ast_is_not_empty(ast->if_stmt.else_body))
AstId else_id = ast->if_stmt.else_body;
Ast *else_body = else_id ? astptr(else_id) : NULL;
if (ast_is_not_empty(else_body))
{
else_block = llvm_basic_block_new(c, "if.else");
}
ast->if_stmt.break_block = exit_block;
Expr *cond = exprptr(ast->if_stmt.cond);
ast->if_stmt.codegen.break_block = exit_block;
// Output boolean value and switch.
@@ -265,7 +276,7 @@ void llvm_emit_if(GenContext *c, Ast *ast)
if (then_body->ast_kind == AST_IF_CATCH_SWITCH_STMT)
{
llvm_emit_decl_expr_list(c, &be_value, ast->if_stmt.cond, false);
llvm_emit_decl_expr_list(c, &be_value, cond, false);
llvm_value_rvalue(c, &be_value);
BEValue comp;
llvm_emit_int_comp_zero(c, &comp, &be_value, BINARYOP_NE);
@@ -277,7 +288,7 @@ void llvm_emit_if(GenContext *c, Ast *ast)
goto EMIT_ELSE;
}
llvm_emit_decl_expr_list(c, &be_value, ast->if_stmt.cond, true);
llvm_emit_decl_expr_list(c, &be_value, cond, true);
llvm_value_rvalue(c, &be_value);
@@ -313,7 +324,7 @@ void llvm_emit_if(GenContext *c, Ast *ast)
if (then_block != exit_block)
{
llvm_emit_block(c, then_block);
llvm_emit_stmt(c, ast->if_stmt.then_body);
llvm_emit_stmt(c, then_body);
// Jump to exit.
llvm_emit_br(c, exit_block);
@@ -324,7 +335,7 @@ void llvm_emit_if(GenContext *c, Ast *ast)
if (else_block != exit_block)
{
llvm_emit_block(c, else_block);
llvm_emit_stmt(c, ast->if_stmt.else_body);
llvm_emit_stmt(c, else_body);
llvm_emit_br(c, exit_block);
}
@@ -342,12 +353,12 @@ typedef enum
LOOP_NONE
} LoopType;
static inline LoopType loop_type_for_cond(Expr *cond, bool skip_first)
static inline LoopType loop_type_for_cond(Expr *cond, bool do_while)
{
if (!cond)
{
// We may have do-while (0)
if (skip_first) return LOOP_NONE;
if (do_while) return LOOP_NONE;
// OR we have for (int x;;x++)
return LOOP_INFINITE;
@@ -375,10 +386,10 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
{
// First, emit all inits.
BEValue value;
if (ast->for_stmt.init) llvm_emit_expr(c, &value, ast->for_stmt.init);
if (ast->for_stmt.init) llvm_emit_expr(c, &value, exprptr(ast->for_stmt.init));
bool no_exit = ast->for_stmt.flow.no_exit;
Expr *incr = ast->for_stmt.incr;
ExprId incr = ast->for_stmt.incr;
LLVMBasicBlockRef inc_block = incr ? llvm_basic_block_new(c, "loop.inc") : NULL;
Ast *body = astptr(ast->for_stmt.body);
@@ -388,7 +399,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
// Skipping first cond? This is do-while semantics
bool skip_first = ast->for_stmt.flow.skip_first;
Expr *cond = ast->for_stmt.cond;
ExprId cond_id = ast->for_stmt.cond;
Expr *cond = cond_id ? exprptr(cond_id) : NULL;
LoopType loop = loop_type_for_cond(cond, skip_first);
// This is the starting block to loop back to, and may either be cond, body or inc
@@ -433,8 +445,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
continue_block = loop == LOOP_NONE ? exit_block : loop_start_block;
}
ast->for_stmt.continue_block = continue_block;
ast->for_stmt.exit_block = exit_block;
ast->for_stmt.codegen.continue_block = continue_block;
ast->for_stmt.codegen.exit_block = exit_block;
// We have a normal loop, so we emit a cond.
if (loop == LOOP_NORMAL)
@@ -527,7 +539,7 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
llvm_emit_block(c, inc_block);
}
BEValue dummy;
llvm_emit_expr(c, &dummy, incr);
llvm_emit_expr(c, &dummy, incr ? exprptr(incr) : NULL);
}
// Loop back.
@@ -686,7 +698,9 @@ static void llvm_emit_switch_jump_table(GenContext *c,
static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast)
{
bool is_if_chain = switch_ast->switch_stmt.if_chain;
bool is_if_chain = switch_ast->switch_stmt.flow.if_chain;
Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyerr) : exprptr(switch_ast->switch_stmt.cond)->type;
Ast **cases = switch_ast->switch_stmt.cases;
ArraySize case_count = vec_size(cases);
if (!case_count)
@@ -738,8 +752,6 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As
case_stmt->case_stmt.backend_block = next_block;
}
Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyerr) : switch_ast->switch_stmt.cond->type;
BEValue switch_var;
llvm_value_set_address_abi_aligned(&switch_var, llvm_emit_alloca_aligned(c, switch_type, "switch"), switch_type);
switch_ast->switch_stmt.codegen.retry_var = &switch_var;
@@ -804,82 +816,54 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As
void gencontext_emit_switch(GenContext *context, Ast *ast)
{
BEValue switch_value;
llvm_emit_decl_expr_list(context, &switch_value, ast->switch_stmt.cond, false);
llvm_emit_decl_expr_list(context, &switch_value, exprptr(ast->switch_stmt.cond), false);
gencontext_emit_switch_body(context, &switch_value, ast);
}
void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end)
{
if (defer_start == defer_end) return;
AstId defer = defer_start;
while (defer && defer != defer_end)
{
Ast *def = astptr(defer);
LLVMBasicBlockRef exit = llvm_basic_block_new(c, "exit");
Ast *body = def->defer_stmt.body;
def->defer_stmt.codegen.exit_block = exit;
llvm_emit_stmt(c, body);
llvm_emit_br(c, exit);
llvm_emit_block(c, exit);
defer = def->defer_stmt.prev_defer;
}
}
void gencontext_emit_break(GenContext *context, Ast *ast)
void llvm_emit_break(GenContext *c, Ast *ast)
{
llvm_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end);
llvm_emit_statement_chain(c, ast->contbreak_stmt.defers);
Ast *jump_target = astptr(ast->contbreak_stmt.ast);
LLVMBasicBlockRef jump;
switch (jump_target->ast_kind)
{
case AST_IF_STMT:
jump = jump_target->if_stmt.break_block;
break;
case AST_FOREACH_STMT:
jump = jump_target->foreach_stmt.exit_block;
jump = jump_target->if_stmt.codegen.break_block;
break;
case AST_FOR_STMT:
jump = jump_target->for_stmt.exit_block;
jump = jump_target->for_stmt.codegen.exit_block;
break;
case AST_DO_STMT:
case AST_WHILE_STMT:
UNREACHABLE
case AST_IF_CATCH_SWITCH_STMT:
case AST_SWITCH_STMT:
jump = jump_target->switch_stmt.codegen.exit_block;
break;
case AST_DEFER_STMT:
jump = jump_target->defer_stmt.codegen.exit_block;
break;
case AST_FOREACH_STMT:
default:
UNREACHABLE
}
llvm_emit_jmp(context, jump);
llvm_emit_jmp(c, jump);
}
void gencontext_emit_continue(GenContext *context, Ast *ast)
void llvm_emit_continue(GenContext *c, Ast *ast)
{
llvm_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end);
llvm_emit_statement_chain(c, ast->contbreak_stmt.defers);
Ast *jump_target = astptr(ast->contbreak_stmt.ast);
LLVMBasicBlockRef jump;
switch (jump_target->ast_kind)
{
case AST_IF_STMT:
case AST_SWITCH_STMT:
case AST_WHILE_STMT:
case AST_DO_STMT:
UNREACHABLE
case AST_FOREACH_STMT:
jump = jump_target->foreach_stmt.continue_block;
UNREACHABLE
break;
case AST_FOR_STMT:
jump = jump_target->for_stmt.continue_block;
jump = jump_target->for_stmt.codegen.continue_block;
break;
default:
UNREACHABLE
}
llvm_emit_jmp(context, jump);
llvm_emit_jmp(c, jump);
}
void gencontext_emit_next_stmt(GenContext *context, Ast *ast)
@@ -887,23 +871,17 @@ void gencontext_emit_next_stmt(GenContext *context, Ast *ast)
Ast *jump_target = astptr(ast->nextcase_stmt.case_switch_stmt);
if (jump_target->ast_kind != AST_SWITCH_STMT)
{
llvm_emit_defer(context, ast->nextcase_stmt.defers.start, ast->nextcase_stmt.defers.end);
llvm_emit_statement_chain(context, ast->nextcase_stmt.defer_id);
llvm_emit_jmp(context, jump_target->case_stmt.backend_block);
return;
}
BEValue be_value;
llvm_emit_expr(context, &be_value, ast->nextcase_stmt.switch_expr);
llvm_store_value(context, jump_target->switch_stmt.codegen.retry_var, &be_value);
llvm_emit_defer(context, ast->nextcase_stmt.defers.start, ast->nextcase_stmt.defers.end);
llvm_emit_statement_chain(context, ast->nextcase_stmt.defer_id);
llvm_emit_jmp(context, jump_target->switch_stmt.codegen.retry_block);
}
void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
{
llvm_emit_stmt(context, astptr(ast->scoped_stmt.stmt));
llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
}
static inline void llvm_emit_assume(GenContext *c, Expr *expr)
{
@@ -1232,12 +1210,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_POISONED:
case AST_IF_CATCH_SWITCH_STMT:
case AST_FOREACH_STMT:
case AST_WHILE_STMT:
case AST_DO_STMT:
UNREACHABLE
case AST_SCOPED_STMT:
gencontext_emit_scoped_stmt(c, ast);
break;
case AST_EXPR_STMT:
gencontext_emit_expr_stmt(c, ast);
break;
@@ -1245,16 +1218,19 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
llvm_emit_local_decl(c, ast->declare_stmt);
break;
case AST_BREAK_STMT:
gencontext_emit_break(c, ast);
llvm_emit_break(c, ast);
break;
case AST_CONTINUE_STMT:
gencontext_emit_continue(c, ast);
llvm_emit_continue(c, ast);
break;
case AST_IF_STMT:
llvm_emit_if(c, ast);
break;
case AST_RETURN_STMT:
gencontext_emit_return(c, ast);
llvm_emit_return(c, ast);
break;
case AST_BLOCK_EXIT_STMT:
llvm_emit_block_exit_return(c, ast);
break;
case AST_COMPOUND_STMT:
llvm_emit_compound_stmt(c, ast);

View File

@@ -565,28 +565,6 @@ static Expr *parse_grouping_expr(ParseContext *c, Expr *left)
return expr;
}
/**
* initializer
* : initializer_list
* | expr
* | void
* ;
*
* @param c
* @return the parsed expression
*/
Expr *parse_initializer(ParseContext *c)
{
if (tok_is(c, TOKEN_VOID))
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_UNDEF);
expr->type = type_void;
expr->resolve_status = RESOLVE_DONE;
advance(c);
return expr;
}
return parse_expr(c);
}
/**
* initializer_list
@@ -719,7 +697,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
advance(c);
Expr *call = EXPR_NEW_EXPR(EXPR_CALL, left);
call->call_expr.function = left;
call->call_expr.function = exprid(left);
call->call_expr.arguments = params;
call->call_expr.unsplat_last = unsplat;
call->call_expr.body_arguments = body_args;
@@ -731,7 +709,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
}
if (tok_is(c, TOKEN_LBRACE))
{
ASSIGN_AST_OR_RET(call->call_expr.body, parse_compound_stmt(c), poisoned_expr);
ASSIGN_ASTID_OR_RET(call->call_expr.body, parse_compound_stmt(c), poisoned_expr);
}
if (!parse_attributes(c, &call->call_expr.attributes)) return false;
return call;
@@ -911,6 +889,12 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left)
static Expr *parse_identifier(ParseContext *c, Expr *left)
{
assert(!left && "Unexpected left hand side");
if (symstr(c) == kw_return)
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_RETVAL);
advance(c);
return expr;
}
Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER);
expr->identifier_expr.ident = symstr(c);
expr->identifier_expr.is_const = tok_is(c, TOKEN_CONST_IDENT);

View File

@@ -70,6 +70,22 @@ void recover_top_level(ParseContext *c)
}
}
static inline bool parse_decl_initializer(ParseContext *c, Decl *decl, bool allow_void)
{
if (try_consume(c, TOKEN_VOID))
{
if (!allow_void)
{
SEMA_ERROR_LAST("'void' is not allowed here, it's only allowed for non constant global and local variables.");
return false;
}
decl->var.no_init = true;
return true;
}
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_expr(c), false);
return true;
}
// --- Parse CT conditional code
static inline bool parse_top_level_block(ParseContext *c, Decl ***decls, TokenType end1, TokenType end2, TokenType end3)
@@ -699,7 +715,7 @@ Decl *parse_decl_after_type(ParseContext *c, TypeInfo *type)
return poisoned_decl;
}
advance_and_verify(c, TOKEN_EQ);
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl);
if (!parse_decl_initializer(c, decl, true)) return poisoned_decl;
}
return decl;
}
@@ -763,7 +779,7 @@ static Decl *parse_const_declaration(ParseContext *c, Visibility visibility)
CONSUME_OR_RET(TOKEN_EQ, poisoned_decl);
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl);
if (!parse_decl_initializer(c, decl, false)) return poisoned_decl;
RANGE_EXTEND_PREV(decl);
@@ -904,7 +920,7 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
if (try_consume(c, TOKEN_EQ))
{
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl);
if (!parse_decl_initializer(c, decl, true)) return poisoned_decl;
}
CONSUME_EOS_OR_RET(poisoned_decl);
return decl;
@@ -945,7 +961,7 @@ static inline bool parse_param_decl(ParseContext *c, Visibility parent_visibilit
}
if (name && try_consume(c, TOKEN_EQ))
{
ASSIGN_EXPR_OR_RET(param->var.init_expr, parse_initializer(c), false);
if (!parse_decl_initializer(c, param, false)) return poisoned_decl;
}
vec_add(*parameters, param);
@@ -1090,7 +1106,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
advance(c);
if (try_consume(c, TOKEN_EQ))
{
ASSIGN_EXPR_OR_RET(param->var.init_expr, parse_initializer(c), false);
if (!parse_decl_initializer(c, param, false)) return poisoned_decl;
}
}
if (!parse_attributes(c, &param->attributes)) return false;

View File

@@ -71,21 +71,29 @@ static inline Ast* parse_asm_stmt(ParseContext *c)
*/
static inline Ast* parse_do_stmt(ParseContext *c)
{
Ast *do_ast = new_ast(AST_DO_STMT, c->span);
Ast *do_ast = new_ast(AST_FOR_STMT, c->span);
advance_and_verify(c, TOKEN_DO);
ASSIGN_DECL_OR_RET(do_ast->do_stmt.flow.label, parse_optional_label(c, do_ast), poisoned_ast);
ASSIGN_ASTID_OR_RET(do_ast->do_stmt.body, parse_stmt(c), poisoned_ast);
do_ast->flow.skip_first = true;
ASSIGN_DECL_OR_RET(do_ast->for_stmt.flow.label, parse_optional_label(c, do_ast), poisoned_ast);
ASSIGN_ASTID_OR_RET(do_ast->for_stmt.body, parse_stmt(c), poisoned_ast);
if (try_consume(c, TOKEN_WHILE))
if (try_consume(c, TOKEN_EOS))
{
Expr *exit = expr_new(EXPR_CONST, c->prev_span);
expr_const_set_bool(&exit->const_expr, false);
exit->type = type_bool;
do_ast->for_stmt.cond = exprid(exit);
}
else
{
CONSUME_OR_RET(TOKEN_WHILE, poisoned_ast);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast);
ASSIGN_EXPR_OR_RET(do_ast->do_stmt.expr, parse_expr(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(do_ast->for_stmt.cond, parse_expr(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
CONSUME_OR_RET(TOKEN_EOS, poisoned_ast);
}
return do_ast;
}
@@ -117,7 +125,7 @@ static inline Ast* parse_defer_stmt(ParseContext *c)
{
advance_and_verify(c, TOKEN_DEFER);
Ast *defer_stmt = new_ast(AST_DEFER_STMT, c->span);
ASSIGN_AST_OR_RET(defer_stmt->defer_stmt.body, parse_stmt(c), poisoned_ast);
ASSIGN_ASTID_OR_RET(defer_stmt->defer_stmt.body, parse_stmt(c), poisoned_ast);
return defer_stmt;
}
@@ -127,15 +135,22 @@ static inline Ast* parse_defer_stmt(ParseContext *c)
*/
static inline Ast* parse_while_stmt(ParseContext *c)
{
Ast *while_ast = new_ast(AST_WHILE_STMT, c->span);
Ast *while_ast = new_ast(AST_FOR_STMT, c->span);
advance_and_verify(c, TOKEN_WHILE);
ASSIGN_DECL_OR_RET(while_ast->while_stmt.flow.label, parse_optional_label(c, while_ast), poisoned_ast);
ASSIGN_DECL_OR_RET(while_ast->for_stmt.flow.label, parse_optional_label(c, while_ast), poisoned_ast);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast);
ASSIGN_EXPRID_OR_RET(while_ast->while_stmt.cond, parse_cond(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(while_ast->for_stmt.cond, parse_cond(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
ASSIGN_ASTID_OR_RET(while_ast->while_stmt.body, parse_stmt(c), poisoned_ast);
unsigned row = c->prev_span.row;
ASSIGN_AST_OR_RET(Ast *body, parse_stmt(c), poisoned_ast);
if (body->ast_kind != AST_COMPOUND_STMT && row != c->prev_span.row)
{
SEMA_ERROR(body, "A single statement after 'while' must be placed on the same line, or be enclosed in {}.");
return poisoned_ast;
}
while_ast->for_stmt.body = astid(body);
return while_ast;
}
@@ -164,7 +179,7 @@ static inline Ast* parse_if_stmt(ParseContext *c)
advance_and_verify(c, TOKEN_IF);
ASSIGN_DECL_OR_RET(if_ast->if_stmt.flow.label, parse_optional_label(c, if_ast), poisoned_ast);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast);
ASSIGN_EXPR_OR_RET(if_ast->if_stmt.cond, parse_cond(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(if_ast->if_stmt.cond, parse_cond(c), poisoned_ast);
unsigned row = c->span.row;
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
// Special case, we might have if ( ) { case ... }
@@ -174,23 +189,23 @@ static inline Ast* parse_if_stmt(ParseContext *c)
Ast **cases = NULL;
if (!parse_switch_body(c, &cases, TOKEN_CASE, TOKEN_DEFAULT, true)) return poisoned_ast;
stmt->switch_stmt.cases = cases;
if_ast->if_stmt.then_body = stmt;
if_ast->if_stmt.then_body = astid(stmt);
}
else
{
unsigned next_row = c->span.row;
ASSIGN_AST_OR_RET(if_ast->if_stmt.then_body, parse_stmt(c), poisoned_ast);
if (row != next_row && if_ast->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT)
ASSIGN_ASTID_OR_RET(if_ast->if_stmt.then_body, parse_stmt(c), poisoned_ast);
if (row != next_row && astptr(if_ast->if_stmt.then_body)->ast_kind != AST_COMPOUND_STMT)
{
// Poison it and pick it up later.
ast_poison(if_ast->if_stmt.then_body);
ast_poison(astptr(if_ast->if_stmt.then_body));
}
}
if (!try_consume(c, TOKEN_ELSE))
{
return if_ast;
}
ASSIGN_AST_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast);
ASSIGN_ASTID_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast);
return if_ast;
}
@@ -283,7 +298,7 @@ static inline Ast* parse_switch_stmt(ParseContext *c)
advance_and_verify(c, TOKEN_SWITCH);
ASSIGN_DECL_OR_RET(switch_ast->switch_stmt.flow.label, parse_optional_label(c, switch_ast), poisoned_ast);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast);
ASSIGN_EXPR_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
if (!parse_switch_body(c, &switch_ast->switch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT, false)) return poisoned_ast;
@@ -310,25 +325,25 @@ static inline Ast* parse_for_stmt(ParseContext *c)
if (!tok_is(c, TOKEN_EOS))
{
ASSIGN_EXPR_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast);
}
else
{
ast->for_stmt.init = NULL;
ast->for_stmt.init = 0;
}
CONSUME_OR_RET(TOKEN_EOS, poisoned_ast);
if (!tok_is(c, TOKEN_EOS))
{
ASSIGN_EXPR_OR_RET(ast->for_stmt.cond, parse_cond(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.cond, parse_cond(c), poisoned_ast);
}
CONSUME_OR_RET(TOKEN_EOS, poisoned_ast);
if (!tok_is(c, TOKEN_RPAREN))
{
ast->for_stmt.incr = parse_expression_list(c, false);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.incr, parse_expression_list(c, false), poisoned_ast);
}
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
@@ -366,7 +381,7 @@ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach)
SEMA_ERROR_HERE("Expected an identifier or type.");
return false;
}
foreach->foreach_stmt.variable = var;
foreach->foreach_stmt.variable = declid(var);
return true;
}
/**
@@ -398,12 +413,12 @@ static inline Ast* parse_foreach_stmt(ParseContext *c)
CONSUME_OR_RET(TOKEN_COLON, poisoned_ast);
ASSIGN_EXPR_OR_RET(ast->foreach_stmt.enumeration, parse_initializer(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->foreach_stmt.enumeration, parse_expr(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
RANGE_EXTEND_PREV(ast);
ASSIGN_AST_OR_RET(ast->foreach_stmt.body, parse_stmt(c), poisoned_ast);
ASSIGN_ASTID_OR_RET(ast->foreach_stmt.body, parse_stmt(c), poisoned_ast);
return ast;
}
@@ -608,7 +623,6 @@ static inline Ast *parse_return(ParseContext *c)
{
advance_and_verify(c, TOKEN_RETURN);
Ast *ast = ast_new_curr(c, AST_RETURN_STMT);
ast->return_stmt.defer = 0;
if (!tok_is(c, TOKEN_EOS))
{
ASSIGN_EXPR_OR_RET(ast->return_stmt.expr, parse_expr(c), poisoned_ast);
@@ -645,7 +659,7 @@ static inline Ast* parse_ct_foreach_stmt(ParseContext *c)
ast->ct_foreach_stmt.value_span = c->span;
TRY_CONSUME_OR_RET(TOKEN_CT_IDENT, "Expected a compile time variable", poisoned_ast);
TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected ':'.", poisoned_ast);
ASSIGN_EXPR_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);
CONSUME_OR_RET(TOKEN_COLON, poisoned_ast);
Ast *body = new_ast(AST_COMPOUND_STMT, ast->span);
@@ -673,17 +687,17 @@ static inline Ast* parse_ct_for_stmt(ParseContext *c)
if (!tok_is(c, TOKEN_EOS))
{
ASSIGN_EXPR_OR_RET(ast->for_stmt.init, parse_ct_expression_list(c, true), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_ct_expression_list(c, true), poisoned_ast);
}
CONSUME_OR_RET(TOKEN_EOS, poisoned_ast);
// Cond is required.
ASSIGN_EXPR_OR_RET(ast->for_stmt.cond, parse_expr(c), poisoned_ast);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.cond, parse_expr(c), poisoned_ast);
CONSUME_OR_RET(TOKEN_EOS, poisoned_ast);
if (!tok_is(c, TOKEN_RPAREN))
{
ast->for_stmt.incr = parse_ct_expression_list(c, false);
ASSIGN_EXPRID_OR_RET(ast->for_stmt.incr, parse_ct_expression_list(c, false), poisoned_ast);
}
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast);

View File

@@ -26,7 +26,6 @@ TypeInfo *parse_type(ParseContext *c);
TypeInfo *parse_failable_type(ParseContext *c);
TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info);
Expr* parse_constant_expr(ParseContext *c);
Expr *parse_initializer(ParseContext *c);
void parse_imports(ParseContext *c);
Decl *parse_decl(ParseContext *c);
Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref);

View File

@@ -755,6 +755,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
case EXPR_SLICE_ASSIGN:
case EXPR_SLICE:
case EXPR_SUBSCRIPT:
case EXPR_RETVAL:
if (type_size(expr->type) > type_size(type)) return expr;
return NULL;
case EXPR_OR_ERROR:
@@ -802,7 +803,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_TYPEID:
case EXPR_TYPEINFO:
case EXPR_UNDEF:
case EXPR_CT_CALL:
case EXPR_NOP:
case EXPR_LEN:
@@ -912,6 +912,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
case EXPR_SLICE_ASSIGN:
case EXPR_SLICE:
case EXPR_SUBSCRIPT:
case EXPR_RETVAL:
if (type_size(expr->type) > type_size(type)) return expr;
return NULL;
case EXPR_LEN:
@@ -959,7 +960,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_TYPEID:
case EXPR_TYPEINFO:
case EXPR_UNDEF:
case EXPR_CT_CALL:
case EXPR_NOP:
case EXPR_BUILTIN:

View File

@@ -1432,7 +1432,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
AstId *next = &body->compound_stmt.first_stmt;
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
Expr *call = expr_new(EXPR_CALL, decl->span);
call->call_expr.function = expr_variable(decl);
call->call_expr.function = exprid(expr_variable(decl));
if (subarray_param)
{
Expr *subarray = expr_new(EXPR_ARGV_TO_SUBARRAY, decl->span);
@@ -1962,12 +1962,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
SEMA_ERROR(decl, "Constants need to have an initial value.");
return false;
}
// 1b. We require defined constants
if (init_expr->expr_kind == EXPR_UNDEF)
{
SEMA_ERROR(decl, "Constants cannot be undefined.");
return false;
}
assert(!decl->var.no_init);
if (!decl->var.type_info)
{
if (!sema_analyse_expr(context, init_expr)) return false;
@@ -1992,20 +1987,15 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
decl->external_name = scratch_buffer_copy();
}
bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY;
if (!decl->var.init_expr && type_is_inferred)
{
SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred without an initializer.");
return false;
}
if (decl->var.init_expr)
{
bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY;
Expr *init = decl->var.init_expr;
// Handle explicit undef
if (init->expr_kind == EXPR_UNDEF)
{
if (type_is_inferred)
{
SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred with explicit undef.");
return false;
}
goto EXIT_OK;
}
if (!type_is_inferred)
{
@@ -2054,8 +2044,8 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
{
CompilationUnit *copy = unit_create(unit->file);
copy->imports = copy_decl_list(unit->imports);
copy->global_decls = copy_decl_list(unit->global_decls);
copy->imports = decl_copy_list(unit->imports);
copy->global_decls = decl_copy_list(unit->global_decls);
copy->module = module;
assert(!unit->functions && !unit->macro_methods && !unit->methods && !unit->enums && !unit->ct_ifs && !unit->types && !unit->external_symbol_list);
return copy;

View File

@@ -153,7 +153,7 @@ Expr *expr_generate_decl(Decl *decl, Expr *assign)
assert(decl->var.init_expr == NULL);
Expr *expr_decl = expr_new(EXPR_DECL, decl->span);
expr_decl->decl_expr = decl;
if (!assign) assign = expr_new(EXPR_UNDEF, decl->span);
if (!assign) decl->var.no_init = true;
decl->var.init_expr = assign;
return expr_decl;
}
@@ -346,6 +346,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
RETRY:
switch (expr->expr_kind)
{
case EXPR_RETVAL:
return false;
case EXPR_BUILTIN:
case EXPR_CT_EVAL:
return false;
@@ -385,7 +387,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
case EXPR_SLICE_ASSIGN:
case EXPR_MACRO_BLOCK:
case EXPR_RETHROW:
case EXPR_UNDEF:
return false;
case EXPR_IDENTIFIER:
if (expr->identifier_expr.decl->decl_kind != DECL_VAR) return true;
@@ -703,7 +704,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
UNREACHABLE
}
if (type_is_abi_aggregate(decl->type)) return true;
expr_replace(expr, copy_expr(decl->var.init_expr));
expr_replace(expr, expr_macro_copy(decl->var.init_expr));
return sema_analyse_expr(context, expr);
case VARDECL_PARAM_EXPR:
UNREACHABLE
@@ -716,7 +717,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
// Impossible to reach this, they are already unfolded
UNREACHABLE
case VARDECL_PARAM_REF:
expr_replace(expr, copy_expr(decl->var.init_expr));
expr_replace(expr, expr_macro_copy(decl->var.init_expr));
return sema_cast_rvalue(context, expr);
case VARDECL_PARAM:
case VARDECL_GLOBAL:
@@ -803,7 +804,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr)
}
if (expr_is_constant_eval(cond, true))
{
Expr *copy = copy_expr(cond);
Expr *copy = expr_macro_copy(cond);
cast(copy, type_bool);
assert(cond->expr_kind == EXPR_CONST);
path = cond->const_expr.b ? 1 : 0;
@@ -955,7 +956,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
case VARDECL_CONST:
if (!decl->type)
{
Expr *copy = copy_expr(decl->var.init_expr);
Expr *copy = expr_macro_copy(decl->var.init_expr);
if (!sema_analyse_expr(context, copy)) return false;
if (!expr_is_constant_eval(copy, false))
{
@@ -1055,7 +1056,8 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr
DEBUG_LOG("Resolution successful of %s.", decl->name);
assert(decl->decl_kind == DECL_VAR);
expr_replace(expr, copy_expr(decl->var.init_expr));
expr_replace(expr, expr_macro_copy(decl->var.init_expr));
REMINDER("Remove analysis for hash");
if (!sema_analyse_expr(decl->var.hash_var.context, expr))
{
// Poison the decl so we don't evaluate twice.
@@ -1376,7 +1378,7 @@ static inline bool sema_expand_call_arguments(SemaContext *context, CalledDecl *
{
if (callee->macro)
{
actual_args[i] = copy_expr(init_expr);
actual_args[i] = expr_macro_copy(init_expr);
}
else
{
@@ -1744,6 +1746,7 @@ static bool sema_check_stmt_compile_time(SemaContext *context, Ast *ast)
case AST_NOP_STMT:
return true;
case AST_RETURN_STMT:
case AST_BLOCK_EXIT_STMT:
if (!ast->return_stmt.expr) return true;
return expr_is_constant_eval(ast->return_stmt.expr, CONSTANT_EVAL_ANY);
case AST_EXPR_STMT:
@@ -1766,7 +1769,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
{
assert(decl->decl_kind == DECL_MACRO);
Decl **params = copy_decl_list(decl->macro_decl.parameters);
Decl **params = decl_copy_list(decl->macro_decl.parameters);
CalledDecl callee = {
.macro = true,
.block_parameter = decl->macro_decl.block_parameter,
@@ -1822,7 +1825,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
if (!body_arg->alignment) body_arg->alignment = type_alloca_alignment(body_arg->type);
}
Ast *body = ast_copy_deep(decl->macro_decl.body);
Ast *body = ast_macro_copy(decl->macro_decl.body);
bool no_scope = decl->no_scope;
bool escaping = decl->escaping;
@@ -1850,9 +1853,11 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
rtype = decl->macro_decl.rtype ? decl->macro_decl.rtype->type : NULL;
macro_context.expected_block_type = rtype;
context_change_scope_with_flags(&macro_context, SCOPE_MACRO);
macro_context.block_return_defer = macro_context.active_scope.defer_last;
}
macro_context.current_macro = decl;
macro_context.yield_body = call_expr->call_expr.body;
AstId body_id = call_expr->call_expr.body;
macro_context.yield_body = body_id ? astptr(body_id) : NULL;
macro_context.yield_params = body_params;
macro_context.yield_context = context;
macro_context.original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row;
@@ -2092,8 +2097,9 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
SemaContext *context = macro_context->yield_context;
Decl **params = macro_context->yield_params;
assert(call_expr->function->expr_kind == EXPR_MACRO_BODY_EXPANSION);
expr_replace(call, call_expr->function);
Expr *func_expr = exprptr(call_expr->function);
assert(func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION);
expr_replace(call, func_expr);
call->body_expansion_expr.values = args;
call->body_expansion_expr.declarations = macro_context->yield_params;
@@ -2104,7 +2110,7 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
Decl *param = params[i];
if (!sema_add_local(context, param)) return SCOPE_POP_ERROR();
}
call->body_expansion_expr.ast = ast_copy_deep(macro_context->yield_body);
call->body_expansion_expr.ast = ast_macro_copy(macro_context->yield_body);
success = sema_analyse_statement(context, call->body_expansion_expr.ast);
SCOPE_END;
@@ -2154,7 +2160,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
if (!sema_analyse_call_attributes(context, decl, expr)) return expr_poison(expr);
if (decl == NULL)
{
return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(expr->call_expr.function->type), failable);
return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(exprptr(expr->call_expr.function)->type), failable);
}
switch (decl->decl_kind)
{
@@ -2164,7 +2170,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
SEMA_ERROR(expr, "A macro neeeds to be called with a '@' prefix, please add it.");
return false;
}
expr->call_expr.func_ref = decl;
expr->call_expr.func_ref = declid(decl);
expr->call_expr.is_func_ref = true;
return sema_expr_analyse_macro_call(context, expr, struct_var, decl, failable);
case DECL_VAR:
if (is_macro)
@@ -2180,7 +2187,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
SEMA_ERROR(expr, "A function cannot be called with a '@' prefix, please remove it.");
return false;
}
expr->call_expr.func_ref = decl;
expr->call_expr.func_ref = declid(decl);
expr->call_expr.is_func_ref = true;
return sema_expr_analyse_func_call(context, expr, decl, struct_var, failable);
case DECL_GENERIC:
if (is_macro)
@@ -2188,7 +2196,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
SEMA_ERROR(expr, "A generic function cannot be called with a '@' prefix, please remove it.");
return false;
}
expr->call_expr.func_ref = decl;
expr->call_expr.func_ref = declid(decl);
expr->call_expr.is_func_ref = true;
return sema_expr_analyse_generic_call(context, expr, struct_var, decl, failable);
case DECL_POISONED:
return false;
@@ -2231,7 +2240,7 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
{
expr->call_expr.is_builtin = true;
BuiltinFunction func = expr->call_expr.function->builtin_expr.builtin;
BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin;
unsigned expected_args = builtin_expected_args(func);
Expr **args = expr->call_expr.arguments;
unsigned arg_count = vec_size(args);
@@ -2363,7 +2372,7 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex
static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
{
Expr *func_expr = expr->call_expr.function;
Expr *func_expr = exprptr(expr->call_expr.function);
if (!sema_analyse_expr_lvalue(context, func_expr)) return false;
if (func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION)
@@ -2697,7 +2706,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
expr->expr_kind = EXPR_CALL;
Expr **args = NULL;
vec_add(args, index);
expr->call_expr = (ExprCall){ .func_ref = decl, .arguments = args };
expr->call_expr = (ExprCall){ .func_ref = declid(decl), .is_func_ref = true, .arguments = args };
expr->call_expr.is_type_method = true;
return sema_expr_analyse_macro_call(context, expr, current_expr, decl, failable);
}
@@ -6079,7 +6088,9 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr)
{
Expr *inner = expr->rethrow_expr.inner;
if (!sema_analyse_expr(context, inner)) return false;
expr->rethrow_expr.defer = context->active_scope.defer_last;
REMINDER("Return defers must be work with blocks");
expr->rethrow_expr.cleanup = context_get_defers(context, context->active_scope.defer_last, 0);
if (inner->type == type_anyfail)
{
SEMA_ERROR(expr, "This expression will always throw, which isn't allowed.");
@@ -6147,14 +6158,17 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
context->expected_block_type = infer_type;
SCOPE_START_WITH_FLAGS(SCOPE_EXPR_BLOCK)
context->block_return_defer = context->active_scope.defer_last;
PUSH_CONTINUE(NULL);
PUSH_BREAK(NULL);
PUSH_NEXT(NULL, NULL);
AstId current = expr->expr_block.first_stmt;
Ast *stmt = NULL;
while (current)
{
if (!sema_analyse_statement(context, ast_next(&current)))
stmt = ast_next(&current);
if (!sema_analyse_statement(context, stmt))
{
success = false;
goto EXIT;
@@ -6180,6 +6194,7 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe
POP_BREAKCONT();
POP_NEXT();
context_pop_defers(context, &stmt->next);
SCOPE_END;
context->expected_block_type = stored_block_type;
context_pop_returns(context, saved_returns);
@@ -6852,6 +6867,21 @@ static inline BuiltinFunction builtin_by_name(const char *name)
return BUILTIN_NONE;
}
static inline bool sema_expr_analyse_retval(SemaContext *c, Expr *expr)
{
if (c->active_scope.flags & SCOPE_MACRO)
{
TODO
}
if (expr->type == type_void)
{
SEMA_ERROR(expr, "'return' cannot be used on void functions.");
return false;
}
expr->type = c->rtype;
return true;
}
static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error)
{
const char *builtin_char = expr->builtin_expr.ident;
@@ -6873,7 +6903,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
switch (expr->expr_kind)
{
case EXPR_COND:
case EXPR_UNDEF:
case EXPR_DESIGNATOR:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_FLATPATH:
@@ -6894,6 +6923,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
if (!sema_analyse_var_decl(context, expr->decl_expr, true)) return false;
expr->type = expr->decl_expr->type;
return true;
case EXPR_RETVAL:
return sema_expr_analyse_retval(context, expr);
case EXPR_BUILTIN:
return sema_expr_analyse_builtin(context, expr, true);
case EXPR_CT_CALL:
@@ -7018,7 +7049,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo
static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr)
{
Decl *decl = expr->ct_ident_expr.decl;
Expr *copy = copy_expr(decl->var.init_expr);
Expr *copy = expr_macro_copy(decl->var.init_expr);
if (!sema_analyse_expr(context, copy)) return false;
expr_replace(expr, copy);
return true;

View File

@@ -34,12 +34,14 @@ do { \
#define SCOPE_ERROR_END_OUTER() \
do { context->active_scope = stored_scope; } while(0)
void context_pop_defers_to(SemaContext *context, DeferList *list);
AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom);
void context_pop_defers(SemaContext *context, AstId *next);
Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr);
void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr);
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
void context_change_scope_for_label(SemaContext *context, Decl *label);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body);
#define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = ast ? astid(ast) : 0; context->X##_defer = context->active_scope.defer_last
#define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer

View File

@@ -82,9 +82,10 @@ static inline bool assert_create_from_contract(SemaContext *context, AstDocDirec
return true;
}
static inline bool sema_analyse_block_return_stmt(SemaContext *context, Ast *statement)
static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *statement)
{
assert(context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO));
statement->ast_kind = AST_BLOCK_EXIT_STMT;
context->active_scope.jump_end = true;
Type *block_type = context->expected_block_type;
if (statement->return_stmt.expr)
@@ -106,6 +107,7 @@ static inline bool sema_analyse_block_return_stmt(SemaContext *context, Ast *sta
return false;
}
}
statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, context->block_return_defer);
vec_add(context->returns, statement);
return true;
}
@@ -127,7 +129,7 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement
// This might be a return in a function block or a macro which must be treated differently.
if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
{
return sema_analyse_block_return_stmt(context, statement);
return sema_analyse_block_exit_stmt(context, statement);
}
// 1. We mark that the current scope ends with a jump.
context->active_scope.jump_end = true;
@@ -136,7 +138,6 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement
assert(expected_rtype && "We should always have known type from a function return.");
Expr *return_expr = statement->return_stmt.expr;
statement->return_stmt.defer = context->active_scope.defer_last;
if (return_expr)
{
@@ -149,27 +150,17 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement
SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
return false;
}
statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, 0);
return true;
}
// Process any ensures.
if (context->return_var)
AstId cleanup = context_get_defers(context, context->active_scope.defer_last, 0);
if (context->ensures)
{
AstId next_id = 0;
AstId *append_id = &next_id;
AstId first = 0;
AstId *append_id = &first;
// Creating an assign statement
if (return_expr)
{
Expr *assign = expr_new(EXPR_BINARY, return_expr->span);
assign->binary_expr.operator = BINARYOP_ASSIGN;
assign->binary_expr.widen = true;
assign->binary_expr.left = expr_variable(context->return_var);
assign->binary_expr.right = return_expr;
Ast *new_ret = new_ast(AST_EXPR_STMT, assign->span);
new_ret->expr_stmt = assign;
if (!sema_analyse_statement(context, new_ret)) return false;
ast_append(&append_id, new_ret);
}
AstDocDirective *directives = context->current_function->docs;
VECEACH(directives, i)
{
@@ -177,21 +168,19 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement
if (directive->kind != DOC_DIRECTIVE_ENSURE) continue;
if (!assert_create_from_contract(context, directive, &append_id)) return false;
}
if (next_id)
if (cleanup)
{
Ast *new_return = new_ast(AST_RETURN_STMT, statement->span);
ast_append(&append_id, new_return);
if (return_expr)
{
new_return->return_stmt.expr = expr_variable(context->return_var);
}
new_return->return_stmt.defer = statement->return_stmt.defer;
new_return->next = statement->next;
statement->next = next_id;
statement->ast_kind = AST_NOP_STMT;
Ast *last = ast_last(astptr(cleanup));
last->next = first;
}
else
{
cleanup = first;
}
}
statement->return_stmt.cleanup = cleanup;
assert(type_no_fail(statement->return_stmt.expr->type)->canonical == type_no_fail(expected_rtype)->canonical);
@@ -454,7 +443,7 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr)
// 4d. A new declaration is created.
Decl *decl = decl_new_var(ident->identifier_expr.ident, ident->span, type, VARDECL_LOCAL, VISIBLE_LOCAL);
decl->var.init_expr = expr_new(EXPR_UNDEF, decl->span);
decl->var.no_init = true;
// 4e. Analyse it
if (!sema_analyse_var_decl(context, decl, true)) return false;
@@ -696,134 +685,7 @@ static inline bool sema_analyse_stmt_placement(Expr *cond, Ast *stmt)
return cond->span.row == stmt->span.row;
}
/**
* Check "while" statement, including end of line placement of a single statement.
*/
static inline bool sema_analyse_while_stmt(SemaContext *context, Ast *statement)
{
Expr *cond = exprptr(statement->while_stmt.cond);
Ast *body = astptr(statement->while_stmt.body);
bool success;
// 1. Begin our scope, this is relevant in case we have something like
// while (File *f = @getFileAndClose!()) where the macro pushes a defer into the scope.
SCOPE_START_WITH_LABEL(statement->while_stmt.flow.label)
// 2. Analyze the condition
if (!sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL))
{
// 2a. In case of error, pop context and exit.
return SCOPE_POP_ERROR();
}
// 4. Push break / continue - which is independent of the scope.
PUSH_BREAKCONT(statement);
// 6. Analyse the statement
success = sema_analyse_statement(context, body);
// 7. Pop break / continue
POP_BREAKCONT();
// 8. Check placement, in case of a single statement, it must be placed on the same line.
if (success && !sema_analyse_stmt_placement(cond, body))
{
SEMA_ERROR(body, "A single statement after 'while' must be placed on the same line, or be enclosed in {}.");
return SCOPE_POP_ERROR();
}
// 9. Pop defers attach them to the statement if needed
context_pop_defers_and_replace_ast(context, body);
// 10. Pop the while scope.
SCOPE_END;
statement->ast_kind = AST_FOR_STMT;
AstForStmt for_stmt = {
.cond = cond,
.flow = statement->while_stmt.flow,
.incr = NULL,
.body = astid(body),
};
statement->for_stmt = for_stmt;
return success;
}
/**
* Check the do ... while (...) statement.
*/
static inline bool sema_analyse_do_stmt(SemaContext *context, Ast *statement)
{
Expr *expr = statement->do_stmt.expr;
Ast *body = astptr(statement->do_stmt.body);
bool success;
// 1. Begin pushing the scope and break / continue.
SCOPE_START_WITH_LABEL(statement->do_stmt.flow.label)
PUSH_BREAKCONT(statement);
// 2. We analyze the statement.
success = sema_analyse_statement(context, body);
// 3. Pop break / continue
POP_BREAKCONT();
// 4. Pop any defers
context_pop_defers_and_replace_ast(context, body);
// 5. If the current scope ended in a jump, then
// the do statement has no exit.
statement->do_stmt.flow.no_exit = context->active_scope.jump_end;
// 6. Pop the scope
SCOPE_END;
// 7. We can now exit if there was an error further up.
if (!success) return false;
// 8. Handle the do { } expression
if (!statement->do_stmt.expr)
{
goto END;
}
// 9. We next handle the while test. This is its own scope.
SCOPE_START
// 10. Try to evaluate and implicitly cast to boolean.
if (!sema_analyse_cond_expr(context, expr))
{
// 10a. On failure, pop and return false.
return SCOPE_POP_ERROR();
}
// 11. Pop any defers in the expression.
statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr);
SCOPE_END;
// 13. Check for infinite loops using do ... while (1).
// If it has no break then that means we've reached a statement which ends with a jump.
if (statement->do_stmt.expr->expr_kind == EXPR_CONST && statement->do_stmt.expr->const_expr.b)
{
// Unless there is a break, this won't ever exit.
context->active_scope.jump_end = !statement->do_stmt.flow.has_break;
}
END:;
FlowCommon flow = statement->do_stmt.flow;
flow.skip_first = true;
statement->ast_kind = AST_FOR_STMT;
AstForStmt for_stmt = {
.cond = expr,
.flow = flow,
.incr = NULL,
.body = astid(body),
};
statement->for_stmt = for_stmt;
return true;
}
@@ -846,108 +708,141 @@ static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement)
return true;
}
static inline bool sema_analyse_defer_stmt(SemaContext *context, Ast *statement)
bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body)
{
// TODO special parsing of "catch"
bool success;
SCOPE_START_WITH_FLAGS(SCOPE_DEFER)
context->active_scope.defer_last = 0;
context->active_scope.defer_start = 0;
context->active_scope.in_defer = statement;
context->active_scope.defer_last = 0;
context->active_scope.defer_start = 0;
context->active_scope.in_defer = statement;
PUSH_CONTINUE(NULL);
PUSH_BREAK(statement);
PUSH_NEXT(NULL, NULL);
PUSH_BREAKCONT(NULL);
PUSH_NEXT(NULL, NULL);
// Only ones allowed.
context->active_scope.flags &= SCOPE_DEFER;
// Only ones allowed.
context->active_scope.flags &= SCOPE_DEFER;
success = sema_analyse_statement(context, statement->defer_stmt.body);
success = sema_analyse_statement(context, body);
POP_BREAKCONT();
POP_NEXT();
POP_BREAKCONT();
POP_NEXT();
context_pop_defers_and_replace_ast(context, statement->defer_stmt.body);
context_pop_defers_and_replace_ast(context, body);
SCOPE_END;
if (!success) return false;
return success;
}
static inline bool sema_analyse_defer_stmt(SemaContext *context, Ast *statement)
{
// TODO special parsing of "catch"
if (!sema_analyse_defer_stmt_body(context, statement, astptr(statement->defer_stmt.body))) return false;
statement->defer_stmt.prev_defer = context->active_scope.defer_last;
context->active_scope.defer_last = astid(statement);
return true;
}
static inline bool sema_analyse_for_cond(SemaContext *context, ExprId *cond_ref, bool *infinite)
{
ExprId cond_id = *cond_ref;
if (!cond_id)
{
*infinite = true;
return true;
}
Expr *cond = exprptr(cond_id);
if (cond->expr_kind == EXPR_COND)
{
if (!sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL)) return false;
}
else
{
if (!sema_analyse_cond_expr(context, cond)) return false;
}
cond = context_pop_defers_and_wrap_expr(context, cond);
// If this is const true, then set this to infinite and remove the expression.
if (cond->expr_kind == EXPR_CONST && cond->const_expr.b)
{
cond = NULL;
*infinite = true;
}
else
{
*infinite = false;
}
*cond_ref = exprid(cond);
return true;
}
static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
{
bool success = true;
bool is_infinite;
bool is_infinite = false;
// Enter for scope
SCOPE_OUTER_START
is_infinite = statement->for_stmt.cond == NULL;
if (statement->for_stmt.init)
{
success = sema_analyse_expr(context, statement->for_stmt.init);
success = sema_analyse_expr(context, exprptr(statement->for_stmt.init));
}
if (success && statement->for_stmt.cond)
{
// Conditional scope start
SCOPE_START
Expr *cond = statement->for_stmt.cond;
if (cond->expr_kind == EXPR_COND)
{
success = sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL);
}
else
{
success = sema_analyse_cond_expr(context, cond);
}
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
// If this is const true, then set this to infinite and remove the expression.
if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b)
{
statement->for_stmt.cond = NULL;
is_infinite = true;
}
// Conditional scope end
SCOPE_END;
}
if (success && statement->for_stmt.incr)
{
// Incr scope start
SCOPE_START
Expr *incr = statement->for_stmt.incr;
success = sema_analyse_expr(context, incr);
statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr);
// Incr scope end
SCOPE_END;
}
if (!success)
{
SCOPE_ERROR_END_OUTER();
return false;
}
assert(statement->for_stmt.body);
Ast *body = astptr(statement->for_stmt.body);
// Create the for body scope.
// Conditional scope start
SCOPE_START_WITH_LABEL(statement->for_stmt.flow.label)
if (!statement->for_stmt.flow.skip_first)
{
if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success)
{
SCOPE_ERROR_END_OUTER();
return false;
}
}
assert(statement->for_stmt.body);
Ast *body = astptr(statement->for_stmt.body);
PUSH_BREAKCONT(statement);
success = sema_analyse_statement(context, body);
statement->for_stmt.flow.no_exit = context->active_scope.jump_end;
POP_BREAKCONT();
// End for body scope
context_pop_defers_and_replace_ast(context, body);
SCOPE_END;
if (statement->for_stmt.flow.skip_first)
{
SCOPE_START
if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success)
{
SCOPE_ERROR_END_OUTER();
return false;
}
SCOPE_END;
}
if (success && statement->for_stmt.incr)
{
// Incr scope start
SCOPE_START
Expr *incr = exprptr(statement->for_stmt.incr);
success = sema_analyse_expr(context, incr);
statement->for_stmt.incr = exprid(context_pop_defers_and_wrap_expr(context, incr));
// Incr scope end
SCOPE_END;
}
// End for body scope
context_pop_defers_and_replace_ast(context, statement);
// End for scope
SCOPE_OUTER_END;
@@ -964,9 +859,10 @@ static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span
{
Expr *len_call = expr_new(EXPR_CALL, span);
len_call->resolve_status = RESOLVE_RUNNING;
len_call->call_expr.func_ref = method_decl;
len_call->call_expr.func_ref = declid(method_decl);
len_call->call_expr.arguments = arguments;
len_call->call_expr.body = NULL;
len_call->call_expr.body = 0;
len_call->call_expr.is_func_ref = true;
len_call->call_expr.unsplat_last = false;
len_call->call_expr.is_type_method = true;
bool is_macro = method_decl->decl_kind == DECL_MACRO;
@@ -982,10 +878,12 @@ static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span
static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statement)
{
// Pull out the relevant data.
Decl *index = statement->foreach_stmt.index;
Decl *var = statement->foreach_stmt.variable;
Expr *enumerator = statement->foreach_stmt.enumeration;
Ast *body = statement->foreach_stmt.body;
DeclId index_id = statement->foreach_stmt.index;
DeclId var_id = statement->foreach_stmt.variable;
Decl *var = var_id ? declptr(var_id) : NULL;
Decl *index = index_id ? declptr(index_id) : NULL;
Expr *enumerator = exprptr(statement->foreach_stmt.enumeration);
AstId body = statement->foreach_stmt.body;
AstId first_stmt = 0;
AstId *succ = &first_stmt;
Expr **expressions = NULL;
@@ -1275,13 +1173,14 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
}
var->var.init_expr = subscript;
ast_append(&succ, value_declare_ast);
ast_append(&succ, body);
Ast *compound_stmt = new_ast(AST_COMPOUND_STMT, body->span);
Ast *body_ast = astptr(body);
ast_append(&succ, body_ast);
Ast *compound_stmt = new_ast(AST_COMPOUND_STMT, body_ast->span);
compound_stmt->compound_stmt.first_stmt = first_stmt;
FlowCommon flow = statement->foreach_stmt.flow;
statement->for_stmt = (AstForStmt){ .init = init_expr,
.cond = binary,
.incr = inc,
statement->for_stmt = (AstForStmt){ .init = exprid(init_expr),
.cond = exprid(binary),
.incr = exprid(inc),
.flow = flow,
.body = astid(compound_stmt)
};
@@ -1305,21 +1204,23 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
bool then_jump;
bool success;
Expr *cond = statement->if_stmt.cond;
Expr *cond = exprptr(statement->if_stmt.cond);
Ast *then = astptr(statement->if_stmt.then_body);
AstId else_id = statement->if_stmt.else_body;
Ast *else_body = else_id ? astptr(else_id) : NULL;
SCOPE_OUTER_START
CondType cond_type = statement->if_stmt.then_body->ast_kind == AST_IF_CATCH_SWITCH_STMT
CondType cond_type = then->ast_kind == AST_IF_CATCH_SWITCH_STMT
? COND_TYPE_UNWRAP : COND_TYPE_UNWRAP_BOOL;
success = sema_analyse_cond(context, cond, cond_type);
Ast *then = statement->if_stmt.then_body;
if (success && !ast_ok(then))
{
SEMA_ERROR(statement->if_stmt.then_body,
SEMA_ERROR(then,
"The 'then' part of a single line if-statement must start on the same line as the 'if' or use '{ }'");
success = false;
}
if (success && statement->if_stmt.else_body)
if (success && else_body)
{
bool then_has_braces = then->ast_kind == AST_COMPOUND_STMT || then->ast_kind == AST_IF_CATCH_SWITCH_STMT;
if (!then_has_braces)
@@ -1327,10 +1228,10 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
SEMA_ERROR(then, "if-statements with an 'else' must use '{ }' even around a single statement.");
success = false;
}
if (success && statement->if_stmt.else_body->ast_kind != AST_COMPOUND_STMT &&
statement->if_stmt.else_body->ast_kind != AST_IF_STMT)
if (success && else_body->ast_kind != AST_COMPOUND_STMT &&
else_body->ast_kind != AST_IF_STMT)
{
SEMA_ERROR(statement->if_stmt.else_body,
SEMA_ERROR(else_body,
"An 'else' must use '{ }' even around a single statement.");
success = false;
}
@@ -1364,9 +1265,9 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
if (statement->if_stmt.else_body)
{
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label);
sema_remove_unwraps_from_try(context, statement->if_stmt.cond);
sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond);
success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
sema_remove_unwraps_from_try(context, cond);
sema_unwrappable_from_catch_in_else(context, cond);
success = success && sema_analyse_statement(context, else_body);
else_jump = context->active_scope.jump_end;
SCOPE_END;
}
@@ -1376,7 +1277,7 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
SCOPE_OUTER_END;
if (then_jump)
{
sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond);
sema_unwrappable_from_catch_in_else(context, cond);
}
if (then_jump && else_jump && !statement->flow.has_break)
{
@@ -1385,10 +1286,6 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
return success;
}
static bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt)
{
if (!sema_analyse_expr(context, stmt->asm_stmt.body)) return false;
@@ -1451,7 +1348,8 @@ static bool sema_analyse_break_stmt(SemaContext *context, Ast *statement)
return false;
}
statement->contbreak_stmt.defers.start = context->active_scope.defer_last;
AstId defer_begin;
statement->contbreak_stmt.is_resolved = true;
if (statement->contbreak_stmt.label.name)
{
Decl *target = sema_analyse_label(context, statement);
@@ -1459,12 +1357,15 @@ static bool sema_analyse_break_stmt(SemaContext *context, Ast *statement)
astptr(target->label.parent)->flow.has_break = true;
statement->contbreak_stmt.ast = target->label.parent;
statement->contbreak_stmt.defers.end = target->label.defer;
return true;
defer_begin = target->label.defer;
}
statement->contbreak_stmt.defers.end = context->break_defer;
statement->contbreak_stmt.ast = context->break_target;
astptr(context->break_target)->flow.has_break = true;
else
{
defer_begin = context->break_defer;
statement->contbreak_stmt.ast = context->break_target;
astptr(context->break_target)->flow.has_break = true;
}
statement->contbreak_stmt.defers = context_get_defers(context, context->active_scope.defer_last, defer_begin);
return true;
}
@@ -1516,28 +1417,27 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
assert(statement->nextcase_stmt.expr);
}
statement->nextcase_stmt.defers.start = context->active_scope.defer_last;
statement->nextcase_stmt.defers.end = parent->switch_stmt.defer;
// Plain next.
if (!statement->nextcase_stmt.expr)
{
assert(context->next_target);
statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer);
statement->nextcase_stmt.case_switch_stmt = context->next_target;
return true;
}
Expr *cond = parent->switch_stmt.cond;
Expr *cond = exprptr(parent->switch_stmt.cond);
if (statement->nextcase_stmt.expr->expr_kind == EXPR_TYPEINFO)
{
TypeInfo *type_info = statement->nextcase_stmt.expr->type_expr;
if (!sema_resolve_type_info(context, type_info)) return false;
Ast **cases;
statement->nextcase_stmt.defers.end = parent->switch_stmt.defer;
if (parent->switch_stmt.cond->type->canonical != type_typeid)
statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer);
if (cond->type->canonical != type_typeid)
{
SEMA_ERROR(statement, "Unexpected 'type' in as an 'nextcase' destination.");
SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type));
SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(cond->type));
return false;
}
cases = parent->switch_stmt.cases;
@@ -1574,10 +1474,11 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
if (!sema_analyse_expr_rhs(context, expected_type, target, false)) return false;
statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer);
if (target->expr_kind == EXPR_CONST)
{
Ast *default_stmt = NULL;
statement->nextcase_stmt.defers.end = parent->switch_stmt.defer;
VECEACH(parent->switch_stmt.cases, i)
{
Ast *case_stmt = parent->switch_stmt.cases[i];
@@ -1612,7 +1513,6 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement)
{
context->active_scope.jump_end = true;
statement->contbreak_stmt.defers.start = context->active_scope.defer_last;
if (!context->continue_target && !statement->contbreak_stmt.label.name)
{
@@ -1620,6 +1520,7 @@ static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement)
return false;
}
AstId defer_bottom;
if (statement->contbreak_stmt.label.name)
{
Decl *target = sema_analyse_label(context, statement);
@@ -1628,21 +1529,22 @@ static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement)
switch (parent->ast_kind)
{
case AST_FOR_STMT:
case AST_WHILE_STMT:
break;
case AST_DO_STMT:
if (parent->do_stmt.expr) break;
// Is this plain "do"?
if (parent->for_stmt.cond || parent->flow.skip_first) break;
FALLTHROUGH;
default:
SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements.");
return false;
}
statement->contbreak_stmt.ast = target->label.parent;
statement->contbreak_stmt.defers.end = target->label.defer;
return true;
defer_bottom = target->label.defer;
}
statement->contbreak_stmt.defers.end = context->continue_defer;
statement->contbreak_stmt.ast = context->continue_target;
else
{
defer_bottom = context->continue_defer;
statement->contbreak_stmt.ast = context->continue_target;
}
statement->contbreak_stmt.defers = context_get_defers(context, context->active_scope.defer_last, defer_bottom);
return true;
}
@@ -1714,16 +1616,18 @@ static inline bool sema_analyse_compound_statement_no_scope(SemaContext *context
{
bool all_ok = ast_ok(compound_statement);
AstId current = compound_statement->compound_stmt.first_stmt;
Ast *ast = NULL;
while (current)
{
Ast *ast = ast_next(&current);
ast = ast_next(&current);
if (!sema_analyse_statement(context, ast))
{
ast_poison(ast);
all_ok = false;
}
}
context_pop_defers_to(context, &compound_statement->compound_stmt.defer_list);
AstId *next = ast ? &ast->next : &compound_statement->compound_stmt.first_stmt;
context_pop_defers(context, next);
return all_ok;
}
@@ -1929,7 +1833,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
SCOPE_END;
}
statement->flow.no_exit = all_jump_end;
statement->switch_stmt.if_chain = if_chain || max_ranged;
statement->switch_stmt.flow.if_chain = if_chain || max_ranged;
if (!success) return false;
return success;
}
@@ -2051,7 +1955,7 @@ static bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statement)
static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement)
{
Expr *collection = statement->ct_foreach_stmt.expr;
Expr *collection = exprptr(statement->ct_foreach_stmt.expr);
if (!sema_analyse_ct_expr(context, collection)) return false;
if (collection->expr_kind != EXPR_INITIALIZER_LIST)
{
@@ -2083,7 +1987,7 @@ static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement)
AstId *current = &start;
VECEACH(expression, i)
{
Ast *compound_stmt = ast_copy_deep(body);
Ast *compound_stmt = ast_macro_copy(body);
value->var.init_expr = expression[i];
if (index)
{
@@ -2101,7 +2005,6 @@ static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement)
SCOPE_END;
statement->ast_kind = AST_COMPOUND_STMT;
statement->compound_stmt.first_stmt = start;
statement->compound_stmt.defer_list = (DeferList) { 0, 0 };
return true;
}
@@ -2111,7 +2014,7 @@ static bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement)
SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label);
Expr *cond = statement->switch_stmt.cond;
Expr *cond = exprptr(statement->switch_stmt.cond);
Type *switch_type;
ExprVariantSwitch var_switch;
@@ -2259,11 +2162,12 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
// Enter for scope
SCOPE_OUTER_START
Expr *init;
ExprId init;
if ((init = statement->for_stmt.init))
{
assert(init->expr_kind == EXPR_EXPRESSION_LIST);
Expr **expressions = init->expression_list;
Expr *init_expr = exprptr(init);
assert(init_expr->expr_kind == EXPR_EXPRESSION_LIST);
Expr **expressions = init_expr->expression_list;
VECEACH (expressions, i)
{
Expr *expr = expressions[i];
@@ -2286,15 +2190,15 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
}
}
}
Expr *condition = statement->for_stmt.cond;
Expr *incr = statement->for_stmt.incr;
ExprId condition = statement->for_stmt.cond;
ExprId incr = statement->for_stmt.incr;
Ast *body = astptr(statement->for_stmt.body);
AstId start = 0;
AstId *current = &start;
assert(condition);
for (int i = 0; i < MAX_MACRO_ITERATIONS; i++)
{
Expr *copy = copy_expr(condition);
Expr *copy = expr_macro_copy(exprptr(condition));
if (!sema_analyse_cond_expr(context, copy)) goto EXIT_ERROR;
if (copy->expr_kind != EXPR_CONST)
{
@@ -2303,17 +2207,17 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
}
if (!copy->const_expr.b) break;
Ast *compound_stmt = ast_copy_deep(body);
Ast *compound_stmt = ast_macro_copy(body);
if (!sema_analyse_compound_stmt(context, compound_stmt)) goto EXIT_ERROR;
*current = astid(compound_stmt);
current = &compound_stmt->next;
if (incr)
{
Expr **exprs = incr->expression_list;
Expr **exprs = exprptr(incr)->expression_list;
VECEACH(exprs, j)
{
copy = copy_expr(exprs[j]);
copy = expr_macro_copy(exprs[j]);
if (!sema_analyse_expr(context, copy)) goto EXIT_ERROR;
if (copy->expr_kind != EXPR_CONST)
{
@@ -2325,7 +2229,6 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
}
statement->ast_kind = AST_COMPOUND_STMT;
statement->compound_stmt.first_stmt = start;
statement->compound_stmt.defer_list = (DeferList) { 0, 0 };
success = true;
EXIT_ERROR:
SCOPE_OUTER_END;
@@ -2353,7 +2256,6 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
switch (statement->ast_kind)
{
case AST_POISONED:
case AST_SCOPED_STMT:
case AST_IF_CATCH_SWITCH_STMT:
UNREACHABLE
case AST_ASM_STMT:
@@ -2380,8 +2282,6 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
return false;
case AST_DEFER_STMT:
return sema_analyse_defer_stmt(context, statement);
case AST_DO_STMT:
return sema_analyse_do_stmt(context, statement);
case AST_EXPR_STMT:
return sema_analyse_expr_stmt(context, statement);
case AST_FOREACH_STMT:
@@ -2392,14 +2292,14 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
return sema_analyse_if_stmt(context, statement);
case AST_NOP_STMT:
return true;
case AST_BLOCK_EXIT_STMT:
UNREACHABLE
case AST_RETURN_STMT:
return sema_analyse_return_stmt(context, statement);
case AST_SWITCH_STMT:
return sema_analyse_switch_stmt(context, statement);
case AST_NEXT_STMT:
return sema_analyse_nextcase_stmt(context, statement);
case AST_WHILE_STMT:
return sema_analyse_while_stmt(context, statement);
case AST_CT_SWITCH_STMT:
return sema_analyse_ct_switch_stmt(context, statement);
case AST_CT_ELSE_STMT:
@@ -2467,7 +2367,7 @@ END:
return success;
}
static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *directives, AstId **asserts, bool *ensure_found)
static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *directives, AstId **asserts)
{
if (!directives) return true;
VECEACH(directives, i)
@@ -2492,7 +2392,7 @@ static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *direct
break;
case DOC_DIRECTIVE_ENSURE:
if (!sema_analyse_ensure(context, directive)) return false;
*ensure_found = true;
context->ensures = true;
break;
}
}
@@ -2521,9 +2421,8 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
context->next_target = 0;
context->next_switch = 0;
context->break_target = 0;
context->return_var = NULL;
context->ensures = false;
func->func_decl.annotations = CALLOCS(FuncAnnotations);
bool ensure_found = false;
func->func_decl.ret_var = NULL;
Ast *body = func->func_decl.body;
SCOPE_START
@@ -2535,7 +2434,7 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
}
AstId assert_first = 0;
AstId *next = &assert_first;
if (!sema_analyse_contracts(context, func->docs, &next, &ensure_found)) return false;
if (!sema_analyse_contracts(context, func->docs, &next)) return false;
if (func->func_decl.attr_naked)
{
AstId current = func->func_decl.body->compound_stmt.first_stmt;
@@ -2552,15 +2451,11 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
}
else
{
if (ensure_found)
if (assert_first)
{
Decl *ret_val = decl_new_generated_var(context->rtype,
VARDECL_LOCAL,
func->func_decl.function_signature.returntype->span);
ret_val->name = kw_return;
context->return_var = ret_val;
func->func_decl.ret_var = ret_val;
if (!sema_add_local(context, ret_val)) return false;
Ast *ast = new_ast(AST_COMPOUND_STMT, body->span);
ast->compound_stmt.first_stmt = assert_first;
ast_prepend(&func->func_decl.body->compound_stmt.first_stmt, ast);
}
Type *canonical_rtype = type_no_fail(prototype->rtype)->canonical;
// Insert an implicit return
@@ -2589,12 +2484,6 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
return false;
}
}
if (assert_first)
{
Ast *ast = new_ast(AST_COMPOUND_STMT, body->span);
ast->compound_stmt.first_stmt = assert_first;
ast_prepend(&func->func_decl.body->compound_stmt.first_stmt, ast);
}
SCOPE_END;
return true;
}

View File

@@ -75,60 +75,79 @@ void context_change_scope_for_label(SemaContext *context, Decl *label)
}
}
void context_pop_defers_to(SemaContext *context, DeferList *list)
AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom)
{
list->end = context->active_scope.defer_start;
assert(context->active_scope.defer_last < 10000000);
list->start = context->active_scope.defer_last;
context->active_scope.defer_last = list->end;
AstId first = 0;
AstId *next = &first;
while (defer_bottom != defer_top)
{
Ast *defer = astptr(defer_top);
Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body));
*next = astid(defer_body);
next = &defer_body->next;
defer_top = defer->defer_stmt.prev_defer;
}
return first;
}
void context_pop_defers(SemaContext *context, AstId *next)
{
AstId defer_start = context->active_scope.defer_start;
if (next && !context->active_scope.jump_end)
{
AstId defer_current = context->active_scope.defer_last;
while (defer_current != defer_start)
{
Ast *defer = astptr(defer_current);
Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body));
*next = astid(defer_body);
next = &defer_body->next;
defer_current = defer->defer_stmt.prev_defer;
}
}
context->active_scope.defer_last = defer_start;
}
Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr)
{
DeferList defers = { 0, 0 };
context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return expr;
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
wrap->type = expr->type;
wrap->resolve_status = RESOLVE_DONE;
wrap->expr_scope.expr = expr;
wrap->expr_scope.defers = defers;
AstId defer_first = 0;
context_pop_defers(context, &defer_first);
if (defer_first)
{
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
wrap->type = expr->type;
wrap->resolve_status = RESOLVE_DONE;
wrap->expr_scope.expr = expr;
wrap->expr_scope.defer_stmts = defer_first;
return wrap;
}
return expr;
}
void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr)
{
DeferList defers = { 0, 0 };
context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return;
Expr *inner = expr_copy(expr);
expr->expr_kind = EXPR_SCOPED_EXPR;
expr->expr_scope.expr = inner;
expr->expr_scope.defers = defers;
AstId defer_first = 0;
context_pop_defers(context, &defer_first);
if (defer_first)
{
Expr *inner = expr_copy(expr);
expr->expr_kind = EXPR_SCOPED_EXPR;
expr->expr_scope.expr = inner;
expr->expr_scope.defer_stmts = defer_first;
}
}
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast)
{
DeferList defers = { 0, 0 };
context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return;
if (ast->ast_kind == AST_DEFER_STMT)
{
assert(defers.start == astid(ast));
*ast = *ast->defer_stmt.body;
return;
}
AstId defer_first = 0;
context_pop_defers(context, &defer_first);
if (!defer_first) return;
assert(ast->ast_kind != AST_COMPOUND_STMT);
Ast *replacement = ast_copy(ast);
ast->ast_kind = AST_SCOPED_STMT;
ast->scoped_stmt.stmt = astid(replacement);
ast->scoped_stmt.defers = defers;
ast->ast_kind = AST_COMPOUND_STMT;
ast->compound_stmt.first_stmt = astid(replacement);
replacement->next = defer_first;
}
static inline void halt_on_error(void)

View File

@@ -1 +1 @@
#define COMPILER_VERSION "PRE.24"
#define COMPILER_VERSION "PRE.25"

View File

@@ -53,30 +53,18 @@ entry:
define i32 @simple_test.test2(i32* %0, i32 %1) #0 {
entry:
%return = alloca i32, align 4
%gt = icmp sgt i32 %1, 100
call void @llvm.assume(i1 %gt)
store i32 444, i32* %0, align 8
store i32 %1, i32* %return, align 4
%2 = load i32, i32* %return, align 4
%lt = icmp slt i32 %2, 200
call void @llvm.assume(i1 %lt)
%3 = load i32, i32* %return, align 4
ret i32 %3
ret i32 %1
}
define i32 @simple_test.test3(i32 %0) #0 {
entry:
%return = alloca i32, align 4
%gt = icmp sgt i32 %0, 0
call void @llvm.assume(i1 %gt)
%add = add i32 %0, 1
store i32 %add, i32* %return, align 4
%1 = load i32, i32* %return, align 4
%gt1 = icmp sgt i32 %1, 0
call void @llvm.assume(i1 %gt1)
%2 = load i32, i32* %return, align 4
ret i32 %2
ret i32 %add
}
define void @simple_test.main() #0 {

View File

@@ -21,7 +21,7 @@ fn void main()
test(10); // Prints "B!A"
}
// #expect: defer1.ll
/* #expect: defer1.ll
define void @defer1.test(i32 %0) #0 {
entry:
@@ -30,48 +30,24 @@ entry:
if.then: ; preds = %entry
%1 = 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
%2 = 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
%eq2 = icmp eq i32 %0, 0
br i1 %eq2, label %if.then3, label %if.exit7
%eq1 = icmp eq i32 %0, 0
br i1 %eq1, label %if.then2, label %if.exit3
if.then3: ; preds = %if.exit
if.then2: ; preds = %if.exit
%3 = 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
%4 = 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
%5 = 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
if.exit3: ; preds = %if.exit
%6 = 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
%7 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
%8 = 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
%9 = 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
}

View File

@@ -0,0 +1,83 @@
// #target: x64-darwin
module foo;
extern fn void printf(char*,...);
macro int abc(x)
{
defer printf("Out x %d\n", x);
x *= 2;
if (x > 100) return x = x - 100;
printf("Normal end\n");
return x;
}
fn void main()
{
defer printf("On exit\n");
@abc(123);
@abc(3);
}
/* #expect: foo.ll
define void @foo.main() #0 {
entry:
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%x1 = alloca i32, align 4
%blockret2 = alloca i32, align 4
store i32 123, i32* %x, align 4
%0 = load i32, i32* %x, align 4
%mul = mul i32 %0, 2
store i32 %mul, i32* %x, align 4
%1 = load i32, i32* %x, align 4
%gt = icmp sgt i32 %1, 100
br i1 %gt, label %if.then, label %if.exit
if.then: ; preds = %entry
%2 = load i32, i32* %x, align 4
%sub = sub i32 %2, 100
store i32 %sub, i32* %x, align 4
%3 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i32 %3)
store i32 %sub, i32* %blockret, align 4
br label %expr_block.exit
if.exit: ; preds = %entry
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i32 0, i32 0))
%4 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %4)
%5 = load i32, i32* %x, align 4
store i32 %5, i32* %blockret, align 4
br label %expr_block.exit
expr_block.exit: ; preds = %if.exit, %if.then
store i32 3, i32* %x1, align 4
%6 = load i32, i32* %x1, align 4
%mul3 = mul i32 %6, 2
store i32 %mul3, i32* %x1, align 4
%7 = load i32, i32* %x1, align 4
%gt4 = icmp sgt i32 %7, 100
br i1 %gt4, label %if.then5, label %if.exit7
if.then5: ; preds = %expr_block.exit
%8 = load i32, i32* %x1, align 4
%sub6 = sub i32 %8, 100
store i32 %sub6, i32* %x1, align 4
%9 = load i32, i32* %x1, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0), i32 %9)
store i32 %sub6, i32* %blockret2, align 4
br label %expr_block.exit8
if.exit7: ; preds = %expr_block.exit
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.4, i32 0, i32 0))
%10 = load i32, i32* %x1, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 %10)
%11 = load i32, i32* %x1, align 4
store i32 %11, i32* %blockret2, align 4
br label %expr_block.exit8
expr_block.exit8: ; preds = %if.exit7, %if.then5
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.6, i32 0, i32 0))
ret void
}

View File

@@ -45,12 +45,6 @@ entry:
call void @foo.foo1()
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 3)
call void @foo2.foo2()
br label %exit
exit: ; preds = %entry
call void @foo2.foo2()
br label %exit1
exit1: ; preds = %exit
ret void
}

View File

@@ -21,6 +21,7 @@ fn void main()
define void @foo.main() #0 {
entry:
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%x1 = alloca i32, align 4
store i32 0, i32* %x, align 4
store i32 0, i32* %x1, align 4
@@ -32,9 +33,10 @@ entry:
store i32 %add2, i32* %x, align 4
%add3 = add i32 %add, %add2
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0))
br label %exit
store i32 %add3, i32* %blockret, align 4
br label %expr_block.exit
exit: ; preds = %entry
expr_block.exit: ; preds = %entry
%3 = load i32, i32* %x, align 4
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %3)
ret void

View File

@@ -38,9 +38,6 @@ entry:
%add1 = add i32 %3, 1
store i32 %add1, i32* %x, align 4
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i32 %3)
br label %exit
exit: ; preds = %entry
%5 = load i32, i32* %a, align 4
store i32 %5, i32* %y, align 4
%6 = load i32, i32* %x, align 4
@@ -51,9 +48,6 @@ exit: ; preds = %entry
%add3 = add i32 %8, 1
store i32 %add3, i32* %x, align 4
%9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.3, i32 0, i32 0), i32 %8)
br label %exit4
exit4: ; preds = %exit
%10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0))
ret void
}

View File

@@ -81,7 +81,6 @@ fn void main()
@.str = private unnamed_addr constant [16 x i8] c"%f => %d => %f\0A\00", align 1
@.str.1 = private unnamed_addr constant [18 x i8] c"%e => %llu => %e\0A\00", align 1
; Function Attrs: nounwind
define i64 @userland_bitcast.testFoo(i16 signext %0) #0 {
entry:
%z = alloca %Foo, align 2
@@ -104,6 +103,7 @@ entry:
store i16 %0, i16* %6, align 2
%7 = load %Foo, %Foo* %z, align 2
store %Foo %7, %Foo* %expr, align 2
store i64 0, i64* %x, align 8
%ptrptr = bitcast %Foo* %expr to i16*
store i16* %ptrptr, i16** %b, align 8
%ptrptr1 = bitcast i64* %x to i16*
@@ -144,6 +144,14 @@ entry:
%i = alloca i64, align 8
%tempcoerce = alloca i32, align 4
store float %0, float* %expr, align 4
%1 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 0
store i8 0, i8* %1, align 1
%2 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 1
store i8 0, i8* %2, align 1
%3 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 2
store i8 0, i8* %3, align 1
%4 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 3
store i8 0, i8* %4, align 1
%ptrptr = bitcast float* %expr to i8*
store i8* %ptrptr, i8** %b, align 8
%ptrptr1 = bitcast [4 x i8]* %x to i8*
@@ -152,30 +160,30 @@ entry:
br label %loop.cond
loop.cond: ; preds = %loop.body, %entry
%1 = load i64, i64* %i, align 8
%lt = icmp ult i64 %1, 4
%5 = load i64, i64* %i, align 8
%lt = icmp ult i64 %5, 4
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%2 = load i8*, i8** %to, align 8
%3 = load i64, i64* %i, align 8
%ptroffset = getelementptr inbounds i8, i8* %2, i64 %3
%4 = load i8*, i8** %b, align 8
%5 = load i64, i64* %i, align 8
%ptroffset2 = getelementptr inbounds i8, i8* %4, i64 %5
%6 = load i8, i8* %ptroffset2, align 1
store i8 %6, i8* %ptroffset, align 1
%6 = load i8*, i8** %to, align 8
%7 = load i64, i64* %i, align 8
%add = add i64 %7, 1
%ptroffset = getelementptr inbounds i8, i8* %6, i64 %7
%8 = load i8*, i8** %b, align 8
%9 = load i64, i64* %i, align 8
%ptroffset2 = getelementptr inbounds i8, i8* %8, i64 %9
%10 = load i8, i8* %ptroffset2, align 1
store i8 %10, i8* %ptroffset, align 1
%11 = load i64, i64* %i, align 8
%add = add i64 %11, 1
store i64 %add, i64* %i, align 8
br label %loop.cond
loop.exit: ; preds = %loop.cond
%8 = bitcast i32* %tempcoerce to i8*
%9 = bitcast [4 x i8]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %8, i8* align 1 %9, i32 4, i1 false)
%10 = load i32, i32* %tempcoerce, align 4
ret i32 %10
%12 = bitcast i32* %tempcoerce to i8*
%13 = bitcast [4 x i8]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %12, i8* align 1 %13, i32 4, i1 false)
%14 = load i32, i32* %tempcoerce, align 4
ret i32 %14
}
define void @userland_bitcast.main() #0 {
@@ -209,6 +217,7 @@ entry:
store float 0x4028B4BC60000000, float* %f, align 4
%0 = load float, float* %f, align 4
store float %0, float* %expr, align 4
store i32 0, i32* %x, align 4
%ptrptr = bitcast float* %expr to i32*
store i32* %ptrptr, i32** %b, align 8
store i32* %x, i32** %to, align 8
@@ -239,6 +248,7 @@ loop.exit: ; preds = %loop.cond
store i32 %8, i32* %i, align 4
%9 = load i32, i32* %i, align 4
store i32 %9, i32* %expr3, align 4
store float 0.000000e+00, float* %x4, align 4
store i32* %expr3, i32** %b5, align 8
%ptrptr7 = bitcast float* %x4 to i32*
store i32* %ptrptr7, i32** %to6, align 8
@@ -276,6 +286,7 @@ loop.exit15: ; preds = %loop.cond9
store double 1.235300e+268, double* %d, align 8
%21 = load double, double* %d, align 8
store double %21, double* %expr17, align 8
store i64 0, i64* %x18, align 8
%ptrptr20 = bitcast double* %expr17 to i64*
store i64* %ptrptr20, i64** %b19, align 8
store i64* %x18, i64** %to21, align 8
@@ -306,6 +317,7 @@ loop.exit29: ; preds = %loop.cond23
store i64 %29, i64* %l, align 8
%30 = load double, double* %d, align 8
store double %30, double* %expr30, align 8
store double 0.000000e+00, double* %x31, align 8
%ptrptr33 = bitcast double* %expr30 to i64*
store i64* %ptrptr33, i64** %b32, align 8
%ptrptr35 = bitcast double* %x31 to i64*
@@ -340,4 +352,5 @@ loop.exit43: ; preds = %loop.cond37
%41 = load double, double* %d2, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.1, i32 0, i32 0), double %39, i64 %40, double %41)
ret void
}
}

View File

@@ -18,11 +18,10 @@ fn int main(int argc, char** argv)
{
int a = 0;
{
defer
{
defer do {
if (a == 1) break;
defer1();
}
} while(0);
defer2();
}
defer defer3();
@@ -58,82 +57,58 @@ entry:
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
br label %exit
br label %loop.exit
if.exit: ; preds = %entry
call void @foo.defer1()
br label %exit
br label %loop.exit
exit: ; preds = %if.exit, %if.then
loop.exit: ; preds = %if.exit, %if.then
br label %loop.cond
loop.cond: ; preds = %exit6, %exit
loop.cond: ; preds = %if.exit3, %loop.exit
%3 = load i32, i32* %a, align 4
%intbool = icmp ne i32 %3, 0
br i1 %intbool, label %loop.body, label %loop.exit
br i1 %intbool, label %loop.body, label %loop.exit4
loop.body: ; preds = %loop.cond
%eq1 = icmp eq i32 %0, 1
br i1 %eq1, label %if.then2, label %if.exit4
br i1 %eq1, label %if.then2, label %if.exit3
if.then2: ; preds = %loop.body
call void @foo.defer4()
br label %exit3
br label %loop.exit4
exit3: ; preds = %if.then2
br label %loop.exit
if.exit4: ; preds = %loop.body
if.exit3: ; preds = %loop.body
call void @foo.defer6()
call void @foo.defer5()
br label %exit5
exit5: ; preds = %if.exit4
call void @foo.defer4()
br label %exit6
exit6: ; preds = %exit5
br label %loop.cond
loop.exit: ; preds = %exit3, %loop.cond
br label %loop.cond7
loop.exit4: ; preds = %if.then2, %loop.cond
br label %loop.cond5
loop.cond7: ; preds = %loop.exit
loop.cond5: ; preds = %loop.exit4
%4 = load i32, i32* %a, align 4
%intbool8 = icmp ne i32 %4, 0
br i1 %intbool8, label %loop.body9, label %loop.exit18
%intbool6 = icmp ne i32 %4, 0
br i1 %intbool6, label %loop.body7, label %loop.exit11
loop.body9: ; preds = %loop.cond7
%eq10 = icmp eq i32 %0, 1
br i1 %eq10, label %if.then11, label %if.exit13
loop.body7: ; preds = %loop.cond5
%eq8 = icmp eq i32 %0, 1
br i1 %eq8, label %if.then9, label %if.exit10
if.then11: ; preds = %loop.body9
if.then9: ; preds = %loop.body7
call void @foo.defer8()
br label %exit12
br label %loop.exit11
exit12: ; preds = %if.then11
br label %loop.exit18
if.exit13: ; preds = %loop.body9
if.exit10: ; preds = %loop.body7
call void @foo.defer10()
call void @foo.defer9()
br label %exit14
exit14: ; preds = %if.exit13
call void @foo.defer8()
br label %exit15
br label %loop.exit11
exit15: ; preds = %exit14
br label %loop.exit18
loop.exit18: ; preds = %exit15, %exit12, %loop.cond7
loop.exit11: ; preds = %if.exit10, %if.then9, %loop.cond5
call void @foo.defer7()
br label %exit19
exit19: ; preds = %loop.exit18
call void @foo.defer3()
br label %exit20
exit20: ; preds = %exit19
ret i32 0
}

View File

@@ -23,7 +23,8 @@ fn int main(int argc, char** argv)
return 0;
}
// #expect: test.ll
/* #expect: test.ll
define i32 @main(i32 %0, i8** %1) #0 {
@@ -32,7 +33,7 @@ entry:
store i32 0, i32* %a, align 4
br label %loop.cond
loop.cond: ; preds = %exit3, %entry
loop.cond: ; preds = %if.exit, %entry
%2 = load i32, i32* %a, align 4
%intbool = icmp ne i32 %2, 0
br i1 %intbool, label %loop.body, label %loop.exit
@@ -44,28 +45,16 @@ loop.body: ; preds = %loop.cond
if.then: ; preds = %loop.body
call void @test.testA()
call void @test.testB()
br label %exit
exit: ; preds = %if.then
call void @test.test2()
br label %exit1
exit1: ; preds = %exit
br label %loop.exit
if.exit: ; preds = %loop.body
call void @test.test3()
call void @test.testA()
call void @test.testB()
br label %exit2
exit2: ; preds = %if.exit
call void @test.test2()
br label %exit3
exit3: ; preds = %exit2
br label %loop.cond
loop.exit: ; preds = %exit1, %loop.cond
loop.exit: ; preds = %if.then, %loop.cond
ret i32 0
}

View File

@@ -19,7 +19,7 @@ fn void test(int i)
}
}
// #expect: defer_break_switch.ll
/* #expect: defer_break_switch.ll
define void @defer_break_switch.test(i32 %0) #0 {
entry:
@@ -33,7 +33,7 @@ switch.entry: ; preds = %entry
%1 = load i32, i32* %switch, align 4
switch i32 %1, label %switch.exit [
i32 1, label %switch.case
i32 2, label %switch.case2
i32 2, label %switch.case1
]
switch.case: ; preds = %switch.entry
@@ -43,23 +43,17 @@ switch.case: ; preds = %switch.entry
if.then: ; preds = %switch.case
call void @defer_break_switch.test2()
br label %exit
exit: ; preds = %if.then
br label %switch.exit
if.exit: ; preds = %switch.case
call void @defer_break_switch.test1()
call void @defer_break_switch.test2()
br label %exit1
exit1: ; preds = %if.exit
br label %switch.exit
switch.case2: ; preds = %switch.entry
switch.case1: ; preds = %switch.entry
call void @defer_break_switch.test1()
br label %switch.exit
switch.exit: ; preds = %switch.case2, %exit1, %exit, %switch.entry
switch.exit: ; preds = %switch.case1, %if.exit, %if.then, %switch.entry
ret void
}

View File

@@ -0,0 +1,38 @@
// #target: x64-darwin
module foo;
fn void test()
{
int a;
do
{
a++;
defer a++;
} while(a < 10);
}
/* #expect: foo.ll
define void @foo.test() #0 {
entry:
%a = alloca i32, align 4
store i32 0, i32* %a, align 4
br label %loop.body
loop.cond: ; preds = %loop.body
%0 = load i32, i32* %a, align 4
%lt = icmp slt i32 %0, 10
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond, %entry
%1 = load i32, i32* %a, align 4
%add = add i32 %1, 1
store i32 %add, i32* %a, align 4
%2 = load i32, i32* %a, align 4
%add1 = add i32 %2, 1
store i32 %add1, i32* %a, align 4
br label %loop.cond
loop.exit: ; preds = %loop.cond
ret void
}

View File

@@ -0,0 +1,71 @@
// #target: x64-darwin
module foo;
extern fn void printf(char*,...);
fn void test(int x)
{
defer printf("---\n");
{|
defer printf("Hello %d\n", x);
x *= 2;
if (x < 100) return;
x *= 10000;
|};
printf("+++\n");
if (x == 0)
{
printf("0x\n");
return;
}
if (x == 1) return;
}
fn void main()
{
test(123);
test(1);
test(0);
}
/* #expect: foo.ll
define void @foo.test(i32 %0) #0 {
entry:
%x = alloca i32, align 4
store i32 %0, i32* %x, align 4
%1 = load i32, i32* %x, align 4
%mul = mul i32 %1, 2
store i32 %mul, i32* %x, align 4
%2 = load i32, i32* %x, align 4
%lt = icmp slt i32 %2, 100
br i1 %lt, label %if.then, label %if.exit
if.then: ; preds = %entry
%3 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i32 %3)
br label %expr_block.exit
if.exit: ; preds = %entry
%4 = load i32, i32* %x, align 4
%mul1 = mul i32 %4, 10000
store i32 %mul1, i32* %x, align 4
%5 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i32 0, i32 0), i32 %5)
br label %expr_block.exit
expr_block.exit: ; preds = %if.exit, %if.then
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0))
%6 = load i32, i32* %x, align 4
%eq = icmp eq i32 %6, 0
br i1 %eq, label %if.then2, label %if.exit3
if.then2: ; preds = %expr_block.exit
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0))
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i32 0, i32 0))
ret void
if.exit3: ; preds = %expr_block.exit
%7 = load i32, i32* %x, align 4
%eq4 = icmp eq i32 %7, 1
br i1 %eq4, label %if.then5, label %if.exit6
if.then5: ; preds = %if.exit3
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i32 0, i32 0))
ret void
if.exit6: ; preds = %if.exit3
call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i32 0, i32 0))
ret void
}

View File

@@ -22,15 +22,17 @@ fn void test_line()
// #expect: defer_in_defer.ll
define void @defer_in_defer.test() #0 {
entry:
call void @defer_in_defer.test4()
call void @defer_in_defer.test2()
call void @defer_in_defer.test3()
br label %exit
exit:
call void @defer_in_defer.test1()
ret void
}
define void @defer_in_defer.test_line() #0 {
entry:
call void @defer_in_defer.test1()
br label %exit
ret void
}

View File

@@ -0,0 +1,120 @@
// #target: x64-darwin
module test;
extern fn void printf(char*,...);
fn void test(int x)
{
defer
{
do
{
defer printf("Hello %d\n", x);
x *= 2;
if (x < 100) break;
x *= 10000;
};
}
if (x == 1)
{
printf("1x\n");
return;
}
if (x == 0) return;
}
fn void main()
{
test(123);
test(1);
test(0);
}
/* #expect: test.ll
define void @test.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.exit3
if.then: ; preds = %entry
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0))
%2 = load i32, i32* %x, align 4
%mul = mul i32 %2, 2
store i32 %mul, i32* %x, align 4
%3 = load i32, i32* %x, align 4
%lt = icmp slt i32 %3, 100
br i1 %lt, label %if.then1, label %if.exit
if.then1: ; preds = %if.then
%4 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i32 0, i32 0), i32 %4)
br label %loop.exit
if.exit: ; preds = %if.then
%5 = load i32, i32* %x, align 4
%mul2 = mul i32 %5, 10000
store i32 %mul2, i32* %x, align 4
%6 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %6)
br label %loop.exit
loop.exit: ; preds = %if.exit, %if.then1
ret void
if.exit3: ; preds = %entry
%7 = load i32, i32* %x, align 4
%eq4 = icmp eq i32 %7, 0
br i1 %eq4, label %if.then5, label %if.exit12
if.then5: ; preds = %if.exit3
%8 = load i32, i32* %x, align 4
%mul6 = mul i32 %8, 2
store i32 %mul6, i32* %x, align 4
%9 = load i32, i32* %x, align 4
%lt7 = icmp slt i32 %9, 100
br i1 %lt7, label %if.then8, label %if.exit9
if.then8: ; preds = %if.then5
%10 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0), i32 %10)
br label %loop.exit11
if.exit9: ; preds = %if.then5
%11 = load i32, i32* %x, align 4
%mul10 = mul i32 %11, 10000
store i32 %mul10, i32* %x, align 4
%12 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.4, i32 0, i32 0), i32 %12)
br label %loop.exit11
loop.exit11: ; preds = %if.exit9, %if.then8
ret void
if.exit12: ; preds = %if.exit3
%13 = load i32, i32* %x, align 4
%mul13 = mul i32 %13, 2
store i32 %mul13, i32* %x, align 4
%14 = load i32, i32* %x, align 4
%lt14 = icmp slt i32 %14, 100
br i1 %lt14, label %if.then15, label %if.exit16
if.then15: ; preds = %if.exit12
%15 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 %15)
br label %loop.exit18
if.exit16: ; preds = %if.exit12
%16 = load i32, i32* %x, align 4
%mul17 = mul i32 %16, 10000
store i32 %mul17, i32* %x, align 4
%17 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i32 %17)
br label %loop.exit18
loop.exit18: ; preds = %if.exit16, %if.then15
ret void
}

View File

@@ -19,7 +19,7 @@ fn void test(int i)
}
}
// #expect: defer_next_switch.ll
/* #expect: defer_next_switch.ll
define void @defer_next_switch.test(i32 %0) #0 {
entry:
@@ -33,7 +33,7 @@ switch.entry: ; preds = %entry
%1 = load i32, i32* %switch, align 4
switch i32 %1, label %switch.exit [
i32 1, label %switch.case
i32 2, label %switch.case2
i32 2, label %switch.case1
]
switch.case: ; preds = %switch.entry
@@ -43,23 +43,17 @@ switch.case: ; preds = %switch.entry
if.then: ; preds = %switch.case
call void @defer_next_switch.test2()
br label %exit
exit: ; preds = %if.then
br label %switch.case2
br label %switch.case1
if.exit: ; preds = %switch.case
call void @defer_next_switch.test1()
call void @defer_next_switch.test2()
br label %exit1
exit1: ; preds = %if.exit
br label %switch.exit
switch.case2: ; preds = %switch.entry, %exit
switch.case1: ; preds = %switch.entry, %if.then
call void @defer_next_switch.test1()
br label %switch.exit
switch.exit: ; preds = %switch.case2, %exit1, %switch.entry
switch.exit: ; preds = %switch.case1, %if.exit, %switch.entry
ret void
}

View File

@@ -42,7 +42,7 @@ entry:
store i32 0, i32* %a, align 4
br label %loop.cond
loop.cond: ; preds = %exit3, %entry
loop.cond: ; preds = %if.exit, %entry
%2 = load i32, i32* %a, align 4
%intbool = icmp ne i32 %2, 0
br i1 %intbool, label %loop.body, label %loop.exit
@@ -55,85 +55,46 @@ if.then: ; preds = %loop.body
%3 = load i32, i32* %a, align 4
%add = add i32 %3, %0
call void @test.test2()
br label %exit
exit: ; preds = %if.then
call void @test.test1()
br label %exit1
exit1: ; preds = %exit
ret i32 %add
if.exit: ; preds = %loop.body
call void @test.test4()
call void @test.test3()
br label %exit2
exit2: ; preds = %if.exit
call void @test.test2()
br label %exit3
exit3: ; preds = %exit2
br label %loop.cond
loop.exit: ; preds = %loop.cond
br label %loop.cond4
br label %loop.cond1
loop.cond4: ; preds = %loop.exit
loop.cond1: ; preds = %loop.exit
%4 = load i32, i32* %a, align 4
%intbool5 = icmp ne i32 %4, 0
br i1 %intbool5, label %loop.body6, label %loop.exit21
%intbool2 = icmp ne i32 %4, 0
br i1 %intbool2, label %loop.body3, label %loop.exit8
loop.body6: ; preds = %loop.cond4
%eq7 = icmp eq i32 %0, 1
br i1 %eq7, label %if.then8, label %if.exit13
loop.body3: ; preds = %loop.cond1
%eq4 = icmp eq i32 %0, 1
br i1 %eq4, label %if.then5, label %if.exit7
if.then8: ; preds = %loop.body6
if.then5: ; preds = %loop.body3
%5 = load i32, i32* %a, align 4
%add9 = add i32 %5, 2
%add6 = add i32 %5, 2
call void @test.test6()
br label %exit10
exit10: ; preds = %if.then8
call void @test.test5()
br label %exit11
exit11: ; preds = %exit10
call void @test.test1()
br label %exit12
ret i32 %add6
exit12: ; preds = %exit11
ret i32 %add9
if.exit13: ; preds = %loop.body6
if.exit7: ; preds = %loop.body3
call void @test.test8()
call void @test.test7()
br label %exit14
exit14: ; preds = %if.exit13
call void @test.test6()
br label %exit15
exit15: ; preds = %exit14
call void @test.test5()
br label %exit16
exit16: ; preds = %exit15
call void @test.test1()
br label %exit17
exit17: ; preds = %exit16
ret i32 4
loop.exit21: ; preds = %loop.cond4
%add22 = add i32 0, %0
loop.exit8: ; preds = %loop.cond1
%add9 = add i32 0, %0
call void @test.test5()
br label %exit23
exit23: ; preds = %loop.exit21
call void @test.test1()
br label %exit24
exit24: ; preds = %exit23
ret i32 %add22
}
ret i32 %add9
}

View File

@@ -4,7 +4,6 @@ fn void test()
defer
{
i = i + 1;
break;
}
return;
}

View File

@@ -0,0 +1,108 @@
// #target: x64-darwin
module test;
extern fn void printf(char*,...);
fn void test(int x)
{
defer
{
for (int i = 0; i < 3; i++)
{
printf("%d\n", x + i);
}
}
if (x == 1)
{
printf("1x\n");
return;
}
if (x == 0) return;
}
fn void main()
{
test(123);
test(1);
test(0);
}
/* #expect: test.ll
define void @test.test(i32 %0) #0 {
entry:
%i = alloca i32, align 4
%i4 = alloca i32, align 4
%i12 = alloca i32, align 4
%eq = icmp eq i32 %0, 1
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0))
store i32 0, i32* %i, align 4
br label %loop.cond
loop.cond: ; preds = %loop.body, %if.then
%1 = load i32, i32* %i, align 4
%lt = icmp slt i32 %1, 3
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%2 = load i32, i32* %i, align 4
%add = add i32 %0, %2
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %add)
%3 = load i32, i32* %i, align 4
%add1 = add i32 %3, 1
store i32 %add1, i32* %i, align 4
br label %loop.cond
loop.exit: ; preds = %loop.cond
ret void
if.exit: ; preds = %entry
%eq2 = icmp eq i32 %0, 0
br i1 %eq2, label %if.then3, label %if.exit11
if.then3: ; preds = %if.exit
store i32 0, i32* %i4, align 4
br label %loop.cond5
loop.cond5: ; preds = %loop.body7, %if.then3
%4 = load i32, i32* %i4, align 4
%lt6 = icmp slt i32 %4, 3
br i1 %lt6, label %loop.body7, label %loop.exit10
loop.body7: ; preds = %loop.cond5
%5 = load i32, i32* %i4, align 4
%add8 = add i32 %0, %5
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), i32 %add8)
%6 = load i32, i32* %i4, align 4
%add9 = add i32 %6, 1
store i32 %add9, i32* %i4, align 4
br label %loop.cond5
loop.exit10: ; preds = %loop.cond5
ret void
if.exit11: ; preds = %if.exit
store i32 0, i32* %i12, align 4
br label %loop.cond13
loop.cond13: ; preds = %loop.body15, %if.exit11
%7 = load i32, i32* %i12, align 4
%lt14 = icmp slt i32 %7, 3
br i1 %lt14, label %loop.body15, label %loop.exit18
loop.body15: ; preds = %loop.cond13
%8 = load i32, i32* %i12, align 4
%add16 = add i32 %0, %8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %add16)
%9 = load i32, i32* %i12, align 4
%add17 = add i32 %9, 1
store i32 %add17, i32* %i12, align 4
br label %loop.cond13
loop.exit18: ; preds = %loop.cond13
ret void
}

View File

@@ -40,12 +40,9 @@ if.then: ; preds = %entry
%2 = load i32, i32* %x, align 4
%add = add i32 %2, 1
store i32 %add, i32* %x, align 4
br label %exit
exit: ; preds = %if.then
br label %if.exit
if.exit: ; preds = %exit, %entry
if.exit: ; preds = %if.then, %entry
ret void
}

View File

@@ -7,7 +7,7 @@ fn int main()
{
return 1;
}
}
};
return 0;
}
@@ -20,5 +20,5 @@ fn void test1()
{
break BAR; // #error: Cannot find a labelled statement with the name 'BAR'
}
}
};
}

View File

@@ -185,15 +185,5 @@ fn void test24()
int a = b123; // #error: 'int[2][3]' into 'int'
}
fn void test25()
{
const A = void; // #error: Constants cannot be undefined.
}
fn void test26()
{
const int A = void; // #error: Constants cannot be undefined.
}