Skip to content

Commit

Permalink
gccrs: add discriminant value intrinsic
Browse files Browse the repository at this point in the history
This is pretty nasty piece of rust in my opinion the return type of this
intrinsic results into a lang item associated type:

  <T as DiscriminantKind>::Discriminant

This is a special case which needs to support mapping onto the repr type
of the associated ADT that is passed in, but defaults to iszie otherwise.

This patch assumes we only come accross this case in a HIR::CALL_EXPR, so
and makes assumutions that its always of this function signiture. I will
do some checking in libcore to verify that assumption. More work is needed
to parse the repr type on enums but the code is there to support this when
its in to change the types etc.

Addresses #3348

gcc/rust/ChangeLog:

	* backend/rust-compile-intrinsic.cc (discriminant_value_handler): new handler
	* typecheck/rust-hir-trait-resolve.cc (TraitItemReference::resolve_item): track the defid
	* typecheck/rust-hir-type-check-base.cc (TypeCheckBase::parse_repr_options): default isize
	* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): special case CallExpr
	* typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): parse repr options enum
	* typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): remove bad diagnostic
	* typecheck/rust-tyty.cc (PlaceholderType::PlaceholderType): track defid
	(PlaceholderType::clone): likewise
	(PlaceholderType::get_def_id): likeiwse
	* typecheck/rust-tyty.h: placeholder track defid
	* util/rust-lang-item.cc: add new lang items
	* util/rust-lang-item.h: likewise

gcc/testsuite/ChangeLog:

	* rust/execute/torture/enum_intrinsics1.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
  • Loading branch information
philberty committed Feb 11, 2025
1 parent af234dd commit 3fd738c
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 62 deletions.
149 changes: 105 additions & 44 deletions gcc/rust/backend/rust-compile-intrinsic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "rust-compile-intrinsic.h"
#include "rust-compile-context.h"
#include "rust-compile-type.h"
#include "rust-compile-expr.h"
#include "rust-compile-fnparam.h"
#include "rust-builtins.h"
#include "rust-diagnostics.h"
Expand All @@ -27,14 +26,10 @@
#include "rust-tree.h"
#include "tree-core.h"
#include "rust-gcc.h"
#include "print-tree.h"
#include "fold-const.h"
#include "langhooks.h"
#include "rust-gcc.h"
#include "rust-constexpr.h"

#include "print-tree.h"

// declaration taken from "stringpool.h"
// the get_identifier macro causes compilation issues
extern tree
Expand Down Expand Up @@ -93,6 +88,8 @@ static tree
move_val_init_handler (Context *ctx, TyTy::FnType *fntype);
static tree
assume_handler (Context *ctx, TyTy::FnType *fntype);
static tree
discriminant_value_handler (Context *ctx, TyTy::FnType *fntype);

