diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-07-22 13:40:06 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-22 13:40:06 +0000 |
commit | dec7ee4c5e703422ecb9bc94417645d66af7eaae (patch) | |
tree | 3aea5c56255e3cd08ff7ac851e7da4c789e40894 | |
parent | 15d4bdd84a7aca62bceb9dead770fd1df4759360 (diff) | |
parent | 8dc692afc2c86cbf3b5124484dd2596514a5acf3 (diff) | |
download | gcc-dec7ee4c5e703422ecb9bc94417645d66af7eaae.zip gcc-dec7ee4c5e703422ecb9bc94417645d66af7eaae.tar.gz gcc-dec7ee4c5e703422ecb9bc94417645d66af7eaae.tar.bz2 |
Merge #1406
1406: Add Attribute checking visitor r=CohenArthur a=CohenArthur
This PR adds a new attribute checker visitor. Its role is to take care of validating builtin attributes and their inputs.
This is currently a draft as there are multiple issues:
1. The visitor is not complete
2. The lexer is broken, but was also broken before in that it didn't allow multiline string literals. There is a FIXME asking for how to check for an `EOF` character when parsing UTF-8 strings
3. The checking of attributes is very limited. Currently, only the `#[doc(alias = "...")]` is being checked. This is incomplete.
I'm looking for feedback on the implementation and advice for my issues. Thanks :)
Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-base.cc | 2 | ||||
-rw-r--r-- | gcc/rust/lex/rust-codepoint.h | 4 | ||||
-rw-r--r-- | gcc/rust/lex/rust-lex.cc | 49 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 3 | ||||
-rw-r--r-- | gcc/rust/util/rust-attributes.cc | 767 | ||||
-rw-r--r-- | gcc/rust/util/rust-attributes.h | 200 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs | 11 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/undended-string-1.rs | 5 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/undended-string-2.rs | 5 |
9 files changed, 1023 insertions, 23 deletions
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index e31b95b..cae4428 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -872,6 +872,8 @@ ASTLoweringBase::handle_doc_item_attribute (const HIR::Item &item, AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item (); // TODO: add actual and complete checks for the doc attributes + // + // FIXME: Move this to the AttributeChecker visitor rust_assert (meta_item); } diff --git a/gcc/rust/lex/rust-codepoint.h b/gcc/rust/lex/rust-codepoint.h index cdadfcd..22da080 100644 --- a/gcc/rust/lex/rust-codepoint.h +++ b/gcc/rust/lex/rust-codepoint.h @@ -32,11 +32,13 @@ struct Codepoint // Creates a codepoint from an encoded UTF-8 value. Codepoint (uint32_t value) : value (value) {} + static Codepoint eof () { return Codepoint (UINT32_MAX); } + bool is_eof () const { return value == UINT32_MAX; } + // Returns a C++ string containing string value of codepoint. std::string as_string (); bool operator== (Codepoint other) const { return value == other.value; } - bool operator!= (Codepoint other) const { return !operator== (other); } }; } // namespace Rust diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc index ecf151d..70e6b50 100644 --- a/gcc/rust/lex/rust-lex.cc +++ b/gcc/rust/lex/rust-lex.cc @@ -1696,7 +1696,7 @@ Lexer::parse_byte_string (Location loc) int length = 1; current_char = peek_input (); - while (current_char != '"' && current_char != '\n') + while (current_char != '"' && current_char != EOF) { if (current_char == '\\') { @@ -1723,17 +1723,18 @@ Lexer::parse_byte_string (Location loc) current_column += length; - if (current_char == '\n') - { - rust_error_at (get_current_location (), "unended byte string literal"); - } - else if (current_char == '"') + if (current_char == '"') { current_column++; skip_input (); current_char = peek_input (); } + else if (current_char == EOF) + { + rust_error_at (get_current_location (), "unended byte string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } else { gcc_unreachable (); @@ -1917,7 +1918,8 @@ Lexer::parse_string (Location loc) int length = 1; current_char32 = peek_codepoint_input (); - while (current_char32.value != '\n' && current_char32.value != '"') + // FIXME: This fails if the input ends. How do we check for EOF? + while (current_char32.value != '"' && !current_char32.is_eof ()) { if (current_char32.value == '\\') { @@ -1949,20 +1951,18 @@ Lexer::parse_string (Location loc) current_column += length; - if (current_char32.value == '\n') - { - rust_error_at (get_current_location (), "unended string literal"); - // by this point, the parser will stuck at this position due to - // undetermined string termination. we now need to unstuck the parser - skip_broken_string_input (current_char32.value); - } - else if (current_char32.value == '"') + if (current_char32.value == '"') { current_column++; skip_input (); current_char = peek_input (); } + else if (current_char32.is_eof ()) + { + rust_error_at (get_current_location (), "unended string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } else { gcc_unreachable (); @@ -2046,7 +2046,7 @@ Lexer::parse_raw_string (Location loc, int initial_hash_count) skip_input (); Codepoint current_char32 = peek_codepoint_input (); - while (true) + while (!current_char32.is_eof ()) { if (current_char32.value == '"') { @@ -2318,6 +2318,8 @@ Lexer::parse_char_or_lifetime (Location loc) int length = 1; current_char32 = peek_codepoint_input (); + if (current_char32.is_eof ()) + return nullptr; // parse escaped char literal if (current_char32.value == '\\') @@ -2398,6 +2400,9 @@ Lexer::get_input_codepoint_length () { uint8_t input = peek_input (); + if ((int8_t) input == EOF) + return 0; + if (input < 128) { // ascii -- 1 byte @@ -2467,7 +2472,8 @@ Lexer::get_input_codepoint_length () } else { - rust_error_at (get_current_location (), "invalid UTF-8 (too long)"); + rust_error_at (get_current_location (), + "invalid UTF-8 [FIRST] (too long)"); return 0; } } @@ -2478,6 +2484,9 @@ Lexer::peek_codepoint_input () { uint8_t input = peek_input (); + if ((int8_t) input == EOF) + return Codepoint::eof (); + if (input < 128) { // ascii -- 1 byte @@ -2534,7 +2543,8 @@ Lexer::peek_codepoint_input () } else { - rust_error_at (get_current_location (), "invalid UTF-8 (too long)"); + rust_error_at (get_current_location (), + "invalid UTF-8 [SECND] (too long)"); return {0xFFFE}; } } @@ -2620,7 +2630,8 @@ Lexer::test_get_input_codepoint_n_length (int n_start_offset) } else { - rust_error_at (get_current_location (), "invalid UTF-8 (too long)"); + rust_error_at (get_current_location (), + "invalid UTF-8 [THIRD] (too long)"); return 0; } } diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index eb4240a..1ef6765 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -35,6 +35,7 @@ #include "rust-export-metadata.h" #include "rust-imports.h" #include "rust-extern-crate.h" +#include "rust-attributes.h" #include "diagnostic.h" #include "input.h" @@ -738,6 +739,8 @@ Session::parse_file (const char *filename) // TODO: what do I dump here? injected crate names? } + Analysis::AttributeChecker ().go (parsed_crate); + // expansion pipeline stage expansion (parsed_crate); rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index b5989fb..bf4bb2f 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -17,6 +17,10 @@ // <http://www.gnu.org/licenses/>. #include "rust-attributes.h" +#include "rust-ast.h" +#include "rust-ast-full.h" +#include "rust-diagnostics.h" +#include "safe-ctype.h" namespace Rust { namespace Analysis { @@ -68,5 +72,768 @@ BuiltinAttributeMappings::BuiltinAttributeMappings () } } +AttributeChecker::AttributeChecker () {} + +void +AttributeChecker::go (AST::Crate &crate) +{ + check_attributes (crate.get_inner_attrs ()); + + for (auto &item : crate.items) + item->accept_vis (*this); +} + +static bool +is_builtin (const AST::Attribute &attribute, BuiltinAttrDefinition &builtin) +{ + auto &segments = attribute.get_path ().get_segments (); + + // Builtin attributes always have a single segment. This avoids us creating + // strings all over the place and performing a linear search in the builtins + // map + if (segments.size () != 1) + return false; + + builtin = BuiltinAttributeMappings::get ()->lookup_builtin ( + segments.at (0).get_segment_name ()); + + return !builtin.is_error (); +} + +/** + * Check that the string given to #[doc(alias = ...)] or #[doc(alias(...))] is + * valid. + * + * This means no whitespace characters other than spaces and no quoting + * characters. + */ +static void +check_doc_alias (const std::string &alias_input, const Location &locus) +{ + // FIXME: The locus here is for the whole attribute. Can we get the locus + // of the alias input instead? + for (auto c : alias_input) + if ((ISSPACE (c) && c != ' ') || c == '\'' || c == '\"') + { + auto to_print = std::string (1, c); + switch (c) + { + case '\n': + to_print = "\\n"; + break; + case '\t': + to_print = "\\t"; + break; + default: + break; + } + rust_error_at (locus, + "invalid character used in %<#[doc(alias)]%> input: %qs", + to_print.c_str ()); + } + + if (alias_input.empty ()) + return; + + if (alias_input.front () == ' ' || alias_input.back () == ' ') + rust_error_at (locus, + "%<#[doc(alias)]%> input cannot start or end with a space"); +} + +static void +check_doc_attribute (const AST::Attribute &attribute) +{ + if (!attribute.has_attr_input ()) + { + rust_error_at ( + attribute.get_locus (), + // FIXME: Improve error message here. Rustc has a very good one + "%<#[doc]%> cannot be an empty attribute"); + return; + } + + switch (attribute.get_attr_input ().get_attr_input_type ()) + { + case AST::AttrInput::LITERAL: + case AST::AttrInput::META_ITEM: + break; + // FIXME: Handle them as well + + case AST::AttrInput::TOKEN_TREE: { + // FIXME: This doesn't check for #[doc(alias(...))] + const auto &option = static_cast<const AST::DelimTokenTree &> ( + attribute.get_attr_input ()); + auto *meta_item = option.parse_to_meta_item (); + + for (auto &item : meta_item->get_items ()) + { + if (item->is_key_value_pair ()) + { + auto name_value + = static_cast<AST::MetaNameValueStr *> (item.get ()) + ->get_name_value_pair (); + + // FIXME: Check for other stuff than #[doc(alias = ...)] + if (name_value.first == "alias") + check_doc_alias (name_value.second, attribute.get_locus ()); + } + } + break; + } + } +} + +void +AttributeChecker::check_attribute (const AST::Attribute &attribute) +{ + BuiltinAttrDefinition result; + + // This checker does not check non-builtin attributes + if (!is_builtin (attribute, result)) + return; + + // TODO: Add checks here for each builtin attribute + // TODO: Have an enum of builtins as well, switching on strings is annoying + // and costly + if (result.name == "doc") + check_doc_attribute (attribute); +} + +void +AttributeChecker::check_attributes (const AST::AttrVec &attributes) +{ + for (auto &attr : attributes) + check_attribute (attr); +} + +void +AttributeChecker::visit (AST::Token &tok) +{} + +void +AttributeChecker::visit (AST::DelimTokenTree &delim_tok_tree) +{} + +void +AttributeChecker::visit (AST::AttrInputMetaItemContainer &input) +{} + +void +AttributeChecker::visit (AST::IdentifierExpr &ident_expr) +{} + +void +AttributeChecker::visit (AST::Lifetime &lifetime) +{} + +void +AttributeChecker::visit (AST::LifetimeParam &lifetime_param) +{} + +void +AttributeChecker::visit (AST::ConstGenericParam &const_param) +{} + +// rust-path.h +void +AttributeChecker::visit (AST::PathInExpression &path) +{} + +void +AttributeChecker::visit (AST::TypePathSegment &segment) +{} + +void +AttributeChecker::visit (AST::TypePathSegmentGeneric &segment) +{} + +void +AttributeChecker::visit (AST::TypePathSegmentFunction &segment) +{} + +void +AttributeChecker::visit (AST::TypePath &path) +{} + +void +AttributeChecker::visit (AST::QualifiedPathInExpression &path) +{} + +void +AttributeChecker::visit (AST::QualifiedPathInType &path) +{} + +// rust-expr.h +void +AttributeChecker::visit (AST::LiteralExpr &expr) +{} + +void +AttributeChecker::visit (AST::AttrInputLiteral &attr_input) +{} + +void +AttributeChecker::visit (AST::MetaItemLitExpr &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaItemPathLit &meta_item) +{} + +void +AttributeChecker::visit (AST::BorrowExpr &expr) +{} + +void +AttributeChecker::visit (AST::DereferenceExpr &expr) +{} + +void +AttributeChecker::visit (AST::ErrorPropagationExpr &expr) +{} + +void +AttributeChecker::visit (AST::NegationExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArithmeticOrLogicalExpr &expr) +{} + +void +AttributeChecker::visit (AST::ComparisonExpr &expr) +{} + +void +AttributeChecker::visit (AST::LazyBooleanExpr &expr) +{} + +void +AttributeChecker::visit (AST::TypeCastExpr &expr) +{} + +void +AttributeChecker::visit (AST::AssignmentExpr &expr) +{} + +void +AttributeChecker::visit (AST::CompoundAssignmentExpr &expr) +{} + +void +AttributeChecker::visit (AST::GroupedExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArrayElemsValues &elems) +{} + +void +AttributeChecker::visit (AST::ArrayElemsCopied &elems) +{} + +void +AttributeChecker::visit (AST::ArrayExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArrayIndexExpr &expr) +{} + +void +AttributeChecker::visit (AST::TupleExpr &expr) +{} + +void +AttributeChecker::visit (AST::TupleIndexExpr &expr) +{} + +void +AttributeChecker::visit (AST::StructExprStruct &expr) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIdentifier &field) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIdentifierValue &field) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIndexValue &field) +{} + +void +AttributeChecker::visit (AST::StructExprStructFields &expr) +{} + +void +AttributeChecker::visit (AST::StructExprStructBase &expr) +{} + +void +AttributeChecker::visit (AST::CallExpr &expr) +{} + +void +AttributeChecker::visit (AST::MethodCallExpr &expr) +{} + +void +AttributeChecker::visit (AST::FieldAccessExpr &expr) +{} + +void +AttributeChecker::visit (AST::ClosureExprInner &expr) +{} + +void +AttributeChecker::visit (AST::BlockExpr &expr) +{} + +void +AttributeChecker::visit (AST::ClosureExprInnerTyped &expr) +{} + +void +AttributeChecker::visit (AST::ContinueExpr &expr) +{} + +void +AttributeChecker::visit (AST::BreakExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromToExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeToExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFullExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromToInclExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeToInclExpr &expr) +{} + +void +AttributeChecker::visit (AST::ReturnExpr &expr) +{} + +void +AttributeChecker::visit (AST::UnsafeBlockExpr &expr) +{} + +void +AttributeChecker::visit (AST::LoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::WhileLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::WhileLetLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::ForLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqElse &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqIf &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqIfLet &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqElse &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqIf &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqIfLet &expr) +{} + +void +AttributeChecker::visit (AST::MatchExpr &expr) +{} + +void +AttributeChecker::visit (AST::AwaitExpr &expr) +{} + +void +AttributeChecker::visit (AST::AsyncBlockExpr &expr) +{} + +// rust-item.h +void +AttributeChecker::visit (AST::TypeParam ¶m) +{} + +void +AttributeChecker::visit (AST::LifetimeWhereClauseItem &item) +{} + +void +AttributeChecker::visit (AST::TypeBoundWhereClauseItem &item) +{} + +void +AttributeChecker::visit (AST::Method &method) +{} + +void +AttributeChecker::visit (AST::Module &module) +{} + +void +AttributeChecker::visit (AST::ExternCrate &crate) +{} + +void +AttributeChecker::visit (AST::UseTreeGlob &use_tree) +{} + +void +AttributeChecker::visit (AST::UseTreeList &use_tree) +{} + +void +AttributeChecker::visit (AST::UseTreeRebind &use_tree) +{} + +void +AttributeChecker::visit (AST::UseDeclaration &use_decl) +{} + +void +AttributeChecker::visit (AST::Function &function) +{} + +void +AttributeChecker::visit (AST::TypeAlias &type_alias) +{} + +void +AttributeChecker::visit (AST::StructStruct &struct_item) +{ + check_attributes (struct_item.get_outer_attrs ()); +} + +void +AttributeChecker::visit (AST::TupleStruct &tuple_struct) +{} + +void +AttributeChecker::visit (AST::EnumItem &item) +{} + +void +AttributeChecker::visit (AST::EnumItemTuple &item) +{} + +void +AttributeChecker::visit (AST::EnumItemStruct &item) +{} + +void +AttributeChecker::visit (AST::EnumItemDiscriminant &item) +{} + +void +AttributeChecker::visit (AST::Enum &enum_item) +{} + +void +AttributeChecker::visit (AST::Union &union_item) +{} + +void +AttributeChecker::visit (AST::ConstantItem &const_item) +{} + +void +AttributeChecker::visit (AST::StaticItem &static_item) +{} + +void +AttributeChecker::visit (AST::TraitItemFunc &item) +{} + +void +AttributeChecker::visit (AST::TraitItemMethod &item) +{} + +void +AttributeChecker::visit (AST::TraitItemConst &item) +{} + +void +AttributeChecker::visit (AST::TraitItemType &item) +{} + +void +AttributeChecker::visit (AST::Trait &trait) +{} + +void +AttributeChecker::visit (AST::InherentImpl &impl) +{} + +void +AttributeChecker::visit (AST::TraitImpl &impl) +{} + +void +AttributeChecker::visit (AST::ExternalStaticItem &item) +{} + +void +AttributeChecker::visit (AST::ExternalFunctionItem &item) +{} + +void +AttributeChecker::visit (AST::ExternBlock &block) +{} + +// rust-macro.h +void +AttributeChecker::visit (AST::MacroMatchFragment &match) +{} + +void +AttributeChecker::visit (AST::MacroMatchRepetition &match) +{} + +void +AttributeChecker::visit (AST::MacroMatcher &matcher) +{} + +void +AttributeChecker::visit (AST::MacroRulesDefinition &rules_def) +{} + +void +AttributeChecker::visit (AST::MacroInvocation ¯o_invoc) +{} + +void +AttributeChecker::visit (AST::MetaItemPath &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaItemSeq &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaWord &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaNameValueStr &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaListPaths &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaListNameValueStr &meta_item) +{} + +// rust-pattern.h +void +AttributeChecker::visit (AST::LiteralPattern &pattern) +{} + +void +AttributeChecker::visit (AST::IdentifierPattern &pattern) +{} + +void +AttributeChecker::visit (AST::WildcardPattern &pattern) +{} + +// void AttributeChecker::visit(RangePatternBound& bound){} + +void +AttributeChecker::visit (AST::RangePatternBoundLiteral &bound) +{} + +void +AttributeChecker::visit (AST::RangePatternBoundPath &bound) +{} + +void +AttributeChecker::visit (AST::RangePatternBoundQualPath &bound) +{} + +void +AttributeChecker::visit (AST::RangePattern &pattern) +{} + +void +AttributeChecker::visit (AST::ReferencePattern &pattern) +{} + +// void AttributeChecker::visit(StructPatternField& field){} + +void +AttributeChecker::visit (AST::StructPatternFieldTuplePat &field) +{} + +void +AttributeChecker::visit (AST::StructPatternFieldIdentPat &field) +{} + +void +AttributeChecker::visit (AST::StructPatternFieldIdent &field) +{} + +void +AttributeChecker::visit (AST::StructPattern &pattern) +{} + +// void AttributeChecker::visit(TupleStructItems& tuple_items){} + +void +AttributeChecker::visit (AST::TupleStructItemsNoRange &tuple_items) +{} + +void +AttributeChecker::visit (AST::TupleStructItemsRange &tuple_items) +{} + +void +AttributeChecker::visit (AST::TupleStructPattern &pattern) +{} + +// void AttributeChecker::visit(TuplePatternItems& tuple_items){} + +void +AttributeChecker::visit (AST::TuplePatternItemsMultiple &tuple_items) +{} + +void +AttributeChecker::visit (AST::TuplePatternItemsRanged &tuple_items) +{} + +void +AttributeChecker::visit (AST::TuplePattern &pattern) +{} + +void +AttributeChecker::visit (AST::GroupedPattern &pattern) +{} + +void +AttributeChecker::visit (AST::SlicePattern &pattern) +{} + +// rust-stmt.h +void +AttributeChecker::visit (AST::EmptyStmt &stmt) +{} + +void +AttributeChecker::visit (AST::LetStmt &stmt) +{} + +void +AttributeChecker::visit (AST::ExprStmtWithoutBlock &stmt) +{} + +void +AttributeChecker::visit (AST::ExprStmtWithBlock &stmt) +{} + +// rust-type.h +void +AttributeChecker::visit (AST::TraitBound &bound) +{} + +void +AttributeChecker::visit (AST::ImplTraitType &type) +{} + +void +AttributeChecker::visit (AST::TraitObjectType &type) +{} + +void +AttributeChecker::visit (AST::ParenthesisedType &type) +{} + +void +AttributeChecker::visit (AST::ImplTraitTypeOneBound &type) +{} + +void +AttributeChecker::visit (AST::TraitObjectTypeOneBound &type) +{} + +void +AttributeChecker::visit (AST::TupleType &type) +{} + +void +AttributeChecker::visit (AST::NeverType &type) +{} + +void +AttributeChecker::visit (AST::RawPointerType &type) +{} + +void +AttributeChecker::visit (AST::ReferenceType &type) +{} + +void +AttributeChecker::visit (AST::ArrayType &type) +{} + +void +AttributeChecker::visit (AST::SliceType &type) +{} + +void +AttributeChecker::visit (AST::InferredType &type) +{} + +void +AttributeChecker::visit (AST::BareFunctionType &type) +{} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index 6c2063c7..3ac93ff 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -16,7 +16,9 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-ast.h" #include "rust-system.h" +#include "rust-ast-visitor.h" namespace Rust { namespace Analysis { @@ -66,5 +68,203 @@ private: std::map<std::string, const BuiltinAttrDefinition> mappings; }; +/** + * Checks the validity of various attributes. The goal of this visitor is to + * make sure that attributes are applied in allowed contexts, for example to + * make sure that #[inline] is only applied to functions and closures, as well + * as checking the "arguments" or input given to these attributes, making sure + * it is appropriate and valid. + */ +class AttributeChecker : public AST::ASTVisitor +{ +public: + AttributeChecker (); + + /** + * Check all the attributes of all the items of a crate + */ + void go (AST::Crate &crate); + +private: + /* Check the validity of a given attribute */ + void check_attribute (const AST::Attribute &attribute); + + /* Check the validity of all given attributes */ + void check_attributes (const AST::AttrVec &attributes); + + // rust-ast.h + void visit (AST::Token &tok); + void visit (AST::DelimTokenTree &delim_tok_tree); + void visit (AST::AttrInputMetaItemContainer &input); + void visit (AST::IdentifierExpr &ident_expr); + void visit (AST::Lifetime &lifetime); + void visit (AST::LifetimeParam &lifetime_param); + void visit (AST::ConstGenericParam &const_param); + + // rust-path.h + void visit (AST::PathInExpression &path); + void visit (AST::TypePathSegment &segment); + void visit (AST::TypePathSegmentGeneric &segment); + void visit (AST::TypePathSegmentFunction &segment); + void visit (AST::TypePath &path); + void visit (AST::QualifiedPathInExpression &path); + void visit (AST::QualifiedPathInType &path); + + // rust-expr.h + void visit (AST::LiteralExpr &expr); + void visit (AST::AttrInputLiteral &attr_input); + void visit (AST::MetaItemLitExpr &meta_item); + void visit (AST::MetaItemPathLit &meta_item); + void visit (AST::BorrowExpr &expr); + void visit (AST::DereferenceExpr &expr); + void visit (AST::ErrorPropagationExpr &expr); + void visit (AST::NegationExpr &expr); + void visit (AST::ArithmeticOrLogicalExpr &expr); + void visit (AST::ComparisonExpr &expr); + void visit (AST::LazyBooleanExpr &expr); + void visit (AST::TypeCastExpr &expr); + void visit (AST::AssignmentExpr &expr); + void visit (AST::CompoundAssignmentExpr &expr); + void visit (AST::GroupedExpr &expr); + void visit (AST::ArrayElemsValues &elems); + void visit (AST::ArrayElemsCopied &elems); + void visit (AST::ArrayExpr &expr); + void visit (AST::ArrayIndexExpr &expr); + void visit (AST::TupleExpr &expr); + void visit (AST::TupleIndexExpr &expr); + void visit (AST::StructExprStruct &expr); + void visit (AST::StructExprFieldIdentifier &field); + void visit (AST::StructExprFieldIdentifierValue &field); + void visit (AST::StructExprFieldIndexValue &field); + void visit (AST::StructExprStructFields &expr); + void visit (AST::StructExprStructBase &expr); + void visit (AST::CallExpr &expr); + void visit (AST::MethodCallExpr &expr); + void visit (AST::FieldAccessExpr &expr); + void visit (AST::ClosureExprInner &expr); + void visit (AST::BlockExpr &expr); + void visit (AST::ClosureExprInnerTyped &expr); + void visit (AST::ContinueExpr &expr); + void visit (AST::BreakExpr &expr); + void visit (AST::RangeFromToExpr &expr); + void visit (AST::RangeFromExpr &expr); + void visit (AST::RangeToExpr &expr); + void visit (AST::RangeFullExpr &expr); + void visit (AST::RangeFromToInclExpr &expr); + void visit (AST::RangeToInclExpr &expr); + void visit (AST::ReturnExpr &expr); + void visit (AST::UnsafeBlockExpr &expr); + void visit (AST::LoopExpr &expr); + void visit (AST::WhileLoopExpr &expr); + void visit (AST::WhileLetLoopExpr &expr); + void visit (AST::ForLoopExpr &expr); + void visit (AST::IfExpr &expr); + void visit (AST::IfExprConseqElse &expr); + void visit (AST::IfExprConseqIf &expr); + void visit (AST::IfExprConseqIfLet &expr); + void visit (AST::IfLetExpr &expr); + void visit (AST::IfLetExprConseqElse &expr); + void visit (AST::IfLetExprConseqIf &expr); + void visit (AST::IfLetExprConseqIfLet &expr); + void visit (AST::MatchExpr &expr); + void visit (AST::AwaitExpr &expr); + void visit (AST::AsyncBlockExpr &expr); + + // rust-item.h + void visit (AST::TypeParam ¶m); + void visit (AST::LifetimeWhereClauseItem &item); + void visit (AST::TypeBoundWhereClauseItem &item); + void visit (AST::Method &method); + void visit (AST::Module &module); + void visit (AST::ExternCrate &crate); + void visit (AST::UseTreeGlob &use_tree); + void visit (AST::UseTreeList &use_tree); + void visit (AST::UseTreeRebind &use_tree); + void visit (AST::UseDeclaration &use_decl); + void visit (AST::Function &function); + void visit (AST::TypeAlias &type_alias); + void visit (AST::StructStruct &struct_item); + void visit (AST::TupleStruct &tuple_struct); + void visit (AST::EnumItem &item); + void visit (AST::EnumItemTuple &item); + void visit (AST::EnumItemStruct &item); + void visit (AST::EnumItemDiscriminant &item); + void visit (AST::Enum &enum_item); + void visit (AST::Union &union_item); + void visit (AST::ConstantItem &const_item); + void visit (AST::StaticItem &static_item); + void visit (AST::TraitItemFunc &item); + void visit (AST::TraitItemMethod &item); + void visit (AST::TraitItemConst &item); + void visit (AST::TraitItemType &item); + void visit (AST::Trait &trait); + void visit (AST::InherentImpl &impl); + void visit (AST::TraitImpl &impl); + void visit (AST::ExternalStaticItem &item); + void visit (AST::ExternalFunctionItem &item); + void visit (AST::ExternBlock &block); + + // rust-macro.h + void visit (AST::MacroMatchFragment &match); + void visit (AST::MacroMatchRepetition &match); + void visit (AST::MacroMatcher &matcher); + void visit (AST::MacroRulesDefinition &rules_def); + void visit (AST::MacroInvocation ¯o_invoc); + void visit (AST::MetaItemPath &meta_item); + void visit (AST::MetaItemSeq &meta_item); + void visit (AST::MetaWord &meta_item); + void visit (AST::MetaNameValueStr &meta_item); + void visit (AST::MetaListPaths &meta_item); + void visit (AST::MetaListNameValueStr &meta_item); + + // rust-pattern.h + void visit (AST::LiteralPattern &pattern); + void visit (AST::IdentifierPattern &pattern); + void visit (AST::WildcardPattern &pattern); + // void visit(RangePatternBound& bound); + void visit (AST::RangePatternBoundLiteral &bound); + void visit (AST::RangePatternBoundPath &bound); + void visit (AST::RangePatternBoundQualPath &bound); + void visit (AST::RangePattern &pattern); + void visit (AST::ReferencePattern &pattern); + // void visit(StructPatternField& field); + void visit (AST::StructPatternFieldTuplePat &field); + void visit (AST::StructPatternFieldIdentPat &field); + void visit (AST::StructPatternFieldIdent &field); + void visit (AST::StructPattern &pattern); + // void visit(TupleStructItems& tuple_items); + void visit (AST::TupleStructItemsNoRange &tuple_items); + void visit (AST::TupleStructItemsRange &tuple_items); + void visit (AST::TupleStructPattern &pattern); + // void visit(TuplePatternItems& tuple_items); + void visit (AST::TuplePatternItemsMultiple &tuple_items); + void visit (AST::TuplePatternItemsRanged &tuple_items); + void visit (AST::TuplePattern &pattern); + void visit (AST::GroupedPattern &pattern); + void visit (AST::SlicePattern &pattern); + + // rust-stmt.h + void visit (AST::EmptyStmt &stmt); + void visit (AST::LetStmt &stmt); + void visit (AST::ExprStmtWithoutBlock &stmt); + void visit (AST::ExprStmtWithBlock &stmt); + + // rust-type.h + void visit (AST::TraitBound &bound); + void visit (AST::ImplTraitType &type); + void visit (AST::TraitObjectType &type); + void visit (AST::ParenthesisedType &type); + void visit (AST::ImplTraitTypeOneBound &type); + void visit (AST::TraitObjectTypeOneBound &type); + void visit (AST::TupleType &type); + void visit (AST::NeverType &type); + void visit (AST::RawPointerType &type); + void visit (AST::ReferenceType &type); + void visit (AST::ArrayType &type); + void visit (AST::SliceType &type); + void visit (AST::InferredType &type); + void visit (AST::BareFunctionType &type); +}; + } // namespace Analysis } // namespace Rust diff --git a/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs b/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs index 33001c0..e113120 100644 --- a/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs +++ b/gcc/testsuite/rust/compile/torture/check-doc-attr-string.rs @@ -5,9 +5,14 @@ pub struct Bar; #[doc(alias = " -")] // { dg-error "unended string literal" "" { target *-*-* } .-1 } +")] // { dg-error "invalid character used" "" { target *-*-* } .-1 } pub struct Foo; -#[doc(alias(" -"))] // { dg-error "unended string literal" "" { target *-*-* } .-1 } +#[doc(alias( + " +" +))] // ko but unchecked for now pub struct Foo2; + +#[doc(whatever = "buidule")] // ko as well but unchecked for now +struct Boo; diff --git a/gcc/testsuite/rust/compile/torture/undended-string-1.rs b/gcc/testsuite/rust/compile/torture/undended-string-1.rs new file mode 100644 index 0000000..66f0cd5 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/undended-string-1.rs @@ -0,0 +1,5 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended string literal" "" { target *-*-* } .+1 } + let s = "123 +} diff --git a/gcc/testsuite/rust/compile/torture/undended-string-2.rs b/gcc/testsuite/rust/compile/torture/undended-string-2.rs new file mode 100644 index 0000000..c0f4249 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/undended-string-2.rs @@ -0,0 +1,5 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended byte string literal" "" { target *-*-* } .+1 } + let s = b"123 +} |