[gccrs COMMIT] gccrs: Support silly legacy rustc const generics for stdarch
gerris.rs@gmail.com
gerris.rs@gmail.com
Mon Sep 14 19:44:14 GMT 2026
From: Philip Herron <herron.philip@googlemail.com>
This is a daft feature so instead of using the turbo fish to supply the
const generics like a sensible language rustc uses this attribute to support
that the order/index of call arguments are the const generic arguments in
order for the param list. So we walk them then grab the associated subst
param mapping and unify it.
Fixes Rust-GCC/gccrs#3868
gcc/rust/ChangeLog:
* backend/rust-compile-expr.cc (CompileExpr::visit): check for const args
* hir/tree/rust-hir-expr.cc (CallExpr::CallExpr): add new helper to parse attribute
(CallExpr::operator=): new member
* hir/tree/rust-hir-expr.h (class CallExpr): new helper
* hir/tree/rust-hir-item.cc (Function::get_legacy_const_generic_indexes): likewise
* hir/tree/rust-hir-item.h: likewise
* typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): handle const args
* typecheck/rust-tyty-subst.cc (SubstitutionRef::resolve_const_argument): refactor out
* typecheck/rust-tyty-subst.h: likewise
gcc/testsuite/ChangeLog:
* rust/compile/issues/issue-3868.rs: New test.
Signed-off-by: Philip Herron <herron.philip@googlemail.com>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github: https://github.com/Rust-GCC/gccrs/commit/36860cbddb7e28cb0349911724c906acdb5689ea
The commit has been mentioned in the following issue(s):
- Rust-GCC/gccrs#3868: https://github.com/Rust-GCC/gccrs/issues/3868
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4892
gcc/rust/backend/rust-compile-expr.cc | 15 +-
gcc/rust/hir/tree/rust-hir-expr.cc | 3 +-
gcc/rust/hir/tree/rust-hir-expr.h | 17 +++
gcc/rust/hir/tree/rust-hir-item.cc | 72 +++++++++
gcc/rust/hir/tree/rust-hir-item.h | 2 +
gcc/rust/typecheck/rust-tyty-call.cc | 101 ++++++++++--
gcc/rust/typecheck/rust-tyty-subst.cc | 144 +++++++++---------
gcc/rust/typecheck/rust-tyty-subst.h | 3 +
.../rust/compile/issues/issue-3868.rs | 15 ++
9 files changed, 282 insertions(+), 90 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/issues/issue-3868.rs
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 815f53cb0..e2e564493 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -1760,12 +1760,18 @@ CompileExpr::visit (HIR::CallExpr &expr)
}
std::vector<tree> args;
- for (size_t i = 0; i < expr.get_arguments ().size (); i++)
+ for (size_t source_argument_index = 0;
+ source_argument_index < expr.get_arguments ().size ();
+ source_argument_index++)
{
- auto &argument = expr.get_arguments ().at (i);
+ if (expr.is_const_argument (source_argument_index))
+ continue;
+
+ auto &argument = expr.get_arguments ().at (source_argument_index);
+ size_t runtime_argument_index = args.size ();
auto rvalue = CompileExpr::Compile (*argument, ctx);
- if (is_variadic && i >= required_num_args)
+ if (is_variadic && runtime_argument_index >= required_num_args)
{
args.push_back (rvalue);
continue;
@@ -1775,7 +1781,8 @@ CompileExpr::visit (HIR::CallExpr &expr)
// necessary
bool ok;
TyTy::BaseType *expected = nullptr;
- ok = get_parameter_tyty_at_index (tyty, i, &expected);
+ ok
+ = get_parameter_tyty_at_index (tyty, runtime_argument_index, &expected);
rust_assert (ok);
TyTy::BaseType *actual = nullptr;
diff --git a/gcc/rust/hir/tree/rust-hir-expr.cc b/gcc/rust/hir/tree/rust-hir-expr.cc
index c4ccad149..080ac4da6 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.cc
+++ b/gcc/rust/hir/tree/rust-hir-expr.cc
@@ -581,7 +581,7 @@ CallExpr::CallExpr (Analysis::NodeMapping mappings,
CallExpr::CallExpr (CallExpr const &other)
: ExprWithoutBlock (other), function (other.function->clone_expr ()),
- locus (other.locus)
+ const_argument_indexes (other.const_argument_indexes), locus (other.locus)
/*, params(other.params),*/ {
params.reserve (other.params.size ());
for (const auto &e : other.params)
@@ -593,6 +593,7 @@ CallExpr::operator= (CallExpr const &other)
{
ExprWithoutBlock::operator= (other);
function = other.function->clone_expr ();
+ const_argument_indexes = other.const_argument_indexes;
locus = other.locus;
params.reserve (other.params.size ());
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 02c6f2538..14e29e085 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -1413,6 +1413,7 @@ class CallExpr : public ExprWithoutBlock
{
std::unique_ptr<Expr> function;
std::vector<std::unique_ptr<Expr>> params;
+ std::vector<size_t> const_argument_indexes;
location_t locus;
public:
@@ -1440,6 +1441,22 @@ public:
void accept_vis (HIRFullVisitor &vis) override;
void accept_vis (HIRExpressionVisitor &vis) override;
+ void set_const_argument_indexes (const std::vector<size_t> &indexes)
+ {
+ const_argument_indexes = indexes;
+ }
+
+ bool is_const_argument (size_t index) const
+ {
+ for (auto const_index : const_argument_indexes)
+ {
+ if (index == const_index)
+ return true;
+ }
+
+ return false;
+ }
+
bool has_fnexpr () const { return function != nullptr; }
Expr &get_fnexpr () { return *function; }
diff --git a/gcc/rust/hir/tree/rust-hir-item.cc b/gcc/rust/hir/tree/rust-hir-item.cc
index d5c9ad154..8273ab516 100644
--- a/gcc/rust/hir/tree/rust-hir-item.cc
+++ b/gcc/rust/hir/tree/rust-hir-item.cc
@@ -18,6 +18,8 @@
#include "rust-hir-item.h"
#include "optional.h"
+#include "rust-attribute-values.h"
+#include "rust-attributes.h"
namespace Rust {
namespace HIR {
@@ -261,6 +263,76 @@ Module::operator= (Module const &other)
return *this;
}
+tl::optional<std::vector<size_t>>
+Function::get_legacy_const_generic_indexes () const
+{
+ std::vector<size_t> legacy_const_generic_indexes;
+ const auto &attrs = get_outer_attrs ();
+ for (const auto &attr : attrs)
+ {
+ const auto possibly_builtin = Analysis::lookup_builtin (attr);
+ if (!possibly_builtin.has_value ())
+ continue;
+
+ const auto &mapping = possibly_builtin.value ();
+ if (mapping.name != Values::Attributes::RUSTC_ARGS_REQUIRED_CONST)
+ continue;
+
+ if (!attr.has_attr_input ())
+ {
+ rust_error_at (attr.get_locus (), "malformed %qs attribute",
+ mapping.name.c_str ());
+ return tl::nullopt;
+ }
+
+ auto parsed_attr = attr;
+ parsed_attr.parse_attr_to_meta_item ();
+ if (!parsed_attr.is_parsed_to_meta_item ())
+ {
+ rust_error_at (attr.get_locus (), "malformed %qs attribute",
+ mapping.name.c_str ());
+ return tl::nullopt;
+ }
+
+ const auto &container
+ = static_cast<const AST::AttrInputMetaItemContainer &> (
+ parsed_attr.get_attr_input ());
+ const auto &items = container.get_items ();
+ for (const auto &item : items)
+ {
+ if (item->get_kind () != AST::MetaItemInner::Kind::LitExpr)
+ {
+ rust_error_at (item->get_locus (),
+ "expected an integer argument index");
+ return tl::nullopt;
+ }
+ const auto &literal
+ = static_cast<AST::MetaItemLitExpr &> (*item).get_literal ();
+ if (literal.get_lit_type () != AST::Literal::INT)
+ {
+ rust_error_at (item->get_locus (),
+ "expected an integer argument index");
+ return tl::nullopt;
+ }
+
+ mpz_t value;
+ if (mpz_init_set_str (value, literal.as_string ().c_str (), 10) != 0)
+ {
+ mpz_clear (value);
+ rust_error_at (item->get_locus (), "failed load argument index");
+ return tl::nullopt;
+ }
+
+ size_t index = 0;
+ mpz_export (&index, nullptr, 1, sizeof (index), 0, 0, value);
+ mpz_clear (value);
+ legacy_const_generic_indexes.push_back (index);
+ }
+ }
+
+ return legacy_const_generic_indexes;
+}
+
Function::Function (Analysis::NodeMapping mappings, Identifier function_name,
FunctionQualifiers qualifiers,
std::vector<std::unique_ptr<GenericParam>> generic_params,
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 9a572bf92..a07334ee9 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -966,6 +966,8 @@ class Function : public VisItem, public ImplItem
public:
std::string to_string () const override;
+ tl::optional<std::vector<size_t>> get_legacy_const_generic_indexes () const;
+
// Returns whether function has generic parameters.
bool has_generics () const { return !generic_params.empty (); }
diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc
index f87b160f8..3dd72a5fd 100644
--- a/gcc/rust/typecheck/rust-tyty-call.cc
+++ b/gcc/rust/typecheck/rust-tyty-call.cc
@@ -17,10 +17,13 @@
// <http://www.gnu.org/licenses/>.
#include "rust-tyty-call.h"
+#include "optional.h"
+#include "rust-hir-item.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check.h"
#include "rust-type-util.h"
#include "rust-hir-trait-reference.h"
+#include "rust-tyty.h"
namespace Rust {
namespace TyTy {
@@ -153,26 +156,91 @@ TypeCheckCallExpr::visit (ADTType &type)
void
TypeCheckCallExpr::visit (FnType &type)
{
- if (call.num_params () != type.num_params ())
+ std::vector<size_t> indexes;
+ const auto lookup = mappings.lookup_defid (type.get_id ());
+ if (lookup.has_value ())
+ {
+ const auto *item = lookup.value ();
+ rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Function);
+
+ const auto &fn = *static_cast<const HIR::Function *> (item);
+ auto legacy_const_generic_indexes
+ = fn.get_legacy_const_generic_indexes ();
+
+ bool malformed_const_generic_indexes
+ = !legacy_const_generic_indexes.has_value ();
+ if (malformed_const_generic_indexes)
+ return;
+
+ indexes = legacy_const_generic_indexes.value ();
+ }
+
+ size_t expected_args = type.num_params () + indexes.size ();
+ if (call.num_params () < expected_args
+ || (!type.is_variadic () && call.num_params () != expected_args))
+ {
+ emit_unexpected_argument_error (call.get_locus (), call.num_params (),
+ expected_args);
+ return;
+ }
+
+ if (!indexes.empty ())
{
- if (type.is_variadic ())
+ std::set<size_t> seen;
+ for (size_t i = 0; i < indexes.size (); i++)
{
- if (call.num_params () < type.num_params ())
+ size_t index = indexes[i];
+ seen.insert (index);
+
+ bool duplicate_index = seen.size () != i + 1;
+ if (index >= call.num_params () || duplicate_index)
{
- emit_unexpected_argument_error (
- call.get_locus (), (unsigned long) call.num_params (),
- (unsigned long) type.num_params ());
+ rust_error_at (call.get_locus (), "invalid const argument index");
return;
}
}
- else
+
+ std::vector<SubstitutionParamMapping *> const_params;
+ for (auto &sub : type.get_substs ())
+ {
+ if (sub.get_generic_param ().get_kind ()
+ == HIR::GenericParam::GenericKind::CONST)
+ const_params.push_back (&sub);
+ }
+
+ if (const_params.size () != indexes.size ())
{
- emit_unexpected_argument_error (call.get_locus (),
- (unsigned long) call.num_params (),
- (unsigned long) type.num_params ());
+ rust_error_at (
+ call.get_locus (),
+ "const argument count does not match const parameters");
+
return;
}
+
+ auto &subst_mappings = type.get_substitution_arguments ();
+ for (size_t i = 0; i < indexes.size (); i++)
+ {
+ size_t cidx = indexes[i];
+ auto &argument = *call.get_arguments ().at (cidx);
+
+ auto *param = const_params[i]->get_param_ty ();
+ auto const_ty = param->as_const_type ()->get_specified_type ();
+ auto *value
+ = SubstitutionRef::resolve_const_argument (argument, const_ty);
+
+ if (value->is<ErrorType> ())
+ return;
+
+ SubstitutionArg existing = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (param, &existing);
+ rust_assert (ok);
+
+ Resolver::unify_site (argument.get_mappings ().get_hirid (),
+ TyWithLocation (existing.get_tyty ()),
+ TyWithLocation (value), argument.get_locus ());
+ }
}
+ call.set_const_argument_indexes (indexes);
// if the surrounding context has pushed an expected type, try unifying it
// with the fn's return type before checking arguments. This lets the callee
@@ -193,9 +261,13 @@ TypeCheckCallExpr::visit (FnType &type)
true /*implicit_infer_vars*/, true /*cleanup*/);
}
- size_t i = 0;
- for (auto &argument : call.get_arguments ())
+ size_t i;
+ for (i = 0; i < call.get_arguments ().size (); i++)
{
+ auto &argument = call.get_arguments ().at (i);
+ if (call.is_const_argument (i))
+ continue;
+
location_t arg_locus = argument->get_locus ();
TyTy::BaseType *param_ty = nullptr;
@@ -204,6 +276,7 @@ TypeCheckCallExpr::visit (FnType &type)
if (param_ty != nullptr)
ctx->push_expected_type (param_ty);
+
auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
if (param_ty != nullptr)
ctx->pop_expected_type ();
@@ -309,11 +382,9 @@ TypeCheckCallExpr::visit (FnType &type)
break;
}
}
-
- i++;
}
- if (i < call.num_params ())
+ if (i + indexes.size () < call.num_params ())
{
emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
(unsigned long) call.num_params ());
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc
index 73e4479fe..d589b2547 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -823,11 +823,6 @@ SubstitutionRef::get_mappings_from_generic_args (
for (auto &arg : args.get_const_args ())
{
auto &expr = *arg.get_expression ().get ();
- BaseType *expr_type = Resolver::TypeCheckExpr::Resolve (expr);
- if (expr_type == nullptr || expr_type->is<ErrorType> ())
- return SubstitutionArgumentMappings::error ();
-
- // validate this param is really a const generic
const auto ¶m_mapping = substitutions.at (offs);
const auto &generic = param_mapping.get_generic_param ();
if (generic.get_kind () != HIR::GenericParam::GenericKind::CONST)
@@ -838,73 +833,13 @@ SubstitutionRef::get_mappings_from_generic_args (
return SubstitutionArgumentMappings::error ();
}
- // get the const generic specified type
- const auto base_generic = param_mapping.get_param_ty ();
- rust_assert (base_generic->get_kind () == TyTy::TypeKind::CONST);
- const auto const_param
- = static_cast<const TyTy::ConstParamType *> (base_generic);
- auto specified_type = const_param->get_specified_type ();
-
- // validate this const generic is of the correct type
- TyTy::BaseType *coereced_type = nullptr;
- if (expr_type->get_kind () == TyTy::TypeKind::CONST)
- {
- auto const_expr_type = expr_type->as_const_type ();
- auto const_value_type = const_expr_type->get_specified_type ();
- coereced_type
- = Resolver::coercion_site (expr.get_mappings ().get_hirid (),
- TyTy::TyWithLocation (specified_type),
- TyTy::TyWithLocation (const_value_type,
- expr.get_locus ()),
- arg.get_locus ());
- }
- else
- {
- coereced_type
- = Resolver::coercion_site (expr.get_mappings ().get_hirid (),
- TyTy::TyWithLocation (specified_type),
- TyTy::TyWithLocation (expr_type,
- expr.get_locus ()),
- arg.get_locus ());
- }
-
- if (coereced_type == nullptr || coereced_type->is<ErrorType> ())
+ auto specified_type = param_mapping.get_param_ty ()
+ ->as_const_type ()
+ ->get_specified_type ();
+ auto const_value_ty = resolve_const_argument (expr, specified_type);
+ if (const_value_ty->is<ErrorType> ())
return SubstitutionArgumentMappings::error ();
- TyTy::BaseType *const_value_ty = nullptr;
- if (expr_type->get_kind () == TyTy::TypeKind::CONST)
- const_value_ty = expr_type;
- else
- {
- // const fold it if available
- auto ctx = Compile::Context::get ();
- tree folded
- = Compile::HIRCompileBase::query_compile_const_expr (ctx,
- coereced_type,
- expr);
-
- if (folded == error_mark_node)
- {
- rich_location r (line_table, arg.get_locus ());
- r.add_range (expr.get_locus ());
- rust_error_at (r, "failed to resolve const expression");
- return SubstitutionArgumentMappings::error ();
- }
-
- // Use a fresh HirId to avoid conflicts with the expr's type
- auto &global_mappings = Analysis::Mappings::get ();
- HirId const_value_id = global_mappings.get_next_hir_id ();
- const_value_ty
- = new TyTy::ConstValueType (folded, coereced_type, const_value_id,
- const_value_id, {});
-
- // Insert the ConstValueType into the context so it can be looked up
- auto context = Resolver::TypeCheckContext::get ();
- context->insert_type (
- Analysis::NodeMapping (0, 0, const_value_ty->get_ref (), 0),
- const_value_ty);
- }
-
mappings.emplace_back (¶m_mapping, const_value_ty);
offs++;
}
@@ -950,6 +885,75 @@ SubstitutionRef::get_mappings_from_generic_args (
constraint_arguments};
}
+BaseType *
+SubstitutionRef::resolve_const_argument (HIR::Expr &expr,
+ BaseType *specified_type)
+{
+ BaseType *expr_type = Resolver::TypeCheckExpr::Resolve (expr);
+ if (expr_type == nullptr || expr_type->is<ErrorType> ())
+ return new ErrorType (expr.get_mappings ().get_hirid ());
+
+ TyTy::BaseType *coerced_type = nullptr;
+ if (expr_type->get_kind () == TyTy::TypeKind::CONST)
+ {
+ auto const_expr_type = expr_type->as_const_type ();
+ auto const_value_type = const_expr_type->get_specified_type ();
+ coerced_type
+ = Resolver::coercion_site (expr.get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (specified_type),
+ TyTy::TyWithLocation (const_value_type,
+ expr.get_locus ()),
+ expr.get_locus ());
+ }
+ else
+ {
+ coerced_type
+ = Resolver::coercion_site (expr.get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (specified_type),
+ TyTy::TyWithLocation (expr_type,
+ expr.get_locus ()),
+ expr.get_locus ());
+ }
+
+ if (coerced_type == nullptr || coerced_type->is<ErrorType> ())
+ return new ErrorType (expr.get_mappings ().get_hirid ());
+
+ TyTy::BaseType *const_value_ty = nullptr;
+ if (expr_type->get_kind () == TyTy::TypeKind::CONST)
+ const_value_ty = expr_type;
+ else
+ {
+ auto ctx = Compile::Context::get ();
+ tree folded
+ = Compile::HIRCompileBase::query_compile_const_expr (ctx, coerced_type,
+ expr);
+
+ if (folded == error_mark_node)
+ {
+ rich_location r (line_table, expr.get_locus ());
+ r.add_range (expr.get_locus ());
+ rust_error_at (r, "failed to resolve const expression");
+ return new ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ // Use a fresh HirId to avoid conflicts with the expr's type
+ auto &global_mappings = Analysis::Mappings::get ();
+ HirId const_value_id = global_mappings.get_next_hir_id ();
+ const_value_ty
+ = new TyTy::ConstValueType (folded, coerced_type, const_value_id,
+ const_value_id, {});
+
+ // Insert the ConstValueType into the context so it can be looked up
+ auto context = Resolver::TypeCheckContext::get ();
+ context->insert_type (Analysis::NodeMapping (0, 0,
+ const_value_ty->get_ref (),
+ 0),
+ const_value_ty);
+ }
+
+ return const_value_ty;
+}
+
BaseType *
SubstitutionRef::infer_substitions (location_t locus)
{
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h
index 623593b9a..bfe462b11 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -315,6 +315,9 @@ public:
get_mappings_from_generic_args (HIR::GenericArgs &args,
const std::vector<Region> ®ions);
+ static BaseType *resolve_const_argument (HIR::Expr &expr,
+ BaseType *specified_type);
+
// Recursive substitutions
// Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
//
diff --git a/gcc/testsuite/rust/compile/issues/issue-3868.rs b/gcc/testsuite/rust/compile/issues/issue-3868.rs
new file mode 100644
index 000000000..7f8a9ce9c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-3868.rs
@@ -0,0 +1,15 @@
+#![feature(no_core, intrinsics, lang_items, staged_api)]
+#![feature(rustc_attrs)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[rustc_args_required_const(1)]
+fn foo<const N: usize>(x: i32) -> i32 {
+ x + N as i32
+}
+
+fn main() {
+ let _a = foo(10, 3);
+}
base-commit: d1ca5590e49cc489740410365392e6bc6027cf3b
--
2.55.0
More information about the Gcc-rust
mailing list