diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 54f2d986..4307b147 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -2494,14 +2494,52 @@ auto Parser::parse_member_expression(ExpressionAST*& yyast) -> bool { /*inRequiresClause*/ false)) parse_error("expected an unqualified id"); - (void)check_psuedo_destructor_access(ast); + check_member_expression(ast); yyast = ast; return true; } -auto Parser::check_psuedo_destructor_access(MemberExpressionAST* ast) -> bool { +void Parser::check_member_expression(MemberExpressionAST* ast) { + if (check_pseudo_destructor_access(ast)) return; + if (check_member_access(ast)) return; +} + +auto Parser::check_member_access(MemberExpressionAST* ast) -> bool { + const Type* objectType = ast->baseExpression->type; + auto cv = strip_cv(objectType); + + if (ast->accessOp == TokenKind::T_MINUS_GREATER) { + auto pointerType = type_cast(objectType); + if (!pointerType) return false; + + objectType = pointerType->elementType(); + cv = strip_cv(objectType); + } + + auto classType = type_cast(objectType); + if (!classType) return false; + + auto memberName = convertName(ast->unqualifiedId); + + auto classSymbol = classType->symbol(); + + auto symbol = + Lookup{scope_}.qualifiedLookup(classSymbol->scope(), memberName); + + ast->symbol = symbol; + + if (symbol) { + ast->type = symbol->type(); + } + + // TODO: value category + + return true; +} + +auto Parser::check_pseudo_destructor_access(MemberExpressionAST* ast) -> bool { auto objectType = ast->baseExpression->type; auto cv = strip_cv(objectType); @@ -2538,6 +2576,7 @@ auto Parser::check_psuedo_destructor_access(MemberExpressionAST* ast) -> bool { } ast->symbol = symbol; + ast->type = control_->getFunctionType(control_->getVoidType(), {}); return true; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index cedd8584..2efbf98f 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -240,7 +240,11 @@ class Parser final { -> bool; [[nodiscard]] auto parse_member_expression(ExpressionAST*& yyast) -> bool; - [[nodiscard]] auto check_psuedo_destructor_access(MemberExpressionAST* ast) + + void check_member_expression(MemberExpressionAST* ast); + + [[nodiscard]] auto check_member_access(MemberExpressionAST* ast) -> bool; + [[nodiscard]] auto check_pseudo_destructor_access(MemberExpressionAST* ast) -> bool; [[nodiscard]] auto parse_subscript_expression(ExpressionAST*& yyast, diff --git a/tests/unit_tests/sema/member_access_02.cc b/tests/unit_tests/sema/member_access_02.cc new file mode 100644 index 00000000..f731e394 --- /dev/null +++ b/tests/unit_tests/sema/member_access_02.cc @@ -0,0 +1,31 @@ +// RUN: %cxx -verify -fcheck -freport-missing-types %s + +struct X { + enum E { kValue = 0 }; + + static int s_value; +}; + +auto main() -> int { + X x; + static_assert(__is_reference(decltype(x.kValue)) == false); + static_assert(__is_same(decltype(x.kValue), X::E)); + + X& xr = x; + static_assert(__is_reference(decltype(xr.kValue)) == false); + static_assert(__is_same(decltype(xr.kValue), X::E)); + + const X& cxr = x; + static_assert(__is_reference(decltype(cxr.kValue)) == false); + static_assert(__is_same(decltype(cxr.kValue), X::E)); + + X* px = &x; + + static_assert(__is_reference(decltype(px->kValue)) == false); + static_assert(__is_same(decltype(px->kValue), X::E)); + + static_assert(__is_reference(decltype(px->s_value)) == false); + static_assert(__is_same(decltype(px->s_value), int)); + + return 0; +}