diff --git a/src/mlir/cxx/mlir/codegen_expressions.cc b/src/mlir/cxx/mlir/codegen_expressions.cc index 98aae627..339d374b 100644 --- a/src/mlir/cxx/mlir/codegen_expressions.cc +++ b/src/mlir/cxx/mlir/codegen_expressions.cc @@ -1363,16 +1363,39 @@ auto Codegen::ExpressionVisitor::operator()(BinaryExpressionAST* ast) auto Codegen::ExpressionVisitor::operator()(ConditionalExpressionAST* ast) -> ExpressionResult { - auto op = - gen.emitTodoExpr(ast->firstSourceLocation(), to_string(ast->kind())); + auto trueBlock = gen.newBlock(); + auto falseBlock = gen.newBlock(); + auto endBlock = gen.newBlock(); -#if false - auto conditionResult = gen.expression(ast->condition); - auto iftrueExpressionResult = gen.expression(ast->iftrueExpression); - auto iffalseExpressionResult = gen.expression(ast->iffalseExpression); -#endif + auto t = gen.newTemp(ast->type, ast->questionLoc); - return {op}; + gen.condition(ast->condition, trueBlock, falseBlock); + + auto endLoc = gen.getLocation(ast->lastSourceLocation()); + + // place the true block + gen.builder_.setInsertionPointToEnd(trueBlock); + auto trueExpressionResult = gen.expression(ast->iftrueExpression); + auto trueValue = gen.builder_.create( + gen.getLocation(ast->questionLoc), trueExpressionResult.value, t); + gen.branch(endLoc, endBlock); + + // place the false block + gen.builder_.setInsertionPointToEnd(falseBlock); + auto falseExpressionResult = gen.expression(ast->iffalseExpression); + auto falseValue = gen.builder_.create( + gen.getLocation(ast->colonLoc), falseExpressionResult.value, t); + gen.branch(endLoc, endBlock); + + // place the end block + gen.builder_.setInsertionPointToEnd(endBlock); + + if (format == ExpressionFormat::kSideEffect) return {}; + + auto resultType = gen.convertType(ast->type); + auto loadOp = gen.builder_.create( + gen.getLocation(ast->colonLoc), resultType, t); + return {loadOp}; } auto Codegen::ExpressionVisitor::operator()(YieldExpressionAST* ast) diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index f3d8c573..906a4215 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -1229,9 +1229,10 @@ void TypeChecker::Visitor::operator()(ConditionalExpressionAST* ast) { control()->remove_cv(ast->iffalseExpression->type))) return false; - ast->valueCategory = ast->iftrueExpression->valueCategory; ast->type = ast->iftrueExpression->type; + ast->valueCategory = ast->iftrueExpression->valueCategory; + return true; }; @@ -1277,33 +1278,47 @@ void TypeChecker::Visitor::operator()(ConditionalExpressionAST* ast) { return true; }; - if (ast->iftrueExpression && ast->iffalseExpression) { - if (check_void_type()) return; - if (check_same_type_and_value_category()) return; - - (void)array_to_pointer_conversion(ast->iftrueExpression); - (void)function_to_pointer_conversion(ast->iftrueExpression); + if (!ast->iftrueExpression) { + error(ast->questionLoc, + "left operand to ? is null, but right operand is not null"); + return; + } - (void)array_to_pointer_conversion(ast->iffalseExpression); - (void)function_to_pointer_conversion(ast->iffalseExpression); + if (!ast->iffalseExpression) { + error(ast->colonLoc, + "right operand to ? is null, but left operand is not null"); + return; + } - if (check_arith_types()) return; - if (check_same_types()) return; - if (check_compatible_pointers()) return; + if (is_parsing_c()) { + // in C, both expressions must be prvalues + (void)ensure_prvalue(ast->iftrueExpression); + (void)ensure_prvalue(ast->iffalseExpression); } - if (!ast->type) { - auto iftrueType = - ast->iftrueExpression ? ast->iftrueExpression->type : nullptr; + if (check_void_type()) return; + if (check_same_type_and_value_category()) return; - auto iffalseType = - ast->iffalseExpression ? ast->iffalseExpression->type : nullptr; + (void)array_to_pointer_conversion(ast->iftrueExpression); + (void)function_to_pointer_conversion(ast->iftrueExpression); - error(ast->questionLoc, - std::format( - "left operand to ? is '{}', but right operand is of type '{}'", - to_string(iftrueType), to_string(iffalseType))); - } + (void)array_to_pointer_conversion(ast->iffalseExpression); + (void)function_to_pointer_conversion(ast->iffalseExpression); + + if (check_arith_types()) return; + if (check_same_types()) return; + if (check_compatible_pointers()) return; + + auto iftrueType = + ast->iftrueExpression ? ast->iftrueExpression->type : nullptr; + + auto iffalseType = + ast->iffalseExpression ? ast->iffalseExpression->type : nullptr; + + error(ast->questionLoc, + std::format( + "left operand to ? is '{}', but right operand is of type '{}'", + to_string(iftrueType), to_string(iffalseType))); } void TypeChecker::Visitor::operator()(YieldExpressionAST* ast) {}