diff --git a/doc/langref.md b/doc/langref.md index b982ec0197213cd4abfb4bc999e5ff3a233146d6..7cb02eef6dc91742d66c858e69d21f76f388737c 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -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" diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index 02eacef28ce8bc1f08519108177b0ddeda80af3c..119d33bc4f184c70c06603f99aabef538cb65c34 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -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 diff --git a/src/all_types.hpp b/src/all_types.hpp index d1826299e4ca12703642c540c3d59a84f2c7720c..0f67f371ea8c4d6e61d09cfdb11adaf8143a4864 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -129,7 +129,6 @@ enum TldResolution { struct TopLevelDecl { // populated by parser Buf *name; - ZigList *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 cast_alloca_list; ZigList struct_val_expr_alloca_list; ZigList 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 { diff --git a/src/analyze.cpp b/src/analyze.cpp index 93786ed15aec7b75abc55af8ac08c9436e4a5302..21f82c68ec57a49bb1625ab6e3049faa48bf1d87 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 81429586b5fe50d70c51b6687eaac376d7345c17..1a8463e85d04508e98c33219cfdb0b339578cc6a 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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 *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); diff --git a/src/codegen.cpp b/src/codegen.cpp index 956b5be0a6a9d33c13fdb419ba64f3659fe05a1b..296a9998c49098e207b12560d3d605fc3998fda6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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) { diff --git a/src/eval.cpp b/src/eval.cpp index 3677a14f6ab31cd85560ec432faec4c47b0e9136..b74fb38af9e38aad36c07e96247dcbc3cc1b17e1 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -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(); } diff --git a/src/parseh.cpp b/src/parseh.cpp index 307129d4a0a399932254c223f6829cc9880cf6a5..1a581f3a23d16f9b632a5267e7f4d21e3542a85a 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -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; diff --git a/src/parser.cpp b/src/parser.cpp index 52d3a855d0fd397d66c997d94af39fb5c741f6e3..6ab0024433c9f07928261a751f4685ebabe668db 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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 *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 *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 *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 *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 *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 *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 *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 *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 *directive_list = allocate>(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 *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 *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 *top_level_decls) { for (;;) { - Token *directive_token = &pc->tokens->at(*token_index); - ZigList *directives = allocate>(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 *dest, ZigL } } -static void clone_subtree_list_ptr(ZigList **dest_ptr, ZigList *src, - uint32_t *next_node_index) -{ - if (src) { - ZigList *dest = allocate>(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(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); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 62c4ea1f4c27225fc96e9bb24ab22334acd57ddb..3af876d074e0201f6c3d57ca9008d9fdb6031692 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -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 ","; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index f67828b7cca9ffa83cb67b56dc5ded22588a1a2c..48f41b6ea7878ad5e4b107e85e61b4207c181bbd 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -46,6 +46,8 @@ enum TokenId { TokenIdKeywordInline, TokenIdKeywordDefer, TokenIdKeywordThis, + TokenIdKeywordColdCC, + TokenIdKeywordNakedCC, TokenIdLParen, TokenIdRParen, TokenIdComma, diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 2a2d1148dd2f4d265429985547edaa793dfead7a..adb263ede654fc278dd22fceb6126a0c75cfb523 100644 --- a/std/bootstrap.zig +++ b/std/bootstrap.zig @@ -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; diff --git a/std/builtin.zig b/std/builtin.zig index cc4cbbcafcd7aeb28b64f17b203902dcfb66596c..5fe596eb331bb94bad8ee1582a3637c984247f1e 100644 --- a/std/builtin.zig +++ b/std/builtin.zig @@ -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]; diff --git a/std/compiler_rt.zig b/std/compiler_rt.zig index a227d45a430c25735a4e9f1e00d118168b73e4b5..b27da3b3de2c92a40439538d51078dc8aa7b8b0f 100644 --- a/std/compiler_rt.zig +++ b/std/compiler_rt.zig @@ -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}, diff --git a/std/cstr.zig b/std/cstr.zig index e5035aec4baa7ff90d5857e869cf59534341c86b..afe8d5b40400de5a356b8c2b61f1542859e86d60 100644 --- a/std/cstr.zig +++ b/std/cstr.zig @@ -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)); } diff --git a/std/hash_map.zig b/std/hash_map.zig index c20d78c202ed40e9cc41c73266110f560aac57bb..14289542208d31226eb0849f47aa79783d07097d 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -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(); diff --git a/std/io.zig b/std/io.zig index 938368c585999edb46f36adeaf001548c5f9fd62..be8702f44a292bc2bbe3d456cedd59aa1eaf5d72 100644 --- a/std/io.zig +++ b/std/io.zig @@ -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(); diff --git a/std/list.zig b/std/list.zig index 36c682cc1c44a6e2c23aa16c4a02d35103748cda..0c5bf92da6486eb42f0c26212246ad751f2cd00d 100644 --- a/std/list.zig +++ b/std/list.zig @@ -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(); diff --git a/std/mem.zig b/std/mem.zig index e4eb94f8da74ab9ab37b212188ca4d093e04d0a0..ba65679c73a59bb3507f8a444e8e31073ace2365 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -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); diff --git a/std/net.zig b/std/net.zig index 3c943091b26a94c4a273ba909be18ad768bffaef..2b52e8bf9779dc8cbcf772f6f6d43b965994e585 100644 --- a/std/net.zig +++ b/std/net.zig @@ -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); diff --git a/std/os.zig b/std/os.zig index 806cc43f33a6d364d07ee6ebceaad70fe87a68a9..8def16601d58276dd84366ab829150f550305cc6 100644 --- a/std/os.zig +++ b/std/os.zig @@ -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); diff --git a/std/rand.zig b/std/rand.zig index 15cf9626b7e747213bbb995e63734296d73c906b..16af7c490d5392a24aec26b094015f5f787de9ed 100644 --- a/std/rand.zig +++ b/std/rand.zig @@ -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| { diff --git a/std/str.zig b/std/str.zig index e72a042e3fe9bdf0540a8ce026b4da094fbc6014..ced98a46ea2418f5d2b3b99b14c1ac800c0ec061 100644 --- a/std/str.zig +++ b/std/str.zig @@ -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")); diff --git a/test/cases/const_slice_child.zig b/test/cases/const_slice_child.zig index 97b37028d15238e69351bdf3ca2c9fc0c50764d6..bd22ca6da8e2a43d2b5a81a4cdbbc5ba3ea49147 100644 --- a/test/cases/const_slice_child.zig +++ b/test/cases/const_slice_child.zig @@ -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; diff --git a/test/cases/enum_to_int.zig b/test/cases/enum_to_int.zig index 54994754dd9758cf76143dc80b32b408d1c3447b..0be2c32a459374cc7516fd3f4e58a8841da6fcc5 100644 --- a/test/cases/enum_to_int.zig +++ b/test/cases/enum_to_int.zig @@ -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); } diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig index cff5883b19cc12d33c628609d33a606347d21475..4f26c9f258d6c03eb04cda9771d54098a4c50c48 100644 --- a/test/cases/enum_with_members.zig +++ b/test/cases/enum_with_members.zig @@ -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; diff --git a/test/cases/max_value_type.zig b/test/cases/max_value_type.zig index 62b950831869c24ec84b8017d3de923b8267a03b..e93ce5eb84654cf5effe731364f71ed2efd0ed29 100644 --- a/test/cases/max_value_type.zig +++ b/test/cases/max_value_type.zig @@ -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. diff --git a/test/cases/maybe_return.zig b/test/cases/maybe_return.zig index e779c1c50b650120c7a338a772e45a207559d896..0caa5bdb0bd8cefcd5ac83f06102e8441850a368 100644 --- a/test/cases/maybe_return.zig +++ b/test/cases/maybe_return.zig @@ -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; } diff --git a/test/cases/namespace_depends_on_compile_var/index.zig b/test/cases/namespace_depends_on_compile_var/index.zig index d6c7313e880ef672a098aa01eb03a67706edbf47..3fdc207cb99ae9ac4e4f66e5fd5d374838a57070 100644 --- a/test/cases/namespace_depends_on_compile_var/index.zig +++ b/test/cases/namespace_depends_on_compile_var/index.zig @@ -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 { diff --git a/test/cases/pub_enum/index.zig b/test/cases/pub_enum/index.zig index 7767c940025f998ab1920d88dedc13373b597acc..72ace5a1173551618333682581211dbb28bfdb54 100644 --- a/test/cases/pub_enum/index.zig +++ b/test/cases/pub_enum/index.zig @@ -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); } diff --git a/test/cases/return_type_type.zig b/test/cases/return_type_type.zig index 4337c072b2c8c6f8105a4224df5acd36d645fe78..24b7a06500f96540eba32afa60f0969d2ea9ed25 100644 --- a/test/cases/return_type_type.zig +++ b/test/cases/return_type_type.zig @@ -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; diff --git a/test/cases/sizeof_and_typeof.zig b/test/cases/sizeof_and_typeof.zig index 097307518058f3f8275dc8fbdac4468bcd79997f..9711718e8b7f1758bab4af230b3b2a4de57c34b0 100644 --- a/test/cases/sizeof_and_typeof.zig +++ b/test/cases/sizeof_and_typeof.zig @@ -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); } diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig index 24b5c92116aeb7b440928e0827e8824afb0838ab..2a8fc52deda05d09fea07e3ae297127b4e339a8d 100644 --- a/test/cases/struct_contains_slice_of_itself.zig +++ b/test/cases/struct_contains_slice_of_itself.zig @@ -5,8 +5,9 @@ struct Node { children: []Node, } -#attribute("test") fn structContainsSliceOfItself() { + @setFnTest(this, true); + var nodes = []Node { Node { .payload = 1, diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig index cb8c864357a90860278dfe697f2940cefcd933a2..fb7b2e2832f2a609dd0aec98c727e0699725392a 100644 --- a/test/cases/switch_prong_err_enum.zig +++ b/test/cases/switch_prong_err_enum.zig @@ -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); } diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/cases/switch_prong_implicit_cast.zig index ad37761f458c80129911567ed3099280bf3bd8d3..cc447660dab6d61b74d83af9af68cf7b00f7d80d 100644 --- a/test/cases/switch_prong_implicit_cast.zig +++ b/test/cases/switch_prong_implicit_cast.zig @@ -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, diff --git a/test/cases/this.zig b/test/cases/this.zig index deac9c26e81a156ee77ff95ad20d20e0c0e9d1a2..f7197290f2c70ab458a0e62012165b77ba4d57cc 100644 --- a/test/cases/this.zig +++ b/test/cases/this.zig @@ -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); } diff --git a/test/cases/var_params.zig b/test/cases/var_params.zig index 66cf4da8b79dc1a491495e00880fd008fdf7c9be..8db3b3e33198c03a34c5717acf0acb109e0adae0 100644 --- a/test/cases/var_params.zig +++ b/test/cases/var_params.zig @@ -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) } diff --git a/test/cases/zeroes.zig b/test/cases/zeroes.zig index 94774e434d41500d0d9ad2f2caf021fb325d7c18..c30b01d4aff32a48c8d169afccc73e8acc904b3b 100644 --- a/test/cases/zeroes.zig +++ b/test/cases/zeroes.zig @@ -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); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 4b03efc7d6a59eb83fe9bfbdab6647e04b1b9dd3..564381cd1a2f6e6cf047ccfdd3756cb5284edccc 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -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"); diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 777de7f29e55050e894d05ea64a62f3d1af413ae..d85f50c5644abe5688bcd3a272bf82f934a9865e 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -19,12 +19,15 @@ const test_this = @import("cases/this.zig"); // normal comment /// this is a documentation comment /// doc comment line 2 -#attribute("test") -fn emptyFunctionWithComments() {} +fn emptyFunctionWithComments() { + @setFnTest(this, true); +} + -#attribute("test") fn ifStatements() { + @setFnTest(this, true); + shouldBeEqual(1, 1); firstEqlThird(2, 1, 2); } @@ -48,8 +51,9 @@ fn firstEqlThird(a: i32, b: i32, c: i32) { } -#attribute("test") fn params() { + @setFnTest(this, true); + assert(testParamsAdd(22, 11) == 33); } fn testParamsAdd(a: i32, b: i32) -> i32 { @@ -57,8 +61,9 @@ fn testParamsAdd(a: i32, b: i32) -> i32 { } -#attribute("test") fn localVariables() { + @setFnTest(this, true); + testLocVars(2); } fn testLocVars(b: i32) { @@ -66,14 +71,16 @@ fn testLocVars(b: i32) { if (a + b != 3) @unreachable(); } -#attribute("test") fn boolLiterals() { + @setFnTest(this, true); + assert(true); assert(!false); } -#attribute("test") fn voidParameters() { + @setFnTest(this, true); + voidFun(1, void{}, 2, {}); } fn voidFun(a : i32, b : void, c : i32, d : void) { @@ -83,8 +90,9 @@ fn voidFun(a : i32, b : void, c : i32, d : void) { return vv; } -#attribute("test") fn mutableLocalVariables() { + @setFnTest(this, true); + var zero : i32 = 0; assert(zero == 0); @@ -95,8 +103,9 @@ fn mutableLocalVariables() { assert(i == 3); } -#attribute("test") fn arrays() { + @setFnTest(this, true); + var array : [5]u32 = undefined; var i : u32 = 0; @@ -120,8 +129,9 @@ fn getArrayLen(a: []u32) -> usize { a.len } -#attribute("test") fn shortCircuit() { + @setFnTest(this, true); + var hit_1 = false; var hit_2 = false; var hit_3 = false; @@ -148,13 +158,15 @@ fn shortCircuit() { assert(hit_4); } -#static_eval_enable(false) fn assertRuntime(b: bool) { + @setFnStaticEval(this, false); + if (!b) @unreachable() } -#attribute("test") fn modifyOperators() { + @setFnTest(this, true); + var i : i32 = 0; i += 5; assert(i == 5); i -= 2; assert(i == 3); @@ -171,8 +183,9 @@ fn modifyOperators() { } -#attribute("test") fn separateBlockScopes() { + @setFnTest(this, true); + { const no_conflict : i32 = 5; assert(no_conflict == 5); @@ -186,8 +199,9 @@ fn separateBlockScopes() { } -#attribute("test") fn voidStructFields() { + @setFnTest(this, true); + const foo = VoidStructFieldsFoo { .a = void{}, .b = 1, @@ -204,8 +218,9 @@ struct VoidStructFieldsFoo { -#attribute("test") pub fn structs() { + @setFnTest(this, true); + var foo : StructFoo = undefined; @memset(&foo, 0, @sizeOf(StructFoo)); foo.a += 1; @@ -234,8 +249,9 @@ struct Val { x: i32, } -#attribute("test") fn structPointToSelf() { + @setFnTest(this, true); + var root : Node = undefined; root.val.x = 1; @@ -248,8 +264,9 @@ fn structPointToSelf() { assert(node.next.next.next.val.x == 1); } -#attribute("test") fn structByvalAssign() { + @setFnTest(this, true); + var foo1 : StructFoo = undefined; var foo2 : StructFoo = undefined; @@ -269,16 +286,18 @@ fn structInitializer() { const g1 : i32 = 1233 + 1; var g2 : i32 = 0; -#attribute("test") fn globalVariables() { + @setFnTest(this, true); + assert(g2 == 0); g2 = g1; assert(g2 == 1234); } -#attribute("test") fn whileLoop() { + @setFnTest(this, true); + var i : i32 = 0; while (i < 4) { i += 1; @@ -295,8 +314,9 @@ fn whileLoop2() -> i32 { } } -#attribute("test") fn voidArrays() { + @setFnTest(this, true); + var array: [4]void = undefined; array[0] = void{}; array[1] = array[2]; @@ -305,8 +325,9 @@ fn voidArrays() { } -#attribute("test") fn threeExprInARow() { + @setFnTest(this, true); + assertFalse(false || false || false); assertFalse(true && true && false); assertFalse(1 | 2 | 4 != 7); @@ -325,8 +346,9 @@ fn assertFalse(b: bool) { } -#attribute("test") fn maybeType() { + @setFnTest(this, true); + const x : ?bool = true; if (const y ?= x) { @@ -353,8 +375,9 @@ fn maybeType() { } -#attribute("test") fn enumType() { + @setFnTest(this, true); + const foo1 = EnumTypeFoo.One {13}; const foo2 = EnumTypeFoo.Two {EnumType { .x = 1234, .y = 5678, }}; const bar = EnumTypeBar.B; @@ -387,8 +410,9 @@ enum EnumTypeBar { } -#attribute("test") fn arrayLiteral() { + @setFnTest(this, true); + const hex_mult = []u16{4096, 256, 16, 1}; assert(hex_mult.len == 4); @@ -396,8 +420,9 @@ fn arrayLiteral() { } -#attribute("test") fn constNumberLiteral() { + @setFnTest(this, true); + const one = 1; const eleven = ten + one; @@ -406,8 +431,9 @@ fn constNumberLiteral() { const ten = 10; -#attribute("test") fn errorValues() { + @setFnTest(this, true); + const a = i32(error.err1); const b = i32(error.err2); assert(a != b); @@ -417,8 +443,9 @@ error err2; -#attribute("test") fn fnCallOfStructField() { + @setFnTest(this, true); + assert(callStructField(Foo {.ptr = aFunc,}) == 13); } @@ -434,8 +461,9 @@ fn callStructField(foo: Foo) -> i32 { -#attribute("test") fn redefinitionOfErrorValuesAllowed() { + @setFnTest(this, true); + shouldBeNotEqual(error.AnError, error.SecondError); } error AnError; @@ -448,8 +476,9 @@ fn shouldBeNotEqual(a: error, b: error) { -#attribute("test") fn constantEnumWithPayload() { + @setFnTest(this, true); + var empty = AnEnumWithPayload.Empty; var full = AnEnumWithPayload.Full {13}; shouldBeEmpty(empty); @@ -476,8 +505,9 @@ enum AnEnumWithPayload { } -#attribute("test") fn continueInForLoop() { + @setFnTest(this, true); + const array = []i32 {1, 2, 3, 4, 5}; var sum : i32 = 0; for (array) |x| { @@ -491,8 +521,9 @@ fn continueInForLoop() { } -#attribute("test") fn castBoolToInt() { + @setFnTest(this, true); + const t = true; const f = false; assert(i32(t) == i32(1)); @@ -506,8 +537,9 @@ fn nonConstCastBoolToInt(t: bool, f: bool) { } -#attribute("test") fn switchOnEnum() { + @setFnTest(this, true); + const fruit = Fruit.Orange; nonConstSwitchOnEnum(fruit); } @@ -516,8 +548,9 @@ enum Fruit { Orange, Banana, } -#static_eval_enable(false) fn nonConstSwitchOnEnum(fruit: Fruit) { + @setFnStaticEval(this, false); + switch (fruit) { Apple => @unreachable(), Orange => {}, @@ -525,12 +558,14 @@ fn nonConstSwitchOnEnum(fruit: Fruit) { } } -#attribute("test") fn switchStatement() { + @setFnTest(this, true); + nonConstSwitch(SwitchStatmentFoo.C); } -#static_eval_enable(false) fn nonConstSwitch(foo: SwitchStatmentFoo) { + @setFnStaticEval(this, false); + const val: i32 = switch (foo) { A => 1, B => 2, @@ -547,8 +582,9 @@ enum SwitchStatmentFoo { } -#attribute("test") fn switchProngWithVar() { + @setFnTest(this, true); + switchProngWithVarFn(SwitchProngWithVarEnum.One {13}); switchProngWithVarFn(SwitchProngWithVarEnum.Two {13.0}); switchProngWithVarFn(SwitchProngWithVarEnum.Meh); @@ -558,8 +594,9 @@ enum SwitchProngWithVarEnum { Two: f32, Meh, } -#static_eval_enable(false) fn switchProngWithVarFn(a: SwitchProngWithVarEnum) { + @setFnStaticEval(this, false); + switch(a) { One => |x| { if (x != 13) @unreachable(); @@ -574,13 +611,15 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) { } -#attribute("test") fn errReturnInAssignment() { + @setFnTest(this, true); + %%doErrReturnInAssignment(); } -#static_eval_enable(false) fn doErrReturnInAssignment() -> %void { + @setFnStaticEval(this, false); + var x : i32 = undefined; x = %return makeANonErr(); } @@ -591,15 +630,17 @@ fn makeANonErr() -> %i32 { -#attribute("test") fn rhsMaybeUnwrapReturn() { + @setFnTest(this, true); + const x = ?true; const y = x ?? return; } -#attribute("test") fn implicitCastFnUnreachableReturn() { + @setFnTest(this, true); + wantsFnWithVoid(fnWithUnreachable); } @@ -610,15 +651,17 @@ fn fnWithUnreachable() -> unreachable { } -#attribute("test") fn explicitCastMaybePointers() { + @setFnTest(this, true); + const a: ?&i32 = undefined; const b: ?&f32 = (?&f32)(a); } -#attribute("test") fn constExprEvalOnSingleExprBlocks() { + @setFnTest(this, true); + assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3); } @@ -635,14 +678,16 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 { } -#attribute("test") fn builtinConstEval() { + @setFnTest(this, true); + const x : i32 = @constEval(1 + 2 + 3); assert(x == @constEval(6)); } -#attribute("test") fn slicing() { + @setFnTest(this, true); + var array : [20]i32 = undefined; array[5] = 1234; @@ -659,8 +704,9 @@ fn slicing() { } -#attribute("test") fn memcpyAndMemsetIntrinsics() { + @setFnTest(this, true); + var foo : [20]u8 = undefined; var bar : [20]u8 = undefined; @@ -671,31 +717,36 @@ fn memcpyAndMemsetIntrinsics() { } -#attribute("test") -fn arrayDotLenConstExpr() { } +fn arrayDotLenConstExpr() { + @setFnTest(this, true); +} + struct ArrayDotLenConstExpr { y: [@constEval(some_array.len)]u8, } const some_array = []u8 {0, 1, 2, 3}; -#attribute("test") fn countLeadingZeroes() { + @setFnTest(this, true); + assert(@clz(u8, 0b00001010) == 4); assert(@clz(u8, 0b10001010) == 0); assert(@clz(u8, 0b00000000) == 8); } -#attribute("test") fn countTrailingZeroes() { + @setFnTest(this, true); + assert(@ctz(u8, 0b10100000) == 5); assert(@ctz(u8, 0b10001010) == 1); assert(@ctz(u8, 0b00000000) == 8); } -#attribute("test") fn multilineString() { + @setFnTest(this, true); + const s1 = \\one \\two) @@ -705,8 +756,9 @@ fn multilineString() { assert(str.eql(s1, s2)); } -#attribute("test") fn multilineCString() { + @setFnTest(this, true); + const s1 = c\\one c\\two) @@ -718,8 +770,9 @@ fn multilineCString() { -#attribute("test") fn simpleGenericFn() { + @setFnTest(this, true); + assert(max(i32, 3, -1) == 3); assert(max(f32, 0.123, 0.456) == 0.456); assert(add(2, 3) == 5); @@ -734,8 +787,9 @@ fn add(inline a: i32, b: i32) -> i32 { } -#attribute("test") fn constantEqualFunctionPointers() { + @setFnTest(this, true); + const alias = emptyFn; assert(@constEval(emptyFn == alias)); } @@ -743,44 +797,50 @@ fn constantEqualFunctionPointers() { fn emptyFn() {} -#attribute("test") fn genericMallocFree() { + @setFnTest(this, true); + const a = %%memAlloc(u8, 10); memFree(u8, a); } const some_mem : [100]u8 = undefined; -#static_eval_enable(false) fn memAlloc(inline T: type, n: usize) -> %[]T { + @setFnStaticEval(this, false); + return (&T)(&some_mem[0])[0...n]; } fn memFree(inline T: type, mem: []T) { } -#attribute("test") fn callFnWithEmptyString() { + @setFnTest(this, true); + acceptsString(""); } fn acceptsString(foo: []u8) { } -#attribute("test") fn hexEscape() { + @setFnTest(this, true); + assert(str.eql("\x68\x65\x6c\x6c\x6f", "hello")); } error AnError; error ALongerErrorName; -#attribute("test") fn errorNameString() { + @setFnTest(this, true); + assert(str.eql(@errorName(error.AnError), "AnError")); assert(str.eql(@errorName(error.ALongerErrorName), "ALongerErrorName")); } -#attribute("test") fn gotoAndLabels() { + @setFnTest(this, true); + gotoLoop(); assert(goto_counter == 10); } @@ -799,12 +859,14 @@ var goto_counter: i32 = 0; -#attribute("test") fn gotoLeaveDeferScope() { + @setFnTest(this, true); + testGotoLeaveDeferScope(true); } -#static_eval_enable(false) fn testGotoLeaveDeferScope(b: bool) { + @setFnStaticEval(this, false); + var it_worked = false; goto entry; @@ -819,8 +881,9 @@ entry: } -#attribute("test") fn castUndefined() { + @setFnTest(this, true); + const array: [100]u8 = undefined; const slice = ([]u8)(array); testCastUndefined(slice); @@ -828,8 +891,9 @@ fn castUndefined() { fn testCastUndefined(x: []u8) {} -#attribute("test") fn castSmallUnsignedToLargerSigned() { + @setFnTest(this, true); + assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); } @@ -837,8 +901,9 @@ fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x } fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x } -#attribute("test") fn implicitCastAfterUnreachable() { + @setFnTest(this, true); + assert(outer() == 1234); } fn inner() -> i32 { 1234 } @@ -847,8 +912,9 @@ fn outer() -> i64 { } -#attribute("test") fn elseIfExpression() { + @setFnTest(this, true); + assert(elseIfExpressionF(1) == 1); } fn elseIfExpressionF(c: u8) -> u8 { @@ -861,8 +927,9 @@ fn elseIfExpressionF(c: u8) -> u8 { } } -#attribute("test") fn errBinaryOperator() { + @setFnTest(this, true); + const a = errBinaryOperatorG(true) %% 3; const b = errBinaryOperatorG(false) %% 3; assert(a == 3); @@ -877,16 +944,18 @@ fn errBinaryOperatorG(x: bool) -> %isize { } } -#attribute("test") fn unwrapSimpleValueFromError() { + @setFnTest(this, true); + const i = %%unwrapSimpleValueFromErrorDo(); assert(i == 13); } fn unwrapSimpleValueFromErrorDo() -> %isize { 13 } -#attribute("test") fn storeMemberFunctionInVariable() { + @setFnTest(this, true); + const instance = MemberFnTestFoo { .x = 1234, }; const memberFn = MemberFnTestFoo.member; const result = memberFn(instance); @@ -897,15 +966,17 @@ struct MemberFnTestFoo { fn member(foo: MemberFnTestFoo) -> i32 { foo.x } } -#attribute("test") fn callMemberFunctionDirectly() { + @setFnTest(this, true); + const instance = MemberFnTestFoo { .x = 1234, }; const result = MemberFnTestFoo.member(instance); assert(result == 1234); } -#attribute("test") fn memberFunctions() { + @setFnTest(this, true); + const r = MemberFnRand {.seed = 1234}; assert(r.getSeed() == 1234); } @@ -916,16 +987,18 @@ struct MemberFnRand { } } -#attribute("test") fn staticFunctionEvaluation() { + @setFnTest(this, true); + assert(statically_added_number == 3); } const statically_added_number = staticAdd(1, 2); fn staticAdd(a: i32, b: i32) -> i32 { a + b } -#attribute("test") fn staticallyInitalizedList() { + @setFnTest(this, true); + assert(static_point_list[0].x == 1); assert(static_point_list[0].y == 2); assert(static_point_list[1].x == 3); @@ -944,8 +1017,9 @@ fn makePoint(x: i32, y: i32) -> Point { } -#attribute("test") fn staticEvalRecursive() { + @setFnTest(this, true); + assert(some_data.len == 21); } var some_data: [usize(fibbonaci(7))]u8 = undefined; @@ -954,8 +1028,9 @@ fn fibbonaci(x: i32) -> i32 { return fibbonaci(x - 1) + fibbonaci(x - 2); } -#attribute("test") fn staticEvalWhile() { + @setFnTest(this, true); + assert(static_eval_while_number == 1); } const static_eval_while_number = staticWhileLoop1(); @@ -968,8 +1043,9 @@ fn staticWhileLoop2() -> i32 { } } -#attribute("test") fn staticEvalListInit() { + @setFnTest(this, true); + assert(static_vec3.data[2] == 1.0); } const static_vec3 = vec3(0.0, 0.0, 1.0); @@ -983,8 +1059,9 @@ pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { } -#attribute("test") fn genericFnWithImplicitCast() { + @setFnTest(this, true); + assert(getFirstByte(u8, []u8 {13}) == 13); assert(getFirstByte(u16, []u16 {0, 13}) == 0); } @@ -993,8 +1070,9 @@ fn getFirstByte(inline T: type, mem: []T) -> u8 { getByte((&u8)(&mem[0])) } -#attribute("test") fn continueAndBreak() { + @setFnTest(this, true); + runContinueAndBreakTest(); assert(continue_and_break_counter == 8); } @@ -1013,8 +1091,9 @@ fn runContinueAndBreakTest() { } -#attribute("test") fn pointerDereferencing() { + @setFnTest(this, true); + var x = i32(3); const y = &x; @@ -1024,16 +1103,18 @@ fn pointerDereferencing() { assert(*y == 4); } -#attribute("test") fn constantExpressions() { + @setFnTest(this, true); + var array : [array_size]u8 = undefined; assert(@sizeOf(@typeOf(array)) == 20); } const array_size : u8 = 20; -#attribute("test") fn minValueAndMaxValue() { + @setFnTest(this, true); + assert(@maxValue(u8) == 255); assert(@maxValue(u16) == 65535); assert(@maxValue(u32) == 4294967295); @@ -1055,8 +1136,9 @@ fn minValueAndMaxValue() { assert(@minValue(i64) == -9223372036854775808); } -#attribute("test") fn overflowIntrinsics() { + @setFnTest(this, true); + var result: u8 = undefined; assert(@addWithOverflow(u8, 250, 100, &result)); assert(!@addWithOverflow(u8, 100, 150, &result)); @@ -1064,8 +1146,9 @@ fn overflowIntrinsics() { } -#attribute("test") fn nestedArrays() { + @setFnTest(this, true); + const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"}; for (array_of_strings) |s, i| { if (i == 0) assert(str.eql(s, "hello")); @@ -1076,21 +1159,24 @@ fn nestedArrays() { } } -#attribute("test") fn intToPtrCast() { + @setFnTest(this, true); + const x = isize(13); const y = (&u8)(x); const z = usize(y); assert(z == 13); } -#attribute("test") fn stringConcatenation() { + @setFnTest(this, true); + assert(str.eql("OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); } -#attribute("test") fn constantStructWithNegation() { + @setFnTest(this, true); + assert(vertices[0].x == -0.6); } struct Vertex { @@ -1107,8 +1193,9 @@ const vertices = []Vertex { }; -#attribute("test") fn returnWithImplicitCastFromWhileLoop() { + @setFnTest(this, true); + %%returnWithImplicitCastFromWhileLoopTest(); } fn returnWithImplicitCastFromWhileLoopTest() -> %void { @@ -1117,8 +1204,9 @@ fn returnWithImplicitCastFromWhileLoopTest() -> %void { } } -#attribute("test") fn returnStructByvalFromFunction() { + @setFnTest(this, true); + const bar = makeBar(1234, 5678); assert(bar.y == 5678); } @@ -1133,8 +1221,9 @@ fn makeBar(x: i32, y: i32) -> Bar { } } -#attribute("test") fn functionPointers() { + @setFnTest(this, true); + const fns = []@typeOf(fn1) { fn1, fn2, fn3, fn4, }; for (fns) |f, i| { assert(f() == u32(i) + 5); @@ -1147,8 +1236,9 @@ fn fn4() -> u32 {8} -#attribute("test") fn staticallyInitalizedStruct() { + @setFnTest(this, true); + st_init_str_foo.x += 1; assert(st_init_str_foo.x == 14); } @@ -1158,8 +1248,9 @@ struct StInitStrFoo { } var st_init_str_foo = StInitStrFoo { .x = 13, .y = true, }; -#attribute("test") fn staticallyInitializedArrayLiteral() { + @setFnTest(this, true); + const y : [4]u8 = st_init_arr_lit_x; assert(y[3] == 4); } @@ -1167,8 +1258,9 @@ const st_init_arr_lit_x = []u8{1,2,3,4}; -#attribute("test") fn pointerToVoidReturnType() { + @setFnTest(this, true); + %%testPointerToVoidReturnType(); } fn testPointerToVoidReturnType() -> %void { @@ -1181,8 +1273,9 @@ fn testPointerToVoidReturnType2() -> &void { } -#attribute("test") fn callResultOfIfElseExpression() { + @setFnTest(this, true); + assert(str.eql(f2(true), "a")); assert(str.eql(f2(false), "b")); } @@ -1193,8 +1286,9 @@ fn fA() -> []u8 { "a" } fn fB() -> []u8 { "b" } -#attribute("test") fn constExpressionEvalHandlingOfVariables() { + @setFnTest(this, true); + var x = true; while (x) { x = false; @@ -1203,8 +1297,9 @@ fn constExpressionEvalHandlingOfVariables() { -#attribute("test") fn constantEnumInitializationWithDifferingSizes() { + @setFnTest(this, true); + test3_1(test3_foo); test3_2(test3_bar); } @@ -1219,8 +1314,9 @@ struct Test3Point { } const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}}; const test3_bar = Test3Foo.Two{13}; -#static_eval_enable(false) fn test3_1(f: Test3Foo) { + @setFnStaticEval(this, false); + switch (f) { Three => |pt| { assert(pt.x == 3); @@ -1229,8 +1325,9 @@ fn test3_1(f: Test3Foo) { else => @unreachable(), } } -#static_eval_enable(false) fn test3_2(f: Test3Foo) { + @setFnStaticEval(this, false); + switch (f) { Two => |x| { assert(x == 13); @@ -1241,8 +1338,9 @@ fn test3_2(f: Test3Foo) { -#attribute("test") fn whileWithContinueExpr() { + @setFnTest(this, true); + var sum: i32 = 0; {var i: i32 = 0; while (i < 10; i += 1) { if (i == 5) continue; @@ -1252,38 +1350,47 @@ fn whileWithContinueExpr() { } -#attribute("test") fn forLoopWithPointerElemVar() { + @setFnTest(this, true); + const source = "abcdefg"; var target: [source.len]u8 = undefined; @memcpy(&target[0], &source[0], source.len); mangleString(target); assert(str.eql(target, "bcdefgh")); } -#static_eval_enable(false) fn mangleString(s: []u8) { + @setFnStaticEval(this, false); + for (s) |*c| { *c += 1; } } -#attribute("test") fn emptyStructMethodCall() { + @setFnTest(this, true); + const es = EmptyStruct{}; assert(es.method() == 1234); } struct EmptyStruct { - #static_eval_enable(false) - fn method(es: EmptyStruct) -> i32 { 1234 } + fn method(es: EmptyStruct) -> i32 { + @setFnStaticEval(this, false); + 1234 + } + } -#attribute("test") -fn @"weird function name"() { } +fn @"weird function name"() { + @setFnTest(this, true); +} + -#attribute("test") fn returnEmptyStructFromFn() { + @setFnTest(this, true); + testReturnEmptyStructFromFn(); testReturnEmptyStructFromFnNoeval(); } @@ -1291,13 +1398,15 @@ struct EmptyStruct2 {} fn testReturnEmptyStructFromFn() -> EmptyStruct2 { EmptyStruct2 {} } -#static_eval_enable(false) fn testReturnEmptyStructFromFnNoeval() -> EmptyStruct2 { + @setFnStaticEval(this, false); + EmptyStruct2 {} } -#attribute("test") fn passSliceOfEmptyStructToFn() { + @setFnTest(this, true); + assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1); } fn testPassSliceOfEmptyStructToFn(slice: []EmptyStruct2) -> usize { @@ -1305,8 +1414,9 @@ fn testPassSliceOfEmptyStructToFn(slice: []EmptyStruct2) -> usize { } -#attribute("test") fn pointerComparison() { + @setFnTest(this, true); + const a = ([]u8)("a"); const b = &a; assert(ptrEql(b, b)); @@ -1315,15 +1425,17 @@ fn ptrEql(a: &[]u8, b: &[]u8) -> bool { a == b } -#attribute("test") fn characterLiterals() { + @setFnTest(this, true); + assert('\'' == single_quote); } const single_quote = '\''; -#attribute("test") fn switchWithMultipleExpressions() { + @setFnTest(this, true); + const x: i32 = switch (returnsFive()) { 1, 2, 3 => 1, 4, 5, 6 => 2, @@ -1331,12 +1443,16 @@ fn switchWithMultipleExpressions() { }; assert(x == 2); } -#static_eval_enable(false) -fn returnsFive() -> i32 { 5 } +fn returnsFive() -> i32 { + @setFnStaticEval(this, false); + 5 +} + -#attribute("test") fn switchOnErrorUnion() { + @setFnTest(this, true); + const x = switch (returnsTen()) { Ok => |val| val + 1, ItBroke, NoMem => 1, @@ -1347,20 +1463,28 @@ fn switchOnErrorUnion() { error ItBroke; error NoMem; error CrappedOut; -#static_eval_enable(false) -fn returnsTen() -> %i32 { 10 } +fn returnsTen() -> %i32 { + @setFnStaticEval(this, false); + 10 +} + -#attribute("test") fn boolCmp() { + @setFnTest(this, true); + assert(testBoolCmp(true, false) == false); } -#static_eval_enable(false) -fn testBoolCmp(a: bool, b: bool) -> bool { a == b } +fn testBoolCmp(a: bool, b: bool) -> bool { + @setFnStaticEval(this, false); + a == b +} + -#attribute("test") fn takeAddressOfParameter() { + @setFnTest(this, true); + testTakeAddressOfParameter(12.34); testTakeAddressOfParameterNoeval(12.34); } @@ -1368,20 +1492,23 @@ fn testTakeAddressOfParameter(f: f32) { const f_ptr = &f; assert(*f_ptr == 12.34); } -#static_eval_enable(false) fn testTakeAddressOfParameterNoeval(f: f32) { + @setFnStaticEval(this, false); + const f_ptr = &f; assert(*f_ptr == 12.34); } -#attribute("test") fn arrayMultOperator() { + @setFnTest(this, true); + assert(str.eql("ab" ** 5, "ababababab")); } -#attribute("test") fn stringEscapes() { + @setFnTest(this, true); + assert(str.eql("\"", "\x22")); assert(str.eql("\'", "\x27")); assert(str.eql("\n", "\x0a")); @@ -1391,12 +1518,14 @@ fn stringEscapes() { assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69")); } -#attribute("test") fn ifVarMaybePointer() { + @setFnTest(this, true); + assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15); } -#static_eval_enable(false) fn shouldBeAPlus1(p: Particle) -> u64 { + @setFnStaticEval(this, false); + var maybe_particle: ?Particle = p; if (const *particle ?= maybe_particle) { particle.a += 1; @@ -1413,8 +1542,9 @@ struct Particle { d: u64, } -#attribute("test") fn assignToIfVarPtr() { + @setFnTest(this, true); + var maybe_bool: ?bool = true; if (const *b ?= maybe_bool) { @@ -1424,22 +1554,25 @@ fn assignToIfVarPtr() { assert(??maybe_bool == false); } -#attribute("test") fn cmpxchg() { + @setFnTest(this, true); + var x: i32 = 1234; while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} assert(x == 5678); } -#attribute("test") fn fence() { + @setFnTest(this, true); + var x: i32 = 1234; @fence(AtomicOrder.SeqCst); x = 5678; } -#attribute("test") fn unsignedWrapping() { + @setFnTest(this, true); + testUnsignedWrappingEval(@maxValue(u32)); testUnsignedWrappingNoeval(@maxValue(u32)); } @@ -1449,16 +1582,18 @@ fn testUnsignedWrappingEval(x: u32) { const orig = zero -% 1; assert(orig == @maxValue(u32)); } -#static_eval_enable(false) fn testUnsignedWrappingNoeval(x: u32) { + @setFnStaticEval(this, false); + const zero = x +% 1; assert(zero == 0); const orig = zero -% 1; assert(orig == @maxValue(u32)); } -#attribute("test") fn signedWrapping() { + @setFnTest(this, true); + testSignedWrappingEval(@maxValue(i32)); testSignedWrappingNoeval(@maxValue(i32)); } @@ -1468,16 +1603,18 @@ fn testSignedWrappingEval(x: i32) { const max_val = min_val -% 1; assert(max_val == @maxValue(i32)); } -#static_eval_enable(false) fn testSignedWrappingNoeval(x: i32) { + @setFnStaticEval(this, false); + const min_val = x +% 1; assert(min_val == @minValue(i32)); const max_val = min_val -% 1; assert(max_val == @maxValue(i32)); } -#attribute("test") fn negationWrapping() { + @setFnTest(this, true); + testNegationWrappingEval(@minValue(i16)); testNegationWrappingNoeval(@minValue(i16)); } @@ -1486,15 +1623,17 @@ fn testNegationWrappingEval(x: i16) { const neg = -%x; assert(neg == -32768); } -#static_eval_enable(false) fn testNegationWrappingNoeval(x: i16) { + @setFnStaticEval(this, false); + assert(x == -32768); const neg = -%x; assert(neg == -32768); } -#attribute("test") fn shlWrapping() { + @setFnTest(this, true); + testShlWrappingEval(@maxValue(u16)); testShlWrappingNoeval(@maxValue(u16)); } @@ -1502,22 +1641,25 @@ fn testShlWrappingEval(x: u16) { const shifted = x <<% 1; assert(shifted == 65534); } -#static_eval_enable(false) fn testShlWrappingNoeval(x: u16) { + @setFnStaticEval(this, false); + const shifted = x <<% 1; assert(shifted == 65534); } -#attribute("test") fn shlWithOverflow() { + @setFnTest(this, true); + var result: u16 = undefined; assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); assert(result == 0b1011111111111100); } -#attribute("test") fn cStringConcatenation() { + @setFnTest(this, true); + const a = c"OK" ++ c" IT " ++ c"WORKED"; const b = c"OK IT WORKED"; @@ -1530,8 +1672,9 @@ fn cStringConcatenation() { assert(b[len] == 0); } -#attribute("test") fn genericStruct() { + @setFnTest(this, true); + var a1 = GenNode(i32) {.value = 13, .next = null,}; var b1 = GenNode(bool) {.value = true, .next = null,}; assert(a1.value == 13); @@ -1544,8 +1687,9 @@ struct GenNode(T: type) { fn getVal(n: &const GenNode(T)) -> T { n.value } } -#attribute("test") fn castSliceToU8Slice() { + @setFnTest(this, true); + assert(@sizeOf(i32) == 4); var big_thing_array = []i32{1, 2, 3, 4}; const big_thing_slice: []i32 = big_thing_array; @@ -1565,26 +1709,31 @@ fn castSliceToU8Slice() { assert(bytes[11] == @maxValue(u8)); } -#attribute("test") fn floatDivision() { + @setFnTest(this, true); + assert(fdiv32(12.0, 3.0) == 4.0); } -#static_eval_enable(false) fn fdiv32(a: f32, b: f32) -> f32 { + @setFnStaticEval(this, false); + a / b } -#attribute("test") fn exactDivision() { + @setFnTest(this, true); + assert(divExact(55, 11) == 5); } -#static_eval_enable(false) fn divExact(a: u32, b: u32) -> u32 { + @setFnStaticEval(this, false); + @divExact(a, b) } -#attribute("test") fn nullLiteralOutsideFunction() { + @setFnTest(this, true); + const is_null = if (const _ ?= here_is_a_null_literal.context) false else true; assert(is_null); } @@ -1595,25 +1744,29 @@ const here_is_a_null_literal = SillyStruct { .context = null, }; -#attribute("test") fn truncate() { + @setFnTest(this, true); + assert(testTruncate(0x10fd) == 0xfd); } -#static_eval_enable(false) fn testTruncate(x: u32) -> u8 { + @setFnStaticEval(this, false); + @truncate(u8, x) } -#attribute("test") fn constDeclsInStruct() { + @setFnTest(this, true); + assert(GenericDataThing(3).count_plus_one == 4); } struct GenericDataThing(count: isize) { const count_plus_one = count + 1; } -#attribute("test") fn useGenericParamInGenericParam() { + @setFnTest(this, true); + assert(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(inline T: type, inline a: T, b: T) -> T { @@ -1621,14 +1774,16 @@ fn aGenericFn(inline T: type, inline a: T, b: T) -> T { } -#attribute("test") fn unsigned64BitDivision() { + @setFnTest(this, true); + const result = div(1152921504606846976, 34359738365); assert(result.quotient == 33554432); assert(result.remainder == 100663296); } -#static_eval_enable(false) fn div(a: u64, b: u64) -> DivResult { + @setFnStaticEval(this, false); + DivResult { .quotient = a / b, .remainder = a % b, @@ -1639,8 +1794,9 @@ struct DivResult { remainder: u64, } -#attribute("test") fn intTypeBuiltin() { + @setFnTest(this, true); + assert(@intType(true, 8) == i8); assert(@intType(true, 16) == i16); assert(@intType(true, 32) == i32); @@ -1670,16 +1826,18 @@ fn intTypeBuiltin() { } -#attribute("test") fn intToEnum() { + @setFnTest(this, true); + testIntToEnumEval(3); testIntToEnumNoeval(3); } fn testIntToEnumEval(x: i32) { assert(IntToEnumNumber(x) == IntToEnumNumber.Three); } -#static_eval_enable(false) fn testIntToEnumNoeval(x: i32) { + @setFnStaticEval(this, false); + assert(IntToEnumNumber(x) == IntToEnumNumber.Three); } enum IntToEnumNumber {