diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 7c0689ac..16510244 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -307,7 +307,29 @@ struct Parser::GetDeclaratorType { } } - void operator()(PtrToMemberOperatorAST* ast) {} + void operator()(PtrToMemberOperatorAST* ast) { + if (!type_) return; + + auto symbol = ast->nestedNameSpecifier->symbol; + if (!symbol) return; + + auto classType = type_cast(symbol->type()); + if (!classType) return; + + if (auto functionType = type_cast(type_)) { + type_ = control()->getMemberFunctionPointerType(classType, functionType); + } else { + type_ = control()->getMemberObjectPointerType(classType, type_); + } + + for (auto it = ast->cvQualifierList; it; it = it->next) { + if (ast_cast(it->value)) { + type_ = control()->getConstType(type_); + } else if (ast_cast(it->value)) { + type_ = control()->getVolatileType(type_); + } + } + } void operator()(BitfieldDeclaratorAST* ast) {} @@ -1562,6 +1584,7 @@ auto Parser::parse_type_nested_name_specifier(NestedNameSpecifierAST*& yyast, return true; } +namespace { struct IsReferencingTemplateParameter { Parser& p; int depth = 0; @@ -1592,6 +1615,7 @@ struct IsReferencingTemplateParameter { return false; } }; +} // namespace auto Parser::parse_template_nested_name_specifier( NestedNameSpecifierAST*& yyast, NestedNameSpecifierContext ctx, int depth) @@ -2930,7 +2954,54 @@ auto Parser::parse_unop_expression(ExpressionAST*& yyast, break; } - case cxx::TokenKind::T_PLUS: { + case TokenKind::T_AMP: { + if (!ast->expression->type) { + break; + } + + if (!is_glvalue(ast->expression)) { + break; + } + + // TODO xvalue to lvalue + + if (auto idExpr = ast_cast(ast->expression); + idExpr && idExpr->nestedNameSpecifier) { + auto symbol = idExpr->symbol; + if (auto field = symbol_cast(symbol); + field && !field->isStatic()) { + auto parentClass = field->enclosingSymbol(); + auto classType = type_cast(parentClass->type()); + + ast->type = + control_->getMemberObjectPointerType(classType, field->type()); + + ast->valueCategory = ValueCategory::kPrValue; + + break; + } + + if (auto function = symbol_cast(symbol); + function && !function->isStatic()) { + auto functionType = type_cast(function->type()); + auto parentClass = function->enclosingSymbol(); + auto classType = type_cast(parentClass->type()); + + ast->type = + control_->getMemberFunctionPointerType(classType, functionType); + + ast->valueCategory = ValueCategory::kPrValue; + + break; + } + } // id expression + + ast->type = control_->getPointerType(ast->expression->type); + ast->valueCategory = ValueCategory::kPrValue; + break; + } + + case TokenKind::T_PLUS: { ExpressionAST* expr = ast->expression; ensure_prvalue(expr); auto ty = control_->remove_cvref(expr->type); @@ -2946,6 +3017,41 @@ auto Parser::parse_unop_expression(ExpressionAST*& yyast, break; } + case TokenKind::T_MINUS: { + ExpressionAST* expr = ast->expression; + ensure_prvalue(expr); + auto ty = control_->remove_cvref(expr->type); + if (control_->is_arithmetic_or_unscoped_enum(ty)) { + if (control_->is_integral_or_unscoped_enum(ty)) { + (void)integral_promotion(expr); + } + ast->expression = expr; + ast->type = expr->type; + ast->valueCategory = ValueCategory::kPrValue; + } + break; + } + + case TokenKind::T_EXCLAIM: { + (void)implicit_conversion(ast->expression, control_->getBoolType()); + ast->type = control_->getBoolType(); + ast->valueCategory = ValueCategory::kPrValue; + break; + } + + case TokenKind::T_TILDE: { + ExpressionAST* expr = ast->expression; + ensure_prvalue(expr); + auto ty = control_->remove_cvref(expr->type); + if (control_->is_integral_or_unscoped_enum(ty)) { + (void)integral_promotion(expr); + ast->expression = expr; + ast->type = expr->type; + ast->valueCategory = ValueCategory::kPrValue; + } + break; + } + default: break; } // switch @@ -5948,6 +6054,13 @@ void Parser::check_type_traits() { rewind(typeTraitLoc); } +auto Parser::strip_parentheses(ExpressionAST* ast) -> ExpressionAST* { + while (auto paren = ast_cast(ast)) { + ast = paren->expression; + } + return ast; +} + auto Parser::lvalue_to_rvalue_conversion(ExpressionAST*& expr) -> bool { if (!is_glvalue(expr)) return false; diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index ff855509..c9724fbe 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -827,6 +827,8 @@ class Parser final { void check_type_traits(); + [[nodiscard]] auto strip_parentheses(ExpressionAST* ast) -> ExpressionAST*; + // standard conversions [[nodiscard]] auto lvalue_to_rvalue_conversion(ExpressionAST*& expr) -> bool; [[nodiscard]] auto array_to_pointer_conversion(ExpressionAST*& expr) -> bool; diff --git a/tests/unit_tests/sema/address_op_01.cc b/tests/unit_tests/sema/address_op_01.cc new file mode 100644 index 00000000..fd73342b --- /dev/null +++ b/tests/unit_tests/sema/address_op_01.cc @@ -0,0 +1,41 @@ +// RUN: %cxx -verify -fcheck %s + +struct X { + int m{}; + const int ci{}; + const volatile int cvi{}; + + void f(); + void g(int a, const void* ptr) const; +}; + +auto main() -> int { + static_assert(__is_same(decltype(&X::m), int X::*)); + static_assert(__is_same(decltype(&X::ci), const int X::*)); + static_assert(__is_same(decltype(&X::cvi), const volatile int X::*)); + static_assert(__is_same(decltype(&X::f), void (X::*)())); + static_assert( + __is_same(decltype(&X::g), void (X::*)(int, const void*) const)); + + char ch{}; + static_assert(__is_same(decltype(&ch), char*)); + + int i{}; + static_assert(__is_same(decltype(&i), int*)); + + const void* p = nullptr; + static_assert(__is_same(decltype(&p), const void**)); + + int a[2]; + static_assert(__is_same(decltype(&a), int(*)[2])); + + X x; + static_assert(__is_same(decltype(&x), X*)); + static_assert(__is_same(decltype(*&x), X&)); + + const X cx; + static_assert(__is_same(decltype(&cx), const X*)); + static_assert(__is_same(decltype(*&cx), const X&)); + + return 0; +} \ No newline at end of file diff --git a/tests/unit_tests/sema/bitwise_not_01.cc b/tests/unit_tests/sema/bitwise_not_01.cc new file mode 100644 index 00000000..3c8cefc3 --- /dev/null +++ b/tests/unit_tests/sema/bitwise_not_01.cc @@ -0,0 +1,18 @@ +// RUN: %cxx -verify -fcheck %s + +auto main() -> int { + static_assert(__is_same(decltype(~'a'), int)); + static_assert(__is_same(decltype(~1), int)); + static_assert(__is_same(decltype(~1l), long)); + static_assert(__is_same(decltype(~1ll), long long)); + static_assert(__is_same(decltype(~1ul), unsigned long)); + static_assert(__is_same(decltype(~1ull), unsigned long long)); + + short x{}; + static_assert(__is_same(decltype(~x), int)); + + short& y = x; + static_assert(__is_same(decltype(~y), int)); + + return 0; +} \ No newline at end of file diff --git a/tests/unit_tests/sema/logical_neg_01.cc b/tests/unit_tests/sema/logical_neg_01.cc new file mode 100644 index 00000000..836e94c8 --- /dev/null +++ b/tests/unit_tests/sema/logical_neg_01.cc @@ -0,0 +1,24 @@ +// RUN: %cxx -verify -fcheck %s + +auto main() -> int { + static_assert(__is_same(decltype(!true), bool)); + static_assert(__is_same(decltype(!!true), bool)); + + static_assert(__is_same(decltype(!1), bool)); + static_assert(__is_same(decltype(!1.0), bool)); + + const void* p = nullptr; + static_assert(__is_same(decltype(!p), bool)); + + static_assert(__is_same(decltype(!main), bool)); + + const int a[2] = {1, 2}; + static_assert(__is_same(decltype(!a), bool)); + + int x{}, &y = x; + + static_assert(__is_same(decltype(!x), bool)); + static_assert(__is_same(decltype(!y), bool)); + + return 0; +} \ No newline at end of file diff --git a/tests/unit_tests/sema/unary_minus_01.cc b/tests/unit_tests/sema/unary_minus_01.cc new file mode 100644 index 00000000..bb034468 --- /dev/null +++ b/tests/unit_tests/sema/unary_minus_01.cc @@ -0,0 +1,23 @@ +// RUN: %cxx -verify -fcheck %s + +auto main() -> int { + static_assert(__is_same(decltype(-'a'), int)); + static_assert(__is_same(decltype(-1), int)); + static_assert(__is_same(decltype(-1l), long)); + static_assert(__is_same(decltype(-1ll), long long)); + static_assert(__is_same(decltype(-1ul), unsigned long)); + static_assert(__is_same(decltype(-1ull), unsigned long long)); + static_assert(__is_same(decltype(-1.0f), float)); + static_assert(__is_same(decltype(-1.0), double)); + + short x{}; + static_assert(__is_same(decltype(-x), int)); + + short& y = x; + static_assert(__is_same(decltype(-y), int)); + + unsigned u{}; + static_assert(__is_same(decltype(-u), unsigned)); + + return 0; +} \ No newline at end of file