From: Wesley Lewis <[email protected]> Return the error E0802 on structs that have no type parameter to act as a pointee, or several which are marked as pointee. For structs having multiple non-generic typed fields, the one marked with #[pointee] will be selected as the pointee.
Fixes Rust-GCC/gccrs#4915 Author: Wesley Lewis <[email protected]> gcc/rust/ChangeLog: * expand/rust-derive-coerce-pointee.cc (DeriveCoercePointee::validate_non_generic_pointee): New. (DeriveCoercePointee::go): Call validate_non_generic_pointee. * expand/rust-derive-coerce-pointee.h (DeriveCoercePointee::validate_non_generic_pointee): Declare. * util/rust-attribute-values.h: Added POINTEE. gcc/testsuite/ChangeLog: * rust/compile/derive-coerce-pointee6.rs: New test. Signed-off-by: Wesley Lewis <[email protected]> --- 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/bf1780e025a28132ef1ca46fc3acc40a1dda9d4e The commit has been mentioned in the following issue(s): - Rust-GCC/gccrs#4915: https://github.com/Rust-GCC/gccrs/issues/4915 The commit has been mentioned in the following pull-request(s): - https://github.com/Rust-GCC/gccrs/pull/4950 gcc/rust/expand/rust-derive-coerce-pointee.cc | 123 +++++++++++++----- gcc/rust/expand/rust-derive-coerce-pointee.h | 17 ++- gcc/rust/util/rust-attribute-values.h | 1 + .../rust/compile/derive-coerce-pointee6.rs | 41 ++++++ .../rust/compile/derive-coerce-pointee7.rs | 27 ++++ 5 files changed, 172 insertions(+), 37 deletions(-) create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee6.rs create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee7.rs diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.cc b/gcc/rust/expand/rust-derive-coerce-pointee.cc index b2c71d2c8..e23362b75 100644 --- a/gcc/rust/expand/rust-derive-coerce-pointee.cc +++ b/gcc/rust/expand/rust-derive-coerce-pointee.cc @@ -18,7 +18,6 @@ #include "rust-attribute-values.h" #include "rust-derive-coerce-pointee.h" -#include "rust-diagnostics.h" #include "rust-feature-store.h" #include "rust-feature.h" #include "rust-session-manager.h" @@ -34,8 +33,7 @@ DeriveCoercePointee::DeriveCoercePointee (location_t loc, std::unique_ptr<AST::Item> DeriveCoercePointee::go (Item &item) { - validate_repr_transparent (item); - validate_number_of_fields (item); + item.accept_vis (*this); Features::EarlyFeatureGateStore::get ().add ( Feature::Name::DERIVE_COERCE_POINTEE, Error (loc, "use of unstable library feature %<derive_coerce_pointee%>")); @@ -77,7 +75,7 @@ DeriveCoercePointee::go (Item &item) } // CoercePointee requires the Struct or Tuple to have transparent representation -bool +void DeriveCoercePointee::validate_repr_transparent (const Item &item) { const auto &attrs = item.get_outer_attrs (); @@ -85,55 +83,118 @@ DeriveCoercePointee::validate_repr_transparent (const Item &item) { if (attr.get_path ().as_string () != Values::Attributes::REPR) continue; - if (attr.empty_input ()) - continue; + rust_assert (!attr.empty_input ()); const auto &attr_input = attr.get_attr_input (); - if (attr_input.get_attr_input_type () - != AST::AttrInput::AttrInputType::TOKEN_TREE) - continue; + rust_assert (attr_input.get_attr_input_type () + == AST::AttrInput::AttrInputType::TOKEN_TREE); auto meta_item = static_cast<const AST::DelimTokenTree &> (attr_input) .parse_to_meta_item (); + rust_assert (meta_item); for (const auto &item : meta_item->get_items ()) if (item->as_string () == "transparent") - return true; + return; } rust_error_at (item.get_locus (), ErrorCode::E0802, "%<CoercePointee%> is only applicable to struct/tuple with " "repr(transparent) layout"); - return false; } // Structs or Tuples with CoercePointee must have minimum of one field else // compile time error -bool +void DeriveCoercePointee::validate_number_of_fields (const Item &item) { - size_t field_count = 0; - - if (item.get_item_kind () == Item::Kind::Struct) - { - auto *struct_item = static_cast<const StructStruct *> (&item); - field_count = struct_item->get_fields ().size (); - } - else - { - rust_error_at (item.get_locus (), ErrorCode::E0802, - "%<CoercePointee%> can only be derived on structs with " - "#[repr(transparent)]"); - return false; - } + rust_assert (item.get_item_kind () == Item::Kind::Struct); + auto &struct_item = static_cast<const StructStruct &> (item); + size_t field_count = struct_item.get_fields ().size (); if (field_count == 0) + rust_error_at (item.get_locus (), ErrorCode::E0802, + "%<CoercePointee%> can only be derived on a struct " + "with at least one field"); +} + +// #[pointee] needs to be on a generic type parameter, and if there are 2 or +// more generic parameters (not traits), one of them must have the attribute +void +DeriveCoercePointee::validate_non_generic_pointee (const Rust::AST::Item &item) +{ + rust_assert (item.get_item_kind () == Item::Kind::Struct); + const StructStruct &struct_item = static_cast<const StructStruct &> (item); + const std::vector<std::unique_ptr<GenericParam>> &generic_params + = struct_item.get_generic_params (); + + // Implicitly it becomes the pointee + if (generic_params.size () == 1) + return; + + size_t pointee_count = 0; + + for (size_t i = 0; i < generic_params.size (); ++i) { - rust_error_at (item.get_locus (), ErrorCode::E0802, - "%<CoercePointee%> can only be derived on a struct " - "with at least one field"); - return false; + if (generic_params[i].get ()->get_kind () != GenericParam::Kind::Const + && (generic_params)[i].get ()->get_kind () + != GenericParam::Kind::Lifetime) + { + auto &type_param + = static_cast<TypeParam &> (*(generic_params)[i].get ()); + + for (const auto &attr : type_param.get_outer_attrs ()) + { + if (attr.get_path ().as_string () == Values::Attributes::POINTEE) + pointee_count += 1; + } + } } - return true; + + if (pointee_count == 0 || pointee_count > 1) + rust_error_at (item.get_locus (), ErrorCode::E0802, + "exactly one generic type parameter must be marked " + "as %<#[pointee]%> to derive %<CoercePointee%> traits"); +} + +// validates all the requirements for a type to be derived as CoercePointee +void +DeriveCoercePointee::validate (const Item &item) +{ + validate_repr_transparent (item); + validate_number_of_fields (item); + validate_non_generic_pointee (item); +} + +void +DeriveCoercePointee::visit_struct (StructStruct &item) +{ + validate (item); +} + +void +DeriveCoercePointee::visit_tuple (TupleStruct &item) +{ + validate (item); +} + +void +DeriveCoercePointee::visit_enum (Enum &item) +{ + error_for_non_supported_objects (item); +} + +void +DeriveCoercePointee::visit_union (Union &item) +{ + error_for_non_supported_objects (item); +} + +void +DeriveCoercePointee::error_for_non_supported_objects (const Item &item) +{ + rust_error_at (item.get_locus (), ErrorCode::E0802, + "%<CoercePointee%> can only be derived on structs with " + "%<#[repr(transparent)]%>"); } } // namespace AST } // namespace Rust diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.h b/gcc/rust/expand/rust-derive-coerce-pointee.h index b3f4e5239..e8be9a76b 100644 --- a/gcc/rust/expand/rust-derive-coerce-pointee.h +++ b/gcc/rust/expand/rust-derive-coerce-pointee.h @@ -31,13 +31,18 @@ public: std::unique_ptr<Item> go (Item &item); - bool validate_repr_transparent (const Item &item); - bool validate_number_of_fields (const Item &item); + void validate (const Item &item); + void validate_repr_transparent (const Item &item); + void validate_number_of_fields (const Item &item); + void validate_non_generic_pointee (const Item &item); + + void error_for_non_supported_objects (const Item &item); + private: - virtual void visit_struct (StructStruct &item) override {} - virtual void visit_tuple (TupleStruct &item) override {} - virtual void visit_enum (Enum &item) override {} - virtual void visit_union (Union &item) override {} + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index e42a67296..291e43338 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -58,6 +58,7 @@ public: static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute"; static constexpr auto &CRATE_NAME = "crate_name"; static constexpr auto &CRATE_TYPE = "crate_type"; + static constexpr auto &POINTEE = "pointee"; static constexpr auto &TARGET_FEATURE = "target_feature"; static constexpr auto &FEATURE = "feature"; diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs b/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs new file mode 100644 index 000000000..1b4d0905e --- /dev/null +++ b/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs @@ -0,0 +1,41 @@ +// { dg-additional-options "-frust-compat-version=1.84" } +// { dg-prune-output "could not resolve attribute macro invocation 'pointee'" } + +// checks for 1 non-generic type for structs with derive CoercePointee having more than 1 generic +// params + +#![feature(no_core)] +#![feature(lang_items)] +#![feature(derive_coerce_pointee)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +// user-defined trait +trait MyTrait {} + +#[lang = "phantom_data"] +pub struct PhantomData<T>; + +#[repr(transparent)] +#[derive(CoercePointee)] // { dg-warning "no effect" } + // { dg-error "one generic type parameter must be marked as '#\\\[pointee\\\]'" "" { target *-*-* } .+1 } +struct MultipleGenericStruct<T: MyTrait, U> { + a: *const T, + b: PhantomData<U>, +} + +#[repr(transparent)] +#[derive(CoercePointee)] // { dg-warning "no effect" } +struct MultipleMarkedPointee<#[pointee] T: MyTrait, #[pointee] U> { // { dg-error "one generic type parameter must be marked as '#\\\[pointee\\\]'" "" { target *-*-* } } + a: *const T, + b: PhantomData<U>, +} + +#[repr(transparent)] +#[derive(CoercePointee)] // { dg-warning "no effect" } +struct Good<#[pointee]T: MyTrait, U> { + a: *const T, + b: PhantomData<U>, +} diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs b/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs new file mode 100644 index 000000000..19e6c8994 --- /dev/null +++ b/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs @@ -0,0 +1,27 @@ +// { dg-additional-options "-frust-compat-version=1.84" } + +// Check if derive CoercePointee errors out on Union & Enums + +#![feature(no_core)] +#![feature(lang_items)] +#![feature(derive_coerce_pointee)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +// user-defined trait +trait MyTrait {} + +#[repr(transparent)] +#[derive(CoercePointee)] // { dg-warning "no effect" } +// { dg-error "only be derived on structs with '#\\\[repr\\(transparent\\)\\\]'" "" { target *-*-* } .+1 } +enum GenericEnum<T: MyTrait> { + A(T) +} + +#[repr(transparent)] +#[derive(CoercePointee)] // { dg-warning "no effect" } +union GenericUnion<T: MyTrait> { // { dg-error "only be derived on structs with '#\\\[repr\\(transparent\\)\\\]'" "" { target *-*-* } } + a: T, +} -- 2.56.0
