generic functions can access comptime args in align value

See #37
This commit is contained in:
Andrew Kelley 2017-08-30 00:46:38 -04:00
parent c2357830b4
commit fa9006f8d1
2 changed files with 36 additions and 31 deletions

View File

@ -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;

View File

@ -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 }