Skip to content

Commit

Permalink
ast: Check if the #[derive] attribute is used on a compatible item
Browse files Browse the repository at this point in the history
gcc/rust/ChangeLog:

	* ast/rust-ast.h: Create new `Item::Kind` enum and new `Item::get_item_kind` method
	* ast/rust-item.h: Implement `Item::get_item_kind` method
	* ast/rust-macro.h: Implement `Item::get_item_kind` method
	* expand/rust-derive.cc (DeriveVisitor::derive): Check that `#[derive]` is applied
	on compatible item
	* expand/rust-expand-visitor.cc: Check if returned item is null before putting it
	into the item list

gcc/testsuite/ChangeLog:

	* rust/compile/derive_macro9.rs: New test.
  • Loading branch information
GuillaumeGomez committed Mar 6, 2024
1 parent 452345f commit 3c9d66b
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 4 deletions.
22 changes: 22 additions & 0 deletions gcc/rust/ast/rust-ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,26 @@ class Stmt : public Node
class Item : public Stmt
{
public:
enum class Kind
{
Static = 0,
Constant,
TypeAlias,
Function,
UseDeclaration,
ExternBlock,
ExternCrate,
Struct,
Union,
Enum,
EnumItem,
Trait,
Impl,
Module,
MacroRules,
MacroInvocation,
};

// Unique pointer custom clone function
std::unique_ptr<Item> clone_item () const
{
Expand All @@ -1151,6 +1171,8 @@ class Item : public Stmt
add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const
{}

virtual Kind get_item_kind () const = 0;

Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Item; }

// FIXME: ARTHUR: Is it okay to have removed that final? Is it *required*
Expand Down
28 changes: 28 additions & 0 deletions gcc/rust/ast/rust-item.h
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,8 @@ class Module : public VisItem
UNLOADED,
};

Item::Kind get_item_kind () const { return Item::Kind::Module; }

Identifier get_name () const { return module_name; }

AST::Kind get_ast_kind () const override { return AST::Kind::MODULE; }
Expand Down Expand Up @@ -898,6 +900,8 @@ class ExternCrate : public VisItem
"extern crate foo"
"extern crate std as cool_std" */
public:
Item::Kind get_item_kind () const { return Item::Kind::ExternCrate; }

std::string as_string () const override;

// Returns whether extern crate declaration has an as clause.
Expand Down Expand Up @@ -1227,6 +1231,8 @@ class UseDeclaration : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::UseDeclaration; }

std::string as_string () const override;

UseDeclaration (std::unique_ptr<UseTree> use_tree, Visibility visibility,
Expand Down Expand Up @@ -1302,6 +1308,8 @@ class Function : public VisItem, public AssociatedItem
bool is_default;

public:
Item::Kind get_item_kind () const { return Item::Kind::Function; }

std::string as_string () const override;

// Returns whether function has generic parameters.
Expand Down Expand Up @@ -1452,6 +1460,8 @@ class TypeAlias : public VisItem, public AssociatedItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::TypeAlias; }

std::string as_string () const override;

// Returns whether type alias has generic parameters.
Expand Down Expand Up @@ -1577,6 +1587,8 @@ class Struct : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Struct; }

// Returns whether struct has generic parameters.
bool has_generics () const { return !generic_params.empty (); }

Expand Down Expand Up @@ -1946,6 +1958,8 @@ class EnumItem : public VisItem
variant_name (std::move (variant_name)), locus (locus)
{}

Item::Kind get_item_kind () const { return Item::Kind::EnumItem; }

// Unique pointer custom clone function
std::unique_ptr<EnumItem> clone_enum_item () const
{
Expand Down Expand Up @@ -2115,6 +2129,8 @@ class Enum : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Enum; }

std::string as_string () const override;

// Returns whether "enum" has generic parameters.
Expand Down Expand Up @@ -2230,6 +2246,8 @@ class Union : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Union; }

std::string as_string () const override;

// Returns whether union has generic params.
Expand Down Expand Up @@ -2327,6 +2345,8 @@ class ConstantItem : public VisItem, public AssociatedItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Constant; }

std::string as_string () const override;

ConstantItem (std::string ident, Visibility vis, std::unique_ptr<Type> type,
Expand Down Expand Up @@ -2442,6 +2462,8 @@ class StaticItem : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Static; }

std::string as_string () const override;

StaticItem (Identifier name, bool is_mut, std::unique_ptr<Type> type,
Expand Down Expand Up @@ -2740,6 +2762,8 @@ class Trait : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Trait; }

std::string as_string () const override;

// Returns whether trait has generic parameters.
Expand Down Expand Up @@ -2912,6 +2936,8 @@ class Impl : public VisItem
location_t locus;

public:
Item::Kind get_item_kind () const { return Item::Kind::Impl; }

// Returns whether impl has generic parameters.
bool has_generics () const { return !generic_params.empty (); }

