From 24769089e55a82cab698c10db14b8f7c90cb175e Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 13 Mar 2025 10:42:27 +0100 Subject: [PATCH 1/5] Move template symbol instantiation out of Parser --- .../cxx-gen-ast/src/new_ast_rewriter_cc.ts | 5 +- .../cxx-gen-ast/src/new_ast_rewriter_h.ts | 2 + src/parser/cxx/ast_rewriter.cc | 5 +- src/parser/cxx/ast_rewriter.h | 2 + src/parser/cxx/binder.cc | 54 +++++++++++ src/parser/cxx/binder.h | 6 ++ src/parser/cxx/decl_specs.cc | 10 +- src/parser/cxx/parser.cc | 96 ++++--------------- src/parser/cxx/parser.h | 9 -- 9 files changed, 97 insertions(+), 92 deletions(-) diff --git a/packages/cxx-gen-ast/src/new_ast_rewriter_cc.ts b/packages/cxx-gen-ast/src/new_ast_rewriter_cc.ts index 1c8677b8..6fd9aafb 100644 --- a/packages/cxx-gen-ast/src/new_ast_rewriter_cc.ts +++ b/packages/cxx-gen-ast/src/new_ast_rewriter_cc.ts @@ -222,8 +222,9 @@ namespace cxx { ${opName}::${opName}(TypeChecker* typeChcker, const std::vector& templateArguments) : typeChecker_(typeChcker) -, unit_(typeChcker->translationUnit()) -, templateArguments_(templateArguments) {} +, unit_(typeChcker->translationUnit()) +, templateArguments_(templateArguments) +, binder_(typeChcker->translationUnit()) {} ${opName}::~${opName}() {} diff --git a/packages/cxx-gen-ast/src/new_ast_rewriter_h.ts b/packages/cxx-gen-ast/src/new_ast_rewriter_h.ts index f31792ce..cf20cab2 100644 --- a/packages/cxx-gen-ast/src/new_ast_rewriter_h.ts +++ b/packages/cxx-gen-ast/src/new_ast_rewriter_h.ts @@ -70,6 +70,7 @@ export function new_ast_rewriter_h({ #include #include +#include #include @@ -96,6 +97,7 @@ private: TypeChecker* typeChecker_ = nullptr; const std::vector& templateArguments_; TranslationUnit* unit_ = nullptr; + Binder binder_; }; } // namespace cxx diff --git a/src/parser/cxx/ast_rewriter.cc b/src/parser/cxx/ast_rewriter.cc index 858038b5..bf40a5de 100644 --- a/src/parser/cxx/ast_rewriter.cc +++ b/src/parser/cxx/ast_rewriter.cc @@ -33,7 +33,8 @@ ASTRewriter::ASTRewriter(TypeChecker* typeChcker, const std::vector& templateArguments) : typeChecker_(typeChcker), unit_(typeChcker->translationUnit()), - templateArguments_(templateArguments) {} + templateArguments_(templateArguments), + binder_(typeChcker->translationUnit()) {} ASTRewriter::~ASTRewriter() {} @@ -1027,6 +1028,7 @@ auto ASTRewriter::operator()(EnumeratorAST* ast) -> EnumeratorAST* { copy->equalLoc = ast->equalLoc; copy->expression = operator()(ast->expression); copy->identifier = ast->identifier; + copy->symbol = ast->symbol; return copy; } @@ -3094,6 +3096,7 @@ auto ASTRewriter::ExpressionVisitor::operator()(ConditionExpressionAST* ast) copy->declarator = rewrite(ast->declarator); copy->initializer = rewrite(ast->initializer); + copy->symbol = ast->symbol; return copy; } diff --git a/src/parser/cxx/ast_rewriter.h b/src/parser/cxx/ast_rewriter.h index b6485107..4c16c150 100644 --- a/src/parser/cxx/ast_rewriter.h +++ b/src/parser/cxx/ast_rewriter.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include @@ -136,6 +137,7 @@ class ASTRewriter { TypeChecker* typeChecker_ = nullptr; const std::vector& templateArguments_; TranslationUnit* unit_ = nullptr; + Binder binder_; }; } // namespace cxx diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 081df35c..e536f553 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -617,4 +617,58 @@ auto Binder::isConstructor(Symbol* symbol) const -> bool { return true; } +auto Binder::resolve(NestedNameSpecifierAST* nestedNameSpecifier, + UnqualifiedIdAST* unqualifiedId, bool canInstantiate) + -> Symbol* { + if (auto templateId = ast_cast(unqualifiedId)) { + if (!canInstantiate) return nullptr; + + auto instance = instantiate(templateId); + + if (!is_type(instance)) return nullptr; + + return instance; + } + + auto name = ast_cast(unqualifiedId); + + auto symbol = + Lookup{scope()}.lookupType(nestedNameSpecifier, name->identifier); + + if (!is_type(symbol)) return nullptr; + + return symbol; +} + +auto Binder::instantiate(SimpleTemplateIdAST* templateId) -> Symbol* { + std::vector args; + for (auto it = templateId->templateArgumentList; it; it = it->next) { + if (auto arg = ast_cast(it->value)) { + args.push_back(arg->typeId->type); + } else { + error(it->value->firstSourceLocation(), + std::format("only type template arguments are supported")); + } + } + + auto needsInstantiation = [&]() -> bool { + if (args.empty()) return true; + for (std::size_t i = 0; i < args.size(); ++i) { + auto typeArgument = std::get_if(&args[i]); + if (!typeArgument) return true; + auto ty = type_cast(*typeArgument); + if (!ty) return true; + if (ty->symbol()->index() != i) return true; + } + return false; + }; + + if (!needsInstantiation()) return nullptr; + + auto symbol = control()->instantiate(unit_, templateId->primaryTemplateSymbol, + std::move(args)); + + return symbol; +} + } // namespace cxx diff --git a/src/parser/cxx/binder.h b/src/parser/cxx/binder.h index 30bd3f27..d4267668 100644 --- a/src/parser/cxx/binder.h +++ b/src/parser/cxx/binder.h @@ -121,6 +121,12 @@ class Binder { void bind(UsingDirectiveAST* ast); + [[nodiscard]] auto instantiate(SimpleTemplateIdAST* templateId) -> Symbol*; + + [[nodiscard]] auto resolve(NestedNameSpecifierAST* nestedNameSpecifier, + UnqualifiedIdAST* unqualifiedId, + bool canInstantiate) -> Symbol*; + class ScopeGuard { public: Binder* p = nullptr; diff --git a/src/parser/cxx/decl_specs.cc b/src/parser/cxx/decl_specs.cc index c06ac34f..bd773f4a 100644 --- a/src/parser/cxx/decl_specs.cc +++ b/src/parser/cxx/decl_specs.cc @@ -254,7 +254,12 @@ void DeclSpecs::Visitor::operator()(ComplexTypeSpecifierAST* ast) { void DeclSpecs::Visitor::operator()(NamedTypeSpecifierAST* ast) { specs.typeSpecifier = ast; - if (ast->symbol) specs.type = ast->symbol->type(); + + if (ast->symbol) + specs.type = ast->symbol->type(); + else + specs.type = control()->getUnresolvedNameType( + specs.unit, ast->nestedNameSpecifier, ast->unqualifiedId); } void DeclSpecs::Visitor::operator()(AtomicTypeSpecifierAST* ast) { @@ -322,6 +327,9 @@ void DeclSpecs::Visitor::operator()(ClassSpecifierAST* ast) { void DeclSpecs::Visitor::operator()(TypenameSpecifierAST* ast) { specs.typeSpecifier = ast; + specs.type = control()->getUnresolvedNameType( + specs.unit, ast->nestedNameSpecifier, ast->unqualifiedId); + // ### todo } diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index fcc01a3b..0e64b43a 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -837,7 +837,7 @@ auto Parser::parse_id_expression(IdExpressionAST*& yyast, ast->isTemplateIntroduced = isTemplateIntroduced; if (unqualifiedId) { - auto name = convertName(unqualifiedId); + auto name = get_name(control_, unqualifiedId); const Name* componentName = name; if (auto templateId = name_cast(name)) componentName = templateId->name(); @@ -1073,8 +1073,8 @@ auto Parser::parse_template_nested_name_specifier( } } - if (!ast->symbol) { - ast->symbol = instantiate(templateId); + if (!ast->symbol && config_.checkTypes) { + ast->symbol = binder_.instantiate(templateId); } return true; @@ -1921,7 +1921,7 @@ auto Parser::check_member_access(MemberExpressionAST* ast) -> bool { auto classType = type_cast(objectType); if (!classType) return false; - auto memberName = convertName(ast->unqualifiedId); + auto memberName = get_name(control_, ast->unqualifiedId); auto classSymbol = classType->symbol(); @@ -2135,7 +2135,7 @@ auto Parser::parse_builtin_offsetof_expression(ExpressionAST*& yyast, if (classType && id && !id->nestedNameSpecifier) { auto symbol = classType->symbol(); - auto name = convertName(id->unqualifiedId); + auto name = get_name(control_, id->unqualifiedId); auto member = Lookup{scope()}.qualifiedLookup(symbol->scope(), name); auto field = symbol_cast(member); ast->symbol = field; @@ -4929,39 +4929,6 @@ auto Parser::parse_complex_type_specifier(SpecifierAST*& yyast, return true; } -auto Parser::instantiate(SimpleTemplateIdAST* templateId) -> Symbol* { - if (!config_.checkTypes) return nullptr; - - std::vector args; - for (auto it = templateId->templateArgumentList; it; it = it->next) { - if (auto arg = ast_cast(it->value)) { - args.push_back(arg->typeId->type); - } else { - parse_error(it->value->firstSourceLocation(), - std::format("only type template arguments are supported")); - } - } - - auto needsInstantiation = [&]() -> bool { - if (args.empty()) return true; - for (std::size_t i = 0; i < args.size(); ++i) { - auto typeArgument = std::get_if(&args[i]); - if (!typeArgument) return true; - auto ty = type_cast(*typeArgument); - if (!ty) return true; - if (ty->symbol()->index() != i) return true; - } - return false; - }; - - if (!needsInstantiation()) return nullptr; - - auto symbol = control_->instantiate(unit, templateId->primaryTemplateSymbol, - std::move(args)); - - return symbol; -} - auto Parser::parse_named_type_specifier(SpecifierAST*& yyast, DeclSpecs& specs) -> bool { if (specs.isUnsigned || specs.isSigned || specs.isShort || specs.isLong) @@ -4984,37 +4951,23 @@ auto Parser::parse_named_type_specifier(SpecifierAST*& yyast, DeclSpecs& specs) return false; } - Symbol* typeSymbol = nullptr; - if (auto templateId = ast_cast(unqualifiedId)) { - if (auto conceptSymbol = - symbol_cast(templateId->primaryTemplateSymbol)) { - if (!lookat(TokenKind::T_AUTO)) return false; - } + auto primaryTemplateSymbol = templateId->primaryTemplateSymbol; + auto conceptSymbol = symbol_cast(primaryTemplateSymbol); + if (conceptSymbol && !lookat(TokenKind::T_AUTO)) return false; + } - if (auto symbol = instantiate(templateId)) { - specs.type = symbol->type(); - } - } else { - auto name = ast_cast(unqualifiedId); - auto symbol = - Lookup{scope()}.lookupType(nestedNameSpecifier, name->identifier); + const auto canInstantiate = config_.checkTypes; - if (is_type(symbol)) { - typeSymbol = symbol; - specs.type = symbol->type(); - } else { - if (config_.checkTypes) return false; - } + auto symbol = + binder_.resolve(nestedNameSpecifier, unqualifiedId, canInstantiate); + + if (config_.checkTypes && !symbol && ast_cast(unqualifiedId)) { + return false; } lookahead.commit(); - if (!specs.type) { - specs.type = control_->getUnresolvedNameType(unit, nestedNameSpecifier, - unqualifiedId); - } - auto ast = make_node(pool_); yyast = ast; @@ -5022,7 +4975,7 @@ auto Parser::parse_named_type_specifier(SpecifierAST*& yyast, DeclSpecs& specs) ast->templateLoc = templateLoc; ast->unqualifiedId = unqualifiedId; ast->isTemplateIntroduced = isTemplateIntroduced; - ast->symbol = typeSymbol; + ast->symbol = symbol; specs.accept(ast); @@ -5191,13 +5144,6 @@ 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::strip_cv(const Type*& type) -> CvQualifiers { if (auto qualType = type_cast(type)) { auto cv = qualType->cvQualifiers(); @@ -6816,7 +6762,7 @@ auto Parser::parse_using_declarator(UsingDeclaratorAST*& yyast) -> bool { /*inRequiresClause*/ false)) return false; - auto name = convertName(unqualifiedId); + auto name = get_name(control_, unqualifiedId); auto target = Lookup{scope()}.lookup(nestedNameSpecifier, name); SourceLocation ellipsisLoc; @@ -9303,9 +9249,6 @@ auto Parser::parse_typename_specifier(SpecifierAST*& yyast, DeclSpecs& specs) ast->nestedNameSpecifier = nestedNameSpecifier; ast->unqualifiedId = unqualifiedId; - specs.type = - control_->getUnresolvedNameType(unit, nestedNameSpecifier, unqualifiedId); - specs.accept(ast); return true; @@ -9596,11 +9539,6 @@ void Parser::check(ExpressionAST* ast) { check(ast); } -auto Parser::convertName(UnqualifiedIdAST* id) -> const Name* { - if (!id) return nullptr; - return get_name(control_, id); -} - auto Parser::getFunction(Scope* scope, const Name* name, const Type* type) -> FunctionSymbol* { auto parentScope = scope; diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index e6cab81d..db2593b9 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -790,7 +790,6 @@ class Parser final { void check(ExpressionAST* ast); // lookup - [[nodiscard]] auto convertName(UnqualifiedIdAST* id) -> const Name*; [[nodiscard]] auto getFunction(Scope* scope, const Name* name, const Type* type) -> FunctionSymbol*; @@ -801,15 +800,8 @@ class Parser final { void enterFunctionScope(FunctionDeclaratorChunkAST* functionDeclarator); - [[nodiscard]] auto instantiate(SimpleTemplateIdAST* templateId) -> Symbol*; - - void applySpecifiers(FunctionSymbol* symbol, const DeclSpecs& specs); - void applySpecifiers(VariableSymbol* symbol, const DeclSpecs& specs); - void applySpecifiers(FieldSymbol* symbol, const DeclSpecs& specs); - void check_type_traits(); - [[nodiscard]] auto strip_parentheses(ExpressionAST* ast) -> ExpressionAST*; [[nodiscard]] auto strip_cv(const Type*& type) -> CvQualifiers; [[nodiscard]] auto is_const(CvQualifiers cv) const -> bool; [[nodiscard]] auto is_volatile(CvQualifiers cv) const -> bool; @@ -820,7 +812,6 @@ class Parser final { [[nodiscard]] auto is_glvalue(ExpressionAST* expr) const -> bool; [[nodiscard]] auto is_template(Symbol* symbol) const -> bool; - [[nodiscard]] auto is_constructor(Symbol* symbol) const -> bool; [[nodiscard]] auto evaluate_constant_expression(ExpressionAST* expr) -> std::optional; From 817d45204cc790cfbcffd371bcc56e03e98f1da7 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 13 Mar 2025 10:49:24 +0100 Subject: [PATCH 2/5] Move checking of member expressions out of Parser --- src/parser/cxx/cli.cc | 4 +- src/parser/cxx/parser.cc | 172 ++++------- src/parser/cxx/parser.h | 6 - src/parser/cxx/type_checker.cc | 288 +++++++++++++------ tests/unit_tests/ast/variadic_function_02.cc | 2 +- 5 files changed, 262 insertions(+), 210 deletions(-) diff --git a/src/parser/cxx/cli.cc b/src/parser/cxx/cli.cc index 15f8c124..6177b4db 100644 --- a/src/parser/cxx/cli.cc +++ b/src/parser/cxx/cli.cc @@ -264,7 +264,9 @@ auto CLI::positionals() const -> std::vector { std::vector result; for (const auto& match : result_) { if (auto p = std::get_if(&match)) { - result.push_back(std::get<0>(*p)); + auto arg = std::get<0>(*p); + if (arg.empty()) continue; + result.push_back(std::move(arg)); } } return result; diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 0e64b43a..b8b7f75b 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -1894,112 +1894,13 @@ auto Parser::parse_member_expression(ExpressionAST*& yyast) -> bool { /*inRequiresClause*/ false)) parse_error("expected an unqualified id"); - check_member_expression(ast); + check(ast); yyast = ast; return true; } -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 cv1 = strip_cv(objectType); - - if (ast->accessOp == TokenKind::T_MINUS_GREATER) { - auto pointerType = type_cast(objectType); - if (!pointerType) return false; - - objectType = pointerType->elementType(); - cv1 = strip_cv(objectType); - } - - auto classType = type_cast(objectType); - if (!classType) return false; - - auto memberName = get_name(control_, ast->unqualifiedId); - - auto classSymbol = classType->symbol(); - - auto symbol = - Lookup{scope()}.qualifiedLookup(classSymbol->scope(), memberName); - - ast->symbol = symbol; - - if (symbol) { - ast->type = symbol->type(); - - if (symbol->isEnumerator()) { - ast->valueCategory = ValueCategory::kPrValue; - } else { - if (is_lvalue(ast->baseExpression)) { - ast->valueCategory = ValueCategory::kLValue; - } else { - ast->valueCategory = ValueCategory::kXValue; - } - - if (auto field = symbol_cast(symbol); - field && !field->isStatic()) { - auto cv2 = strip_cv(ast->type); - - if (is_volatile(cv1) || is_volatile(cv2)) - ast->type = control_->add_volatile(ast->type); - - if (!field->isMutable() && (is_const(cv1) || is_const(cv2))) - ast->type = control_->add_const(ast->type); - } - } - } - - return true; -} - -auto Parser::check_pseudo_destructor_access(MemberExpressionAST* ast) -> bool { - auto 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); - } - - if (!control_->is_scalar(objectType)) { - // return false if the object type is not a scalar type - return false; - } - - // from this point on we are going to assume that we want a pseudo destructor - // to be called on a scalar type. - - auto dtor = ast_cast(ast->unqualifiedId); - if (!dtor) return true; - - auto name = ast_cast(dtor->id); - if (!name) return true; - - auto symbol = - Lookup{scope()}.lookupType(ast->nestedNameSpecifier, name->identifier); - if (!symbol) return true; - - if (!control_->is_same(symbol->type(), objectType)) { - parse_error(ast->unqualifiedId->firstSourceLocation(), - "the type of object expression does not match the type " - "being destroyed"); - return true; - } - - ast->symbol = symbol; - ast->type = control_->getFunctionType(control_->getVoidType(), {}); - - return true; -} - auto Parser::parse_subscript_expression(ExpressionAST*& yyast, const ExprContext& ctx) -> bool { SourceLocation lbracketLoc; @@ -2007,6 +1908,7 @@ auto Parser::parse_subscript_expression(ExpressionAST*& yyast, if (!match(TokenKind::T_LBRACKET, lbracketLoc)) return false; auto ast = make_node(pool_); + ast->baseExpression = yyast; ast->lbracketLoc = lbracketLoc; @@ -2016,6 +1918,8 @@ auto Parser::parse_subscript_expression(ExpressionAST*& yyast, expect(TokenKind::T_RBRACKET, ast->rbracketLoc); + check(ast); + return true; } @@ -2059,6 +1963,8 @@ auto Parser::parse_postincr_expression(ExpressionAST*& yyast, ast->op = unit->tokenKind(ast->opLoc); yyast = ast; + check(ast); + return true; } @@ -2101,47 +2007,44 @@ auto Parser::parse_cpp_cast_expression(ExpressionAST*& yyast, auto Parser::parse_builtin_bit_cast_expression(ExpressionAST*& yyast, const ExprContext& ctx) -> bool { - if (!lookat(TokenKind::T___BUILTIN_BIT_CAST)) return false; + SourceLocation castLoc; + if (!match(TokenKind::T___BUILTIN_BIT_CAST, castLoc)) return false; auto ast = make_node(pool_); yyast = ast; - ast->castLoc = consumeToken(); + ast->castLoc = castLoc; expect(TokenKind::T_LPAREN, ast->lparenLoc); + if (!parse_type_id(ast->typeId)) parse_error("expected a type id"); + expect(TokenKind::T_COMMA, ast->commaLoc); parse_expression(ast->expression, ctx); expect(TokenKind::T_RPAREN, ast->rparenLoc); + check(ast); + return true; } auto Parser::parse_builtin_offsetof_expression(ExpressionAST*& yyast, const ExprContext& ctx) -> bool { - if (!lookat(TokenKind::T___BUILTIN_OFFSETOF)) return false; + SourceLocation offsetofLoc; + if (!match(TokenKind::T___BUILTIN_OFFSETOF, offsetofLoc)) return false; auto ast = make_node(pool_); yyast = ast; - ast->offsetofLoc = consumeToken(); + ast->offsetofLoc = offsetofLoc; expect(TokenKind::T_LPAREN, ast->lparenLoc); + if (!parse_type_id(ast->typeId)) parse_error("expected a type id"); + expect(TokenKind::T_COMMA, ast->commaLoc); parse_expression(ast->expression, ctx); expect(TokenKind::T_RPAREN, ast->rparenLoc); - auto classType = type_cast(ast->typeId->type); - auto id = ast_cast(ast->expression); - - if (classType && id && !id->nestedNameSpecifier) { - auto symbol = classType->symbol(); - auto name = get_name(control_, id->unqualifiedId); - auto member = Lookup{scope()}.qualifiedLookup(symbol->scope(), name); - auto field = symbol_cast(member); - ast->symbol = field; - } - - ast->type = control_->getSizeType(); + check(ast); return true; } @@ -2221,6 +2124,8 @@ auto Parser::parse_cpp_type_cast_expression(ExpressionAST*& yyast, ast->expressionList = expressionList; ast->rparenLoc = rparenLoc; + check(ast); + return true; } @@ -2252,6 +2157,8 @@ auto Parser::parse_typeid_expression(ExpressionAST*& yyast, ast->typeId = typeId; ast->rparenLoc = rparenLoc; + check(ast); + return true; }; @@ -2267,6 +2174,8 @@ auto Parser::parse_typeid_expression(ExpressionAST*& yyast, expect(TokenKind::T_RPAREN, ast->rparenLoc); + check(ast); + return true; } @@ -2288,6 +2197,8 @@ auto Parser::parse_typename_expression(ExpressionAST*& yyast, ast->typeSpecifier = typenameSpecifier; ast->bracedInitList = bracedInitList; + check(ast); + return true; } @@ -2315,6 +2226,8 @@ auto Parser::parse_typename_expression(ExpressionAST*& yyast, ast->expressionList = expressionList; ast->rparenLoc = rparenLoc; + check(ast); + return true; } @@ -2339,9 +2252,9 @@ auto Parser::parse_va_arg_expression(ExpressionAST*& yyast, expect(TokenKind::T_COMMA, ast->commaLoc); if (!parse_type_id(ast->typeId)) parse_error("expected a type id"); expect(TokenKind::T_RPAREN, ast->rparenLoc); - if (ast->type) { - ast->type = ast->typeId->type; - } + + check(ast); + return true; } @@ -2381,7 +2294,7 @@ auto Parser::parse_builtin_call_expression(ExpressionAST*& yyast, expect(TokenKind::T_RPAREN, ast->rparenLoc); - ast->type = control_->getBoolType(); + check(ast); return true; } @@ -2603,6 +2516,8 @@ auto Parser::parse_await_expression(ExpressionAST*& yyast, if (!parse_cast_expression(ast->expression, ctx)) parse_error("expected an expression"); + check(ast); + return true; } @@ -2621,6 +2536,8 @@ auto Parser::parse_noexcept_expression(ExpressionAST*& yyast, expect(TokenKind::T_RPAREN, ast->rparenLoc); + check(ast); + return true; } @@ -2667,6 +2584,8 @@ auto Parser::parse_new_expression(ExpressionAST*& yyast, const ExprContext& ctx) ast->rparenLoc = rparenLoc; ast->newInitalizer = newInitializer; + check(ast); + return true; }; @@ -2682,6 +2601,8 @@ auto Parser::parse_new_expression(ExpressionAST*& yyast, const ExprContext& ctx) parse_optional_new_initializer(ast->newInitalizer, ctx); + check(ast); + return true; } @@ -2761,6 +2682,8 @@ auto Parser::parse_delete_expression(ExpressionAST*& yyast, parse_error("expected an expression"); } + check(ast); + return true; } @@ -2772,6 +2695,7 @@ auto Parser::parse_cast_expression(ExpressionAST*& yyast, LookaheadParser lookahead{this}; if (!parse_cast_expression_helper(yyast, ctx)) return false; lookahead.commit(); + return true; }; @@ -2811,6 +2735,8 @@ auto Parser::parse_cast_expression_helper(ExpressionAST*& yyast, ast->rparenLoc = rparenLoc; ast->expression = expression; + check(ast); + return true; } @@ -2972,6 +2898,8 @@ auto Parser::parse_conditional_expression(ExpressionAST*& yyast, } else { parse_assignment_expression(ast->iffalseExpression, exprContext); } + + check(ast); } return true; @@ -2989,6 +2917,8 @@ auto Parser::parse_yield_expression(ExpressionAST*& yyast, ast->yieldLoc = yieldLoc; parse_expr_or_braced_init_list(ast->expression, ctx); + check(ast); + return true; } @@ -3009,6 +2939,8 @@ auto Parser::parse_throw_expression(ExpressionAST*& yyast, lookahead.commit(); } + check(ast); + return true; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index db2593b9..cb5d6eda 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -240,12 +240,6 @@ class Parser final { [[nodiscard]] auto parse_member_expression(ExpressionAST*& yyast) -> bool; - 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, const ExprContext& ctx) -> bool; [[nodiscard]] auto parse_call_expression(ExpressionAST*& yyast, diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 7d818329..78f0ea69 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -123,6 +125,10 @@ struct TypeChecker::Visitor { void check_addition(BinaryExpressionAST* ast); void check_subtraction(BinaryExpressionAST* ast); + [[nodiscard]] auto check_member_access(MemberExpressionAST* ast) -> bool; + [[nodiscard]] auto check_pseudo_destructor_access(MemberExpressionAST* ast) + -> bool; + void operator()(GeneratedLiteralExpressionAST* ast); void operator()(CharLiteralExpressionAST* ast); void operator()(BoolLiteralExpressionAST* ast); @@ -249,7 +255,11 @@ void TypeChecker::Visitor::operator()(LeftFoldExpressionAST* ast) {} void TypeChecker::Visitor::operator()(RequiresExpressionAST* ast) {} -void TypeChecker::Visitor::operator()(VaArgExpressionAST* ast) {} +void TypeChecker::Visitor::operator()(VaArgExpressionAST* ast) { + if (ast->typeId) { + ast->type = ast->typeId->type; + } +} void TypeChecker::Visitor::operator()(SubscriptExpressionAST* ast) {} @@ -301,7 +311,10 @@ void TypeChecker::Visitor::operator()(BracedTypeConstructionAST* ast) {} void TypeChecker::Visitor::operator()(SpliceMemberExpressionAST* ast) {} -void TypeChecker::Visitor::operator()(MemberExpressionAST* ast) {} +void TypeChecker::Visitor::operator()(MemberExpressionAST* ast) { + if (check_pseudo_destructor_access(ast)) return; + if (check_member_access(ast)) return; +} void TypeChecker::Visitor::operator()(PostIncrExpressionAST* ast) {} @@ -414,7 +427,20 @@ auto TypeChecker::Visitor::check_cast_to_derived(const Type* targetType, void TypeChecker::Visitor::operator()(BuiltinBitCastExpressionAST* ast) {} -void TypeChecker::Visitor::operator()(BuiltinOffsetofExpressionAST* ast) {} +void TypeChecker::Visitor::operator()(BuiltinOffsetofExpressionAST* ast) { + auto classType = type_cast(ast->typeId->type); + auto id = ast_cast(ast->expression); + + if (classType && id && !id->nestedNameSpecifier) { + auto symbol = classType->symbol(); + auto name = get_name(control(), id->unqualifiedId); + auto member = Lookup{scope()}.qualifiedLookup(symbol->scope(), name); + auto field = symbol_cast(member); + ast->symbol = field; + } + + ast->type = control()->getSizeType(); +} void TypeChecker::Visitor::operator()(TypeidExpressionAST* ast) {} @@ -744,84 +770,6 @@ void TypeChecker::Visitor::operator()(BinaryExpressionAST* ast) { } // switch } -void TypeChecker::Visitor::check_addition(BinaryExpressionAST* ast) { - (void)ensure_prvalue(ast->leftExpression); - (void)ensure_prvalue(ast->rightExpression); - - if (auto ty = usual_arithmetic_conversion(ast->leftExpression, - ast->rightExpression)) { - ast->type = ty; - return; - } - - const auto left_is_pointer = control()->is_pointer(ast->leftExpression->type); - - const auto right_is_pointer = - control()->is_pointer(ast->rightExpression->type); - - const auto left_is_integral = - control()->is_integral_or_unscoped_enum(ast->leftExpression->type); - - const auto right_is_integral = - control()->is_integral_or_unscoped_enum(ast->rightExpression->type); - - if (left_is_pointer && right_is_integral) { - (void)integral_promotion(ast->rightExpression); - ast->type = ast->leftExpression->type; - return; - } - - if (right_is_pointer && left_is_integral) { - (void)integral_promotion(ast->leftExpression); - ast->type = ast->rightExpression->type; - return; - } - - error(ast->opLoc, - std::format( - "invalid operands of types '{}' and '{}' to binary operator '+'", - to_string(ast->leftExpression->type), - to_string(ast->rightExpression->type))); -} - -void TypeChecker::Visitor::check_subtraction(BinaryExpressionAST* ast) { - (void)ensure_prvalue(ast->leftExpression); - (void)ensure_prvalue(ast->rightExpression); - - if (auto ty = usual_arithmetic_conversion(ast->leftExpression, - ast->rightExpression)) { - ast->type = ty; - return; - } - - const auto left_is_pointer = control()->is_pointer(ast->leftExpression->type); - - const auto right_is_pointer = - control()->is_pointer(ast->rightExpression->type); - - if (left_is_pointer && right_is_pointer) { - auto lhs = control()->remove_cv(ast->leftExpression->type); - auto rhs = control()->remove_cv(ast->rightExpression->type); - if (control()->is_same(lhs, rhs)) { - ast->type = control()->getLongIntType(); // TODO: ptrdiff_t - return; - } - } - - if (left_is_pointer && - control()->is_integral_or_unscoped_enum(ast->rightExpression->type)) { - (void)integral_promotion(ast->rightExpression); - ast->type = ast->leftExpression->type; - return; - } - - error(ast->opLoc, - std::format( - "invalid operands of types '{}' and '{}' to binary operator '-'", - to_string(ast->leftExpression->type), - to_string(ast->rightExpression->type))); -} - void TypeChecker::Visitor::operator()(ConditionalExpressionAST* ast) {} void TypeChecker::Visitor::operator()(YieldExpressionAST* ast) {} @@ -842,7 +790,9 @@ void TypeChecker::Visitor::operator()(PackExpansionExpressionAST* ast) {} void TypeChecker::Visitor::operator()(DesignatedInitializerClauseAST* ast) {} -void TypeChecker::Visitor::operator()(TypeTraitExpressionAST* ast) {} +void TypeChecker::Visitor::operator()(TypeTraitExpressionAST* ast) { + ast->type = control()->getBoolType(); +} void TypeChecker::Visitor::operator()(ConditionExpressionAST* ast) {} @@ -1575,4 +1525,178 @@ void TypeChecker::check(ExpressionAST* ast) { visit(Visitor{*this}, ast); } +void TypeChecker::Visitor::check_addition(BinaryExpressionAST* ast) { + (void)ensure_prvalue(ast->leftExpression); + (void)ensure_prvalue(ast->rightExpression); + + if (auto ty = usual_arithmetic_conversion(ast->leftExpression, + ast->rightExpression)) { + ast->type = ty; + return; + } + + const auto left_is_pointer = control()->is_pointer(ast->leftExpression->type); + + const auto right_is_pointer = + control()->is_pointer(ast->rightExpression->type); + + const auto left_is_integral = + control()->is_integral_or_unscoped_enum(ast->leftExpression->type); + + const auto right_is_integral = + control()->is_integral_or_unscoped_enum(ast->rightExpression->type); + + if (left_is_pointer && right_is_integral) { + (void)integral_promotion(ast->rightExpression); + ast->type = ast->leftExpression->type; + return; + } + + if (right_is_pointer && left_is_integral) { + (void)integral_promotion(ast->leftExpression); + ast->type = ast->rightExpression->type; + return; + } + + error(ast->opLoc, + std::format( + "invalid operands of types '{}' and '{}' to binary operator '+'", + to_string(ast->leftExpression->type), + to_string(ast->rightExpression->type))); +} + +void TypeChecker::Visitor::check_subtraction(BinaryExpressionAST* ast) { + (void)ensure_prvalue(ast->leftExpression); + (void)ensure_prvalue(ast->rightExpression); + + if (auto ty = usual_arithmetic_conversion(ast->leftExpression, + ast->rightExpression)) { + ast->type = ty; + return; + } + + const auto left_is_pointer = control()->is_pointer(ast->leftExpression->type); + + const auto right_is_pointer = + control()->is_pointer(ast->rightExpression->type); + + if (left_is_pointer && right_is_pointer) { + auto lhs = control()->remove_cv(ast->leftExpression->type); + auto rhs = control()->remove_cv(ast->rightExpression->type); + if (control()->is_same(lhs, rhs)) { + ast->type = control()->getLongIntType(); // TODO: ptrdiff_t + return; + } + } + + if (left_is_pointer && + control()->is_integral_or_unscoped_enum(ast->rightExpression->type)) { + (void)integral_promotion(ast->rightExpression); + ast->type = ast->leftExpression->type; + return; + } + + error(ast->opLoc, + std::format( + "invalid operands of types '{}' and '{}' to binary operator '-'", + to_string(ast->leftExpression->type), + to_string(ast->rightExpression->type))); +} + +auto TypeChecker::Visitor::check_member_access(MemberExpressionAST* ast) + -> bool { + const Type* objectType = ast->baseExpression->type; + auto cv1 = strip_cv(objectType); + + if (ast->accessOp == TokenKind::T_MINUS_GREATER) { + auto pointerType = type_cast(objectType); + if (!pointerType) return false; + + objectType = pointerType->elementType(); + cv1 = strip_cv(objectType); + } + + auto classType = type_cast(objectType); + if (!classType) return false; + + auto memberName = get_name(control(), ast->unqualifiedId); + + auto classSymbol = classType->symbol(); + + auto symbol = + Lookup{scope()}.qualifiedLookup(classSymbol->scope(), memberName); + + ast->symbol = symbol; + + if (symbol) { + ast->type = symbol->type(); + + if (symbol->isEnumerator()) { + ast->valueCategory = ValueCategory::kPrValue; + } else { + if (is_lvalue(ast->baseExpression)) { + ast->valueCategory = ValueCategory::kLValue; + } else { + ast->valueCategory = ValueCategory::kXValue; + } + + if (auto field = symbol_cast(symbol); + field && !field->isStatic()) { + auto cv2 = strip_cv(ast->type); + + if (is_volatile(cv1) || is_volatile(cv2)) + ast->type = control()->add_volatile(ast->type); + + if (!field->isMutable() && (is_const(cv1) || is_const(cv2))) + ast->type = control()->add_const(ast->type); + } + } + } + + return true; +} + +auto TypeChecker::Visitor::check_pseudo_destructor_access( + MemberExpressionAST* ast) -> bool { + auto 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); + } + + if (!control()->is_scalar(objectType)) { + // return false if the object type is not a scalar type + return false; + } + + // from this point on we are going to assume that we want a pseudo destructor + // to be called on a scalar type. + + auto dtor = ast_cast(ast->unqualifiedId); + if (!dtor) return true; + + auto name = ast_cast(dtor->id); + if (!name) return true; + + auto symbol = + Lookup{scope()}.lookupType(ast->nestedNameSpecifier, name->identifier); + if (!symbol) return true; + + if (!control()->is_same(symbol->type(), objectType)) { + error(ast->unqualifiedId->firstSourceLocation(), + "the type of object expression does not match the type " + "being destroyed"); + return true; + } + + ast->symbol = symbol; + ast->type = control()->getFunctionType(control()->getVoidType(), {}); + + return true; +} + } // namespace cxx diff --git a/tests/unit_tests/ast/variadic_function_02.cc b/tests/unit_tests/ast/variadic_function_02.cc index 7b79a228..bb79b5bb 100644 --- a/tests/unit_tests/ast/variadic_function_02.cc +++ b/tests/unit_tests/ast/variadic_function_02.cc @@ -98,7 +98,7 @@ void ff(int count, ...) { // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: void-type-specifier -// CHECK-NEXT: expression: va-arg-expression +// CHECK-NEXT: expression: va-arg-expression [prvalue int] // CHECK-NEXT: expression: id-expression [lvalue __builtin_va_list] // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: args From f15ef55bd65195476faa4ec602f6a56a800fc8f4 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 13 Mar 2025 11:33:39 +0100 Subject: [PATCH 3/5] Move binding decltype specifiers out of the Parser --- packages/cxx-gen-ast/src/gen_ast_h.ts | 21 +++++++++++ src/parser/cxx/ast.h | 21 +++++++++++ src/parser/cxx/binder.cc | 16 +++++++++ src/parser/cxx/binder.h | 2 ++ src/parser/cxx/parser.cc | 52 +-------------------------- src/parser/cxx/parser.h | 9 ----- src/parser/cxx/type_checker.cc | 25 ------------- 7 files changed, 61 insertions(+), 85 deletions(-) diff --git a/packages/cxx-gen-ast/src/gen_ast_h.ts b/packages/cxx-gen-ast/src/gen_ast_h.ts index a9f29f7a..bb98a9d7 100644 --- a/packages/cxx-gen-ast/src/gen_ast_h.ts +++ b/packages/cxx-gen-ast/src/gen_ast_h.ts @@ -274,6 +274,27 @@ template ${code.join("\n")} +[[nodiscard]] inline auto is_prvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kPrValue; +} + +[[nodiscard]] inline auto is_lvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kLValue; +} + +[[nodiscard]] inline auto is_xvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kXValue; +} + +[[nodiscard]] inline auto is_glvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kLValue || + expr->valueCategory == ValueCategory::kXValue; +} + } // namespace cxx `; diff --git a/src/parser/cxx/ast.h b/src/parser/cxx/ast.h index 4f323749..613b8c5c 100644 --- a/src/parser/cxx/ast.h +++ b/src/parser/cxx/ast.h @@ -5328,4 +5328,25 @@ template <> } // switch } +[[nodiscard]] inline auto is_prvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kPrValue; +} + +[[nodiscard]] inline auto is_lvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kLValue; +} + +[[nodiscard]] inline auto is_xvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kXValue; +} + +[[nodiscard]] inline auto is_glvalue(ExpressionAST* expr) -> bool { + if (!expr) return false; + return expr->valueCategory == ValueCategory::kLValue || + expr->valueCategory == ValueCategory::kXValue; +} + } // namespace cxx diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index e536f553..06883155 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -276,6 +276,22 @@ void Binder::bind(ParameterDeclarationAST* ast, const Decl& decl, } } +void Binder::bind(DecltypeSpecifierAST* ast) { + if (auto id = ast_cast(ast->expression)) { + if (id->symbol) ast->type = id->symbol->type(); + } else if (auto member = ast_cast(ast->expression)) { + if (member->symbol) ast->type = member->symbol->type(); + } else if (ast->expression && ast->expression->type) { + if (is_lvalue(ast->expression)) { + ast->type = control()->add_lvalue_reference(ast->expression->type); + } else if (is_xvalue(ast->expression)) { + ast->type = control()->add_rvalue_reference(ast->expression->type); + } else { + ast->type = ast->expression->type; + } + } +} + void Binder::bind(EnumeratorAST* ast, const Type* type, std::optional value) { auto symbol = control()->newEnumeratorSymbol(scope(), ast->identifierLoc); diff --git a/src/parser/cxx/binder.h b/src/parser/cxx/binder.h index d4267668..e65458b5 100644 --- a/src/parser/cxx/binder.h +++ b/src/parser/cxx/binder.h @@ -93,6 +93,8 @@ class Binder { void complete(ClassSpecifierAST* ast); + void bind(DecltypeSpecifierAST* ast); + void bind(EnumeratorAST* ast, const Type* type, std::optional value); diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index b8b7f75b..26013695 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -5076,44 +5076,6 @@ void Parser::check_type_traits() { rewind(typeTraitLoc); } -auto Parser::strip_cv(const Type*& type) -> CvQualifiers { - if (auto qualType = type_cast(type)) { - auto cv = qualType->cvQualifiers(); - type = qualType->elementType(); - return cv; - } - return {}; -} - -auto Parser::is_const(CvQualifiers cv) const -> bool { - return cv == CvQualifiers::kConst || cv == CvQualifiers::kConstVolatile; -} - -auto Parser::is_volatile(CvQualifiers cv) const -> bool { - return cv == CvQualifiers::kVolatile || cv == CvQualifiers::kConstVolatile; -} - -auto Parser::is_prvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kPrValue; -} - -auto Parser::is_lvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kLValue; -} - -auto Parser::is_xvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kXValue; -} - -auto Parser::is_glvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kLValue || - expr->valueCategory == ValueCategory::kXValue; -} - auto Parser::is_template(Symbol* symbol) const -> bool { if (!symbol) return false; if (symbol->isTemplateTypeParameter()) return true; @@ -5231,19 +5193,7 @@ auto Parser::parse_decltype_specifier(DecltypeSpecifierAST*& yyast) -> bool { expect(TokenKind::T_RPAREN, ast->rparenLoc); - if (auto id = ast_cast(ast->expression)) { - if (id->symbol) ast->type = id->symbol->type(); - } else if (auto member = ast_cast(ast->expression)) { - if (member->symbol) ast->type = member->symbol->type(); - } else if (ast->expression && ast->expression->type) { - if (is_lvalue(ast->expression)) { - ast->type = control_->add_lvalue_reference(ast->expression->type); - } else if (is_xvalue(ast->expression)) { - ast->type = control_->add_rvalue_reference(ast->expression->type); - } else { - ast->type = ast->expression->type; - } - } + binder_.bind(ast); return true; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index cb5d6eda..3e5a11d3 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -796,15 +796,6 @@ class Parser final { void check_type_traits(); - [[nodiscard]] auto strip_cv(const Type*& type) -> CvQualifiers; - [[nodiscard]] auto is_const(CvQualifiers cv) const -> bool; - [[nodiscard]] auto is_volatile(CvQualifiers cv) const -> bool; - - [[nodiscard]] auto is_prvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_lvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_xvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_glvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_template(Symbol* symbol) const -> bool; [[nodiscard]] auto evaluate_constant_expression(ExpressionAST* expr) diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 78f0ea69..52421e25 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -110,10 +110,6 @@ struct TypeChecker::Visitor { [[nodiscard]] auto is_null_pointer_constant(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_prvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_lvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_xvalue(ExpressionAST* expr) const -> bool; - [[nodiscard]] auto is_glvalue(ExpressionAST* expr) const -> bool; [[nodiscard]] auto check_cv_qualifiers(CvQualifiers target, CvQualifiers source) const -> bool; @@ -1483,27 +1479,6 @@ auto TypeChecker::Visitor::is_null_pointer_constant(ExpressionAST* expr) const return false; } -auto TypeChecker::Visitor::is_prvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kPrValue; -} - -auto TypeChecker::Visitor::is_lvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kLValue; -} - -auto TypeChecker::Visitor::is_xvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kXValue; -} - -auto TypeChecker::Visitor::is_glvalue(ExpressionAST* expr) const -> bool { - if (!expr) return false; - return expr->valueCategory == ValueCategory::kLValue || - expr->valueCategory == ValueCategory::kXValue; -} - auto TypeChecker::Visitor::check_cv_qualifiers(CvQualifiers target, CvQualifiers source) const -> bool { From 7de0829e9264a1d53860cb6ecbb730d69b5a9da6 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 13 Mar 2025 11:46:56 +0100 Subject: [PATCH 4/5] Move binding of type ids out of the Parser --- src/parser/cxx/binder.cc | 4 ++++ src/parser/cxx/binder.h | 2 ++ src/parser/cxx/parser.cc | 11 +++++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 06883155..f2ffa4a0 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -491,6 +491,10 @@ void Binder::bind(UsingDirectiveAST* ast) { } } +void Binder::bind(TypeIdAST* ast, const Decl& decl) { + ast->type = getDeclaratorType(unit_, ast->declarator, decl.specs.getType()); +} + auto Binder::declareTypedef(DeclaratorAST* declarator, const Decl& decl) -> TypeAliasSymbol* { auto name = decl.getName(); diff --git a/src/parser/cxx/binder.h b/src/parser/cxx/binder.h index e65458b5..abda0b20 100644 --- a/src/parser/cxx/binder.h +++ b/src/parser/cxx/binder.h @@ -123,6 +123,8 @@ class Binder { void bind(UsingDirectiveAST* ast); + void bind(TypeIdAST* ast, const Decl& decl); + [[nodiscard]] auto instantiate(SimpleTemplateIdAST* templateId) -> Symbol*; [[nodiscard]] auto resolve(NestedNameSpecifierAST* nestedNameSpecifier, diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 26013695..82d11b25 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -5698,8 +5698,7 @@ auto Parser::parse_type_id(TypeIdAST*& yyast) -> bool { Decl decl{specs}; parse_optional_abstract_declarator(yyast->declarator, decl); - yyast->type = - getDeclaratorType(unit, yyast->declarator, decl.specs.getType()); + binder_.bind(yyast, decl); return true; } @@ -5726,7 +5725,8 @@ auto Parser::parse_defining_type_id( ast->typeSpecifierList = typeSpecifierList; ast->declarator = declarator; - ast->type = getDeclaratorType(unit, ast->declarator, decl.specs.getType()); + + binder_.bind(ast, decl); return true; } @@ -7935,7 +7935,10 @@ auto Parser::parse_conversion_function_id(ConversionFunctionIdAST*& yyast) auto typeId = make_node(pool_); typeId->typeSpecifierList = typeSpecifierList; typeId->declarator = declarator; - typeId->type = getDeclaratorType(unit, declarator, specs.getType()); + + Decl decl{specs}; + + binder_.bind(typeId, decl); auto ast = make_node(pool_); yyast = ast; From 81e79f8db5ffb5877674d414cfe4b151f004c965 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 13 Mar 2025 12:37:09 +0100 Subject: [PATCH 5/5] Move checking of id expressions out of the Parser --- src/parser/cxx/binder.cc | 10 ++++++++++ src/parser/cxx/binder.h | 2 ++ src/parser/cxx/parser.cc | 23 ++-------------------- src/parser/cxx/type_checker.cc | 18 ++++++++++++++++- tests/unit_tests/ast/new_expression_01.cc | 8 ++++---- tests/unit_tests/ast/template_lambda_01.cc | 4 ++-- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index f2ffa4a0..2e97aa70 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -691,4 +691,14 @@ auto Binder::instantiate(SimpleTemplateIdAST* templateId) -> Symbol* { return symbol; } +void Binder::bind(IdExpressionAST* ast) { + if (ast->unqualifiedId) { + auto name = get_name(control(), ast->unqualifiedId); + const Name* componentName = name; + if (auto templateId = name_cast(name)) + componentName = templateId->name(); + ast->symbol = Lookup{scope()}(ast->nestedNameSpecifier, componentName); + } +} + } // namespace cxx diff --git a/src/parser/cxx/binder.h b/src/parser/cxx/binder.h index abda0b20..ba44f533 100644 --- a/src/parser/cxx/binder.h +++ b/src/parser/cxx/binder.h @@ -125,6 +125,8 @@ class Binder { void bind(TypeIdAST* ast, const Decl& decl); + void bind(IdExpressionAST* ast); + [[nodiscard]] auto instantiate(SimpleTemplateIdAST* templateId) -> Symbol*; [[nodiscard]] auto resolve(NestedNameSpecifierAST* nestedNameSpecifier, diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 82d11b25..73a52e25 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -836,29 +836,10 @@ auto Parser::parse_id_expression(IdExpressionAST*& yyast, ast->unqualifiedId = unqualifiedId; ast->isTemplateIntroduced = isTemplateIntroduced; - if (unqualifiedId) { - auto name = get_name(control_, unqualifiedId); - const Name* componentName = name; - if (auto templateId = name_cast(name)) - componentName = templateId->name(); - ast->symbol = Lookup{scope()}(nestedNameSpecifier, componentName); - } + binder_.bind(ast); if (ctx == IdExpressionContext::kExpression) { - if (ast->symbol) { - if (auto conceptSymbol = symbol_cast(ast->symbol)) { - ast->type = control_->getBoolType(); - ast->valueCategory = ValueCategory::kPrValue; - } else { - ast->type = control_->remove_reference(ast->symbol->type()); - - if (auto enumerator = symbol_cast(ast->symbol)) { - ast->valueCategory = ValueCategory::kPrValue; - } else { - ast->valueCategory = ValueCategory::kLValue; - } - } - } + check(ast); } return true; diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 52421e25..99134c7c 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -239,7 +239,23 @@ void TypeChecker::Visitor::operator()(NestedExpressionAST* ast) { ast->valueCategory = ast->expression->valueCategory; } -void TypeChecker::Visitor::operator()(IdExpressionAST* ast) {} +void TypeChecker::Visitor::operator()(IdExpressionAST* ast) { + if (ast->symbol) { + if (auto conceptSymbol = symbol_cast(ast->symbol)) { + ast->type = control()->getBoolType(); + ast->valueCategory = ValueCategory::kPrValue; + } else { + ast->type = control()->remove_reference(ast->symbol->type()); + + if (ast->symbol->isEnumOrScopedEnum() || + ast->symbol->isNonTypeParameter()) { + ast->valueCategory = ValueCategory::kPrValue; + } else { + ast->valueCategory = ValueCategory::kLValue; + } + } + } +} void TypeChecker::Visitor::operator()(LambdaExpressionAST* ast) {} diff --git a/tests/unit_tests/ast/new_expression_01.cc b/tests/unit_tests/ast/new_expression_01.cc index 67468d22..2a85c5c2 100644 --- a/tests/unit_tests/ast/new_expression_01.cc +++ b/tests/unit_tests/ast/new_expression_01.cc @@ -63,7 +63,7 @@ auto make(void* where, T init) { // CHECK-NEXT: expression: new-expression // CHECK-NEXT: new-placement: new-placement // CHECK-NEXT: expression-list -// CHECK-NEXT: id-expression [lvalue void*] +// CHECK-NEXT: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: where // CHECK-NEXT: type-specifier-list @@ -73,7 +73,7 @@ auto make(void* where, T init) { // CHECK-NEXT: new-initalizer: new-braced-initializer // CHECK-NEXT: braced-init-list: braced-init-list // CHECK-NEXT: expression-list -// CHECK-NEXT: id-expression [lvalue T] +// CHECK-NEXT: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: init // CHECK-NEXT: declaration-statement @@ -90,7 +90,7 @@ auto make(void* where, T init) { // CHECK-NEXT: expression: new-expression // CHECK-NEXT: new-placement: new-placement // CHECK-NEXT: expression-list -// CHECK-NEXT: id-expression [lvalue void*] +// CHECK-NEXT: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: where // CHECK-NEXT: type-specifier-list @@ -99,6 +99,6 @@ auto make(void* where, T init) { // CHECK-NEXT: identifier: T // CHECK-NEXT: new-initalizer: new-paren-initializer // CHECK-NEXT: expression-list -// CHECK-NEXT: id-expression [lvalue T] +// CHECK-NEXT: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: init diff --git a/tests/unit_tests/ast/template_lambda_01.cc b/tests/unit_tests/ast/template_lambda_01.cc index caec7651..e3ebeadc 100644 --- a/tests/unit_tests/ast/template_lambda_01.cc +++ b/tests/unit_tests/ast/template_lambda_01.cc @@ -83,9 +83,9 @@ struct S { // CHECK-NEXT: return-statement // CHECK-NEXT: expression: binary-expression // CHECK-NEXT: op: + -// CHECK-NEXT: left-expression: id-expression [lvalue T1] +// CHECK-NEXT: left-expression: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: a -// CHECK-NEXT: right-expression: id-expression [lvalue T2] +// CHECK-NEXT: right-expression: id-expression // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: b