remove compiler directives

* add `setFnTest`, `setFnVisible`, `setFnStaticEval`,
   `setFnNoInline` builtin functions to replace previous
   directive functionality
 * add `coldcc` and `nakedcc` as keywords which can be used as part
   of a function prototype.
 * `setDebugSafety` builtin can be used to set debug safety features
   at a per block scope level.
 * closes #169
This commit is contained in:
Andrew Kelley 2016-09-28 02:33:32 -04:00
parent e5fd8efcb6
commit b581da41f8
40 changed files with 812 additions and 528 deletions

View File

@ -3,9 +3,11 @@
## Grammar
```
Root = many(TopLevelDecl) "EOF"
Root = many(TopLevelItem) "EOF"
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | ErrorValueDecl | TypeDecl | UseDecl)
TopLevelItem = ErrorValueDecl | Block | TopLevelDecl
TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | TypeDecl | UseDecl)
TypeDecl = "type" Symbol "=" TypeExpr ";"
@ -17,7 +19,7 @@ VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) "=" Expressi
ContainerDecl = ("struct" | "enum" | "union") Symbol option(ParamDeclList) "{" many(StructMember) "}"
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl)
StructMember = (StructField | FnDef | GlobalVarDecl | ContainerDecl)
StructField = Symbol option(":" Expression) ",")
@ -25,9 +27,7 @@ UseDecl = "use" Expression ";"
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
FnProto = "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
Directive = "#" Symbol "(" Expression ")"
FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
VisibleMod = "pub" | "export"

View File

@ -8,7 +8,7 @@ if exists("b:current_syntax")
endif
let b:current_syntax = "zig"
syn keyword zigStorage const var extern export pub noalias inline noinline
syn keyword zigStorage const var extern export pub noalias inline nakedcc coldcc
syn keyword zigStructure struct enum union
syn keyword zigStatement goto break return continue asm defer
syn keyword zigConditional if else switch

View File

@ -129,7 +129,6 @@ enum TldResolution {
struct TopLevelDecl {
// populated by parser
Buf *name;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
@ -153,7 +152,6 @@ enum NodeType {
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeBlock,
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeDefer,
NodeTypeVariableDeclaration,
@ -210,6 +208,8 @@ struct AstNodeFnProto {
bool is_var_args;
bool is_extern;
bool is_inline;
bool is_coldcc;
bool is_nakedcc;
// populated by semantic analyzer:
@ -459,11 +459,6 @@ struct AstNodeFieldAccessExpr {
AstNode *container_init_expr_node;
};
struct AstNodeDirective {
Buf *name;
AstNode *expr;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
@ -802,7 +797,6 @@ struct AstNode {
AstNodeErrorValueDecl error_value_decl;
AstNodeBinOpExpr bin_op_expr;
AstNodeUnwrapErrorExpr unwrap_err_expr;
AstNodeDirective directive;
AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr;
@ -1109,10 +1103,14 @@ struct FnTableEntry {
WantPure want_pure;
AstNode *want_pure_attr_node;
AstNode *want_pure_return_type;
bool safety_off;
FnInline fn_inline;
FnAnalState anal_state;
AstNode *fn_no_inline_set_node;
AstNode *fn_export_set_node;
AstNode *fn_test_set_node;
AstNode *fn_static_eval_set_node;
ZigList<AstNode *> cast_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
ZigList<VariableTableEntry *> variable_list;
@ -1154,6 +1152,11 @@ enum BuiltinFnId {
BuiltinFnIdTruncate,
BuiltinFnIdIntType,
BuiltinFnIdUnreachable,
BuiltinFnIdSetFnTest,
BuiltinFnIdSetFnVisible,
BuiltinFnIdSetFnStaticEval,
BuiltinFnIdSetFnNoInline,
BuiltinFnIdSetDebugSafety,
};
struct BuiltinFnEntry {
@ -1373,6 +1376,7 @@ struct BlockContext {
bool codegen_excluded;
bool safety_off;
AstNode *safety_set_node;
};
enum AtomicOrder {

View File

@ -75,7 +75,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeBlock:
case NodeTypeDirective:
case NodeTypeReturnExpr:
case NodeTypeDefer:
case NodeTypeVariableDeclaration:
@ -1123,6 +1122,28 @@ static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockC
return true;
}
static FnTableEntry *resolve_const_expr_fn(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode **node)
{
TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr, *node);
if (resolved_type->id == TypeTableEntryIdInvalid) {
return nullptr;
} else if (resolved_type->id == TypeTableEntryIdFn) {
ConstExprValue *const_val = &get_resolved_expr(*node)->const_val;
if (!const_val->ok) {
add_node_error(g, *node, buf_sprintf("unable to evaluate constant expression"));
return nullptr;
}
return const_val->data.x_fn;
} else {
add_node_error(g, *node, buf_sprintf("expected function, got '%s'", buf_ptr(&resolved_type->name)));
return nullptr;
}
}
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
ImportTableEntry *import, BlockContext *containing_context)
{
@ -1133,85 +1154,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
return;
}
bool is_cold = false;
bool is_naked = false;
bool is_test = false;
bool is_noinline = false;
if (fn_proto->top_level_decl.directives) {
for (size_t i = 0; i < fn_proto->top_level_decl.directives->length; i += 1) {
AstNode *directive_node = fn_proto->top_level_decl.directives->at(i);
Buf *name = directive_node->data.directive.name;
if (buf_eql_str(name, "attribute")) {
if (fn_table_entry->fn_def_node) {
Buf *attr_name = resolve_const_expr_str(g, import, import->block_context,
&directive_node->data.directive.expr);
if (attr_name) {
if (buf_eql_str(attr_name, "naked")) {
is_naked = true;
} else if (buf_eql_str(attr_name, "noinline")) {
is_noinline = true;
} else if (buf_eql_str(attr_name, "cold")) {
is_cold = true;
} else if (buf_eql_str(attr_name, "test")) {
is_test = true;
g->test_fn_count += 1;
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
}
}
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
}
} else if (buf_eql_str(name, "debug_safety")) {
if (!fn_table_entry->fn_def_node) {
add_node_error(g, directive_node,
buf_sprintf("#debug_safety valid only on function definitions"));
} else {
bool enable;
bool ok = resolve_const_expr_bool(g, import, import->block_context,
&directive_node->data.directive.expr, &enable);
if (ok && !enable) {
fn_table_entry->safety_off = true;
}
}
} else if (buf_eql_str(name, "condition")) {
if (fn_proto->top_level_decl.visib_mod == VisibModExport) {
bool include;
bool ok = resolve_const_expr_bool(g, import, import->block_context,
&directive_node->data.directive.expr, &include);
if (ok && !include) {
fn_proto->top_level_decl.visib_mod = VisibModPub;
}
} else {
add_node_error(g, directive_node,
buf_sprintf("#condition valid only on exported symbols"));
}
} else if (buf_eql_str(name, "static_eval_enable")) {
if (!fn_table_entry->fn_def_node) {
add_node_error(g, directive_node,
buf_sprintf("#static_val_enable valid only on function definitions"));
} else {
bool enable;
bool ok = resolve_const_expr_bool(g, import, import->block_context,
&directive_node->data.directive.expr, &enable);
if (!ok || !enable) {
fn_table_entry->want_pure = WantPureFalse;
} else if (ok && enable) {
fn_table_entry->want_pure = WantPureTrue;
fn_table_entry->want_pure_attr_node = directive_node->data.directive.expr;
}
}
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
}
}
}
bool is_internal = (fn_proto->top_level_decl.visib_mod != VisibModExport);
bool is_c_compat = !is_internal || fn_proto->is_extern;
fn_table_entry->internal_linkage = !is_c_compat;
@ -1219,24 +1161,17 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node,
is_naked, is_cold, fn_table_entry);
fn_proto->is_nakedcc, fn_proto->is_coldcc, fn_table_entry);
fn_table_entry->type_entry = fn_type;
fn_table_entry->is_test = is_test;
if (fn_type->id == TypeTableEntryIdInvalid) {
fn_proto->skip = true;
return;
}
if (fn_proto->is_inline && is_noinline) {
add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
fn_proto->skip = true;
return;
} else if (fn_proto->is_inline) {
if (fn_proto->is_inline) {
fn_table_entry->fn_inline = FnInlineAlways;
} else if (is_noinline) {
fn_table_entry->fn_inline = FnInlineNever;
}
@ -1881,7 +1816,6 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
zig_panic("TODO resolve_top_level_decl NodeTypeUse");
break;
case NodeTypeFnDef:
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
@ -2406,13 +2340,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
context->parent_loop_node = parent->parent_loop_node;
context->c_import_buf = parent->c_import_buf;
context->codegen_excluded = parent->codegen_excluded;
context->safety_off = parent->safety_off;
}
if (node && node->type == NodeTypeFnDef) {
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry;
context->safety_off = context->fn_entry->safety_off;
} else if (parent) {
context->fn_entry = parent->fn_entry;
}
@ -5246,6 +5178,203 @@ static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
}
static TypeTableEntry *analyze_set_fn_test(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node)
{
AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
AstNode **value_node = &node->data.fn_call_expr.params.at(1);
FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
if (!fn_entry) {
return g->builtin_types.entry_invalid;
}
bool ok = resolve_const_expr_bool(g, import, context, value_node, &fn_entry->is_test);
if (!ok) {
return g->builtin_types.entry_invalid;
}
if (fn_entry->fn_test_set_node) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function test attribute set twice"));
add_error_note(g, msg, fn_entry->fn_test_set_node, buf_sprintf("first set here"));
return g->builtin_types.entry_invalid;
}
fn_entry->fn_test_set_node = node;
g->test_fn_count += 1;
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_set_fn_no_inline(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node)
{
AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
AstNode **value_node = &node->data.fn_call_expr.params.at(1);
FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
if (!fn_entry) {
return g->builtin_types.entry_invalid;
}
bool is_noinline;
bool ok = resolve_const_expr_bool(g, import, context, value_node, &is_noinline);
if (!ok) {
return g->builtin_types.entry_invalid;
}
if (fn_entry->fn_no_inline_set_node) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function no inline attribute set twice"));
add_error_note(g, msg, fn_entry->fn_no_inline_set_node, buf_sprintf("first set here"));
return g->builtin_types.entry_invalid;
}
fn_entry->fn_no_inline_set_node = node;
if (fn_entry->fn_inline == FnInlineAlways) {
add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
fn_entry->proto_node->data.fn_proto.skip = true;
return g->builtin_types.entry_invalid;
} else if (is_noinline) {
fn_entry->fn_inline = FnInlineNever;
}
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_set_fn_static_eval(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node)
{
AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
AstNode **value_node = &node->data.fn_call_expr.params.at(1);
FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
if (!fn_entry) {
return g->builtin_types.entry_invalid;
}
bool want_static_eval;
bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_static_eval);
if (!ok) {
return g->builtin_types.entry_invalid;
}
if (fn_entry->fn_static_eval_set_node) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function static eval attribute set twice"));
add_error_note(g, msg, fn_entry->fn_static_eval_set_node, buf_sprintf("first set here"));
return g->builtin_types.entry_invalid;
}
fn_entry->fn_static_eval_set_node = node;
if (want_static_eval && !context->fn_entry->is_pure) {
add_node_error(g, node, buf_sprintf("attribute appears too late within function"));
return g->builtin_types.entry_invalid;
}
if (want_static_eval) {
fn_entry->want_pure = WantPureTrue;
fn_entry->want_pure_attr_node = node;
} else {
fn_entry->want_pure = WantPureFalse;
fn_entry->is_pure = false;
}
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_set_fn_visible(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node)
{
AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
AstNode **value_node = &node->data.fn_call_expr.params.at(1);
FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
if (!fn_entry) {
return g->builtin_types.entry_invalid;
}
bool want_export;
bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_export);
if (!ok) {
return g->builtin_types.entry_invalid;
}
if (fn_entry->fn_export_set_node) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function visibility set twice"));
add_error_note(g, msg, fn_entry->fn_export_set_node, buf_sprintf("first set here"));
return g->builtin_types.entry_invalid;
}
fn_entry->fn_export_set_node = node;
AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto;
if (fn_proto->top_level_decl.visib_mod != VisibModExport) {
ErrorMsg *msg = add_node_error(g, node,
buf_sprintf("function must be marked export to set function visibility"));
add_error_note(g, msg, fn_entry->proto_node, buf_sprintf("function declared here"));
return g->builtin_types.entry_void;
}
if (!want_export) {
fn_proto->top_level_decl.visib_mod = VisibModPub;
}
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_set_debug_safety(CodeGen *g, ImportTableEntry *import,
BlockContext *parent_context, AstNode *node)
{
AstNode **target_node = &node->data.fn_call_expr.params.at(0);
AstNode **value_node = &node->data.fn_call_expr.params.at(1);
TypeTableEntry *target_type = analyze_expression(g, import, parent_context, nullptr, *target_node);
BlockContext *target_context;
ConstExprValue *const_val = &get_resolved_expr(*target_node)->const_val;
if (target_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
}
if (!const_val->ok) {
add_node_error(g, *target_node, buf_sprintf("unable to evaluate constant expression"));
return g->builtin_types.entry_invalid;
}
if (target_type->id == TypeTableEntryIdBlock) {
target_context = const_val->data.x_block;
} else if (target_type->id == TypeTableEntryIdFn) {
target_context = const_val->data.x_fn->fn_def_node->data.fn_def.block_context;
} else if (target_type->id == TypeTableEntryIdMetaType) {
TypeTableEntry *type_arg = const_val->data.x_type;
if (type_arg->id == TypeTableEntryIdStruct) {
target_context = type_arg->data.structure.block_context;
} else if (type_arg->id == TypeTableEntryIdEnum) {
target_context = type_arg->data.enumeration.block_context;
} else if (type_arg->id == TypeTableEntryIdUnion) {
target_context = type_arg->data.unionation.block_context;
} else {
add_node_error(g, *target_node,
buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&type_arg->name)));
return g->builtin_types.entry_invalid;
}
} else {
add_node_error(g, *target_node,
buf_sprintf("expected scope reference, got type '%s'", buf_ptr(&target_type->name)));
return g->builtin_types.entry_invalid;
}
bool want_debug_safety;
bool ok = resolve_const_expr_bool(g, import, parent_context, value_node, &want_debug_safety);
if (!ok) {
return g->builtin_types.entry_invalid;
}
if (target_context->safety_set_node) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("debug safety for scope set twice"));
add_error_note(g, msg, target_context->safety_set_node, buf_sprintf("first set here"));
return g->builtin_types.entry_invalid;
}
target_context->safety_set_node = node;
target_context->safety_off = !want_debug_safety;
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
@ -5607,6 +5736,16 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
return analyze_int_type(g, import, context, node);
case BuiltinFnIdUnreachable:
return g->builtin_types.entry_unreachable;
case BuiltinFnIdSetFnTest:
return analyze_set_fn_test(g, import, context, node);
case BuiltinFnIdSetFnNoInline:
return analyze_set_fn_no_inline(g, import, context, node);
case BuiltinFnIdSetFnStaticEval:
return analyze_set_fn_static_eval(g, import, context, node);
case BuiltinFnIdSetFnVisible:
return analyze_set_fn_visible(g, import, context, node);
case BuiltinFnIdSetDebugSafety:
return analyze_set_debug_safety(g, import, context, node);
}
zig_unreachable();
}
@ -6876,7 +7015,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
break;
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeDirective:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeRoot:
@ -7109,7 +7247,6 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
// error value declarations do not depend on other top level decls
preview_error_value_decl(g, node);
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
@ -7418,7 +7555,6 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeContainerDecl:
case NodeTypeStructField:
@ -7469,7 +7605,6 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeBlock:
case NodeTypeDirective:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeSymbol:

View File

@ -141,8 +141,6 @@ static const char *node_type_str(NodeType node_type) {
return "ArrayAccessExpr";
case NodeTypeSliceExpr:
return "SliceExpr";
case NodeTypeDirective:
return "Directive";
case NodeTypeReturnExpr:
return "ReturnExpr";
case NodeTypeDefer:
@ -416,13 +414,6 @@ static void render_node(AstRender *ar, AstNode *node) {
}
case NodeTypeFnDef:
{
ZigList<AstNode *> *directives =
node->data.fn_def.fn_proto->data.fn_proto.top_level_decl.directives;
if (directives) {
for (size_t i = 0; i < directives->length; i += 1) {
render_node(ar, directives->at(i));
}
}
render_node(ar, node->data.fn_def.fn_proto);
fprintf(ar->f, " ");
render_node(ar, node->data.fn_def.body);
@ -445,11 +436,6 @@ static void render_node(AstRender *ar, AstNode *node) {
print_indent(ar);
fprintf(ar->f, "}");
break;
case NodeTypeDirective:
fprintf(ar->f, "#%s(", buf_ptr(node->data.directive.name));
render_node(ar, node->data.directive.expr);
fprintf(ar->f, ")\n");
break;
case NodeTypeReturnExpr:
{
const char *return_str = return_string(node->data.return_expr.kind);

View File

@ -352,8 +352,20 @@ static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValue
}
}
static bool want_debug_safety_recursive(CodeGen *g, BlockContext *context) {
if (context->safety_set_node || !context->parent) {
return !context->safety_off;
}
context->safety_off = want_debug_safety_recursive(g, context->parent);
context->safety_set_node = context->parent->safety_set_node;
return !context->safety_off;
}
static bool want_debug_safety(CodeGen *g, AstNode *node) {
return !g->is_release_build && !node->block_context->safety_off;
if (g->is_release_build) {
return false;
}
return want_debug_safety_recursive(g, node->block_context);
}
static void gen_debug_safety_crash(CodeGen *g) {
@ -709,6 +721,13 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
return gen_truncate(g, node);
case BuiltinFnIdUnreachable:
return gen_unreachable(g, node);
case BuiltinFnIdSetFnTest:
case BuiltinFnIdSetFnVisible:
case BuiltinFnIdSetFnStaticEval:
case BuiltinFnIdSetFnNoInline:
case BuiltinFnIdSetDebugSafety:
// do nothing
return nullptr;
}
zig_unreachable();
}
@ -3617,7 +3636,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeContainerDecl:
case NodeTypeStructField:
@ -4880,6 +4898,11 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "intType", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdUnreachable, "unreachable", 0);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnTest, "setFnTest", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnStaticEval, "setFnStaticEval", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnNoInline, "setFnNoInline", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
}
static void init(CodeGen *g, Buf *source_path) {

View File

@ -963,6 +963,12 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
case BuiltinFnIdCompileErr:
case BuiltinFnIdIntType:
zig_unreachable();
case BuiltinFnIdSetFnTest:
case BuiltinFnIdSetFnVisible:
case BuiltinFnIdSetFnStaticEval:
case BuiltinFnIdSetFnNoInline:
case BuiltinFnIdSetDebugSafety:
return false;
}
return false;
@ -1398,7 +1404,6 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
case NodeTypeUse:
case NodeTypeAsmExpr:
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeTypeDecl:
zig_unreachable();
}

View File

@ -124,7 +124,6 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod;
node->data.variable_declaration.expr = init_node;
node->data.variable_declaration.top_level_decl.directives = nullptr;
node->data.variable_declaration.type = type_node;
normalize_parent_ptrs(node);
return node;

View File

@ -211,8 +211,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod);
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod);
static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index);
static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bool mandatory);
@ -233,39 +232,6 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token
return token;
}
/*
Directive = "#" "Symbol" "(" Expression ")"
*/
static AstNode *ast_parse_directive(ParseContext *pc, size_t *token_index) {
Token *number_sign = ast_eat_token(pc, token_index, TokenIdNumberSign);
AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.directive.name = token_buf(name_symbol);
node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true);
normalize_parent_ptrs(node);
return node;
}
static void ast_parse_directives(ParseContext *pc, size_t *token_index,
ZigList<AstNode *> *directives)
{
for (;;) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdNumberSign) {
AstNode *directive_node = ast_parse_directive(pc, token_index);
directives->append(directive_node);
} else {
return;
}
}
zig_unreachable();
}
/*
TypeExpr = PrefixOpExpression | "var"
*/
@ -686,7 +652,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
return node;
} else if (token->id == TokenIdKeywordExtern) {
*token_index += 1;
AstNode *node = ast_parse_fn_proto(pc, token_index, true, nullptr, VisibModPrivate);
AstNode *node = ast_parse_fn_proto(pc, token_index, true, VisibModPrivate);
node->data.fn_proto.is_extern = true;
return node;
} else if (token->id == TokenIdAtSign) {
@ -735,7 +701,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
return array_type_node;
}
AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, nullptr, VisibModPrivate);
AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, VisibModPrivate);
if (fn_proto_node) {
return fn_proto_node;
}
@ -1487,7 +1453,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
VariableDeclaration : ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
*/
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index);
@ -1509,7 +1475,6 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = visib_mod;
node->data.variable_declaration.top_level_decl.directives = directives;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.variable_declaration.symbol = token_buf(name_token);
@ -1985,8 +1950,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
if (statement_node) {
semicolon_expected = false;
} else {
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false,
nullptr, VisibModPrivate);
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
if (!statement_node) {
statement_node = ast_parse_defer_expr(pc, token_index);
}
@ -2023,25 +1987,35 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
}
/*
FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
Token *fn_token;
if (first_token->id != TokenIdKeywordFn) {
if (mandatory) {
ast_expect_token(pc, first_token, TokenIdKeywordFn);
} else {
return nullptr;
}
bool is_coldcc = false;
bool is_nakedcc = false;
if (first_token->id == TokenIdKeywordColdCC) {
*token_index += 1;
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
is_coldcc = true;
} else if (first_token->id == TokenIdKeywordNakedCC) {
*token_index += 1;
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
is_nakedcc = true;
} else if (first_token->id == TokenIdKeywordFn) {
fn_token = first_token;
*token_index += 1;
} else if (mandatory) {
ast_expect_token(pc, first_token, TokenIdKeywordFn);
} else {
return nullptr;
}
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeFnProto, first_token);
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
node->data.fn_proto.top_level_decl.visib_mod = visib_mod;
node->data.fn_proto.top_level_decl.directives = directives;
node->data.fn_proto.is_coldcc = is_coldcc;
node->data.fn_proto.is_nakedcc = is_nakedcc;
Token *fn_name = &pc->tokens->at(*token_index);
if (fn_name->id == TokenIdSymbol) {
@ -2068,9 +2042,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
/*
FnDef = option("inline" | "extern") FnProto Block
*/
static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
bool is_inline;
bool is_extern;
@ -2087,7 +2059,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
is_extern = false;
}
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, directives, visib_mod);
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod);
if (!fn_proto) {
if (is_inline || is_extern) {
*token_index -= 1;
@ -2115,9 +2087,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
/*
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
*/
static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode *> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
Token *extern_kw = &pc->tokens->at(*token_index);
if (extern_kw->id != TokenIdKeywordExtern) {
if (mandatory) {
@ -2128,7 +2098,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
}
*token_index += 1;
AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, directives, visib_mod);
AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, visib_mod);
if (fn_proto_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon);
@ -2138,7 +2108,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
return fn_proto_node;
}
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, directives, visib_mod);
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon);
@ -2155,9 +2125,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
/*
UseDecl = "use" Expression ";"
*/
static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordUse)
return nullptr;
@ -2165,7 +2133,6 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index,
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
node->data.use.top_level_decl.visib_mod = visib_mod;
node->data.use.top_level_decl.directives = directives;
node->data.use.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdSemicolon);
@ -2175,13 +2142,11 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index,
}
/*
ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl)
StructField : "Symbol" option(":" Expression) ",")
ContainerDecl = ("struct" | "enum" | "union") Symbol option(ParamDeclList) "{" many(StructMember) "}"
StructMember = (StructField | FnDef | GlobalVarDecl | ContainerDecl)
StructField = Symbol option(":" Expression) ",")
*/
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
ContainerKind kind;
@ -2203,7 +2168,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
node->data.struct_decl.kind = kind;
node->data.struct_decl.name = token_buf(struct_name);
node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
node->data.struct_decl.top_level_decl.directives = directives;
Token *paren_or_brace = &pc->tokens->at(*token_index);
if (paren_or_brace->id == TokenIdLParen) {
@ -2217,10 +2181,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
}
for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
ZigList<AstNode *> *directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directive_list);
Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) {
@ -2233,20 +2193,20 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
visib_mod = VisibModPrivate;
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, directive_list, visib_mod);
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, visib_mod);
if (fn_def_node) {
node->data.struct_decl.decls.append(fn_def_node);
continue;
}
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, directive_list, visib_mod);
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.struct_decl.decls.append(var_decl_node);
continue;
}
AstNode *container_decl_node = ast_parse_container_decl(pc, token_index, directive_list, visib_mod);
AstNode *container_decl_node = ast_parse_container_decl(pc, token_index, visib_mod);
if (container_decl_node) {
node->data.struct_decl.decls.append(container_decl_node);
continue;
@ -2255,10 +2215,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
if (directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
*token_index += 1;
break;
} else if (token->id == TokenIdSymbol) {
@ -2266,7 +2222,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
*token_index += 1;
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod;
field_node->data.struct_field.top_level_decl.directives = directive_list;
field_node->data.struct_field.name = token_buf(token);
Token *expr_or_comma = &pc->tokens->at(*token_index);
@ -2293,9 +2248,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
/*
ErrorValueDecl : "error" "Symbol" ";"
*/
static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
if (first_token->id != TokenIdKeywordError) {
@ -2308,7 +2261,6 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
node->data.error_value_decl.top_level_decl.visib_mod = visib_mod;
node->data.error_value_decl.top_level_decl.directives = directives;
node->data.error_value_decl.name = token_buf(name_tok);
normalize_parent_ptrs(node);
@ -2318,9 +2270,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index
/*
TypeDecl = "type" "Symbol" "=" TypeExpr ";"
*/
static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
if (first_token->id != TokenIdKeywordType) {
@ -2338,21 +2288,17 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index,
ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.type_decl.top_level_decl.visib_mod = visib_mod;
node->data.type_decl.top_level_decl.directives = directives;
normalize_parent_ptrs(node);
return node;
}
/*
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
TopLevelItem = ErrorValueDecl | Block | TopLevelDecl
TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | TypeDecl | UseDecl)
*/
static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
ZigList<AstNode *> *directives = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directives);
Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) {
@ -2365,61 +2311,56 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
visib_mod = VisibModPrivate;
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, directives, visib_mod);
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, visib_mod);
if (fn_def_node) {
top_level_decls->append(fn_def_node);
continue;
}
AstNode *fn_proto_node = ast_parse_extern_decl(pc, token_index, false, directives, visib_mod);
AstNode *fn_proto_node = ast_parse_extern_decl(pc, token_index, false, visib_mod);
if (fn_proto_node) {
top_level_decls->append(fn_proto_node);
continue;
}
AstNode *use_node = ast_parse_use(pc, token_index, directives, visib_mod);
AstNode *use_node = ast_parse_use(pc, token_index, visib_mod);
if (use_node) {
top_level_decls->append(use_node);
continue;
}
AstNode *struct_node = ast_parse_container_decl(pc, token_index, directives, visib_mod);
AstNode *struct_node = ast_parse_container_decl(pc, token_index, visib_mod);
if (struct_node) {
top_level_decls->append(struct_node);
continue;
}
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false,
directives, visib_mod);
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon);
top_level_decls->append(var_decl_node);
continue;
}
AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, directives, visib_mod);
AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, visib_mod);
if (error_value_node) {
top_level_decls->append(error_value_node);
continue;
}
AstNode *type_decl_node = ast_parse_type_decl(pc, token_index, directives, visib_mod);
AstNode *type_decl_node = ast_parse_type_decl(pc, token_index, visib_mod);
if (type_decl_node) {
top_level_decls->append(type_decl_node);
continue;
}
if (directives->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
return;
}
zig_unreachable();
}
/*
Root : many(TopLevelDecl) token(EOF)
Root = many(TopLevelItem) "EOF"
*/
static AstNode *ast_parse_root(ParseContext *pc, size_t *token_index) {
AstNode *node = ast_create_node(pc, NodeTypeRoot, &pc->tokens->at(*token_index));
@ -2471,7 +2412,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
break;
case NodeTypeFnProto:
visit_field(&node->data.fn_proto.return_type, visit, context);
visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context);
visit_node_list(&node->data.fn_proto.params, visit, context);
break;
case NodeTypeFnDef:
@ -2487,9 +2427,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeBlock:
visit_node_list(&node->data.block.statements, visit, context);
break;
case NodeTypeDirective:
visit_field(&node->data.directive.expr, visit, context);
break;
case NodeTypeReturnExpr:
visit_field(&node->data.return_expr.expr, visit, context);
break;
@ -2497,12 +2434,10 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.defer.expr, visit, context);
break;
case NodeTypeVariableDeclaration:
visit_node_list(node->data.variable_declaration.top_level_decl.directives, visit, context);
visit_field(&node->data.variable_declaration.type, visit, context);
visit_field(&node->data.variable_declaration.expr, visit, context);
break;
case NodeTypeTypeDecl:
visit_node_list(node->data.type_decl.top_level_decl.directives, visit, context);
visit_field(&node->data.type_decl.child_type, visit, context);
break;
case NodeTypeErrorValueDecl:
@ -2550,7 +2485,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
break;
case NodeTypeUse:
visit_field(&node->data.use.expr, visit, context);
visit_node_list(node->data.use.top_level_decl.directives, visit, context);
break;
case NodeTypeBoolLiteral:
// none
@ -2626,11 +2560,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeContainerDecl:
visit_node_list(&node->data.struct_decl.fields, visit, context);
visit_node_list(&node->data.struct_decl.decls, visit, context);
visit_node_list(node->data.struct_decl.top_level_decl.directives, visit, context);
break;
case NodeTypeStructField:
visit_field(&node->data.struct_field.type, visit, context);
visit_node_list(node->data.struct_field.top_level_decl.directives, visit, context);
break;
case NodeTypeContainerInitExpr:
visit_field(&node->data.container_init_expr.type, visit, context);
@ -2688,16 +2620,6 @@ static void clone_subtree_list_omit_inline_params(ZigList<AstNode *> *dest, ZigL
}
}
static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,
uint32_t *next_node_index)
{
if (src) {
ZigList<AstNode *> *dest = allocate<ZigList<AstNode *>>(1);
*dest_ptr = dest;
clone_subtree_list(dest, src, next_node_index);
}
}
static void clone_subtree_field_special(AstNode **dest, AstNode *src, uint32_t *next_node_index,
enum AstCloneSpecial special)
{
@ -2713,10 +2635,6 @@ static void clone_subtree_field(AstNode **dest, AstNode *src, uint32_t *next_nod
return clone_subtree_field_special(dest, src, next_node_index, AstCloneSpecialNone);
}
static void clone_subtree_tld(TopLevelDecl *dest, TopLevelDecl *src, uint32_t *next_node_index) {
clone_subtree_list_ptr(&dest->directives, src->directives, next_node_index);
}
AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, enum AstCloneSpecial special) {
AstNode *new_node = allocate_nonzero<AstNode>(1);
safe_memcpy(new_node, old_node, 1);
@ -2730,8 +2648,6 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
&old_node->data.root.top_level_decls, next_node_index);
break;
case NodeTypeFnProto:
clone_subtree_tld(&new_node->data.fn_proto.top_level_decl, &old_node->data.fn_proto.top_level_decl,
next_node_index);
clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,
next_node_index);
@ -2761,9 +2677,6 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
clone_subtree_list(&new_node->data.block.statements, &old_node->data.block.statements,
next_node_index);
break;
case NodeTypeDirective:
clone_subtree_field(&new_node->data.directive.expr, old_node->data.directive.expr, next_node_index);
break;
case NodeTypeReturnExpr:
clone_subtree_field(&new_node->data.return_expr.expr, old_node->data.return_expr.expr, next_node_index);
break;
@ -2771,14 +2684,10 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
clone_subtree_field(&new_node->data.defer.expr, old_node->data.defer.expr, next_node_index);
break;
case NodeTypeVariableDeclaration:
clone_subtree_list_ptr(&new_node->data.variable_declaration.top_level_decl.directives,
old_node->data.variable_declaration.top_level_decl.directives, next_node_index);
clone_subtree_field(&new_node->data.variable_declaration.type, old_node->data.variable_declaration.type, next_node_index);
clone_subtree_field(&new_node->data.variable_declaration.expr, old_node->data.variable_declaration.expr, next_node_index);
break;
case NodeTypeTypeDecl:
clone_subtree_list_ptr(&new_node->data.type_decl.top_level_decl.directives,
old_node->data.type_decl.top_level_decl.directives, next_node_index);
clone_subtree_field(&new_node->data.type_decl.child_type, old_node->data.type_decl.child_type, next_node_index);
break;
case NodeTypeErrorValueDecl:
@ -2832,8 +2741,6 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
break;
case NodeTypeUse:
clone_subtree_field(&new_node->data.use.expr, old_node->data.use.expr, next_node_index);
clone_subtree_list_ptr(&new_node->data.use.top_level_decl.directives,
old_node->data.use.top_level_decl.directives, next_node_index);
break;
case NodeTypeBoolLiteral:
// none
@ -2908,13 +2815,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
next_node_index);
clone_subtree_list(&new_node->data.struct_decl.decls, &old_node->data.struct_decl.decls,
next_node_index);
clone_subtree_list_ptr(&new_node->data.struct_decl.top_level_decl.directives,
old_node->data.struct_decl.top_level_decl.directives, next_node_index);
break;
case NodeTypeStructField:
clone_subtree_field(&new_node->data.struct_field.type, old_node->data.struct_field.type, next_node_index);
clone_subtree_list_ptr(&new_node->data.struct_field.top_level_decl.directives,
old_node->data.struct_field.top_level_decl.directives, next_node_index);
break;
case NodeTypeContainerInitExpr:
clone_subtree_field(&new_node->data.container_init_expr.type, old_node->data.container_init_expr.type, next_node_index);

View File

@ -109,6 +109,7 @@ struct ZigKeyword {
static const struct ZigKeyword zig_keywords[] = {
{"asm", TokenIdKeywordAsm},
{"break", TokenIdKeywordBreak},
{"coldcc", TokenIdKeywordColdCC},
{"const", TokenIdKeywordConst},
{"continue", TokenIdKeywordContinue},
{"defer", TokenIdKeywordDefer},
@ -123,6 +124,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"goto", TokenIdKeywordGoto},
{"if", TokenIdKeywordIf},
{"inline", TokenIdKeywordInline},
{"nakedcc", TokenIdKeywordNakedCC},
{"noalias", TokenIdKeywordNoAlias},
{"null", TokenIdKeywordNull},
{"pub", TokenIdKeywordPub},
@ -1476,6 +1478,8 @@ const char * token_name(TokenId id) {
case TokenIdKeywordType: return "type";
case TokenIdKeywordInline: return "inline";
case TokenIdKeywordDefer: return "defer";
case TokenIdKeywordColdCC: return "coldcc";
case TokenIdKeywordNakedCC: return "nakedcc";
case TokenIdLParen: return "(";
case TokenIdRParen: return ")";
case TokenIdComma: return ",";

View File

@ -46,6 +46,8 @@ enum TokenId {
TokenIdKeywordInline,
TokenIdKeywordDefer,
TokenIdKeywordThis,
TokenIdKeywordColdCC,
TokenIdKeywordNakedCC,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,

View File

@ -13,9 +13,9 @@ const want_main_symbol = !want_start_symbol;
var argc: usize = undefined;
var argv: &&u8 = undefined;
#attribute("naked")
#condition(want_start_symbol)
export fn _start() -> unreachable {
export nakedcc fn _start() -> unreachable {
@setFnVisible(this, want_start_symbol);
switch (@compileVar("arch")) {
x86_64 => {
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
@ -44,8 +44,9 @@ fn callMainAndExit() -> unreachable {
linux.exit(0);
}
#condition(want_main_symbol)
export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
@setFnVisible(this, want_main_symbol);
argc = usize(c_argc);
argv = c_argv;
callMain() %% return 1;

View File

@ -1,8 +1,9 @@
// These functions are provided when not linking against libc because LLVM
// sometimes generates code that calls them.
#debug_safety(false)
export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
@setDebugSafety(this, false);
var index: usize = 0;
while (index != n) {
dest[index] = c;
@ -11,8 +12,9 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
return dest;
}
#debug_safety(false)
export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) -> &u8 {
@setDebugSafety(this, false);
var index: usize = 0;
while (index != n) {
dest[index] = src[index];

View File

@ -8,18 +8,19 @@ const udwords = [2]su_int;
const low = if (@compileVar("is_big_endian")) 1 else 0;
const high = 1 - low;
#debug_safety(false)
export fn __udivdi3(a: du_int, b: du_int) -> du_int {
@setDebugSafety(this, false);
return __udivmoddi4(a, b, null);
}
#debug_safety(false)
fn du_int_to_udwords(x: du_int) -> udwords {
@setDebugSafety(this, false);
return *(&udwords)(&x);
}
#debug_safety(false)
export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
@setDebugSafety(this, false);
const n_uword_bits = @sizeOf(su_int) * CHAR_BIT;
const n_udword_bits = @sizeOf(du_int) * CHAR_BIT;
var n = du_int_to_udwords(a);
@ -203,15 +204,17 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
return *(&du_int)(&q[0]);
}
#debug_safety(false)
export fn __umoddi3(a: du_int, b: du_int) -> du_int {
@setDebugSafety(this, false);
var r: du_int = undefined;
__udivmoddi4(a, b, &r);
return r;
}
#attribute("test")
fn test_umoddi3() {
@setFnTest(this, true);
test_one_umoddi3(0, 1, 0);
test_one_umoddi3(2, 1, 0);
test_one_umoddi3(0x8000000000000000, 1, 0x0);
@ -224,8 +227,9 @@ fn test_one_umoddi3(a: du_int, b: du_int, expected_r: du_int) {
assert(r == expected_r);
}
#attribute("test")
fn test_udivmoddi4() {
@setFnTest(this, true);
const cases = [][4]du_int {
[]du_int{0x0000000000000000, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000},
[]du_int{0x0000000080000000, 0x0000000100000001, 0x0000000000000000, 0x0000000080000000},

View File

@ -126,8 +126,9 @@ pub struct CBuf {
}
}
#attribute("test")
fn testSimpleCBuf() {
@setFnTest(this, true);
var buf = %%CBuf.initEmpty(&debug.global_allocator);
assert(buf.len() == 0);
%%buf.appendCStr(c"hello");
@ -146,12 +147,14 @@ fn testSimpleCBuf() {
assert(buf.startsWithCBuf(&buf2));
}
#attribute("test")
fn testCompileTimeStrCmp() {
@setFnTest(this, true);
assert(@constEval(cmp(c"aoeu", c"aoez") == -1));
}
#attribute("test")
fn testCompileTimeStrLen() {
@setFnTest(this, true);
assert(@constEval(len(c"123456789") == 9));
}

View File

@ -230,8 +230,9 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
}
}
#attribute("test")
fn basicHashMapTest() {
@setFnTest(this, true);
var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined;
map.init(&debug.global_allocator);
defer map.deinit();

View File

@ -423,8 +423,9 @@ fn bufPrintUnsigned(inline T: type, out_buf: []u8, x: T) -> usize {
return len;
}
#attribute("test")
fn parseU64DigitTooBig() {
@setFnTest(this, true);
parseUnsigned(u64, "123a", 10) %% |err| {
if (err == error.InvalidChar) return;
@unreachable();

View File

@ -49,8 +49,9 @@ pub struct List(T: type) {
}
}
#attribute("test")
fn basicListTest() {
@setFnTest(this, true);
var list = List(i32).init(&debug.global_allocator);
defer list.deinit();

View File

@ -77,8 +77,8 @@ pub fn sliceAsInt(buf: []u8, is_be: bool, inline T: type) -> T {
return result;
}
#attribute("test")
fn testSliceAsInt() {
@setFnTest(this, true);
{
const buf = []u8{0x00, 0x00, 0x12, 0x34};
const answer = sliceAsInt(buf[0...], true, u64);

View File

@ -180,8 +180,9 @@ error Overflow;
error JunkAtEnd;
error Incomplete;
#static_eval_enable(false)
fn parseIp6(buf: []const u8) -> %Address {
@setFnStaticEval(this, false);
var result: Address = undefined;
result.family = linux.AF_INET6;
result.scope_id = 0;
@ -318,8 +319,9 @@ fn parseIp4(buf: []const u8) -> %u32 {
}
#attribute("test")
fn testParseIp4() {
@setFnTest(this, true);
assert(%%parseIp4("127.0.0.1") == endian.swapIfLe(u32, 0x7f000001));
switch (parseIp4("256.0.0.1")) { Overflow => {}, else => @unreachable(), }
switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => @unreachable(), }
@ -328,8 +330,9 @@ fn testParseIp4() {
switch (parseIp4("100..0.1")) { InvalidChar => {}, else => @unreachable(), }
}
#attribute("test")
fn testParseIp6() {
@setFnTest(this, true);
{
const addr = %%parseIp6("FF01:0:0:0:0:0:0:FB");
assert(addr.addr[0] == 0xff);
@ -338,8 +341,9 @@ fn testParseIp6() {
}
}
#attribute("test")
fn testLookupSimpleIp() {
@setFnTest(this, true);
{
var addrs_buf: [5]Address = undefined;
const addrs = %%lookup("192.168.1.1", addrs_buf);

View File

@ -27,8 +27,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
}
}
#attribute("cold")
pub fn abort() -> unreachable {
pub coldcc fn abort() -> unreachable {
switch (@compileVar("os")) {
linux, darwin => {
system.raise(system.SIGABRT);

View File

@ -153,8 +153,9 @@ struct MersenneTwister(
}
}
#attribute("test")
fn testFloat32() {
@setFnTest(this, true);
var r: Rand = undefined;
r.init(42);
@ -165,8 +166,9 @@ fn testFloat32() {
}}
}
#attribute("test")
fn testMT19937_64() {
@setFnTest(this, true);
var rng: MT19937_64 = undefined;
rng.init(rand_test.mt64_seed);
for (rand_test.mt64_data) |value| {
@ -174,8 +176,9 @@ fn testMT19937_64() {
}
}
#attribute("test")
fn testMT19937_32() {
@setFnTest(this, true);
var rng: MT19937_32 = undefined;
rng.init(rand_test.mt32_seed);
for (rand_test.mt32_data) |value| {

View File

@ -12,8 +12,9 @@ pub fn sliceEql(inline T: type, a: []const T, b: []const T) -> bool {
return true;
}
#attribute("test")
fn stringEquality() {
fn testStringEquality() {
@setFnTest(this, true);
assert(eql("abcd", "abcd"));
assert(!eql("abcdef", "abZdef"));
assert(!eql("abcdefg", "abcdef"));

View File

@ -2,8 +2,9 @@ const assert = @import("std").debug.assert;
var argv: &&const u8 = undefined;
#attribute("test")
fn constSliceChild() {
@setFnTest(this, true);
const strs = ([]&const u8) {
c"one",
c"two",
@ -13,16 +14,18 @@ fn constSliceChild() {
bar(strs.len);
}
#static_eval_enable(false)
fn foo(args: [][]const u8) {
@setFnStaticEval(this, false);
assert(args.len == 3);
assert(streql(args[0], "one"));
assert(streql(args[1], "two"));
assert(streql(args[2], "three"));
}
#static_eval_enable(false)
fn bar(argc: usize) {
@setFnStaticEval(this, false);
var args: [argc][]u8 = undefined;
for (args) |_, i| {
const ptr = argv[i];
@ -31,15 +34,17 @@ fn bar(argc: usize) {
foo(args);
}
#static_eval_enable(false)
fn strlen(ptr: &const u8) -> usize {
@setFnStaticEval(this, false);
var count: usize = 0;
while (ptr[count] != 0; count += 1) {}
return count;
}
#static_eval_enable(false)
fn streql(a: []const u8, b: []const u8) -> bool {
@setFnStaticEval(this, false);
if (a.len != b.len) return false;
for (a) |item, index| {
if (b[index] != item) return false;

View File

@ -8,17 +8,24 @@ enum Number {
Four,
}
#attribute("test")
fn enumToInt() {
shouldEqual(Number.Zero, 0);
shouldEqual(Number.One, 1);
shouldEqual(Number.Two, 2);
shouldEqual(Number.Three, 3);
shouldEqual(Number.Four, 4);
@setFnTest(this, true);
shouldEqual(false, Number.Zero, 0);
shouldEqual(false, Number.One, 1);
shouldEqual(false, Number.Two, 2);
shouldEqual(false, Number.Three, 3);
shouldEqual(false, Number.Four, 4);
shouldEqual(true, Number.Zero, 0);
shouldEqual(true, Number.One, 1);
shouldEqual(true, Number.Two, 2);
shouldEqual(true, Number.Three, 3);
shouldEqual(true, Number.Four, 4);
}
// TODO add test with this disabled
#static_eval_enable(false)
fn shouldEqual(n: Number, expected: usize) {
fn shouldEqual(inline static_eval: bool, n: Number, expected: usize) {
@setFnStaticEval(this, static_eval);
assert(usize(n) == expected);
}

View File

@ -15,8 +15,9 @@ enum ET {
}
}
#attribute("test")
fn enumWithMembers() {
@setFnTest(this, true);
const a = ET.SINT { -42 };
const b = ET.UINT { 42 };
var buf: [20]u8 = undefined;

View File

@ -1,7 +1,8 @@
const assert = @import("std").debug.assert;
#attribute("test")
fn maxValueType() {
@setFnTest(this, true);
// If the type of @maxValue(i32) was i32 then this implicit cast to
// u32 would not work. But since the value is a number literal,
// it works fine.

View File

@ -1,15 +1,17 @@
const assert = @import("std").debug.assert;
#attribute("test")
fn maybeReturn() {
@setFnTest(this, true);
assert(??foo(1235));
assert(if (const _ ?= foo(null)) false else true);
assert(!??foo(1234));
}
// TODO add another function with static_eval_enable(true)
#static_eval_enable(false)
// TODO test static eval maybe return
fn foo(x: ?i32) -> ?bool {
@setFnStaticEval(this, false);
const value = ?return x;
return value > 1234;
}

View File

@ -1,7 +1,8 @@
const assert = @import("std").debug.assert;
#attribute("test")
fn namespaceDependsOnCompileVar() {
@setFnTest(this, true);
if (some_namespace.a_bool) {
assert(some_namespace.a_bool);
} else {

View File

@ -1,16 +1,18 @@
const assert = @import("std").debug.assert;
const other = @import("other.zig");
#attribute("test")
fn pubEnum() {
@setFnTest(this, true);
pubEnumTest(other.APubEnum.Two);
}
fn pubEnumTest(foo: other.APubEnum) {
assert(foo == other.APubEnum.Two);
}
#attribute("test")
fn castWithImportedSymbol() {
@setFnTest(this, true);
assert(other.size_t(42) == 42);
}

View File

@ -10,8 +10,9 @@ pub struct SmallList(inline T: type, inline STATIC_SIZE: usize) {
prealloc_items: [STATIC_SIZE]T,
}
#attribute("test")
fn functionWithReturnTypeType() {
@setFnTest(this, true);
var list: List(i32) = undefined;
var list2: List(i32) = undefined;
list.length = 10;

View File

@ -1,7 +1,8 @@
const assert = @import("std").debug.assert;
#attribute("test")
fn sizeofAndTypeOf() {
@setFnTest(this, true);
const y: @typeOf(x) = 120;
assert(@sizeOf(@typeOf(y)) == 2);
}

View File

@ -5,8 +5,9 @@ struct Node {
children: []Node,
}
#attribute("test")
fn structContainsSliceOfItself() {
@setFnTest(this, true);
var nodes = []Node {
Node {
.payload = 1,

View File

@ -14,16 +14,18 @@ enum FormValue {
Other: bool,
}
#static_eval_enable(false)
fn doThing(form_id: u64) -> %FormValue {
@setFnStaticEval(this, false);
return switch (form_id) {
17 => FormValue.Address { %return readOnce() },
else => error.InvalidDebugInfo,
}
}
#attribute("test")
fn switchProngReturnsErrorEnum() {
@setFnTest(this, true);
%%doThing(17);
assert(read_count == 1);
}

View File

@ -7,8 +7,9 @@ enum FormValue {
error Whatever;
#static_eval_enable(false)
fn foo(id: u64) -> %FormValue {
@setFnStaticEval(this, false);
switch (id) {
2 => FormValue.Two { true },
1 => FormValue.One,
@ -16,8 +17,9 @@ fn foo(id: u64) -> %FormValue {
}
}
#attribute("test")
fn switchProngImplicitCast() {
@setFnTest(this, true);
const result = switch (%%foo(2)) {
One => false,
Two => |x| x,

View File

@ -25,13 +25,15 @@ fn factorial(x: i32) -> i32 {
}
}
#attribute("test")
fn thisReferToModuleCallPrivateFn() {
@setFnTest(this, true);
assert(module.add(1, 2) == 3);
}
#attribute("test")
fn thisReferToContainer() {
@setFnTest(this, true);
var pt = Point(i32) {
.x = 12,
.y = 34,
@ -41,7 +43,8 @@ fn thisReferToContainer() {
assert(pt.y == 35);
}
#attribute("test")
fn thisReferToFn() {
@setFnTest(this, true);
assert(factorial(5) == 120);
}

View File

@ -1,7 +1,8 @@
const assert = @import("std").debug.assert;
#attribute("test")
fn varParams() {
@setFnTest(this, true);
assert(max_i32(12, 34) == 34);
assert(max_f64(1.2, 3.4) == 3.4);
@ -21,12 +22,14 @@ fn max_f64(a: f64, b: f64) -> f64 {
max(a, b)
}
#static_eval_enable(false)
fn max_i32_noeval(a: i32, b: i32) -> i32 {
@setFnStaticEval(this, false);
max(a, b)
}
#static_eval_enable(false)
fn max_f64_noeval(a: f64, b: f64) -> f64 {
@setFnStaticEval(this, false);
max(a, b)
}

View File

@ -7,8 +7,9 @@ struct Foo {
d: ?i32,
}
#attribute("test")
fn initializing_a_struct_with_zeroes() {
@setFnTest(this, true);
const foo: Foo = zeroes;
assert(foo.a == 0.0);
assert(foo.b == 0);

View File

@ -279,8 +279,9 @@ pub fn bar_function() {
)SOURCE");
add_source_file(tc, "other.zig", R"SOURCE(
#static_eval_enable(false)
pub fn foo_function() -> bool {
@setFnStaticEval(this, false);
// this one conflicts with the one from foo
return true;
}
@ -686,14 +687,6 @@ fn a() {}
fn a() {}
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
add_compile_fail_case("bad directive", R"SOURCE(
#bogus1("")
extern fn b();
#bogus2("")
fn a() {}
)SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'",
".tmp_source.zig:4:1: error: invalid directive: 'bogus2'");
add_compile_fail_case("unreachable with return", R"SOURCE(
fn a() -> unreachable {return;}
)SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'");
@ -1280,8 +1273,11 @@ struct Foo {
x: i32,
}
const a = get_it();
#static_eval_enable(false)
fn get_it() -> Foo { Foo {.x = 13} }
fn get_it() -> Foo {
@setFnStaticEval(this, false);
Foo {.x = 13}
}
)SOURCE", 1, ".tmp_source.zig:5:17: error: unable to evaluate constant expression");
add_compile_fail_case("undeclared identifier error should mark fn as impure", R"SOURCE(
@ -1316,8 +1312,11 @@ fn foo() {
else => 3,
};
}
#static_eval_enable(false)
fn bar() -> i32 { 2 }
fn bar() -> i32 {
@setFnStaticEval(this, false);
2
}
)SOURCE", 1, ".tmp_source.zig:3:15: error: unable to infer expression type");
add_compile_fail_case("atomic orderings of cmpxchg", R"SOURCE(
@ -1458,7 +1457,6 @@ pub struct SmallList(inline T: type, inline STATIC_SIZE: usize) {
prealloc_items: [STATIC_SIZE]T,
}
#attribute("test")
fn function_with_return_type_type() {
var list: List(i32) = undefined;
list.length = 10;
@ -1623,12 +1621,15 @@ pub fn main(args: [][]u8) -> %void {
const a = []i32{1, 2, 3, 4};
baz(bar(a));
}
#static_eval_enable(false)
fn bar(a: []i32) -> i32 {
@setFnStaticEval(this, false);
a[4]
}
#static_eval_enable(false)
fn baz(a: i32) {}
fn baz(a: i32) {
@setFnStaticEval(this, false);
}
)SOURCE");
add_debug_safety_case("integer addition overflow", R"SOURCE(
@ -1637,8 +1638,9 @@ pub fn main(args: [][]u8) -> %void {
const x = add(65530, 10);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn add(a: u16, b: u16) -> u16 {
@setFnStaticEval(this, false);
a + b
}
)SOURCE");
@ -1649,8 +1651,9 @@ pub fn main(args: [][]u8) -> %void {
const x = sub(10, 20);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn sub(a: u16, b: u16) -> u16 {
@setFnStaticEval(this, false);
a - b
}
)SOURCE");
@ -1661,8 +1664,9 @@ pub fn main(args: [][]u8) -> %void {
const x = mul(300, 6000);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn mul(a: u16, b: u16) -> u16 {
@setFnStaticEval(this, false);
a * b
}
)SOURCE");
@ -1673,8 +1677,9 @@ pub fn main(args: [][]u8) -> %void {
const x = neg(-32768);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn neg(a: i16) -> i16 {
@setFnStaticEval(this, false);
-a
}
)SOURCE");
@ -1685,8 +1690,9 @@ pub fn main(args: [][]u8) -> %void {
const x = shl(-16385, 1);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn shl(a: i16, b: i16) -> i16 {
@setFnStaticEval(this, false);
a << b
}
)SOURCE");
@ -1697,8 +1703,9 @@ pub fn main(args: [][]u8) -> %void {
const x = shl(0b0010111111111111, 3);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn shl(a: u16, b: u16) -> u16 {
@setFnStaticEval(this, false);
a << b
}
)SOURCE");
@ -1708,8 +1715,9 @@ error Whatever;
pub fn main(args: [][]u8) -> %void {
const x = div0(999, 0);
}
#static_eval_enable(false)
fn div0(a: i32, b: i32) -> i32 {
@setFnStaticEval(this, false);
a / b
}
)SOURCE");
@ -1720,8 +1728,9 @@ pub fn main(args: [][]u8) -> %void {
const x = divExact(10, 3);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn divExact(a: i32, b: i32) -> i32 {
@setFnStaticEval(this, false);
@divExact(a, b)
}
)SOURCE");
@ -1732,8 +1741,9 @@ pub fn main(args: [][]u8) -> %void {
const x = widenSlice([]u8{1, 2, 3, 4, 5});
if (x.len == 0) return error.Whatever;
}
#static_eval_enable(false)
fn widenSlice(slice: []u8) -> []i32 {
@setFnStaticEval(this, false);
([]i32)(slice)
}
)SOURCE");
@ -1744,8 +1754,9 @@ pub fn main(args: [][]u8) -> %void {
const x = shorten_cast(200);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn shorten_cast(x: i32) -> i8 {
@setFnStaticEval(this, false);
i8(x)
}
)SOURCE");
@ -1756,8 +1767,9 @@ pub fn main(args: [][]u8) -> %void {
const x = unsigned_cast(-10);
if (x == 0) return error.Whatever;
}
#static_eval_enable(false)
fn unsigned_cast(x: i32) -> u32 {
@setFnStaticEval(this, false);
u32(x)
}
)SOURCE");

File diff suppressed because it is too large Load Diff