diff --git a/README.md b/README.md index b334eb5da..5f8ce64ef 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ the r/ProgrammingLanguages Discord: https://discord.gg/cfu4wdk - [ ] CT type constants - [ ] Reflection methods - [ ] Anonymous structs -- [ ] Distinct types +- [x] Distinct types - [ ] LTO/ThinLTO setup - [ ] Built-in linking - [ ] `global` / `shared` for globals @@ -106,7 +106,7 @@ the r/ProgrammingLanguages Discord: https://discord.gg/cfu4wdk - [ ] Implicit capturing macros - [ ] Trailing body macros - [ ] Subarray initializers -- [ ] slice initializers e.g. `{ [1..2] = 2 }` +- [x] range initializers e.g. `{ [1..2] = 2 }` - [ ] Bitstructs - [ ] `asm` section - [ ] `$switch` diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 0486632cd..6b2746a5a 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -87,6 +87,9 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility case DECL_ENUM: kind = TYPE_ENUM; break; + case DECL_DISTINCT: + kind = TYPE_DISTINCT; + break; case DECL_TYPEDEF: kind = TYPE_TYPEDEF; break; @@ -326,7 +329,9 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) } switch (type->type_kind) { - + case TYPE_DISTINCT: + DUMPF("(distinct %s)", type->name); + return; case TYPE_COMPLEX: DUMP("(type complex"); return; @@ -878,6 +883,17 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent) DUMPTI(decl->typedef_decl.type_info); } DUMPEND(); + case DECL_DISTINCT: + DUMPF("(distinct %s", decl->name); + if (decl->typedef_decl.is_func) + { + fprint_func_signature(context, file, &decl->typedef_decl.function_signature, indent + 1); + } + else + { + DUMPTI(decl->typedef_decl.type_info); + } + DUMPEND(); case DECL_CT_IF: DUMP("(ct-if"); DUMPEXPR(decl->ct_if_decl.expr); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 0f7563af0..98445eec4 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -393,6 +393,16 @@ typedef struct }; } TypedefDecl; +typedef struct +{ + union + { + TypedefDecl typedef_decl; + Type *base_type; + }; + Decl** methods; +} DistinctDecl; + typedef struct { bool failable : 1; @@ -482,6 +492,7 @@ typedef struct _Decl FuncDecl func; AttrDecl attr; TypedefDecl typedef_decl; + DistinctDecl distinct_decl; MacroDecl macro_decl; GenericDecl generic_decl; DefineDecl define_decl; @@ -1313,21 +1324,22 @@ extern Type *type_typeid, *type_error, *type_typeinfo; extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; -extern const char *kw_main; -extern const char *kw_sizeof; -extern const char *kw_alignof; extern const char *kw_align; -extern const char *kw_offsetof; -extern const char *kw_kindof; -extern const char *kw_nameof; -extern const char *kw_qnameof; -extern const char *kw_len; +extern const char *kw_alignof; +extern const char *kw_distinct; extern const char *kw_inline; +extern const char *kw_kindof; +extern const char *kw_len; +extern const char *kw_main; +extern const char *kw_nameof; +extern const char *kw_offsetof; extern const char *kw_ordinal; -extern const char *kw___round; +extern const char *kw_qnameof; +extern const char *kw_sizeof; extern const char *kw___ceil; -extern const char *kw___trunc; +extern const char *kw___round; extern const char *kw___sqrt; +extern const char *kw___trunc; #define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id(_token.id)) #define AST_NEW(_kind, _loc) new_ast(_kind, _loc) @@ -1748,11 +1760,6 @@ static inline bool type_convert_will_trunc(Type *destination, Type *source) return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize; } -static inline bool type_is_numeric(Type *type) -{ - if (type->type_kind == TYPE_TYPEDEF) type = type->canonical; - return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX; -} UnaryOp unaryop_from_token(TokenType type); TokenType unaryop_to_token(UnaryOp type); @@ -1779,6 +1786,11 @@ static inline void advance_and_verify(Context *context, TokenType token_type) } +static inline Type *type_flatten(Type *type) +{ + type = type->canonical; + return type->type_kind == TYPE_DISTINCT ? type->decl->distinct_decl.base_type : type; +} static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; } static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; } static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; } @@ -1788,6 +1800,13 @@ static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; } bool type_is_scalar(Type *type); + +static inline bool type_is_numeric(Type *type) +{ + type = type_flatten(type); + return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX; +} + static inline bool type_kind_is_derived(TypeKind kind) { switch (kind) @@ -1819,7 +1838,7 @@ static inline bool type_is_structlike(Type *type) static inline Type *type_lowering(Type *type) { - Type *canonical = type->canonical; + Type *canonical = type_flatten(type); if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical; if (canonical->type_kind == TYPE_TYPEID) return type_usize->canonical; return canonical; diff --git a/src/compiler/context.c b/src/compiler/context.c index 93c0f66c9..f56d373a3 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -120,6 +120,7 @@ void context_register_global_decl(Context *context, Decl *decl) case DECL_STRUCT: case DECL_UNION: case DECL_TYPEDEF: + case DECL_DISTINCT: case DECL_ERR: vec_add(context->types, decl); decl_set_external_name(decl); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 1e4ed957a..888a9dea1 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -134,6 +134,7 @@ typedef enum DECL_LABEL, DECL_ENUM_CONSTANT, DECL_TYPEDEF, + DECL_DISTINCT, DECL_STRUCT, DECL_UNION, DECL_ENUM, @@ -488,6 +489,7 @@ typedef enum TYPE_ERRTYPE, TYPE_ERR_UNION, TYPE_TYPEDEF, + TYPE_DISTINCT, TYPE_STRING, TYPE_ARRAY, TYPE_VARARRAY, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 492f17e63..9d5c9ad37 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -96,6 +96,8 @@ static void header_print_type(FILE *file, Type *type) case TYPE_UNION: OUTPUT("union %s__", type->decl->external_name); return; + case TYPE_DISTINCT: + TODO case TYPE_ERRTYPE: break; case TYPE_ERR_UNION: @@ -204,6 +206,7 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl) case DECL_FUNC: TODO case DECL_TYPEDEF: + case DECL_DISTINCT: TODO case DECL_STRUCT: header_gen_struct(file, indent, decl); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 6e565da6e..92b35ff3e 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -667,7 +667,7 @@ void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type) value->value = llvm_value; value->alignment = type_abi_alignment(type); value->kind = BE_VALUE; - value->type = type; + value->type = type_flatten(type); } bool llvm_value_is_const(BEValue *value) @@ -680,11 +680,11 @@ void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type value->value = llvm_value; value->alignment = alignment; value->kind = BE_ADDRESS; - value->type = type; + value->type = type_flatten(type); } void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type) { - llvm_value_set_address_align(value, llvm_value, type, type_abi_alignment(type)); + llvm_value_set_address_align(value, llvm_value, type_flatten(type), type_abi_alignment(type)); } void llvm_value_fold_failable(GenContext *c, BEValue *value) @@ -782,6 +782,9 @@ static void gencontext_emit_decl(GenContext *context, Decl *decl) break; case DECL_TYPEDEF: break; + case DECL_DISTINCT: + // TODO + break; case DECL_ENUM_CONSTANT: // TODO break;; diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index e796ffba4..5ce4a1d3b 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -437,6 +437,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_FUNC: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_DISTINCT: UNREACHABLE case TYPE_VOID: *current = CLASS_NO_CLASS; @@ -631,6 +632,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_TYPEDEF: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_DISTINCT: UNREACHABLE case TYPE_I128: case TYPE_U128: diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index a14d8b312..ff0b79602 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -114,11 +114,12 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_FUNC: case TYPE_TYPEDEF: case TYPE_TYPEINFO: + case TYPE_DISTINCT: + case TYPE_ENUM: UNREACHABLE case ALL_INTS: case ALL_FLOATS: case TYPE_BOOL: - case TYPE_ENUM: case TYPE_POINTER: case TYPE_TYPEID: case TYPE_VARARRAY: @@ -588,6 +589,7 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type * case TYPE_TYPEDEF: case TYPE_VOID: case TYPE_ENUM: + case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEID: UNREACHABLE diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 4e2362896..abd66f79a 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -525,6 +525,8 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case TYPE_STRUCT: case TYPE_UNION: return type->backend_debug_type = llvm_debug_structlike_type(c, type, scope); + case TYPE_DISTINCT: + TODO case TYPE_TYPEDEF: return type->backend_debug_type = llvm_debug_typedef_type(c, type); case TYPE_STRING: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index f12d23e3d..afaf62df1 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -136,7 +136,7 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty static inline void gencontext_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent) { LLVMValueRef parent_value; - Type *type = parent->type->canonical; + Type *type = type_flatten(parent->type); switch (type->type_kind) { case TYPE_POINTER: @@ -226,7 +226,7 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index) { assert(llvm_value_is_addr(parent)); - Type *type = parent->type->canonical; + Type *type = type_flatten(parent->type); switch (type->type_kind) { case TYPE_POINTER: @@ -342,7 +342,7 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_ llvm_emit_expr(context, be_value, parent); Decl *member = expr->access_expr.ref; - gencontext_emit_member_addr(context, be_value, parent->type->canonical->decl, member); + gencontext_emit_member_addr(context, be_value, type_flatten(parent->type)->decl, member); } static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr) @@ -524,9 +524,11 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type) { + to_type = type_flatten(to_type); + from_type = type_flatten(from_type); value->value = gencontext_emit_cast_inner(c, cast_kind, value, to_type, from_type); - value->type = to_type; - value->kind = to_type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE; + value->type = type_flatten(to_type); + value->kind = value->type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE; } static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_value, Expr *expr) @@ -535,8 +537,8 @@ static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_va llvm_emit_cast(context, expr->cast_expr.kind, be_value, - expr->type->canonical, - expr->cast_expr.expr->type->canonical); + expr->type, + expr->cast_expr.expr->type); } @@ -634,7 +636,7 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref, switch (const_init->kind) { case CONST_INIT_ZERO: - if (type_is_builtin(ref->type->canonical->type_kind) || ref->type->canonical->type_kind == TYPE_ARRAY) + if (type_is_builtin(ref->type->type_kind) || ref->type->type_kind == TYPE_ARRAY) { llvm_store_bevalue_raw(c, ref, llvm_get_zero(c, ref->type)); return; @@ -725,16 +727,11 @@ static void llvm_emit_inititialize_reference_const(GenContext *c, BEValue *ref, } static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue *ref, Expr *expr) { - // Getting ready to initialize, get the real type. - Type *real_type = ref->type->canonical; ConstInitializer *initializer = expr->initializer_expr.initializer; // Make sure we have an address. llvm_value_addr(c, ref); - Type *canonical = expr->type->canonical; - LLVMTypeRef type = llvm_get_type(c, canonical); - llvm_emit_inititialize_reference_const(c, ref, initializer); } @@ -742,7 +739,7 @@ static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue * static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *ref, Expr *expr) { // Getting ready to initialize, get the real type. - Type *real_type = ref->type->canonical; + Type *real_type = type_flatten(ref->type); Expr **elements = expr->initializer_expr.initializer_expr; // Make sure we have an address. @@ -784,12 +781,12 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r offset = i * type_size(array_element_type); LLVMValueRef index = llvm_const_int(c, type_uint, i); LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, array_element_type_llvm, value, &index, 1, ""); - unsigned alignment = aligned_offset(offset, ref->alignment); + unsigned alignment = type_min_alignment(offset, ref->alignment); llvm_value_set_address_align(&pointer, ptr, element->type, alignment); } else { - llvm_value_set_address_align(&pointer, value, element->type, 0); + llvm_value_set_address_align(&pointer, value, element->type, ref->alignment); } // If this is an initializer, we want to actually run the initialization recursively. if (element->expr_kind == EXPR_INITIALIZER_LIST) @@ -915,7 +912,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ unsigned decl_alignment = decl_abi_alignment(decl); if (ref->type->type_kind == TYPE_UNION) { - llvm_value_set_address_align(&value, llvm_emit_bitcast(c, ref->value, type_get_ptr(type)), type, aligned_offset(offset, decl_alignment)); + llvm_value_set_address_align(&value, llvm_emit_bitcast(c, ref->value, type_get_ptr(type)), type, type_min_alignment(offset, decl_alignment)); } else { @@ -926,7 +923,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ } case DESIGNATOR_ARRAY: { - Type *type = ref->type->canonical->array.base; + Type *type = ref->type->array.base; LLVMValueRef indices[2]; if (curr->index_expr->expr_kind == EXPR_CONST) { @@ -943,7 +940,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ indices[1] = llvm_value_rvalue_store(c, &res); } LLVMValueRef ptr = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, ref->type), ref->value, indices, 2, ""); - llvm_value_set_address_align(&value, ptr, type, aligned_offset(offset, type_abi_alignment(type))); + llvm_value_set_address_align(&value, ptr, type, type_min_alignment(offset, type_abi_alignment(type))); llvm_emit_initialize_designated(c, &value, offset, current + 1, last, expr, emitted_value); break; } @@ -965,14 +962,15 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEValue *ref, Expr *expr) { // Getting ready to initialize, get the real type. - Type *real_type = ref->type->canonical; + Type *real_type = type_flatten(ref->type); Expr **elements = expr->initializer_expr.initializer_expr; + assert(vec_size(elements)); // Make sure we have an address. llvm_value_addr(c, ref); - // Clear the memory - llvm_emit_memclear(c, ref); + // Clear the memory if not union. + if (real_type->type_kind != TYPE_UNION) llvm_emit_memclear(c, ref); LLVMValueRef value = ref->value; @@ -1188,7 +1186,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_addr(c, value); // Transform to value value->kind = BE_VALUE; - value->type = expr->type; + value->type = type_flatten(expr->type); return; case UNARYOP_DEREF: llvm_emit_expr(c, value, expr->unary_expr.expr); @@ -1196,7 +1194,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_rvalue(c, value); // Convert pointer to address value->kind = BE_ADDRESS; - value->type = expr->type; + value->type = type_flatten(expr->type); return; case UNARYOP_INC: llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false); @@ -2144,7 +2142,7 @@ void gencontext_emit_elvis_expr(GenContext *c, BEValue *value, Expr *expr) llvm_value_rvalue(c, value); LLVMValueRef lhs = value->value; - Type *cond_type = expr->ternary_expr.cond->type->canonical; + Type *cond_type = expr->ternary_expr.cond->type; // If the cond is not a boolean, we need to do the cast. if (value->kind != BE_BOOLEAN) @@ -2316,7 +2314,7 @@ static void gencontext_expand_struct_to_args(GenContext *context, Type *param_ty static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values) { REDO: - switch (param_type->type_kind) + switch (type_flatten(param_type)->type_kind) { case TYPE_POISONED: case TYPE_VOID: @@ -2326,6 +2324,7 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_FUNC: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_DISTINCT: UNREACHABLE break; case TYPE_BOOL: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index ba4a18ae6..a11b2f19d 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -615,6 +615,7 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) { case DECL_POISONED: case DECL_TYPEDEF: + case DECL_DISTINCT: UNREACHABLE; case DECL_FUNC: decl->backend_ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name, diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index eb8d6165b..dbe37e10d 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -33,7 +33,7 @@ typedef struct { BackendValueKind kind : 5; AlignSize alignment; - Type *type; + Type *type; // Should never be a distinct or canonical type. LLVMValueRef value; LLVMValueRef failable; } BEValue; diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 5a977edb0..d6fb82628 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -134,7 +134,7 @@ void gencontext_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr } if (bool_cast) { - type = type->canonical; + type = type_flatten(type); if (type->type_kind != TYPE_BOOL) { CastKind cast = cast_to_bool_kind(type); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 1f1573edb..467f2a913 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -30,6 +30,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) } case DECL_TYPEDEF: return llvm_get_type(c, decl->typedef_decl.type_info->type); + case DECL_DISTINCT: + return llvm_get_type(c, decl->distinct_decl.base_type); case DECL_STRUCT: { LLVMTypeRef *types = NULL; @@ -328,6 +330,8 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize); case TYPE_TYPEDEF: return any_type->backend_type = llvm_get_type(c, any_type->canonical); + case TYPE_DISTINCT: + return any_type->backend_type = llvm_get_type(c, any_type->decl->distinct_decl.base_type); case TYPE_ENUM: return any_type->backend_type = llvm_get_type(c, any_type->decl->enums.type_info->type->canonical); case TYPE_ERR_UNION: diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 0c2a8f590..128aa0780 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -1419,9 +1419,6 @@ static inline Decl *parse_attribute_declaration(Context *context, Visibility vis return decl; } -/** - * - */ /** * func_typedef * : FUNC failable_type opt_parameter_type_list @@ -1446,6 +1443,14 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v } +/** + * typedef_declaration + * : TYPEDEF (func_typedef | type) AS ('distinct')? type_ident + * + * @param context + * @param visibility + * @return + */ static inline Decl *parse_typedef_declaration(Context *context, Visibility visibility) { advance_and_verify(context, TOKEN_TYPEDEF); @@ -1460,6 +1465,14 @@ static inline Decl *parse_typedef_declaration(Context *context, Visibility visib decl->typedef_decl.is_func = false; } CONSUME_OR(TOKEN_AS, poisoned_decl); + + // Parse optional "distinct" + if (context->tok.type == TOKEN_IDENT && TOKSTR(context->tok) == kw_distinct) + { + advance(context); + decl->type->type_kind = TYPE_DISTINCT; + decl->decl_kind = DECL_DISTINCT; + } decl->name = TOKSTR(context->tok); decl->type->name = TOKSTR(context->tok); decl->name_token = context->tok.id; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 361c124ff..065efbb47 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -729,10 +729,11 @@ bool cast_implicit(Context *context, Expr *expr, Type *to_type) CastKind cast_to_bool_kind(Type *type) { - switch (type->type_kind) + switch (type_flatten(type)->type_kind) { case TYPE_TYPEDEF: - return cast_to_bool_kind(type->canonical); + case TYPE_DISTINCT: + UNREACHABLE case TYPE_POISONED: case TYPE_VOID: case TYPE_ERR_UNION: @@ -772,6 +773,16 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) Type *from_type = expr->type->canonical; Type *canonical = to_type->canonical; if (from_type == canonical) return true; + if (cast_type == CAST_TYPE_EXPLICIT) + { + canonical = type_flatten(canonical); + from_type = type_flatten(from_type); + if (from_type == canonical) + { + expr->type = to_type; + return true; + } + } switch (from_type->type_kind) { case TYPE_POISONED: @@ -779,6 +790,7 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) case TYPE_TYPEID: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_DISTINCT: break; case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. @@ -790,6 +802,7 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) if (to_type->type_kind == TYPE_ERRTYPE) return euer(context, expr, canonical, to_type, cast_type); break; case TYPE_IXX: + canonical = type_flatten(canonical); // Compile time integers may convert into ints, floats, bools if (expr->expr_kind != EXPR_CONST && !expr->reeval) { @@ -818,6 +831,10 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); break; case ALL_FLOATS: + if (from_type->type_kind == TYPE_FXX) + { + canonical = type_flatten(canonical); + } // Compile time integers may convert into ints, floats, bools if (from_type->type_kind == TYPE_FXX && expr->expr_kind != EXPR_CONST && !expr->reeval) { diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 9ac5f4b52..0c488b52f 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -444,6 +444,22 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl) return true; } +static inline bool sema_analyse_distinct(Context *context, Decl *decl) +{ + if (decl->distinct_decl.typedef_decl.is_func) + { + Type *func_type = sema_analyse_function_signature(context, &decl->distinct_decl.typedef_decl.function_signature, false); + if (!func_type) return false; + decl->distinct_decl.base_type = type_get_ptr(func_type); + return true; + } + TypeInfo *info = decl->distinct_decl.typedef_decl.type_info; + if (!sema_resolve_type_info(context, info)) return false; + decl->distinct_decl.base_type = info->type->canonical; + // Do we need anything else? + return true; +} + static inline bool sema_analyse_enum(Context *context, Decl *decl) { // Resolve the type of the enum. @@ -942,6 +958,9 @@ bool sema_analyse_decl(Context *context, Decl *decl) if (!sema_analyse_global(context, decl)) return decl_poison(decl); decl_set_external_name(decl); break; + case DECL_DISTINCT: + if (!sema_analyse_distinct(context, decl)) return decl_poison(decl); + break; case DECL_TYPEDEF: if (!sema_analyse_typedef(context, decl)) return decl_poison(decl); break; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 57408a371..b26a1d94c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -65,7 +65,7 @@ static inline bool both_const(Expr *left, Expr *right) static inline bool both_any_integer(Expr *left, Expr *right) { - return type_is_any_integer(left->type->canonical) && type_is_any_integer(right->type->canonical); + return type_is_any_integer(type_flatten(left->type)) && type_is_any_integer(type_flatten(right->type)); } static inline void context_pop_returns(Context *context, Ast **restore) @@ -163,6 +163,8 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr return true; case DECL_VAR: break; + case DECL_DISTINCT: + TODO case DECL_TYPEDEF: UNREACHABLE case DECL_POISONED: @@ -1412,7 +1414,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr) expr->failable = expr->subscript_expr.expr->failable; assert(expr->expr_kind == EXPR_SUBSCRIPT); Expr *subscripted = expr->subscript_expr.expr; - Type *type = subscripted->type->canonical; + Type *type = type_flatten(subscripted->type); Expr *index = expr->subscript_expr.index; Type *current_type = type; Expr *current_expr = subscripted; @@ -1448,7 +1450,7 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) Expr *subscripted = expr->slice_expr.expr; expr->pure = subscripted->pure; expr->constant = subscripted->constant; - Type *type = subscripted->type->canonical; + Type *type = type_flatten(subscripted->type); Expr *start = expr->slice_expr.start; Expr *end = expr->slice_expr.end; @@ -1928,12 +1930,12 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) assert(parent->resolve_status == RESOLVE_DONE); Type *parent_type = parent->type; - Type *type = parent_type->canonical; + Type *type = type_flatten(parent_type); bool is_pointer = type->type_kind == TYPE_POINTER; if (is_pointer) { - type = type->pointer; + type = type_flatten(type->pointer); if (!sema_cast_rvalue(context, NULL, parent)) return false; insert_access_deref(expr); parent = expr->access_expr.parent; @@ -1941,6 +1943,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) const char *kw = TOKSTR(expr->access_expr.sub_element); Expr *current_parent = parent; CHECK_DEEPER: + switch (type->type_kind) { case TYPE_SUBARRAY: @@ -2187,7 +2190,7 @@ static void sema_create_const_initializer_value(ConstInitializer *const_init, Ex return; } const_init->init_value = value; - const_init->type = value->type->canonical; + const_init->type = type_flatten(value->type); const_init->kind = CONST_INIT_VALUE; } @@ -2228,7 +2231,7 @@ static inline void sema_update_const_initializer_with_designator_struct(ConstIni { // Create zero initializers for each of those { a: zeroinit, b: zeroinit, ... } ConstInitializer *element_init = MALLOC(sizeof(ConstInitializer)); - element_init->type = elements[i]->type->canonical; + element_init->type = type_flatten(elements[i]->type); element_init->kind = CONST_INIT_ZERO; const_inits[i] = element_init; } @@ -2296,7 +2299,7 @@ static inline void sema_update_const_initializer_with_designator_union(ConstInit } // Update of the sub element. - sub_element->type = const_init->type->decl->strukt.members[element->index]->type->canonical; + sub_element->type = type_flatten(const_init->type->decl->strukt.members[element->index]->type); // And the index const_init->init_union.index = element->index; @@ -2338,7 +2341,7 @@ static inline void sema_update_const_initializer_with_designator_array(ConstInit const_init->init_array.elements = NULL; } - Type *element_type = const_init->type->array.base; + Type *element_type = type_flatten(const_init->type->array.base); DesignatorElement **next_element = curr + 1; bool is_last_path_element = next_element == end; @@ -2444,10 +2447,16 @@ static inline void sema_update_const_initializer_with_designator( } +/** + * Create a const initializer. + */ static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer) { const_init->kind = CONST_INIT_ZERO; - const_init->type = initializer->type->canonical; + // Flatten the type since the external type might be typedef or a distinct type. + const_init->type = type_flatten(initializer->type); + + // Loop through the initializers. Expr **init_expressions = initializer->initializer_expr.initializer_expr; VECEACH(init_expressions, i) { @@ -2623,7 +2632,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_STRUCT; - const_init->type = initializer->type->canonical; + const_init->type = type_flatten(initializer->type); ConstInitializer **inits = MALLOC(sizeof(ConstInitializer *) * vec_size(elements)); VECEACH(elements, i) { @@ -2701,7 +2710,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_ARRAY_FULL; - const_init->type = initializer->type->canonical; + const_init->type = type_flatten(initializer->type); ConstInitializer **inits = MALLOC(sizeof(ConstInitializer *) * vec_size(elements)); VECEACH(elements, i) { @@ -2725,9 +2734,9 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T return true; } -static inline bool sema_expr_analyse_initializer(Context *context, Type *assigned, Expr *expr) +static inline bool sema_expr_analyse_initializer(Context *context, Type *external_type, Type *assigned, Expr *expr) { - expr->type = assigned; + expr->type = external_type; Expr **init_expressions = expr->initializer_expr.initializer_expr; @@ -2736,7 +2745,7 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *assigne { ConstInitializer *initializer = CALLOCS(ConstInitializer); initializer->kind = CONST_INIT_ZERO; - initializer->type = expr->type; + initializer->type = type_flatten(expr->type); expr->initializer_expr.init_type = INITIALIZER_CONST; expr->initializer_expr.initializer = initializer; expr->constant = true; @@ -2763,15 +2772,14 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *assigne static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr) { assert(to); - Type *assigned = to->canonical; - assert(assigned); + Type *assigned = type_flatten(to); switch (assigned->type_kind) { case TYPE_STRUCT: case TYPE_UNION: case TYPE_ARRAY: case TYPE_ERRTYPE: - return sema_expr_analyse_initializer(context, assigned, expr); + return sema_expr_analyse_initializer(context, to, assigned, expr); case TYPE_VARARRAY: TODO default: @@ -3857,8 +3865,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp bool is_equality_type_op = expr->binary_expr.operator == BINARYOP_NE || expr->binary_expr.operator == BINARYOP_EQ; - Type *left_type = left->type->canonical; - Type *right_type = right->type->canonical; + Type *left_type = type_flatten(left->type); + Type *right_type = type_flatten(right->type); // 2. Handle the case of signed comparisons. // This happens when either side has a definite integer type @@ -3873,7 +3881,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp else { // 3. In the normal case, treat this as a binary op, finding the max type. - Type *max = type_find_max_type(left_type, right_type); + Type *max = type_find_max_type(left->type->canonical, right->type->canonical); // 4. If no common type, then that's an error: if (!max) @@ -3886,7 +3894,12 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp // so we need to check that as well. if (!is_equality_type_op) { - switch (max->type_kind) + Type *effective_type = max; + if (max->type_kind == TYPE_DISTINCT) + { + effective_type = max->decl->distinct_decl.base_type; + } + switch (effective_type->type_kind) { case TYPE_POISONED: return false; @@ -3894,6 +3907,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_TYPEDEF: + case TYPE_DISTINCT: UNREACHABLE case TYPE_BOOL: case TYPE_ENUM: @@ -4241,13 +4255,14 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * return true; } Type *canonical = inner->type->canonical; - switch (canonical->type_kind) + switch (type_flatten(canonical)->type_kind) { case TYPE_POISONED: case TYPE_IXX: case TYPE_FXX: case TYPE_TYPEDEF: case TYPE_ERR_UNION: + case TYPE_DISTINCT: UNREACHABLE case TYPE_FUNC: case TYPE_ARRAY: diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index f34986273..51b08b2b6 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -116,6 +116,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ERR: case DECL_ENUM: case DECL_TYPEDEF: + case DECL_DISTINCT: type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc)); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 31254cc23..03fda9a84 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -36,21 +36,22 @@ static SymTab symtab; const char *attribute_list[NUMBER_OF_ATTRIBUTES]; -const char *kw_main; -const char *kw_sizeof; -const char *kw_alignof; const char *kw_align; -const char *kw_offsetof; -const char *kw_nameof; -const char *kw_qnameof; +const char *kw_alignof; +const char *kw_distinct; +const char *kw_inline; const char *kw_kindof; const char *kw_len; -const char *kw_inline; +const char *kw_main; +const char *kw_nameof; +const char *kw_offsetof; const char *kw_ordinal; -const char *kw___round; +const char *kw_qnameof; +const char *kw_sizeof; const char *kw___ceil; -const char *kw___trunc; +const char *kw___round; const char *kw___sqrt; +const char *kw___trunc; void symtab_init(uint32_t capacity) { @@ -84,21 +85,22 @@ void symtab_init(uint32_t capacity) // Init some constant idents TokenType type = TOKEN_IDENT; #define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type) - kw_inline = KW_DEF("inline"); - kw_main = KW_DEF("main"); - kw_sizeof = KW_DEF("sizeof"); + kw_align = KW_DEF("align"); kw_alignof = KW_DEF("alignof"); - kw_offsetof = KW_DEF("offsetof"); - kw_nameof = KW_DEF("nameof"); - kw_qnameof = KW_DEF("qnameof"); + kw_distinct = KW_DEF("distinct"); + kw_inline = KW_DEF("inline"); kw_kindof = KW_DEF("kindof"); kw_len = KW_DEF("len"); - kw_align = KW_DEF("align"); + kw_main = KW_DEF("main"); + kw_nameof = KW_DEF("nameof"); + kw_offsetof = KW_DEF("offsetof"); kw_ordinal = KW_DEF("ordinal"); + kw_qnameof = KW_DEF("qnameof"); + kw_sizeof = KW_DEF("sizeof"); + kw___ceil = KW_DEF("__ceil"); kw___round = KW_DEF("__round"); kw___sqrt = KW_DEF("__sqrt"); kw___trunc = KW_DEF("__trunc"); - kw___ceil = KW_DEF("__ceil"); attribute_list[ATTRIBUTE_INLINE] = kw_inline; attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline"); diff --git a/src/compiler/types.c b/src/compiler/types.c index f9d8a5687..6a234b9f8 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -97,6 +97,7 @@ const char *type_to_error_string(Type *type) case ALL_FLOATS: case TYPE_UNION: case TYPE_ERRTYPE: + case TYPE_DISTINCT: return type->name; case TYPE_FUNC: { @@ -173,6 +174,8 @@ ByteSize type_size(Type *type) { switch (type->type_kind) { + case TYPE_DISTINCT: + return type_size(type->decl->distinct_decl.base_type); case TYPE_VECTOR: return type_size(type->vector.base) * type->vector.len; case TYPE_COMPLEX: @@ -316,6 +319,8 @@ bool type_is_abi_aggregate(Type *type) { case TYPE_POISONED: return false; + case TYPE_DISTINCT: + return type_is_abi_aggregate(type->decl->distinct_decl.base_type); case TYPE_TYPEDEF: return type_is_abi_aggregate(type->canonical); case ALL_FLOATS: @@ -462,6 +467,8 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) *base = type->complex; *elements = 2; break; + case TYPE_DISTINCT: + return type_is_homogenous_aggregate(type->decl->distinct_decl.base_type, base, elements); case TYPE_FXX: case TYPE_POISONED: case TYPE_IXX: @@ -602,6 +609,8 @@ AlignSize type_abi_alignment(Type *type) TODO case TYPE_VOID: return 1; + case TYPE_DISTINCT: + return type_abi_alignment(type->decl->distinct_decl.base_type); case TYPE_TYPEDEF: return type_abi_alignment(type->canonical); case TYPE_ENUM: @@ -752,6 +761,7 @@ bool type_is_user_defined(Type *type) Type *type_get_indexed_type(Type *type) { + RETRY: switch (type->type_kind) { case TYPE_POINTER: @@ -762,13 +772,15 @@ Type *type_get_indexed_type(Type *type) return type->array.base; case TYPE_STRING: return type_char; + case TYPE_DISTINCT: + type = type->decl->distinct_decl.base_type; + goto RETRY; + case TYPE_TYPEDEF: + type = type->canonical; + goto RETRY; default: - break; + return NULL; } - Type *canonical = type->canonical; - if (canonical != type) return type_get_indexed_type(type); - return NULL; - } @@ -942,6 +954,9 @@ bool type_is_scalar(Type *type) case TYPE_VARARRAY: case TYPE_COMPLEX: return true; + case TYPE_DISTINCT: + type = type->decl->distinct_decl.base_type; + goto RETRY; case TYPE_TYPEDEF: type = type->canonical; goto RETRY; @@ -1142,10 +1157,17 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_TYPEINFO: case TYPE_MEMBER: return NULL; - case ALL_INTS: - if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical); + case TYPE_IXX: + if (other->type_kind == TYPE_DISTINCT && type_is_numeric(other->decl->distinct_decl.base_type)) return other; FALLTHROUGH; - case ALL_FLOATS: + case ALL_SIGNED_INTS: + case ALL_UNSIGNED_INTS: + if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical); + return type_find_max_num_type(type, other); + case TYPE_FXX: + if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other; + FALLTHROUGH; + case ALL_REAL_FLOATS: return type_find_max_num_type(type, other); case TYPE_POINTER: return type_find_max_ptr_type(type, other); @@ -1156,11 +1178,12 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_ERRTYPE: if (other->type_kind == TYPE_ERRTYPE) return type_error; return NULL; + case TYPE_DISTINCT: + return NULL; case TYPE_FUNC: case TYPE_UNION: case TYPE_ERR_UNION: case TYPE_TYPEID: - return NULL; case TYPE_STRUCT: TODO case TYPE_TYPEDEF: diff --git a/test/test_suite/distinct/distinct_struct.c3 b/test/test_suite/distinct/distinct_struct.c3 new file mode 100644 index 000000000..0b045896a --- /dev/null +++ b/test/test_suite/distinct/distinct_struct.c3 @@ -0,0 +1,28 @@ + +struct Struct +{ + int x; + double y; +} + +typedef Struct as distinct Foo; + +struct Struct2 +{ + Foo f; + int d; + struct bar + { + Foo x; + } +} +Foo f = { 1, 1.0 }; + +func void test(int x) +{ + Struct s = { 1, 2.0 }; + Foo f2 = cast(s as Foo); + Foo f3 = { .x = 1 }; + Struct2 s2 = { .f = { 1, 2.0 } }; + Struct2 s3 = { .bar.x.y = 3.0 }; +} \ No newline at end of file diff --git a/test/test_suite/distinct/distinct_struct_array.c3 b/test/test_suite/distinct/distinct_struct_array.c3 new file mode 100644 index 000000000..da6e833b1 --- /dev/null +++ b/test/test_suite/distinct/distinct_struct_array.c3 @@ -0,0 +1,20 @@ +module test; + +typedef int as distinct Foo; + +struct Struct +{ + Foo x; + int y; +} + +typedef Struct as distinct Struct2; +typedef Struct2[3] as distinct StructArr; + +func void test(int x) +{ + StructArr z = { { .x = 1 }, { .y = x }, { 1, 2 }}; + usize xr = z.sizeof; + usize len = z.len; + Foo zz = z[2].x; +} diff --git a/test/test_suite/distinct/distinct_union.c3 b/test/test_suite/distinct/distinct_union.c3 new file mode 100644 index 000000000..95f210af6 --- /dev/null +++ b/test/test_suite/distinct/distinct_union.c3 @@ -0,0 +1,34 @@ +module test; + +union Union +{ + int x; + double y; +} + +typedef Union as distinct Foo; + +union Union2 +{ + Foo f; + int d; + struct bar + { + Foo x; + } +} +Foo f = { .x = 1 }; + +typedef Union2 as distinct Union3; + +typedef Union3[3] as distinct UnionArr; + +func void test(int x) +{ + Union s = { .y = 2.0 }; + Foo f2 = cast(s as Foo); + Foo f3 = { .x = 1 }; + Union2 s2 = { .f = { .y = 1 } }; + Union2 s3 = { .bar.x.y = 3.0 }; + UnionArr a = { [0].bar.x.x = 100 }; +} diff --git a/test/test_suite/distinct/test_errors.c3 b/test/test_suite/distinct/test_errors.c3 new file mode 100644 index 000000000..01ff9ee8c --- /dev/null +++ b/test/test_suite/distinct/test_errors.c3 @@ -0,0 +1,11 @@ +module test; + +typedef int as distinct Int2; + +func void test() +{ + Int2 a = 1; + a = a + 1; + int b; + a = b; // #error: Cannot implicitly cast 'int' to 'Int2' +} \ No newline at end of file diff --git a/test/test_suite/distinct/test_ops_on_int.c3 b/test/test_suite/distinct/test_ops_on_int.c3 new file mode 100644 index 000000000..b6b52a90f --- /dev/null +++ b/test/test_suite/distinct/test_ops_on_int.c3 @@ -0,0 +1,29 @@ +module test; + +typedef int as distinct Foo; + +func int test1() +{ + Foo x = 1; + x += 2; + Foo y = 3; + y = x + y; + int z = 4; + y += cast(z as Foo); + y = y << z; + y = y >> z; + y = y + y; + y = y - y; + y = y * y; + y = y / y; + y = y & y; + y = y ^ y; + y = y | y; + bool a1 = y != y; + bool a2 = y < y; + bool a3 = y <= y; + bool a4 = y == y; + y = y == 1 ? 1 : y; + y = y < (y + 1) ? 1 : y; + return cast(y as int); +} diff --git a/test/test_suite/distinct/test_ops_on_struct.c3 b/test/test_suite/distinct/test_ops_on_struct.c3 new file mode 100644 index 000000000..3908fc55d --- /dev/null +++ b/test/test_suite/distinct/test_ops_on_struct.c3 @@ -0,0 +1,24 @@ +module test; + +struct Struct +{ + int x; + double y; +} + +typedef Struct as distinct Foo; + +struct Struct2 +{ + Foo f; + int d; +} +Foo f = { 1, 1.0 }; + +func void test(int x) +{ + Struct s = { 1, 2.0 }; + Foo f2 = cast(s as Foo); + Foo f3 = { .x = 1 }; + Struct2 s2 = { .f = { 1, 2.0 } }; +} \ No newline at end of file diff --git a/test/test_suite/union/union_codegen_overwrite_call.c3t b/test/test_suite/union/union_codegen_overwrite_call.c3t index 651e4d60a..4e24777d7 100644 --- a/test/test_suite/union/union_codegen_overwrite_call.c3t +++ b/test/test_suite/union/union_codegen_overwrite_call.c3t @@ -21,10 +21,11 @@ func void test() entry: %b = alloca %test.UnionB, align 8 -%1 = bitcast %test.UnionB* %b to i32* -%2 = call i32 @bar() -store i32 %2, i32* %1, align 4 -%3 = bitcast %test.UnionB* %b to %test.b* -%4 = bitcast %test.b* %3 to i8* -call void @llvm.memset.p0i8.i64(i8* %4, i8 0, i64 4, i1 false) +%0 = bitcast %test.UnionB* %b to i32* +%1 = call i32 @bar() +store i32 %1, i32* %0, align 4 +%2 = bitcast %test.UnionB* %b to %test.b* +%3 = bitcast %test.b* %2 to i8* +call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false) ret void +