Skip to content
Open
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
3 changes: 3 additions & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ GRS_OBJS = \
rust/rust-compile-resolve-path.o \
rust/rust-macro-expand.o \
rust/rust-cfg-strip.o \
rust/rust-early-cfg-strip.o \
rust/rust-expand-visitor.o \
rust/rust-ast-builder.o \
rust/rust-derive.o \
Expand Down Expand Up @@ -229,6 +230,8 @@ GRS_OBJS = \
rust/rust-builtins.o \
rust/rust-feature.o \
rust/rust-feature-gate.o \
rust/rust-feature-store.o \
rust/rust-feature-collector.o \
rust/rust-ast-validation.o \
rust/rust-dir-owner.o \
rust/rust-unicode.o \
Expand Down
2 changes: 1 addition & 1 deletion gcc/rust/ast/rust-ast-full-decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class DelimTokenTree;
class PathSegment;
class SimplePathSegment;
class SimplePath;
struct Attribute;
class Attribute;
class MetaItemInner;
class AttrInputMetaItemContainer;
class MetaItem;
Expand Down
8 changes: 8 additions & 0 deletions gcc/rust/ast/rust-ast-visitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ DefaultASTVisitor::visit (AST::LiteralExpr &expr)
visit_outer_attrs (expr);
}

void
DefaultASTVisitor::visit (AST::Attribute &attribute)
{
visit (attribute.get_path ());
if (attribute.has_attr_input ())
visit (attribute.get_attr_input ());
}