Expand Down Expand Up @@ -3718,6 +3744,8 @@ class ExternBlock : public VisItem
bool marked_for_strip = false;

public:
Item::Kind get_item_kind () const { return Item::Kind::ExternBlock; }

std::string as_string () const override;

// Returns whether extern block has inner attributes.
Expand Down
4 changes: 4 additions & 0 deletions gcc/rust/ast/rust-macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ class MacroRulesDefinition : public VisItem
DeclMacro,
};

Item::Kind get_item_kind () const { return Item::Kind::MacroRules; }

private:
std::vector<Attribute> outer_attrs;
Identifier rule_name;
Expand Down Expand Up @@ -608,6 +610,8 @@ class MacroInvocation : public TypeNoBounds,
Builtin,
};

Item::Kind get_item_kind () const { return Item::Kind::MacroInvocation; }

std::string as_string () const override;

/**
Expand Down
13 changes: 13 additions & 0 deletions gcc/rust/expand/rust-derive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ std::unique_ptr<Item>
DeriveVisitor::derive (Item &item, const Attribute &attr,
BuiltinMacro to_derive)
{
switch (item.get_item_kind ())
{
case Item::Kind::Struct:
case Item::Kind::Union:
case Item::Kind::Enum:
break;
default:
rust_error_at (
attr.get_locus (),
"the %<#[derive]%> attribute can only be used on struct, union and "
"enum declaration");
return nullptr;
}
switch (to_derive)
{
case BuiltinMacro::Clone:
Expand Down
32 changes: 28 additions & 4 deletions gcc/rust/expand/rust-expand-visitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,12 @@ ExpandVisitor::expand_inner_items (
auto new_item
= builtin_derive_item (*item, current,
maybe_builtin.value ());
// this inserts the derive *before* the item - is it a
// problem?
it = items.insert (it, std::move (new_item));
if (new_item != nullptr)
{
// this inserts the derive *before* the item - is
// it a problem?
it = items.insert (it, std::move (new_item));
}
}
else
{
Expand Down Expand Up @@ -353,6 +356,23 @@ ExpandVisitor::maybe_expand_type (std::unique_ptr<AST::Type> &type)
expander.pop_context ();
}

void
ExpandVisitor::check_derive (std::vector<AST::Attribute> &attrs)
{
for (auto attr_it = attrs.begin (); attr_it != attrs.end (); ++attr_it)
{
auto current = *attr_it;

if (current.is_derive ())
{
rust_error_at (
current.get_locus (),
"the %<#[derive]%> attribute can only be used on struct, union and "
"enum declaration");
}
}
}

// FIXME: Can this be refactored into a `scoped` method? Which takes a
// ContextType as parameter and a lambda? And maybe just an std::vector<T>&?
void
Expand All @@ -361,14 +381,18 @@ ExpandVisitor::expand_struct_fields (std::vector<AST::StructField> &fields)
for (auto &field : fields)
{
maybe_expand_type (field.get_field_type ());
check_derive (field.get_outer_attrs ());
}
}

void
ExpandVisitor::expand_tuple_fields (std::vector<AST::TupleField> &fields)
{
for (auto &field : fields)
maybe_expand_type (field.get_field_type ());
{
maybe_expand_type (field.get_field_type ());
check_derive (field.get_outer_attrs ());
}
}

// FIXME: This can definitely be refactored with the method above
Expand Down
5 changes: 5 additions & 0 deletions gcc/rust/expand/rust-expand-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ class ExpandVisitor : public AST::DefaultASTVisitor
void expand_closure_params (std::vector<AST::ClosureParam> &params);
void expand_where_clause (AST::WhereClause &where_clause);

/**
* Checks if there is a `#[derive]` attribute and emit an error if so.
*/
void check_derive (std::vector<AST::Attribute> &attrs);

/**
* Expand a set of values, erasing them if they are marked for strip, and
* replacing them with expanded macro nodes if necessary.
Expand Down
25 changes: 25 additions & 0 deletions gcc/testsuite/rust/compile/derive_macro9.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#[derive(Clone)] // { dg-error "attribute can only be used on struct, union and enum declaration" }
pub fn foo() {}

pub struct Struct {
#[derive(Clone)] // { dg-error "attribute can only be used on struct, union and enum declaration" }
a: u32,
}

pub enum Enum {
// FIXME: This is a bug, it should warn!
#[derive(Clone)]
A,
// FIXME: This is a bug, it should warn!
#[derive(Clone)]
B(u32),
// FIXME: This is a bug, it should warn!
#[derive(Clone)]
C { a: u32 },
}

pub union Union {
#[derive(Clone)] // { dg-error "attribute can only be used on struct, union and enum declaration" }
a: u32,
b: u8,
}

0 comments on commit 3c9d66b

Please sign in to comment.