diff --git a/src/mlir/cxx/mlir/cxx_dialect_conversions.cc b/src/mlir/cxx/mlir/cxx_dialect_conversions.cc index 18c3a882..32377f5c 100644 --- a/src/mlir/cxx/mlir/cxx_dialect_conversions.cc +++ b/src/mlir/cxx/mlir/cxx_dialect_conversions.cc @@ -359,6 +359,7 @@ auto cxx::lowerToMLIR(mlir::ModuleOp module) -> mlir::LogicalResult { pm.addPass(cxx::createLowerToLLVMPass()); if (failed(pm.run(module))) { + module.print(llvm::errs()); return mlir::failure(); } diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 8d104db3..d475ce70 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -600,6 +600,14 @@ auto Binder::declareFunction(DeclaratorAST* declarator, const Decl& decl) auto functionSymbol = control()->newFunctionSymbol(scope(), decl.location()); + // todo: scope chain fixup should be handled elsewhere, not here. + if (auto proto = getFunctionPrototype(declarator)) { + if (proto->parameterDeclarationClause) { + proto->parameterDeclarationClause->functionParametersSymbol->scope() + ->setParent(functionSymbol->scope()); + } + } + if (is_parsing_c()) { functionSymbol->setHasCxxLinkage(false); } diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index c570fd2f..59ec7a9a 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -3534,6 +3534,7 @@ auto Parser::parse_if_statement(StatementAST*& yyast) -> bool { parse_init_statement(ast->initializer); parse_condition(ast->condition, ExprContext{}); + check_bool_condition(ast->condition); expect(TokenKind::T_RPAREN, ast->rparenLoc); @@ -3567,6 +3568,7 @@ auto Parser::parse_switch_statement(StatementAST*& yyast) -> bool { parse_init_statement(ast->initializer); parse_condition(ast->condition, ExprContext{}); + check_integral_condition(ast->condition); expect(TokenKind::T_RPAREN, ast->rparenLoc); @@ -3594,6 +3596,7 @@ auto Parser::parse_while_statement(StatementAST*& yyast) -> bool { expect(TokenKind::T_LPAREN, ast->lparenLoc); parse_condition(ast->condition, ExprContext{}); + check_bool_condition(ast->condition); expect(TokenKind::T_RPAREN, ast->rparenLoc); @@ -3623,6 +3626,7 @@ auto Parser::parse_do_statement(StatementAST*& yyast) -> bool { expect(TokenKind::T_LPAREN, ast->lparenLoc); parse_expression(ast->expression, ExprContext{}); + check_bool_condition(ast->expression); expect(TokenKind::T_RPAREN, ast->rparenLoc); @@ -3694,6 +3698,7 @@ auto Parser::parse_for_statement(StatementAST*& yyast) -> bool { if (!match(TokenKind::T_SEMICOLON, ast->semicolonLoc)) { parse_condition(ast->condition, ExprContext{}); + check_bool_condition(ast->condition); expect(TokenKind::T_SEMICOLON, ast->semicolonLoc); } @@ -4047,6 +4052,7 @@ auto Parser::parse_empty_or_attribute_declaration( auto Parser::parse_notypespec_function_definition( DeclarationAST*& yyast, List* atributes, BindingContext ctx) -> bool { + if (!is_parsing_cxx()) return false; if (!context_allows_function_definition(ctx)) return false; LookaheadParser lookahead{this}; @@ -4110,6 +4116,8 @@ auto Parser::parse_structured_binding(DeclarationAST*& yyast, List* declSpecifierList, const DeclSpecs& specs, BindingContext ctx) -> bool { + if (!is_parsing_cxx()) return false; + LookaheadParser lookahead{this}; if (!context_allows_structured_bindings(ctx)) { @@ -5507,6 +5515,11 @@ auto Parser::parse_init_declarator(InitDeclaratorAST*& yyast, } } + if (ast->initializer && !control()->is_reference(symbol->type())) { + (void)implicit_conversion(ast->initializer, + control()->remove_cv(symbol->type())); + } + return true; } @@ -9821,6 +9834,31 @@ void Parser::check(StatementAST* ast) { check.checkReturnStatement(returnStatement); } +void Parser::check_bool_condition(ExpressionAST*& ast) { + if (binder_.inTemplate()) return; + TypeChecker check{unit}; + check.setScope(scope()); + check.setReportErrors(config().checkTypes); + check.check_bool_condition(ast); +} + +void Parser::check_integral_condition(ExpressionAST*& ast) { + if (binder_.inTemplate()) return; + TypeChecker check{unit}; + check.setScope(scope()); + check.setReportErrors(config().checkTypes); + check.check_integral_condition(ast); +} + +auto Parser::implicit_conversion(ExpressionAST*& yyast, const Type* targetType) + -> bool { + if (binder_.inTemplate()) return true; + TypeChecker check{unit}; + check.setScope(scope()); + check.setReportErrors(config().checkTypes); + return check.implicit_conversion(yyast, targetType); +} + 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 bbb14c3c..6d650914 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -791,6 +791,12 @@ class Parser final { void check(ExpressionAST* ast); void check(StatementAST* ast); + void check_bool_condition(ExpressionAST*& ast); + void check_integral_condition(ExpressionAST*& ast); + + [[nodiscard]] auto implicit_conversion(ExpressionAST*& yyast, + const Type* targetType) -> bool; + // lookup [[nodiscard]] auto getFunction(Scope* scope, const Name* name, diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index dc7d9c09..4ba75023 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -1726,14 +1726,13 @@ auto TypeChecker::Visitor::implicit_conversion(ExpressionAST*& expr, if (!expr || !expr->type) return false; if (!destinationType) return false; - if (control()->is_same(expr->type, destinationType)) return true; - auto savedValueCategory = expr->valueCategory; auto savedExpr = expr; auto didConvert = ensure_prvalue(expr); adjust_cv(expr); + if (control()->is_same(expr->type, destinationType)) return true; if (integral_promotion(expr)) return true; if (floating_point_promotion(expr)) return true; if (integral_conversion(expr, destinationType)) return true; @@ -2286,4 +2285,24 @@ void TypeChecker::checkReturnStatement(ReturnStatementAST* ast) { (void)visitor.implicit_conversion(ast->expression, targetType); } +auto TypeChecker::implicit_conversion(ExpressionAST*& yyast, + const Type* targetType) -> bool { + Visitor visitor{*this}; + return visitor.implicit_conversion(yyast, targetType); +} + +void TypeChecker::check_bool_condition(ExpressionAST*& expr) { + Visitor visitor{*this}; + (void)visitor.implicit_conversion(expr, unit_->control()->getBoolType()); +} + +void TypeChecker::check_integral_condition(ExpressionAST*& expr) { + auto control = unit_->control(); + if (!control->is_integral(expr->type) && !control->is_enum(expr->type)) + return; + Visitor visitor{*this}; + (void)visitor.lvalue_to_rvalue_conversion(expr); + visitor.adjust_cv(expr); +} + } // namespace cxx diff --git a/src/parser/cxx/type_checker.h b/src/parser/cxx/type_checker.h index e2ae0188..2d844453 100644 --- a/src/parser/cxx/type_checker.h +++ b/src/parser/cxx/type_checker.h @@ -45,8 +45,15 @@ class TypeChecker { void check(ExpressionAST* ast); + // todo: remove void checkReturnStatement(ReturnStatementAST* ast); + void check_bool_condition(ExpressionAST*& ast); + void check_integral_condition(ExpressionAST*& ast); + + [[nodiscard]] auto implicit_conversion(ExpressionAST*& expr, + const Type* targetType) -> bool; + private: struct Visitor; diff --git a/tests/unit_tests/ast/asm_declaration_01.cc b/tests/unit_tests/ast/asm_declaration_01.cc index 8cd67169..7ba83a84 100644 --- a/tests/unit_tests/ast/asm_declaration_01.cc +++ b/tests/unit_tests/ast/asm_declaration_01.cc @@ -90,9 +90,11 @@ end:; // CHECK-NEXT: core-declarator: id-declarator // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: p -// CHECK-NEXT: initializer: equal-initializer [prvalue decltype(nullptr)] -// CHECK-NEXT: expression: nullptr-literal-expression [prvalue decltype(nullptr)] -// CHECK-NEXT: literal: nullptr +// CHECK-NEXT: initializer: implicit-cast-expression [prvalue char*] +// CHECK-NEXT: cast-kind: pointer-conversion +// CHECK-NEXT: expression: equal-initializer [prvalue decltype(nullptr)] +// CHECK-NEXT: expression: nullptr-literal-expression [prvalue decltype(nullptr)] +// CHECK-NEXT: literal: nullptr // CHECK-NEXT: declaration-statement // CHECK-NEXT: declaration: asm-declaration // CHECK-NEXT: literal: "nop" diff --git a/tests/unit_tests/ast/deduce_this_01.cc b/tests/unit_tests/ast/deduce_this_01.cc index ce44028c..69dbc0fc 100644 --- a/tests/unit_tests/ast/deduce_this_01.cc +++ b/tests/unit_tests/ast/deduce_this_01.cc @@ -51,6 +51,8 @@ struct object { // CHECK-NEXT: statement: compound-statement // CHECK-NEXT: statement-list // CHECK-NEXT: return-statement -// CHECK-NEXT: expression: id-expression [lvalue auto] -// CHECK-NEXT: unqualified-id: name-id -// CHECK-NEXT: identifier: self +// CHECK-NEXT: expression: implicit-cast-expression [prvalue auto] +// CHECK-NEXT: cast-kind: lvalue-to-rvalue-conversion +// CHECK-NEXT: expression: id-expression [lvalue auto] +// CHECK-NEXT: unqualified-id: name-id +// CHECK-NEXT: identifier: self diff --git a/tests/unit_tests/ast/function_to_pointer_conv_01.cc b/tests/unit_tests/ast/function_to_pointer_conv_01.cc index d4737171..cc7fb691 100644 --- a/tests/unit_tests/ast/function_to_pointer_conv_01.cc +++ b/tests/unit_tests/ast/function_to_pointer_conv_01.cc @@ -91,9 +91,7 @@ auto main() -> int { // CHECK-NEXT: unqualified-id: name-id // CHECK-NEXT: identifier: p // CHECK-NEXT: right-expression: implicit-cast-expression [prvalue void (*)(int, int)] -// CHECK-NEXT: cast-kind: function-pointer-conversion -// CHECK-NEXT: expression: implicit-cast-expression [prvalue void (*)(int, int)] -// CHECK-NEXT: cast-kind: function-to-pointer-conversion -// CHECK-NEXT: expression: id-expression [lvalue void (int, int)] -// CHECK-NEXT: unqualified-id: name-id -// CHECK-NEXT: identifier: f +// CHECK-NEXT: cast-kind: function-to-pointer-conversion +// CHECK-NEXT: expression: id-expression [lvalue void (int, int)] +// CHECK-NEXT: unqualified-id: name-id +// CHECK-NEXT: identifier: f