public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] ast: Add new AttributeChecker visitor
@ 2022-07-22 21:25 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-07-22 21:25 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8dc692afc2c86cbf3b5124484dd2596514a5acf3

commit 8dc692afc2c86cbf3b5124484dd2596514a5acf3
Author: Arthur Cohen <arthur.cohen@embecosm.com>
Date:   Wed Jul 20 15:28:23 2022 +0200

    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.

Diff:
---
 gcc/rust/hir/rust-ast-lower-base.cc                |   2 +
 gcc/rust/lex/rust-codepoint.h                      |   4 +-
 gcc/rust/lex/rust-lex.cc                           |  49 +-
 gcc/rust/rust-session-manager.cc                   |   3 +
 gcc/rust/util/rust-attributes.cc                   | 767 +++++++++++++++++++++
 gcc/rust/util/rust-attributes.h                    | 200 ++++++
 .../rust/compile/torture/check-doc-attr-string.rs  |  11 +-
 .../rust/compile/torture/undended-string-1.rs      |   5 +
 .../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 e31b95b07bd..cae4428dea6 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 cdadfcd45d4..22da080bbb2 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 ecf151dc778..70e6b50209f 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 eb4240a447f..1ef67654969 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 b5989fba676..bf4bb2fbfe9 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 &param)
+{}
+
+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 &macro_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 6c2063c7455..3ac93ff5908 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 &param);
+  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 &macro_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 33001c01fd0..e113120bdbc 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 00000000000..66f0cd52269
--- /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 00000000000..c0f424927c2
--- /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
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-22 21:25 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-22 21:25 [gcc/devel/rust/master] ast: Add new AttributeChecker visitor Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).