From 13bb2b6690fc369738bfd37934b6d4465bf3ba3b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 27 Jun 2025 01:48:21 +0200 Subject: [PATCH] Const Enums From / to ordinal using casts is back. Add "--use-old-enums", deprecating lookup. --- lib/std/atomic.c3 | 1 + lib/std/core/types.c3 | 29 +- lib/std/hash/sha512.c3 | 2 +- lib/std/io/formatter.c3 | 1 + lib/std/io/formatter_private.c3 | 3 +- lib/std/net/socket.c3 | 4 +- releasenotes.md | 5 + src/build/build.h | 2 + src/build/build_options.c | 6 + src/build/builder.c | 2 +- src/compiler/abi/c_abi_x86.c | 19 +- src/compiler/ast.c | 5 + src/compiler/c_codegen.c | 2 + src/compiler/codegen_internal.h | 3 +- src/compiler/compiler_internal.h | 119 ++- src/compiler/context.c | 2 + src/compiler/copying.c | 23 +- src/compiler/enums.h | 30 +- src/compiler/expr.c | 5 +- src/compiler/headers.c | 3 + src/compiler/json_output.c | 1 + src/compiler/llvm_codegen.c | 2 + src/compiler/llvm_codegen_debug_info.c | 48 +- src/compiler/llvm_codegen_expr.c | 14 +- src/compiler/llvm_codegen_internal_impl.h | 15 + src/compiler/llvm_codegen_stmt.c | 4 +- src/compiler/llvm_codegen_type.c | 8 +- src/compiler/number.c | 14 +- src/compiler/parse_global.c | 186 +++-- src/compiler/sema_casts.c | 268 ++++--- src/compiler/sema_decls.c | 128 +++- src/compiler/sema_expr.c | 202 +++-- src/compiler/sema_internal.h | 1 + src/compiler/sema_liveness.c | 6 +- src/compiler/sema_name_resolution.c | 1 + src/compiler/sema_stmts.c | 12 +- src/compiler/sema_types.c | 1 + src/compiler/semantic_analyser.c | 1 + src/compiler/types.c | 43 +- test/test_suite/abi/small_struct_x64.c3t | 2 +- test/test_suite/any/any_in_any.c3t | 4 +- test/test_suite/any/variant_test.c3t | 2 +- .../test_suite/arrays/complex_array_const.c3t | 2 +- .../attributes/attribute_no_infer_type.c3t | 2 +- .../attributes/user_defined_attributes.c3t | 2 +- test/test_suite/cast/invalid_enum_casts.c3 | 4 +- test/test_suite/clang/2002-07.c3t | 10 +- .../compile_time/ct_subscript_inc.c3t | 4 +- .../compile_time/untyped_conversions.c3t | 14 +- .../compile_time_introspection/paramsof.c3t | 4 +- .../compile_time_introspection/parentof.c3t | 4 +- .../compile_time_introspection/qnameof.c3t | 2 +- .../concurrency/atomic_load_store_debug.c3t | 2 +- test/test_suite/dynamic/dynamic_tracing.c3t | 6 +- test/test_suite/dynamic/inherit_linux.c3t | 2 +- test/test_suite/dynamic/inherit_macos.c3t | 2 +- .../dynamic/overlapping_function_linux.c3t | 2 +- .../dynamic/overlapping_function_macos.c3t | 2 +- .../enum_associated_values_other.c3t | 2 +- .../enumerations/enum_cast_error.c3 | 9 +- test/test_suite/enumerations/enum_const.c3t | 701 ++++++++++++++++++ .../enumerations/enum_conversions.c3t | 8 +- test/test_suite/enumerations/enum_lookup.c3t | 3 +- .../enumerations/enum_signed_cast_swap.c3t | 2 +- .../enumerations/inline_enum_compare.c3t | 3 +- .../enumerations/inline_enum_size.c3 | 2 + test/test_suite/enumerations/inline_enums.c3t | 4 +- test/test_suite/enumerations/lookup_errors.c3 | 21 +- .../errors/optional_taddr_and_access.c3t | 2 +- .../expressions/casts/cast_enum_to_various.c3 | 2 +- .../expressions/optional_ternary.c3t | 2 +- .../test_suite/expressions/pointer_access.c3t | 8 +- .../func_ptr_conversions_and_names.c3t | 6 +- test/test_suite/functions/test_regression.c3t | 10 +- .../functions/test_regression_mingw.c3t | 10 +- test/test_suite/generic/nested_typedef.c3t | 4 +- .../initializer_lists/general_tests.c3t | 4 +- test/test_suite/initializer_lists/statics.c3t | 4 +- .../initializer_lists/subarrays.c3t | 4 +- test/test_suite/macros/userland_bitcast.c3t | 2 +- .../statements/custom_foreach_with_ref.c3t | 2 +- .../statements/foreach_custom_macro.c3t | 2 +- test/test_suite/statements/switch_errors.c3 | 6 +- test/test_suite/struct/nested_struct_init.c3t | 12 +- test/test_suite/struct/struct_as_value.c3t | 2 +- test/test_suite/struct/struct_codegen.c3t | 2 +- .../struct/struct_const_construct_simple.c3t | 2 +- .../switch/switch_in_defer_macro.c3t | 6 +- test/test_suite/types/enum_inference.c3 | 6 +- .../test_suite/visibility/export_property.c3t | 4 +- test/unit/stdlib/collections/map.c3 | 2 +- test/unit/stdlib/time/format.c3 | 2 +- 92 files changed, 1716 insertions(+), 438 deletions(-) create mode 100644 test/test_suite/enumerations/enum_const.c3t diff --git a/lib/std/atomic.c3 b/lib/std/atomic.c3 index 1f9ab1833..1e931dcf8 100644 --- a/lib/std/atomic.c3 +++ b/lib/std/atomic.c3 @@ -175,6 +175,7 @@ macro bool is_native_atomic_type($Type) $case BOOL: return true; $case DISTINCT: + $case CONST_ENUM: return is_native_atomic_type($Type.inner); $default: return false; diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 0342f4a5b..2067fb3a9 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -96,13 +96,18 @@ macro bool is_subtype_of($Type, $OtherType) } macro bool is_numerical($Type) { - var $kind = $Type.kindof; - $if $kind == TypeKind.DISTINCT: - return is_numerical($Type.inner); - $else - return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT - || $kind == TypeKind.VECTOR; - $endif + $switch $Type.kindof: + $case DISTINCT: + $case CONST_ENUM: + return is_numerical($Type.inner); + $case SIGNED_INT: + $case UNSIGNED_INT: + $case FLOAT: + $case VECTOR: + return true; + $default: + return false; + $endswitch } fn bool TypeKind.is_int(kind) @inline @@ -158,7 +163,7 @@ macro bool is_unsigned($Type) @const macro typeid flat_type($Type) @const { - $if $Type.kindof == DISTINCT: + $if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM: return flat_type($Type.inner); $else return $Type.typeid; @@ -167,7 +172,7 @@ macro typeid flat_type($Type) @const macro TypeKind flat_kind($Type) @const { - $if $Type.kindof == DISTINCT: + $if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM: return flat_type($Type.inner); $else return $Type.kindof; @@ -191,8 +196,8 @@ macro bool is_flat_intlike($Type) @const $case UNSIGNED_INT: return true; $case VECTOR: - return is_flat_intlike($Type.inner); $case DISTINCT: + $case CONST_ENUM: return is_flat_intlike($Type.inner); $default: return false; @@ -246,7 +251,7 @@ macro bool is_vector($Type) @const macro typeid inner_type($Type) @const { - $if $Type.kindof == TypeKind.DISTINCT: + $if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM: return inner_type($Type.inner); $else return $Type.typeid; @@ -302,6 +307,7 @@ macro lower_to_atomic_compatible_type($Type) @const $case UNSIGNED_INT: return $Type.typeid; $case DISTINCT: + $case CONST_ENUM: return lower_to_atomic_compatible_type($Type.inner); $case FLOAT: $switch $Type: @@ -375,6 +381,7 @@ enum TypeKind : char FAULT, ANY, ENUM, + CONST_ENUM, STRUCT, UNION, BITSTRUCT, diff --git a/lib/std/hash/sha512.c3 b/lib/std/hash/sha512.c3 index d802f3fd0..35599a497 100644 --- a/lib/std/hash/sha512.c3 +++ b/lib/std/hash/sha512.c3 @@ -61,7 +61,7 @@ const ulong[80] K @local = { // See: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf // All truncation types are simple to add onto the base SHA512 implementation at a (near) future time. -enum HashTruncationType : uint (inline uint truncation_width, ulong[8] initial_state) +enum HashTruncationType : uint (uint truncation_width, ulong[8] initial_state) { SHA512 = { 512, diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index 6b556c23a..491a9ba60 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -205,6 +205,7 @@ fn usz? Formatter.out_str(&self, any arg) @private } self.width = 0; return self.out_substr("0x")! + self.ntoa_any(arg, 16); + case CONST_ENUM: case DISTINCT: if (arg.type == String.typeid) { diff --git a/lib/std/io/formatter_private.c3 b/lib/std/io/formatter_private.c3 index 2b6f1750c..5291355f3 100644 --- a/lib/std/io/formatter_private.c3 +++ b/lib/std/io/formatter_private.c3 @@ -44,6 +44,7 @@ fn uint128? int_from_any(any arg, bool *is_neg) @private *is_neg = false; return (uint128)(uptr)*(void**)arg.ptr; case DISTINCT: + case CONST_ENUM: return int_from_any(arg.as_inner(), is_neg); default: break; @@ -94,7 +95,7 @@ fn FloatType? float_from_any(any arg) @private $if env::F128_SUPPORT: if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr); $endif - if (arg.type.kindof == TypeKind.DISTINCT) + if (arg.type.kindof == DISTINCT || arg.type.kindof == CONST_ENUM) { return float_from_any(arg.as_inner()); } diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index 0398eb6a5..27b8b1f9b 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -167,7 +167,7 @@ fn usz? Socket.peek(&self, char[] bytes) @dynamic return (usz)n; } -enum SocketShutdownHow : (inline CInt native_value) +enum SocketShutdownHow : (CInt native_value) { RECEIVE = @select(env::WIN32, libc::SD_RECEIVE, libc::SHUT_RD), SEND = @select(env::WIN32, libc::SD_SEND, libc::SHUT_WR), @@ -176,7 +176,7 @@ enum SocketShutdownHow : (inline CInt native_value) fn void? Socket.shutdown(&self, SocketShutdownHow how) { - if (libc::shutdown(self.sock, how) < 0) + if (libc::shutdown(self.sock, how.native_value) < 0) { return os::socket_error()?; } diff --git a/releasenotes.md b/releasenotes.md index b74a77cb8..46ea7d8a3 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -3,7 +3,12 @@ ## 0.7.4 Change list ### Changes / improvements +- Added const enums: `enum Foo : const`. Behaves like C enums but may be any type. +- Casting to / from an enum is now possible again. No need to use `.ordinal` and `.from_ordinal`. +- Inline associated enum values are deprecated, use `--use-old-enums` to re-enable them. + ### Fixes + ### Stdlib changes ## 0.7.3 Change list diff --git a/src/build/build.h b/src/build/build.h index 154c28060..fd7c95979 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -553,6 +553,7 @@ typedef struct BuildOptions_ bool run_once; bool suppress_run; bool old_slice_copy; + bool old_enums; int verbosity_level; const char *panicfn; const char *benchfn; @@ -687,6 +688,7 @@ typedef struct bool silence_deprecation; bool print_stats; bool old_slice_copy; + bool old_enums; int build_threads; TrustLevel trust_level; OptimizationSetting optsetting; diff --git a/src/build/build_options.c b/src/build/build_options.c index e3b0e590d..b58dc69d3 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -131,6 +131,7 @@ static void usage(bool full) print_opt("--show-backtrace=", "Show detailed backtrace on segfaults."); print_opt("--lsp", "Emit data about errors suitable for a LSP."); print_opt("--use-old-slice-copy", "Use the old slice copy semantics."); + print_opt("--use-old-enums", "Use the old enum syntax and semantics."); } PRINTF(""); print_opt("-g", "Emit debug info."); @@ -743,6 +744,11 @@ static void parse_option(BuildOptions *options) options->old_slice_copy = true; return; } + if (match_longopt("use-new-enums")) + { + options->old_enums = true; + return; + } if (match_longopt("test-filter")) { if (at_end() || next_is_opt()) FAIL_WITH_ERR_LONG("error: --test-filter needs an argument."); diff --git a/src/build/builder.c b/src/build/builder.c index 798f01f2a..d4107a5a7 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -344,7 +344,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * target->backend = options->backend; target->old_slice_copy = options->old_slice_copy; - + target->old_enums = options->old_enums; // Remove feature flags FOREACH(const char *, remove_feature, options->removed_feature_names) { diff --git a/src/compiler/abi/c_abi_x86.c b/src/compiler/abi/c_abi_x86.c index 3f1b20a74..0b4094299 100644 --- a/src/compiler/abi/c_abi_x86.c +++ b/src/compiler/abi/c_abi_x86.c @@ -107,19 +107,20 @@ static bool x86_should_return_type_in_reg(Type *type) switch (type->type_kind) { - case TYPE_VECTOR: - case TYPE_VOID: - case TYPE_FUNC_RAW: - case TYPE_TYPEDEF: - case TYPE_DISTINCT: - case TYPE_ENUM: - case TYPE_TYPEID: + case CT_TYPES: case TYPE_ANYFAULT: case TYPE_BITSTRUCT: - case CT_TYPES: - case TYPE_OPTIONAL: + case TYPE_DISTINCT: + case TYPE_ENUM: case TYPE_FLEXIBLE_ARRAY: + case TYPE_FUNC_RAW: case TYPE_INTERFACE: + case TYPE_OPTIONAL: + case TYPE_CONST_ENUM: + case TYPE_TYPEDEF: + case TYPE_TYPEID: + case TYPE_VECTOR: + case TYPE_VOID: UNREACHABLE case ALL_INTS: case ALL_FLOATS: diff --git a/src/compiler/ast.c b/src/compiler/ast.c index cf4664c9c..f1c991300 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -67,6 +67,9 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type) case DECL_ENUM: kind = TYPE_ENUM; break; + case DECL_CONST_ENUM: + kind = TYPE_CONST_ENUM; + break; case DECL_DISTINCT: kind = TYPE_DISTINCT; break; @@ -115,6 +118,7 @@ const char *decl_to_a_name(Decl *decl) case DECL_ALIAS: case DECL_TYPEDEF: return "an alias"; case DECL_DISTINCT: return "a distinct type"; case DECL_ENUM: return "an enum"; + case DECL_CONST_ENUM: return "a raw enum"; case DECL_ENUM_CONSTANT: return "an enum value"; case DECL_ERASED: return "an erased declaration"; case DECL_FAULT: return "a fault"; @@ -366,6 +370,7 @@ bool decl_is_externally_visible(Decl *decl) return decl->is_external_visible || decl->visibility == VISIBLE_PUBLIC || decl->is_export; } + bool decl_is_global(Decl *ident) { switch (ident->var.kind) diff --git a/src/compiler/c_codegen.c b/src/compiler/c_codegen.c index 7b74c0588..75654010f 100644 --- a/src/compiler/c_codegen.c +++ b/src/compiler/c_codegen.c @@ -95,6 +95,7 @@ static const char *c_type_name(GenContext *c, Type *type) case TYPE_FUNC_RAW: case TYPE_TYPEDEF: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_UNTYPED_LIST: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: @@ -147,6 +148,7 @@ static bool c_emit_type_decl(GenContext *c, Type *type) case TYPE_FUNC_RAW: case TYPE_TYPEDEF: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_UNTYPED_LIST: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index c3b90cecf..a9e9b8e86 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -32,8 +32,9 @@ static inline Type *type_lowering(Type *type) case TYPE_DISTINCT: type = type->decl->distinct->type; continue; + case TYPE_CONST_ENUM: case TYPE_ENUM: - type = type->decl->enums.type_info->type; + type = enum_inner_type(type); continue; case TYPE_FUNC_PTR: { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index bca8bb1ce..9dfdae4f6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -478,9 +478,16 @@ typedef struct VarDecl_ typedef struct { - Expr **args; - uint32_t ordinal; - DeclId parent; + bool is_raw; + union + { + struct + { + Expr **associated; + uint32_t inner_ordinal; + }; + Expr *value; + }; } EnumConstantDecl; @@ -1162,6 +1169,7 @@ struct Expr_ ExprCtCall ct_call_expr; // 24 ExprIdentifierRaw ct_ident_expr; // 24 Decl *decl_expr; // 8 + Decl *iota_decl_expr; // 8 Expr **designated_init_list; // 8 ExprDesignator designator_expr; // 16 ExprNamedArgument named_argument_expr; @@ -2711,6 +2719,7 @@ INLINE bool type_may_implement_interface(Type *type) case TYPE_STRUCT: case TYPE_UNION: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_DISTINCT: case TYPE_BITSTRUCT: return true; @@ -2809,6 +2818,7 @@ INLINE bool type_is_atomic(Type *type_flat) case ALL_SIGNED_INTS: case ALL_FLOATS: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_BOOL: @@ -2905,6 +2915,11 @@ INLINE const char *type_invalid_storage_type_name(Type *type) } } +INLINE Type *enum_inner_type(Type *enum_type) +{ + assert(enum_type->type_kind == TYPE_ENUM || enum_type->type_kind == TYPE_CONST_ENUM); + return enum_type->decl->enums.type_info->type; +} INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span) { @@ -2967,9 +2982,9 @@ INLINE Type *type_flatten_for_bitstruct(Type *type) { type = type->decl->distinct->type; } - if (type->type_kind == TYPE_ENUM) + if (type->type_kind == TYPE_ENUM || type->type_kind == TYPE_CONST_ENUM) { - type = type->decl->enums.type_info->type->canonical; + type = enum_inner_type(type)->canonical; goto RETRY; } return type; @@ -2986,7 +3001,8 @@ static inline Type *type_base(Type *type) type = type->decl->distinct->type; break; case TYPE_ENUM: - type = type->decl->enums.type_info->type; + case TYPE_CONST_ENUM: + type = enum_inner_type(type); break; case TYPE_OPTIONAL: type = type->optional; @@ -2999,22 +3015,40 @@ static inline Type *type_base(Type *type) } } +INLINE bool type_is_distinct_like(Type *type) +{ + TypeKind kind = type->type_kind; + return kind == TYPE_DISTINCT || kind == TYPE_CONST_ENUM; +} + +static inline Type *type_inline(Type *type) +{ + assert(type_is_distinct_like(type)); + return type->type_kind == TYPE_CONST_ENUM ? type->decl->enums.type_info->type : type->decl->distinct->type; +} + + static inline Type *type_flat_distinct_inline(Type *type) { - do + while (1) { type = type->canonical; - if (type->type_kind != TYPE_DISTINCT) break; - Decl *decl = type->decl; - if (!decl->is_substruct) break; - type = decl->distinct->type; - } while (1); - return type; + switch (type->type_kind) + { + case TYPE_DISTINCT: + case TYPE_CONST_ENUM: + if (!type->decl->is_substruct) return type; + type = type_inline(type); + break; + default: + return type; + } + } } static inline Type *type_flat_distinct_enum_inline(Type *type) { - do + while (1) { type = type->canonical; Decl *decl; @@ -3022,13 +3056,18 @@ static inline Type *type_flat_distinct_enum_inline(Type *type) { case TYPE_DISTINCT: decl = type->decl; - if (!decl->is_substruct) break; + if (!decl->is_substruct) return type;; type = decl->distinct->type; continue; + case TYPE_CONST_ENUM: + decl = type->decl; + if (!decl->is_substruct) return type; + type = decl->enums.type_info->type; + continue; case TYPE_ENUM: decl = type->decl; - if (!decl->is_substruct) break; - if (decl->enums.inline_value) + if (!decl->is_substruct) return type; + if (!compiler.build.old_enums || decl->enums.inline_value) { type = decl->enums.type_info->type; continue; @@ -3036,11 +3075,9 @@ static inline Type *type_flat_distinct_enum_inline(Type *type) type = decl->enums.parameters[decl->enums.inline_index]->type; continue; default: - break; + return type; } - break; - } while (1); - return type; + } } static inline Type *type_flatten_to_int(Type *type) @@ -3059,6 +3096,9 @@ static inline Type *type_flatten_to_int(Type *type) case TYPE_BITSTRUCT: type = type->decl->strukt.container_type->type; break; + case TYPE_CONST_ENUM: + type = type->decl->enums.type_info->type; + break; case TYPE_ENUM: return type; case TYPE_VECTOR: @@ -3080,6 +3120,9 @@ static inline CanonicalType *type_flatten(Type *type) type = type->canonical; switch (type->type_kind) { + case TYPE_CONST_ENUM: + type = enum_inner_type(type); + break; case TYPE_DISTINCT: type = type->decl->distinct->type; break; @@ -3108,6 +3151,10 @@ static inline Type *type_flatten_no_export(Type *type) if (type->decl->is_export) return type; type = type->decl->distinct->type; break; + case TYPE_CONST_ENUM: + if (type->decl->is_export) return type; + type = enum_inner_type(type); + break; case TYPE_OPTIONAL: type = type->optional; break; @@ -3179,28 +3226,30 @@ INLINE bool type_is_number(Type *type) return (kind >= TYPE_I8) && (kind <= TYPE_FLOAT_LAST); } + static inline Type *type_flat_for_arithmethics(Type *type) { while (true) { type = type->canonical; + Type *inner; switch (type->type_kind) { case TYPE_OPTIONAL: type = type->optional; continue; + case TYPE_CONST_ENUM: case TYPE_DISTINCT: + inner = type_inline(type); + if (type->decl->is_substruct) + { + type = inner; + continue; + } break; default: return type; } - Decl *decl = type->decl; - Type *inner = decl->distinct->type; - if (decl->is_substruct) - { - type = inner; - continue; - } inner = type_flat_for_arithmethics(inner); if (type_is_number_or_bool(inner)) return inner; return type; @@ -3552,6 +3601,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc) case EXPR_MEMBER_SET: case EXPR_RVALUE: case EXPR_CT_SUBSCRIPT: + case EXPR_IOTA_DECL: break; } } @@ -3884,6 +3934,19 @@ INLINE void expr_rewrite_ext_trunc(Expr *expr, Type *type, bool is_signed) expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } +INLINE void expr_rewrite_const_integer(Expr *expr, Type *type, Int128 i) +{ + expr->expr_kind = EXPR_CONST; + expr->type = type; + expr->resolve_status = RESOLVE_DONE; + expr->const_expr.ixx = (Int) { + .i = i, + .type = type_flatten_to_int(type)->type_kind + }; + expr->const_expr.is_character = false; + expr->const_expr.const_kind = CONST_INTEGER; +} + INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v) { expr->expr_kind = EXPR_CONST; diff --git a/src/compiler/context.c b/src/compiler/context.c index a18dccbc0..d6296369f 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -172,6 +172,7 @@ void decl_register(Decl *decl) case DECL_BITSTRUCT: case DECL_DISTINCT: case DECL_ENUM: + case DECL_CONST_ENUM: case DECL_STRUCT: case DECL_TYPEDEF: case DECL_UNION: @@ -253,6 +254,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) vec_add(unit->generic_defines, decl); decl_register(decl); break; + case DECL_CONST_ENUM: case DECL_ENUM: ASSERT(decl->name); vec_add(unit->enums, decl); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 78bf8338f..bfa140b65 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -406,6 +406,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) MACRO_COPY_DECL(expr->catch_expr.decl); MACRO_COPY_EXPR_LIST(expr->catch_expr.exprs); return expr; + case EXPR_IOTA_DECL: + fixup_decl(c, &expr->iota_decl_expr); + return expr; case EXPR_IDENTIFIER: { Decl *var = expr->ident_expr; @@ -1030,6 +1033,13 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) break; case DECL_FAULT: break; + case DECL_CONST_ENUM: + copy_decl_type(copy); + MACRO_COPY_TYPE_LIST(copy->interfaces); + MACRO_COPY_DECL_LIST(copy->methods); + MACRO_COPY_TYPE(copy->enums.type_info); + MACRO_COPY_DECL_LIST(copy->enums.values); + break; case DECL_ENUM: copy_decl_type(copy); MACRO_COPY_TYPE_LIST(copy->interfaces); @@ -1072,8 +1082,17 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) // Note that the ast id should be patched by the parent. return copy; case DECL_ENUM_CONSTANT: - fixup_declid(c, ©->enum_constant.parent); - MACRO_COPY_EXPR_LIST(copy->enum_constant.args); + if (copy->enum_constant.is_raw) + { + MACRO_COPY_EXPR_LIST(copy->enum_constant.associated); + } + else + { + if (copy->resolve_status != RESOLVE_DONE) + { + MACRO_COPY_EXPR(copy->enum_constant.value); + } + } break; case DECL_TYPEDEF: copy_decl_type(copy); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index de8956315..48255a1b4 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -636,6 +636,7 @@ typedef enum CONV_ANY, CONV_INTERFACE, CONV_ENUM, + CONV_RAW_ENUM, CONV_FUNC, CONV_TYPEID, CONV_ANYFAULT, @@ -679,6 +680,7 @@ typedef enum DECL_LABEL, DECL_MACRO, DECL_INTERFACE, + DECL_CONST_ENUM, DECL_STRUCT, DECL_TYPEDEF, DECL_UNION, @@ -771,6 +773,7 @@ typedef enum EXPR_INITIALIZER_LIST, EXPR_INT_TO_FLOAT, EXPR_INT_TO_PTR, + EXPR_IOTA_DECL, EXPR_PTR_TO_INT, EXPR_LAMBDA, EXPR_LAST_FAULT, @@ -850,17 +853,18 @@ typedef enum INTROSPECT_TYPE_ANYFAULT = 6, INTROSPECT_TYPE_ANY = 7, INTROSPECT_TYPE_ENUM = 8, - INTROSPECT_TYPE_STRUCT = 9, - INTROSPECT_TYPE_UNION = 10, - INTROSPECT_TYPE_BITSTRUCT = 11, - INTROSPECT_TYPE_FUNC = 12, - INTROSPECT_TYPE_OPTIONAL = 13, - INTROSPECT_TYPE_ARRAY = 14, - INTROSPECT_TYPE_SLICE = 15, - INTROSPECT_TYPE_VECTOR = 16, - INTROSPECT_TYPE_DISTINCT = 17, - INTROSPECT_TYPE_POINTER = 18, - INTROSPECT_TYPE_INTERFACE = 19, + INTROSPECT_TYPE_CONST_ENUM = 9, + INTROSPECT_TYPE_STRUCT = 10, + INTROSPECT_TYPE_UNION = 11, + INTROSPECT_TYPE_BITSTRUCT = 12, + INTROSPECT_TYPE_FUNC = 13, + INTROSPECT_TYPE_OPTIONAL = 14, + INTROSPECT_TYPE_ARRAY = 15, + INTROSPECT_TYPE_SLICE = 16, + INTROSPECT_TYPE_VECTOR = 17, + INTROSPECT_TYPE_DISTINCT = 18, + INTROSPECT_TYPE_POINTER = 19, + INTROSPECT_TYPE_INTERFACE = 20, } IntrospectType; typedef enum @@ -1370,6 +1374,7 @@ typedef enum TYPE_FUNC_PTR, TYPE_POINTER, TYPE_DISTINCT, + TYPE_CONST_ENUM, TYPE_ENUM, TYPE_FUNC_RAW, TYPE_STRUCT, @@ -1695,7 +1700,7 @@ static_assert(EXPR_LAST < 128, "Too many expression types"); #define LOWERED_TYPES CT_TYPES: case TYPE_ENUM: case TYPE_TYPEDEF: case TYPE_TYPEID: \ case TYPE_DISTINCT: case TYPE_ANYFAULT: case TYPE_BITSTRUCT: \ - case TYPE_OPTIONAL: case TYPE_INTERFACE + case TYPE_OPTIONAL: case TYPE_INTERFACE: case TYPE_CONST_ENUM #define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: case TYPE_UNTYPED_LIST: \ case TYPE_POISONED: case TYPE_MEMBER: case TYPE_WILDCARD @@ -1706,4 +1711,5 @@ case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128 #define UNRESOLVED_EXPRS EXPR_TRY_UNRESOLVED: case EXPR_ACCESS_UNRESOLVED: \ case EXPR_CATCH_UNRESOLVED: case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_CAST: \ case EXPR_TYPEID: case EXPR_EMBED: case EXPR_VASPLAT: case EXPR_OTHER_CONTEXT: \ + case EXPR_IOTA_DECL: \ case EXPR_GENERIC_IDENT: case EXPR_COMPOUND_LITERAL: case EXPR_MACRO_BODY: case EXPR_CT_SUBSCRIPT diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 30c403ef7..e06c72c86 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -139,7 +139,7 @@ bool expr_is_zero(Expr *expr) case CONST_BOOL: return !expr->const_expr.b; case CONST_ENUM: - return !expr->const_expr.enum_val->enum_constant.ordinal; + return !expr->const_expr.enum_val->enum_constant.inner_ordinal; case CONST_BYTES: case CONST_STRING: { @@ -671,6 +671,9 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) expr->const_expr.fault = NULL; expr->resolve_status = RESOLVE_DONE; break; + case TYPE_CONST_ENUM: + expr_rewrite_const_int(expr, type, 0); + return; case TYPE_ENUM: expr->const_expr.const_kind = CONST_ENUM; ASSERT(canonical->decl->resolve_status == RESOLVE_DONE); diff --git a/src/compiler/headers.c b/src/compiler/headers.c index d32009974..6117e8aed 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -164,6 +164,7 @@ static void header_print_type(HeaderContext *c, Type *type) case TYPE_STRUCT: case TYPE_UNION: case TYPE_ENUM: + case TYPE_CONST_ENUM: PRINTF("%s", decl_get_extname(type->decl)); return; case TYPE_BITSTRUCT: @@ -551,6 +552,8 @@ RETRY: case TYPE_ENUM: header_gen_enum(c, 0, type->decl); return; + case TYPE_CONST_ENUM: + TODO; case TYPE_FUNC_RAW: UNREACHABLE return; diff --git a/src/compiler/json_output.c b/src/compiler/json_output.c index 3cb44d0cf..c70857d34 100644 --- a/src/compiler/json_output.c +++ b/src/compiler/json_output.c @@ -101,6 +101,7 @@ static inline const char *decl_type_to_string(Decl *type) case DECL_STRUCT: return "struct"; case DECL_UNION: return "union"; case DECL_TYPEDEF: return "typedef"; + case DECL_CONST_ENUM: return "raw_enum"; case DECL_BODYPARAM: case DECL_DECLARRAY: case DECL_ERASED: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 9a0c2f52a..ebc930535 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1004,6 +1004,7 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl) case DECL_UNION: case DECL_ENUM: case DECL_BITSTRUCT: + case DECL_CONST_ENUM: llvm_get_typeid(context, decl->type); break; } @@ -1360,6 +1361,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl) case DECL_CT_ASSERT: case DECL_DISTINCT: case DECL_ENUM: + case DECL_CONST_ENUM: case DECL_ENUM_CONSTANT: case DECL_IMPORT: case DECL_LABEL: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 1c19408a4..674671589 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -21,6 +21,7 @@ static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_slice_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_any_type(GenContext *c, Type *type); static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope); +static LLVMMetadataRef llvm_debug_raw_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope); INLINE LLVMMetadataRef llvm_create_debug_location_with_inline(GenContext *c, unsigned row, unsigned col, LLVMMetadataRef scope) { @@ -341,7 +342,7 @@ static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetad bool is_unsigned = type_is_unsigned(enum_real_type); FOREACH(Decl *, enum_constant, enums) { - int64_t val = enum_constant->enum_constant.ordinal; + int64_t val = enum_constant->enum_constant.inner_ordinal; LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator( c->debug.builder, enum_constant->name, strlen(enum_constant->name), @@ -363,6 +364,49 @@ static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetad return real; } +static LLVMMetadataRef llvm_debug_raw_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope) +{ + Decl *decl = type->decl; + // FIXME TODO + + LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, "temp_enum", &decl->span, scope, LLVMDIFlagZero); + type->backend_debug_type = forward; + + Type *enum_real_type = decl->enums.type_info->type->canonical; + + LLVMMetadataRef *elements = NULL; + Decl **enums = decl->enums.values; + + bool is_unsigned = type_is_unsigned(enum_real_type); + /*if () + FOREACH(Decl *, enum_constant, enums) + { + // TODO, support other 128 + if (type_size(enum_real_type) > 8) + { + TODO + } + LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator( + c->debug.builder, + enum_constant->name, strlen(enum_constant->name), + enum_constant->enum_constant.const_value.low, + is_unsigned); + vec_add(elements, debug_info); + }*/ + + unsigned row = decl->span.row; + LLVMMetadataRef real = LLVMDIBuilderCreateEnumerationType(c->debug.builder, + scope, + type->decl->name, strlen(type->decl->name), + c->debug.file.debug_file, row ? row : 1, type_size(type) * 8, + type_abi_alignment(type) * 8, + elements, vec_size(elements), + llvm_get_debug_type(c, enum_real_type)); + + LLVMMetadataReplaceAllUsesWith(forward, real); + return real; +} + static LLVMMetadataRef llvm_debug_structlike_type(GenContext *c, Type *type, LLVMMetadataRef scope) { Decl *decl = type->decl; @@ -616,6 +660,8 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * return type->backend_debug_type = llvm_debug_pointer_type(c, type); case TYPE_ENUM: return type->backend_debug_type = llvm_debug_enum_type(c, type, scope); + case TYPE_CONST_ENUM: + return type->backend_debug_type = llvm_debug_raw_enum_type(c, type, scope); case TYPE_FUNC_RAW: return type->backend_debug_type = llvm_debug_func_type(c, type); case TYPE_STRUCT: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 5fd37d020..d32ba7dc3 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3486,6 +3486,7 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, case ALL_INTS: case TYPE_POINTER: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_FUNC_PTR: case TYPE_INTERFACE: case TYPE_ANY: @@ -4772,7 +4773,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) return; } case CONST_ENUM: - llvm_value_set(be_value, llvm_const_int(c, type, expr->const_expr.enum_val->enum_constant.ordinal), type); + llvm_value_set(be_value, llvm_const_int(c, type, expr->const_expr.enum_val->enum_constant.inner_ordinal), type); return; case CONST_MEMBER: case CONST_UNTYPED_LIST: @@ -6409,10 +6410,13 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex { BEValue check; LLVMBasicBlockRef exit = llvm_basic_block_new(c, "check_type_ok"); - IntrospectType checks[8] = { INTROSPECT_TYPE_ARRAY, INTROSPECT_TYPE_POINTER, - INTROSPECT_TYPE_VECTOR, INTROSPECT_TYPE_ENUM, - INTROSPECT_TYPE_SLICE, INTROSPECT_TYPE_DISTINCT, - INTROSPECT_TYPE_OPTIONAL, INTROSPECT_TYPE_BITSTRUCT }; + IntrospectType checks[9] = { + INTROSPECT_TYPE_ARRAY, INTROSPECT_TYPE_POINTER, + INTROSPECT_TYPE_VECTOR, INTROSPECT_TYPE_ENUM, + INTROSPECT_TYPE_SLICE, INTROSPECT_TYPE_DISTINCT, + INTROSPECT_TYPE_CONST_ENUM, INTROSPECT_TYPE_BITSTRUCT, + INTROSPECT_TYPE_OPTIONAL, + }; for (int i = 0; i < 8; i++) { llvm_emit_int_comp_raw(c, diff --git a/src/compiler/llvm_codegen_internal_impl.h b/src/compiler/llvm_codegen_internal_impl.h index 958b381dd..3dd62a813 100644 --- a/src/compiler/llvm_codegen_internal_impl.h +++ b/src/compiler/llvm_codegen_internal_impl.h @@ -322,6 +322,21 @@ INLINE LLVMValueRef llvm_get_struct_of_type(GenContext *c, Type *type, LLVMValue return LLVMConstNamedStruct(llvm_get_type(c, type), vals, count); } +INLINE LLVMValueRef llvm_const_integer(GenContext *c, Int128 i, Type *type) +{ + switch (type_lowering(type)->type_kind) + { + case TYPE_I128: + case TYPE_U128: + { + uint64_t words[2] = { i.low, i.high }; + return LLVMConstIntOfArbitraryPrecision(llvm_get_type(c, type), 2, words); + } + default: + return llvm_const_int(c, type, i.low); + } +} + INLINE LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val) { type = type_lowering(type); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index e61709070..c584e1f04 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -793,10 +793,10 @@ static void llvm_set_jump_table_values(ExprId from, ExprId to, Int *from_ref, In if (type_flat->type_kind == TYPE_ENUM) { Type *low = type_lowering(type_flat); - *from_ref = (Int) { .i.low = from_expr->const_expr.enum_val->enum_constant.ordinal, .type = low->type_kind }; + *from_ref = (Int) { .i.low = from_expr->const_expr.enum_val->enum_constant.inner_ordinal, .type = low->type_kind }; if (to) { - *to_ref = (Int) { .i.low = to_expr->const_expr.enum_val->enum_constant.ordinal, .type = low->type_kind }; + *to_ref = (Int) { .i.low = to_expr->const_expr.enum_val->enum_constant.inner_ordinal, .type = low->type_kind }; } else { diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 78f4779ab..9b76cf445 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -25,6 +25,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) UNREACHABLE case DECL_TYPEDEF: return llvm_get_type(c, decl->type); + case DECL_CONST_ENUM: + return llvm_get_type(c, decl->enums.type_info->type); case DECL_DISTINCT: return llvm_get_type(c, decl->distinct->type); case DECL_STRUCT: @@ -544,7 +546,7 @@ static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) { assert(values); BEValue value; - llvm_emit_expr_global_value(c, &value, enum_vals[i]->enum_constant.args[ai]); + llvm_emit_expr_global_value(c, &value, enum_vals[i]->enum_constant.associated[ai]); LLVMValueRef llvm_value = llvm_load_value_store(c, &value); values[i] = llvm_value; if (!val_type) @@ -619,9 +621,11 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) case TYPE_POINTER: return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_POINTER, type->pointer, 0, NULL, false); case TYPE_DISTINCT: - return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct->type, 0, NULL, false); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type_inline(type), 0, NULL, false); case TYPE_ENUM: return llvm_get_introspection_for_enum(c, type); + case TYPE_CONST_ENUM: + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_CONST_ENUM, type_inline(type), vec_size(type->decl->enums.values), NULL, false); case TYPE_STRUCT: case TYPE_UNION: return llvm_get_introspection_for_struct_union(c, type); diff --git a/src/compiler/number.c b/src/compiler/number.c index 5245dca98..5c7ce8e4f 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -201,21 +201,21 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp Decl *right_decl = right->enum_val; // Non-matching cannot be compared. if (right_decl->type != left_decl->type) return false; - int64_t right_ordinal = right->enum_val->enum_constant.ordinal; + int64_t right_ordinal = right->enum_val->enum_constant.inner_ordinal; switch (op) { case BINARYOP_GT: - return left_decl->enum_constant.ordinal > right_ordinal; + return left_decl->enum_constant.inner_ordinal > right_ordinal; case BINARYOP_GE: - return left_decl->enum_constant.ordinal >= right_ordinal; + return left_decl->enum_constant.inner_ordinal >= right_ordinal; case BINARYOP_LT: - return left_decl->enum_constant.ordinal < right_ordinal; + return left_decl->enum_constant.inner_ordinal < right_ordinal; case BINARYOP_LE: - return left_decl->enum_constant.ordinal <= right_ordinal; + return left_decl->enum_constant.inner_ordinal <= right_ordinal; case BINARYOP_NE: - return left_decl->enum_constant.ordinal != right_ordinal; + return left_decl->enum_constant.inner_ordinal != right_ordinal; case BINARYOP_EQ: - return left_decl->enum_constant.ordinal == right_ordinal; + return left_decl->enum_constant.inner_ordinal == right_ordinal; default: return false; } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 4826d3329..ec8e775e7 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2434,6 +2434,10 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref bool is_inline = try_consume(c, TOKEN_INLINE); if (is_inline) { + if (!compiler.build.old_enums) + { + RETURN_PRINT_ERROR_HERE("Inline parameters are not allowed for enums."); + } if (has_inline) RETURN_PRINT_ERROR_HERE("An enum cannot combine an inline value and a inline parameter."); if (*inline_index > -1) RETURN_PRINT_ERROR_HERE("An enum may only have one inline parameter."); *inline_index = index; @@ -2450,11 +2454,88 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref return true; } +static bool parse_enum_values(ParseContext *c, Decl*** values_ref, Visibility visibility, bool is_single_value, bool is_const_enum) +{ + Decl **values = NULL; + while (!try_consume(c, TOKEN_RBRACE)) + { + Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span); + if (is_const_enum) enum_const->enum_constant.is_raw = is_const_enum; + enum_const->visibility = visibility; + const char *name = enum_const->name; + if (!consume_const_name(c, "enum constant")) return false; + FOREACH(Decl *, other_constant, values) + { + if (other_constant->name == name) + { + PRINT_ERROR_AT(enum_const, "This enum constant is declared twice."); + SEMA_NOTE(other_constant, "The previous declaration was here."); + return false; + } + } + if (!parse_attributes_for_global(c, enum_const)) return false; + if (try_consume(c, TOKEN_EQ)) + { + Expr **args = NULL; + if (is_single_value || !tok_is(c, TOKEN_LBRACE)) + { + ASSIGN_EXPR_OR_RET(Expr *single, parse_constant_expr(c), false); + if (is_const_enum) + { + enum_const->enum_constant.value = single; + goto NEXT; + } + vec_add(args, single); + } + else + { + CONSUME_OR_RET(TOKEN_LBRACE, false); + while (1) + { + if (try_consume(c, TOKEN_RBRACE)) break; + ASSIGN_EXPR_OR_RET(Expr *arg, parse_expr(c), false); + vec_add(args, arg); + if (tok_is(c, TOKEN_COLON) && arg->expr_kind == EXPR_UNRESOLVED_IDENTIFIER) + { + print_error_at(extend_span_with_token(arg->span, c->span), + "This looks like a designated initializer, but that style of declaration " + "is not supported for declaring enum associated values."); + return false; + } + if (!try_consume(c, TOKEN_COMMA)) + { + if (!try_consume(c, TOKEN_RBRACE)) + { + PRINT_ERROR_HERE("A comma or a closing brace was expected here."); + return false; + } + break; + } + } + } + enum_const->enum_constant.associated = args; + } +NEXT: + vec_add(values, enum_const); + // Allow trailing ',' + if (!try_consume(c, TOKEN_COMMA)) + { + if (tok_is(c, TOKEN_CONST_IDENT)) + { + PRINT_ERROR_HERE("It looks like you forgot a comma before this identifier."); + return false; + } + EXPECT_OR_RET(TOKEN_RBRACE, false); + } + } + *values_ref = values; + return true; +} /** * Parse an enum declaration (after "enum") * - * enum ::= ENUM TYPE_IDENT opt_interfaces (':' type? enum_param_list?)? opt_attributes '{' enum_body '}' + * enum ::= ENUM TYPE_IDENT opt_interfaces (':' 'inline'? type? ('const' | enum_param_list?)?)? opt_attributes '{' enum_body '}' * enum_body ::= enum_def (',' enum_def)* ','? * enum_def ::= CONST_IDENT ('(' arg_list ')')? */ @@ -2462,16 +2543,25 @@ static inline Decl *parse_enum_declaration(ParseContext *c) { advance_and_verify(c, TOKEN_ENUM); - Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_ENUM); + const char *name = symstr(c); + SourceSpan span = c->span; if (!consume_type_name(c, "enum")) return poisoned_decl; - if (!parse_interface_impls(c, &decl->interfaces)) return poisoned_decl; - + TypeInfo **interfaces = NULL; + if (!parse_interface_impls(c, &interfaces)) return poisoned_decl; TypeInfo *type = NULL; bool val_is_inline = false; ArrayIndex inline_index = -1; + bool is_const_enum = false; + Decl **param_list = NULL; if (try_consume(c, TOKEN_COLON)) { + is_const_enum = try_consume(c, TOKEN_CONST); + if (is_const_enum && compiler.build.old_enums) + { + PRINT_ERROR_LAST("'const' enums are not available with '--use-old-enums'."); + return poisoned_decl; + } if (!tok_is(c, TOKEN_LPAREN) && !tok_is(c, TOKEN_LBRACE)) { val_is_inline = try_consume(c, TOKEN_INLINE); @@ -2481,9 +2571,23 @@ static inline Decl *parse_enum_declaration(ParseContext *c) RETURN_PRINT_ERROR_AT(poisoned_decl, type, "An enum can't have an optional type."); } } - if (!parse_enum_param_list(c, &decl->enums.parameters, val_is_inline ? NULL : &inline_index)) return poisoned_decl; + if (is_const_enum) + { + if (tok_is(c, TOKEN_LPAREN)) + { + PRINT_ERROR_HERE("Const enums cannot have associated values."); + return poisoned_decl; + } + } + else + { + if (!parse_enum_param_list(c, ¶m_list, val_is_inline ? NULL : &inline_index)) return poisoned_decl; + } } + Decl *decl = decl_new_with_type(name, span, is_const_enum ? DECL_CONST_ENUM : DECL_ENUM); + decl->interfaces = interfaces; + if (param_list) decl->enums.parameters = param_list; if (!parse_attributes_for_global(c, decl)) return poisoned_decl; unsigned expected_parameters = vec_size(decl->enums.parameters); Visibility visibility = decl->visibility; @@ -2491,75 +2595,9 @@ static inline Decl *parse_enum_declaration(ParseContext *c) decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span); decl->enums.inline_index = (int16_t)inline_index; - decl->enums.inline_value = val_is_inline; - while (!try_consume(c, TOKEN_RBRACE)) - { - Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span); - enum_const->visibility = visibility; - const char *name = enum_const->name; - if (!consume_const_name(c, "enum constant")) - { - return poisoned_decl; - } - FOREACH(Decl *, other_constant, decl->enums.values) - { - if (other_constant->name == name) - { - PRINT_ERROR_AT(enum_const, "This enum constant is declared twice."); - SEMA_NOTE(other_constant, "The previous declaration was here."); - decl_poison(enum_const); - break; - } - } - if (!parse_attributes_for_global(c, enum_const)) return poisoned_decl; - if (try_consume(c, TOKEN_EQ)) - { - Expr **args = NULL; - if (expected_parameters == 1 || !tok_is(c, TOKEN_LBRACE)) - { - ASSIGN_EXPR_OR_RET(Expr *single, parse_expr(c), poisoned_decl); - vec_add(args, single); - } - else - { - CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl); - while (1) - { - if (try_consume(c, TOKEN_RBRACE)) break; - ASSIGN_EXPR_OR_RET(Expr *arg, parse_expr(c), poisoned_decl); - vec_add(args, arg); - if (tok_is(c, TOKEN_COLON) && arg->expr_kind == EXPR_UNRESOLVED_IDENTIFIER) - { - print_error_at(extend_span_with_token(arg->span, c->span), - "This looks like a designated initializer, but that style of declaration " - "is not supported for declaring enum associated values."); - return poisoned_decl; - } - if (!try_consume(c, TOKEN_COMMA)) - { - if (!try_consume(c, TOKEN_RBRACE)) - { - PRINT_ERROR_HERE("A comma or a closing brace was expected here."); - return poisoned_decl; - } - break; - } - } - } - enum_const->enum_constant.args = args; - } - vec_add(decl->enums.values, enum_const); - // Allow trailing ',' - if (!try_consume(c, TOKEN_COMMA)) - { - if (tok_is(c, TOKEN_CONST_IDENT)) - { - PRINT_ERROR_HERE("It looks like you forgot a comma before this identifier."); - return poisoned_decl; - } - EXPECT_OR_RET(TOKEN_RBRACE, poisoned_decl); - } - } + decl->enums.inline_value = is_const_enum ? false : val_is_inline; + if (is_const_enum && val_is_inline) decl->is_substruct = true; + if (!parse_enum_values(c, &decl->enums.values, visibility, is_const_enum || expected_parameters == 1, is_const_enum)) return poisoned_decl; return decl; } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index da0a16ee3..af534f8e4 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -771,7 +771,7 @@ static bool report_cast_error(CastContext *cc, bool may_cast_explicit) } if (expr->type->type_kind == TYPE_ENUM && type_is_integer(to)) { - if (to == expr->type->decl->enums.type_info->type) + if (to == enum_inner_type(expr->type)) { RETURN_CAST_ERROR(expr, "It is not possible to cast the enum %s to %s, but you can use .ordinal to get the ordinal. E.g. 'my_enum.ordinal.", type_quoted_error_string(type_no_optional(expr->type)), @@ -1486,6 +1486,29 @@ static bool rule_int_to_bits(CastContext *cc, bool is_explicit, bool is_silent) return true; } +static bool rule_int_to_enum(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + Decl *decl = cc->to_type->decl; + if (sema_cast_const(cc->expr)) + { + Int to_convert = cc->expr->const_expr.ixx; + if (int_is_neg(to_convert)) + { + if (is_silent) return false; + RETURN_CAST_ERROR(cc->expr, "Casting a negative number cannot yield a valid enum."); + } + unsigned max_enums = vec_size(decl->enums.values); + Int max = {.i.low = max_enums, .type = TYPE_U32}; + if (int_comp(to_convert, max, BINARYOP_GE)) + { + if (is_silent) return false; + RETURN_CAST_ERROR(cc->expr, "The value '%s' exceeds the max ordinal '%u'.", int_to_str(max, 10, false), max_enums - 1); + } + } + return true; +} + static bool rule_arr_to_bits(CastContext *cc, bool is_explicit, bool is_silent) { Type *base_type = cc->to->decl->strukt.container_type->type; @@ -1501,27 +1524,64 @@ static bool rule_enum_to_value(CastContext *cc, bool is_explicit, bool is_silent { Decl *enum_decl = cc->from->decl; + if (compiler.build.old_enums) + { + if (!enum_decl->is_substruct) + { + + return sema_cast_error(cc, false, is_silent); + } + + Type *inline_type; + if (enum_decl->enums.inline_value) + { + inline_type = enum_decl->enums.type_info->type; + } + else + { + inline_type = enum_decl->enums.parameters[enum_decl->enums.inline_index]->type; + } + if (is_explicit) + { + cast_context_set_from(cc, type_flatten(inline_type)); + // Explicit just flattens and tries again. + return cast_is_allowed(cc, is_explicit, is_silent); + } + cast_context_set_from(cc, inline_type->canonical); + return cast_is_allowed(cc, is_explicit, is_silent); + } + + // First handle const enums, they behave much like distinct types + if (enum_decl->decl_kind == DECL_CONST_ENUM) + { + if (!is_explicit || !enum_decl->is_substruct) + { + return sema_cast_error(cc, false, is_silent); + } + // Use the inner type. + Type *inner = enum_decl->enums.type_info->type; + cast_context_set_from(cc, is_explicit ? type_flatten(inner) : inner); + return cast_is_allowed(cc, is_explicit, is_silent); + } + + Type *inner = enum_decl->enums.type_info->type; + if (!type_is_integer_or_bool_kind(type_flatten(cc->to))) + { + if (is_silent) return false; + RETURN_CAST_ERROR(cc->expr, "An enum %s can only be cast to an int type, casting directly to %s is not valid.", + type_quoted_error_string(enum_decl->type), type_quoted_error_string(cc->to_type)); + } + if (is_explicit) + { + cast_context_set_from(cc, type_flatten(inner)); + // Explicit just flattens and tries again. + return cast_is_allowed(cc, is_explicit, is_silent); + } if (!enum_decl->is_substruct) { return sema_cast_error(cc, false, is_silent); } - - Type *inline_type; - if (enum_decl->enums.inline_value) - { - inline_type = enum_decl->enums.type_info->type; - } - else - { - inline_type = enum_decl->enums.parameters[enum_decl->enums.inline_index]->type; - } - if (is_explicit) - { - cast_context_set_from(cc, type_flatten(inline_type)); - // Explicit just flattens and tries again. - return cast_is_allowed(cc, is_explicit, is_silent); - } - cast_context_set_from(cc, inline_type->canonical); + cast_context_set_from(cc, inner->canonical); return cast_is_allowed(cc, is_explicit, is_silent); } @@ -1780,36 +1840,65 @@ static void cast_int_to_float(Expr *expr, Type *type) expr_rewrite_const_float(expr, type, f); } +static void cast_int_to_enum(Expr *expr, Type *type) +{ + Decl *decl = type_flatten(type)->decl; + if (sema_cast_const(expr)) + { + Int to_convert = expr->const_expr.ixx; + unsigned max_enums = vec_size(decl->enums.values); + assert(max_enums > to_convert.i.low); + expr->expr_kind = EXPR_CONST; + expr->const_expr = (ExprConst) { + .enum_val = decl->enums.values[to_convert.i.low], + .const_kind = CONST_ENUM + }; + expr->type = type; + return; + } + + Expr *inner = copy_expr_single(expr); + expr->expr_kind = EXPR_ENUM_FROM_ORD; + expr->inner_expr = inner; + expr->type = type; +} + static void cast_enum_to_value(Expr* expr, Type *to_type) { Type *enum_type = type_flatten(expr->type); Decl *decl = enum_type->decl; - assert(decl->is_substruct); - if (decl->enums.inline_value) + if (compiler.build.old_enums) { - sema_expr_convert_enum_to_int(expr); - cast_no_check(expr, to_type, IS_OPTIONAL(expr)); - return; - } - if (expr_is_const_enum(expr)) - { - expr_replace(expr, copy_expr_single(expr->const_expr.enum_val->enum_constant.args[decl->enums.inline_index])); - if (expr->type != to_type) + assert(decl->is_substruct); + if (decl->enums.inline_value) { - cast_no_check(expr, to_type, false); + sema_expr_convert_enum_to_int(expr); + cast_no_check(expr, to_type, IS_OPTIONAL(expr)); + return; + } + if (expr_is_const_enum(expr)) + { + expr_replace(expr, copy_expr_single(expr->const_expr.enum_val->enum_constant.associated[decl->enums.inline_index])); + if (expr->type != to_type) + { + cast_no_check(expr, to_type, false); + } + return; + } + Expr *copy = expr_copy(expr); + expr->expr_kind = EXPR_ACCESS_RESOLVED; + expr->access_resolved_expr.parent = copy; + Decl *member = decl->enums.parameters[decl->enums.inline_index]; + expr->access_resolved_expr.ref = member; + expr->type = type_add_optional(member->type, IS_OPTIONAL(expr)); + if (member->type != to_type) + { + cast_no_check(expr, to_type, IS_OPTIONAL(expr)); } return; } - Expr *copy = expr_copy(expr); - expr->expr_kind = EXPR_ACCESS_RESOLVED; - expr->access_resolved_expr.parent = copy; - Decl *member = decl->enums.parameters[decl->enums.inline_index]; - expr->access_resolved_expr.ref = member; - expr->type = type_add_optional(member->type, IS_OPTIONAL(expr)); - if (member->type != to_type) - { - cast_no_check(expr, to_type, IS_OPTIONAL(expr)); - } + sema_expr_convert_enum_to_int(expr); + cast_no_check(expr, to_type, IS_OPTIONAL(expr)); } /** @@ -2278,9 +2367,10 @@ static void cast_typeid_to_bool(Expr *expr, Type *to_type) { expr_rewrite_int_to #define IN2BO &cast_int_to_bool #define IN2IN &cast_int_to_int #define IN2FP &cast_int_to_float -#define IN2PT &cast_int_to_ptr +#define IN2PT &cast_int_to_ptr +#define IN2EN &cast_int_to_enum #define EN2XX &cast_enum_to_value -#define FP2BO &cast_float_to_bool +#define FP2BO &cast_float_to_bool #define FP2IN &cast_float_to_int #define FP2FP &cast_float_to_float #define PT2BO &cast_ptr_to_bool @@ -2318,6 +2408,7 @@ static void cast_typeid_to_bool(Expr *expr, Type *to_type) { expr_rewrite_int_to #define _NA__ &rule_not_applicable /* "Not applicable" - should not be seen. */ #define RWIDE &rule_widen_narrow /* Widen / narrow conversion of int/float */ #define RINFL &rule_int_to_float /* Simple expressions, check sizes */ +#define RINEN &rule_int_to_enum /* Const int must fit */ #define ROKOK &rule_all_ok /* Always works */ #define RINPT &rule_int_to_ptr /* Int -> ptr (explicit + size match) */ #define RPTIN &rule_ptr_to_int /* Ptr -> int (explicit + size match) */ @@ -2353,57 +2444,59 @@ static void cast_typeid_to_bool(Expr *expr, Type *to_type) { expr_rewrite_int_to #define RVPAN &rule_voidptr_to_any /* void* -> interface/any */ CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { -// void, wildc, bool, int, float, ptr, slice, vec, bitst, distc, array, strct, union, any, infc, enum, func, typid, afaul, voidp, arrpt, infer, ulist (to) +// void, wildc, bool, int, float, ptr, slice, vec, bitst, distc, array, strct, union, any, infc, enum, renum, func, typid, afaul, voidp, arrpt, infer, ulist (to) {_NA__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // VOID (from) - {ROKOK, _NA__, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, _NO__, _NO__}, // WILDCARD - {REXPL, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BOOL - {REXPL, _NO__, REXPL, RWIDE, RINFL, RINPT, _NO__, REXVC, RINBS, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RINPT, _NO__, _NO__, RINPT, RINPT, _NO__, _NO__}, // INT - {REXPL, _NO__, REXPL, REXPL, RWIDE, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // FLOAT - {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RPTIF, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // PTR - {REXPL, _NO__, REXPL, _NO__, _NO__, RSLPT, RSLSL, RSLVA, _NO__, RXXDI, RSLVA, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, RSLPT, RSLFE, _NO__}, // SLICE - {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, RVASL, RVCVC, _NO__, RXXDI, RVCAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE, _NO__}, // VECTOR - {REXPL, _NO__, REXPL, RBSIN, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, RBSAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BITSTRUCT - {REXPL, _NO__, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIDI, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, _NO__}, // DISTINCT - {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, RVASL, RARVC, RARBS, RXXDI, RARAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE, _NO__}, // ARRAY - {REXPL, _NO__, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTDI, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, _NO__, _NO__}, // STRUCT - {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // UNION - {REXPL, _NO__, REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NA__, REXPL, _NO__, _NO__, _NO__, _NO__, ROKOK, REXPL, _NO__, _NO__}, // ANY - {REXPL, _NO__, REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RIFIF, _NO__, _NO__, _NO__, _NO__, ROKOK, REXPL, _NO__, _NO__}, // INTERFACE - {REXPL, _NO__, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, _NO__}, // ENUM - {REXPL, _NO__, REXPL, RPTIN, _NO__, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RPTPT, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__}, // FUNC - {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NA__, _NO__, REXPL, REXPL, _NO__, _NO__}, // TYPEID - {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__}, // ANYFAULT - {REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, RVPAN, RVPAN, _NO__, ROKOK, _NO__, _NO__, _NA__, ROKOK, _NO__, _NO__}, // VOIDPTR - {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, RAPSL, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // ARRPTR - {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // INFERRED - {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RULSL, RULAR, RULST, RXXDI, RULAR, RULST, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RULFE, _NO__}, // UNTYPED_LIST + {ROKOK, _NA__, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, _NO__, _NO__}, // WILDCARD + {REXPL, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BOOL + {REXPL, _NO__, REXPL, RWIDE, RINFL, RINPT, _NO__, REXVC, RINBS, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RINEN, RXXDI, RINPT, _NO__, _NO__, RINPT, RINPT, _NO__, _NO__}, // INT + {REXPL, _NO__, REXPL, REXPL, RWIDE, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // FLOAT + {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RPTIF, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // PTR + {REXPL, _NO__, REXPL, _NO__, _NO__, RSLPT, RSLSL, RSLVA, _NO__, RXXDI, RSLVA, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RSLPT, RSLFE, _NO__}, // SLICE + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, RVASL, RVCVC, _NO__, RXXDI, RVCAR, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE, _NO__}, // VECTOR + {REXPL, _NO__, REXPL, RBSIN, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, RBSAR, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BITSTRUCT + {REXPL, _NO__, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIDI, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIDI, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, _NO__}, // DISTINCT + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, RVASL, RARVC, RARBS, RXXDI, RARAR, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE, _NO__}, // ARRAY + {REXPL, _NO__, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTDI, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTDI, RSTST, RSTST, RSTST, RSTST, RSTST, _NO__, _NO__}, // STRUCT + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // UNION + {REXPL, _NO__, REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NA__, REXPL, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, REXPL, _NO__, _NO__}, // ANY + {REXPL, _NO__, REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RIFIF, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, REXPL, _NO__, _NO__}, // INTERFACE + {REXPL, _NO__, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, RENXX, _NO__}, // ENUM + {REXPL, _NO__, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIDI, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, _NO__}, // CONST_ENUM + {REXPL, _NO__, REXPL, RPTIN, _NO__, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, RPTPT, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__}, // FUNC + {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NA__, _NO__, REXPL, REXPL, _NO__, _NO__}, // TYPEID + {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__}, // ANYFAULT + {REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, RVPAN, RVPAN, _NO__, RXXDI, ROKOK, _NO__, _NO__, _NA__, ROKOK, _NO__, _NO__}, // VOIDPTR + {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, RAPSL, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // ARRPTR + {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // INFERRED + {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RULSL, RULAR, RULST, RXXDI, RULAR, RULST, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RULFE, _NO__}, // UNTYPED_LIST }; CastFunction cast_function[CONV_LAST + 1][CONV_LAST + 1] = { -//void, wildcd, bool, int, float, ptr, slice, vec, bitst, dist, array,struct,union, any, infc, enum, func, typeid, anyfa, vptr, aptr, infer, ulist (to) +//void, wildcd, bool, int, float, ptr, slice, vec, bitst, dist, array,struct,union, any, infc, enum, renum, func, typeid, anyfa, vptr, aptr, infer, ulist (to) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // VOID (from) - {XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, 0 }, // WILDCARD - {XX2VO, 0, 0, BO2IN, BO2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BOOL - {XX2VO, 0, IN2BO, IN2IN, IN2FP, IN2PT, 0, EX2VC, IA2BS, 0, 0, 0, 0, 0, 0, 0, IN2PT, 0, 0, IN2PT, IN2PT, 0, 0 }, // INT - {XX2VO, 0, FP2BO, FP2IN, FP2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // FLOAT - {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE, 0 }, // PTR - {XX2VO, 0, SL2BO, 0, 0, SL2PT, SL2SL, SL2VA, 0, 0, SL2VA, 0, 0, 0, 0, 0, 0, 0, 0, SL2PT, SL2PT, SL2FE, 0 }, // SLICE - {XX2VO, 0, 0, 0, 0, 0, VA2SL, VC2VC, 0, 0, VC2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE, 0 }, // VECTOR - {XX2VO, 0, BS2BO, BS2IA, 0, 0, 0, 0, 0, 0, BS2IA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BITSTRUCT - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // DISTINCT - {XX2VO, 0, 0, 0, 0, 0, VA2SL, AR2VC, IA2BS, 0, AR2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE, 0 }, // ARRAY - {XX2VO, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0, 0 }, // STRUCT - {XX2VO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // UNION - {XX2VO, 0, AY2BO, 0, 0, AY2PT, 0, 0, 0, 0, 0, 0, 0, PT2PT, PT2PT, 0, 0, 0, 0, AY2PT, AY2PT, 0, 0 }, // ANY - {XX2VO, 0, AY2BO, 0, 0, AY2PT, 0, 0, 0, 0, 0, 0, 0, PT2PT, PT2PT, 0, 0, 0, 0, AY2PT, AY2PT, 0, 0 }, // INTERFACE - {XX2VO, 0, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX }, // ENUM - {XX2VO, 0, PT2BO, PT2IN, 0, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, PT2PT, 0, 0, PT2PT, 0, 0, 0 }, // FUNC - {XX2VO, 0, TI2BO, TI2IN, 0, TI2PT, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TI2PT, TI2PT, 0, 0 }, // TYPEID - {XX2VO, 0, AF2BO, FA2IN, 0, FA2IN, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FA2IN, FA2IN, 0, 0 }, // ANYFAULT - {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, PT2PT, 0, 0, 0, PT2PT, 0, 0 }, // VOIDPTR - {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, AP2SL, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE, 0 }, // ARRAYPTR - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // INFERRED - { 0, 0, 0, 0, 0, 0, UL2XX, UL2XX, UL2XX, 0, UL2XX, UL2XX, 0, 0, 0, 0, 0, 0, 0, 0, 0, UL2XX, 0 }, // UNTYPED + {XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, 0 }, // WILDCARD + {XX2VO, 0, 0, BO2IN, BO2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BOOL + {XX2VO, 0, IN2BO, IN2IN, IN2FP, IN2PT, 0, EX2VC, IA2BS, 0, 0, 0, 0, 0, 0, IN2EN, 0, IN2PT, 0, 0, IN2PT, IN2PT, 0, 0 }, // INT + {XX2VO, 0, FP2BO, FP2IN, FP2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // FLOAT + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE, 0 }, // PTR + {XX2VO, 0, SL2BO, 0, 0, SL2PT, SL2SL, SL2VA, 0, 0, SL2VA, 0, 0, 0, 0, 0, 0, 0, 0, 0, SL2PT, SL2PT, SL2FE, 0 }, // SLICE + {XX2VO, 0, 0, 0, 0, 0, VA2SL, VC2VC, 0, 0, VC2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE, 0 }, // VECTOR + {XX2VO, 0, BS2BO, BS2IA, 0, 0, 0, 0, 0, 0, BS2IA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BITSTRUCT + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // DISTINCT + {XX2VO, 0, 0, 0, 0, 0, VA2SL, AR2VC, IA2BS, 0, AR2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE, 0 }, // ARRAY + {XX2VO, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0, 0 }, // STRUCT + {XX2VO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // UNION + {XX2VO, 0, AY2BO, 0, 0, AY2PT, 0, 0, 0, 0, 0, 0, 0, PT2PT, PT2PT, 0, 0, 0, 0, 0, AY2PT, AY2PT, 0, 0 }, // ANY + {XX2VO, 0, AY2BO, 0, 0, AY2PT, 0, 0, 0, 0, 0, 0, 0, PT2PT, PT2PT, 0, 0, 0, 0, 0, AY2PT, AY2PT, 0, 0 }, // INTERFACE + {XX2VO, 0, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX, EN2XX }, // ENUM + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // CONST ENUM + {XX2VO, 0, PT2BO, PT2IN, 0, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, PT2PT, 0, 0, PT2PT, 0, 0, 0 }, // FUNC + {XX2VO, 0, TI2BO, TI2IN, 0, TI2PT, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TI2PT, TI2PT, 0, 0 }, // TYPEID + {XX2VO, 0, AF2BO, FA2IN, 0, FA2IN, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FA2IN, FA2IN, 0, 0 }, // ANYFAULT + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, PT2PT, 0, 0, 0, PT2PT, 0, 0 }, // VOIDPTR + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, AP2SL, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE, 0 }, // ARRAYPTR + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // INFERRED + { 0, 0, 0, 0, 0, 0, UL2XX, UL2XX, UL2XX, 0, UL2XX, UL2XX, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, UL2XX, 0 }, // UNTYPED }; static ConvGroup group_from_type[TYPE_LAST + 1] = { @@ -2431,6 +2524,7 @@ static ConvGroup group_from_type[TYPE_LAST + 1] = { [TYPE_TYPEID] = CONV_TYPEID, [TYPE_POINTER] = CONV_POINTER, [TYPE_ENUM] = CONV_ENUM, + [TYPE_CONST_ENUM] = CONV_RAW_ENUM, [TYPE_FUNC_PTR] = CONV_FUNC, [TYPE_STRUCT] = CONV_STRUCT, [TYPE_UNION] = CONV_UNION, diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 7981bfed7..c4dde6a9d 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -62,6 +62,7 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param); static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl); +static inline bool sema_analyse_raw_enum(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_check_section(SemaContext *context, Attr *attr) { @@ -442,7 +443,8 @@ RETRY:; case TYPE_SLICE: return compiler.platform.align_pointer.align / 8; case TYPE_ENUM: - type = type->decl->enums.type_info->type; + case TYPE_CONST_ENUM: + type = enum_inner_type(type); goto RETRY; case TYPE_STRUCT: case TYPE_UNION: @@ -1021,6 +1023,7 @@ RETRY: case TYPE_ANYFAULT: case TYPE_TYPEID: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: @@ -1572,7 +1575,7 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era } enum_value->type = decl->type; DEBUG_LOG("* Checking enum constant %s.", enum_value->name); - enum_value->enum_constant.ordinal = i; + enum_value->enum_constant.inner_ordinal = i; DEBUG_LOG("* Ordinal: %d", i); ASSERT(enum_value->resolve_status == RESOLVE_NOT_DONE); ASSERT(enum_value->decl_kind == DECL_ENUM_CONSTANT); @@ -1591,12 +1594,12 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era i128_to_string(value, 10, type_is_signed(flat_underlying_type), false), type_quoted_error_string(type)); } - enum_value->enum_constant.ordinal = value.low; + enum_value->enum_constant.inner_ordinal = value.low; // Update the value value.low++; - Expr **args = enum_value->enum_constant.args; + Expr **args = enum_value->enum_constant.associated; unsigned arg_count = vec_size(args); if (arg_count > associated_value_count) { @@ -1621,7 +1624,7 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era for (unsigned i = 0; i < enums; i++) { Decl *enum_value = enum_values[i]; - Expr **args = enum_value->enum_constant.args; + Expr **args = enum_value->enum_constant.associated; unsigned arg_count = vec_size(args); if (arg_count > associated_value_count) { @@ -1653,6 +1656,115 @@ ERR: return false; } +bool sema_analyse_const_enum_constant_val(SemaContext *context, Decl *decl) +{ + Expr *value = decl->enum_constant.value; + if (!sema_analyse_inferred_expr(context, decl->type, value)) return decl_poison(decl); + if (!sema_cast_const(value)) + { + SEMA_ERROR(value, "Expected an constant enum value."); + return decl_poison(decl); + } + if (value->type != decl->type) + { + if (!cast_implicit_binary(context, value, decl->type, NULL)) return decl_poison(decl); + cast_explicit_silent(context, value, decl->type); + } + return true; +} +static inline bool sema_analyse_raw_enum(SemaContext *context, Decl *decl, bool *erase_decl) +{ + if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; + if (!sema_resolve_implemented_interfaces(context, decl, false)) return decl_poison(decl); + + // Resolve the type of the enum. + if (!sema_resolve_type_info(context, decl->enums.type_info, RESOLVE_TYPE_DEFAULT)) return false; + + Type *type = decl->enums.type_info->type; + if (!sema_resolve_type_decl(context, type)) return false; + Type *flat = type_flatten(type); + ASSERT_SPAN(decl, !type_is_optional(type) && "Already stopped when parsing."); + + switch (sema_resolve_storage_type(context, type)) + { + case STORAGE_ERROR: + return decl_poison(decl); + case STORAGE_NORMAL: + break; + case STORAGE_WILDCARD: + SEMA_ERROR(decl->enums.type_info, "No type can be inferred from the optional result."); + return decl_poison(decl); + case STORAGE_VOID: + SEMA_ERROR(decl->enums.type_info, "An enum may not have a void type."); + return decl_poison(decl); + case STORAGE_COMPILE_TIME: + SEMA_ERROR(decl->enums.type_info, "An enum may not have a compile time type."); + return decl_poison(decl); + case STORAGE_UNKNOWN: + SEMA_ERROR(decl->enums.type_info, "An enum may not be %s, as it has an unknown size.", + type_quoted_error_string(type)); + return decl_poison(decl); + } + + DEBUG_LOG("* Raw enum type resolved to %s.", type->name); + + ASSERT_SPAN(decl, !decl->enums.parameters); + + bool success = true; + unsigned enums = vec_size(decl->enums.values); + + Decl **enum_values = decl->enums.values; + for (unsigned i = 0; i < enums; i++) + { + Decl *enum_value = enum_values[i]; + + bool erase_val = false; + if (!sema_analyse_attributes(context, enum_value, enum_value->attributes, ATTR_ENUM_VALUE, &erase_val)) return decl_poison(decl); + if (erase_val) + { + if (enums == 1) + { + RETURN_SEMA_ERROR(decl, "No enum values left in enum after @if resolution, there must be at least one."); + } + vec_erase_at(enum_values, i); + enums--; + i--; + continue; + } + enum_value->type = decl->type; + DEBUG_LOG("* Checking enum constant %s.", enum_value->name); + if (!enum_value->enum_constant.value) + { + if (!type_is_integer(flat)) + { + RETURN_SEMA_ERROR(enum_value, "Enums with missing values must be an integer type."); + } + if (i == 0) + { + enum_value->enum_constant.value = expr_new_const_int(enum_value->span, type, 0); + } + else + { + Expr *expr = expr_new(EXPR_IOTA_DECL, enum_value->span); + expr->decl_expr = enum_values[i - 1]; + enum_value->enum_constant.value = expr; + } + } + ASSERT(enum_value->resolve_status == RESOLVE_NOT_DONE); + ASSERT(enum_value->decl_kind == DECL_ENUM_CONSTANT); + } + decl->resolve_status = RESOLVE_DONE; + for (unsigned i = 0; i < enums; i++) + { + Decl *enum_value = enum_values[i]; + enum_value->resolve_status = RESOLVE_RUNNING; + if (!sema_analyse_const_enum_constant_val(context, enum_value)) return decl_poison(decl); + enum_value->resolve_status = RESOLVE_DONE; + } + return success; +} + static inline bool sema_analyse_fault(SemaContext *context, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FAULT, erase_decl)) return decl_poison(decl); @@ -2699,6 +2811,7 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) goto NOT_VALID_NAME; } FALLTHROUGH; + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: { @@ -5113,6 +5226,7 @@ static inline bool sema_analyse_attribute_decl(SemaContext *context, SemaContext return true; } + static inline bool sema_analyse_alias(SemaContext *context, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ALIAS, erase_decl)) return decl_poison(decl); @@ -5184,6 +5298,7 @@ RETRY: return true; case TYPE_FUNC_RAW: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: @@ -5286,6 +5401,9 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) case DECL_ENUM: if (!sema_analyse_enum(context, decl, &erase_decl)) goto FAILED; break; + case DECL_CONST_ENUM: + if (!sema_analyse_raw_enum(context, decl, &erase_decl)) goto FAILED; + break; case DECL_FAULT: if (!sema_analyse_fault(context, decl, &erase_decl)) goto FAILED; break; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 4eda1877f..22dbdc5b2 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -169,7 +169,7 @@ static Type *sema_expr_check_type_exists(SemaContext *context, TypeInfo *type_in static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr); static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *expr, Expr *typeid, const char *kw, bool *was_error); static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, Type *type, TypeProperty property, Type *parent_type); -static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProperty property); +static bool sema_type_property_is_valid_for_type(CanonicalType *original_type, TypeProperty property); static bool sema_expr_rewrite_typeid_call(Expr *expr, Expr *typeid, TypeIdInfoKind kind, Type *result_type); static inline void sema_expr_rewrite_typeid_kind(Expr *expr, Expr *parent); static inline bool sema_expr_replace_with_enum_array(SemaContext *context, Expr *enum_array_expr, Decl *enum_decl); @@ -177,7 +177,7 @@ static inline bool sema_expr_replace_with_enum_name_array(SemaContext *context, static inline void sema_expr_rewrite_to_type_nameof(Expr *expr, Type *type, TokenType name_type); static inline bool sema_create_const_kind(SemaContext *context, Expr *expr, Type *type); -static inline bool sema_create_const_len(Expr *expr, Type *type); +static inline bool sema_create_const_len(Expr *expr, Type *type, Type *flat); static inline bool sema_create_const_inner(SemaContext *context, Expr *expr, Type *type); static inline bool sema_create_const_min(Expr *expr, Type *type, Type *flat); static inline bool sema_create_const_max(Expr *expr, Type *type, Type *flat); @@ -284,10 +284,10 @@ Expr *sema_enter_inline_member(Expr *parent, CanonicalType *type) if (decl->enums.inline_value) { expr = expr_new_expr(EXPR_CONST, parent); - expr_rewrite_const_int(expr, decl->enums.type_info->type, parent->const_expr.enum_val->enum_constant.ordinal); + expr_rewrite_const_int(expr, decl->enums.type_info->type, parent->const_expr.enum_val->enum_constant.inner_ordinal); return expr; } - expr = copy_expr_single(parent->const_expr.enum_val->enum_constant.args[decl->enums.inline_index]); + expr = copy_expr_single(parent->const_expr.enum_val->enum_constant.associated[decl->enums.inline_index]); break; } if (decl->enums.inline_value) @@ -891,6 +891,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) SEMA_ERROR(expr, "Expected union followed by {...} or '.'."); return expr_poison(expr); case DECL_ENUM: + case DECL_CONST_ENUM: SEMA_ERROR(expr, "Expected enum name followed by '.' and an enum value."); return expr_poison(expr); } @@ -1049,7 +1050,11 @@ static inline bool sema_expr_analyse_enum_constant(SemaContext *context, Expr *e ASSERT_SPAN(expr, enum_constant->resolve_status != RESOLVE_NOT_DONE); expr->type = decl->type; - + if (enum_constant->enum_constant.is_raw) + { + expr_replace(expr, copy_expr_single(enum_constant->enum_constant.value)); + return true; + } expr->expr_kind = EXPR_CONST; expr->const_expr.const_kind = CONST_ENUM; expr->const_expr.enum_val = enum_constant; @@ -1060,25 +1065,16 @@ static inline bool sema_expr_analyse_enum_constant(SemaContext *context, Expr *e static inline bool sema_identifier_find_possible_inferred(SemaContext *context, Type *to, Expr *expr) { - if (to->canonical->type_kind != TYPE_ENUM) return false; - Decl *parent_decl = to->canonical->decl; - if (!decl_ok(parent_decl)) + to = to->canonical; + switch (to->type_kind) { - expr_poison(expr); - return true; - } - switch (parent_decl->decl_kind) - { - case DECL_ENUM: - return sema_expr_analyse_enum_constant(context, expr, expr->unresolved_ident_expr.ident, parent_decl); - case DECL_UNION: - case DECL_STRUCT: - case DECL_BITSTRUCT: - return false; + case TYPE_CONST_ENUM: + case TYPE_ENUM: + if (!decl_ok(to->decl)) return expr_poison(expr), true; + return sema_expr_analyse_enum_constant(context, expr, expr->unresolved_ident_expr.ident, to->decl); default: - UNREACHABLE + return false; } - } static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr) @@ -1260,11 +1256,14 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr if (op_result != 2) goto EVAL_BOTH; if (!sema_analyse_expr(context, left)) return false; - if (left->type->canonical->type_kind == TYPE_ENUM) + switch (left->type->canonical->type_kind) { - return sema_analyse_inferred_expr(context, left->type, right); + case TYPE_ENUM: + case TYPE_CONST_ENUM: + return sema_analyse_inferred_expr(context, left->type, right); + default: + return sema_analyse_expr(context, right); } - return sema_analyse_expr(context, right); EVAL_BOTH: return sema_analyse_expr(context, left) && sema_analyse_expr(context, right); @@ -1276,18 +1275,26 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, if (right->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && right->unresolved_ident_expr.is_const) { if (!sema_analyse_expr(context, left)) return false; - if (type_flatten(left->type)->type_kind == TYPE_ENUM) + switch (type_flatten(left->type)->type_kind) { - return sema_analyse_inferred_expr(context, left->type, right); + case TYPE_ENUM: + case TYPE_CONST_ENUM: + return sema_analyse_inferred_expr(context, left->type, right); + default: + break; } } // Special handling of f = FOO_BAR if (left->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && left->unresolved_ident_expr.is_const) { if (!sema_analyse_expr(context, right)) return false; - if (type_flatten(right->type)->type_kind == TYPE_ENUM) + switch (type_flatten(right->type)->type_kind) { - return sema_analyse_inferred_expr(context, right->type, left); + case TYPE_ENUM: + case TYPE_CONST_ENUM: + return sema_analyse_inferred_expr(context, right->type, left); + default: + break; } } if (right->expr_kind == EXPR_INITIALIZER_LIST) @@ -2966,7 +2973,7 @@ void sema_expr_convert_enum_to_int(Expr *expr) if (sema_cast_const(expr)) { ASSERT(expr->const_expr.const_kind == CONST_ENUM); - expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_val->enum_constant.ordinal); + expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_val->enum_constant.inner_ordinal); } if (expr->expr_kind == EXPR_ENUM_FROM_ORD) { @@ -3024,7 +3031,7 @@ INLINE bool sema_expr_analyse_from_ordinal(SemaContext *context, Expr *expr, Exp { RETURN_SEMA_ERROR(key, "The ordinal should be an integer."); } - + bool is_const_enum = decl->decl_kind == DECL_CONST_ENUM; if (sema_cast_const(key)) { Int to_convert = key->const_expr.ixx; @@ -3038,6 +3045,12 @@ INLINE bool sema_expr_analyse_from_ordinal(SemaContext *context, Expr *expr, Exp { RETURN_SEMA_ERROR(key, "The ordinal '%s' exceeds the max ordinal '%u'.", int_to_str(max, 10, false), max_enums - 1); } + if (is_const_enum) + { + Expr *val = decl->enums.values[to_convert.i.low]->enum_constant.value; + *expr = *copy_expr_single(val); + return true; + } expr->expr_kind = EXPR_CONST; expr->const_expr = (ExprConst) { .enum_val = decl->enums.values[to_convert.i.low], @@ -3046,7 +3059,10 @@ INLINE bool sema_expr_analyse_from_ordinal(SemaContext *context, Expr *expr, Exp expr->type = decl->type; return true; } - + if (is_const_enum) + { + RETURN_SEMA_ERROR(key, ".from_ordinal on const enums is only valid with compile time constant arguments, maybe you can try using regular enums?"); + } expr->expr_kind = EXPR_ENUM_FROM_ORD; expr->inner_expr = key; expr->type = decl->type; @@ -4380,6 +4396,29 @@ static inline bool sema_expr_replace_with_enum_array(SemaContext *context, Expr return sema_analyse_expr(context, enum_array_expr); } +static inline bool sema_expr_replace_with_const_enum_array(SemaContext *context, Expr *enum_array_expr, Decl *enum_decl) +{ + if (!sema_analyse_decl(context, enum_decl)) return false; + Decl **values = enum_decl->enums.values; + SourceSpan span = enum_array_expr->span; + Expr *initializer = expr_new(EXPR_INITIALIZER_LIST, span); + ArraySize elements = vec_size(values); + Expr **element_values = elements > 0 ? VECNEW(Expr*, elements) : NULL; + Type *kind = enum_decl->type; + for (ArraySize i = 0; i < elements; i++) + { + Decl *decl = values[i]; + Expr *expr = copy_expr_single(decl->enum_constant.value); + vec_add(element_values, expr); + } + initializer->initializer_list = element_values; + enum_array_expr->expr_kind = EXPR_COMPOUND_LITERAL; + enum_array_expr->expr_compound_literal.initializer = initializer; + enum_array_expr->expr_compound_literal.type_info = type_info_new_base(type_get_array(kind, elements), span); + enum_array_expr->resolve_status = RESOLVE_NOT_DONE; + return sema_analyse_expr(context, enum_array_expr); +} + static inline bool sema_expr_replace_with_enum_name_array(SemaContext *context, Expr *enum_array_expr, Decl *enum_decl) { if (!sema_analyse_decl(context, enum_decl)) return false; @@ -4445,6 +4484,7 @@ static inline Decl *sema_check_for_type_method(SemaContext *context, Expr *expr, { SEMA_ERROR(expr, "The method '%s' has private visibility.", name); } + return poisoned_decl; } if (ambiguous) @@ -4490,13 +4530,14 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp switch (decl->decl_kind) { case DECL_ENUM: + case DECL_CONST_ENUM: if (is_const) { if (!sema_expr_analyse_enum_constant(context, expr, name, decl)) { if (missing_ref) goto MISSING_REF; if (!decl_ok(decl)) return false; - SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name); + RETURN_SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name); return false; } return true; @@ -4700,18 +4741,20 @@ static inline bool sema_create_const_kind(SemaContext *context, Expr *expr, Type return true; } -static inline bool sema_create_const_len(Expr *expr, Type *type) +static inline bool sema_create_const_len(Expr *expr, Type *type, Type *flat) { - ASSERT_SPAN(expr, type == type_flatten(type) && "Should be flattened already."); + ASSERT_SPAN(expr, flat == type_flatten(flat) && "Should be flattened already."); size_t len; - switch (type->type_kind) + if (type->type_kind == TYPE_CONST_ENUM) goto ENUMS; + switch (flat->type_kind) { case TYPE_ARRAY: case TYPE_VECTOR: len = type->array.len; break; case TYPE_ENUM: +ENUMS: len = vec_size(type->decl->enums.values); break; case TYPE_INFERRED_ARRAY: @@ -4739,8 +4782,9 @@ static inline bool sema_create_const_inner(SemaContext *context, Expr *expr, Typ case TYPE_DISTINCT: inner = type->decl->distinct->type->canonical; break; + case TYPE_CONST_ENUM: case TYPE_ENUM: - inner = type->decl->enums.type_info->type->canonical; + inner = enum_inner_type(type)->canonical; break; case TYPE_BITSTRUCT: inner = type->decl->strukt.container_type->type->canonical; @@ -5264,7 +5308,7 @@ EVAL: } -static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProperty property) +static bool sema_type_property_is_valid_for_type(CanonicalType *original_type, TypeProperty property) { CanonicalType *type = type_flatten(original_type); switch (property) @@ -5284,6 +5328,7 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper case TYPE_OPTIONAL: case TYPE_DISTINCT: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_BITSTRUCT: case TYPE_ARRAY: case TYPE_FLEXIBLE_ARRAY: @@ -5307,6 +5352,7 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper case TYPE_PROPERTY_IS_SUBSTRUCT: return type->type_kind == TYPE_STRUCT; case TYPE_PROPERTY_LEN: + if (original_type->type_kind == TYPE_CONST_ENUM) return true; switch (type->type_kind) { case TYPE_ARRAY: @@ -5316,16 +5362,17 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper default: return false; } - case TYPE_PROPERTY_FROM_ORDINAL: case TYPE_PROPERTY_LOOKUP: case TYPE_PROPERTY_LOOKUP_FIELD: return type->type_kind == TYPE_ENUM; case TYPE_PROPERTY_MIN: case TYPE_PROPERTY_MAX: return type_is_float(type) || type_is_integer(type); - case TYPE_PROPERTY_ELEMENTS: + case TYPE_PROPERTY_FROM_ORDINAL: case TYPE_PROPERTY_NAMES: case TYPE_PROPERTY_VALUES: + return type->type_kind == TYPE_ENUM || original_type->canonical->type_kind == TYPE_CONST_ENUM; + case TYPE_PROPERTY_ELEMENTS: case TYPE_PROPERTY_ASSOCIATED: return type->type_kind == TYPE_ENUM; case TYPE_PROPERTY_MEMBERSOF: @@ -5400,12 +5447,16 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, case TYPE_PROPERTY_KINDOF: return sema_create_const_kind(context, expr, type); case TYPE_PROPERTY_LEN: - return sema_create_const_len(expr, flat); + return sema_create_const_len(expr, type, flat); case TYPE_PROPERTY_MIN: return sema_create_const_min(expr, type, flat); case TYPE_PROPERTY_MAX: return sema_create_const_max(expr, type, flat); case TYPE_PROPERTY_NAMES: + if (type->type_kind == TYPE_CONST_ENUM) + { + return sema_expr_replace_with_enum_name_array(context, expr, type->decl); + } ASSERT_SPAN(expr, flat->type_kind == TYPE_ENUM); return sema_expr_replace_with_enum_name_array(context, expr, flat->decl); case TYPE_PROPERTY_ASSOCIATED: @@ -5417,6 +5468,10 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, expr_rewrite_const_int(expr, type_isz, vec_size(flat->decl->enums.values)); return true; case TYPE_PROPERTY_VALUES: + if (type->type_kind == TYPE_CONST_ENUM) + { + return sema_expr_replace_with_const_enum_array(context, expr, type->decl); + } ASSERT_SPAN(expr, flat->type_kind == TYPE_ENUM); return sema_expr_replace_with_enum_array(context, expr, flat->decl); case TYPE_PROPERTY_NAN: @@ -5488,21 +5543,28 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, .property = property }; return true; } - FALLTHROUGH; - case TYPE_PROPERTY_FROM_ORDINAL: + goto TYPE_CALL;; case TYPE_PROPERTY_LOOKUP: + if (!compiler.build.old_enums) + { + SEMA_DEPRECATED(expr, ".lookup is deprecated."); + } + goto TYPE_CALL; + case TYPE_PROPERTY_FROM_ORDINAL: case TYPE_PROPERTY_LOOKUP_FIELD: - expr->expr_kind = EXPR_TYPECALL; - expr->type_call_expr = (ExprTypeCall) { - .type = type->type_kind == TYPE_FUNC_PTR - ? type->pointer->function.decl - : type->decl, - .property = property }; - return true; + goto TYPE_CALL; case TYPE_PROPERTY_NONE: return false; } UNREACHABLE +TYPE_CALL: + expr->expr_kind = EXPR_TYPECALL; + expr->type_call_expr = (ExprTypeCall) { + .type = type->type_kind == TYPE_FUNC_PTR + ? type->pointer->function.decl + : type->decl, + .property = property }; + return true; } @@ -5847,6 +5909,14 @@ CHECK_DEEPER: } if (kw == kw_nameof) { + if (flat_type->type_kind == TYPE_CONST_ENUM) + { + if (sema_cast_const(current_parent)) + { + expr_rewrite_const_string(expr, current_parent->const_expr.enum_val->name); + return true; + } + } if (flat_type->type_kind == TYPE_ENUM) { if (sema_cast_const(current_parent)) @@ -5911,7 +5981,7 @@ CHECK_DEEPER: Decl *ref = current_parent->const_expr.enum_val; if (!sema_analyse_decl(context, ref)) return false; ASSERT_SPAN(expr, current_parent->const_expr.const_kind == CONST_ENUM); - Expr *copy_init = copy_expr_single(ref->enum_constant.args[member->var.index]); + Expr *copy_init = copy_expr_single(ref->enum_constant.associated[member->var.index]); expr_replace(expr, copy_init); ASSERT_SPAN(expr, copy_init->resolve_status == RESOLVE_DONE); return true; @@ -6706,12 +6776,12 @@ static bool sema_expr_analyse_op_assign_enum_ptr(SemaContext *context, Expr *rhs type_to_error_string(rhs->type), token_type_to_string(binaryop_to_token(op)), is_enum ? "an enum" : "a pointer"); } - Type *to = is_enum ? flat->decl->enums.type_info->type : type_isz; + Type *to = is_enum ? enum_inner_type(flat) : type_isz; if (!cast_implicit(context, rhs, to, true)) return false; } else { - Type *real_type = type_get_vector(is_enum ? base->decl->enums.type_info->type : type_isz, flat->array.len); + Type *real_type = type_get_vector(is_enum ? enum_inner_type(base) : type_isz, flat->array.len); if (flat_rhs == type_untypedlist) { if (!cast_implicit(context, rhs, real_type, true)) return false; @@ -6867,6 +6937,7 @@ BITSTRUCT_OK: Type *type_rhs_inline = type_flat_for_arithmethics(right->type); + // 5. In the enum case we have to treat this differently. if (base->type_kind == TYPE_ENUM) { @@ -7187,7 +7258,6 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left, { return sema_expr_analyse_enum_add_sub(context, expr, left, right, failed_ref); } - left_type = type_no_optional(left->type)->canonical; right_type = type_no_optional(right->type)->canonical; @@ -9428,6 +9498,7 @@ static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr) case DECL_BITSTRUCT: case DECL_DISTINCT: case DECL_ENUM: + case DECL_CONST_ENUM: case DECL_ENUM_CONSTANT: case DECL_FNTYPE: case DECL_FUNC: @@ -10085,6 +10156,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr case EXPR_NAMED_ARGUMENT: case EXPR_ACCESS_RESOLVED: case EXPR_CT_SUBSCRIPT: + case EXPR_IOTA_DECL: UNREACHABLE case EXPR_BINARY: main_expr->resolve_status = RESOLVE_RUNNING; @@ -10251,6 +10323,27 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty } } +static inline bool sema_expr_analyse_iota_decl(SemaContext *context, Expr *expr) +{ + Decl *decl = expr->iota_decl_expr; + if (!decl_ok(decl)) return false; + if (decl->resolve_status != RESOLVE_DONE) + { + RETURN_SEMA_ERROR(expr, "Enum constants values should never need to be resolved out of order."); + } + Expr *iota_expr = decl->enum_constant.value; + assert(expr_is_const_int(iota_expr)); + + Int value = iota_expr->const_expr.ixx; + Int add = int_add64(value, 1); + if (int_comp(add, value, BINARYOP_LT)) + { + RETURN_SEMA_ERROR(expr, "Enum value would overflow the maximum value of the container type %s.", type_quoted_error_string(type_flatten(decl->type))); + } + expr_rewrite_const_integer(expr, iota_expr->type, add.i); + return true; +} + static inline bool sema_expr_analyse_assignable(SemaContext *context, Expr *expr) { ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING); @@ -10506,6 +10599,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_MAKE_SLICE: case EXPR_CT_SUBSCRIPT: UNREACHABLE + case EXPR_IOTA_DECL: + return sema_expr_analyse_iota_decl(context, expr); case EXPR_TWO: if (!sema_analyse_expr(context, expr->two_expr.first)) return false; if (!sema_analyse_expr_check(context, expr->two_expr.last, check)) return false; @@ -11030,6 +11125,7 @@ IDENT_CHECK:; case EXPR_DESIGNATOR: case EXPR_FORCE_UNWRAP: case EXPR_INITIALIZER_LIST: + case EXPR_IOTA_DECL: case EXPR_LAST_FAULT: case EXPR_MACRO_BLOCK: case EXPR_MACRO_BODY_EXPANSION: diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 694609b93..871dc8d4b 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -129,6 +129,7 @@ INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize * INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result); INLINE void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan span); bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *left, Expr *right, bool *failed_ref); +bool sema_analyse_const_enum_constant_val(SemaContext *context, Decl *decl); INLINE bool sema_check_left_right_const(SemaContext *context, Expr *left, Expr *right) { diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 53da02c9d..3a9148e0b 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -605,6 +605,7 @@ RETRY: case DECL_DISTINCT: sema_trace_type_liveness(decl->distinct->type); FALLTHROUGH; + case DECL_CONST_ENUM: case DECL_BITSTRUCT: case DECL_STRUCT: case DECL_UNION: @@ -612,7 +613,10 @@ RETRY: sema_trace_decl_dynamic_methods(decl); return; case DECL_ENUM_CONSTANT: - sema_trace_expr_list_liveness(decl->enum_constant.args); + if (!decl->enum_constant.is_raw) + { + sema_trace_expr_list_liveness(decl->enum_constant.associated); + } return; case DECL_POISONED: case DECL_ATTRIBUTE: diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index b6db780c6..8d93a5fc4 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -951,6 +951,7 @@ bool sema_resolve_type_decl(SemaContext *context, Type *type) if (!type->function.prototype && type->function.decl->decl_kind == DECL_FNTYPE) return sema_analyse_decl(context, type->function.decl); return true; case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index ed27d70ea..56cd5cc06 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1592,7 +1592,6 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen // If it's an enum this is handled in a special way. is_enum_iterator = index_type->canonical->type_kind == TYPE_ENUM; - // We check that the index is either using integer or enums. if (!type_is_integer(index_type) && !is_enum_iterator) { @@ -1717,7 +1716,7 @@ SKIP_OVERLOAD:; } // Find the actual index type -> flattening the enum - Type *actual_index_type = is_enum_iterator ? index_type->canonical->decl->enums.type_info->type : index_type; + Type *actual_index_type = is_enum_iterator ? enum_inner_type(index_type->canonical) : index_type; // Generate the index variable Decl *idx_decl = decl_new_generated_var(actual_index_type, VARDECL_LOCAL, index ? index->span : enumerator->span); @@ -2365,8 +2364,8 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type { if (is_enum) { - uint32_t ord1 = const_expr->enum_val->enum_constant.ordinal; - uint32_t ord2 = to_const_expr->enum_val->enum_constant.ordinal; + uint32_t ord1 = const_expr->enum_val->enum_constant.inner_ordinal; + uint32_t ord2 = to_const_expr->enum_val->enum_constant.inner_ordinal; if (ord1 > ord2) { sema_error_at(context, extend_span_with_token(expr->span, to_expr->span), @@ -2442,8 +2441,8 @@ INLINE const char *create_missing_enums_in_switch_error(Ast **cases, unsigned fo Expr *e = exprptr(cases[j]->case_stmt.expr); Expr *e_to = exprptrzero(cases[j]->case_stmt.to_expr); ASSERT_SPAN(e, expr_is_const_enum(e)); - uint32_t ordinal_from = e->const_expr.enum_val->enum_constant.ordinal; - uint32_t ordinal_to = e_to ? e_to->const_expr.enum_val->enum_constant.ordinal : ordinal_from; + uint32_t ordinal_from = e->const_expr.enum_val->enum_constant.inner_ordinal; + uint32_t ordinal_to = e_to ? e_to->const_expr.enum_val->enum_constant.inner_ordinal : ordinal_from; if (i >= ordinal_from && i <= ordinal_to) goto CONTINUE; } if (++printed != 1) @@ -2598,6 +2597,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem is_type = true; FALLTHROUGH; case TYPE_ENUM: + case TYPE_CONST_ENUM: case ALL_INTS: case ALL_FLOATS: case TYPE_BOOL: diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 3cafb329d..be66ada4d 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -226,6 +226,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in case DECL_BITSTRUCT: case DECL_UNION: case DECL_ENUM: + case DECL_CONST_ENUM: case DECL_INTERFACE: type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 07239f549..cea5f786a 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -255,6 +255,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) case DECL_VAR: case DECL_BITSTRUCT: case DECL_INTERFACE: + case DECL_CONST_ENUM: break; case DECL_MACRO: case DECL_FUNC: diff --git a/src/compiler/types.c b/src/compiler/types.c index 1bdc1107f..6286d07cf 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -117,6 +117,7 @@ void type_append_name_to_scratch(Type *type) case TYPE_TYPEDEF: UNREACHABLE; case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_DISTINCT: @@ -250,6 +251,7 @@ const char *type_to_error_string(Type *type) case TYPE_WILDCARD: return type->name; case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_TYPEDEF: case TYPE_STRUCT: case TYPE_UNION: @@ -342,8 +344,9 @@ RETRY: type = type->canonical; goto RETRY; case TYPE_ENUM: + case TYPE_CONST_ENUM: ASSERT(type->decl->enums.type_info->resolve_status == RESOLVE_DONE); - type = type->decl->enums.type_info->type->canonical; + type = enum_inner_type(type)->canonical; goto RETRY; case TYPE_STRUCT: case TYPE_UNION: @@ -443,6 +446,7 @@ bool type_is_abi_aggregate(Type *type) case TYPE_TYPEID: case TYPE_POINTER: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_FUNC_PTR: case TYPE_FUNC_RAW: case TYPE_VECTOR: @@ -486,6 +490,7 @@ bool type_is_ordered(Type *type) case TYPE_POINTER: case TYPE_BOOL: case TYPE_ENUM: + case TYPE_CONST_ENUM: return true; case TYPE_TYPEDEF: type = type->canonical; @@ -528,7 +533,8 @@ bool type_is_comparable(Type *type) type = type->array.base; goto RETRY; case TYPE_DISTINCT: - type = type->decl->distinct->type; + case TYPE_CONST_ENUM: + type = type_inline(type); goto RETRY; case TYPE_BOOL: case ALL_INTS: @@ -629,6 +635,7 @@ void type_mangle_introspect_name_to_buffer(Type *type) } return; case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: @@ -705,7 +712,8 @@ AlignSize type_abi_alignment(Type *type) type = type->canonical; goto RETRY; case TYPE_ENUM: - type = type->decl->enums.type_info->type->canonical; + case TYPE_CONST_ENUM: + type = enum_inner_type(type)->canonical; goto RETRY; case TYPE_STRUCT: case TYPE_UNION: @@ -1191,6 +1199,7 @@ bool type_is_valid_for_array(Type *type) case TYPE_TYPEID: case TYPE_POINTER: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_FUNC_PTR: case TYPE_FUNC_RAW: case TYPE_STRUCT: @@ -1457,6 +1466,7 @@ bool type_is_scalar(Type *type) case TYPE_POINTER: case TYPE_FUNC_PTR: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_ANYFAULT: return true; case TYPE_BITSTRUCT: @@ -1717,6 +1727,7 @@ bool type_may_have_method(Type *type) case TYPE_UNION: case TYPE_STRUCT: case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_BITSTRUCT: case ALL_FLOATS: case ALL_INTS: @@ -1760,6 +1771,7 @@ bool type_may_have_sub_elements(Type *type) case TYPE_STRUCT: case TYPE_ENUM: case TYPE_BITSTRUCT: + case TYPE_CONST_ENUM: case TYPE_INTERFACE: return true; default: @@ -1892,14 +1904,14 @@ static inline Type *type_find_max_distinct_type(Type *left, Type *right) { ASSERT(left == left->canonical && right == right->canonical); ASSERT(left != right); - ASSERT(left->type_kind == TYPE_DISTINCT && right->type_kind == TYPE_DISTINCT); + ASSERT(type_is_distinct_like(left) && type_is_distinct_like(right)); static Type *left_types[MAX_SEARCH_DEPTH]; int depth = 0; while (depth < MAX_SEARCH_DEPTH) { left_types[depth++] = left; - if (left->type_kind != TYPE_DISTINCT || !left->decl->is_substruct) break; - left = left->decl->distinct->type; + if (!type_is_distinct_like(left) || !left->decl->is_substruct) break; + left = type_inline(left); if (left == right) return right; } if (depth == MAX_SEARCH_DEPTH) @@ -1913,12 +1925,13 @@ static inline Type *type_find_max_distinct_type(Type *left, Type *right) { if (right == left_types[i]) return right; } - if (right->type_kind != TYPE_DISTINCT || !right->decl->is_substruct) return NULL; - right = right->decl->distinct->type; + if (!type_is_distinct_like(right) || !right->decl->is_substruct) return NULL; + right = type_inline(right); if (left == right) return right; } } + Type *type_find_max_type(Type *type, Type *other) { type = type->canonical; @@ -1955,12 +1968,12 @@ RETRY_DISTINCT: case TYPE_FLEXIBLE_ARRAY: return NULL; case ALL_INTS: - if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other; - if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical); + if (type_is_distinct_like(other) && type_underlying_is_numeric(other)) return other; + if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, enum_inner_type(other)->canonical); if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case ALL_FLOATS: - if (other->type_kind == TYPE_DISTINCT && type_is_float(type_flatten(other))) return other; + if (type_is_distinct_like(other) && type_is_float(type_flatten(other))) return other; if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case TYPE_ANY: @@ -2048,7 +2061,8 @@ RETRY_DISTINCT: // No implicit conversion between vectors return NULL; case TYPE_DISTINCT: - if (other->type_kind == TYPE_DISTINCT) + case TYPE_CONST_ENUM: + if (type_is_distinct_like(other)) { return type_find_max_distinct_type(type, other); } @@ -2059,7 +2073,7 @@ RETRY_DISTINCT: // Try matching with its inline type if (type->decl->is_substruct) { - type = type->decl->distinct->type; + type = type_inline(type); goto RETRY_DISTINCT; } // distinct + any other type => no @@ -2109,6 +2123,8 @@ unsigned type_get_introspection_kind(TypeKind kind) return INTROSPECT_TYPE_POINTER; case TYPE_ENUM: return INTROSPECT_TYPE_ENUM; + case TYPE_CONST_ENUM: + return INTROSPECT_TYPE_CONST_ENUM; case TYPE_FUNC_PTR: return INTROSPECT_TYPE_FUNC; case TYPE_STRUCT: @@ -2167,6 +2183,7 @@ Module *type_base_module(Type *type) case TYPE_FUNC_RAW: return type->function.decl ? type->function.decl->unit->module : NULL; case TYPE_ENUM: + case TYPE_CONST_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: diff --git a/test/test_suite/abi/small_struct_x64.c3t b/test/test_suite/abi/small_struct_x64.c3t index d3b49062a..14b114044 100644 --- a/test/test_suite/abi/small_struct_x64.c3t +++ b/test/test_suite/abi/small_struct_x64.c3t @@ -23,7 +23,7 @@ fn Foo getFoo(Foo f) %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %Foo = type { i8, i8, i8 } -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 define i32 @test.testing() #0 { entry: diff --git a/test/test_suite/any/any_in_any.c3t b/test/test_suite/any/any_in_any.c3t index 2aeab2852..56e828ea1 100644 --- a/test/test_suite/any/any_in_any.c3t +++ b/test/test_suite/any/any_in_any.c3t @@ -11,8 +11,8 @@ fn void main() %any = type { ptr, i64 } @"$ct.any$" = linkonce global %.introspect { i8 7, i64 0, ptr null, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.p$any$" = linkonce global %.introspect { i8 18, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.any$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.p$p$any$" = linkonce global %.introspect { i8 18, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.p$any$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.p$any$" = linkonce global %.introspect { i8 19, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.any$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.p$p$any$" = linkonce global %.introspect { i8 19, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.p$any$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 define void @foo.main() #0 { entry: diff --git a/test/test_suite/any/variant_test.c3t b/test/test_suite/any/variant_test.c3t index 26397da0b..cbb329af0 100644 --- a/test/test_suite/any/variant_test.c3t +++ b/test/test_suite/any/variant_test.c3t @@ -68,7 +68,7 @@ fn void main() @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.double" = linkonce global %.introspect { i8 4, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.any$" = linkonce global %.introspect { i8 7, i64 0, ptr null, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.p$int" = linkonce global %.introspect { i8 18, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.p$int" = linkonce global %.introspect { i8 19, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.bool" = linkonce global %.introspect { i8 1, i64 0, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 define void @foo.test(i64 %0, ptr %1) #0 { diff --git a/test/test_suite/arrays/complex_array_const.c3t b/test/test_suite/arrays/complex_array_const.c3t index a789f773f..fcd12f014 100644 --- a/test/test_suite/arrays/complex_array_const.c3t +++ b/test/test_suite/arrays/complex_array_const.c3t @@ -15,7 +15,7 @@ Connection[3] link @private /* #expect: test.ll -@"$ct.test.Connection" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Connection" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [6 x i8] c"link1\00", align 1 @.str.1 = private unnamed_addr constant [6 x i8] c"link2\00", align 1 @.str.2 = private unnamed_addr constant [6 x i8] c"link3\00", align 1 diff --git a/test/test_suite/attributes/attribute_no_infer_type.c3t b/test/test_suite/attributes/attribute_no_infer_type.c3t index b54507e97..f3bec88a7 100644 --- a/test/test_suite/attributes/attribute_no_infer_type.c3t +++ b/test/test_suite/attributes/attribute_no_infer_type.c3t @@ -14,7 +14,7 @@ attrdef @Attr(MyInt x); /* #expect: test.ll -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 define void @test.main() #0 { entry: diff --git a/test/test_suite/attributes/user_defined_attributes.c3t b/test/test_suite/attributes/user_defined_attributes.c3t index 3a9628188..fc7fa96ee 100644 --- a/test/test_suite/attributes/user_defined_attributes.c3t +++ b/test/test_suite/attributes/user_defined_attributes.c3t @@ -33,7 +33,7 @@ fn void main() @TestZero %Foo = type { i32, [1020 x i8], i32, [1020 x i8] } -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @test.f = local_unnamed_addr global %Foo zeroinitializer, align 1024 define weak void @test.testme2() #0 { diff --git a/test/test_suite/cast/invalid_enum_casts.c3 b/test/test_suite/cast/invalid_enum_casts.c3 index 479a46f52..6da31363d 100644 --- a/test/test_suite/cast/invalid_enum_casts.c3 +++ b/test/test_suite/cast/invalid_enum_casts.c3 @@ -6,11 +6,11 @@ enum MyEnum : int fn int toInt(MyEnum value) { - return (int)value; // #error: but you can use .ordinal + return (int)value; } fn MyEnum toEnum(int value) { - return (MyEnum)value; // #error: but you can use .from_ordinal() + return (MyEnum)value; } diff --git a/test/test_suite/clang/2002-07.c3t b/test/test_suite/clang/2002-07.c3t index f643d032b..6ece2a552 100644 --- a/test/test_suite/clang/2002-07.c3t +++ b/test/test_suite/clang/2002-07.c3t @@ -300,11 +300,11 @@ fn int strcmp(char *s1, char *s2) { %SubStruct = type { i16, i16 } %PBVTest = type { double, double, i32 } -@"$ct.foo.List" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.PBVTest" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.FunStructTest" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 64, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.SubStruct" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.Quad" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.List" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.PBVTest" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.FunStructTest" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 64, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.SubStruct" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Quad" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 @foo.data = local_unnamed_addr global ptr null, align 8 @foo.listNode3 = global %List { i32 4, ptr null }, align 8 @foo.listNode2 = global %List { i32 3, ptr @foo.listNode3 }, align 8 diff --git a/test/test_suite/compile_time/ct_subscript_inc.c3t b/test/test_suite/compile_time/ct_subscript_inc.c3t index 2de048a23..01f1fb146 100644 --- a/test/test_suite/compile_time/ct_subscript_inc.c3t +++ b/test/test_suite/compile_time/ct_subscript_inc.c3t @@ -51,9 +51,9 @@ fn void main() @.str.8 = private unnamed_addr constant [3 x i8] c"%c\00", align 1 @.str.9 = private unnamed_addr constant [5 x i8] c"Acdc\00", align 1 @.__const = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4 -@"$ct.std.io.File" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.std.io.File" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.str.10 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 -@"$ct.a3$int" = linkonce global %.introspect { i8 14, i64 0, ptr null, i64 12, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.a3$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 12, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [0 x i64] zeroinitializer }, align 8 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 @.__const.12 = private unnamed_addr constant [3 x i32] [i32 1, i32 3, i32 3], align 4 diff --git a/test/test_suite/compile_time/untyped_conversions.c3t b/test/test_suite/compile_time/untyped_conversions.c3t index 2c8863014..050787316 100644 --- a/test/test_suite/compile_time/untyped_conversions.c3t +++ b/test/test_suite/compile_time/untyped_conversions.c3t @@ -29,20 +29,20 @@ fn void main() %"int[]" = type { ptr, i64 } %any = type { ptr, i64 } -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [9 x i8] c"%s %s %s\00", align 1 -@"$ct.a2$int" = linkonce global %.introspect { i8 14, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.a2$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.sa$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.v2$int" = linkonce global %.introspect { i8 16, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.sa$int" = linkonce global %.introspect { i8 16, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.v2$int" = linkonce global %.introspect { i8 17, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant [1 x %Foo] [%Foo { i32 1, i32 2 }], align 4 @.__const.1 = private unnamed_addr constant %Foo { i32 1, i32 2 }, align 4 @.__const.2 = private unnamed_addr constant [1 x [2 x i32]] [[2 x i32] [i32 1, i32 2]], align 4 @.__const.3 = private unnamed_addr constant [1 x [2 x double]] [[2 x double] [double 1.000000e+00, double 2.000000e+00]], align 16 @.str.4 = private unnamed_addr constant [15 x i8] c"%s %s {%s, %s}\00", align 1 -@"$ct.a1$a2$int" = linkonce global %.introspect { i8 14, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.a1$a2$double" = linkonce global %.introspect { i8 14, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.a2$double" = linkonce global %.introspect { i8 14, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.a1$a2$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.a1$a2$double" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.a2$double" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8 @"$ct.double" = linkonce global %.introspect { i8 4, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @.__const.5 = private unnamed_addr constant [2 x i32] [i32 1, i32 2], align 4 @.__const.6 = private unnamed_addr constant [2 x i32] [i32 3, i32 4], align 4 diff --git a/test/test_suite/compile_time_introspection/paramsof.c3t b/test/test_suite/compile_time_introspection/paramsof.c3t index 2c4f0b4bd..91d98dc9a 100644 --- a/test/test_suite/compile_time_introspection/paramsof.c3t +++ b/test/test_suite/compile_time_introspection/paramsof.c3t @@ -29,9 +29,9 @@ fn void main() @.str.1 = private unnamed_addr constant [2 x i8] c"b\00", align 1 @"$ct.double" = linkonce global %.introspect { i8 4, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant [2 x %ReflectedParam] [%ReflectedParam { %"char[]" { ptr @.str, i64 1 }, i64 ptrtoint (ptr @"$ct.int" to i64) }, %ReflectedParam { %"char[]" { ptr @.str.1, i64 1 }, i64 ptrtoint (ptr @"$ct.double" to i64) }], align 16 -@"$ct.std.io.File" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.std.io.File" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.str.2 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 -@"$ct.ReflectedParam" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.ReflectedParam" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.str.3 = private unnamed_addr constant [2 x i8] c"a\00", align 1 @.str.4 = private unnamed_addr constant [4 x i8] c"int\00", align 1 @.str.5 = private unnamed_addr constant [2 x i8] c"b\00", align 1 diff --git a/test/test_suite/compile_time_introspection/parentof.c3t b/test/test_suite/compile_time_introspection/parentof.c3t index 2a993cdd4..659b6b266 100644 --- a/test/test_suite/compile_time_introspection/parentof.c3t +++ b/test/test_suite/compile_time_introspection/parentof.c3t @@ -20,8 +20,8 @@ fn void main() /* #expect: foo.ll -@"$ct.foo.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.Bar" = linkonce global %.introspect { i8 9, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Bar" = linkonce global %.introspect { i8 10, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @"$ct.void" = linkonce global %.introspect { i8 0, i64 0, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 ; Function Attrs: diff --git a/test/test_suite/compile_time_introspection/qnameof.c3t b/test/test_suite/compile_time_introspection/qnameof.c3t index d78669117..cf63a6bbb 100644 --- a/test/test_suite/compile_time_introspection/qnameof.c3t +++ b/test/test_suite/compile_time_introspection/qnameof.c3t @@ -22,7 +22,7 @@ fn void main() /* #expect: qnametest.ll -@"$ct.qnametest.Blob" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.qnametest.Blob" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @qnametest.x = local_unnamed_addr global i32 0, align 4 @.str = private unnamed_addr constant [12 x i8] c"printf: %s\0A\00", align 1 @.str.1 = private unnamed_addr constant [7 x i8] c"printf\00", align 1 diff --git a/test/test_suite/concurrency/atomic_load_store_debug.c3t b/test/test_suite/concurrency/atomic_load_store_debug.c3t index 8c29a1a82..8fd02ddb9 100644 --- a/test/test_suite/concurrency/atomic_load_store_debug.c3t +++ b/test/test_suite/concurrency/atomic_load_store_debug.c3t @@ -23,7 +23,7 @@ fn void main() %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %any = type { ptr, i64 } -@"$ct.test.Ghh" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 12, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Ghh" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 12, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 diff --git a/test/test_suite/dynamic/dynamic_tracing.c3t b/test/test_suite/dynamic/dynamic_tracing.c3t index 780e5eb6e..eb6cb6b86 100644 --- a/test/test_suite/dynamic/dynamic_tracing.c3t +++ b/test/test_suite/dynamic/dynamic_tracing.c3t @@ -58,9 +58,9 @@ fn void main() { /* #expect: test.ll -@"$ct.test.Aa" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Ba" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Ca" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Aa" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Ba" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Ca" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @"$sel.foo" = linkonce_odr constant [4 x i8] c"foo\00", align 1 @"$c3_dynamic" = internal global [3 x { ptr, ptr, i64 }] [{ ptr, ptr, i64 } { ptr @test.Aa.foo, ptr @"$sel.foo", i64 ptrtoint (ptr @"$ct.test.Aa" to i64) }, { ptr, ptr, i64 } { ptr @test.Ba.foo, ptr @"$sel.foo", i64 ptrtoint (ptr @"$ct.test.Ba" to i64) }, { ptr, ptr, i64 } { ptr @test.Ca.foo, ptr @"$sel.foo", i64 ptrtoint (ptr @"$ct.test.Ca" to i64) }], section "__DATA,__c3_dynamic", no_sanitize_address, align 8 @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.c3_dynamic_retain, ptr null }], no_sanitize_address diff --git a/test/test_suite/dynamic/inherit_linux.c3t b/test/test_suite/dynamic/inherit_linux.c3t index c14d0f753..3ce011da0 100644 --- a/test/test_suite/dynamic/inherit_linux.c3t +++ b/test/test_suite/dynamic/inherit_linux.c3t @@ -45,7 +45,7 @@ $.dyn_search = comdat any $"$ct.inherit.Test" = comdat any $"$sel.tesT" = comdat any $"$sel.hello" = comdat any -@"$ct.inherit.Test" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.inherit.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 @"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", comdat, align 1 @.panic_msg = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 @.func = internal constant [5 x i8] c"main\00", align 1 diff --git a/test/test_suite/dynamic/inherit_macos.c3t b/test/test_suite/dynamic/inherit_macos.c3t index eb7c608d7..792f9b960 100644 --- a/test/test_suite/dynamic/inherit_macos.c3t +++ b/test/test_suite/dynamic/inherit_macos.c3t @@ -42,7 +42,7 @@ fn void main() %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %any = type { ptr, i64 } -@"$ct.inherit.Test" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.inherit.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", align 1 @.panic_msg = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 @.func = internal constant [5 x i8] c"main\00", align 1 diff --git a/test/test_suite/dynamic/overlapping_function_linux.c3t b/test/test_suite/dynamic/overlapping_function_linux.c3t index 851028955..872f9f5be 100644 --- a/test/test_suite/dynamic/overlapping_function_linux.c3t +++ b/test/test_suite/dynamic/overlapping_function_linux.c3t @@ -36,7 +36,7 @@ fn void main() %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %any = type { ptr, i64 } -@"$ct.overlap.Test" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.overlap.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 @"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", comdat, align 1 @.panic_msg = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 @.file = internal constant [30 x i8] c"overlapping_function_linux.c3\00", align 1 diff --git a/test/test_suite/dynamic/overlapping_function_macos.c3t b/test/test_suite/dynamic/overlapping_function_macos.c3t index 51117b75b..4d9d33473 100644 --- a/test/test_suite/dynamic/overlapping_function_macos.c3t +++ b/test/test_suite/dynamic/overlapping_function_macos.c3t @@ -35,7 +35,7 @@ fn void main() %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %any = type { ptr, i64 } -@"$ct.overlap.Test" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.overlap.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", align 1 @.panic_msg = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 @.file = internal constant [30 x i8] c"overlapping_function_macos.c3\00", align 1 diff --git a/test/test_suite/enumerations/enum_associated_values_other.c3t b/test/test_suite/enumerations/enum_associated_values_other.c3t index 6edd29cf7..4c067c6b9 100644 --- a/test/test_suite/enumerations/enum_associated_values_other.c3t +++ b/test/test_suite/enumerations/enum_associated_values_other.c3t @@ -27,7 +27,7 @@ enum Foo : int (String val) %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %"char[]" = type { ptr, i64 } -@"$ct.abc.Abc" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.abc.Abc" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.enum.ABC = internal constant [4 x i8] c"ABC\00", align 1 @.enum.DEF = internal constant [4 x i8] c"DEF\00", align 1 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 diff --git a/test/test_suite/enumerations/enum_cast_error.c3 b/test/test_suite/enumerations/enum_cast_error.c3 index 3f8615e7f..d54816e5e 100644 --- a/test/test_suite/enumerations/enum_cast_error.c3 +++ b/test/test_suite/enumerations/enum_cast_error.c3 @@ -2,23 +2,24 @@ enum Abc : char { ABC } fn void foo() { - Abc x = Abc.from_ordinal(10); // #error: exceeds the max + + Abc x = (Abc)10; // #error: exceeds the max } fn void bar() { int a; - Abc x = Abc.from_ordinal(a); + Abc x = (Abc)a; } fn void baz() { int a; - Abc x = Abc.from_ordinal(0); + Abc x = (Abc)0; } fn void abc() { int a; - Abc x = Abc.from_ordinal(-1); // #error: negative number + Abc x = (Abc)-1; // #error: negative number } \ No newline at end of file diff --git a/test/test_suite/enumerations/enum_const.c3t b/test/test_suite/enumerations/enum_const.c3t new file mode 100644 index 000000000..acdefd6f9 --- /dev/null +++ b/test/test_suite/enumerations/enum_const.c3t @@ -0,0 +1,701 @@ +// #target: macos-x64 +module test; +import std; + +enum Bar : const String +{ + XABC = "foekf", + XDEF = "foekfokef" +} + +enum Foo : const int +{ + ABC = 4, + DEF, + EGH = Foo.ABC + 10, + GHH, + HELLO = DEF +} + + +enum Bde2 : const int +{ + FOO = 2, + BAR = 100 +} + +typedef Bde3 = int; +const BDE3_FOO = 2; +const BDE3_BAR = 100; + + + +enum Abc2 : const int +{ + UP, + DOWN, +} + + +typedef Abc4 = int; +const Abc4 ABC4_UP = 0b10; +const Abc4 ABC4_DOWN = 0b01; + +bitstruct Abc3 : int +{ + bool down : 0; + bool up : 1; +} + +fn void print_bde2(Bde2 v) +{ + if (v == Bde2.FOO) io::printn("FOO!!"); +} + +fn void print_bde3(Bde3 v) +{ + if (v == BDE3_FOO) io::printn("FOO!!"); +} + + +fn void print_direction2(Abc2 a) +{ + if (a & Abc2.UP) io::printn("Up"); + if (a & Abc2.DOWN) io::printn("Down"); +} + +fn void print_direction4(Abc4 a) +{ + if (a & ABC4_UP) io::printn("Up"); + if (a & ABC4_DOWN) io::printn("Down"); +} + +fn void print_direction3(Abc3 a) +{ + if (a.up) io::printn("Up"); + if (a.down) io::printn("Down"); +} + +fn void main() +{ + print_direction2(Abc2.UP | Abc2.DOWN); + print_direction4(ABC4_UP | ABC4_DOWN); + print_direction3({ .up, .down }); + print_bde2(FOO); + print_bde3(BDE3_FOO); + +} + +fn int test() +{ + Bar bar = XDEF; + Foo f = ABC; + Foo b = Foo.ABC * Foo.ABC; + int x = (int)Foo.ABC; + Foo e = (Foo)4; + return 0; +} + +/* #expect: test.ll + +define void @test.print_bde2(i32 %0) #0 { +entry: + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %eq = icmp eq i32 %0, 2 + br i1 %eq, label %if.then, label %if.exit + +if.then: ; preds = %entry + %1 = call ptr @std.io.stdout() + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str, i64 5) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %2, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %if.then + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10) + %not_err3 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %6, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %5, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err9 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %8, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %7, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit + +if.exit: ; preds = %voiderr, %entry + ret void +} + +define void @test.print_bde3(i32 %0) #0 { +entry: + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %eq = icmp eq i32 %0, 2 + br i1 %eq, label %if.then, label %if.exit + +if.then: ; preds = %entry + %1 = call ptr @std.io.stdout() + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.4, i64 5) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %2, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %if.then + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10) + %not_err3 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %6, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %5, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err9 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %8, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %7, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit + +if.exit: ; preds = %voiderr, %entry + ret void +} + +define void @test.print_direction2(i32 %0) #0 { +entry: + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %len17 = alloca i64, align 8 + %error_var18 = alloca i64, align 8 + %retparam20 = alloca i64, align 8 + %error_var26 = alloca i64, align 8 + %error_var32 = alloca i64, align 8 + %and = and i32 %0, 0 + %i2b = icmp ne i32 %and, 0 + br i1 %i2b, label %if.then, label %if.exit + +if.then: ; preds = %entry + %1 = call ptr @std.io.stdout() + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.5, i64 2) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %2, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %if.then + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10) + %not_err3 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %6, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %5, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err9 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %8, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %7, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit + +if.exit: ; preds = %voiderr, %entry + %and14 = and i32 %0, 1 + %i2b15 = icmp ne i32 %and14, 0 + br i1 %i2b15, label %if.then16, label %if.exit40 + +if.then16: ; preds = %if.exit + %10 = call ptr @std.io.stdout() + %11 = call i64 @std.io.File.write(ptr %retparam20, ptr %10, ptr @.str.6, i64 4) + %not_err21 = icmp eq i64 %11, 0 + %12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true) + br i1 %12, label %after_check23, label %assign_optional22 + +assign_optional22: ; preds = %if.then16 + store i64 %11, ptr %error_var18, align 8 + br label %guard_block24 + +after_check23: ; preds = %if.then16 + br label %noerr_block25 + +guard_block24: ; preds = %assign_optional22 + br label %voiderr39 + +noerr_block25: ; preds = %after_check23 + %13 = load i64, ptr %retparam20, align 8 + store i64 %13, ptr %len17, align 8 + %14 = call i64 @std.io.File.write_byte(ptr %10, i8 zeroext 10) + %not_err27 = icmp eq i64 %14, 0 + %15 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true) + br i1 %15, label %after_check29, label %assign_optional28 + +assign_optional28: ; preds = %noerr_block25 + store i64 %14, ptr %error_var26, align 8 + br label %guard_block30 + +after_check29: ; preds = %noerr_block25 + br label %noerr_block31 + +guard_block30: ; preds = %assign_optional28 + br label %voiderr39 + +noerr_block31: ; preds = %after_check29 + %16 = call i64 @std.io.File.flush(ptr %10) + %not_err33 = icmp eq i64 %16, 0 + %17 = call i1 @llvm.expect.i1(i1 %not_err33, i1 true) + br i1 %17, label %after_check35, label %assign_optional34 + +assign_optional34: ; preds = %noerr_block31 + store i64 %16, ptr %error_var32, align 8 + br label %guard_block36 + +after_check35: ; preds = %noerr_block31 + br label %noerr_block37 + +guard_block36: ; preds = %assign_optional34 + br label %voiderr39 + +noerr_block37: ; preds = %after_check35 + %18 = load i64, ptr %len17, align 8 + %add38 = add i64 %18, 1 + br label %voiderr39 + +voiderr39: ; preds = %noerr_block37, %guard_block36, %guard_block30, %guard_block24 + br label %if.exit40 + +if.exit40: ; preds = %voiderr39, %if.exit + ret void +} + +define void @test.print_direction4(i32 %0) #0 { +entry: + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %len17 = alloca i64, align 8 + %error_var18 = alloca i64, align 8 + %retparam20 = alloca i64, align 8 + %error_var26 = alloca i64, align 8 + %error_var32 = alloca i64, align 8 + %and = and i32 %0, 2 + %i2b = icmp ne i32 %and, 0 + br i1 %i2b, label %if.then, label %if.exit + +if.then: ; preds = %entry + %1 = call ptr @std.io.stdout() + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.7, i64 2) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %2, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %if.then + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10) + %not_err3 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %6, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %5, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err9 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %8, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %7, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit + +if.exit: ; preds = %voiderr, %entry + %and14 = and i32 %0, 1 + %i2b15 = icmp ne i32 %and14, 0 + br i1 %i2b15, label %if.then16, label %if.exit40 + +if.then16: ; preds = %if.exit + %10 = call ptr @std.io.stdout() + %11 = call i64 @std.io.File.write(ptr %retparam20, ptr %10, ptr @.str.8, i64 4) + %not_err21 = icmp eq i64 %11, 0 + %12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true) + br i1 %12, label %after_check23, label %assign_optional22 + +assign_optional22: ; preds = %if.then16 + store i64 %11, ptr %error_var18, align 8 + br label %guard_block24 + +after_check23: ; preds = %if.then16 + br label %noerr_block25 + +guard_block24: ; preds = %assign_optional22 + br label %voiderr39 + +noerr_block25: ; preds = %after_check23 + %13 = load i64, ptr %retparam20, align 8 + store i64 %13, ptr %len17, align 8 + %14 = call i64 @std.io.File.write_byte(ptr %10, i8 zeroext 10) + %not_err27 = icmp eq i64 %14, 0 + %15 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true) + br i1 %15, label %after_check29, label %assign_optional28 + +assign_optional28: ; preds = %noerr_block25 + store i64 %14, ptr %error_var26, align 8 + br label %guard_block30 + +after_check29: ; preds = %noerr_block25 + br label %noerr_block31 + +guard_block30: ; preds = %assign_optional28 + br label %voiderr39 + +noerr_block31: ; preds = %after_check29 + %16 = call i64 @std.io.File.flush(ptr %10) + %not_err33 = icmp eq i64 %16, 0 + %17 = call i1 @llvm.expect.i1(i1 %not_err33, i1 true) + br i1 %17, label %after_check35, label %assign_optional34 + +assign_optional34: ; preds = %noerr_block31 + store i64 %16, ptr %error_var32, align 8 + br label %guard_block36 + +after_check35: ; preds = %noerr_block31 + br label %noerr_block37 + +guard_block36: ; preds = %assign_optional34 + br label %voiderr39 + +noerr_block37: ; preds = %after_check35 + %18 = load i64, ptr %len17, align 8 + %add38 = add i64 %18, 1 + br label %voiderr39 + +voiderr39: ; preds = %noerr_block37, %guard_block36, %guard_block30, %guard_block24 + br label %if.exit40 + +if.exit40: ; preds = %voiderr39, %if.exit + ret void +} + +define void @test.print_direction3(i32 %0) #0 { +entry: + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %len16 = alloca i64, align 8 + %error_var17 = alloca i64, align 8 + %retparam19 = alloca i64, align 8 + %error_var25 = alloca i64, align 8 + %error_var31 = alloca i64, align 8 + %lshrl = lshr i32 %0, 1 + %1 = and i32 1, %lshrl + %trunc = trunc i32 %1 to i8 + %2 = trunc i8 %trunc to i1 + br i1 %2, label %if.then, label %if.exit + +if.then: ; preds = %entry + %3 = call ptr @std.io.stdout() + %4 = call i64 @std.io.File.write(ptr %retparam, ptr %3, ptr @.str.9, i64 2) + %not_err = icmp eq i64 %4, 0 + %5 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %5, label %after_check, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %4, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %if.then + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %6 = load i64, ptr %retparam, align 8 + store i64 %6, ptr %len, align 8 + %7 = call i64 @std.io.File.write_byte(ptr %3, i8 zeroext 10) + %not_err3 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %8, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %7, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %9 = call i64 @std.io.File.flush(ptr %3) + %not_err9 = icmp eq i64 %9, 0 + %10 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %10, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %9, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %11 = load i64, ptr %len, align 8 + %add = add i64 %11, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit + +if.exit: ; preds = %voiderr, %entry + %12 = and i32 1, %0 + %trunc14 = trunc i32 %12 to i8 + %13 = trunc i8 %trunc14 to i1 + br i1 %13, label %if.then15, label %if.exit39 + +if.then15: ; preds = %if.exit + %14 = call ptr @std.io.stdout() + %15 = call i64 @std.io.File.write(ptr %retparam19, ptr %14, ptr @.str.10, i64 4) + %not_err20 = icmp eq i64 %15, 0 + %16 = call i1 @llvm.expect.i1(i1 %not_err20, i1 true) + br i1 %16, label %after_check22, label %assign_optional21 + +assign_optional21: ; preds = %if.then15 + store i64 %15, ptr %error_var17, align 8 + br label %guard_block23 + +after_check22: ; preds = %if.then15 + br label %noerr_block24 + +guard_block23: ; preds = %assign_optional21 + br label %voiderr38 + +noerr_block24: ; preds = %after_check22 + %17 = load i64, ptr %retparam19, align 8 + store i64 %17, ptr %len16, align 8 + %18 = call i64 @std.io.File.write_byte(ptr %14, i8 zeroext 10) + %not_err26 = icmp eq i64 %18, 0 + %19 = call i1 @llvm.expect.i1(i1 %not_err26, i1 true) + br i1 %19, label %after_check28, label %assign_optional27 + +assign_optional27: ; preds = %noerr_block24 + store i64 %18, ptr %error_var25, align 8 + br label %guard_block29 + +after_check28: ; preds = %noerr_block24 + br label %noerr_block30 + +guard_block29: ; preds = %assign_optional27 + br label %voiderr38 + +noerr_block30: ; preds = %after_check28 + %20 = call i64 @std.io.File.flush(ptr %14) + %not_err32 = icmp eq i64 %20, 0 + %21 = call i1 @llvm.expect.i1(i1 %not_err32, i1 true) + br i1 %21, label %after_check34, label %assign_optional33 + +assign_optional33: ; preds = %noerr_block30 + store i64 %20, ptr %error_var31, align 8 + br label %guard_block35 + +after_check34: ; preds = %noerr_block30 + br label %noerr_block36 + +guard_block35: ; preds = %assign_optional33 + br label %voiderr38 + +noerr_block36: ; preds = %after_check34 + %22 = load i64, ptr %len16, align 8 + %add37 = add i64 %22, 1 + br label %voiderr38 + +voiderr38: ; preds = %noerr_block36, %guard_block35, %guard_block29, %guard_block23 + br label %if.exit39 + +if.exit39: ; preds = %voiderr38, %if.exit + ret void +} +define void @test.main() #0 { +entry: + call void @test.print_direction2(i32 1) + call void @test.print_direction4(i32 3) + call void @test.print_direction3(i32 3) + call void @test.print_bde2(i32 2) + call void @test.print_bde3(i32 2) + ret void +} + +define i32 @test.test() #0 { +entry: + %bar = alloca %"char[]", align 8 + %f = alloca i32, align 4 + %b = alloca i32, align 4 + %x = alloca i32, align 4 + %e = alloca i32, align 4 + store %"char[]" { ptr @.str.11, i64 9 }, ptr %bar, align 8 + store i32 4, ptr %f, align 4 + store i32 16, ptr %b, align 4 + store i32 4, ptr %x, align 4 + store i32 4, ptr %e, align 4 + ret i32 0 +} diff --git a/test/test_suite/enumerations/enum_conversions.c3t b/test/test_suite/enumerations/enum_conversions.c3t index 9922feec3..434d0f42f 100644 --- a/test/test_suite/enumerations/enum_conversions.c3t +++ b/test/test_suite/enumerations/enum_conversions.c3t @@ -6,13 +6,13 @@ enum Abc : char { ABC } fn void main() { int a; - Abc x = Abc.from_ordinal(a); + Abc x = (Abc)a; long z; - Abc y = Abc.from_ordinal(z); + Abc y = (Abc)z; a = 256; - y = Abc.from_ordinal(a); + y = (Abc)a; a = -1; - y = Abc.from_ordinal(a); + y = (Abc)a; } /* #expect: test.ll diff --git a/test/test_suite/enumerations/enum_lookup.c3t b/test/test_suite/enumerations/enum_lookup.c3t index 0de7dd618..6c94050e5 100644 --- a/test/test_suite/enumerations/enum_lookup.c3t +++ b/test/test_suite/enumerations/enum_lookup.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +/* module test; import std; @@ -15,7 +16,7 @@ fn int main(String[] a) return x.ordinal ?? 222; } -/* #expect: test.ll +/* expect: test.ll define i32 @test.main(ptr %0, i64 %1) #0 { entry: diff --git a/test/test_suite/enumerations/enum_signed_cast_swap.c3t b/test/test_suite/enumerations/enum_signed_cast_swap.c3t index f88545e7b..8b59417ca 100644 --- a/test/test_suite/enumerations/enum_signed_cast_swap.c3t +++ b/test/test_suite/enumerations/enum_signed_cast_swap.c3t @@ -14,7 +14,7 @@ fn void foo(Mouse_Button button) fn int main() { uint x = 1; - foo(Mouse_Button.from_ordinal(x)); + foo((Mouse_Button)x); return 0; } diff --git a/test/test_suite/enumerations/inline_enum_compare.c3t b/test/test_suite/enumerations/inline_enum_compare.c3t index 6f79b2485..085902470 100644 --- a/test/test_suite/enumerations/inline_enum_compare.c3t +++ b/test/test_suite/enumerations/inline_enum_compare.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +/* module test; typedef Baz = int; enum Foo : char (inline Baz x) @@ -12,7 +13,7 @@ fn void main() if (y == x) return; } -/* #expect: test.ll +/* expect: test.ll define void @test.main() #0 { entry: diff --git a/test/test_suite/enumerations/inline_enum_size.c3 b/test/test_suite/enumerations/inline_enum_size.c3 index 916628b59..62d9fed8d 100644 --- a/test/test_suite/enumerations/inline_enum_size.c3 +++ b/test/test_suite/enumerations/inline_enum_size.c3 @@ -1,3 +1,4 @@ +/* enum Bar : inline usz { FOO, @@ -17,3 +18,4 @@ fn int main() char[Bar2.BAR] a; return 0; } +*/ \ No newline at end of file diff --git a/test/test_suite/enumerations/inline_enums.c3t b/test/test_suite/enumerations/inline_enums.c3t index 56da02b1e..ebb524a45 100644 --- a/test/test_suite/enumerations/inline_enums.c3t +++ b/test/test_suite/enumerations/inline_enums.c3t @@ -1,6 +1,6 @@ // #target: macos-x64 module test; - +/* enum Abc : inline int { ABC, @@ -20,7 +20,7 @@ fn void main() String hello = Foo.ABC; String world = Foo.DEF; } -/* #expect: test.ll +/* expect: test.ll define void @test.main() #0 { entry: diff --git a/test/test_suite/enumerations/lookup_errors.c3 b/test/test_suite/enumerations/lookup_errors.c3 index 6d12f04ba..35a84947b 100644 --- a/test/test_suite/enumerations/lookup_errors.c3 +++ b/test/test_suite/enumerations/lookup_errors.c3 @@ -1,4 +1,4 @@ - +/* typedef Baz = int; enum Foo : char (inline Baz x, String hello) { @@ -12,21 +12,22 @@ enum Bar : char (Baz x) fn void test1() { - (void)Bar.lookup(123); // #error: 'lookup' requires an inline associated value + (void)Bar.lookup(123); // error: 'lookup' requires an inline associated value } fn void test2() { - Foo.lookup(123, 322); // #error: Expected one (1) - Foo.lookup(); // #error: Expected one (1) - Foo.lookup_field(0); // #error: requires two arguments - Foo.lookup_field(33, 22, 44); // #error: requires two arguments + Foo.lookup(123, 322); // error: Expected one (1) + Foo.lookup(); // error: Expected one (1) + Foo.lookup_field(0); // error: requires two arguments + Foo.lookup_field(33, 22, 44); // error: requires two arguments } fn void test3() { - Foo.lookup("hello"); // #error: possible to cast 'String' - Foo.lookup_field("hello", "hello"); // #error: identifier - Foo.lookup_field(hello, 2); // #error: possible to cast 'int' - Foo.lookup_field(err, 4); // #error: no associated value of + Foo.lookup("hello"); // error: possible to cast 'String' + Foo.lookup_field("hello", "hello"); // error: identifier + Foo.lookup_field(hello, 2); // error: possible to cast 'int' + Foo.lookup_field(err, 4); // error: no associated value of } +*/ \ No newline at end of file diff --git a/test/test_suite/errors/optional_taddr_and_access.c3t b/test/test_suite/errors/optional_taddr_and_access.c3t index adc082ad7..deefdb0af 100644 --- a/test/test_suite/errors/optional_taddr_and_access.c3t +++ b/test/test_suite/errors/optional_taddr_and_access.c3t @@ -24,7 +24,7 @@ fn void main() %Foo = type { i32, i32 } -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 @test.FOO = linkonce constant %"char[]" { ptr @test.FOO.nameof, i64 9 }, align 8 @test.FOO.nameof = internal constant [10 x i8] c"test::FOO\00", align 1 diff --git a/test/test_suite/expressions/casts/cast_enum_to_various.c3 b/test/test_suite/expressions/casts/cast_enum_to_various.c3 index 286a36df6..f7dfe9d59 100644 --- a/test/test_suite/expressions/casts/cast_enum_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_enum_to_various.c3 @@ -17,7 +17,7 @@ alias Func = fn void(Enum); fn void test1(Enum e) { - bool a = (bool)e; // #error: bool + bool a = (bool)e; char b = (char)e.ordinal; uint c = (uint)e.ordinal; float d = (float)e; // #error: float diff --git a/test/test_suite/expressions/optional_ternary.c3t b/test/test_suite/expressions/optional_ternary.c3t index 40f5cc114..9158d152f 100644 --- a/test/test_suite/expressions/optional_ternary.c3t +++ b/test/test_suite/expressions/optional_ternary.c3t @@ -63,7 +63,7 @@ target triple = "x86_64-apple @"test.Foo$X" = linkonce constant %.fault { i64 ptrtoint (%.introspect* @"$ct.test.Foo" to i64), %"char[]" { i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.fault, i64 0, i64 0), i64 1 } }, align 8 @.fault = internal constant [2 x i8] c"X\00", align 1 -@"$ct.test.Foo" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.zstr = internal constant [28 x i8] c"Runtime error force unwrap!\00", align 1 @.zstr.1 = internal constant [20 x i8] c"optional_ternary.c3\00", align 1 @.zstr.2 = internal constant [5 x i8] c"main\00", align 1 diff --git a/test/test_suite/expressions/pointer_access.c3t b/test/test_suite/expressions/pointer_access.c3t index a6b457d15..27f3746cb 100644 --- a/test/test_suite/expressions/pointer_access.c3t +++ b/test/test_suite/expressions/pointer_access.c3t @@ -42,10 +42,10 @@ fn void testSimple() %.anon = type { i32, i32 } %.anon.0 = type { double } -@"$ct.pointer_access.c" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 -@"$ct.pointer_access.$anon" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.pointer_access.$anon.4" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.pointer_access.ExtraSimple" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8 +@"$ct.pointer_access.c" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 +@"$ct.pointer_access.$anon" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.pointer_access.$anon.4" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.pointer_access.ExtraSimple" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [71 x i8] c"a = %d, c.e = %f, c.f = %f, c.j = %f, g = %d, o0 = %f, r = %d, s = %d\0A\00", align 1 define void @pointer_access.testSimple() #0 { diff --git a/test/test_suite/functions/func_ptr_conversions_and_names.c3t b/test/test_suite/functions/func_ptr_conversions_and_names.c3t index 0db1581e6..4f3aa0f63 100644 --- a/test/test_suite/functions/func_ptr_conversions_and_names.c3t +++ b/test/test_suite/functions/func_ptr_conversions_and_names.c3t @@ -37,8 +37,8 @@ fn void main() @.str.2 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 @.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 @.str.4 = private unnamed_addr constant [12 x i8] c"fn int(int)\00", align 1 -@"$ct.String" = linkonce global %.introspect { i8 17, i64 ptrtoint (ptr @"$ct.sa$char" to i64), ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 -@"$ct.sa$char" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.String" = linkonce global %.introspect { i8 18, i64 ptrtoint (ptr @"$ct.sa$char" to i64), ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.sa$char" = linkonce global %.introspect { i8 16, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.char" = linkonce global %.introspect { i8 3, i64 0, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @.str.5 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 @.str.6 = private unnamed_addr constant [12 x i8] c"fn int(int)\00", align 1 @@ -48,7 +48,7 @@ fn void main() @.str.10 = private unnamed_addr constant [12 x i8] c"fn int(int)\00", align 1 @.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 @.str.12 = private unnamed_addr constant [13 x i8] c"fn int!(int)\00", align 1 -@"$ct.fn$int$int$" = linkonce global %.introspect { i8 12, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.fn$int$int$" = linkonce global %.introspect { i8 13, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 define void @test.main() #0 { entry: diff --git a/test/test_suite/functions/test_regression.c3t b/test/test_suite/functions/test_regression.c3t index af54c6e56..c1c05e79b 100644 --- a/test/test_suite/functions/test_regression.c3t +++ b/test/test_suite/functions/test_regression.c3t @@ -237,11 +237,11 @@ fn Type getValue(Blob blob) %List = type { i64, i64, %any, ptr } %Foo = type { i32, i32 } -@"$ct.test.Bobo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Blob" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Foor" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Foo2" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Blob" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foor" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.test.MyEnum" = linkonce global { i8, i64, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 0, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.HELO, i64 4 }, %"char[]" { ptr @.enum.WORLD, i64 5 }, %"char[]" { ptr @.enum.BYE, i64 3 }] }, align 8 @test_static.x = internal unnamed_addr global i32 1, align 4 diff --git a/test/test_suite/functions/test_regression_mingw.c3t b/test/test_suite/functions/test_regression_mingw.c3t index 7a2f92389..b9c71e59a 100644 --- a/test/test_suite/functions/test_regression_mingw.c3t +++ b/test/test_suite/functions/test_regression_mingw.c3t @@ -253,11 +253,11 @@ $"$ct.int" = comdat any $"$ct.test.MyEnum" = comdat any -@"$ct.test.Bobo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8 -@"$ct.test.Blob" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 -@"$ct.test.Foor" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 -@"$ct.test.Foo2" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.test.Blob" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.test.Foor" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8 @.enum.HELO = internal constant [5 x i8] c"HELO\00", align 1 @.enum.WORLD = internal constant [6 x i8] c"WORLD\00", align 1 @.enum.BYE = internal constant [4 x i8] c"BYE\00", align 1 diff --git a/test/test_suite/generic/nested_typedef.c3t b/test/test_suite/generic/nested_typedef.c3t index 5d3e7459a..90f8e1246 100644 --- a/test/test_suite/generic/nested_typedef.c3t +++ b/test/test_suite/generic/nested_typedef.c3t @@ -24,7 +24,7 @@ fn void main() {} /* #expect: test.ll -@"$ct.test.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Foo2" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 define i32 @test.test() #0 { define i32 @test.test2() #0 { diff --git a/test/test_suite/initializer_lists/general_tests.c3t b/test/test_suite/initializer_lists/general_tests.c3t index 1c72c3a3e..170afc755 100644 --- a/test/test_suite/initializer_lists/general_tests.c3t +++ b/test/test_suite/initializer_lists/general_tests.c3t @@ -37,8 +37,8 @@ fn int test() %"int[]" = type { ptr, i64 } %"Bar[]" = type { ptr, i64 } -@"$ct.general_tests.Baz" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.general_tests.Bar" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.general_tests.Baz" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.general_tests.Bar" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8 @test.foo1 = internal unnamed_addr global i32 22, align 4 @.str = private unnamed_addr constant [7 x i8] c"Hello!\00", align 1 diff --git a/test/test_suite/initializer_lists/statics.c3t b/test/test_suite/initializer_lists/statics.c3t index f7a634016..725e9f1c3 100644 --- a/test/test_suite/initializer_lists/statics.c3t +++ b/test/test_suite/initializer_lists/statics.c3t @@ -35,8 +35,8 @@ fn int main() %Bar = type { i32, i32 } %"Bar[]" = type { ptr, i64 } -@"$ct.statics.Baz" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.statics.Bar" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.statics.Baz" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.statics.Bar" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant [1 x %Bar] [%Bar { i32 1, i32 2 }], align 4 @.__const_slice = private unnamed_addr global [1 x %Bar] [%Bar { i32 1, i32 2 }], align 4 @test.c = internal unnamed_addr global %"Bar[]" { ptr @.__const_slice, i64 1 }, align 8 diff --git a/test/test_suite/initializer_lists/subarrays.c3t b/test/test_suite/initializer_lists/subarrays.c3t index 5cc523fca..1c47a6841 100644 --- a/test/test_suite/initializer_lists/subarrays.c3t +++ b/test/test_suite/initializer_lists/subarrays.c3t @@ -50,8 +50,8 @@ fn int main() %"int[]" = type { ptr, i64 } %Baz = type { double } -@"$ct.subarrays.Baz" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.subarrays.Bar" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.subarrays.Baz" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.subarrays.Bar" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.__const_slice = private unnamed_addr global [2 x %Bar] [%Bar { i32 3, i32 4 }, %Bar { i32 8, i32 9 }], align 16 @subarrays.arrbar = local_unnamed_addr global %"Bar[]" { ptr @.__const_slice, i64 2 }, align 8 @.__const_slice.3 = private unnamed_addr global [2 x i32] [i32 1, i32 2], align 4 diff --git a/test/test_suite/macros/userland_bitcast.c3t b/test/test_suite/macros/userland_bitcast.c3t index 2b2c913fc..6f425e337 100644 --- a/test/test_suite/macros/userland_bitcast.c3t +++ b/test/test_suite/macros/userland_bitcast.c3t @@ -79,7 +79,7 @@ fn void main() %Foo = type { i16, i8, i8, i16, i16 } -@"$ct.userland_bitcast.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 +@"$ct.userland_bitcast.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [16 x i8] c"%f => %d => %f\0A\00", align 1 @.str.1 = private unnamed_addr constant [18 x i8] c"%e => %llu => %e\0A\00", align 1 diff --git a/test/test_suite/statements/custom_foreach_with_ref.c3t b/test/test_suite/statements/custom_foreach_with_ref.c3t index 1fb04c457..8d6207323 100644 --- a/test/test_suite/statements/custom_foreach_with_ref.c3t +++ b/test/test_suite/statements/custom_foreach_with_ref.c3t @@ -85,7 +85,7 @@ fn void main() %Foo = type { [3 x i32] } -@"$ct.foo.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 12, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 12, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.str = private unnamed_addr constant [11 x i8] c"getFields\0A\00", align 1 @.__const = private unnamed_addr constant [5 x i32] [i32 3, i32 5, i32 2, i32 10, i32 111], align 16 @.str.1 = private unnamed_addr constant [11 x i8] c"Call made\0A\00", align 1 diff --git a/test/test_suite/statements/foreach_custom_macro.c3t b/test/test_suite/statements/foreach_custom_macro.c3t index 85926974b..26497fc9d 100644 --- a/test/test_suite/statements/foreach_custom_macro.c3t +++ b/test/test_suite/statements/foreach_custom_macro.c3t @@ -35,7 +35,7 @@ extern fn int printf(char *fmt, ...); %Foo = type { %"int[]" } %"int[]" = type { ptr, i64 } -@"$ct.foo.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant [3 x i32] [i32 1, i32 3, i32 10], align 4 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index 895c9ccb0..42dd719c1 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -28,9 +28,9 @@ fn void test_check_nums() Foo f = A; switch (f) { - case Foo.from_ordinal(1): + case (Foo)1: break; - case Foo.from_ordinal(0): + case (Foo)0: break; } } @@ -66,7 +66,7 @@ fn void test_duplicate_case2(Foo i) { case A: break; - case Foo.from_ordinal(1): + case (Foo)1: break; case A: // #error: same case value appears break; diff --git a/test/test_suite/struct/nested_struct_init.c3t b/test/test_suite/struct/nested_struct_init.c3t index 074a22705..c67162466 100644 --- a/test/test_suite/struct/nested_struct_init.c3t +++ b/test/test_suite/struct/nested_struct_init.c3t @@ -38,12 +38,12 @@ fn void main() %Matrix2x2_b = type { %.anon.1 } %.anon.1 = type { [4 x float] } -@"$ct.foo.$anon" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.$anon.3" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.Matrix2x2" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.$anon.6" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.$anon.7" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.foo.Matrix2x2_b" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.$anon" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.$anon.3" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Matrix2x2" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.$anon.6" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.$anon.7" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.foo.Matrix2x2_b" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant %Matrix2x2 { %.anon { %.anon.0 { float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00 } } }, align 4 @.__const.8 = private unnamed_addr constant %Matrix2x2_b { %.anon.1 { [4 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00] } }, align 4 @.str = private unnamed_addr constant [13 x i8] c"%f %f %f %f\0A\00", align 1 diff --git a/test/test_suite/struct/struct_as_value.c3t b/test/test_suite/struct/struct_as_value.c3t index 7bd97267a..58d5a0602 100644 --- a/test/test_suite/struct/struct_as_value.c3t +++ b/test/test_suite/struct/struct_as_value.c3t @@ -16,7 +16,7 @@ fn Event test(int x) /* #expect: test.ll %Event = type { i32 } -@"$ct.test.Event" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Event" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant %Event { i32 1 }, align 4 @.__const.1 = private unnamed_addr constant %Event { i32 2 }, align 4 diff --git a/test/test_suite/struct/struct_codegen.c3t b/test/test_suite/struct/struct_codegen.c3t index bac07a6cd..966691695 100644 --- a/test/test_suite/struct/struct_codegen.c3t +++ b/test/test_suite/struct/struct_codegen.c3t @@ -16,7 +16,7 @@ fn void test1() %Point = type { i32, i32 } -@"$ct.test.Point" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Point" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.__const = private unnamed_addr constant %Point { i32 5, i32 6 }, align 4 define void @test.test1() #0 { diff --git a/test/test_suite/struct/struct_const_construct_simple.c3t b/test/test_suite/struct/struct_const_construct_simple.c3t index 7b670605a..2a81d9db5 100644 --- a/test/test_suite/struct/struct_const_construct_simple.c3t +++ b/test/test_suite/struct/struct_const_construct_simple.c3t @@ -20,7 +20,7 @@ Foo foo8 @private = FOO7; /* #expect: structo.ll -@"$ct.structo.Foo" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.structo.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @structo.x = internal unnamed_addr global i64 16, align 8 @structo.foo1 = internal unnamed_addr global %Foo { i32 1, i64 2 }, align 8 @structo.foo2 = internal unnamed_addr global %Foo { i32 2, i64 0 }, align 8 diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 7db31f1ad..acea76d33 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -58,7 +58,7 @@ fn void? Lexer.init(&self, InStream reader, Ident ident, Allocator using = mem) { String name = tok.token; assert(name.len > 0 && name.len <= ushort.max); - trie.set(name, Token.from_ordinal(i))!; + trie.set(name, (Token)i)!; max_token = max(max_token, (ushort)name.len); } foreach (tok : Comment.values) @@ -679,7 +679,7 @@ fn void test() %List = type { i64, i64, %any, ptr } %.anon = type { %"char[]" } -@"$ct.lexer_test.UintTest" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.lexer_test.UintTest" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.enum.KEYWORD1 = internal constant [9 x i8] c"KEYWORD1\00", align 1 @.enum.KEYWORD2 = internal constant [9 x i8] c"KEYWORD2\00", align 1 @.enum.SINGLE = internal constant [7 x i8] c"SINGLE\00", align 1 @@ -697,7 +697,7 @@ fn void test() @.str.5 = private unnamed_addr constant [3 x i8] c"*/\00", align 1 @"lexer_test.Comment$end" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str.4, i64 1 }, %"char[]" { ptr @.str.5, i64 2 }], align 8 @std.core.ascii.ASCII_LOOKUP = extern_weak constant [256 x i16], align 16 -@"$ct.std.io.ByteReader" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.std.io.ByteReader" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @std.core.mem.allocator.thread_allocator = extern_weak thread_local global %any, align 8 ; Function Attrs: diff --git a/test/test_suite/types/enum_inference.c3 b/test/test_suite/types/enum_inference.c3 index 9c7f54325..cf2191f75 100644 --- a/test/test_suite/types/enum_inference.c3 +++ b/test/test_suite/types/enum_inference.c3 @@ -25,8 +25,8 @@ fn void enumInferenceTest() bool y = x1 == x1; Inf2 z = C; if (z == Inf2.A) return; - if (z == Inf2.from_ordinal(1)) return; - z = Inf2.from_ordinal(2); + if (z == (Inf2)1) return; + z = (Inf2)2; switch (z) { case Inf2.A: @@ -34,7 +34,7 @@ fn void enumInferenceTest() return; case B: return; - case Inf2.from_ordinal(2): + case (Inf2)2: x1 += 1; return; default: diff --git a/test/test_suite/visibility/export_property.c3t b/test/test_suite/visibility/export_property.c3t index c9efe1f28..d47e4a0fd 100644 --- a/test/test_suite/visibility/export_property.c3t +++ b/test/test_suite/visibility/export_property.c3t @@ -31,8 +31,8 @@ struct Test %Test = type { %.anon, i32, i32, [0 x i32] } %.anon = type { i32, i32 } -@"$ct.test.$anon" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 -@"$ct.test.Test" = linkonce global %.introspect { i8 9, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.$anon" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8 @.enum.ABC = internal constant [4 x i8] c"ABC\00", align 1 @.enum.DEF = internal constant [4 x i8] c"DEF\00", align 1 @"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 diff --git a/test/unit/stdlib/collections/map.c3 b/test/unit/stdlib/collections/map.c3 index 1f6eb76c0..524c7c906 100644 --- a/test/unit/stdlib/collections/map.c3 +++ b/test/unit/stdlib/collections/map.c3 @@ -63,7 +63,7 @@ enum Foobar : inline char BAZ } -enum Foobar2 : int (inline char y) +enum Foobar2 : const inline int { ABC = 3, DEF = 5, diff --git a/test/unit/stdlib/time/format.c3 b/test/unit/stdlib/time/format.c3 index cba2891b0..4bfc77d2b 100644 --- a/test/unit/stdlib/time/format.c3 +++ b/test/unit/stdlib/time/format.c3 @@ -9,7 +9,7 @@ fn void test_with_tz() { FormatTzTestSpec[*] tests = { { datetime::from_date(1970, Month.JANUARY, 1, 0, 0, 0).with_gmt_offset(0), RFC1123, "Thu, 01 Jan 1970 00:00:00 GMT" }, - { datetime::from_date(1994, Month.from_ordinal(10), 6, 8, 49, 37).with_gmt_offset(0), RFC1123, "Sun, 06 Nov 1994 08:49:37 GMT" }, + { datetime::from_date(1994, (Month)10, 6, 8, 49, 37).with_gmt_offset(0), RFC1123, "Sun, 06 Nov 1994 08:49:37 GMT" }, { datetime::from_date(2020, Month.JANUARY, 1, 0, 0, 0).with_gmt_offset(0), RFC1123, "Wed, 01 Jan 2020 00:00:00 GMT" }, { datetime::from_date(2020, Month.JANUARY, 1, 0, 0, 0).with_gmt_offset(-3600), RFC1123, "Wed, 01 Jan 2020 01:00:00 GMT" }, { datetime::from_date(2020, Month.JANUARY, 1, 0, 0, 0).with_gmt_offset(-3600), RFC1123Z, "Wed, 01 Jan 2020 00:00:00 -0100" },