mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Changing how defer works. Remove of undef. Simplify ensure.
This commit is contained in:
committed by
Christoffer Lerno
parent
9b0dfe8ba3
commit
069a2d40cb
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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(©_struct, source_ast);
|
||||
}
|
||||
|
||||
Expr *expr_macro_copy(Expr *source_expr)
|
||||
{
|
||||
copy_struct.current_fixup = copy_struct.fixups;
|
||||
return copy_expr(©_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(©_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(©->func_decl.function_signature);
|
||||
copy_function_signature_deep(c, ©->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(©->typedef_decl.function_signature);
|
||||
copy_function_signature_deep(c, ©->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(©->distinct_decl.typedef_decl.function_signature);
|
||||
copy_function_signature_deep(c, ©->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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(¤t));
|
||||
}
|
||||
}
|
||||
|
||||
#define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0);
|
||||
|
||||
#define PUSH_ERROR() \
|
||||
|
||||
@@ -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(¤t));
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ¶m->attributes)) return false;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(¯o_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(¤t)))
|
||||
stmt = ast_next(¤t);
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(¤t);
|
||||
ast = ast_next(¤t);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "PRE.24"
|
||||
#define COMPILER_VERSION "PRE.25"
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
83
test/test_suite/macros/macro_defer_exit.c3t
Normal file
83
test/test_suite/macros/macro_defer_exit.c3t
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
38
test/test_suite/statements/defer_do_while.c3t
Normal file
38
test/test_suite/statements/defer_do_while.c3t
Normal 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
|
||||
}
|
||||
71
test/test_suite/statements/defer_in_block.c3t
Normal file
71
test/test_suite/statements/defer_in_block.c3t
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
120
test/test_suite/statements/defer_in_defer2.c3t
Normal file
120
test/test_suite/statements/defer_in_defer2.c3t
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -4,7 +4,6 @@ fn void test()
|
||||
defer
|
||||
{
|
||||
i = i + 1;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
108
test/test_suite/statements/defer_with_loop.c3t
Normal file
108
test/test_suite/statements/defer_with_loop.c3t
Normal 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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user