Skip to content

Improve checks of builtin subscript expressions #529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/parser/cxx/control.cc
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,10 @@ auto Control::remove_extent(const Type* type) -> const Type* {
return d->traits.remove_extent(type);
}

auto Control::get_element_type(const Type* type) -> const Type* {
return d->traits.get_element_type(type);
}

auto Control::remove_cv(const Type* type) -> const Type* {
return d->traits.remove_cv(type);
}
Expand Down
1 change: 1 addition & 0 deletions src/parser/cxx/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class Control {

// arrays
[[nodiscard]] auto remove_extent(const Type* type) -> const Type*;
[[nodiscard]] auto get_element_type(const Type* type) -> const Type*;

// cv qualifiers
[[nodiscard]] auto remove_cv(const Type* type) -> const Type*;
Expand Down
59 changes: 45 additions & 14 deletions src/parser/cxx/type_checker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,24 +276,55 @@ void TypeChecker::Visitor::operator()(VaArgExpressionAST* ast) {
}

void TypeChecker::Visitor::operator()(SubscriptExpressionAST* ast) {
if (auto pointerType = type_cast<PointerType>(ast->baseExpression->type)) {
ast->type = pointerType->elementType();
ast->valueCategory = ast->baseExpression->valueCategory;
if (!ast->baseExpression || control()->is_class(ast->baseExpression->type))
return;
}

if (auto arrayType = type_cast<BoundedArrayType>(ast->baseExpression->type)) {
ast->type = arrayType->elementType();
ast->valueCategory = ast->baseExpression->valueCategory;
if (!ast->indexExpression || control()->is_class(ast->indexExpression->type))
return;
}

if (auto arrayType =
type_cast<UnboundedArrayType>(ast->baseExpression->type)) {
ast->type = arrayType->elementType();
ast->valueCategory = ast->baseExpression->valueCategory;
return;
}
// builtin subscript operator

auto array_subscript = [this](ExpressionAST* ast, ExpressionAST*& base,
ExpressionAST*& index) {
if (!control()->is_array(base->type)) return false;
if (!control()->is_arithmetic_or_unscoped_enum(index->type)) return false;

(void)temporary_materialization_conversion(base);
(void)ensure_prvalue(index);
adjust_cv(index);
(void)integral_promotion(base);

ast->type = control()->get_element_type(base->type);
ast->valueCategory = base->valueCategory;
return true;
};

auto pointer_subscript = [this](ExpressionAST* ast, ExpressionAST*& base,
ExpressionAST*& index) {
if (!control()->is_pointer(base->type)) return false;
if (!control()->is_arithmetic_or_unscoped_enum(index->type)) return false;

(void)ensure_prvalue(base);
adjust_cv(base);

(void)ensure_prvalue(index);
adjust_cv(index);
(void)integral_promotion(index);

ast->type = control()->get_element_type(base->type);
ast->valueCategory = ValueCategory::kLValue;
return true;
};

if (array_subscript(ast, ast->baseExpression, ast->indexExpression)) return;
if (array_subscript(ast, ast->indexExpression, ast->baseExpression)) return;
if (pointer_subscript(ast, ast->baseExpression, ast->indexExpression)) return;
if (pointer_subscript(ast, ast->indexExpression, ast->baseExpression)) return;

error(ast->firstSourceLocation(),
std::format("invalid subscript of type '{}' with index type '{}'",
to_string(ast->baseExpression->type),
to_string(ast->indexExpression->type)));
}

void TypeChecker::Visitor::operator()(CallExpressionAST* ast) {
Expand Down
40 changes: 40 additions & 0 deletions src/parser/cxx/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ class TypeTraits {
return visit(remove_extent_, type);
}

auto get_element_type(const Type* type) const -> const Type* {
if (!type) return type;
return visit(get_element_type_, type);
}

// cv qualifiers

auto remove_cv(const Type* type) const -> const Type* {
Expand Down Expand Up @@ -741,6 +746,41 @@ class TypeTraits {
auto operator()(auto type) const -> const Type* { return type; }
} remove_extent_;

struct {
TypeTraits& traits;

auto operator()(const BoundedArrayType* type) const -> const Type* {
return type->elementType();
}

auto operator()(const UnboundedArrayType* type) const -> const Type* {
return type->elementType();
}

auto operator()(const UnresolvedBoundedArrayType* type) const
-> const Type* {
return type->elementType();
}

auto operator()(const PointerType* type) const -> const Type* {
return type->elementType();
}

auto operator()(const LvalueReferenceType* type) const -> const Type* {
return type->elementType();
}

auto operator()(const RvalueReferenceType* type) const -> const Type* {
return type->elementType();
}

auto operator()(const QualType* type) const -> const Type* {
return visit(*this, type->elementType());
}

auto operator()(auto type) const -> const Type* { return nullptr; }
} get_element_type_{*this};

struct {
auto operator()(const QualType* type) const -> const Type* {
return type->elementType();
Expand Down