diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-07-20 15:28:23 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-07-21 11:16:19 +0200 |
commit | 8dc692afc2c86cbf3b5124484dd2596514a5acf3 (patch) | |
tree | 9bc01a3484c3786743ab0d4a65cfca4dae95321e | |
parent | 137cd3bbaa05038b01c46f7ac7472da7ca662ed7 (diff) | |
download | gcc-8dc692afc2c86cbf3b5124484dd2596514a5acf3.zip gcc-8dc692afc2c86cbf3b5124484dd2596514a5acf3.tar.gz gcc-8dc692afc2c86cbf3b5124484dd2596514a5acf3.tar.bz2 |
ast: Add new AttributeChecker visitor
This commit adds a new attribute checker visitor. Its role is to take care of validating builtin attributes and their inputs.
In order to validate doc(alias) strings properly, as well as handle
multiline (byte) strings, this also fixes the lexer to better handle EOF
in bytes and codepoints.
-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 +} |