gccrs: Handle `async` functions in traits
[official-gcc.git] / gcc / rust / checks / errors / rust-ast-validation.cc
blob0ed5d06089431346bb2706e201cba0f15253c926
1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
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"
25 namespace Rust {
27 void
28 ASTValidation::visit (AST::Lifetime &lifetime)
30 auto name = lifetime.get_lifetime_name ();
31 auto valid = std::set<std::string>{"static", "_"};
32 auto &keywords = Values::Keywords::keywords;
34 if (valid.find (name) == valid.end ()
35 && keywords.find (name) != keywords.end ())
36 rust_error_at (lifetime.get_locus (), "lifetimes cannot use keyword names");
38 AST::ContextualASTVisitor::visit (lifetime);
41 void
42 ASTValidation::visit (AST::LoopLabel &label)
44 auto name = label.get_lifetime ().get_lifetime_name ();
45 auto lifetime_name = '\'' + name;
46 auto &keywords = Values::Keywords::keywords;
47 if (keywords.find (name) != keywords.end ())
48 rust_error_at (label.get_lifetime ().get_locus (), "invalid label name %qs",
49 lifetime_name.c_str ());
51 // WARNING: Do not call ContextualASTVisitor, we don't want to visit the
52 // lifetime
53 // Maybe we should refactor LoopLabel instead ?
56 void
57 ASTValidation::visit (AST::ConstantItem &const_item)
59 if (!const_item.has_expr () && context.back () != Context::TRAIT_IMPL)
61 rust_error_at (const_item.get_locus (),
62 "associated constant in %<impl%> without body");
64 AST::ContextualASTVisitor::visit (const_item);
67 void
68 ASTValidation::visit (AST::ExternalFunctionItem &item)
70 auto &params = item.get_function_params ();
72 if (params.size () == 1 && params[0].is_variadic ())
73 rust_error_at (
74 params[0].get_locus (),
75 "C-variadic function must be declared with at least one named argument");
77 for (auto it = params.begin (); it != params.end (); it++)
78 if (it->is_variadic () && it + 1 != params.end ())
79 rust_error_at (
80 it->get_locus (),
81 "%<...%> must be the last argument of a C-variadic function");
83 AST::ContextualASTVisitor::visit (item);
86 void
87 ASTValidation::visit (AST::Union &item)
89 if (item.get_variants ().empty ())
90 rust_error_at (item.get_locus (), "unions cannot have zero fields");
92 AST::ContextualASTVisitor::visit (item);
95 void
96 ASTValidation::visit (AST::Function &function)
98 std::set<Context> valid_context
99 = {Context::INHERENT_IMPL, Context::TRAIT_IMPL};
101 const auto &qualifiers = function.get_qualifiers ();
102 if (qualifiers.is_async () && qualifiers.is_const ())
103 rust_error_at (function.get_locus (),
104 "functions cannot be both %<const%> and %<async%>");
106 if (qualifiers.is_const () && context.back () == Context::TRAIT_IMPL)
107 rust_error_at (function.get_locus (), ErrorCode::E0379,
108 "functions in traits cannot be declared const");
110 // may change soon
111 if (qualifiers.is_async () && context.back () == Context::TRAIT_IMPL)
112 rust_error_at (function.get_locus (), ErrorCode::E0706,
113 "functions in traits cannot be declared %<async%>");
115 if (valid_context.find (context.back ()) == valid_context.end ()
116 && function.has_self_param ())
117 rust_error_at (
118 function.get_self_param ()->get_locus (),
119 "%<self%> parameter is only allowed in associated functions");
121 if (!function.has_body ())
123 if (context.back () == Context::INHERENT_IMPL
124 || context.back () == Context::TRAIT_IMPL)
125 rust_error_at (function.get_locus (),
126 "associated function in %<impl%> without body");
127 else if (context.back () != Context::TRAIT)
128 rust_error_at (function.get_locus (), "free function without a body");
131 if (function.is_variadic ())
132 rust_error_at (
133 function.get_function_params ().back ()->get_locus (),
134 "only foreign or %<unsafe extern \"C\"%> functions may be C-variadic");
136 AST::ContextualASTVisitor::visit (function);
139 void
140 ASTValidation::visit (AST::TraitFunctionDecl &decl)
142 const auto &qualifiers = decl.get_qualifiers ();
144 if (context.back () == Context::TRAIT)
146 // may change soon
147 if (qualifiers.is_async ())
148 rust_error_at (decl.get_identifier ().get_locus (), ErrorCode::E0706,
149 "functions in traits cannot be declared %<async%>");
150 if (qualifiers.is_const ())
151 rust_error_at (decl.get_identifier ().get_locus (), ErrorCode::E0379,
152 "functions in traits cannot be declared const");
156 void
157 ASTValidation::visit (AST::Trait &trait)
159 if (trait.is_auto ())
161 if (trait.has_generics ())
162 rust_error_at (trait.get_generic_params ()[0]->get_locus (),
163 ErrorCode::E0567,
164 "auto traits cannot have generic parameters");
165 if (trait.has_type_param_bounds ())
166 rust_error_at (trait.get_type_param_bounds ()[0]->get_locus (),
167 ErrorCode::E0568,
168 "auto traits cannot have super traits");
169 if (trait.has_trait_items ())
171 rust_error_at (trait.get_identifier ().get_locus (), ErrorCode::E0380,
172 "auto traits cannot have methods or associated items");
173 for (const auto &item : trait.get_trait_items ())
174 Error::Hint (item->get_locus (), "remove this item").emit ();
178 AST::ContextualASTVisitor::visit (trait);
181 void
182 ASTValidation::visit (AST::Module &module)
184 if (module.get_unsafety () == Unsafety::Unsafe)
185 rust_error_at (module.get_locus (), "module cannot be declared unsafe");
187 AST::ContextualASTVisitor::visit (module);
190 } // namespace Rust