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 9448 : ASTValidation::visit (AST::Lifetime &lifetime)
29 : {
30 9448 : auto name = lifetime.get_lifetime_name ();
31 47240 : auto valid = std::set<std::string>{"static", "_"};
32 9448 : auto &keywords = Values::Keywords::keywords;
33 :
34 9448 : if (valid.find (name) == valid.end ()
35 9448 : && keywords.find (name) != keywords.end ())
36 2 : rust_error_at (lifetime.get_locus (), "lifetimes cannot use keyword names");
37 :
38 9448 : AST::ContextualASTVisitor::visit (lifetime);
39 9448 : }
40 :
41 : void
42 63 : ASTValidation::visit (AST::LoopLabel &label)
43 : {
44 63 : auto name = label.get_lifetime ().get_lifetime_name ();
45 63 : auto lifetime_name = '\'' + name;
46 63 : auto &keywords = Values::Keywords::keywords;
47 63 : 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 63 : }
55 :
56 : void
57 578 : ASTValidation::visit (AST::ConstantItem &const_item)
58 : {
59 578 : 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 578 : AST::ContextualASTVisitor::visit (const_item);
65 578 : }
66 :
67 : void
68 107 : ASTValidation::visit (AST::Union &item)
69 : {
70 107 : if (item.get_variants ().empty ())
71 1 : rust_error_at (item.get_locus (), "unions cannot have zero fields");
72 :
73 107 : AST::ContextualASTVisitor::visit (item);
74 107 : }
75 :
76 : void
77 18285 : ASTValidation::visit (AST::Function &function)
78 : {
79 18285 : const auto &qualifiers = function.get_qualifiers ();
80 18285 : if (qualifiers.is_async () && qualifiers.is_const ())
81 1 : rust_error_at (function.get_locus (),
82 : "functions cannot be both %<const%> and %<async%>");
83 :
84 18285 : if (qualifiers.is_const ()
85 18285 : && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT))
86 2 : rust_error_at (function.get_locus (), ErrorCode::E0379,
87 : "functions in traits cannot be declared %<const%>");
88 :
89 : // may change soon
90 18285 : if (qualifiers.is_async ()
91 18285 : && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT))
92 3 : rust_error_at (function.get_locus (), ErrorCode::E0706,
93 : "functions in traits cannot be declared %<async%>");
94 :
95 : // if not an associated function but has a self parameter
96 18285 : if (ctx.peek () != Kind::TRAIT && ctx.peek () != Kind::TRAIT_IMPL
97 8769 : && ctx.peek () != Kind::INHERENT_IMPL && function.has_self_param ())
98 0 : rust_error_at (
99 0 : function.get_self_param ().get_locus (),
100 : "%<self%> parameter is only allowed in associated functions");
101 :
102 18285 : if (function.is_external ())
103 : {
104 2212 : if (function.has_body ())
105 1 : rust_error_at (function.get_locus (), "cannot have a body");
106 :
107 2212 : auto ¶ms = function.get_function_params ();
108 :
109 2212 : if (params.size () == 1 && function.is_variadic ())
110 1 : rust_error_at (function.get_locus (),
111 : "C-variadic function must be declared with at least one "
112 : "named argument");
113 :
114 5733 : for (auto it = params.begin (); it != params.end (); it++)
115 : {
116 3521 : if (it->get ()->is_variadic () && it + 1 != params.end ())
117 1 : rust_error_at (
118 : it->get ()->get_locus (),
119 : "%<...%> must be the last argument of a C-variadic function");
120 :
121 : // if functional parameter
122 3521 : if (!it->get ()->is_self () && !it->get ()->is_variadic ())
123 : {
124 2688 : auto ¶m = static_cast<AST::FunctionParam &> (**it);
125 2688 : auto kind = param.get_pattern ().get_pattern_kind ();
126 :
127 2688 : if (kind != AST::Pattern::Kind::Identifier
128 2688 : && kind != AST::Pattern::Kind::Wildcard)
129 0 : rust_error_at (it->get ()->get_locus (), ErrorCode::E0130,
130 : "pattern not allowed in foreign function");
131 : }
132 : }
133 : }
134 :
135 : else
136 : {
137 16073 : if (!function.has_body ())
138 : {
139 1705 : if (ctx.peek () == Kind::INHERENT_IMPL
140 1705 : || ctx.peek () == Kind::TRAIT_IMPL)
141 3 : rust_error_at (function.get_locus (),
142 : "associated function in %<impl%> without body");
143 1702 : else if (ctx.peek () != Kind::TRAIT)
144 1 : rust_error_at (function.get_locus (),
145 : "free function without a body");
146 : }
147 16073 : auto &function_params = function.get_function_params ();
148 32183 : for (auto it = function_params.begin (); it != function_params.end ();
149 16110 : it++)
150 : {
151 16110 : if (it->get ()->is_variadic ())
152 4 : rust_error_at (
153 : it->get ()->get_locus (),
154 : "only foreign or %<unsafe extern \"C\"%> functions may "
155 : "be C-variadic");
156 : }
157 : }
158 :
159 18285 : AST::ContextualASTVisitor::visit (function);
160 18285 : }
161 :
162 : void
163 3736 : ASTValidation::visit (AST::Trait &trait)
164 : {
165 3736 : if (trait.is_auto ())
166 : {
167 20 : if (trait.has_generics ())
168 1 : rust_error_at (trait.get_generic_params ()[0]->get_locus (),
169 : ErrorCode::E0567,
170 : "auto traits cannot have generic parameters");
171 20 : if (trait.has_type_param_bounds ())
172 1 : rust_error_at (trait.get_type_param_bounds ()[0]->get_locus (),
173 : ErrorCode::E0568,
174 : "auto traits cannot have super traits");
175 20 : if (trait.has_trait_items ())
176 : {
177 1 : rust_error_at (trait.get_identifier ().get_locus (), ErrorCode::E0380,
178 : "auto traits cannot have methods or associated items");
179 6 : for (const auto &item : trait.get_trait_items ())
180 5 : Error::Hint (item->get_locus (), "remove this item").emit ();
181 : }
182 : }
183 :
184 3736 : AST::ContextualASTVisitor::visit (trait);
185 3736 : }
186 :
187 : void
188 1305 : ASTValidation::visit (AST::Module &module)
189 : {
190 1305 : if (module.get_unsafety () == Unsafety::Unsafe)
191 1 : rust_error_at (module.get_locus (), "module cannot be declared unsafe");
192 :
193 1305 : AST::ContextualASTVisitor::visit (module);
194 1305 : }
195 :
196 : } // namespace Rust
|