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