// Copyright (C) 2020-2025 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-ast-validation.h" #include "rust-common.h" #include "rust-diagnostics.h" #include "rust-item.h" #include "rust-keyword-values.h" namespace Rust { void ASTValidation::visit (AST::Lifetime &lifetime) { auto name = lifetime.get_lifetime_name (); auto valid = std::set{"static", "_"}; auto &keywords = Values::Keywords::keywords; if (valid.find (name) == valid.end () && keywords.find (name) != keywords.end ()) rust_error_at (lifetime.get_locus (), "lifetimes cannot use keyword names"); AST::ContextualASTVisitor::visit (lifetime); } void ASTValidation::visit (AST::LoopLabel &label) { auto name = label.get_lifetime ().get_lifetime_name (); auto lifetime_name = '\'' + name; auto &keywords = Values::Keywords::keywords; if (keywords.find (name) != keywords.end ()) rust_error_at (label.get_lifetime ().get_locus (), "invalid label name %qs", lifetime_name.c_str ()); // WARNING: Do not call ContextualASTVisitor, we don't want to visit the // lifetime // Maybe we should refactor LoopLabel instead ? } void ASTValidation::visit (AST::ConstantItem &const_item) { if (!const_item.has_expr () && ctx.peek () != Kind::TRAIT_IMPL) { rust_error_at (const_item.get_locus (), "associated constant in % without body"); } AST::ContextualASTVisitor::visit (const_item); } void ASTValidation::visit (AST::Union &item) { if (item.get_variants ().empty ()) rust_error_at (item.get_locus (), "unions cannot have zero fields"); AST::ContextualASTVisitor::visit (item); } void ASTValidation::visit (AST::Function &function) { const auto &qualifiers = function.get_qualifiers (); if (qualifiers.is_async () && qualifiers.is_const ()) rust_error_at (function.get_locus (), "functions cannot be both % and %"); if (qualifiers.is_const () && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT)) rust_error_at (function.get_locus (), ErrorCode::E0379, "functions in traits cannot be declared %"); // may change soon if (qualifiers.is_async () && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT)) rust_error_at (function.get_locus (), ErrorCode::E0706, "functions in traits cannot be declared %"); // if not an associated function but has a self parameter if (ctx.peek () != Kind::TRAIT && ctx.peek () != Kind::TRAIT_IMPL && ctx.peek () != Kind::INHERENT_IMPL && function.has_self_param ()) rust_error_at ( function.get_self_param ().get_locus (), "% parameter is only allowed in associated functions"); if (function.is_external ()) { if (function.has_body ()) rust_error_at (function.get_locus (), "cannot have a body"); auto ¶ms = function.get_function_params (); if (params.size () == 1 && function.is_variadic ()) rust_error_at (function.get_locus (), "C-variadic function must be declared with at least one " "named argument"); for (auto it = params.begin (); it != params.end (); it++) { if (it->get ()->is_variadic () && it + 1 != params.end ()) rust_error_at ( it->get ()->get_locus (), "%<...%> must be the last argument of a C-variadic function"); // if functional parameter if (!it->get ()->is_self () && !it->get ()->is_variadic ()) { auto ¶m = static_cast (**it); auto kind = param.get_pattern ().get_pattern_kind (); if (kind != AST::Pattern::Kind::Identifier && kind != AST::Pattern::Kind::Wildcard) rust_error_at (it->get ()->get_locus (), ErrorCode::E0130, "pattern not allowed in foreign function"); } } } else { if (!function.has_body ()) { if (ctx.peek () == Kind::INHERENT_IMPL || ctx.peek () == Kind::TRAIT_IMPL) rust_error_at (function.get_locus (), "associated function in % without body"); else if (ctx.peek () != Kind::TRAIT) rust_error_at (function.get_locus (), "free function without a body"); } auto &function_params = function.get_function_params (); for (auto it = function_params.begin (); it != function_params.end (); it++) { if (it->get ()->is_variadic ()) rust_error_at ( it->get ()->get_locus (), "only foreign or % functions may " "be C-variadic"); } } AST::ContextualASTVisitor::visit (function); } void ASTValidation::visit (AST::Trait &trait) { if (trait.is_auto ()) { if (trait.has_generics ()) rust_error_at (trait.get_generic_params ()[0]->get_locus (), ErrorCode::E0567, "auto traits cannot have generic parameters"); if (trait.has_type_param_bounds ()) rust_error_at (trait.get_type_param_bounds ()[0]->get_locus (), ErrorCode::E0568, "auto traits cannot have super traits"); if (trait.has_trait_items ()) { rust_error_at (trait.get_identifier ().get_locus (), ErrorCode::E0380, "auto traits cannot have methods or associated items"); for (const auto &item : trait.get_trait_items ()) Error::Hint (item->get_locus (), "remove this item").emit (); } } AST::ContextualASTVisitor::visit (trait); } void ASTValidation::visit (AST::Module &module) { if (module.get_unsafety () == Unsafety::Unsafe) rust_error_at (module.get_locus (), "module cannot be declared unsafe"); AST::ContextualASTVisitor::visit (module); } } // namespace Rust