mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-01 11:35:57 +00:00
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
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
+66
-62
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user