remove compiler directives

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

View File

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

View File

@ -8,7 +8,7 @@ if exists("b:current_syntax")
endif endif
let b:current_syntax = "zig" 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 zigStructure struct enum union
syn keyword zigStatement goto break return continue asm defer syn keyword zigStatement goto break return continue asm defer
syn keyword zigConditional if else switch syn keyword zigConditional if else switch

View File

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

View File

@ -75,7 +75,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeBlock: case NodeTypeBlock:
case NodeTypeDirective:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
case NodeTypeDefer: case NodeTypeDefer:
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
@ -1123,6 +1122,28 @@ static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockC
return true; 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, static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
ImportTableEntry *import, BlockContext *containing_context) ImportTableEntry *import, BlockContext *containing_context)
{ {
@ -1133,85 +1154,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
return; 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_internal = (fn_proto->top_level_decl.visib_mod != VisibModExport);
bool is_c_compat = !is_internal || fn_proto->is_extern; bool is_c_compat = !is_internal || fn_proto->is_extern;
fn_table_entry->internal_linkage = !is_c_compat; 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, 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->type_entry = fn_type;
fn_table_entry->is_test = is_test;
if (fn_type->id == TypeTableEntryIdInvalid) { if (fn_type->id == TypeTableEntryIdInvalid) {
fn_proto->skip = true; fn_proto->skip = true;
return; return;
} }
if (fn_proto->is_inline && is_noinline) { if (fn_proto->is_inline) {
add_node_error(g, node, buf_sprintf("function is both inline and noinline"));
fn_proto->skip = true;
return;
} else if (fn_proto->is_inline) {
fn_table_entry->fn_inline = FnInlineAlways; 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"); zig_panic("TODO resolve_top_level_decl NodeTypeUse");
break; break;
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
@ -2406,13 +2340,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
context->parent_loop_node = parent->parent_loop_node; context->parent_loop_node = parent->parent_loop_node;
context->c_import_buf = parent->c_import_buf; context->c_import_buf = parent->c_import_buf;
context->codegen_excluded = parent->codegen_excluded; context->codegen_excluded = parent->codegen_excluded;
context->safety_off = parent->safety_off;
} }
if (node && node->type == NodeTypeFnDef) { if (node && node->type == NodeTypeFnDef) {
AstNode *fn_proto_node = node->data.fn_def.fn_proto; AstNode *fn_proto_node = node->data.fn_def.fn_proto;
context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry; context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry;
context->safety_off = context->fn_entry->safety_off;
} else if (parent) { } else if (parent) {
context->fn_entry = parent->fn_entry; 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, static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) 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); return analyze_int_type(g, import, context, node);
case BuiltinFnIdUnreachable: case BuiltinFnIdUnreachable:
return g->builtin_types.entry_unreachable; 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(); zig_unreachable();
} }
@ -6876,7 +7015,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
break; break;
case NodeTypeSwitchProng: case NodeTypeSwitchProng:
case NodeTypeSwitchRange: case NodeTypeSwitchRange:
case NodeTypeDirective:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeRoot: 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 // error value declarations do not depend on other top level decls
preview_error_value_decl(g, node); preview_error_value_decl(g, node);
break; break;
case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
@ -7418,7 +7555,6 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeUse: case NodeTypeUse:
case NodeTypeContainerDecl: case NodeTypeContainerDecl:
case NodeTypeStructField: case NodeTypeStructField:
@ -7469,7 +7605,6 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeBlock: case NodeTypeBlock:
case NodeTypeDirective:
case NodeTypeStringLiteral: case NodeTypeStringLiteral:
case NodeTypeCharLiteral: case NodeTypeCharLiteral:
case NodeTypeSymbol: case NodeTypeSymbol:

View File

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

View File

