Commit 2ed949a6ae

Andrew Kelley <superjoe30@gmail.com>
2016-08-09 05:43:38
add zeroes value
1 parent 0d5ecc4
doc/langref.md
@@ -151,7 +151,7 @@ GotoExpression = "goto" Symbol
 
 GroupedExpression = "(" Expression ")"
 
-KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
 ```
 
 ## Operator Precedence
src/all_types.hpp
@@ -62,11 +62,18 @@ struct ConstErrValue {
     ConstExprValue *payload;
 };
 
+enum ConstValSpecial {
+    ConstValSpecialOther,
+    ConstValSpecialUndef,
+    ConstValSpecialZeroes,
+};
+
 struct ConstExprValue {
-    bool ok; // true if constant expression evalution worked
+    bool ok;
     bool depends_on_compile_var;
-    bool undef;
+    ConstValSpecial special;
 
+    // populated if val_type == ConstValTypeOk
     union {
         BigNum x_bignum;
         bool x_bool;
@@ -167,6 +174,7 @@ enum NodeType {
     NodeTypeBoolLiteral,
     NodeTypeNullLiteral,
     NodeTypeUndefinedLiteral,
+    NodeTypeZeroesLiteral,
     NodeTypeIfBoolExpr,
     NodeTypeIfVarExpr,
     NodeTypeWhileExpr,
@@ -694,6 +702,12 @@ struct AstNodeUndefinedLiteral {
     Expr resolved_expr;
 };
 
+struct AstNodeZeroesLiteral {
+    // populated by semantic analyzer
+    StructValExprCodeGen resolved_struct_val_expr;
+    Expr resolved_expr;
+};
+
 struct AstNodeSymbolExpr {
     Buf *symbol;
 
@@ -791,6 +805,7 @@ struct AstNode {
         AstNodeStructValueField struct_val_field;
         AstNodeNullLiteral null_literal;
         AstNodeUndefinedLiteral undefined_literal;
+        AstNodeZeroesLiteral zeroes_literal;
         AstNodeSymbolExpr symbol_expr;
         AstNodeBoolLiteral bool_literal;
         AstNodeBreakExpr break_expr;
src/analyze.cpp
@@ -90,6 +90,7 @@ static AstNode *first_executing_node(AstNode *node) {
         case NodeTypeBoolLiteral:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeIfBoolExpr:
         case NodeTypeIfVarExpr:
         case NodeTypeLabel:
@@ -1849,6 +1850,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
         case NodeTypeBoolLiteral:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeSymbol:
         case NodeTypePrefixOpExpr:
         case NodeTypeIfBoolExpr:
@@ -3937,7 +3939,19 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt
     ConstExprValue *const_val = &expr->const_val;
 
     const_val->ok = true;
-    const_val->undef = true;
+    const_val->special = ConstValSpecialUndef;
+
+    return expected_type ? expected_type : g->builtin_types.entry_undef;
+}
+
+static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+        TypeTableEntry *expected_type, AstNode *node)
+{
+    Expr *expr = get_resolved_expr(node);
+    ConstExprValue *const_val = &expr->const_val;
+
+    const_val->ok = true;
+    const_val->special = ConstValSpecialZeroes;
 
     return expected_type ? expected_type : g->builtin_types.entry_undef;
 }
@@ -4252,7 +4266,7 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import
     }
 
     ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
-    if (cond_val->undef) {
+    if (cond_val->special == ConstValSpecialUndef) {
         add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value"));
         return cond_type;
     }
@@ -6504,6 +6518,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
         case NodeTypeUndefinedLiteral:
             return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node);
             break;
+        case NodeTypeZeroesLiteral:
+            return_type = analyze_zeroes_literal_expr(g, import, context, expected_type, node);
+            break;
         case NodeTypeSymbol:
             return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only);
             break;
@@ -6771,6 +6788,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
         case NodeTypeBoolLiteral:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeSymbol:
         case NodeTypePrefixOpExpr:
         case NodeTypeIfBoolExpr:
@@ -7029,6 +7047,8 @@ Expr *get_resolved_expr(AstNode *node) {
             return &node->data.null_literal.resolved_expr;
         case NodeTypeUndefinedLiteral:
             return &node->data.undefined_literal.resolved_expr;
+        case NodeTypeZeroesLiteral:
+            return &node->data.zeroes_literal.resolved_expr;
         case NodeTypeGoto:
             return &node->data.goto_expr.resolved_expr;
         case NodeTypeBreak:
@@ -7111,6 +7131,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
         case NodeTypeBoolLiteral:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeLabel:
         case NodeTypeGoto:
         case NodeTypeBreak:
src/ast_render.cpp
@@ -171,6 +171,8 @@ static const char *node_type_str(NodeType node_type) {
             return "NullLiteral";
         case NodeTypeUndefinedLiteral:
             return "UndefinedLiteral";
+        case NodeTypeZeroesLiteral:
+            return "ZeroesLiteral";
         case NodeTypeIfBoolExpr:
             return "IfBoolExpr";
         case NodeTypeIfVarExpr:
@@ -591,6 +593,8 @@ static void render_node(AstRender *ar, AstNode *node) {
             zig_panic("TODO");
         case NodeTypeUndefinedLiteral:
             zig_panic("TODO");
+        case NodeTypeZeroesLiteral:
+            zig_panic("TODO");
         case NodeTypeIfBoolExpr:
             zig_panic("TODO");
         case NodeTypeIfVarExpr:
src/codegen.cpp
@@ -3141,11 +3141,15 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
     }
 
     bool have_init_expr = false;
+    bool want_zeroes = false;
     if (var_decl->expr) {
         ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
-        if (!const_val->ok || !const_val->undef) {
+        if (!const_val->ok || const_val->special == ConstValSpecialOther) {
             have_init_expr = true;
         }
+        if (const_val->ok && const_val->special == ConstValSpecialZeroes) {
+            want_zeroes = true;
+        }
     }
     if (have_init_expr) {
         TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
@@ -3204,7 +3208,8 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
                 }
             }
         }
-        if (!ignore_uninit && want_debug_safety(g, source_node)) {
+        bool want_safe = want_debug_safety(g, source_node);
+        if (!ignore_uninit && (want_safe || want_zeroes)) {
             TypeTableEntry *usize = g->builtin_types.entry_usize;
             uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref);
             uint64_t align_bytes = get_memcpy_align(g, variable->type);
@@ -3212,7 +3217,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
             // memset uninitialized memory to 0xa
             set_debug_source_node(g, source_node);
             LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
-            LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+            LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false);
             LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
             LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
             LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
@@ -3535,6 +3540,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
         case NodeTypeCharLiteral:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeErrorType:
         case NodeTypeTypeLiteral:
         case NodeTypeArrayType:
@@ -3562,8 +3568,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
 static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
     assert(const_val->ok);
 
-    if (const_val->undef) {
-        return LLVMGetUndef(type_entry->type_ref);
+    switch (const_val->special) {
+        case ConstValSpecialUndef:
+            return LLVMGetUndef(type_entry->type_ref);
+        case ConstValSpecialZeroes:
+            return LLVMConstNull(type_entry->type_ref);
+        case ConstValSpecialOther:
+            break;
+
     }
 
     switch (type_entry->id) {
src/eval.cpp
@@ -545,7 +545,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
         ConstExprValue *const_val, TypeTableEntry *new_type)
 {
     const_val->depends_on_compile_var = other_val->depends_on_compile_var;
-    const_val->undef = other_val->undef;
+    const_val->special = other_val->special;
 
     assert(other_val != const_val);
     switch (cast_op) {
@@ -572,7 +572,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
                     const_val->data.x_ptr.ptr = ptr_val;
                     const_val->data.x_ptr.len = 1;
                     const_val->ok = true;
-                    const_val->undef = other_val->undef;
+                    const_val->special = other_val->special;
                     const_val->depends_on_compile_var = other_val->depends_on_compile_var;
                 } else {
                     zig_panic("TODO");
@@ -608,7 +608,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
 
                         const_val->data.x_maybe = ptr_parent;
                         const_val->ok = true;
-                        const_val->undef = other_val->undef;
+                        const_val->special = other_val->special;
                         const_val->depends_on_compile_var = other_val->depends_on_compile_var;
                     } else {
                         zig_panic("TODO");
@@ -1277,6 +1277,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
         case NodeTypeSliceExpr:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
+        case NodeTypeZeroesLiteral:
         case NodeTypeIfVarExpr:
         case NodeTypeSwitchExpr:
         case NodeTypeSwitchProng:
src/parser.cpp
@@ -606,7 +606,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
 
 /*
 PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
-KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
 */
 static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
@@ -654,6 +654,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
         AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
         *token_index += 1;
         return node;
+    } else if (token->id == TokenIdKeywordZeroes) {
+        AstNode *node = ast_create_node(pc, NodeTypeZeroesLiteral, token);
+        *token_index += 1;
+        return node;
     } else if (token->id == TokenIdKeywordType) {
         AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token);
         *token_index += 1;
@@ -2539,6 +2543,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
         case NodeTypeUndefinedLiteral:
             // none
             break;
+        case NodeTypeZeroesLiteral:
+            // none
+            break;
         case NodeTypeIfBoolExpr:
             visit_field(&node->data.if_bool_expr.condition, visit, context);
             visit_field(&node->data.if_bool_expr.then_block, visit, context);
@@ -2813,6 +2820,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
         case NodeTypeUndefinedLiteral:
             // none
             break;
+        case NodeTypeZeroesLiteral:
+            // none
+            break;
         case NodeTypeIfBoolExpr:
             clone_subtree_field(&new_node->data.if_bool_expr.condition, old_node->data.if_bool_expr.condition, next_node_index);
             clone_subtree_field(&new_node->data.if_bool_expr.then_block, old_node->data.if_bool_expr.then_block, next_node_index);
src/tokenizer.cpp
@@ -137,6 +137,7 @@ static const struct ZigKeyword zig_keywords[] = {
     {"var", TokenIdKeywordVar},
     {"volatile", TokenIdKeywordVolatile},
     {"while", TokenIdKeywordWhile},
+    {"zeroes", TokenIdKeywordZeroes},
 };
 
 bool is_zig_keyword(Buf *buf) {
@@ -1467,6 +1468,7 @@ const char * token_name(TokenId id) {
         case TokenIdKeywordNoAlias: return "noalias";
         case TokenIdKeywordSwitch: return "switch";
         case TokenIdKeywordUndefined: return "undefined";
+        case TokenIdKeywordZeroes: return "zeroes";
         case TokenIdKeywordError: return "error";
         case TokenIdKeywordType: return "type";
         case TokenIdKeywordInline: return "inline";
src/tokenizer.hpp
@@ -40,6 +40,7 @@ enum TokenId {
     TokenIdKeywordNoAlias,
     TokenIdKeywordSwitch,
     TokenIdKeywordUndefined,
+    TokenIdKeywordZeroes,
     TokenIdKeywordError,
     TokenIdKeywordType,
     TokenIdKeywordInline,
test/cases/zeroes.zig
@@ -0,0 +1,18 @@
+const assert = @import("std").debug.assert;
+
+struct Foo {
+    a: f32,
+    b: i32,
+    c: bool,
+    d: ?i32,
+}
+
+#attribute("test")
+fn initializing_a_struct_with_zeroes() {
+    const foo: Foo = zeroes;
+    assert(foo.a == 0.0);
+    assert(foo.b == 0);
+    assert(foo.c == false);
+    assert(if (const x ?= foo.d) false else true);
+}
+
test/self_hosted.zig
@@ -4,6 +4,7 @@ const str = std.str;
 const cstr = std.cstr;
 const other = @import("other.zig");
 const cases_return_type_type = @import("cases/return_type_type.zig");
+const test_zeroes = @import("cases/zeroes.zig");
 
 // normal comment
 /// this is a documentation comment