enum class Prefetch
{
Expand Down Expand Up @@ -217,45 +214,45 @@ sorry_handler (Context *ctx, TyTy::FnType *fntype)

static const std::map<std::string,
std::function<tree (Context *, TyTy::FnType *)>>
generic_intrinsics = {
{"offset", offset_handler},
{"size_of", sizeof_handler},
{"transmute", transmute_handler},
{"rotate_left", rotate_left_handler},
{"rotate_right", rotate_right_handler},
{"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
{"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
{"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
{"add_with_overflow", op_with_overflow (PLUS_EXPR)},
{"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
{"mul_with_overflow", op_with_overflow (MULT_EXPR)},
{"copy", copy_handler (true)},
{"copy_nonoverlapping", copy_handler (false)},
{"prefetch_read_data", prefetch_read_data},
{"prefetch_write_data", prefetch_write_data},
{"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)},
{"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)},
{"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)},
{"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)},
{"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)},
{"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)},
{"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)},
{"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)},
{"unchecked_add", unchecked_op_handler (PLUS_EXPR)},
{"unchecked_sub", unchecked_op_handler (MINUS_EXPR)},
{"unchecked_mul", unchecked_op_handler (MULT_EXPR)},
{"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)},
{"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)},
{"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)},
{"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)},
{"uninit", uninit_handler},
{"move_val_init", move_val_init_handler},
{"likely", expect_handler (true)},
{"unlikely", expect_handler (false)},
{"assume", assume_handler},
{"try", try_handler (false)},
{"catch_unwind", try_handler (true)},
};
generic_intrinsics
= {{"offset", offset_handler},
{"size_of", sizeof_handler},
{"transmute", transmute_handler},
{"rotate_left", rotate_left_handler},
{"rotate_right", rotate_right_handler},
{"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
{"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
{"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
{"add_with_overflow", op_with_overflow (PLUS_EXPR)},
{"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
{"mul_with_overflow", op_with_overflow (MULT_EXPR)},
{"copy", copy_handler (true)},
{"copy_nonoverlapping", copy_handler (false)},
{"prefetch_read_data", prefetch_read_data},
{"prefetch_write_data", prefetch_write_data},
{"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)},
{"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)},
{"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)},
{"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)},
{"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)},
{"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)},
{"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)},
{"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)},
{"unchecked_add", unchecked_op_handler (PLUS_EXPR)},
{"unchecked_sub", unchecked_op_handler (MINUS_EXPR)},
{"unchecked_mul", unchecked_op_handler (MULT_EXPR)},
{"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)},
{"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)},
{"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)},
{"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)},
{"uninit", uninit_handler},
{"move_val_init", move_val_init_handler},
{"likely", expect_handler (true)},
{"unlikely", expect_handler (false)},
{"assume", assume_handler},
{"try", try_handler (false)},
{"catch_unwind", try_handler (true)},
{"discriminant_value", discriminant_value_handler}};

Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}

Expand Down Expand Up @@ -1375,5 +1372,69 @@ try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api)
return fndecl;
}

static tree
discriminant_value_handler (Context *ctx, TyTy::FnType *fntype)
{
rust_assert (fntype->get_params ().size () == 1);
rust_assert (fntype->get_return_type ()->is<TyTy::PlaceholderType> ());
rust_assert (fntype->has_substitutions ());
rust_assert (fntype->get_num_type_params () == 1);
auto &mapping = fntype->get_substs ().at (0);
auto param_ty = mapping.get_param_ty ();
rust_assert (param_ty->can_resolve ());
auto resolved = param_ty->resolve ();
auto p = static_cast<TyTy::PlaceholderType *> (fntype->get_return_type ());

TyTy::BaseType *return_type = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("isize", &return_type);
rust_assert (ok);

bool is_adt = resolved->is<TyTy::ADTType> ();
bool is_enum = false;
if (is_adt)
{
const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
return_type = adt.get_repr_options ().repr;
rust_assert (return_type != nullptr);
is_enum = adt.is_enum ();
}

p->set_associated_type (return_type->get_ref ());

tree lookup = NULL_TREE;
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
return lookup;

auto fndecl = compile_intrinsic_function (ctx, fntype);

std::vector<Bvariable *> param_vars;
compile_fn_params (ctx, fntype, fndecl, &param_vars);

if (!Backend::function_set_parameters (fndecl, param_vars))
return error_mark_node;

enter_intrinsic_block (ctx, fndecl);

// BUILTIN disriminant_value FN BODY BEGIN

tree result = integer_zero_node;
if (is_enum)
{
tree val = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
tree deref = build_fold_indirect_ref_loc (UNKNOWN_LOCATION, val);
result = Backend::struct_field_expression (deref, 0, UNKNOWN_LOCATION);
}

auto return_statement
= Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
ctx->add_statement (return_statement);

// BUILTIN disriminant_value FN BODY END

finalize_intrinsic_block (ctx, fndecl);

return fndecl;
}

} // namespace Compile
} // namespace Rust
1 change: 1 addition & 0 deletions gcc/rust/typecheck/rust-hir-trait-resolve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ TraitItemReference::resolve_item (HIR::TraitItemType &type)
{
TyTy::BaseType *ty
= new TyTy::PlaceholderType (type.get_name ().as_string (),
type.get_mappings ().get_defid (),
type.get_mappings ().get_hirid ());
context->insert_type (type.get_mappings (), ty);
}
Expand Down
4 changes: 4 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
repr.pack = 0;
repr.align = 0;

// FIXME handle repr types....
bool ok = context->lookup_builtin ("isize", &repr.repr);
rust_assert (ok);

for (const auto &attr : attrs)
{
bool is_repr = attr.get_path ().as_string () == Values::Attributes::REPR;
Expand Down
46 changes: 46 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,52 @@ TypeCheckExpr::visit (HIR::CallExpr &expr)
}

infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);

auto discriminant_type_lookup
= mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
if (infered->is<TyTy::PlaceholderType> () && discriminant_type_lookup)
{
const auto &p = *static_cast<const TyTy::PlaceholderType *> (infered);
if (p.get_def_id () == discriminant_type_lookup.value ())
{
// this is a special case where this will actually return the repr of
// the enum. We dont currently support repr on enum yet to change the
// discriminant type but the default is always isize. We need to
// assert this is a generic function with one param
//
// fn<BookFormat> (v & T=BookFormat{Paperback) -> <placeholder:>
//
// note the default is isize

bool ok = context->lookup_builtin ("isize", &infered);
rust_assert (ok);

rust_assert (function_tyty->is<TyTy::FnType> ());
auto &fn = *static_cast<TyTy::FnType *> (function_tyty);
rust_assert (fn.has_substitutions ());
rust_assert (fn.get_num_type_params () == 1);
auto &mapping = fn.get_substs ().at (0);
auto param_ty = mapping.get_param_ty ();

if (!param_ty->can_resolve ())
{
// this could be a valid error need to test more weird cases and
// look at rustc
rust_internal_error_at (expr.get_locus (),
"something wrong computing return type");
return;
}

auto resolved = param_ty->resolve ();
bool is_adt = resolved->is<TyTy::ADTType> ();
if (is_adt)
{
const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
infered = adt.get_repr_options ().repr;
rust_assert (infered != nullptr);
}
}
}
}

void
Expand Down
7 changes: 6 additions & 1 deletion gcc/rust/typecheck/rust-hir-type-check-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
if (enum_decl.has_generics ())
resolve_generic_params (enum_decl.get_generic_params (), substitutions);

// Process #[repr(X)] attribute, if any
const AST::AttrVec &attrs = enum_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, enum_decl.get_locus ());

std::vector<TyTy::VariantDef *> variants;
int64_t discriminant_value = 0;
for (auto &variant : enum_decl.get_variants ())
Expand Down Expand Up @@ -375,7 +380,7 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
enum_decl.get_mappings ().get_hirid (),
enum_decl.get_identifier ().as_string (), ident,
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
std::move (substitutions));
std::move (substitutions), repr);

context->insert_type (enum_decl.get_mappings (), type);
infered = type;
Expand Down
8 changes: 0 additions & 8 deletions gcc/rust/typecheck/rust-hir-type-check-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,6 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
if (trait_ref->is_error ())
return;

// does this type actually implement this type-bound?
if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
{
rust_error_at (qual_path_type.get_locus (),
"root does not satisfy specified trait-bound");
return;
}

// get the predicate for the bound
auto specified_bound = get_predicate_from_bound (qual_path_type.get_trait (),
qual_path_type.get_type ());
Expand Down
20 changes: 13 additions & 7 deletions gcc/rust/typecheck/rust-tyty.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3483,20 +3483,20 @@ NeverType::clone () const

// placeholder type

PlaceholderType::PlaceholderType (std::string symbol, HirId ref,
PlaceholderType::PlaceholderType (std::string symbol, DefId id, HirId ref,
std::set<HirId> refs)
: BaseType (ref, ref, KIND,
{Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION},
refs),
symbol (symbol)
symbol (symbol), defId (id)
{}

PlaceholderType::PlaceholderType (std::string symbol, HirId ref, HirId ty_ref,
std::set<HirId> refs)
PlaceholderType::PlaceholderType (std::string symbol, DefId id, HirId ref,
HirId ty_ref, std::set<HirId> refs)
: BaseType (ref, ty_ref, KIND,
{Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION},
refs),
symbol (symbol)
symbol (symbol), defId (id)
{}

std::string
Expand Down Expand Up @@ -3540,8 +3540,8 @@ PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
BaseType *
PlaceholderType::clone () const
{
return new PlaceholderType (get_symbol (), get_ref (), get_ty_ref (),
get_combined_refs ());
return new PlaceholderType (get_symbol (), get_def_id (), get_ref (),
get_ty_ref (), get_combined_refs ());
}

void
Expand Down Expand Up @@ -3602,6 +3602,12 @@ PlaceholderType::is_equal (const BaseType &other) const
return get_symbol ().compare (other2.get_symbol ()) == 0;
}

DefId
PlaceholderType::get_def_id () const
{
return defId;
}

// Projection type

ProjectionType::ProjectionType (
Expand Down
8 changes: 6 additions & 2 deletions gcc/rust/typecheck/rust-tyty.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ class ADTType : public BaseType, public SubstitutionRef
// parsing the #[repr] attribute.
unsigned char align = 0;
unsigned char pack = 0;
BaseType *repr = nullptr;
};

ADTType (HirId ref, std::string identifier, RustIdent ident, ADTKind adt_kind,
Expand Down Expand Up @@ -1530,9 +1531,9 @@ class PlaceholderType : public BaseType
public:
static constexpr auto KIND = TypeKind::PLACEHOLDER;

PlaceholderType (std::string symbol, HirId ref,
PlaceholderType (std::string symbol, DefId id, HirId ref,
std::set<HirId> refs = std::set<HirId> ());
PlaceholderType (std::string symbol, HirId ref, HirId ty_ref,
PlaceholderType (std::string symbol, DefId id, HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());

void accept_vis (TyVisitor &vis) override;
Expand All @@ -1558,8 +1559,11 @@ class PlaceholderType : public BaseType

bool is_equal (const BaseType &other) const override;

DefId get_def_id () const;

private:
std::string symbol;
DefId defId;
};

class ProjectionType : public BaseType, public SubstitutionRef
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/util/rust-lang-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{

{"structural_peq", Kind::STRUCTURAL_PEQ},
{"structural_teq", Kind::STRUCTURAL_TEQ},

{"discriminant_kind", Kind::DISCRIMINANT_KIND},
{"discriminant_type", Kind::DISCRIMINANT_TYPE},
}};

tl::optional<LangItem::Kind>
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/util/rust-lang-item.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ class LangItem

STRUCTURAL_PEQ,
STRUCTURAL_TEQ,

DISCRIMINANT_TYPE,
DISCRIMINANT_KIND,
};

static const BiMap<std::string, Kind> lang_items;
Expand Down
Loading

0 comments on commit 3fd738c

Please sign in to comment.