| author | |
| committer | |
| log | 3cebaaad1ca16a9e0203ed8c1684d0ce72da9487 |
| tree | a153e50f75fad0a1b6c683ad5c06e28e102ff848 |
| parent | 08eedc962d8e2582db8fb5b4a50114f2913519fd |
GenZir struct now has rl_ty_inst field which tracks the result location
type (if any) a block expects all of its results to be coerced to.
Remove a redundant coercion on const local initialization with a
specified type.
Switch expressions, during elision of store_to_block_ptr instructions,
now re-purpose them to be type coercion when the block has a type in the
result location.4 files changed, 227 insertions(+), 105 deletions(-)
src/AstGen.zig+65-22| ... | ... | @@ -1415,6 +1415,7 @@ fn varDecl( |
| 1415 | 1415 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); |
| 1416 | 1416 | opt_type_inst = type_inst; |
| 1417 | 1417 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); |
| 1418 | init_scope.rl_ty_inst = type_inst; | |
| 1418 | 1419 | } else { |
| 1419 | 1420 | const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node); |
| 1420 | 1421 | resolve_inferred_alloc = alloc; |
| ... | ... | @@ -1441,20 +1442,13 @@ fn varDecl( |
| 1441 | 1442 | parent_zir.appendAssumeCapacity(src_inst); |
| 1442 | 1443 | } |
| 1443 | 1444 | assert(parent_zir.items.len == expected_len); |
| 1444 | const casted_init = if (opt_type_inst != .none) | |
| 1445 | try gz.addPlNode(.as_node, var_decl.ast.type_node, zir.Inst.As{ | |
| 1446 | .dest_type = opt_type_inst, | |
| 1447 | .operand = init_inst, | |
| 1448 | }) | |
| 1449 | else | |
| 1450 | init_inst; | |
| 1451 | 1445 | |
| 1452 | 1446 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 1453 | 1447 | sub_scope.* = .{ |
| 1454 | 1448 | .parent = scope, |
| 1455 | 1449 | .gen_zir = gz, |
| 1456 | 1450 | .name = ident_name, |
| 1457 | .inst = casted_init, | |
| 1451 | .inst = init_inst, | |
| 1458 | 1452 | .src = name_src, |
| 1459 | 1453 | }; |
| 1460 | 1454 | return &sub_scope.base; |
| ... | ... | @@ -3029,25 +3023,48 @@ fn switchExpr( |
| 3029 | 3023 | // all prongs, except for prongs that ended with a noreturn instruction. |
| 3030 | 3024 | // Elide all the `store_to_block_ptr` instructions. |
| 3031 | 3025 | |
| 3026 | // The break instructions need to have their operands coerced if the | |
| 3027 | // switch's result location is a `ty`. In this case we overwrite the | |
| 3028 | // `store_to_block_ptr` instruction with an `as` instruction and repurpose | |
| 3029 | // it as the break operand. | |
| 3030 | ||
| 3032 | 3031 | var extra_index: usize = 0; |
| 3033 | 3032 | extra_index += 2; |
| 3034 | 3033 | extra_index += @boolToInt(multi_cases_len != 0); |
| 3035 | if (special_prong != .none) { | |
| 3034 | if (special_prong != .none) special_prong: { | |
| 3036 | 3035 | const body_len_index = extra_index; |
| 3037 | 3036 | const body_len = scalar_cases_payload.items[extra_index]; |
| 3038 | 3037 | extra_index += 1; |
| 3038 | if (body_len < 2) { | |
| 3039 | extra_index += body_len; | |
| 3040 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | |
| 3041 | break :special_prong; | |
| 3042 | } | |
| 3039 | 3043 | extra_index += body_len - 2; |
| 3040 | 3044 | const store_inst = scalar_cases_payload.items[extra_index]; |
| 3041 | if (zir_tags[store_inst] == .store_to_block_ptr) { | |
| 3042 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | |
| 3043 | scalar_cases_payload.items[body_len_index] -= 1; | |
| 3045 | if (zir_tags[store_inst] != .store_to_block_ptr) { | |
| 3046 | extra_index += 2; | |
| 3044 | 3047 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| 3048 | break :special_prong; | |
| 3049 | } | |
| 3050 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | |
| 3051 | if (block_scope.rl_ty_inst != .none) { | |
| 3045 | 3052 | extra_index += 1; |
| 3046 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | |
| 3053 | const break_inst = scalar_cases_payload.items[extra_index]; | |
| 3047 | 3054 | extra_index += 1; |
| 3055 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | |
| 3056 | zir_tags[store_inst] = .as; | |
| 3057 | zir_datas[store_inst].bin = .{ | |
| 3058 | .lhs = block_scope.rl_ty_inst, | |
| 3059 | .rhs = zir_datas[break_inst].@"break".operand, | |
| 3060 | }; | |
| 3061 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | |
| 3048 | 3062 | } else { |
| 3049 | extra_index += 2; | |
| 3063 | scalar_cases_payload.items[body_len_index] -= 1; | |
| 3050 | 3064 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| 3065 | extra_index += 1; | |
| 3066 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | |
| 3067 | extra_index += 1; | |
| 3051 | 3068 | } |
| 3052 | 3069 | } else { |
| 3053 | 3070 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| ... | ... | @@ -3066,16 +3083,29 @@ fn switchExpr( |
| 3066 | 3083 | } |
| 3067 | 3084 | extra_index += body_len - 2; |
| 3068 | 3085 | const store_inst = scalar_cases_payload.items[extra_index]; |
| 3069 | if (zir_tags[store_inst] == .store_to_block_ptr) { | |
| 3086 | if (zir_tags[store_inst] != .store_to_block_ptr) { | |
| 3087 | extra_index += 2; | |
| 3088 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | |
| 3089 | continue; | |
| 3090 | } | |
| 3091 | if (block_scope.rl_ty_inst != .none) { | |
| 3092 | extra_index += 1; | |
| 3093 | const break_inst = scalar_cases_payload.items[extra_index]; | |
| 3094 | extra_index += 1; | |
| 3095 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | |
| 3096 | zir_tags[store_inst] = .as; | |
| 3097 | zir_datas[store_inst].bin = .{ | |
| 3098 | .lhs = block_scope.rl_ty_inst, | |
| 3099 | .rhs = zir_datas[break_inst].@"break".operand, | |
| 3100 | }; | |
| 3101 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | |
| 3102 | } else { | |
| 3070 | 3103 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 3071 | 3104 | scalar_cases_payload.items[body_len_index] -= 1; |
| 3072 | 3105 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); |
| 3073 | 3106 | extra_index += 1; |
| 3074 | 3107 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); |
| 3075 | 3108 | extra_index += 1; |
| 3076 | } else { | |
| 3077 | extra_index += 2; | |
| 3078 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | |
| 3079 | 3109 | } |
| 3080 | 3110 | } |
| 3081 | 3111 | extra_index = 0; |
| ... | ... | @@ -3098,16 +3128,29 @@ fn switchExpr( |
| 3098 | 3128 | } |
| 3099 | 3129 | extra_index += body_len - 2; |
| 3100 | 3130 | const store_inst = multi_cases_payload.items[extra_index]; |
| 3101 | if (zir_tags[store_inst] == .store_to_block_ptr) { | |
| 3131 | if (zir_tags[store_inst] != .store_to_block_ptr) { | |
| 3132 | extra_index += 2; | |
| 3133 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | |
| 3134 | continue; | |
| 3135 | } | |
| 3136 | if (block_scope.rl_ty_inst != .none) { | |
| 3137 | extra_index += 1; | |
| 3138 | const break_inst = multi_cases_payload.items[extra_index]; | |
| 3139 | extra_index += 1; | |
| 3140 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | |
| 3141 | zir_tags[store_inst] = .as; | |
| 3142 | zir_datas[store_inst].bin = .{ | |
| 3143 | .lhs = block_scope.rl_ty_inst, | |
| 3144 | .rhs = zir_datas[break_inst].@"break".operand, | |
| 3145 | }; | |
| 3146 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | |
| 3147 | } else { | |
| 3102 | 3148 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 3103 | 3149 | multi_cases_payload.items[body_len_index] -= 1; |
| 3104 | 3150 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); |
| 3105 | 3151 | extra_index += 1; |
| 3106 | 3152 | astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); |
| 3107 | 3153 | extra_index += 1; |
| 3108 | } else { | |
| 3109 | extra_index += 2; | |
| 3110 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | |
| 3111 | 3154 | } |
| 3112 | 3155 | } |
| 3113 | 3156 |
src/Module.zig+8-1| ... | ... | @@ -942,6 +942,8 @@ pub const Scope = struct { |
| 942 | 942 | break_result_loc: AstGen.ResultLoc = undefined, |
| 943 | 943 | /// When a block has a pointer result location, here it is. |
| 944 | 944 | rl_ptr: zir.Inst.Ref = .none, |
| 945 | /// When a block has a type result location, here it is. | |
| 946 | rl_ty_inst: zir.Inst.Ref = .none, | |
| 945 | 947 | /// Keeps track of how many branches of a block did not actually |
| 946 | 948 | /// consume the result location. astgen uses this to figure out |
| 947 | 949 | /// whether to rely on break instructions or writing to the result |
| ... | ... | @@ -1001,7 +1003,11 @@ pub const Scope = struct { |
| 1001 | 1003 | // we emit ZIR for the block break instructions to have the result values, |
| 1002 | 1004 | // and then rvalue() on that to pass the value to the result location. |
| 1003 | 1005 | switch (parent_rl) { |
| 1004 | .discard, .none, .ty, .ptr, .ref => { | |
| 1006 | .ty => |ty_inst| { | |
| 1007 | gz.rl_ty_inst = ty_inst; | |
| 1008 | gz.break_result_loc = parent_rl; | |
| 1009 | }, | |
| 1010 | .discard, .none, .ptr, .ref => { | |
| 1005 | 1011 | gz.break_result_loc = parent_rl; |
| 1006 | 1012 | }, |
| 1007 | 1013 | |
| ... | ... | @@ -1016,6 +1022,7 @@ pub const Scope = struct { |
| 1016 | 1022 | }, |
| 1017 | 1023 | |
| 1018 | 1024 | .block_ptr => |parent_block_scope| { |
| 1025 | gz.rl_ty_inst = parent_block_scope.rl_ty_inst; | |
| 1019 | 1026 | gz.rl_ptr = parent_block_scope.rl_ptr; |
| 1020 | 1027 | gz.break_result_loc = .{ .block_ptr = gz }; |
| 1021 | 1028 | }, |
src/Sema.zig+88-82| ... | ... | @@ -4104,102 +4104,108 @@ fn coerce( |
| 4104 | 4104 | } |
| 4105 | 4105 | assert(inst.ty.zigTypeTag() != .Undefined); |
| 4106 | 4106 | |
| 4107 | // null to ?T | |
| 4108 | if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) { | |
| 4109 | return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); | |
| 4110 | } | |
| 4111 | ||
| 4112 | // T to ?T | |
| 4113 | if (dest_type.zigTypeTag() == .Optional) { | |
| 4114 | var buf: Type.Payload.ElemType = undefined; | |
| 4115 | const child_type = dest_type.optionalChild(&buf); | |
| 4116 | if (child_type.eql(inst.ty)) { | |
| 4117 | return sema.wrapOptional(block, dest_type, inst); | |
| 4118 | } else if (try sema.coerceNum(block, child_type, inst)) |some| { | |
| 4119 | return sema.wrapOptional(block, dest_type, some); | |
| 4120 | } | |
| 4121 | } | |
| 4122 | ||
| 4123 | 4107 | // T to E!T or E to E!T |
| 4124 | 4108 | if (dest_type.tag() == .error_union) { |
| 4125 | 4109 | return try sema.wrapErrorUnion(block, dest_type, inst); |
| 4126 | 4110 | } |
| 4127 | 4111 | |
| 4128 | // Coercions where the source is a single pointer to an array. | |
| 4129 | src_array_ptr: { | |
| 4130 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; | |
| 4131 | const array_type = inst.ty.elemType(); | |
| 4132 | if (array_type.zigTypeTag() != .Array) break :src_array_ptr; | |
| 4133 | const array_elem_type = array_type.elemType(); | |
| 4134 | if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; | |
| 4135 | if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; | |
| 4136 | ||
| 4137 | const dst_elem_type = dest_type.elemType(); | |
| 4138 | switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { | |
| 4139 | .ok => {}, | |
| 4140 | .no_match => break :src_array_ptr, | |
| 4141 | } | |
| 4142 | ||
| 4143 | switch (dest_type.ptrSize()) { | |
| 4144 | .Slice => { | |
| 4145 | // *[N]T to []T | |
| 4146 | return sema.coerceArrayPtrToSlice(block, dest_type, inst); | |
| 4147 | }, | |
| 4148 | .C => { | |
| 4149 | // *[N]T to [*c]T | |
| 4150 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4151 | }, | |
| 4152 | .Many => { | |
| 4153 | // *[N]T to [*]T | |
| 4154 | // *[N:s]T to [*:s]T | |
| 4155 | const src_sentinel = array_type.sentinel(); | |
| 4156 | const dst_sentinel = dest_type.sentinel(); | |
| 4157 | if (src_sentinel == null and dst_sentinel == null) | |
| 4158 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4159 | ||
| 4160 | if (src_sentinel) |src_s| { | |
| 4161 | if (dst_sentinel) |dst_s| { | |
| 4162 | if (src_s.eql(dst_s)) { | |
| 4163 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4164 | } | |
| 4165 | } | |
| 4166 | } | |
| 4167 | }, | |
| 4168 | .One => {}, | |
| 4169 | } | |
| 4170 | } | |
| 4171 | ||
| 4172 | 4112 | // comptime known number to other number |
| 4173 | 4113 | if (try sema.coerceNum(block, dest_type, inst)) |some| |
| 4174 | 4114 | return some; |
| 4175 | 4115 | |
| 4176 | 4116 | const target = sema.mod.getTarget(); |
| 4177 | 4117 | |
| 4178 | // integer widening | |
| 4179 | if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) { | |
| 4180 | assert(inst.value() == null); // handled above | |
| 4118 | switch (dest_type.zigTypeTag()) { | |
| 4119 | .Optional => { | |
| 4120 | // null to ?T | |
| 4121 | if (inst.ty.zigTypeTag() == .Null) { | |
| 4122 | return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); | |
| 4123 | } | |
| 4181 | 4124 | |
| 4182 | const src_info = inst.ty.intInfo(target); | |
| 4183 | const dst_info = dest_type.intInfo(target); | |
| 4184 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | |
| 4185 | // small enough unsigned ints can get casted to large enough signed ints | |
| 4186 | (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) | |
| 4187 | { | |
| 4188 | try sema.requireRuntimeBlock(block, inst_src); | |
| 4189 | return block.addUnOp(inst_src, dest_type, .intcast, inst); | |
| 4190 | } | |
| 4191 | } | |
| 4125 | // T to ?T | |
| 4126 | var buf: Type.Payload.ElemType = undefined; | |
| 4127 | const child_type = dest_type.optionalChild(&buf); | |
| 4128 | if (child_type.eql(inst.ty)) { | |
| 4129 | return sema.wrapOptional(block, dest_type, inst); | |
| 4130 | } else if (try sema.coerceNum(block, child_type, inst)) |some| { | |
| 4131 | return sema.wrapOptional(block, dest_type, some); | |
| 4132 | } | |
| 4133 | }, | |
| 4134 | .Pointer => { | |
| 4135 | // Coercions where the source is a single pointer to an array. | |
| 4136 | src_array_ptr: { | |
| 4137 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; | |
| 4138 | const array_type = inst.ty.elemType(); | |
| 4139 | if (array_type.zigTypeTag() != .Array) break :src_array_ptr; | |
| 4140 | const array_elem_type = array_type.elemType(); | |
| 4141 | if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; | |
| 4142 | if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; | |
| 4143 | ||
| 4144 | const dst_elem_type = dest_type.elemType(); | |
| 4145 | switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { | |
| 4146 | .ok => {}, | |
| 4147 | .no_match => break :src_array_ptr, | |
| 4148 | } | |
| 4192 | 4149 | |
| 4193 | // float widening | |
| 4194 | if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) { | |
| 4195 | assert(inst.value() == null); // handled above | |
| 4150 | switch (dest_type.ptrSize()) { | |
| 4151 | .Slice => { | |
| 4152 | // *[N]T to []T | |
| 4153 | return sema.coerceArrayPtrToSlice(block, dest_type, inst); | |
| 4154 | }, | |
| 4155 | .C => { | |
| 4156 | // *[N]T to [*c]T | |
| 4157 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4158 | }, | |
| 4159 | .Many => { | |
| 4160 | // *[N]T to [*]T | |
| 4161 | // *[N:s]T to [*:s]T | |
| 4162 | const src_sentinel = array_type.sentinel(); | |
| 4163 | const dst_sentinel = dest_type.sentinel(); | |
| 4164 | if (src_sentinel == null and dst_sentinel == null) | |
| 4165 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4196 | 4166 | |
| 4197 | const src_bits = inst.ty.floatBits(target); | |
| 4198 | const dst_bits = dest_type.floatBits(target); | |
| 4199 | if (dst_bits >= src_bits) { | |
| 4200 | try sema.requireRuntimeBlock(block, inst_src); | |
| 4201 | return block.addUnOp(inst_src, dest_type, .floatcast, inst); | |
| 4202 | } | |
| 4167 | if (src_sentinel) |src_s| { | |
| 4168 | if (dst_sentinel) |dst_s| { | |
| 4169 | if (src_s.eql(dst_s)) { | |
| 4170 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | |
| 4171 | } | |
| 4172 | } | |
| 4173 | } | |
| 4174 | }, | |
| 4175 | .One => {}, | |
| 4176 | } | |
| 4177 | } | |
| 4178 | }, | |
| 4179 | .Int => { | |
| 4180 | // integer widening | |
| 4181 | if (inst.ty.zigTypeTag() == .Int) { | |
| 4182 | assert(inst.value() == null); // handled above | |
| 4183 | ||
| 4184 | const dst_info = dest_type.intInfo(target); | |
| 4185 | const src_info = inst.ty.intInfo(target); | |
| 4186 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | |
| 4187 | // small enough unsigned ints can get casted to large enough signed ints | |
| 4188 | (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) | |
| 4189 | { | |
| 4190 | try sema.requireRuntimeBlock(block, inst_src); | |
| 4191 | return block.addUnOp(inst_src, dest_type, .intcast, inst); | |
| 4192 | } | |
| 4193 | } | |
| 4194 | }, | |
| 4195 | .Float => { | |
| 4196 | // float widening | |
| 4197 | if (inst.ty.zigTypeTag() == .Float) { | |
| 4198 | assert(inst.value() == null); // handled above | |
| 4199 | ||
| 4200 | const src_bits = inst.ty.floatBits(target); | |
| 4201 | const dst_bits = dest_type.floatBits(target); | |
| 4202 | if (dst_bits >= src_bits) { | |
| 4203 | try sema.requireRuntimeBlock(block, inst_src); | |
| 4204 | return block.addUnOp(inst_src, dest_type, .floatcast, inst); | |
| 4205 | } | |
| 4206 | } | |
| 4207 | }, | |
| 4208 | else => {}, | |
| 4203 | 4209 | } |
| 4204 | 4210 | |
| 4205 | 4211 | return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); |
test/stage2/cbe.zig+66| ... | ... | @@ -279,6 +279,72 @@ pub fn addCases(ctx: *TestContext) !void { |
| 279 | 279 | \\ return a - 4; |
| 280 | 280 | \\} |
| 281 | 281 | , ""); |
| 282 | ||
| 283 | // Switch expression missing else case. | |
| 284 | case.addError( | |
| 285 | \\export fn main() c_int { | |
| 286 | \\ var cond: c_int = 0; | |
| 287 | \\ const a: c_int = switch (cond) { | |
| 288 | \\ 1 => 1, | |
| 289 | \\ 2 => 2, | |
| 290 | \\ 3 => 3, | |
| 291 | \\ 4 => 4, | |
| 292 | \\ }; | |
| 293 | \\ return a - 4; | |
| 294 | \\} | |
| 295 | , &.{":3:22: error: switch must handle all possibilities"}); | |
| 296 | ||
| 297 | // Switch expression, has an unreachable prong. | |
| 298 | case.addCompareOutput( | |
| 299 | \\export fn main() c_int { | |
| 300 | \\ var cond: c_int = 0; | |
| 301 | \\ const a: c_int = switch (cond) { | |
| 302 | \\ 1 => 1, | |
| 303 | \\ 2 => 2, | |
| 304 | \\ 99...300, 12 => 3, | |
| 305 | \\ 0 => 4, | |
| 306 | \\ 13 => unreachable, | |
| 307 | \\ else => 5, | |
| 308 | \\ }; | |
| 309 | \\ return a - 4; | |
| 310 | \\} | |
| 311 | , ""); | |
| 312 | ||
| 313 | // Switch expression, has an unreachable prong and prongs write | |
| 314 | // to result locations. | |
| 315 | case.addCompareOutput( | |
| 316 | \\export fn main() c_int { | |
| 317 | \\ var cond: c_int = 0; | |
| 318 | \\ var a: c_int = switch (cond) { | |
| 319 | \\ 1 => 1, | |
| 320 | \\ 2 => 2, | |
| 321 | \\ 99...300, 12 => 3, | |
| 322 | \\ 0 => 4, | |
| 323 | \\ 13 => unreachable, | |
| 324 | \\ else => 5, | |
| 325 | \\ }; | |
| 326 | \\ return a - 4; | |
| 327 | \\} | |
| 328 | , ""); | |
| 329 | ||
| 330 | // Switch expression has duplicate case value. | |
| 331 | case.addError( | |
| 332 | \\export fn main() c_int { | |
| 333 | \\ var cond: c_int = 0; | |
| 334 | \\ const a: c_int = switch (cond) { | |
| 335 | \\ 1 => 1, | |
| 336 | \\ 2 => 2, | |
| 337 | \\ 96, 11...13, 97 => 3, | |
| 338 | \\ 0 => 4, | |
| 339 | \\ 90, 12 => 100, | |
| 340 | \\ else => 5, | |
| 341 | \\ }; | |
| 342 | \\ return a - 4; | |
| 343 | \\} | |
| 344 | , &.{ | |
| 345 | ":8:13: error: duplicate switch value", | |
| 346 | ":6:15: note: previous value here", | |
| 347 | }); | |
| 282 | 348 | } |
| 283 | 349 | //{ |
| 284 | 350 | // var case = ctx.exeFromCompiledC("optionals", .{}); |