diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 2fea6369..e6e19eeb 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -1417,17 +1417,25 @@ auto Parser::parse_id_expression(IdExpressionAST*& yyast, if (unqualifiedId) { auto name = convertName(unqualifiedId); - ast->symbol = Lookup{scope_}(nestedNameSpecifier, name); + const Name* componentName = name; + if (auto templateId = name_cast(name)) + componentName = templateId->name(); + ast->symbol = Lookup{scope_}(nestedNameSpecifier, componentName); } if (ctx == IdExpressionContext::kExpression) { if (ast->symbol) { - ast->type = control_->remove_reference(ast->symbol->type()); - - if (auto enumerator = symbol_cast(ast->symbol)) { + if (auto conceptSymbol = symbol_cast(ast->symbol)) { + ast->type = control_->getBoolType(); ast->valueCategory = ValueCategory::kPrValue; } else { - ast->valueCategory = ValueCategory::kLValue; + ast->type = control_->remove_reference(ast->symbol->type()); + + if (auto enumerator = symbol_cast(ast->symbol)) { + ast->valueCategory = ValueCategory::kPrValue; + } else { + ast->valueCategory = ValueCategory::kLValue; + } } } } @@ -5650,6 +5658,11 @@ auto Parser::parse_named_type_specifier(SpecifierAST*& yyast, DeclSpecs& specs) } if (auto templateId = ast_cast(unqualifiedId)) { + if (auto conceptSymbol = + symbol_cast(templateId->primaryTemplateSymbol)) { + if (!lookat(TokenKind::T_AUTO)) return false; + } + if (auto symbol = instantiate(templateId)) { specs.type = symbol->type(); } @@ -10733,6 +10746,7 @@ void Parser::completeFunctionDefinition(FunctionDefinitionAST* ast) { } void Parser::check(ExpressionAST* ast) { + if (inTemplate_) return; TypeChecker check{unit}; check.setScope(scope_); check.setReportErrors(config_.checkTypes); diff --git a/src/parser/cxx/type_checker.cc b/src/parser/cxx/type_checker.cc index 0e9624d5..6d587bfb 100644 --- a/src/parser/cxx/type_checker.cc +++ b/src/parser/cxx/type_checker.cc @@ -448,6 +448,9 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { } if (!is_glvalue(ast->expression)) { + error(ast->opLoc, + std::format("cannot take the address of an rvalue of type '{}'", + to_string(ast->expression->type))); break; } @@ -542,6 +545,8 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { case TokenKind::T_PLUS_PLUS: { if (!is_glvalue(ast->expression)) { + error(ast->opLoc, std::format("cannot increment an rvalue of type '{}'", + to_string(ast->expression->type))); break; } @@ -554,18 +559,23 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { } if (auto ptrTy = type_cast(ty)) { - if (ptrTy && !control()->is_void(ptrTy->elementType())) { + if (!control()->is_void(ptrTy->elementType())) { ast->type = ptrTy; ast->valueCategory = ValueCategory::kLValue; + break; } } + error(ast->opLoc, std::format("cannot increment a value of type '{}'", + to_string(ast->expression->type))); break; } case TokenKind::T_MINUS_MINUS: { if (!is_glvalue(ast->expression)) { - break; + error(ast->opLoc, std::format("cannot decrement an rvalue of type '{}'", + to_string(ast->expression->type))); + break; } auto ty = ast->expression->type; @@ -580,9 +590,12 @@ void TypeChecker::Visitor::operator()(UnaryExpressionAST* ast) { if (ptrTy && !control()->is_void(ptrTy->elementType())) { ast->type = ptrTy; ast->valueCategory = ValueCategory::kLValue; + break; } } + error(ast->opLoc, std::format("cannot decrement a value of type '{}'", + to_string(ast->expression->type))); break; } diff --git a/tests/unit_tests/ast/template_lambda_01.cc b/tests/unit_tests/ast/template_lambda_01.cc index 85947bab..caec7651 100644 --- a/tests/unit_tests/ast/template_lambda_01.cc +++ b/tests/unit_tests/ast/template_lambda_01.cc @@ -83,13 +83,9 @@ struct S { // CHECK-NEXT: return-statement // CHECK-NEXT: expression: binary-expression // CHECK-NEXT: op: + -// CHECK-NEXT: left-expression: implicit-cast-expression [prvalue T1] -// CHECK-NEXT: cast-kind: lvalue-to-rvalue-conversion -// CHECK-NEXT: expression: id-expression [lvalue T1] -// CHECK-NEXT: unqualified-id: name-id -// CHECK-NEXT: identifier: a -// CHECK-NEXT: right-expression: implicit-cast-expression [prvalue T2] -// CHECK-NEXT: cast-kind: lvalue-to-rvalue-conversion -// CHECK-NEXT: expression: id-expression [lvalue T2] -// CHECK-NEXT: unqualified-id: name-id -// CHECK-NEXT: identifier: b +// CHECK-NEXT: left-expression: id-expression [lvalue T1] +// CHECK-NEXT: unqualified-id: name-id +// CHECK-NEXT: identifier: a +// CHECK-NEXT: right-expression: id-expression [lvalue T2] +// CHECK-NEXT: unqualified-id: name-id +// CHECK-NEXT: identifier: b diff --git a/tests/unit_tests/sema/incr_01.cc b/tests/unit_tests/sema/incr_01.cc index 59d6f201..41e5f784 100644 --- a/tests/unit_tests/sema/incr_01.cc +++ b/tests/unit_tests/sema/incr_01.cc @@ -37,5 +37,18 @@ auto main() -> int { static_assert(__is_lvalue_reference(decltype(++pr))); static_assert(__is_lvalue_reference(decltype(--pr))); + // clang-format off + + int a[10]; + + ++(+a); // expected-error {{cannot increment an rvalue of type 'int*'}} + + ++a; // expected-error {{cannot increment a value of type 'int [10]'}} + + --(+a); // expected-error {{cannot decrement an rvalue of type 'int*'}} + + --a; // expected-error {{cannot decrement a value of type 'int [10]'}} + + // clang-format on return 0; -} \ No newline at end of file +}