Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ast validation trait const #2753

Merged
merged 6 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gcc/rust/ast/rust-ast-builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ AstBuilder::tuple_idx (std::string receiver, int idx)
FunctionQualifiers
AstBuilder::fn_qualifiers ()
{
return FunctionQualifiers (loc, AsyncConstStatus::NONE, false);
return FunctionQualifiers (loc, Async::No, Const::No, Unsafety::Normal);
}

PathExprSegment
Expand Down
16 changes: 4 additions & 12 deletions gcc/rust/ast/rust-ast-collector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -317,18 +317,10 @@ TokenCollector::visit (FunctionQualifiers &qualifiers)
// `const`? `async`? `unsafe`? (`extern` Abi?)?
// unsafe? (extern Abi?)?

switch (qualifiers.get_const_status ())
{
case NONE:
break;
case CONST_FN:
push (Rust::Token::make (CONST, qualifiers.get_locus ()));
break;
case ASYNC_FN:
push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
break;
}

if (qualifiers.is_async ())
push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
if (qualifiers.is_const ())
push (Rust::Token::make (CONST, qualifiers.get_locus ()));
if (qualifiers.is_unsafe ())
push (Rust::Token::make (UNSAFE, qualifiers.get_locus ()));
if (qualifiers.is_extern ())
Expand Down
21 changes: 5 additions & 16 deletions gcc/rust/ast/rust-ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2333,22 +2333,11 @@ FunctionQualifiers::as_string () const
{
std::string str;

switch (const_status)
{
case NONE:
// do nothing
break;
case CONST_FN:
str += "const ";
break;
case ASYNC_FN:
str += "async ";
break;
default:
return "ERROR_MARK_STRING: async-const status failure";
}

if (has_unsafe)
if (is_async ())
str += "async ";
if (is_const ())
str += "const ";
if (is_unsafe ())
str += "unsafe ";

if (has_extern)
Expand Down
22 changes: 13 additions & 9 deletions gcc/rust/ast/rust-item.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,19 +533,20 @@ class SelfParam : public Param
// Qualifiers for function, i.e. const, unsafe, extern etc.
class FunctionQualifiers
{
AsyncConstStatus const_status;
bool has_unsafe;
Async async_status;
Const const_status;
Unsafety unsafe_status;
bool has_extern;
std::string extern_abi;
location_t locus;

public:
FunctionQualifiers (location_t locus, AsyncConstStatus const_status,
bool has_unsafe, bool has_extern = false,
FunctionQualifiers (location_t locus, Async async_status, Const const_status,
Unsafety unsafe_status, bool has_extern = false,
std::string extern_abi = std::string ())
: const_status (const_status), has_unsafe (has_unsafe),
has_extern (has_extern), extern_abi (std::move (extern_abi)),
locus (locus)
: async_status (async_status), const_status (const_status),
unsafe_status (unsafe_status), has_extern (has_extern),
extern_abi (std::move (extern_abi)), locus (locus)
{
if (!this->extern_abi.empty ())
{
Expand All @@ -556,11 +557,14 @@ class FunctionQualifiers

std::string as_string () const;

AsyncConstStatus get_const_status () const { return const_status; }
bool is_unsafe () const { return has_unsafe; }
bool is_unsafe () const { return unsafe_status == Unsafety::Unsafe; }
bool is_extern () const { return has_extern; }
bool is_const () const { return const_status == Const::Yes; }
bool is_async () const { return async_status == Async::Yes; }
std::string get_extern_abi () const { return extern_abi; }
bool has_abi () const { return !extern_abi.empty (); }
Const get_const_status () const { return const_status; }
Async get_async_status () const { return async_status; }

location_t get_locus () const { return locus; }
};
Expand Down
15 changes: 15 additions & 0 deletions gcc/rust/checks/errors/rust-ast-validation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ ASTValidation::visit (AST::Function &function)
std::set<Context> valid_context
= {Context::INHERENT_IMPL, Context::TRAIT_IMPL};

const auto &qualifiers = function.get_qualifiers ();
if (qualifiers.is_async () && qualifiers.is_const ())
rust_error_at (function.get_locus (),
"functions cannot be both %<const%> and %<async%>");

if (valid_context.find (context.back ()) == valid_context.end ()
&& function.has_self_param ())
rust_error_at (
Expand All @@ -111,6 +116,16 @@ ASTValidation::visit (AST::Function &function)
AST::ContextualASTVisitor::visit (function);
}

void
ASTValidation::visit (AST::TraitFunctionDecl &decl)
{
const auto &qualifiers = decl.get_qualifiers ();

if (context.back () == Context::TRAIT && qualifiers.is_const ())
rust_error_at (decl.get_identifier ().get_locus (), ErrorCode::E0379,
"functions in traits cannot be declared const");
Comment on lines +125 to +126
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can add the same check for async functions, even if that is about to change soon. but probably in another PR is better

}

void
ASTValidation::visit (AST::Trait &trait)
{
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/checks/errors/rust-ast-validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ASTValidation : public AST::ContextualASTVisitor
virtual void visit (AST::Union &item);
virtual void visit (AST::Function &function);
virtual void visit (AST::Trait &trait);
virtual void visit (AST::TraitFunctionDecl &decl);
};

} // namespace Rust
Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/hir/rust-ast-lower-base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,8 @@ ASTLoweringBase::lower_qualifiers (const AST::FunctionQualifiers &qualifiers)
"invalid ABI: found %qs", extern_abi.c_str ());
}

return HIR::FunctionQualifiers (qualifiers.get_const_status (), unsafety,
return HIR::FunctionQualifiers (qualifiers.get_async_status (),
qualifiers.get_const_status (), unsafety,
has_extern, abi);
}

Expand Down
14 changes: 8 additions & 6 deletions gcc/rust/hir/tree/rust-hir-item.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,24 +481,26 @@ struct SelfParam
struct FunctionQualifiers
{
private:
AsyncConstStatus const_status;
Async async_status;
Const const_status;
Unsafety unsafety;
bool has_extern;
ABI abi;

public:
FunctionQualifiers (AsyncConstStatus const_status, Unsafety unsafety,
FunctionQualifiers (Async async_status, Const const_status, Unsafety unsafety,
bool has_extern, ABI abi)
: const_status (const_status), unsafety (unsafety), has_extern (has_extern),
abi (abi)
: async_status (async_status), const_status (const_status),
unsafety (unsafety), has_extern (has_extern), abi (abi)
{}

std::string as_string () const;

AsyncConstStatus get_status () const { return const_status; }
Const get_const_status () const { return const_status; }

bool is_const () const { return const_status == AsyncConstStatus::CONST_FN; }
bool is_const () const { return const_status == Const::Yes; }
bool is_unsafe () const { return unsafety == Unsafety::Unsafe; }
bool is_async () const { return async_status == Async::Yes; }

ABI get_abi () const { return abi; }
};
Expand Down
25 changes: 6 additions & 19 deletions gcc/rust/hir/tree/rust-hir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1947,25 +1947,12 @@ FunctionQualifiers::as_string () const
{
std::string str;

switch (const_status)
{
case NONE:
// do nothing
break;
case CONST_FN:
str += "const ";
break;
case ASYNC_FN:
str += "async ";
break;
default:
return "ERROR_MARK_STRING: async-const status failure";
}

if (unsafety == Unsafety::Unsafe)
{
str += "unsafe ";
}
if (is_const ())
str += "const ";
if (is_async ())
str += "async ";
if (is_unsafe ())
str += "unsafe ";

if (has_extern)
{
Expand Down
54 changes: 33 additions & 21 deletions gcc/rust/parse/rust-parse-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* This is also the reason why there are no include guards. */

#include "rust-item.h"
#include "rust-common.h"
#include "rust-token.h"
#define INCLUDE_ALGORITHM
#include "rust-diagnostics.h"
Expand Down Expand Up @@ -1381,6 +1382,8 @@ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
return parse_const_item (std::move (vis), std::move (outer_attrs));
case UNSAFE:
case EXTERN_KW:
case ASYNC:
return parse_async_item (std::move (vis), std::move (outer_attrs));
case FN_KW:
return parse_function (std::move (vis), std::move (outer_attrs));
default:
Expand Down Expand Up @@ -1441,7 +1444,9 @@ std::unique_ptr<AST::Function>
Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
AST::AttrVec outer_attrs)
{
const_TokenPtr t = lexer.peek_token ();
auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
const_TokenPtr t = lexer.peek_token (offset);

if (Session::get_instance ().options.get_edition ()
== CompileOptions::Edition::E2015)
{
Expand All @@ -1452,7 +1457,7 @@ Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
"to use %<async fn%>, switch to Rust 2018 or later"));
}

t = lexer.peek_token (1);
t = lexer.peek_token (offset + 1);

switch (t->get_id ())
{
Expand Down Expand Up @@ -2976,33 +2981,40 @@ template <typename ManagedTokenSource>
AST::FunctionQualifiers
Parser<ManagedTokenSource>::parse_function_qualifiers ()
{
AsyncConstStatus const_status = NONE;
bool has_unsafe = false;
Async async_status = Async::No;
Const const_status = Const::No;
Unsafety unsafe_status = Unsafety::Normal;
bool has_extern = false;
std::string abi;

const_TokenPtr t;
location_t locus;
// Check in order of const, unsafe, then extern
const_TokenPtr t = lexer.peek_token ();
location_t locus = t->get_locus ();
switch (t->get_id ())
for (int i = 0; i < 2; i++)
{
case CONST:
lexer.skip_token ();
const_status = CONST_FN;
break;
case ASYNC:
lexer.skip_token ();
const_status = ASYNC_FN;
break;
default:
// const status is still none
break;
t = lexer.peek_token ();
locus = t->get_locus ();

switch (t->get_id ())
{
case CONST:
lexer.skip_token ();
const_status = Const::Yes;
break;
case ASYNC:
lexer.skip_token ();
async_status = Async::Yes;
break;
default:
// const status is still none
break;
}
}

if (lexer.peek_token ()->get_id () == UNSAFE)
{
lexer.skip_token ();
has_unsafe = true;
unsafe_status = Unsafety::Unsafe;
}

if (lexer.peek_token ()->get_id () == EXTERN_KW)
Expand All @@ -3019,8 +3031,8 @@ Parser<ManagedTokenSource>::parse_function_qualifiers ()
}
}

return AST::FunctionQualifiers (locus, const_status, has_unsafe, has_extern,
std::move (abi));
return AST::FunctionQualifiers (locus, async_status, const_status,
unsafe_status, has_extern, std::move (abi));
}

// Parses generic (lifetime or type) params inside angle brackets (optional).
Expand Down
16 changes: 14 additions & 2 deletions gcc/rust/util/rust-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,30 @@

namespace Rust {

enum Mutability
enum class Mutability
{
Imm,
Mut
};

enum Unsafety
enum class Unsafety
{
Unsafe,
Normal
};

enum class Const
{
Yes,
No,
};

enum class Async
{
Yes,
No
};

enum BoundPolarity
{
RegularBound,
Expand Down
3 changes: 3 additions & 0 deletions gcc/testsuite/rust/compile/const_async_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// { dg-additional-options "-frust-edition=2018" }
const async fn weird_function() {}
// { dg-error "functions cannot be both .const. and .async." "" { target *-*-* } .-1 }
4 changes: 4 additions & 0 deletions gcc/testsuite/rust/compile/const_trait_fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
trait Osterkz {
const fn x();
// { dg-error "functions in traits cannot be declared const .E0379." "" { target *-*-* } .-1 }
}