void
DefaultASTVisitor::visit (AST::AttrInputLiteral &attr_input)
{
Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/ast/rust-ast-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class ASTVisitor

// rust-ast.h
// virtual void visit(AttrInput& attr_input) = 0;
virtual void visit (AST::Attribute &attribute) = 0;
// virtual void visit(TokenTree& token_tree) = 0;
// virtual void visit(MacroMatch& macro_match) = 0;
virtual void visit (Token &tok) = 0;
Expand Down Expand Up @@ -444,7 +445,7 @@ class DefaultASTVisitor : public ASTVisitor
virtual void visit (AST::StructPatternElements &spe);
virtual void visit (AST::MaybeNamedParam &param);

void visit (AST::Attribute &attribute) {}
virtual void visit (AST::Attribute &attribute) override;

template <typename T> void visit_outer_attrs (T &node)
{
Expand Down
6 changes: 6 additions & 0 deletions gcc/rust/ast/rust-ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ Attribute::as_string () const
return path_str + attr_input->as_string ();
}

void
Attribute::accept_vis (ASTVisitor &vis)
{
vis.visit (*this);
}

bool
Attribute::is_derive () const
{
Expand Down
12 changes: 8 additions & 4 deletions gcc/rust/ast/rust-ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,9 +565,8 @@ struct Visibility

// aka Attr
// Attribute AST representation
struct Attribute
class Attribute : Visitable
{
private:
SimplePath path;

// bool has_attr_input;
Expand All @@ -577,6 +576,8 @@ struct Attribute

bool inner_attribute;

NodeId node_id;

// TODO: maybe a variable storing whether attr input is parsed or not

public:
Expand All @@ -587,7 +588,8 @@ struct Attribute
Attribute (SimplePath path, std::unique_ptr<AttrInput> input,
location_t locus = UNDEF_LOCATION, bool inner_attribute = false)
: path (std::move (path)), attr_input (std::move (input)), locus (locus),
inner_attribute (inner_attribute)
inner_attribute (inner_attribute),
node_id (Analysis::Mappings::get ().get_next_node_id ())
{}

bool is_derive () const;
Expand Down Expand Up @@ -685,11 +687,13 @@ struct Attribute

bool is_inner_attribute () const { return inner_attribute; }

// no visitor pattern as not currently polymorphic
void accept_vis (ASTVisitor &vis) override;

const SimplePath &get_path () const { return path; }
SimplePath &get_path () { return path; }

NodeId get_node_id () { return node_id; }

// Call to parse attribute body to meta item syntax.
void parse_attr_to_meta_item ();

Expand Down
4 changes: 2 additions & 2 deletions gcc/rust/checks/errors/feature/contrib/fetch
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.

RUST_VERSION="1.49.0"
RUST_VERSION="1.50.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.49 libraries need features new to the 1.50 compiler?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm experimenting with rust for linux, initially I thought this would be fine because we only had a superset of features but since the regeneration removes a feature I'll make a separate header with whatever features I need for linux.


[ $# = 1 ] || exit 1

Expand All @@ -27,4 +27,4 @@ RUST_VERSION="1.49.0"
URL_PREFIX='https://raw.githubusercontent.com/rust-lang/rust/refs/tags'
URL_TEMPLATE="$URL_PREFIX/$RUST_VERSION/compiler/rustc_feature/src"

wget -O $1 "$URL_TEMPLATE"/{accepted,active,removed}.rs
wget -O $1 "$URL_TEMPLATE/accepted.rs" "$URL_TEMPLATE/active.rs" "$URL_TEMPLATE/removed.rs"
117 changes: 117 additions & 0 deletions gcc/rust/checks/errors/feature/rust-feature-collector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (C) 2026 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.

#include "rust-feature-collector.h"
#include "rust-attribute-values.h"

namespace Rust {
namespace Features {

FeatureCollector::FeatureCollector () : features (CrateFeatures{UNKNOWN_NODEID})
{}

CrateFeatures
FeatureCollector::collect (AST::Crate &crate)
{
features.valid_lang_features.clear ();
features.valid_lib_features.clear ();
features.crate_id = crate.get_node_id ();

visit (crate);

return features;
}

namespace {
bool
is_feature_attribute (const AST::Attribute &attribute)
{
return Values::Attributes::FEATURE == attribute.get_path ().as_string ();
}

// check for empty feature, such as `#![feature], this is an error
bool
is_valid_feature_attribute (const AST::Attribute &attribute)
{
return !attribute.empty_input ();
}
} // namespace

void
FeatureCollector::add_features_from_token_tree (
const AST::DelimTokenTree &delim_ttree)
{
std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
delim_ttree.parse_to_meta_item ());
add_features_from_meta_item_container (*meta_item);
}

void
FeatureCollector::add_features_from_meta_item_container (
const AST::AttrInputMetaItemContainer &meta_item_container)
{
for (const auto &item : meta_item_container.get_items ())
{
const auto &name_str = item->as_string ();

// TODO: detect duplicates
if (auto tname = Feature::as_name (name_str))
features.valid_lang_features.insert (*tname);
else
features.valid_lib_features.emplace (name_str, item->get_locus ());
}
}

void
FeatureCollector::identify_feature (const AST::Attribute &attribute)
{
if (is_feature_attribute (attribute))
{
if (!is_valid_feature_attribute (attribute))
{
rust_error_at (attribute.get_locus (), ErrorCode::E0556,
"malformed %<feature%> attribute input");
return;
}
const auto &attr_input = attribute.get_attr_input ();
auto type = attr_input.get_attr_input_type ();
if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
{
const auto &delim_ttree = static_cast<const AST::DelimTokenTree &> (
attribute.get_attr_input ());
add_features_from_token_tree (delim_ttree);
}
else if (type == AST::AttrInput::AttrInputType::META_ITEM)
{
// We can find a meta item in #[cfg(toto),feature(xxxx)]
const auto &meta_item_container
= static_cast<const AST::AttrInputMetaItemContainer &> (attr_input);
add_features_from_meta_item_container (meta_item_container);
}
}
}

void
FeatureCollector::visit (AST::Crate &crate)
{
for (const auto &attribute : crate.inner_attrs)
identify_feature (attribute);
}

} // namespace Features
} // namespace Rust
62 changes: 62 additions & 0 deletions gcc/rust/checks/errors/feature/rust-feature-collector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (C) 2026 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_FEATURE_COLLECTOR_H
#define RUST_FEATURE_COLLECTOR_H

#include "rust-feature.h"
#include "rust-ast-visitor.h"

namespace Rust {
namespace Features {

/** Helper structure gathering all features enabled within a given crate
* using the #![feature(XXXXX)] syntax.
**/
struct CrateFeatures
{
// The node id identifying the crate those features belong to.
NodeId crate_id;
// Language features that have been declared within the crate.
std::set<Feature::Name> valid_lang_features;
// Library features that have been declared within the crate.
std::map<std::string, location_t> valid_lib_features;

CrateFeatures (NodeId crate_id) : crate_id (crate_id) {}
};

class FeatureCollector : public AST::DefaultASTVisitor
{
public:
FeatureCollector ();

CrateFeatures collect (AST::Crate &crate);

private:
CrateFeatures features;

using AST::DefaultASTVisitor::visit;
void visit (AST::Crate &crate) override;
void identify_feature (const AST::Attribute &attribute);
void add_features_from_token_tree (const AST::DelimTokenTree &delim_ttree);
void add_features_from_meta_item_container (
const AST::AttrInputMetaItemContainer &meta_item_container);
};
} // namespace Features
} // namespace Rust

#endif /* ! RUST_FEATURE_COLLECTOR_H */
10 changes: 8 additions & 2 deletions gcc/rust/checks/errors/feature/rust-feature-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ FEATURE_ACTIVE ("fundamental", FUNDAMENTAL, "1.0.0", ISSUE_SOME (29635),
FEATURE_ACTIVE ("unboxed_closures", UNBOXED_CLOSURES, "1.0.0",
ISSUE_SOME (29625), EDITION_NONE)
FEATURE_ACTIVE ("linkage", LINKAGE, "1.0.0", ISSUE_SOME (29603), EDITION_NONE)
FEATURE_ACTIVE ("optin_builtin_traits", OPTIN_BUILTIN_TRAITS, "1.0.0",
ISSUE_SOME (13231), EDITION_NONE)
FEATURE_ACTIVE ("box_patterns", BOX_PATTERNS, "1.0.0", ISSUE_SOME (29641),
EDITION_NONE)
FEATURE_ACTIVE ("prelude_import", PRELUDE_IMPORT, "1.2.0", ISSUE_NONE,
Expand Down Expand Up @@ -257,6 +255,8 @@ FEATURE_ACTIVE ("test_2018_feature", TEST_2018_FEATURE, "1.31.0", ISSUE_NONE,
FEATURE_ACTIVE ("no_niche", NO_NICHE, "1.42.0", ISSUE_NONE, EDITION_NONE)
FEATURE_ACTIVE ("rustc_allow_const_fn_unstable", RUSTC_ALLOW_CONST_FN_UNSTABLE,
"1.49.0", ISSUE_SOME (69399), EDITION_NONE)
FEATURE_ACTIVE ("auto_traits", AUTO_TRAITS, "1.50.0", ISSUE_SOME (13231),
EDITION_NONE)
FEATURE_ACTIVE ("arm_target_feature", ARM_TARGET_FEATURE, "1.27.0",
ISSUE_SOME (44839), EDITION_NONE)
FEATURE_ACTIVE ("aarch64_target_feature", AARCH64_TARGET_FEATURE, "1.27.0",
Expand Down Expand Up @@ -519,6 +519,10 @@ FEATURE_ACTIVE ("destructuring_assignment", DESTRUCTURING_ASSIGNMENT, "1.49.0",
ISSUE_SOME (71126), EDITION_NONE)
FEATURE_ACTIVE ("cfg_panic", CFG_PANIC, "1.49.0", ISSUE_SOME (77443),
EDITION_NONE)
FEATURE_ACTIVE ("capture_disjoint_fields", CAPTURE_DISJOINT_FIELDS, "1.49.0",
ISSUE_SOME (53488), EDITION_NONE)
FEATURE_ACTIVE ("extended_key_value_attributes", EXTENDED_KEY_VALUE_ATTRIBUTES,
"1.50.0", ISSUE_SOME (78835), EDITION_NONE)
FEATURE_REMOVED ("import_shadowing", IMPORT_SHADOWING, "1.0.0", ISSUE_NONE,
REASON_NONE)
FEATURE_REMOVED ("managed_boxes", MANAGED_BOXES, "1.0.0", ISSUE_NONE,
Expand Down Expand Up @@ -550,6 +554,8 @@ FEATURE_REMOVED (
"custom_attribute", CUSTOM_ATTRIBUTE, "1.0.0", ISSUE_SOME (29642),
REASON_SOME (
"removed in favor of `#![register_tool]` and `#![register_attr]`"))
FEATURE_REMOVED ("optin_builtin_traits", OPTIN_BUILTIN_TRAITS, "1.0.0",
ISSUE_SOME (13231), REASON_SOME ("renamed to `auto_traits`"))
FEATURE_REMOVED ("pushpop_unsafe", PUSHPOP_UNSAFE, "1.2.0", ISSUE_NONE,
REASON_NONE)
FEATURE_REMOVED ("needs_allocator", NEEDS_ALLOCATOR, "1.4.0",
Expand Down
Loading
Loading