From 018fde13ec361b5baf1a4d8fdb7ebe4ba477e76f Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Sat, 19 Jul 2025 17:04:08 +0200 Subject: [PATCH] Fix increments and assignments to enums Fixes #599 Signed-off-by: Roberto Raggi --- src/parser/cxx/type_checker.cc | 65 +++++++++++++++++++++---------- tests/unit_tests/sema/incr_c_01.c | 22 +++++++++++ 2 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 tests/unit_tests/sema/incr_c_01.c diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 3ba81d27..8ee72f3a 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -50,6 +50,14 @@ struct TypeChecker::Visitor { return check.unit_->control(); } + [[nodiscard]] auto is_parsing_c() const { + return check.unit_->language() == LanguageKind::kC; + } + + [[nodiscard]] auto is_parsing_cxx() const { + return check.unit_->language() == LanguageKind::kCXX; + } + void error(SourceLocation loc, std::string message) { if (!check.reportErrors_) return; check.unit_->error(loc, std::move(message)); @@ -498,7 +506,16 @@ void TypeChecker::Visitor::operator()(PostIncrExpressionAST* ast) { } auto incr_arithmetic = [&]() { - if (!control()->is_arithmetic(ast->baseExpression->type)) return false; + if (control()->is_const(ast->baseExpression->type)) return false; + + if (is_parsing_cxx() && + !control()->is_arithmetic(ast->baseExpression->type)) + return false; + + if (is_parsing_c() && + !control()->is_arithmetic_or_unscoped_enum(ast->baseExpression->type)) + return false; + auto ty = control()->remove_cv(ast->baseExpression->type); if (type_cast(ty)) return false; @@ -798,20 +815,23 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { break; } - auto ty = ast->expression->type; + if (!control()->is_const(ast->expression->type)) { + const auto ty = ast->expression->type; - if (control()->is_arithmetic(ty) && !control()->is_const(ty)) { - ast->type = ty; - ast->valueCategory = ValueCategory::kLValue; - break; - } - - if (auto ptrTy = type_cast(ty)) { - if (!control()->is_void(ptrTy->elementType())) { - ast->type = ptrTy; + if (is_parsing_cxx() ? control()->is_arithmetic(ty) + : control()->is_arithmetic_or_unscoped_enum(ty)) { + ast->type = ty; ast->valueCategory = ValueCategory::kLValue; break; } + + if (auto ptrTy = type_cast(ty)) { + if (!control()->is_void(ptrTy->elementType())) { + ast->type = ptrTy; + ast->valueCategory = ValueCategory::kLValue; + break; + } + } } error(ast->opLoc, std::format("cannot increment a value of type '{}'", @@ -826,20 +846,23 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { break; } - auto ty = ast->expression->type; - - if (control()->is_arithmetic(ty) && !control()->is_const(ty)) { - ast->type = ty; - ast->valueCategory = ValueCategory::kLValue; - break; - } + if (!control()->is_const(ast->expression->type)) { + auto ty = ast->expression->type; - if (auto ptrTy = type_cast(ty)) { - if (ptrTy && !control()->is_void(ptrTy->elementType())) { - ast->type = ptrTy; + if (is_parsing_cxx() ? control()->is_arithmetic(ty) + : control()->is_arithmetic_or_unscoped_enum(ty)) { + ast->type = ty; ast->valueCategory = ValueCategory::kLValue; break; } + + if (auto ptrTy = type_cast(ty)) { + if (ptrTy && !control()->is_void(ptrTy->elementType())) { + ast->type = ptrTy; + ast->valueCategory = ValueCategory::kLValue; + break; + } + } } error(ast->opLoc, std::format("cannot decrement a value of type '{}'", diff --git a/tests/unit_tests/sema/incr_c_01.c b/tests/unit_tests/sema/incr_c_01.c new file mode 100644 index 00000000..ba43eaed --- /dev/null +++ b/tests/unit_tests/sema/incr_c_01.c @@ -0,0 +1,22 @@ +// RUN: %cxx -verify -fcheck -xc %s + +enum E { a, b, c }; + +int main() { + enum E e = a; + ++e; + --e; + e++; + e--; + + const E ce = a; + // expected-error@1 {{cannot increment a value of type 'const E'}} + ++ce; + // expected-error@1 {{cannot decrement a value of type 'const E'}} + --ce; + // expected-error@1 {{cannot increment a value of type 'const E'}} + ce++; + // expected-error@1 {{cannot decrement a value of type 'const E'}} + ce--; + return 0; +}