diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 4e1575b7..8ef96ead 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -123,7 +123,7 @@ void Binder::bind(EnumSpecifierAST* ast, const DeclSpecs& underlyingTypeSpecs) { auto enumName = get_name(control(), ast->unqualifiedId); - if (ast->classLoc) { + if (ast->classLoc && is_parsing_cxx()) { auto enumSymbol = control()->newScopedEnumSymbol(scope(), location); ast->symbol = enumSymbol; @@ -133,6 +133,10 @@ void Binder::bind(EnumSpecifierAST* ast, const DeclSpecs& underlyingTypeSpecs) { setScope(enumSymbol); } else { + if (is_parsing_c() && ast->classLoc) { + error(ast->classLoc, "scoped enums are not allowed in C"); + } + auto enumSymbol = control()->newEnumSymbol(scope(), location); if (ast->typeSpecifierList) { @@ -360,21 +364,34 @@ void Binder::bind(EnumeratorAST* ast, const Type* type, symbol->setType(type); ast->symbol->setValue(value); scope()->addSymbol(symbol); + + if (auto enumSymbol = symbol_cast(scope()->owner())) { + auto parentScope = enumSymbol->enclosingScope(); + + auto u = + control()->newUsingDeclarationSymbol(parentScope, ast->identifierLoc); + u->setName(ast->identifier); + u->setTarget(symbol); + parentScope->addSymbol(u); + } + + return; } + // in C mode + if (auto enumSymbol = symbol_cast(scope()->owner())) { + auto parentScope = enumSymbol->enclosingScope(); + auto enumeratorSymbol = - control()->newEnumeratorSymbol(scope(), ast->identifierLoc); + control()->newEnumeratorSymbol(parentScope, ast->identifierLoc); + ast->symbol = enumeratorSymbol; + enumeratorSymbol->setName(ast->identifier); enumeratorSymbol->setType(type); enumeratorSymbol->setValue(value); - auto parentScope = enumSymbol->enclosingScope(); parentScope->addSymbol(enumeratorSymbol); - - if (!is_parsing_cxx()) { - ast->symbol = enumeratorSymbol; - } } } diff --git a/src/parser/cxx/symbol_printer.cc b/src/parser/cxx/symbol_printer.cc index 74991986..bf086c6a 100644 --- a/src/parser/cxx/symbol_printer.cc +++ b/src/parser/cxx/symbol_printer.cc @@ -33,6 +33,21 @@ namespace cxx { namespace { +struct GetEnumeratorValue { + auto operator()(bool value) const -> std::string { + return value ? "true" : "false"; + } + auto operator()(std::intmax_t value) const -> std::string { + return std::to_string(value); + } + + auto operator()(std::uintmax_t value) const -> std::string { + return std::to_string(value); + } + + auto operator()(auto x) const -> std::string { return {}; } +}; + struct DumpSymbols { std::ostream& out; int depth = 0; @@ -316,8 +331,21 @@ struct DumpSymbols { void operator()(EnumeratorSymbol* symbol) { indent(); - out << std::format("enumerator {}\n", + + auto get_value = [](auto value) { + return std::visit(GetEnumeratorValue{}, value); + }; + + const auto value = symbol->value().transform(get_value); + + out << std::format("enumerator {}", to_string(symbol->type(), symbol->name())); + + if (value.has_value() && !value->empty()) { + out << std::format(" = {}", *value); + } + + out << "\n"; } void operator()(UsingDeclarationSymbol* symbol) { diff --git a/tests/unit_tests/sema/struct_c_01.c b/tests/unit_tests/sema/struct_c_01.c index 8118599b..f5666c31 100644 --- a/tests/unit_tests/sema/struct_c_01.c +++ b/tests/unit_tests/sema/struct_c_01.c @@ -26,14 +26,14 @@ int main() { // clang-format off // CHECK:namespace // CHECK-NEXT: enum E : int -// CHECK-NEXT: enumerator E v +// CHECK-NEXT: enumerator E v = 0 // CHECK-NEXT: class A // CHECK-NEXT: field E e // CHECK-NEXT: field int x // CHECK-NEXT: function int main() // CHECK-NEXT: block // CHECK-NEXT: enum K : int -// CHECK-NEXT: enumerator K w +// CHECK-NEXT: enumerator K w = 0 // CHECK-NEXT: class B // CHECK-NEXT: field K k // CHECK-NEXT: field E e