]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: permit compiler directives in parenthesized groups
authorIan Lance Taylor <iant@golang.org>
Tue, 26 Oct 2021 17:50:40 +0000 (10:50 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 26 Oct 2021 23:11:26 +0000 (16:11 -0700)
The original compiler directive support was only for //line at the
start of a line and for //go: comments before function declarations.
When support was added for //go:notinheap for types and //go:embed for
variables the code did not adapt to permit spaces before the comment
or to permit the comments in var() or type() groups.  This change
corrects those omissions.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/358699

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/lex.cc
gcc/go/gofrontend/lex.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h

index affba73e4bb9d0820904d4c7895717804aef0743..e7ff670556378283e4bf4277b767e41bee484934 100644 (file)
@@ -1,4 +1,4 @@
-925ace70ac7426c3f8b5c0bfb75aa9601f071de4
+128ea3dce9b8753167f33d0a96bd093a6cbd58b8
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index dd66c0209a46e520d6874d0dac1d9649b6bcafe3..d6909b840a8e06d3e271cfa8d37931168e6c2555 100644 (file)
@@ -1909,14 +1909,13 @@ Lex::skip_cpp_comment()
   if (saw_error)
     return;
 
-  // Recognize various magic comments at the start of a line.
+  // Recognize various magic comments at the start of a line, preceded
+  // only by spaces or tabs.
 
-  if (lineoff != 2)
-    {
-      // Not at the start of the line.  (lineoff == 2 because of the
-      // two characters in "//").
+  // "- 2" for the "//" at the start of the comment.
+  for (const char* psp = this->linebuf_; psp < p - 2; psp++)
+    if (*psp != ' ' && *psp != '\t')
       return;
-    }
 
   while (pend > p
         && (pend[-1] == ' ' || pend[-1] == '\t'
index 75c8429b68f0b01d66ac69e35f5a6412ec0d4690..1c4cc5bd2a1323a1f1329789dcaae8fbbd22c504 100644 (file)
@@ -420,6 +420,12 @@ class Lex
     std::swap(*embeds, this->embeds_);
   }
 
+  // Clear any go:embed patterns seen so far.  This is used for
+  // erroneous cases.
+  void
+  clear_embeds()
+  { this->embeds_.clear(); }
+
   // Return whether the identifier NAME should be exported.  NAME is a
   // mangled name which includes only ASCII characters.
   static bool
index e43b5f2144846b9004991fcf511106552bfcbb68..cc197e5eb359a6a3de4dc7b9169911d3bae84b56 100644 (file)
@@ -1307,46 +1307,14 @@ void
 Parse::declaration()
 {
   const Token* token = this->peek_token();
-
-  unsigned int pragmas = this->lex_->get_and_clear_pragmas();
-  if (pragmas != 0
-      && !token->is_keyword(KEYWORD_FUNC)
-      && !token->is_keyword(KEYWORD_TYPE))
-    go_warning_at(token->location(), 0,
-                 "ignoring magic comment before non-function");
-
-  std::vector<std::string>* embeds = NULL;
-  if (this->lex_->has_embeds())
-    {
-      embeds = new(std::vector<std::string>);
-      this->lex_->get_and_clear_embeds(embeds);
-
-      if (!this->gogo_->current_file_imported_embed())
-       {
-         go_error_at(token->location(),
-                     "invalid go:embed: missing import %<embed%>");
-         delete embeds;
-         embeds = NULL;
-       }
-      if (!token->is_keyword(KEYWORD_VAR))
-       {
-         go_error_at(token->location(), "misplaced go:embed directive");
-         if (embeds != NULL)
-           {
-             delete embeds;
-             embeds = NULL;
-           }
-       }
-    }
-
   if (token->is_keyword(KEYWORD_CONST))
     this->const_decl();
   else if (token->is_keyword(KEYWORD_TYPE))
-    this->type_decl(pragmas);
+    this->type_decl();
   else if (token->is_keyword(KEYWORD_VAR))
-    this->var_decl(embeds);
+    this->var_decl();
   else if (token->is_keyword(KEYWORD_FUNC))
-    this->function_decl(pragmas);
+    this->function_decl();
   else
     {
       go_error_at(this->location(), "expected declaration");
@@ -1367,8 +1335,7 @@ Parse::declaration_may_start_here()
 // Decl<P> = P | "(" [ List<P> ] ")" .
 
 void
-Parse::decl(void (Parse::*pfn)(unsigned int, std::vector<std::string>*),
-           unsigned int pragmas, std::vector<std::string>* embeds)
+Parse::decl(void (Parse::*pfn)())
 {
   if (this->peek_token()->is_eof())
     {
@@ -1378,15 +1345,18 @@ Parse::decl(void (Parse::*pfn)(unsigned int, std::vector<std::string>*),
     }
 
   if (!this->peek_token()->is_op(OPERATOR_LPAREN))
-    (this->*pfn)(pragmas, embeds);
+    (this->*pfn)();
   else
     {
-      if (pragmas != 0)
-       go_warning_at(this->location(), 0,
-                     "ignoring magic %<//go:...%> comment before group");
-      if (embeds != NULL)
+      if (this->lex_->get_and_clear_pragmas() != 0)
        go_error_at(this->location(),
-                   "ignoring %<//go:embed%> comment before group");
+                   "ignoring compiler directive before group");
+      if (this->lex_->has_embeds())
+       {
+         this->lex_->clear_embeds();
+         go_error_at(this->location(),
+                     "ignoring %<//go:embed%> comment before group");
+       }
       if (!this->advance_token()->is_op(OPERATOR_RPAREN))
        {
          this->list(pfn, true);
@@ -1410,10 +1380,9 @@ Parse::decl(void (Parse::*pfn)(unsigned int, std::vector<std::string>*),
 // might follow.  This is either a '}' or a ')'.
 
 void
-Parse::list(void (Parse::*pfn)(unsigned int, std::vector<std::string>*),
-           bool follow_is_paren)
+Parse::list(void (Parse::*pfn)(), bool follow_is_paren)
 {
-  (this->*pfn)(0, NULL);
+  (this->*pfn)();
   Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY;
   while (this->peek_token()->is_op(OPERATOR_SEMICOLON)
         || this->peek_token()->is_op(OPERATOR_COMMA))
@@ -1422,7 +1391,7 @@ Parse::list(void (Parse::*pfn)(unsigned int, std::vector<std::string>*),
        go_error_at(this->location(), "unexpected comma");
       if (this->advance_token()->is_op(follow))
        break;
-      (this->*pfn)(0, NULL);
+      (this->*pfn)();
     }
 }
 
@@ -1469,6 +1438,8 @@ Parse::const_decl()
 void
 Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list)
 {
+  this->check_directives();
+
   Location loc = this->location();
   Typed_identifier_list til;
   this->identifier_list(&til);
@@ -1545,18 +1516,21 @@ Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list)
 // TypeDecl = "type" Decl<TypeSpec> .
 
 void
-Parse::type_decl(unsigned int pragmas)
+Parse::type_decl()
 {
   go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE));
   this->advance_token();
-  this->decl(&Parse::type_spec, pragmas, NULL);
+  this->decl(&Parse::type_spec);
 }
 
 // TypeSpec = identifier ["="] Type .
 
 void
-Parse::type_spec(unsigned int pragmas, std::vector<std::string>*)
+Parse::type_spec()
 {
+  unsigned int pragmas = this->lex_->get_and_clear_pragmas();
+  this->check_directives();
+
   const Token* token = this->peek_token();
   if (!token->is_identifier())
     {
@@ -1649,23 +1623,34 @@ Parse::type_spec(unsigned int pragmas, std::vector<std::string>*)
 // VarDecl = "var" Decl<VarSpec> .
 
 void
-Parse::var_decl(std::vector<std::string>* embeds)
+Parse::var_decl()
 {
   go_assert(this->peek_token()->is_keyword(KEYWORD_VAR));
   this->advance_token();
-  this->decl(&Parse::var_spec, 0, embeds);
+  this->decl(&Parse::var_spec);
 }
 
 // VarSpec = IdentifierList
 //             ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) .
 
 void
-Parse::var_spec(unsigned int pragmas, std::vector<std::string>* embeds)
+Parse::var_spec()
 {
   Location loc = this->location();
 
-  if (pragmas != 0)
-    go_warning_at(loc, 0, "ignoring magic %<//go:...%> comment before var");
+  std::vector<std::string>* embeds = NULL;
+  if (this->lex_->has_embeds())
+    {
+      if (!this->gogo_->current_file_imported_embed())
+       go_error_at(loc, "invalid go:embed: missing import %<embed%>");
+      else
+       {
+         embeds = new(std::vector<std::string>);
+         this->lex_->get_and_clear_embeds(embeds);
+       }
+    }
+
+  this->check_directives();
 
   // Get the variable names.
   Typed_identifier_list til;
@@ -2339,9 +2324,13 @@ Parse::simple_var_decl_or_assignment(const std::string& name,
 // PRAGMAS is a bitset of magic comments.
 
 void
-Parse::function_decl(unsigned int pragmas)
+Parse::function_decl()
 {
   go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
+
+  unsigned int pragmas = this->lex_->get_and_clear_pragmas();
+  this->check_directives();
+
   Location location = this->location();
   std::string extern_name = this->lex_->extern_name();
   const Token* token = this->advance_token();
@@ -5370,7 +5359,7 @@ Parse::for_stat(Label* label)
        {
          go_error_at(this->location(),
                       "var declaration not allowed in for initializer");
-         this->var_decl(NULL);
+         this->var_decl();
        }
 
       if (token->is_op(OPERATOR_SEMICOLON))
@@ -5815,17 +5804,15 @@ Parse::import_decl()
 {
   go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT));
   this->advance_token();
-  this->decl(&Parse::import_spec, 0, NULL);
+  this->decl(&Parse::import_spec);
 }
 
 // ImportSpec = [ "." | PackageName ] PackageFileName .
 
 void
-Parse::import_spec(unsigned int pragmas, std::vector<std::string>*)
+Parse::import_spec()
 {
-  if (pragmas != 0)
-    go_warning_at(this->location(), 0,
-                 "ignoring magic %<//go:...%> comment before import");
+  this->check_directives();
 
   const Token* token = this->peek_token();
   Location location = token->location();
@@ -5916,6 +5903,23 @@ Parse::program()
          this->skip_past_error(OPERATOR_INVALID);
        }
     }
+
+  this->check_directives();
+}
+
+// If there are any pending compiler directives, clear them and give
+// an error.  This is called when directives are not permitted.
+
+void
+Parse::check_directives()
+{
+  if (this->lex_->get_and_clear_pragmas() != 0)
+    go_error_at(this->location(), "misplaced compiler directive");
+  if (this->lex_->has_embeds())
+    {
+      this->lex_->clear_embeds();
+      go_error_at(this->location(), "misplaced go:embed directive");
+    }
 }
 
 // Skip forward to a semicolon or OP.  OP will normally be
index 2c3c505ffa98dab2c777b69e1c3412fb99470847..6e300ef800c647093204d0d5c23094c62c94cf23 100644 (file)
@@ -181,15 +181,14 @@ class Parse
   void method_spec(Typed_identifier_list*);
   void declaration();
   bool declaration_may_start_here();
-  void decl(void (Parse::*)(unsigned int, std::vector<std::string>*),
-           unsigned int pragmas, std::vector<std::string>* embeds);
-  void list(void (Parse::*)(unsigned int, std::vector<std::string>*), bool);
+  void decl(void (Parse::*)());
+  void list(void (Parse::*)(), bool);
   void const_decl();
   void const_spec(int, Type**, Expression_list**);
-  void type_decl(unsigned int pragmas);
-  void type_spec(unsigned int pragmas, std::vector<std::string>*);
-  void var_decl(std::vector<std::string>* embeds);
-  void var_spec(unsigned int pragmas, std::vector<std::string>*);
+  void type_decl();
+  void type_spec();
+  void var_decl();
+  void var_spec();
   void init_vars(const Typed_identifier_list*, Type*, Expression_list*,
                 bool is_coloneq, std::vector<std::string>*, Location);
   bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*,
@@ -210,7 +209,7 @@ class Parse
   void simple_var_decl_or_assignment(const std::string&, Location,
                                     bool may_be_composite_lit,
                                     Range_clause*, Type_switch*);
-  void function_decl(unsigned int pragmas);
+  void function_decl();
   Typed_identifier* receiver();
   Expression* operand(bool may_be_sink, bool *is_parenthesized);
   Expression* enclosing_var_reference(Named_object*, Named_object*,
@@ -278,7 +277,10 @@ class Parse
   void goto_stat();
   void package_clause();
   void import_decl();
-  void import_spec(unsigned int pragmas, std::vector<std::string>*);
+  void import_spec();
+
+  // Check for unused compiler directives.
+  void check_directives();
 
   // Skip past an error looking for a semicolon or OP.  Return true if
   // all is well, false if we found EOF.