@ -352,8 +352,20 @@ static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValue
} }
} }
static bool want_debug_safety_recursive(CodeGen *g, BlockContext *context) {
if (context->safety_set_node || !context->parent) {
return !context->safety_off;
}
context->safety_off = want_debug_safety_recursive(g, context->parent);
context->safety_set_node = context->parent->safety_set_node;
return !context->safety_off;
}
static bool want_debug_safety(CodeGen *g, AstNode *node) { 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) { 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); return gen_truncate(g, node);
case BuiltinFnIdUnreachable: case BuiltinFnIdUnreachable:
return gen_unreachable(g, node); return gen_unreachable(g, node);
case BuiltinFnIdSetFnTest:
case BuiltinFnIdSetFnVisible:
case BuiltinFnIdSetFnStaticEval:
case BuiltinFnIdSetFnNoInline:
case BuiltinFnIdSetDebugSafety:
// do nothing
return nullptr;
} }
zig_unreachable(); zig_unreachable();
} }
@ -3617,7 +3636,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeUse: case NodeTypeUse:
case NodeTypeContainerDecl: case NodeTypeContainerDecl:
case NodeTypeStructField: 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, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "intType", 2); 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, 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) { static void init(CodeGen *g, Buf *source_path) {

View File

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

View File

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

View File

@ -211,8 +211,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory); static AstNode *ast_parse_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_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_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, static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod);
ZigList<AstNode*> *directives, VisibMod visib_mod);
static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index); 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); 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; return token;
} }
/*
Directive = "#" "Symbol" "(" Expression ")"
*/
static AstNode *ast_parse_directive(ParseContext *pc, size_t *token_index) {
Token *number_sign = ast_eat_token(pc, token_index, TokenIdNumberSign);
AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.directive.name = token_buf(name_symbol);
node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true);
normalize_parent_ptrs(node);
return node;
}
static void ast_parse_directives(ParseContext *pc, size_t *token_index,
ZigList<AstNode *> *directives)
{
for (;;) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdNumberSign) {
AstNode *directive_node = ast_parse_directive(pc, token_index);
directives->append(directive_node);
} else {
return;
}
}
zig_unreachable();
}
/* /*
TypeExpr = PrefixOpExpression | "var" TypeExpr = PrefixOpExpression | "var"
*/ */
@ -686,7 +652,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
return node; return node;
} else if (token->id == TokenIdKeywordExtern) { } else if (token->id == TokenIdKeywordExtern) {
*token_index += 1; *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; node->data.fn_proto.is_extern = true;
return node; return node;
} else if (token->id == TokenIdAtSign) { } 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; 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) { if (fn_proto_node) {
return 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)) VariableDeclaration : ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
*/ */
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory, static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod) VisibMod visib_mod)
{ {
Token *first_token = &pc->tokens->at(*token_index); 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.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = visib_mod; 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); Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.variable_declaration.symbol = token_buf(name_token); 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) { if (statement_node) {
semicolon_expected = false; semicolon_expected = false;
} else { } else {
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
nullptr, VisibModPrivate);
if (!statement_node) { if (!statement_node) {
statement_node = ast_parse_defer_expr(pc, token_index); 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, static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index); Token *first_token = &pc->tokens->at(*token_index);
Token *fn_token;
if (first_token->id != TokenIdKeywordFn) { bool is_coldcc = false;
if (mandatory) { bool is_nakedcc = false;
ast_expect_token(pc, first_token, TokenIdKeywordFn); if (first_token->id == TokenIdKeywordColdCC) {
} else { *token_index += 1;
return nullptr; 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.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); Token *fn_name = &pc->tokens->at(*token_index);
if (fn_name->id == TokenIdSymbol) { 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 FnDef = option("inline" | "extern") FnProto Block
*/ */
static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index); Token *first_token = &pc->tokens->at(*token_index);
bool is_inline; bool is_inline;
bool is_extern; bool is_extern;
@ -2087,7 +2059,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
is_extern = false; 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 (!fn_proto) {
if (is_inline || is_extern) { if (is_inline || is_extern) {
*token_index -= 1; *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) ";" ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
*/ */
static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
ZigList<AstNode *> *directives, VisibMod visib_mod)
{
Token *extern_kw = &pc->tokens->at(*token_index); Token *extern_kw = &pc->tokens->at(*token_index);
if (extern_kw->id != TokenIdKeywordExtern) { if (extern_kw->id != TokenIdKeywordExtern) {
if (mandatory) { if (mandatory) {
@ -2128,7 +2098,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
} }
*token_index += 1; *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) { if (fn_proto_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon); 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; 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) { if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon); 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 ";" UseDecl = "use" Expression ";"
*/ */
static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *use_kw = &pc->tokens->at(*token_index); Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordUse) if (use_kw->id != TokenIdKeywordUse)
return nullptr; 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); 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.visib_mod = visib_mod;
node->data.use.top_level_decl.directives = directives;
node->data.use.expr = ast_parse_expression(pc, token_index, true); node->data.use.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdSemicolon); 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) "}" 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) ",") StructField = Symbol option(":" Expression) ",")
*/ */
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index); Token *first_token = &pc->tokens->at(*token_index);
ContainerKind kind; 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.kind = kind;
node->data.struct_decl.name = token_buf(struct_name); 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.visib_mod = visib_mod;
node->data.struct_decl.top_level_decl.directives = directives;
Token *paren_or_brace = &pc->tokens->at(*token_index); Token *paren_or_brace = &pc->tokens->at(*token_index);
if (paren_or_brace->id == TokenIdLParen) { if (paren_or_brace->id == TokenIdLParen) {
@ -2217,10 +2181,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
} }
for (;;) { for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
ZigList<AstNode *> *directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directive_list);
Token *visib_tok = &pc->tokens->at(*token_index); Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod; VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) { if (visib_tok->id == TokenIdKeywordPub) {
@ -2233,20 +2193,20 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
visib_mod = VisibModPrivate; 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) { if (fn_def_node) {
node->data.struct_decl.decls.append(fn_def_node); node->data.struct_decl.decls.append(fn_def_node);
continue; 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) { if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon); ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.struct_decl.decls.append(var_decl_node); node->data.struct_decl.decls.append(var_decl_node);
continue; 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) { if (container_decl_node) {
node->data.struct_decl.decls.append(container_decl_node); node->data.struct_decl.decls.append(container_decl_node);
continue; continue;
@ -2255,10 +2215,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
Token *token = &pc->tokens->at(*token_index); Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) { if (token->id == TokenIdRBrace) {
if (directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
*token_index += 1; *token_index += 1;
break; break;
} else if (token->id == TokenIdSymbol) { } else if (token->id == TokenIdSymbol) {
@ -2266,7 +2222,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
*token_index += 1; *token_index += 1;
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod; 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); field_node->data.struct_field.name = token_buf(token);
Token *expr_or_comma = &pc->tokens->at(*token_index); 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" ";" ErrorValueDecl : "error" "Symbol" ";"
*/ */
static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index, static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index); Token *first_token = &pc->tokens->at(*token_index);
if (first_token->id != TokenIdKeywordError) { 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); 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.visib_mod = visib_mod;
node->data.error_value_decl.top_level_decl.directives = directives;
node->data.error_value_decl.name = token_buf(name_tok); node->data.error_value_decl.name = token_buf(name_tok);
normalize_parent_ptrs(node); 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 ";" TypeDecl = "type" "Symbol" "=" TypeExpr ";"
*/ */
static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index); Token *first_token = &pc->tokens->at(*token_index);
if (first_token->id != TokenIdKeywordType) { 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); 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.visib_mod = visib_mod;
node->data.type_decl.top_level_decl.directives = directives;
normalize_parent_ptrs(node); normalize_parent_ptrs(node);
return node; return node;
} }
/* /*
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl) TopLevelItem = ErrorValueDecl | Block | TopLevelDecl
TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | TypeDecl | UseDecl)
*/ */
static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) { static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) { for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
ZigList<AstNode *> *directives = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directives);
Token *visib_tok = &pc->tokens->at(*token_index); Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod; VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) { 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; 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) { if (fn_def_node) {
top_level_decls->append(fn_def_node); top_level_decls->append(fn_def_node);
continue; 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) { if (fn_proto_node) {
top_level_decls->append(fn_proto_node); top_level_decls->append(fn_proto_node);
continue; 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) { if (use_node) {
top_level_decls->append(use_node); top_level_decls->append(use_node);
continue; 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) { if (struct_node) {
top_level_decls->append(struct_node); top_level_decls->append(struct_node);
continue; continue;
} }
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
directives, visib_mod);
if (var_decl_node) { if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon); ast_eat_token(pc, token_index, TokenIdSemicolon);
top_level_decls->append(var_decl_node); top_level_decls->append(var_decl_node);
continue; 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) { if (error_value_node) {
top_level_decls->append(error_value_node); top_level_decls->append(error_value_node);
continue; 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) { if (type_decl_node) {
top_level_decls->append(type_decl_node); top_level_decls->append(type_decl_node);
continue; continue;
} }
if (directives->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
return; return;
} }
zig_unreachable(); zig_unreachable();
} }
/* /*
Root : many(TopLevelDecl) token(EOF) Root = many(TopLevelItem) "EOF"
*/ */
static AstNode *ast_parse_root(ParseContext *pc, size_t *token_index) { static AstNode *ast_parse_root(ParseContext *pc, size_t *token_index) {
AstNode *node = ast_create_node(pc, NodeTypeRoot, &pc->tokens->at(*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; break;
case NodeTypeFnProto: case NodeTypeFnProto:
visit_field(&node->data.fn_proto.return_type, visit, context); 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); visit_node_list(&node->data.fn_proto.params, visit, context);
break; break;
case NodeTypeFnDef: case NodeTypeFnDef:
@ -2487,9 +2427,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeBlock: case NodeTypeBlock:
visit_node_list(&node->data.block.statements, visit, context); visit_node_list(&node->data.block.statements, visit, context);
break; break;
case NodeTypeDirective:
visit_field(&node->data.directive.expr, visit, context);
break;
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
visit_field(&node->data.return_expr.expr, visit, context); visit_field(&node->data.return_expr.expr, visit, context);
break; 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); visit_field(&node->data.defer.expr, visit, context);
break; break;
case NodeTypeVariableDeclaration: 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.type, visit, context);
visit_field(&node->data.variable_declaration.expr, visit, context); visit_field(&node->data.variable_declaration.expr, visit, context);
break; break;
case NodeTypeTypeDecl: 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); visit_field(&node->data.type_decl.child_type, visit, context);
break; break;
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
@ -2550,7 +2485,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
break; break;
case NodeTypeUse: case NodeTypeUse:
visit_field(&node->data.use.expr, visit, context); visit_field(&node->data.use.expr, visit, context);
visit_node_list(node->data.use.top_level_decl.directives, visit, context);
break; break;
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
// none // none
@ -2626,11 +2560,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeContainerDecl: case NodeTypeContainerDecl:
visit_node_list(&node->data.struct_decl.fields, visit, context); 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.decls, visit, context);
visit_node_list(node->data.struct_decl.top_level_decl.directives, visit, context);
break; break;
case NodeTypeStructField: case NodeTypeStructField:
visit_field(&node->data.struct_field.type, visit, context); visit_field(&node->data.struct_field.type, visit, context);
visit_node_list(node->data.struct_field.top_level_decl.directives, visit, context);
break; break;
case NodeTypeContainerInitExpr: case NodeTypeContainerInitExpr:
visit_field(&node->data.container_init_expr.type, visit, context); visit_field(&node->data.container_init_expr.type, visit, context);
@ -2688,16 +2620,6 @@ static void clone_subtree_list_omit_inline_params(ZigList<AstNode *> *dest, ZigL
} }
} }
static void clone_subtree_list_ptr(ZigList<AstNode *> **dest_ptr, ZigList<AstNode *> *src,
uint32_t *next_node_index)
{
if (src) {
ZigList<AstNode *> *dest = allocate<ZigList<AstNode *>>(1);
*dest_ptr = dest;
clone_subtree_list(dest, src, next_node_index);
}
}
static void clone_subtree_field_special(AstNode **dest, AstNode *src, uint32_t *next_node_index, static void clone_subtree_field_special(AstNode **dest, AstNode *src, uint32_t *next_node_index,
enum AstCloneSpecial special) 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); 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 *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, enum AstCloneSpecial special) {
AstNode *new_node = allocate_nonzero<AstNode>(1); AstNode *new_node = allocate_nonzero<AstNode>(1);
safe_memcpy(new_node, old_node, 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); &old_node->data.root.top_level_decls, next_node_index);
break; break;
case NodeTypeFnProto: 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, clone_subtree_field(&new_node->data.fn_proto.return_type, old_node->data.fn_proto.return_type,
next_node_index); 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, clone_subtree_list(&new_node->data.block.statements, &old_node->data.block.statements,
next_node_index); next_node_index);
break; break;
case NodeTypeDirective:
clone_subtree_field(&new_node->data.directive.expr, old_node->data.directive.expr, next_node_index);
break;
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
clone_subtree_field(&new_node->data.return_expr.expr, old_node->data.return_expr.expr, next_node_index); clone_subtree_field(&new_node->data.return_expr.expr, old_node->data.return_expr.expr, next_node_index);
break; 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); clone_subtree_field(&new_node->data.defer.expr, old_node->data.defer.expr, next_node_index);
break; break;
case NodeTypeVariableDeclaration: 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.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); clone_subtree_field(&new_node->data.variable_declaration.expr, old_node->data.variable_declaration.expr, next_node_index);
break; break;
case NodeTypeTypeDecl: 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); clone_subtree_field(&new_node->data.type_decl.child_type, old_node->data.type_decl.child_type, next_node_index);
break; break;
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
@ -2832,8 +2741,6 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
break; break;
case NodeTypeUse: case NodeTypeUse:
clone_subtree_field(&new_node->data.use.expr, old_node->data.use.expr, next_node_index); 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; break;
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
// none // none
@ -2908,13 +2815,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
next_node_index); next_node_index);
clone_subtree_list(&new_node->data.struct_decl.decls, &old_node->data.struct_decl.decls, clone_subtree_list(&new_node->data.struct_decl.decls, &old_node->data.struct_decl.decls,
next_node_index); 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; break;
case NodeTypeStructField: case NodeTypeStructField:
clone_subtree_field(&new_node->data.struct_field.type, old_node->data.struct_field.type, next_node_index); 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; break;
case NodeTypeContainerInitExpr: case NodeTypeContainerInitExpr:
clone_subtree_field(&new_node->data.container_init_expr.type, old_node->data.container_init_expr.type, next_node_index); clone_subtree_field(&new_node->data.container_init_expr.type, old_node->data.container_init_expr.type, next_node_index);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,17 +8,24 @@ enum Number {
Four, Four,
} }
#attribute("test")
fn enumToInt() { fn enumToInt() {
shouldEqual(Number.Zero, 0); @setFnTest(this, true);
shouldEqual(Number.One, 1);
shouldEqual(Number.Two, 2); shouldEqual(false, Number.Zero, 0);
shouldEqual(Number.Three, 3); shouldEqual(false, Number.One, 1);
shouldEqual(Number.Four, 4); 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 fn shouldEqual(inline static_eval: bool, n: Number, expected: usize) {
#static_eval_enable(false) @setFnStaticEval(this, static_eval);
fn shouldEqual(n: Number, expected: usize) {
assert(usize(n) == expected); assert(usize(n) == expected);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff