diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-10-26 10:50:40 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-10-26 16:11:26 -0700 |
commit | ab10383aaebf2feebd2b6d68247f2520eff48f79 (patch) | |
tree | b7296e54620d4fbe3fef6d4ebad91a9bbe7065ff /gcc/go | |
parent | 1ff4dbddcf74203a1e16316b18e12f9e1b5085f0 (diff) | |
download | gcc-ab10383aaebf2feebd2b6d68247f2520eff48f79.zip gcc-ab10383aaebf2feebd2b6d68247f2520eff48f79.tar.gz gcc-ab10383aaebf2feebd2b6d68247f2520eff48f79.tar.bz2 |
compiler: permit compiler directives in parenthesized groups
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
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/lex.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/lex.h | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 128 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.h | 20 |
5 files changed, 89 insertions, 78 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index affba73..e7ff670 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc index dd66c02..d6909b8 100644 --- a/gcc/go/gofrontend/lex.cc +++ b/gcc/go/gofrontend/lex.cc @@ -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' diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h index 75c8429..1c4cc5b 100644 --- a/gcc/go/gofrontend/lex.h +++ b/gcc/go/gofrontend/lex.h @@ -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 diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index e43b5f21..cc197e5 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -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 diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 2c3c505..6e300ef 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -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. |