Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-attributes.h"
20 : #include "rust-ast.h"
21 : #include "rust-ast-full.h"
22 : #include "rust-attribute-values.h"
23 :
24 : namespace Rust {
25 : namespace Analysis {
26 :
27 : using Attrs = Values::Attributes;
28 :
29 : // https://doc.rust-lang.org/stable/nightly-rustc/src/rustc_feature/builtin_attrs.rs.html#248
30 : static const BuiltinAttrDefinition __definitions[]
31 : = {{Attrs::INLINE, CODE_GENERATION},
32 : {Attrs::COLD, CODE_GENERATION},
33 : {Attrs::CFG, EXPANSION},
34 : {Attrs::CFG_ATTR, EXPANSION},
35 : {Attrs::DERIVE_ATTR, EXPANSION},
36 : {Attrs::DEPRECATED, STATIC_ANALYSIS},
37 : {Attrs::ALLOW, STATIC_ANALYSIS},
38 : {Attrs::WARN, STATIC_ANALYSIS},
39 : {Attrs::DENY, STATIC_ANALYSIS},
40 : {Attrs::ALLOW_INTERNAL_UNSTABLE, STATIC_ANALYSIS},
41 : {Attrs::DOC, HIR_LOWERING},
42 : {Attrs::MUST_USE, STATIC_ANALYSIS},
43 : {Attrs::LANG, HIR_LOWERING},
44 : {Attrs::LINK_NAME, CODE_GENERATION},
45 : {Attrs::LINK_SECTION, CODE_GENERATION},
46 : {Attrs::NO_MANGLE, CODE_GENERATION},
47 : {Attrs::RUSTC_STD_INTERNAL_SYMBOL, CODE_GENERATION},
48 : {Attrs::EXPORT_NAME, CODE_GENERATION},
49 : {Attrs::REPR, CODE_GENERATION},
50 : {Attrs::RUSTC_BUILTIN_MACRO, EXPANSION},
51 : {Attrs::RUSTC_MACRO_TRANSPARENCY, EXPANSION},
52 : {Attrs::PATH, EXPANSION},
53 : {Attrs::MACRO_USE, NAME_RESOLUTION},
54 : {Attrs::MACRO_EXPORT, NAME_RESOLUTION},
55 : {Attrs::PROC_MACRO, EXPANSION},
56 : {Attrs::PROC_MACRO_DERIVE, EXPANSION},
57 : {Attrs::PROC_MACRO_ATTRIBUTE, EXPANSION},
58 : // FIXME: This is not implemented yet, see
59 : // https://github.com/Rust-GCC/gccrs/issues/1475
60 : {Attrs::TARGET_FEATURE, CODE_GENERATION},
61 : // From now on, these are reserved by the compiler and gated through
62 : // #![feature(rustc_attrs)]
63 : {Attrs::FEATURE, STATIC_ANALYSIS},
64 : {Attrs::NO_CORE, CODE_GENERATION},
65 : {Attrs::NO_STD, CODE_GENERATION},
66 : {Attrs::DOC, EXTERNAL},
67 : {Attrs::CRATE_NAME, CODE_GENERATION},
68 : {Attrs::CRATE_TYPE, CODE_GENERATION},
69 : {Attrs::MAY_DANGLE, STATIC_ANALYSIS},
70 : {Attrs::RUSTC_DEPRECATED, STATIC_ANALYSIS},
71 : {Attrs::RUSTC_INHERIT_OVERFLOW_CHECKS, CODE_GENERATION},
72 : {Attrs::STABLE, STATIC_ANALYSIS},
73 : {Attrs::UNSTABLE, STATIC_ANALYSIS},
74 : // assuming we keep these for static analysis
75 : {Attrs::RUSTC_PROMOTABLE, CODE_GENERATION},
76 : {Attrs::RUSTC_CONST_STABLE, STATIC_ANALYSIS},
77 : {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS},
78 : {Attrs::RUSTC_ALLOW_CONST_FN_UNSTABLE, STATIC_ANALYSIS},
79 : {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION},
80 : {Attrs::TRACK_CALLER, CODE_GENERATION},
81 : {Attrs::RUSTC_SPECIALIZATION_TRAIT, TYPE_CHECK},
82 : {Attrs::RUSTC_UNSAFE_SPECIALIZATION_MARKER, TYPE_CHECK},
83 : {Attrs::RUSTC_RESERVATION_IMPL, TYPE_CHECK},
84 : {Attrs::RUSTC_PAREN_SUGAR, TYPE_CHECK},
85 : {Attrs::RUSTC_NONNULL_OPTIMIZATION_GUARANTEED, TYPE_CHECK},
86 : {Attrs::RUSTC_LAYOUT_SCALAR_VALID_RANGE_START, CODE_GENERATION},
87 : // TODO: be careful about calling functions marked with this?
88 : {Attrs::RUSTC_ARGS_REQUIRED_CONST, CODE_GENERATION},
89 : {Attrs::RUSTC_LEGACY_CONST_GENERICS, TYPE_CHECK},
90 : {Attrs::COMPILER_BUILTINS, CODE_GENERATION},
91 : {Attrs::NO_BUILTINS, CODE_GENERATION},
92 : {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION},
93 : {Attrs::RUSTC_DIAGNOSTIC_ITEM, STATIC_ANALYSIS},
94 : {Attrs::RUSTC_ON_UNIMPLEMENTED, STATIC_ANALYSIS},
95 : {Attrs::FUNDAMENTAL, TYPE_CHECK},
96 : {Attrs::NON_EXHAUSTIVE, TYPE_CHECK},
97 : {Attrs::RUSTFMT, EXTERNAL},
98 : {Attrs::CLIPPY, EXTERNAL},
99 : {Attrs::DIAGNOSTIC, EXTERNAL},
100 : {Attrs::MIRI, EXTERNAL},
101 : {Attrs::RUST_ANALYZER, EXTERNAL},
102 : {Attrs::TEST, CODE_GENERATION},
103 : {Attrs::NEEDS_ALLOCATOR, CODE_GENERATION},
104 : {Attrs::RUSTC_ALLOCATOR, CODE_GENERATION},
105 : {Attrs::RUSTC_ALLOCATOR_NOUNWIND, CODE_GENERATION},
106 : {Attrs::GLOBAL_ALLOCATOR, CODE_GENERATION},
107 : {Attrs::RUSTC_CONVERSION_SUGGESTION, TYPE_CHECK},
108 : {Attrs::CFI_ENCODING, CODE_GENERATION}};
109 :
110 : static const std::set<std::string> __outer_attributes
111 : = {Attrs::INLINE,
112 : Attrs::DERIVE_ATTR,
113 : Attrs::ALLOW_INTERNAL_UNSTABLE,
114 : Attrs::LANG,
115 : Attrs::REPR,
116 : Attrs::PATH,
117 : Attrs::TARGET_FEATURE,
118 : Attrs::TEST,
119 : Attrs::COLD,
120 : Attrs::MACRO_USE,
121 : Attrs::MACRO_EXPORT,
122 : Attrs::PROC_MACRO_ATTRIBUTE,
123 : Attrs::PROC_MACRO_DERIVE,
124 : Attrs::DEPRECATED,
125 : Attrs::MUST_USE,
126 : Attrs::LINK_NAME,
127 : Attrs::LINK_SECTION};
128 :
129 : Attributes::AttributeKnowledge
130 2616273 : Attributes::is_known (const std::string &attribute_path)
131 : {
132 2616273 : const auto &lookup
133 2616273 : = BuiltinAttributeMappings::get ()->lookup_builtin (attribute_path);
134 :
135 2616273 : if (!lookup.is_error ())
136 : return AttributeKnowledge::Known;
137 :
138 : // We have to check for tool attributes as well
139 : // https://doc.rust-lang.org/reference/attributes.html#tool-attributes
140 : //
141 : // > rustc currently recognizes the tools “clippy”, “rustfmt”, “diagnostic”,
142 : // “miri”, and “rust_analyzer”.
143 2 : static std::unordered_set<std::string> known_tools = {
144 : "clippy", "rustfmt", "diagnostic", "miri", "rust_analyzer",
145 2 : };
146 :
147 2 : auto colon = attribute_path.find ("::");
148 2 : if (colon != std::string::npos)
149 : {
150 0 : auto tool = attribute_path.substr (0, colon);
151 :
152 : // If this is a known tool, the attribute is "known". The rest of the path
153 : // is up to the tool to interpret.
154 0 : if (known_tools.find (tool) != known_tools.end ())
155 0 : return AttributeKnowledge::Tool;
156 0 : }
157 :
158 : return AttributeKnowledge::Unknown;
159 : }
160 :
161 : bool
162 12777 : Attributes::valid_outer_attribute (const std::string &attribute_path)
163 : {
164 12777 : return __outer_attributes.find (attribute_path) != __outer_attributes.cend ();
165 : }
166 :
167 : tl::optional<std::string>
168 7579 : Attributes::extract_string_literal (const AST::Attribute &attr)
169 : {
170 7579 : if (!attr.has_attr_input ())
171 0 : return tl::nullopt;
172 :
173 7579 : auto &attr_input = attr.get_attr_input ();
174 :
175 7579 : if (attr_input.get_attr_input_type ()
176 : != AST::AttrInput::AttrInputType::LITERAL)
177 0 : return tl::nullopt;
178 :
179 7579 : auto &literal_expr
180 7579 : = static_cast<AST::AttrInputLiteral &> (attr_input).get_literal ();
181 :
182 7579 : auto lit_type = literal_expr.get_lit_type ();
183 :
184 : // TODO: bring escape sequence handling out of lexing?
185 7579 : if (lit_type != AST::Literal::LitType::STRING
186 7579 : && lit_type != AST::Literal::LitType::RAW_STRING)
187 0 : return tl::nullopt;
188 :
189 7579 : return literal_expr.as_string ();
190 : }
191 : BuiltinAttributeMappings *
192 4355609 : BuiltinAttributeMappings::get ()
193 : {
194 4355609 : static BuiltinAttributeMappings *instance = nullptr;
195 4355609 : if (instance == nullptr)
196 4975 : instance = new BuiltinAttributeMappings ();
197 :
198 4355609 : return instance;
199 : }
200 :
201 : const BuiltinAttrDefinition &
202 3922042 : BuiltinAttributeMappings::lookup_builtin (const std::string &attr_name) const
203 : {
204 3922042 : auto it = mappings.find (attr_name);
205 3922042 : if (it == mappings.end ())
206 4 : return BuiltinAttrDefinition::error_node ();
207 :
208 3922038 : return it->second;
209 : }
210 :
211 4975 : BuiltinAttributeMappings::BuiltinAttributeMappings ()
212 : {
213 4975 : size_t ndefinitions = sizeof (__definitions) / sizeof (BuiltinAttrDefinition);
214 363175 : for (size_t i = 0; i < ndefinitions; i++)
215 : {
216 358200 : const BuiltinAttrDefinition &def = __definitions[i];
217 716400 : mappings.insert ({def.name, def});
218 : }
219 4975 : }
220 :
221 : tl::optional<BuiltinAttrDefinition>
222 92268 : lookup_builtin (const AST::Attribute &attribute)
223 : {
224 92268 : auto &segments = attribute.get_path ().get_segments ();
225 :
226 : // Builtin attributes always have a single segment. This avoids us creating
227 : // strings all over the place and performing a linear search in the builtins
228 : // map
229 92268 : if (segments.size () != 1)
230 6 : return tl::nullopt;
231 :
232 92262 : return BuiltinAttributeMappings::get ()->lookup_builtin (
233 92262 : segments.at (0).get_segment_name ());
234 : }
235 :
236 : } // namespace Analysis
237 : } // namespace Rust
|