diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 1e426644d0aa..4b6b69872216 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -479,6 +479,35 @@ auto Context::AddConvergenceBlockWithArgAndPush( return AddInst({node_id, SemIR::BlockArg{result_type_id, new_block_id}}); } +auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id, + SemIR::InstId cond_id, + SemIR::InstId if_true, + SemIR::InstId if_false) + -> void { + CARBON_CHECK(insts().Is(select_id)); + + // Determine the constant result based on the condition value. + SemIR::ConstantId const_id = SemIR::ConstantId::NotConstant; + auto cond_const_id = constant_values().Get(cond_id); + if (!cond_const_id.is_template()) { + // Symbolic or non-constant condition means a non-constant result. + } else if (auto literal = insts().TryGetAs( + cond_const_id.inst_id())) { + const_id = constant_values().Get(literal.value().value.ToBool() ? if_true + : if_false); + } else { + CARBON_CHECK(cond_const_id == SemIR::ConstantId::Error) + << "Unexpected constant branch condition."; + const_id = SemIR::ConstantId::Error; + } + + if (const_id.is_constant()) { + CARBON_VLOG() << "Constant: " << insts().Get(select_id) << " -> " + << const_id.inst_id() << "\n"; + constant_values().Set(select_id, const_id); + } +} + // Add the current code block to the enclosing function. auto Context::AddCurrentCodeBlockToFunction(Parse::NodeId node_id) -> void { CARBON_CHECK(!inst_block_stack().empty()) << "no current code block"; diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 62f5d4baddcd..2633075a53f4 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -177,6 +177,17 @@ class Context { Parse::NodeId node_id, std::initializer_list block_args) -> SemIR::InstId; + // Sets the constant value of a block argument created as the result of a + // branch. `select_id` should be a `BlockArg` that selects between two + // values. `cond_id` is the condition, `if_false` is the value to use if the + // condition is false, and `if_true` is the value to use if the condition is + // true. We don't track enough information in the `BlockArg` inst for + // `TryEvalInst` to do this itself. + auto SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id, + SemIR::InstId cond_id, + SemIR::InstId if_true, + SemIR::InstId if_false) -> void; + // Add the current code block to the enclosing function. // TODO: The node_id is taken for expressions, which can occur in // non-function contexts. This should be refactored to support non-function diff --git a/toolchain/check/handle_if_expr.cpp b/toolchain/check/handle_if_expr.cpp index 0c5cdbe9c4ce..1d9177bd2b6c 100644 --- a/toolchain/check/handle_if_expr.cpp +++ b/toolchain/check/handle_if_expr.cpp @@ -11,10 +11,11 @@ auto HandleIfExprIf(Context& context, Parse::IfExprIfId node_id) -> bool { // Alias node_id for if/then/else consistency. auto& if_node = node_id; - auto cond_value_id = context.node_stack().PopExpr(); + auto [cond_node, cond_value_id] = context.node_stack().PopExprWithNodeId(); // Convert the condition to `bool`, and branch on it. cond_value_id = ConvertToBoolValue(context, if_node, cond_value_id); + context.node_stack().Push(cond_node, cond_value_id); auto then_block_id = context.AddDominatedBlockAndBranchIf(if_node, cond_value_id); auto else_block_id = context.AddDominatedBlockAndBranch(if_node); @@ -51,6 +52,7 @@ auto HandleIfExprElse(Context& context, Parse::IfExprElseId node_id) -> bool { auto then_value_id = context.node_stack().Pop(); auto [if_node, _] = context.node_stack().PopWithNodeId(); + auto cond_value_id = context.node_stack().PopExpr(); // Convert the `else` value to the `then` value's type, and finish the `else` // block. @@ -62,6 +64,8 @@ auto HandleIfExprElse(Context& context, Parse::IfExprElseId node_id) -> bool { // Create a resumption block and branches to it. auto chosen_value_id = context.AddConvergenceBlockWithArgAndPush( if_node, {else_value_id, then_value_id}); + context.SetBlockArgResultBeforeConstantUse(chosen_value_id, cond_value_id, + then_value_id, else_value_id); context.AddCurrentCodeBlockToFunction(node_id); // Push the result value. diff --git a/toolchain/check/handle_operator.cpp b/toolchain/check/handle_operator.cpp index 9ee205507632..7d5248533805 100644 --- a/toolchain/check/handle_operator.cpp +++ b/toolchain/check/handle_operator.cpp @@ -343,7 +343,7 @@ auto HandlePrefixOperatorStar(Context& context, static auto HandleShortCircuitOperand(Context& context, Parse::NodeId node_id, bool is_or) -> bool { // Convert the condition to `bool`. - auto cond_value_id = context.node_stack().PopExpr(); + auto [cond_node, cond_value_id] = context.node_stack().PopExprWithNodeId(); cond_value_id = ConvertToBoolValue(context, node_id, cond_value_id); auto bool_type_id = context.insts().Get(cond_value_id).type_id(); @@ -362,6 +362,11 @@ static auto HandleShortCircuitOperand(Context& context, Parse::NodeId node_id, auto end_block_id = context.AddDominatedBlockAndBranchWithArg( node_id, short_circuit_result_id); + // Push the branch condition and result for use when handling the complete + // expression. + context.node_stack().Push(cond_node, branch_value_id); + context.node_stack().Push(cond_node, short_circuit_result_id); + // Push the resumption and the right-hand side blocks, and start emitting the // right-hand operand. context.inst_block_stack().Pop(); @@ -391,6 +396,8 @@ auto HandleShortCircuitOperandOr(Context& context, static auto HandleShortCircuitOperator(Context& context, Parse::NodeId node_id) -> bool { auto [rhs_node, rhs_id] = context.node_stack().PopExprWithNodeId(); + auto short_circuit_result_id = context.node_stack().PopExpr(); + auto branch_value_id = context.node_stack().PopExpr(); // The first operand is wrapped in a ShortCircuitOperand, which we // already handled by creating a RHS block and a resumption block, which @@ -405,9 +412,12 @@ static auto HandleShortCircuitOperator(Context& context, Parse::NodeId node_id) context.AddCurrentCodeBlockToFunction(node_id); // Collect the result from either the first or second operand. - context.AddInstAndPush( + auto result_id = context.AddInst( {node_id, SemIR::BlockArg{context.insts().Get(rhs_id).type_id(), resume_block_id}}); + context.SetBlockArgResultBeforeConstantUse(result_id, branch_value_id, rhs_id, + short_circuit_result_id); + context.node_stack().Push(node_id, result_id); return true; } diff --git a/toolchain/check/testdata/alias/fail_control_flow.carbon b/toolchain/check/testdata/alias/fail_control_flow.carbon index 9f1cbe76a1e0..2478d11a8352 100644 --- a/toolchain/check/testdata/alias/fail_control_flow.carbon +++ b/toolchain/check/testdata/alias/fail_control_flow.carbon @@ -25,7 +25,7 @@ alias a = true or false; // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: %.loc18: bool = block_arg +// CHECK:STDOUT: %.loc18: bool = block_arg [template = constants.%.1] // CHECK:STDOUT: %a: = bind_alias a, [template = ] // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/if_expr/constant_condition.carbon b/toolchain/check/testdata/if_expr/constant_condition.carbon index c8bbb4d44529..31ae362a4b32 100644 --- a/toolchain/check/testdata/if_expr/constant_condition.carbon +++ b/toolchain/check/testdata/if_expr/constant_condition.carbon @@ -15,6 +15,18 @@ fn G() -> i32 { return if false then A() else B(); } +fn Constant() -> i32 { + var v: if true then i32 else i32* = 1; + var w: if false then i32 else i32* = &v; + return *w; +} + +fn PartiallyConstant(t: type) -> i32 { + var v: if true then i32 else t = 1; + var w: if false then t else i32* = &v; + return *w; +} + // CHECK:STDOUT: --- constant_condition.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -22,6 +34,7 @@ fn G() -> i32 { // CHECK:STDOUT: %.2: i32 = int_literal 2 [template] // CHECK:STDOUT: %.3: bool = bool_literal true [template] // CHECK:STDOUT: %.4: bool = bool_literal false [template] +// CHECK:STDOUT: %.5: type = ptr_type i32 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -30,6 +43,8 @@ fn G() -> i32 { // CHECK:STDOUT: .B = %B // CHECK:STDOUT: .F = %F // CHECK:STDOUT: .G = %G +// CHECK:STDOUT: .Constant = %Constant +// CHECK:STDOUT: .PartiallyConstant = %PartiallyConstant // CHECK:STDOUT: } // CHECK:STDOUT: %A: = fn_decl @A [template] { // CHECK:STDOUT: %return.var.loc7: ref i32 = var @@ -43,6 +58,14 @@ fn G() -> i32 { // CHECK:STDOUT: %G: = fn_decl @G [template] { // CHECK:STDOUT: %return.var.loc14: ref i32 = var // CHECK:STDOUT: } +// CHECK:STDOUT: %Constant: = fn_decl @Constant [template] { +// CHECK:STDOUT: %return.var.loc18: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %PartiallyConstant: = fn_decl @PartiallyConstant [template] { +// CHECK:STDOUT: %t.loc24_22.1: type = param t +// CHECK:STDOUT: @PartiallyConstant.%t: type = bind_name t, %t.loc24_22.1 +// CHECK:STDOUT: %return.var.loc24: ref i32 = var +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A() -> i32 { @@ -105,3 +128,88 @@ fn G() -> i32 { // CHECK:STDOUT: return %.loc15_10 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: fn @Constant() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc19_13: bool = bool_literal true [template = constants.%.3] +// CHECK:STDOUT: if %.loc19_13 br !if.expr.then.loc19 else br !if.expr.else.loc19 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc19: +// CHECK:STDOUT: br !if.expr.result.loc19(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc19: +// CHECK:STDOUT: %.loc19_35: type = ptr_type i32 [template = constants.%.5] +// CHECK:STDOUT: br !if.expr.result.loc19(%.loc19_35) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc19: +// CHECK:STDOUT: %.loc19_10: type = block_arg !if.expr.result.loc19 [template = i32] +// CHECK:STDOUT: %v.var: ref i32 = var v +// CHECK:STDOUT: %v: ref i32 = bind_name v, %v.var +// CHECK:STDOUT: %.loc19_39: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: assign %v.var, %.loc19_39 +// CHECK:STDOUT: %.loc20_13: bool = bool_literal false [template = constants.%.4] +// CHECK:STDOUT: if %.loc20_13 br !if.expr.then.loc20 else br !if.expr.else.loc20 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc20: +// CHECK:STDOUT: br !if.expr.result.loc20(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc20: +// CHECK:STDOUT: %.loc20_36: type = ptr_type i32 [template = constants.%.5] +// CHECK:STDOUT: br !if.expr.result.loc20(%.loc20_36) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc20: +// CHECK:STDOUT: %.loc20_10: type = block_arg !if.expr.result.loc20 [template = constants.%.5] +// CHECK:STDOUT: %w.var: ref i32* = var w +// CHECK:STDOUT: %w: ref i32* = bind_name w, %w.var +// CHECK:STDOUT: %v.ref: ref i32 = name_ref v, %v +// CHECK:STDOUT: %.loc20_40: i32* = addr_of %v.ref +// CHECK:STDOUT: assign %w.var, %.loc20_40 +// CHECK:STDOUT: %w.ref: ref i32* = name_ref w, %w +// CHECK:STDOUT: %.loc21_11: i32* = bind_value %w.ref +// CHECK:STDOUT: %.loc21_10.1: ref i32 = deref %.loc21_11 +// CHECK:STDOUT: %.loc21_10.2: i32 = bind_value %.loc21_10.1 +// CHECK:STDOUT: return %.loc21_10.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PartiallyConstant(%t: type) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc25_13: bool = bool_literal true [template = constants.%.3] +// CHECK:STDOUT: if %.loc25_13 br !if.expr.then.loc25 else br !if.expr.else.loc25 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc25: +// CHECK:STDOUT: br !if.expr.result.loc25(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc25: +// CHECK:STDOUT: %t.ref.loc25: type = name_ref t, %t +// CHECK:STDOUT: br !if.expr.result.loc25(%t.ref.loc25) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc25: +// CHECK:STDOUT: %.loc25_10: type = block_arg !if.expr.result.loc25 [template = i32] +// CHECK:STDOUT: %v.var: ref i32 = var v +// CHECK:STDOUT: %v: ref i32 = bind_name v, %v.var +// CHECK:STDOUT: %.loc25_36: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: assign %v.var, %.loc25_36 +// CHECK:STDOUT: %.loc26_13: bool = bool_literal false [template = constants.%.4] +// CHECK:STDOUT: if %.loc26_13 br !if.expr.then.loc26 else br !if.expr.else.loc26 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc26: +// CHECK:STDOUT: %t.ref.loc26: type = name_ref t, %t +// CHECK:STDOUT: br !if.expr.result.loc26(%t.ref.loc26) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc26: +// CHECK:STDOUT: %.loc26_34: type = ptr_type i32 [template = constants.%.5] +// CHECK:STDOUT: br !if.expr.result.loc26(%.loc26_34) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc26: +// CHECK:STDOUT: %.loc26_10: type = block_arg !if.expr.result.loc26 [template = constants.%.5] +// CHECK:STDOUT: %w.var: ref i32* = var w +// CHECK:STDOUT: %w: ref i32* = bind_name w, %w.var +// CHECK:STDOUT: %v.ref: ref i32 = name_ref v, %v +// CHECK:STDOUT: %.loc26_38: i32* = addr_of %v.ref +// CHECK:STDOUT: assign %w.var, %.loc26_38 +// CHECK:STDOUT: %w.ref: ref i32* = name_ref w, %w +// CHECK:STDOUT: %.loc27_11: i32* = bind_value %w.ref +// CHECK:STDOUT: %.loc27_10.1: ref i32 = deref %.loc27_11 +// CHECK:STDOUT: %.loc27_10.2: i32 = bind_value %.loc27_10.1 +// CHECK:STDOUT: return %.loc27_10.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon index 54042af028bc..bd5c08fc7160 100644 --- a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon +++ b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon @@ -4,7 +4,6 @@ // // AUTOUPDATE -// TODO: Should work with compile-time evaluation. // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+12]]:14: ERROR: Semantics TODO: `Control flow expressions are currently only supported inside functions.`. // CHECK:STDERR: let x: i32 = if true then 1 else 0; // CHECK:STDERR: ^~~~~~~ @@ -20,16 +19,11 @@ let x: i32 = if true then 1 else 0; class C { - // TODO: Should work with compile-time evaluation. - // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+15]]:10: ERROR: Semantics TODO: `Control flow expressions are currently only supported inside functions.`. + // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+11]]:10: ERROR: Semantics TODO: `Control flow expressions are currently only supported inside functions.`. // CHECK:STDERR: var n: if true then i32 else f64; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: - // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+11]]:10: ERROR: Semantics TODO: `Control flow expressions are currently only supported inside functions.`. - // CHECK:STDERR: var n: if true then i32 else f64; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+7]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+7]]:10: ERROR: Semantics TODO: `Control flow expressions are currently only supported inside functions.`. // CHECK:STDERR: var n: if true then i32 else f64; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: @@ -46,20 +40,22 @@ class C { // CHECK:STDOUT: %.2: i32 = int_literal 1 [template] // CHECK:STDOUT: %.3: i32 = int_literal 0 [template] // CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.4: type = unbound_element_type C, i32 [template] +// CHECK:STDOUT: %.5: type = struct_type {.n: i32} [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: %.loc20: i32 = block_arg -// CHECK:STDOUT: %x: i32 = bind_name x, %.loc20 +// CHECK:STDOUT: %.loc19: i32 = block_arg [template = constants.%.2] +// CHECK:STDOUT: %x: i32 = bind_name x, %.loc19 // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C { -// CHECK:STDOUT: %.loc39: bool = bool_literal true [template = constants.%.1] -// CHECK:STDOUT: if %.loc39 br !if.expr.then else br !if.expr.else +// CHECK:STDOUT: %.loc33: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc33 br !if.expr.then else br !if.expr.else // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%C -// CHECK:STDOUT: .n = +// CHECK:STDOUT: .n = // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/if_expr/fail_partial_constant.carbon b/toolchain/check/testdata/if_expr/fail_partial_constant.carbon new file mode 100644 index 000000000000..e32a7c61e6f0 --- /dev/null +++ b/toolchain/check/testdata/if_expr/fail_partial_constant.carbon @@ -0,0 +1,128 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- fail_non_constant_condition.carbon + +package NonConstantCondition api; + +fn ConditionIsNonConstant(b: bool) { + // We choose to not accept this even if both arms evaluate to the same + // constant value, because it notionally involves evaluating a non-constant + // condition. + // CHECK:STDERR: fail_non_constant_condition.carbon:[[@LINE+4]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var v: if b then i32 else i32 = 1; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var v: if b then i32 else i32 = 1; +} + +// --- fail_non_constant_result.carbon + +package NonConstantResult api; + +fn ChosenBranchIsNonConstant(t: type) { + // CHECK:STDERR: fail_non_constant_result.carbon:[[@LINE+4]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var v: if true then t else i32 = 1; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var v: if true then t else i32 = 1; + // CHECK:STDERR: fail_non_constant_result.carbon:[[@LINE+3]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var w: if false then i32 else t = 1; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ + var w: if false then i32 else t = 1; +} + +// CHECK:STDOUT: --- fail_non_constant_condition.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .ConditionIsNonConstant = %ConditionIsNonConstant +// CHECK:STDOUT: } +// CHECK:STDOUT: %ConditionIsNonConstant: = fn_decl @ConditionIsNonConstant [template] { +// CHECK:STDOUT: %b.loc4_27.1: bool = param b +// CHECK:STDOUT: @ConditionIsNonConstant.%b: bool = bind_name b, %b.loc4_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @ConditionIsNonConstant(%b: bool) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %b.ref: bool = name_ref b, %b +// CHECK:STDOUT: if %b.ref br !if.expr.then else br !if.expr.else +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then: +// CHECK:STDOUT: br !if.expr.result(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else: +// CHECK:STDOUT: br !if.expr.result(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result: +// CHECK:STDOUT: %.loc12_10: type = block_arg !if.expr.result +// CHECK:STDOUT: %v.var: ref = var v +// CHECK:STDOUT: %v: ref = bind_name v, %v.var +// CHECK:STDOUT: %.loc12_35: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: assign %v.var, +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_non_constant_result.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: bool = bool_literal true [template] +// CHECK:STDOUT: %.2: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.3: bool = bool_literal false [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .ChosenBranchIsNonConstant = %ChosenBranchIsNonConstant +// CHECK:STDOUT: } +// CHECK:STDOUT: %ChosenBranchIsNonConstant: = fn_decl @ChosenBranchIsNonConstant [template] { +// CHECK:STDOUT: %t.loc4_30.1: type = param t +// CHECK:STDOUT: @ChosenBranchIsNonConstant.%t: type = bind_name t, %t.loc4_30.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @ChosenBranchIsNonConstant(%t: type) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc9_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc9_13 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %t.ref.loc9: type = name_ref t, %t +// CHECK:STDOUT: br !if.expr.result.loc9(%t.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: br !if.expr.result.loc9(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_10: type = block_arg !if.expr.result.loc9 +// CHECK:STDOUT: %v.var: ref = var v +// CHECK:STDOUT: %v: ref = bind_name v, %v.var +// CHECK:STDOUT: %.loc9_36: i32 = int_literal 1 [template = constants.%.2] +// CHECK:STDOUT: assign %v.var, +// CHECK:STDOUT: %.loc13_13: bool = bool_literal false [template = constants.%.3] +// CHECK:STDOUT: if %.loc13_13 br !if.expr.then.loc13 else br !if.expr.else.loc13 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc13: +// CHECK:STDOUT: br !if.expr.result.loc13(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc13: +// CHECK:STDOUT: %t.ref.loc13: type = name_ref t, %t +// CHECK:STDOUT: br !if.expr.result.loc13(%t.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc13: +// CHECK:STDOUT: %.loc13_10: type = block_arg !if.expr.result.loc13 +// CHECK:STDOUT: %w.var: ref = var w +// CHECK:STDOUT: %w: ref = bind_name w, %w.var +// CHECK:STDOUT: %.loc13_37: i32 = int_literal 1 [template = constants.%.2] +// CHECK:STDOUT: assign %w.var, +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/and.carbon b/toolchain/check/testdata/operators/builtin/and.carbon index bfc95129f2d7..499a89d5d894 100644 --- a/toolchain/check/testdata/operators/builtin/and.carbon +++ b/toolchain/check/testdata/operators/builtin/and.carbon @@ -11,11 +11,24 @@ fn And() -> bool { return F() and G(); } +fn Constant() { + var a: if true and true then bool else () = true; + var b: if true and false then bool else () = (); + var c: if false and true then bool else () = (); + var d: if false and false then bool else () = (); +} + +fn PartialConstant(x: bool) { + var a: if false and x then bool else () = (); +} + // CHECK:STDOUT: --- and.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: bool = bool_literal true [template] // CHECK:STDOUT: %.2: bool = bool_literal false [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: () = tuple_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -23,6 +36,8 @@ fn And() -> bool { // CHECK:STDOUT: .F = %F // CHECK:STDOUT: .G = %G // CHECK:STDOUT: .And = %And +// CHECK:STDOUT: .Constant = %Constant +// CHECK:STDOUT: .PartialConstant = %PartialConstant // CHECK:STDOUT: } // CHECK:STDOUT: %F: = fn_decl @F [template] { // CHECK:STDOUT: %return.var.loc7: ref bool = var @@ -33,6 +48,11 @@ fn And() -> bool { // CHECK:STDOUT: %And: = fn_decl @And [template] { // CHECK:STDOUT: %return.var.loc10: ref bool = var // CHECK:STDOUT: } +// CHECK:STDOUT: %Constant: = fn_decl @Constant [template] {} +// CHECK:STDOUT: %PartialConstant: = fn_decl @PartialConstant [template] { +// CHECK:STDOUT: %x.loc21_20.1: bool = param x +// CHECK:STDOUT: @PartialConstant.%x: bool = bind_name x, %x.loc21_20.1 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> bool { @@ -68,3 +88,151 @@ fn And() -> bool { // CHECK:STDOUT: return %.loc11_14.4 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: fn @Constant() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc15_18.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc15_13 br !and.rhs.loc15 else br !and.result.loc15(%.loc15_18.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs.loc15: +// CHECK:STDOUT: %.loc15_22: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: br !and.result.loc15(%.loc15_22) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result.loc15: +// CHECK:STDOUT: %.loc15_18.2: bool = block_arg !and.result.loc15 [template = constants.%.1] +// CHECK:STDOUT: if %.loc15_18.2 br !if.expr.then.loc15 else br !if.expr.else.loc15 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc15: +// CHECK:STDOUT: br !if.expr.result.loc15(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc15: +// CHECK:STDOUT: %.loc15_43.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_43.2: type = converted %.loc15_43.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc15(%.loc15_43.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc15: +// CHECK:STDOUT: %.loc15_10: type = block_arg !if.expr.result.loc15 [template = bool] +// CHECK:STDOUT: %a.var: ref bool = var a +// CHECK:STDOUT: %a: ref bool = bind_name a, %a.var +// CHECK:STDOUT: %.loc15_47: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %a.var, %.loc15_47 +// CHECK:STDOUT: %.loc16_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc16_18.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc16_13 br !and.rhs.loc16 else br !and.result.loc16(%.loc16_18.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs.loc16: +// CHECK:STDOUT: %.loc16_22: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: br !and.result.loc16(%.loc16_22) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result.loc16: +// CHECK:STDOUT: %.loc16_18.2: bool = block_arg !and.result.loc16 [template = constants.%.2] +// CHECK:STDOUT: if %.loc16_18.2 br !if.expr.then.loc16 else br !if.expr.else.loc16 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc16: +// CHECK:STDOUT: br !if.expr.result.loc16(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc16: +// CHECK:STDOUT: %.loc16_44.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_44.2: type = converted %.loc16_44.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc16(%.loc16_44.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc16: +// CHECK:STDOUT: %.loc16_10: type = block_arg !if.expr.result.loc16 [template = constants.%.3] +// CHECK:STDOUT: %b.var: ref () = var b +// CHECK:STDOUT: %b: ref () = bind_name b, %b.var +// CHECK:STDOUT: %.loc16_49.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_49.2: init () = tuple_init () to %b.var [template = constants.%.4] +// CHECK:STDOUT: %.loc16_49.3: init () = converted %.loc16_49.1, %.loc16_49.2 [template = constants.%.4] +// CHECK:STDOUT: assign %b.var, %.loc16_49.3 +// CHECK:STDOUT: %.loc17_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc17_19.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc17_13 br !and.rhs.loc17 else br !and.result.loc17(%.loc17_19.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs.loc17: +// CHECK:STDOUT: %.loc17_23: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: br !and.result.loc17(%.loc17_23) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result.loc17: +// CHECK:STDOUT: %.loc17_19.2: bool = block_arg !and.result.loc17 [template = constants.%.2] +// CHECK:STDOUT: if %.loc17_19.2 br !if.expr.then.loc17 else br !if.expr.else.loc17 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc17: +// CHECK:STDOUT: br !if.expr.result.loc17(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc17: +// CHECK:STDOUT: %.loc17_44.1: () = tuple_literal () +// CHECK:STDOUT: %.loc17_44.2: type = converted %.loc17_44.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc17(%.loc17_44.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc17: +// CHECK:STDOUT: %.loc17_10: type = block_arg !if.expr.result.loc17 [template = constants.%.3] +// CHECK:STDOUT: %c.var: ref () = var c +// CHECK:STDOUT: %c: ref () = bind_name c, %c.var +// CHECK:STDOUT: %.loc17_49.1: () = tuple_literal () +// CHECK:STDOUT: %.loc17_49.2: init () = tuple_init () to %c.var [template = constants.%.4] +// CHECK:STDOUT: %.loc17_49.3: init () = converted %.loc17_49.1, %.loc17_49.2 [template = constants.%.4] +// CHECK:STDOUT: assign %c.var, %.loc17_49.3 +// CHECK:STDOUT: %.loc18_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc18_19.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc18_13 br !and.rhs.loc18 else br !and.result.loc18(%.loc18_19.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs.loc18: +// CHECK:STDOUT: %.loc18_23: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: br !and.result.loc18(%.loc18_23) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result.loc18: +// CHECK:STDOUT: %.loc18_19.2: bool = block_arg !and.result.loc18 [template = constants.%.2] +// CHECK:STDOUT: if %.loc18_19.2 br !if.expr.then.loc18 else br !if.expr.else.loc18 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc18: +// CHECK:STDOUT: br !if.expr.result.loc18(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc18: +// CHECK:STDOUT: %.loc18_45.1: () = tuple_literal () +// CHECK:STDOUT: %.loc18_45.2: type = converted %.loc18_45.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc18(%.loc18_45.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc18: +// CHECK:STDOUT: %.loc18_10: type = block_arg !if.expr.result.loc18 [template = constants.%.3] +// CHECK:STDOUT: %d.var: ref () = var d +// CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc18_50.1: () = tuple_literal () +// CHECK:STDOUT: %.loc18_50.2: init () = tuple_init () to %d.var [template = constants.%.4] +// CHECK:STDOUT: %.loc18_50.3: init () = converted %.loc18_50.1, %.loc18_50.2 [template = constants.%.4] +// CHECK:STDOUT: assign %d.var, %.loc18_50.3 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PartialConstant(%x: bool) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc22_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc22_19.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc22_13 br !and.rhs else br !and.result(%.loc22_19.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs: +// CHECK:STDOUT: %x.ref: bool = name_ref x, %x +// CHECK:STDOUT: br !and.result(%x.ref) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result: +// CHECK:STDOUT: %.loc22_19.2: bool = block_arg !and.result [template = constants.%.2] +// CHECK:STDOUT: if %.loc22_19.2 br !if.expr.then else br !if.expr.else +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then: +// CHECK:STDOUT: br !if.expr.result(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else: +// CHECK:STDOUT: %.loc22_41.1: () = tuple_literal () +// CHECK:STDOUT: %.loc22_41.2: type = converted %.loc22_41.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result(%.loc22_41.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result: +// CHECK:STDOUT: %.loc22_10: type = block_arg !if.expr.result [template = constants.%.3] +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %.loc22_46.1: () = tuple_literal () +// CHECK:STDOUT: %.loc22_46.2: init () = tuple_init () to %a.var [template = constants.%.4] +// CHECK:STDOUT: %.loc22_46.3: init () = converted %.loc22_46.1, %.loc22_46.2 [template = constants.%.4] +// CHECK:STDOUT: assign %a.var, %.loc22_46.3 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon b/toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon index b256eab0f039..62bc515e677e 100644 --- a/toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon @@ -45,7 +45,7 @@ var or_: F(true or true); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: %.loc38_17: bool = block_arg +// CHECK:STDOUT: %.loc38_17: bool = block_arg [template = constants.%.1] // CHECK:STDOUT: %.loc38_11.1: init type = call (%.loc38_17) // CHECK:STDOUT: %.loc38_24: type = value_of_initializer %.loc38_11.1 // CHECK:STDOUT: %.loc38_11.2: type = converted %.loc38_11.1, %.loc38_24 diff --git a/toolchain/check/testdata/operators/builtin/fail_and_or_partial_constant.carbon b/toolchain/check/testdata/operators/builtin/fail_and_or_partial_constant.carbon new file mode 100644 index 000000000000..9b1291da4965 --- /dev/null +++ b/toolchain/check/testdata/operators/builtin/fail_and_or_partial_constant.carbon @@ -0,0 +1,185 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- fail_non_constant_result.carbon + +package FailNonConstantResult api; + +fn PartialConstant(x: bool) { + // CHECK:STDERR: fail_non_constant_result.carbon:[[@LINE+4]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var a: if true and x then bool else (); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var a: if true and x then bool else (); + // CHECK:STDERR: fail_non_constant_result.carbon:[[@LINE+4]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var b: if false or x then bool else (); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var b: if false or x then bool else (); +} + +// --- fail_despite_known_result.carbon + +package FailDespiteKnownResult api; + +fn KnownValueButNonConstantCondition(x: bool) { + // We choose not to give these cases constant values, even though we could, + // because they notionally involve evaluating a non-constant condition. + // CHECK:STDERR: fail_despite_known_result.carbon:[[@LINE+4]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var c: if x and false then bool else (); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var c: if x and false then bool else (); + // CHECK:STDERR: fail_despite_known_result.carbon:[[@LINE+3]]:10: ERROR: Cannot evaluate type expression. + // CHECK:STDERR: var d: if x or true then bool else (); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + var d: if x or true then bool else (); +} + +// CHECK:STDOUT: --- fail_non_constant_result.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: bool = bool_literal true [template] +// CHECK:STDOUT: %.2: bool = bool_literal false [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .PartialConstant = %PartialConstant +// CHECK:STDOUT: } +// CHECK:STDOUT: %PartialConstant: = fn_decl @PartialConstant [template] { +// CHECK:STDOUT: %x.loc4_20.1: bool = param x +// CHECK:STDOUT: @PartialConstant.%x: bool = bind_name x, %x.loc4_20.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PartialConstant(%x: bool) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc9_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc9_18.1: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: if %.loc9_13 br !and.rhs else br !and.result(%.loc9_18.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs: +// CHECK:STDOUT: %x.ref.loc9: bool = name_ref x, %x +// CHECK:STDOUT: br !and.result(%x.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result: +// CHECK:STDOUT: %.loc9_18.2: bool = block_arg !and.result +// CHECK:STDOUT: if %.loc9_18.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: br !if.expr.result.loc9(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %.loc9_40.1: () = tuple_literal () +// CHECK:STDOUT: %.loc9_40.2: type = converted %.loc9_40.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc9(%.loc9_40.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_10: type = block_arg !if.expr.result.loc9 +// CHECK:STDOUT: %a.var: ref = var a +// CHECK:STDOUT: %a: ref = bind_name a, %a.var +// CHECK:STDOUT: %.loc14_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc14_19.1: bool = not %.loc14_13 [template = constants.%.1] +// CHECK:STDOUT: %.loc14_19.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc14_19.1 br !or.rhs else br !or.result(%.loc14_19.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs: +// CHECK:STDOUT: %x.ref.loc14: bool = name_ref x, %x +// CHECK:STDOUT: br !or.result(%x.ref.loc14) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result: +// CHECK:STDOUT: %.loc14_19.3: bool = block_arg !or.result +// CHECK:STDOUT: if %.loc14_19.3 br !if.expr.then.loc14 else br !if.expr.else.loc14 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc14: +// CHECK:STDOUT: br !if.expr.result.loc14(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc14: +// CHECK:STDOUT: %.loc14_40.1: () = tuple_literal () +// CHECK:STDOUT: %.loc14_40.2: type = converted %.loc14_40.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc14(%.loc14_40.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc14: +// CHECK:STDOUT: %.loc14_10: type = block_arg !if.expr.result.loc14 +// CHECK:STDOUT: %b.var: ref = var b +// CHECK:STDOUT: %b: ref = bind_name b, %b.var +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_despite_known_result.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: bool = bool_literal false [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: bool = bool_literal true [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .KnownValueButNonConstantCondition = %KnownValueButNonConstantCondition +// CHECK:STDOUT: } +// CHECK:STDOUT: %KnownValueButNonConstantCondition: = fn_decl @KnownValueButNonConstantCondition [template] { +// CHECK:STDOUT: %x.loc4_38.1: bool = param x +// CHECK:STDOUT: @KnownValueButNonConstantCondition.%x: bool = bind_name x, %x.loc4_38.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @KnownValueButNonConstantCondition(%x: bool) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref.loc11: bool = name_ref x, %x +// CHECK:STDOUT: %.loc11_15.1: bool = bool_literal false [template = constants.%.1] +// CHECK:STDOUT: if %x.ref.loc11 br !and.rhs else br !and.result(%.loc11_15.1) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.rhs: +// CHECK:STDOUT: %.loc11_19: bool = bool_literal false [template = constants.%.1] +// CHECK:STDOUT: br !and.result(%.loc11_19) +// CHECK:STDOUT: +// CHECK:STDOUT: !and.result: +// CHECK:STDOUT: %.loc11_15.2: bool = block_arg !and.result +// CHECK:STDOUT: if %.loc11_15.2 br !if.expr.then.loc11 else br !if.expr.else.loc11 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc11: +// CHECK:STDOUT: br !if.expr.result.loc11(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc11: +// CHECK:STDOUT: %.loc11_41.1: () = tuple_literal () +// CHECK:STDOUT: %.loc11_41.2: type = converted %.loc11_41.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: br !if.expr.result.loc11(%.loc11_41.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc11: +// CHECK:STDOUT: %.loc11_10: type = block_arg !if.expr.result.loc11 +// CHECK:STDOUT: %c.var: ref = var c +// CHECK:STDOUT: %c: ref = bind_name c, %c.var +// CHECK:STDOUT: %x.ref.loc15: bool = name_ref x, %x +// CHECK:STDOUT: %.loc15_15.1: bool = not %x.ref.loc15 +// CHECK:STDOUT: %.loc15_15.2: bool = bool_literal true [template = constants.%.3] +// CHECK:STDOUT: if %.loc15_15.1 br !or.rhs else br !or.result(%.loc15_15.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs: +// CHECK:STDOUT: %.loc15_18: bool = bool_literal true [template = constants.%.3] +// CHECK:STDOUT: br !or.result(%.loc15_18) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result: +// CHECK:STDOUT: %.loc15_15.3: bool = block_arg !or.result +// CHECK:STDOUT: if %.loc15_15.3 br !if.expr.then.loc15 else br !if.expr.else.loc15 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc15: +// CHECK:STDOUT: br !if.expr.result.loc15(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc15: +// CHECK:STDOUT: %.loc15_39.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_39.2: type = converted %.loc15_39.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: br !if.expr.result.loc15(%.loc15_39.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc15: +// CHECK:STDOUT: %.loc15_10: type = block_arg !if.expr.result.loc15 +// CHECK:STDOUT: %d.var: ref = var d +// CHECK:STDOUT: %d: ref = bind_name d, %d.var +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon b/toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon index 45ea93d5c982..433338d32b4a 100644 --- a/toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon @@ -160,7 +160,7 @@ fn Main() { // CHECK:STDOUT: br !if.expr.result.loc45(%.loc45_24) // CHECK:STDOUT: // CHECK:STDOUT: !if.expr.result.loc45: -// CHECK:STDOUT: %.loc45_4: i32 = block_arg !if.expr.result.loc45 +// CHECK:STDOUT: %.loc45_4: i32 = block_arg !if.expr.result.loc45 [template = constants.%.1] // CHECK:STDOUT: %.loc45_29: i32 = int_literal 3 [template = constants.%.4] // CHECK:STDOUT: assign %.loc45_4, %.loc45_29 // CHECK:STDOUT: %a.var: ref i32 = var a diff --git a/toolchain/check/testdata/operators/builtin/or.carbon b/toolchain/check/testdata/operators/builtin/or.carbon index 4f50284dd91f..e5c0c7bcc436 100644 --- a/toolchain/check/testdata/operators/builtin/or.carbon +++ b/toolchain/check/testdata/operators/builtin/or.carbon @@ -11,10 +11,24 @@ fn Or() -> bool { return F() or G(); } +fn Constant() { + var a: if true or true then bool else () = true; + var b: if true or false then bool else () = true; + var c: if false or true then bool else () = true; + var d: if false or false then bool else () = (); +} + +fn PartialConstant(x: bool) { + var a: if true or x then bool else () = true; +} + // CHECK:STDOUT: --- or.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: bool = bool_literal true [template] +// CHECK:STDOUT: %.2: bool = bool_literal false [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: () = tuple_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -22,6 +36,8 @@ fn Or() -> bool { // CHECK:STDOUT: .F = %F // CHECK:STDOUT: .G = %G // CHECK:STDOUT: .Or = %Or +// CHECK:STDOUT: .Constant = %Constant +// CHECK:STDOUT: .PartialConstant = %PartialConstant // CHECK:STDOUT: } // CHECK:STDOUT: %F: = fn_decl @F [template] { // CHECK:STDOUT: %return.var.loc7: ref bool = var @@ -32,6 +48,11 @@ fn Or() -> bool { // CHECK:STDOUT: %Or: = fn_decl @Or [template] { // CHECK:STDOUT: %return.var.loc10: ref bool = var // CHECK:STDOUT: } +// CHECK:STDOUT: %Constant: = fn_decl @Constant [template] {} +// CHECK:STDOUT: %PartialConstant: = fn_decl @PartialConstant [template] { +// CHECK:STDOUT: %x.loc21_20.1: bool = param x +// CHECK:STDOUT: @PartialConstant.%x: bool = bind_name x, %x.loc21_20.1 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() -> bool { @@ -68,3 +89,150 @@ fn Or() -> bool { // CHECK:STDOUT: return %.loc11_14.5 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: fn @Constant() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc15_18.1: bool = not %.loc15_13 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_18.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc15_18.1 br !or.rhs.loc15 else br !or.result.loc15(%.loc15_18.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs.loc15: +// CHECK:STDOUT: %.loc15_21: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: br !or.result.loc15(%.loc15_21) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result.loc15: +// CHECK:STDOUT: %.loc15_18.3: bool = block_arg !or.result.loc15 [template = constants.%.1] +// CHECK:STDOUT: if %.loc15_18.3 br !if.expr.then.loc15 else br !if.expr.else.loc15 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc15: +// CHECK:STDOUT: br !if.expr.result.loc15(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc15: +// CHECK:STDOUT: %.loc15_42.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_42.2: type = converted %.loc15_42.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc15(%.loc15_42.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc15: +// CHECK:STDOUT: %.loc15_10: type = block_arg !if.expr.result.loc15 [template = bool] +// CHECK:STDOUT: %a.var: ref bool = var a +// CHECK:STDOUT: %a: ref bool = bind_name a, %a.var +// CHECK:STDOUT: %.loc15_46: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %a.var, %.loc15_46 +// CHECK:STDOUT: %.loc16_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc16_18.1: bool = not %.loc16_13 [template = constants.%.2] +// CHECK:STDOUT: %.loc16_18.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc16_18.1 br !or.rhs.loc16 else br !or.result.loc16(%.loc16_18.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs.loc16: +// CHECK:STDOUT: %.loc16_21: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: br !or.result.loc16(%.loc16_21) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result.loc16: +// CHECK:STDOUT: %.loc16_18.3: bool = block_arg !or.result.loc16 [template = constants.%.1] +// CHECK:STDOUT: if %.loc16_18.3 br !if.expr.then.loc16 else br !if.expr.else.loc16 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc16: +// CHECK:STDOUT: br !if.expr.result.loc16(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc16: +// CHECK:STDOUT: %.loc16_43.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_43.2: type = converted %.loc16_43.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc16(%.loc16_43.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc16: +// CHECK:STDOUT: %.loc16_10: type = block_arg !if.expr.result.loc16 [template = bool] +// CHECK:STDOUT: %b.var: ref bool = var b +// CHECK:STDOUT: %b: ref bool = bind_name b, %b.var +// CHECK:STDOUT: %.loc16_47: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %b.var, %.loc16_47 +// CHECK:STDOUT: %.loc17_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc17_19.1: bool = not %.loc17_13 [template = constants.%.1] +// CHECK:STDOUT: %.loc17_19.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc17_19.1 br !or.rhs.loc17 else br !or.result.loc17(%.loc17_19.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs.loc17: +// CHECK:STDOUT: %.loc17_22: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: br !or.result.loc17(%.loc17_22) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result.loc17: +// CHECK:STDOUT: %.loc17_19.3: bool = block_arg !or.result.loc17 [template = constants.%.1] +// CHECK:STDOUT: if %.loc17_19.3 br !if.expr.then.loc17 else br !if.expr.else.loc17 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc17: +// CHECK:STDOUT: br !if.expr.result.loc17(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc17: +// CHECK:STDOUT: %.loc17_43.1: () = tuple_literal () +// CHECK:STDOUT: %.loc17_43.2: type = converted %.loc17_43.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc17(%.loc17_43.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc17: +// CHECK:STDOUT: %.loc17_10: type = block_arg !if.expr.result.loc17 [template = bool] +// CHECK:STDOUT: %c.var: ref bool = var c +// CHECK:STDOUT: %c: ref bool = bind_name c, %c.var +// CHECK:STDOUT: %.loc17_47: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %c.var, %.loc17_47 +// CHECK:STDOUT: %.loc18_13: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc18_19.1: bool = not %.loc18_13 [template = constants.%.1] +// CHECK:STDOUT: %.loc18_19.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc18_19.1 br !or.rhs.loc18 else br !or.result.loc18(%.loc18_19.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs.loc18: +// CHECK:STDOUT: %.loc18_22: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: br !or.result.loc18(%.loc18_22) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result.loc18: +// CHECK:STDOUT: %.loc18_19.3: bool = block_arg !or.result.loc18 [template = constants.%.2] +// CHECK:STDOUT: if %.loc18_19.3 br !if.expr.then.loc18 else br !if.expr.else.loc18 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc18: +// CHECK:STDOUT: br !if.expr.result.loc18(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc18: +// CHECK:STDOUT: %.loc18_44.1: () = tuple_literal () +// CHECK:STDOUT: %.loc18_44.2: type = converted %.loc18_44.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc18(%.loc18_44.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc18: +// CHECK:STDOUT: %.loc18_10: type = block_arg !if.expr.result.loc18 [template = constants.%.3] +// CHECK:STDOUT: %d.var: ref () = var d +// CHECK:STDOUT: %d: ref () = bind_name d, %d.var +// CHECK:STDOUT: %.loc18_49.1: () = tuple_literal () +// CHECK:STDOUT: %.loc18_49.2: init () = tuple_init () to %d.var [template = constants.%.4] +// CHECK:STDOUT: %.loc18_49.3: init () = converted %.loc18_49.1, %.loc18_49.2 [template = constants.%.4] +// CHECK:STDOUT: assign %d.var, %.loc18_49.3 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PartialConstant(%x: bool) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc22_13: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc22_18.1: bool = not %.loc22_13 [template = constants.%.2] +// CHECK:STDOUT: %.loc22_18.2: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: if %.loc22_18.1 br !or.rhs else br !or.result(%.loc22_18.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.rhs: +// CHECK:STDOUT: %x.ref: bool = name_ref x, %x +// CHECK:STDOUT: br !or.result(%x.ref) +// CHECK:STDOUT: +// CHECK:STDOUT: !or.result: +// CHECK:STDOUT: %.loc22_18.3: bool = block_arg !or.result [template = constants.%.1] +// CHECK:STDOUT: if %.loc22_18.3 br !if.expr.then else br !if.expr.else +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then: +// CHECK:STDOUT: br !if.expr.result(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else: +// CHECK:STDOUT: %.loc22_39.1: () = tuple_literal () +// CHECK:STDOUT: %.loc22_39.2: type = converted %.loc22_39.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result(%.loc22_39.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result: +// CHECK:STDOUT: %.loc22_10: type = block_arg !if.expr.result [template = bool] +// CHECK:STDOUT: %a.var: ref bool = var a +// CHECK:STDOUT: %a: ref bool = bind_name a, %a.var +// CHECK:STDOUT: %.loc22_43: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %a.var, %.loc22_43 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/builtin/unary_op.carbon b/toolchain/check/testdata/operators/builtin/unary_op.carbon index f921e6ebb038..76cf800a04c5 100644 --- a/toolchain/check/testdata/operators/builtin/unary_op.carbon +++ b/toolchain/check/testdata/operators/builtin/unary_op.carbon @@ -11,16 +11,24 @@ fn Not(b: bool) -> bool { let not_true: bool = not true; let not_false: bool = not false; +fn Constant() { + var a: if not true then bool else () = (); + var b: if not false then bool else () = true; +} + // CHECK:STDOUT: --- unary_op.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: bool = bool_literal true [template] // CHECK:STDOUT: %.2: bool = bool_literal false [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: () = tuple_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Not = %Not +// CHECK:STDOUT: .Constant = %Constant // CHECK:STDOUT: } // CHECK:STDOUT: %Not: = fn_decl @Not [template] { // CHECK:STDOUT: %b.loc7_8.1: bool = param b @@ -33,6 +41,7 @@ let not_false: bool = not false; // CHECK:STDOUT: %.loc12_27: bool = bool_literal false [template = constants.%.2] // CHECK:STDOUT: %.loc12_23: bool = not %.loc12_27 [template = constants.%.1] // CHECK:STDOUT: %not_false: bool = bind_name not_false, %.loc12_23 +// CHECK:STDOUT: %Constant: = fn_decl @Constant [template] {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Not(%b: bool) -> bool { @@ -42,3 +51,46 @@ let not_false: bool = not false; // CHECK:STDOUT: return %.loc8 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: fn @Constant() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15_17: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %.loc15_13: bool = not %.loc15_17 [template = constants.%.2] +// CHECK:STDOUT: if %.loc15_13 br !if.expr.then.loc15 else br !if.expr.else.loc15 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc15: +// CHECK:STDOUT: br !if.expr.result.loc15(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc15: +// CHECK:STDOUT: %.loc15_38.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_38.2: type = converted %.loc15_38.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc15(%.loc15_38.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc15: +// CHECK:STDOUT: %.loc15_10: type = block_arg !if.expr.result.loc15 [template = constants.%.3] +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %.loc15_43.1: () = tuple_literal () +// CHECK:STDOUT: %.loc15_43.2: init () = tuple_init () to %a.var [template = constants.%.4] +// CHECK:STDOUT: %.loc15_43.3: init () = converted %.loc15_43.1, %.loc15_43.2 [template = constants.%.4] +// CHECK:STDOUT: assign %a.var, %.loc15_43.3 +// CHECK:STDOUT: %.loc16_17: bool = bool_literal false [template = constants.%.2] +// CHECK:STDOUT: %.loc16_13: bool = not %.loc16_17 [template = constants.%.1] +// CHECK:STDOUT: if %.loc16_13 br !if.expr.then.loc16 else br !if.expr.else.loc16 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc16: +// CHECK:STDOUT: br !if.expr.result.loc16(bool) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc16: +// CHECK:STDOUT: %.loc16_39.1: () = tuple_literal () +// CHECK:STDOUT: %.loc16_39.2: type = converted %.loc16_39.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: br !if.expr.result.loc16(%.loc16_39.2) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc16: +// CHECK:STDOUT: %.loc16_10: type = block_arg !if.expr.result.loc16 [template = bool] +// CHECK:STDOUT: %b.var: ref bool = var b +// CHECK:STDOUT: %b: ref bool = bind_name b, %b.var +// CHECK:STDOUT: %.loc16_43: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: assign %b.var, %.loc16_43 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/pointer/fail_address_of_value.carbon b/toolchain/check/testdata/pointer/fail_address_of_value.carbon index 9c3c31293584..072e5e77e167 100644 --- a/toolchain/check/testdata/pointer/fail_address_of_value.carbon +++ b/toolchain/check/testdata/pointer/fail_address_of_value.carbon @@ -184,7 +184,7 @@ fn AddressOfParam(param: i32) { // CHECK:STDOUT: br !and.result(%.loc49_14) // CHECK:STDOUT: // CHECK:STDOUT: !and.result: -// CHECK:STDOUT: %.loc49_10.2: bool = block_arg !and.result +// CHECK:STDOUT: %.loc49_10.2: bool = block_arg !and.result [template = constants.%.16] // CHECK:STDOUT: %.loc49_3: bool* = addr_of [template = ] // CHECK:STDOUT: %H.ref: = name_ref H, file.%H [template = file.%H] // CHECK:STDOUT: %.loc54_5.1: init {.a: i32} = call %H.ref()