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-ast-validation.h"
20 : #include "rust-common.h"
21 : #include "rust-diagnostics.h"
22 : #include "rust-item.h"
23 : #include "rust-keyword-values.h"
24 :
25 : namespace Rust {
26 :
27 : void
28 27933 : ASTValidation::visit (AST::Lifetime &lifetime)
29 : {
30 27933 : auto name = lifetime.get_lifetime_name ();
31 139665 : auto valid = std::set<std::string>{"static", "_"};
32 27933 : auto &keywords = Values::Keywords::keywords;
33 :
34 27933 : if (valid.find (name) == valid.end ()
35 27933 : && keywords.find (name) != keywords.end ())
36 2 : rust_error_at (lifetime.get_locus (), "lifetimes cannot use keyword names");
37 :
38 27933 : AST::ContextualASTVisitor::visit (lifetime);
39 27933 : }
40 :
41 : void
42 98 : ASTValidation::visit (AST::LoopLabel &label)
43 : {
44 98 : auto name = label.get_lifetime ().get_lifetime_name ();
45 98 : auto lifetime_name = '\'' + name;
46 98 : auto &keywords = Values::Keywords::keywords;
47 98 : if (keywords.find (name) != keywords.end ())
48 6 : rust_error_at (label.get_lifetime ().get_locus (), "invalid label name %qs",
49 : lifetime_name.c_str ());
50 :
51 : // WARNING: Do not call ContextualASTVisitor, we don't want to visit the
52 : // lifetime
53 : // Maybe we should refactor LoopLabel instead ?
54 98 : }
55 :
56 : void
57 1357 : ASTValidation::visit (AST::ConstantItem &const_item)
58 : {
59 1357 : if (!const_item.has_expr () && ctx.peek () != Kind::TRAIT)
60 : {
61 2 : rust_error_at (const_item.get_locus (),
62 : "associated constant in %<impl%> without body");
63 : }
64 1357 : AST::ContextualASTVisitor::visit (const_item);
65 1357 : }
66 :
67 : void
68 116 : ASTValidation::visit (AST::Union &item)
69 : {
70 116 : if (item.get_variants ().empty ())
71 1 : rust_error_at (item.get_locus (), "unions cannot have zero fields");
72 :
73 116 : AST::ContextualASTVisitor::visit (item);
74 116 : }
75 :
76 : void
77 35043 : ASTValidation::visit (AST::Function &function)
78 : {
79 35043 : const auto &qualifiers = function.get_qualifiers ();
80 35043 : if (qualifiers.is_default () && ctx.peek () != Kind::INHERENT_IMPL
81 35114 : && ctx.peek () != Kind::TRAIT_IMPL)
82 1 : rust_error_at (
83 : function.get_locus (),
84 : "%<default%> is only allowed on items within %<impl%> blocks");
85 35043 : if (qualifiers.is_async () && qualifiers.is_const ())
86 1 : rust_error_at (function.get_locus (),
87 : "functions cannot be both %<const%> and %<async%>");
88 :
89 35043 : if (qualifiers.is_const ()
90 35043 : && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT))
91 2 : rust_error_at (function.get_locus (), ErrorCode::E0379,
92 : "functions in traits cannot be declared %<const%>");
93 :
94 : // may change soon
95 35043 : if (qualifiers.is_async ()
96 35043 : && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT))
97 3 : rust_error_at (function.get_locus (), ErrorCode::E0706,
98 : "functions in traits cannot be declared %<async%>");
99 :
100 : // if not an associated function but has a self parameter
101 35043 : if (ctx.peek () != Kind::TRAIT && ctx.peek () != Kind::TRAIT_IMPL
102 13028 : && ctx.peek () != Kind::INHERENT_IMPL && function.has_self_param ())
103 1 : rust_error_at (
104 1 : function.get_self_param ().get_locus (),
105 : "%<self%> parameter is only allowed in associated functions");
106 :
107 : // functions without bodies can only have very specific
108 : // kinds of patterns in their parameters
109 35043 : auto is_param_complex_with_loc
110 8878 : = [] (AST::Param ¶m) -> tl::optional<location_t> {
111 8878 : tl::optional<location_t> ret;
112 :
113 8878 : if (param.is_self () || param.is_variadic ())
114 2772 : return ret;
115 :
116 6106 : auto &fn_param = static_cast<AST::FunctionParam &> (param);
117 6106 : if (!fn_param.has_name ())
118 0 : return ret;
119 :
120 6106 : auto &pat = fn_param.get_pattern ();
121 6106 : ret = pat.get_locus ();
122 6106 : auto kind = pat.get_pattern_kind ();
123 6106 : if (kind == AST::Pattern::Kind::Identifier)
124 : {
125 5952 : auto &ident_pat = static_cast<AST::IdentifierPattern &> (pat);
126 5952 : if (!ident_pat.get_is_ref () && !ident_pat.get_is_mut ()
127 11900 : && !ident_pat.has_subpattern ())
128 : ret = tl::nullopt;
129 : }
130 154 : else if (kind == AST::Pattern::Kind::Wildcard)
131 : ret = tl::nullopt;
132 :
133 6106 : return ret;
134 : };
135 :
136 35043 : if (function.is_external ())
137 : {
138 3546 : if (function.has_body ())
139 1 : rust_error_at (function.get_locus (), "cannot have a body");
140 :
141 3546 : auto ¶ms = function.get_function_params ();
142 :
143 3546 : if (params.size () == 1 && function.is_variadic ())
144 1 : rust_error_at (function.get_locus (),
145 : "C-variadic function must be declared with at least one "
146 : "named argument");
147 :
148 9343 : for (auto it = params.begin (); it != params.end (); it++)
149 : {
150 5797 : if (it->get ()->is_variadic () && it + 1 != params.end ())
151 1 : rust_error_at (
152 : it->get ()->get_locus (),
153 : "%<...%> must be the last argument of a C-variadic function");
154 :
155 5797 : if (auto pat_loc = is_param_complex_with_loc (**it))
156 5 : rust_error_at (*pat_loc, ErrorCode::E0130,
157 : "pattern not allowed in foreign function");
158 : }
159 : }
160 : else
161 : {
162 31497 : if (!function.has_body ())
163 : {
164 2198 : if (ctx.peek () == Kind::INHERENT_IMPL
165 2198 : || ctx.peek () == Kind::TRAIT_IMPL)
166 3 : rust_error_at (function.get_locus (),
167 : "associated function in %<impl%> without body");
168 2195 : else if (ctx.peek () != Kind::TRAIT)
169 3 : rust_error_at (function.get_locus (),
170 : "free function without a body");
171 : }
172 31497 : auto &function_params = function.get_function_params ();
173 73850 : for (auto it = function_params.begin (); it != function_params.end ();
174 42353 : it++)
175 : {
176 42353 : if (it->get ()->is_variadic ())
177 4 : rust_error_at (
178 : it->get ()->get_locus (),
179 : "only foreign or %<unsafe extern \"C\"%> functions may "
180 : "be C-variadic");
181 :
182 42353 : if (!function.has_body ())
183 3081 : if (auto pat_loc = is_param_complex_with_loc (**it))
184 5 : rust_error_at (*pat_loc, ErrorCode::E0642,
185 : "pattern not allowed in function without body");
186 : }
187 : }
188 :
189 35043 : AST::ContextualASTVisitor::visit (function);
190 35043 : }
191 :
192 : void
193 4546 : ASTValidation::visit (AST::Trait &trait)
194 : {
195 4546 : if (trait.is_auto ())
196 : {
197 30 : if (trait.has_generics ())
198 1 : rust_error_at (trait.get_generic_params ()[0]->get_locus (),
199 : ErrorCode::E0567,
200 : "auto traits cannot have generic parameters");
201 30 : if (trait.has_type_param_bounds ())
202 1 : rust_error_at (trait.get_type_param_bounds ()[0]->get_locus (),
203 : ErrorCode::E0568,
204 : "auto traits cannot have super traits");
205 30 : if (trait.has_trait_items ())
206 : {
207 1 : rust_error_at (trait.get_identifier ().get_locus (), ErrorCode::E0380,
208 : "auto traits cannot have methods or associated items");
209 6 : for (const auto &item : trait.get_trait_items ())
210 5 : Error::Hint (item->get_locus (), "remove this item").emit ();
211 : }
212 : }
213 :
214 4546 : AST::ContextualASTVisitor::visit (trait);
215 4546 : }
216 :
217 : void
218 1732 : ASTValidation::visit (AST::Module &module)
219 : {
220 1732 : if (module.get_unsafety () == Unsafety::Unsafe)
221 1 : rust_error_at (module.get_locus (), "module cannot be declared unsafe");
222 :
223 1732 : AST::ContextualASTVisitor::visit (module);
224 1732 : }
225 :
226 : void
227 111 : ASTValidation::visit (AST::SlicePattern &pattern)
228 : {
229 : // TODO: store/use first rest pattern location?
230 : // for nicer errors
231 111 : bool had_rest = false;
232 :
233 174 : auto note_rest = [&] (location_t locus) {
234 63 : if (had_rest)
235 0 : rust_error_at (locus, "%<..%> can only be used once per slice pattern");
236 63 : had_rest = true;
237 174 : };
238 :
239 381 : for (auto &pat : pattern.get_patterns ())
240 : {
241 270 : if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
242 : {
243 58 : note_rest (pat->get_locus ());
244 : }
245 212 : else if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier)
246 : {
247 96 : auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat);
248 96 : if (ident_pat.has_subpattern ())
249 : {
250 5 : auto &ident_sub_pat = ident_pat.get_subpattern ();
251 5 : if (ident_sub_pat.get_pattern_kind () == AST::Pattern::Kind::Rest)
252 5 : note_rest (ident_sub_pat.get_locus ());
253 : }
254 : }
255 : }
256 111 : }
257 :
258 : } // namespace Rust
|