From: Pierre-Emmanuel Patry <[email protected]>
Move all internal attribute structure checking within specific handler
functions called from the attribute visit function instead of multiple
duplicated sources in the various items. Store those handlers in a map
to avoid the expensive string switch comparisons.
gcc/rust/ChangeLog:
* checks/errors/rust-builtin-attribute-checker.cc (check_doc_attribute):
Move from here...
(doc): ...to here.
(check_deprecated_attribute): Move from here...
(deprecated): ...to here.
(check_link_section_attribute): Move from here...
(link_section): ... to here.
(check_export_name_attribute): Move from here...
(export_name): ... to here.
(check_no_mangle_function): Remove internal structure checking and move
it to no_mangle handler.
(check_lint_attribute): Move from here...
(lint): ... to here.
(link_name): Likewise with link_name.
(check_crate_type): Move to anonymous namespace within the handler
namespace.
(proc_macro_derive): Add proc macro specific handler.
(proc_macro): Likewise.
(target_feature): Likewise.
(no_mangle): Add specific handler for no_mangler attribute internal
structure checking.
(std::function<void): Add map with attribute name to handler matching.
(tl::optional<std::function<void): Likewise.
(lookup_handler): Add an helper function to retrieve the handler of any
builtin attribute.
(BuiltinAttributeChecker::visit): Change attribute visitor call with
new handler call.
* checks/errors/rust-builtin-attribute-checker.h
(check_valid_attribute_for_item):
Add prototype.
Signed-off-by: Pierre-Emmanuel Patry <[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/19ff10b0786e1d8bdbfa15e0e26fe6081dcbd5d6
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4505
.../errors/rust-builtin-attribute-checker.cc | 248 ++++++++++--------
.../errors/rust-builtin-attribute-checker.h | 3 +
2 files changed, 136 insertions(+), 115 deletions(-)
diff --git a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
index a2bf83f93..f6a2e2c83 100644
--- a/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
+++ b/gcc/rust/checks/errors/rust-builtin-attribute-checker.cc
@@ -80,8 +80,15 @@ check_doc_alias (const std::string &alias_input, const
location_t locus)
"%<#[doc(alias)]%> input cannot start or end with a space");
}
-static void
-check_doc_attribute (const AST::Attribute &attribute)
+// This namespace contains handlers for the builtin attribute checker,
+// those handlers must verify the attribute internal structure and emit the
+// appropriate error message if the structure is incorrect.
+//
+// They DO NOT check the attribute validity on the parent item.
+namespace handlers {
+
+void
+doc (const AST::Attribute &attribute)
{
if (!attribute.has_attr_input ())
{
@@ -125,8 +132,8 @@ check_doc_attribute (const AST::Attribute &attribute)
}
}
-static void
-check_deprecated_attribute (const AST::Attribute &attribute)
+void
+deprecated (const AST::Attribute &attribute)
{
if (!attribute.has_attr_input ())
return;
@@ -219,8 +226,8 @@ check_deprecated_attribute (const AST::Attribute &attribute)
}
}
-static void
-check_link_section_attribute (const AST::Attribute &attribute)
+void
+link_section (const AST::Attribute &attribute)
{
if (!attribute.has_attr_input ())
{
@@ -231,8 +238,8 @@ check_link_section_attribute (const AST::Attribute
&attribute)
}
}
-static void
-check_export_name_attribute (const AST::Attribute &attribute)
+void
+export_name (const AST::Attribute &attribute)
{
if (!attribute.has_attr_input ())
{
@@ -264,34 +271,131 @@ check_export_name_attribute (const AST::Attribute
&attribute)
rust_error_at (attribute.get_locus (), "attribute must be a string literal");
}
-static void
-check_no_mangle_function (const AST::Attribute &attribute,
- const AST::Function &fun)
+void
+lint (const AST::Attribute &attribute)
{
- if (attribute.has_attr_input ())
+ if (!attribute.has_attr_input ())
{
- rust_error_at (attribute.get_locus (), ErrorCode::E0754,
- "malformed %<no_mangle%> attribute input");
+ auto name = attribute.get_path ().as_string ();
+ rust_error_at (attribute.get_locus (), "malformed %qs attribute input",
+ name.c_str ());
rust_inform (attribute.get_locus (),
- "must be of the form: %<#[no_mangle]%>");
+ "must be of the form: %<#[%s(lint1, lint2, ...)]%>",
+ name.c_str ());
}
- if (!is_ascii_only (fun.get_function_name ().as_string ()))
- rust_error_at (fun.get_function_name ().get_locus (),
- "the %<#[no_mangle]%> attribute requires ASCII identifier");
}
+void
+link_name (const AST::Attribute &attribute)
+{
+ if (!attribute.has_attr_input ())
+ {
+ rust_error_at (attribute.get_locus (),
+ "malformed %<link_name%> attribute input");
+ rust_inform (attribute.get_locus (),
+ "must be of the form: %<#[link_name = \"name\"]%>");
+ }
+}
+
+namespace {
+void
+check_crate_type (const AST::Attribute &attribute)
+{
+ if (!Session::get_instance ().options.is_proc_macro ())
+ {
+ auto name = attribute.get_path ().as_string ();
+
+ rust_error_at (attribute.get_locus (),
+ "the %<#[%s]%> attribute is only usable with crates of "
+ "the %<proc-macro%> crate type",
+ name.c_str ());
+ }
+}
+} // namespace
+
static void
-check_lint_attribute (const AST::Attribute &attribute, const char *name)
+proc_macro_derive (const AST::Attribute &attribute)
{
if (!attribute.has_attr_input ())
{
+ auto name = attribute.get_path ().as_string ();
rust_error_at (attribute.get_locus (), "malformed %qs attribute input",
- name);
+ name.c_str ());
+ rust_inform (attribute.get_locus (),
+ "must be of the form: %<#[proc_macro_derive(TraitName, "
+ "/*opt*/ attributes(name1, name2, ...))]%>");
+ }
+ check_crate_type (attribute);
+}
+
+static void
+proc_macro (const AST::Attribute &attribute)
+{
+ check_crate_type (attribute);
+}
+
+static void
+target_feature (const AST::Attribute &attribute)
+{
+ if (!attribute.has_attr_input ())
+ {
+ rust_error_at (attribute.get_locus (),
+ "malformed %<target_feature%> attribute input");
rust_inform (attribute.get_locus (),
- "must be of the form: %<#[%s(lint1, lint2, ...)]%>", name);
+ "must be of the form: %<#[target_feature(enable = "
+ "\"name\")]%>");
}
}
+void
+no_mangle (const AST::Attribute &attribute)
+{
+ if (attribute.has_attr_input ())
+ {
+ rust_error_at (attribute.get_locus (), ErrorCode::E0754,
+ "malformed %<no_mangle%> attribute input");
+ rust_inform (attribute.get_locus (),
+ "must be of the form: %<#[no_mangle]%>");
+ }
+}
+
+} // namespace handlers
+
+const std::unordered_map<std::string, std::function<void (AST::Attribute &)>>
+ attribute_checking_handlers
+ = {{Attrs::DOC, handlers::doc},
+ {Attrs::DEPRECATED, handlers::deprecated},
+ {Attrs::LINK_SECTION, handlers::link_section},
+ {Attrs::EXPORT_NAME, handlers::export_name},
+ {Attrs::NO_MANGLE, handlers::no_mangle},
+ {Attrs::ALLOW, handlers::lint},
+ {"deny", handlers::lint},
+ {"warn", handlers::lint},
+ {"forbid", handlers::lint},
+ {Attrs::LINK_NAME, handlers::link_name},
+ {Attrs::PROC_MACRO_DERIVE, handlers::proc_macro_derive},
+ {Attrs::PROC_MACRO, handlers::proc_macro},
+ {Attrs::PROC_MACRO_ATTRIBUTE, handlers::proc_macro},
+ {Attrs::TARGET_FEATURE, handlers::target_feature}};
+
+tl::optional<std::function<void (AST::Attribute &)>>
+lookup_handler (std::string attr_name)
+{
+ auto res = attribute_checking_handlers.find (attr_name);
+ if (res != attribute_checking_handlers.cend ())
+ return res->second;
+ return tl::nullopt;
+}
+
+static void
+check_no_mangle_function (const AST::Attribute &attribute,
+ const AST::Function &fun)
+{
+ if (!is_ascii_only (fun.get_function_name ().as_string ()))
+ rust_error_at (fun.get_function_name ().get_locus (),
+ "the %<#[no_mangle]%> attribute requires ASCII identifier");
+}
+
/**
* Emit an error when an attribute is attached
* to an incompatable item type. e.g.:
@@ -302,7 +406,7 @@ check_lint_attribute (const AST::Attribute &attribute,
const char *name)
* Note that "#[derive]" is handled
* explicitly in rust-derive.cc
*/
-static void
+void
check_valid_attribute_for_item (const AST::Attribute &attr,
const AST::Item &item)
{
@@ -349,18 +453,9 @@ BuiltinAttributeChecker::visit (AST::Crate &crate)
void
BuiltinAttributeChecker::visit (AST::Attribute &attribute)
{
- if (auto builtin = lookup_builtin (attribute))
- {
- auto result = builtin.value ();
- // TODO: Add checks here for each builtin attribute
- // TODO: Have an enum of builtins as well, switching on strings is
- // annoying and costly
- if (result.name == Attrs::DOC)
- check_doc_attribute (attribute);
- else if (result.name == Attrs::DEPRECATED)
- check_deprecated_attribute (attribute);
- }
-
+ lookup_handler (attribute.get_path ().as_string ()).map ([&] (auto handler) {
+ handler (attribute);
+ });
AST::DefaultASTVisitor::visit (attribute);
}
@@ -385,14 +480,6 @@ BuiltinAttributeChecker::visit (AST::UseDeclaration
&declaration)
void
BuiltinAttributeChecker::visit (AST::Function &function)
{
- auto check_crate_type = [] (const char *name, AST::Attribute &attribute) {
- if (!Session::get_instance ().options.is_proc_macro ())
- rust_error_at (attribute.get_locus (),
- "the %<#[%s]%> attribute is only usable with crates of "
- "the %<proc-macro%> crate type",
- name);
- };
-
BuiltinAttrDefinition result;
for (auto &attribute : function.get_outer_attrs ())
{
@@ -402,37 +489,9 @@ BuiltinAttributeChecker::visit (AST::Function &function)
if (!result)
return;
- auto name = result->name.c_str ();
-
- if (result->name == Attrs::PROC_MACRO_DERIVE)
- {
- if (!attribute.has_attr_input ())
- {
- rust_error_at (attribute.get_locus (),
- "malformed %qs attribute input", name);
- rust_inform (
- attribute.get_locus (),
- "must be of the form: %<#[proc_macro_derive(TraitName, "
- "/*opt*/ attributes(name1, name2, ...))]%>");
- }
- check_crate_type (name, attribute);
- }
- else if (result->name == Attrs::PROC_MACRO
- || result->name == Attrs::PROC_MACRO_ATTRIBUTE)
+ if (result->name == Attrs::TARGET_FEATURE)
{
- check_crate_type (name, attribute);
- }
- else if (result->name == Attrs::TARGET_FEATURE)
- {
- if (!attribute.has_attr_input ())
- {
- rust_error_at (attribute.get_locus (),
- "malformed %<target_feature%> attribute input");
- rust_inform (attribute.get_locus (),
- "must be of the form: %<#[target_feature(enable = "
- "\"name\")]%>");
- }
- else if (!function.get_qualifiers ().is_unsafe ())
+ if (!function.get_qualifiers ().is_unsafe ())
{
rust_error_at (
attribute.get_locus (),
@@ -442,38 +501,7 @@ BuiltinAttributeChecker::visit (AST::Function &function)
}
else if (result->name == Attrs::NO_MANGLE)
{
- if (attribute.has_attr_input ())
- {
- rust_error_at (attribute.get_locus (),
- "malformed %<no_mangle%> attribute input");
- rust_inform (attribute.get_locus (),
- "must be of the form: %<#[no_mangle]%>");
- }
- else
- check_no_mangle_function (attribute, function);
- }
- else if (result->name == Attrs::EXPORT_NAME)
- {
- check_export_name_attribute (attribute);
- }
- else if (result->name == Attrs::ALLOW || result->name == "deny"
- || result->name == "warn" || result->name == "forbid")
- {
- check_lint_attribute (attribute, name);
- }
- else if (result->name == Attrs::LINK_NAME)
- {
- if (!attribute.has_attr_input ())
- {
- rust_error_at (attribute.get_locus (),
- "malformed %<link_name%> attribute input");
- rust_inform (attribute.get_locus (),
- "must be of the form: %<#[link_name = \"name\"]%>");
- }
- }
- else if (result->name == Attrs::LINK_SECTION)
- {
- check_link_section_attribute (attribute);
+ check_no_mangle_function (attribute, function);
}
}
@@ -520,17 +548,7 @@ void
BuiltinAttributeChecker::visit (AST::StaticItem &item)
{
for (auto &attr : item.get_outer_attrs ())
- {
- check_valid_attribute_for_item (attr, item);
-
- if (auto result = lookup_builtin (attr))
- {
- if (result->name == Attrs::LINK_SECTION)
- check_link_section_attribute (attr);
- else if (result->name == Attrs::EXPORT_NAME)
- check_export_name_attribute (attr);
- }
- }
+ check_valid_attribute_for_item (attr, item);
AST::DefaultASTVisitor::visit (item);
}
diff --git a/gcc/rust/checks/errors/rust-builtin-attribute-checker.h
b/gcc/rust/checks/errors/rust-builtin-attribute-checker.h
index 957243a1a..4765e630d 100644
--- a/gcc/rust/checks/errors/rust-builtin-attribute-checker.h
+++ b/gcc/rust/checks/errors/rust-builtin-attribute-checker.h
@@ -24,6 +24,9 @@
namespace Rust {
namespace Analysis {
+void check_valid_attribute_for_item (const AST::Attribute &attr,
+ const AST::Item &item);
+
class BuiltinAttributeChecker : public AST::DefaultASTVisitor
{
using AST::DefaultASTVisitor::visit;
--
2.53.0