Commit fa9006f8d1

Andrew Kelley <superjoe30@gmail.com>
2017-08-30 06:46:38
generic functions can access comptime args in align value
See #37
1 parent c235783
Changed files (2)
src
test
cases
src/analyze.cpp
@@ -1061,13 +1061,31 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
     fn_type_id->is_var_args = fn_proto->is_var_args;
 }
 
-static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, uint32_t alignment) {
+static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
+    IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
+    if (type_is_invalid(align_result->value.type))
+        return false;
+
+    uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
+    if (align_bytes == 0) {
+        add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
+        return false;
+    }
+    if (!is_power_of_2(align_bytes)) {
+        add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
+        return false;
+    }
+
+    *result = align_bytes;
+    return true;
+}
+
+static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {
     assert(proto_node->type == NodeTypeFnProto);
     AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
 
     FnTypeId fn_type_id = {0};
     init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
-    fn_type_id.alignment = alignment;
 
     for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
         AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
@@ -1156,6 +1174,12 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
         param_info->is_noalias = param_node->data.param_decl.is_noalias;
     }
 
+    if (fn_proto->align_expr != nullptr) {
+        if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &fn_type_id.alignment)) {
+            return g->builtin_types.entry_invalid;
+        }
+    }
+
     fn_type_id.return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
 
     switch (fn_type_id.return_type->id) {
@@ -2012,25 +2036,6 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {
     return g->test_fn_type;
 }
 
-static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
-    IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
-    if (type_is_invalid(align_result->value.type))
-        return false;
-
-    uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
-    if (align_bytes == 0) {
-        add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
-        return false;
-    }
-    if (!is_power_of_2(align_bytes)) {
-        add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
-        return false;
-    }
-
-    *result = align_bytes;
-    return true;
-}
-
 static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
     ImportTableEntry *import = tld_fn->base.import;
     AstNode *source_node = tld_fn->base.source_node;
@@ -2061,16 +2066,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
 
         Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;
 
-        uint32_t alignment = 0;
-        if (fn_proto->align_expr != nullptr) {
-            if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &alignment)) {
-                fn_table_entry->type_entry = g->builtin_types.entry_invalid;
-                tld_fn->base.resolution = TldResolutionInvalid;
-                return;
-            }
-        }
-
-        fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, alignment);
+        fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope);
 
         if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) {
             tld_fn->base.resolution = TldResolutionInvalid;
test/cases/align.zig
@@ -127,3 +127,12 @@ fn fnExpects4(ptr: fn()align 4 -> i32) -> i32 {
     ptr()
 }
 fn simple4() align 4 -> i32 { 0x19 }
+
+
+test "generic function with align param" {
+    assert(whyWouldYouEverDoThis(1) == 0x1);
+    assert(whyWouldYouEverDoThis(4) == 0x1);
+    assert(whyWouldYouEverDoThis(8) == 0x1);
+}
+
+fn whyWouldYouEverDoThis(comptime align_bytes: u8) align align_bytes -> u8 { 0x1 }