make @alignOf lazily evaluate the target type

this case works now:

```zig
const Foo = struct {
    field: Bar(@alignOf(*Foo)),
};
fn Bar(comptime alignment: u29) type {
    return struct {
        field: *align(alignment) Foo,
    };
}
```
This commit is contained in:
Andrew Kelley 2019-08-26 10:03:30 -04:00
parent b13af0750f
commit ede0c22a67
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 60 additions and 56 deletions

View File

@ -314,7 +314,9 @@ struct LazyValue {
struct LazyValueAlignOf {
LazyValue base;
ZigType *target_type;
ConstExprValue *target_type_val;
AstNode *target_type_src_node;
};
struct LazyValueSliceType {

View File

@ -1100,13 +1100,14 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
zig_unreachable();
}
static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) {
Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) {
Error err;
if (type_val->special != ConstValSpecialLazy) {
assert(type_val->special == ConstValSpecialStatic);
if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusAlignmentKnown)))
ZigType *ty = type_val->data.x_type;
if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown)))
return err;
*abi_align = type_val->data.x_type->abi_align;
*abi_align = ty->abi_align;
return ErrorNone;
}
switch (type_val->data.x_lazy->id) {

View File

@ -247,6 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode
void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
bool fn_is_async(ZigFn *fn);
Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type);
Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
#endif

View File

@ -22325,63 +22325,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru
}
static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
IrInstruction *type_value = instruction->type_value->child;
if (type_is_invalid(type_value->value.type))
return ira->codegen->invalid_instruction;
ZigType *type_entry = ir_resolve_type(ira, type_value);
switch (type_entry->id) {
case ZigTypeIdInvalid:
zig_unreachable();
case ZigTypeIdMetaType:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdEnumLiteral:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdVoid:
case ZigTypeIdOpaque:
ir_add_error(ira, instruction->type_value,
buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
case ZigTypeIdBool:
case ZigTypeIdInt:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdStruct:
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
break;
}
if (type_is_resolved(type_entry, ResolveStatusAlignmentKnown)) {
uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
}
// Here we create a lazy value in order to avoid resolving the alignment of the type
// immediately. This avoids false positive dependency loops such as:
// const Node = struct {
// field: []align(@alignOf(Node)) Node,
// };
LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
lazy_align_of->base.id = LazyValueIdAlignOf;
lazy_align_of->base.exec = ira->new_irb.exec;
lazy_align_of->target_type = type_entry;
IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
result->value.special = ConstValSpecialLazy;
LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
result->value.data.x_lazy = &lazy_align_of->base;
lazy_align_of->base.id = LazyValueIdAlignOf;
lazy_align_of->base.exec = ira->new_irb.exec;
lazy_align_of->target_type_val = ir_resolve_type_lazy(ira, instruction->type_value->child);
if (lazy_align_of->target_type_val == nullptr)
return ira->codegen->invalid_instruction;
lazy_align_of->target_type_src_node = instruction->type_value->source_node;
return result;
}
@ -25530,9 +25491,49 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx
zig_unreachable();
case LazyValueIdAlignOf: {
LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(val->data.x_lazy);
if ((err = type_resolve(codegen, lazy_align_of->target_type, ResolveStatusAlignmentKnown)))
if (lazy_align_of->target_type_val->special == ConstValSpecialStatic) {
switch (lazy_align_of->target_type_val->data.x_type->id) {
case ZigTypeIdInvalid:
zig_unreachable();
case ZigTypeIdMetaType:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdEnumLiteral:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdVoid:
case ZigTypeIdOpaque:
exec_add_error_node(codegen, exec, lazy_align_of->target_type_src_node,
buf_sprintf("no align available for type '%s'",
buf_ptr(&lazy_align_of->target_type_val->data.x_type->name)));
return ErrorSemanticAnalyzeFail;
case ZigTypeIdBool:
case ZigTypeIdInt:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdStruct:
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
break;
}
}
uint32_t align_in_bytes;
if ((err = type_val_resolve_abi_align(codegen, lazy_align_of->target_type_val, &align_in_bytes)))
return err;
uint64_t align_in_bytes = get_abi_alignment(codegen, lazy_align_of->target_type);
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdComptimeInt);
bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);