diff --git a/src/parser/cxx/name_lookup.cc b/src/parser/cxx/name_lookup.cc index 3aff838b..bcce3226 100644 --- a/src/parser/cxx/name_lookup.cc +++ b/src/parser/cxx/name_lookup.cc @@ -144,6 +144,19 @@ auto Lookup::lookupHelper(Scope* scope, const Name* name, } if (auto classSymbol = symbol_cast(scope->owner())) { + // iterate over the annonymous nested structs and unions + for (auto member : classSymbol->scope()->symbols()) { + if (member->name()) continue; // skip named members + if (!member->isClass()) continue; // skip non-class members + auto nestedClass = symbol_cast(member); + auto symbol = lookupHelper(nestedClass->scope(), name, cache, accept); + + if (symbol) { + // found a match in an anonymous nested class + return symbol; + } + } + for (const auto& base : classSymbol->baseClasses()) { auto baseClass = symbol_cast(base->symbol()); if (!baseClass) continue; diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 0a9aec25..14a2c898 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -7749,12 +7749,6 @@ auto Parser::parse_class_specifier(ClassSpecifierAST*& yyast, DeclSpecs& specs) SourceLocation classLoc; if (!parse_class_key(classLoc)) return false; - auto globalScopeGuard = Binder::ScopeGuard{&binder_}; - - if (is_parsing_c()) { - setScope(getCurrentNonClassScope()); - } - List* attributeList = nullptr; NestedNameSpecifierAST* nestedNameSpecifier = nullptr; UnqualifiedIdAST* unqualifiedId = nullptr; @@ -7809,6 +7803,15 @@ auto Parser::parse_class_specifier(ClassSpecifierAST*& yyast, DeclSpecs& specs) if (!lookat_class_head()) return false; + auto globalScopeGuard = Binder::ScopeGuard{&binder_}; + + if (is_parsing_c()) { + if (unqualifiedId) { + // declared named structs in the enclosed non-class scope in C mode + setScope(getCurrentNonClassScope()); + } + } + auto ast = make_node(pool_); yyast = ast; diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index a2204824..3ba81d27 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -2124,6 +2124,7 @@ auto TypeChecker::Visitor::check_member_access(MemberExpressionAST* ast) } else { (void)ensure_prvalue(ast->baseExpression); objectType = ast->baseExpression->type; + cv1 = strip_cv(objectType); } auto pointerType = type_cast(objectType); diff --git a/tests/unit_tests/sema/class_02.cc b/tests/unit_tests/sema/class_02.cc new file mode 100644 index 00000000..9d450c20 --- /dev/null +++ b/tests/unit_tests/sema/class_02.cc @@ -0,0 +1,20 @@ +// RUN: %cxx -verify -fcheck %s + +struct A { + struct { + int x; + }; + union { + int y; + struct { + int z; + }; + }; +}; + +int main() { + struct A a; + (void)_Generic(a.x, int: 123); + (void)_Generic(a.y, int: 321); + (void)_Generic(a.z, int: 444); +} \ No newline at end of file