diff --git a/src/parser/cxx/ast_interpreter.cc b/src/parser/cxx/ast_interpreter.cc index 9f8e2be3..2f0bb3b3 100644 --- a/src/parser/cxx/ast_interpreter.cc +++ b/src/parser/cxx/ast_interpreter.cc @@ -122,6 +122,18 @@ struct ASTInterpreter::NewPlacementResult {}; struct ASTInterpreter::NestedNamespaceSpecifierResult {}; +struct ASTInterpreter::ToBool { + ASTInterpreter& interp; + + auto operator()(const StringLiteral*) const -> std::optional { + return true; + } + + auto operator()(const auto& value) const -> std::optional { + return bool(value); + } +}; + struct ASTInterpreter::UnitVisitor { ASTInterpreter& accept; @@ -2193,10 +2205,17 @@ auto ASTInterpreter::ExpressionVisitor::operator()(BinaryExpressionAST* ast) auto ASTInterpreter::ExpressionVisitor::operator()( ConditionalExpressionAST* ast) -> ExpressionResult { auto conditionResult = accept(ast->condition); - auto iftrueExpressionResult = accept(ast->iftrueExpression); - auto iffalseExpressionResult = accept(ast->iffalseExpression); - return ExpressionResult{std::nullopt}; + if (!conditionResult.has_value()) return std::nullopt; + + if (accept.toBool(conditionResult.value())) { + auto result = accept(ast->iftrueExpression); + return result; + } + + auto result = accept(ast->iffalseExpression); + + return result; } auto ASTInterpreter::ExpressionVisitor::operator()(YieldExpressionAST* ast) @@ -3176,4 +3195,8 @@ auto ASTInterpreter::evaluate(ExpressionAST* ast) -> std::optional { return result; } +auto ASTInterpreter::toBool(const ConstValue& value) -> std::optional { + return std::visit(ToBool{*this}, value); +} + } // namespace cxx diff --git a/src/parser/cxx/ast_interpreter.h b/src/parser/cxx/ast_interpreter.h index a28a807f..73b83492 100644 --- a/src/parser/cxx/ast_interpreter.h +++ b/src/parser/cxx/ast_interpreter.h @@ -43,6 +43,8 @@ class ASTInterpreter { [[nodiscard]] auto evaluate(ExpressionAST* ast) -> std::optional; + [[nodiscard]] auto toBool(const ConstValue& value) -> std::optional; + private: using ExpressionResult = std::optional; @@ -116,6 +118,9 @@ class ASTInterpreter { struct AttributeSpecifierVisitor; struct AttributeTokenVisitor; + // ops + struct ToBool; + // run on the base nodes [[nodiscard]] auto operator()(UnitAST* ast) -> UnitResult; [[nodiscard]] auto operator()(DeclarationAST* ast) -> DeclarationResult; diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 152e53df..e78ccf0f 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -1624,8 +1624,6 @@ auto TypeChecker::Visitor::usual_arithmetic_conversion(ExpressionAST*& expr, (void)lvalue_to_rvalue_conversion(other); adjust_cv(other); - if (control()->is_same(expr->type, other->type)) return expr->type; - ExpressionAST* savedExpr = expr; ExpressionAST* savedOther = other; @@ -1991,8 +1989,15 @@ void TypeChecker::Visitor::check_subtraction(BinaryExpressionAST* ast) { } if (control()->is_pointer(ast->rightExpression->type)) { - if (control()->is_same(ast->leftExpression->type, - ast->rightExpression->type)) { + auto leftElementType = + control()->get_element_type(ast->leftExpression->type); + (void)strip_cv(leftElementType); + + auto rightElementType = + control()->get_element_type(ast->rightExpression->type); + (void)strip_cv(rightElementType); + + if (control()->is_same(leftElementType, rightElementType)) { ast->type = control()->getLongIntType(); // TODO: ptrdiff_t } else { error(ast->opLoc, diff --git a/tests/unit_tests/sema/subtraction_01.cc b/tests/unit_tests/sema/subtraction_01.cc new file mode 100644 index 00000000..80706061 --- /dev/null +++ b/tests/unit_tests/sema/subtraction_01.cc @@ -0,0 +1,33 @@ +// RUN: %cxx -verify -fcheck %s + +auto main() -> int { + char* p; + const char* cp; + void* vp; + int i = 0; + short s = 0; + + static_assert(__is_same(int, decltype('a' - '0'))); + static_assert(__is_same(int, decltype('a' - 0))); + static_assert(__is_same(int, decltype('a' - s))); + static_assert(__is_same(long, decltype('a' - 1l))); + static_assert(__is_same(unsigned, decltype('a' - 1u))); + + static_assert(__is_same(decltype(p), decltype(p - 0))); + static_assert(__is_same(decltype(p), decltype(p - i))); + + static_assert(__is_same(long, decltype(p - p))); + static_assert(__is_same(long, decltype(p - cp))); + + // clang-format off + + // expected-error@1 {{'char*' and 'void*' are not pointers to compatible types}} + p - vp; + + // expected-error@1 {{invalid operands to binary expression 'int' and 'char*'}} + 0 - p; + + // clang-format on + + return 0; +} \ No newline at end of file