aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2021-11-16 15:50:04 +0100
committerMartin Liska <mliska@suse.cz>2021-11-16 15:50:04 +0100
commit42369195bef1204e5249f211d33cc64619530167 (patch)
tree9235842fd357e915b47b4a700821d3d9b2aa2230 /gcc/go
parent9345234b2a80fbb26342f8c72aa8714d673c7dad (diff)
parent8d8e8f3ad567c7bd1de708fcc841f691d9686c4d (diff)
downloadgcc-42369195bef1204e5249f211d33cc64619530167.zip
gcc-42369195bef1204e5249f211d33cc64619530167.tar.gz
gcc-42369195bef1204e5249f211d33cc64619530167.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc57
-rw-r--r--gcc/go/gofrontend/expressions.h8
-rw-r--r--gcc/go/gofrontend/gogo.cc5
-rw-r--r--gcc/go/gofrontend/lex.cc11
-rw-r--r--gcc/go/gofrontend/lex.h6
-rw-r--r--gcc/go/gofrontend/parse.cc128
-rw-r--r--gcc/go/gofrontend/parse.h20
8 files changed, 149 insertions, 88 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index affba73..05e47ec 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-925ace70ac7426c3f8b5c0bfb75aa9601f071de4
+3e9f4ee16683883ccfb8661d99318c74bb7a4bef
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/expressions.cc b/gcc/go/gofrontend/expressions.cc
index ddb1d91..7970282 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -7981,7 +7981,7 @@ Bound_method_expression::do_check_types(Gogo*)
Bound_method_expression::Method_value_thunks
Bound_method_expression::method_value_thunks;
-// Find or create the thunk for METHOD.
+// Find or create the thunk for FN.
Named_object*
Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
@@ -8078,14 +8078,28 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
gogo->add_statement(s);
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
+
+ // This is called after lowering but before determine_types.
gogo->lower_block(new_no, b);
- gogo->flatten_block(new_no, b);
+
gogo->finish_function(loc);
ins.first->second = new_no;
return new_no;
}
+// Look up a thunk for FN.
+
+Named_object*
+Bound_method_expression::lookup_thunk(Named_object* fn)
+{
+ Method_value_thunks::const_iterator p =
+ Bound_method_expression::method_value_thunks.find(fn);
+ if (p == Bound_method_expression::method_value_thunks.end())
+ return NULL;
+ return p->second;
+}
+
// Return an expression to check *REF for nil while dereferencing
// according to FIELD_INDEXES. Update *REF to build up the field
// reference. This is a static function so that we don't have to
@@ -8129,10 +8143,11 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*,
{
Location loc = this->location();
- Named_object* thunk = Bound_method_expression::create_thunk(gogo,
- this->method_,
- this->function_);
- if (thunk->is_erroneous())
+ Named_object* thunk = Bound_method_expression::lookup_thunk(this->function_);
+
+ // The thunk should have been created during the
+ // create_function_descriptors pass.
+ if (thunk == NULL || thunk->is_erroneous())
{
go_assert(saw_errors());
return Expression::make_error(loc);
@@ -14757,14 +14772,34 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
gogo->add_statement(s);
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
+
+ // This is called after lowering but before determine_types.
gogo->lower_block(new_no, b);
- gogo->flatten_block(new_no, b);
+
gogo->finish_function(loc);
ins.first->second->push_back(std::make_pair(name, new_no));
return new_no;
}
+// Lookup a thunk to call method NAME on TYPE.
+
+Named_object*
+Interface_field_reference_expression::lookup_thunk(Interface_type* type,
+ const std::string& name)
+{
+ Interface_method_thunks::const_iterator p =
+ Interface_field_reference_expression::interface_method_thunks.find(type);
+ if (p == Interface_field_reference_expression::interface_method_thunks.end())
+ return NULL;
+ for (Method_thunks::const_iterator pm = p->second->begin();
+ pm != p->second->end();
+ ++pm)
+ if (pm->first == name)
+ return pm->second;
+ return NULL;
+}
+
// Get the backend representation for a method value.
Bexpression*
@@ -14778,9 +14813,11 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context)
}
Named_object* thunk =
- Interface_field_reference_expression::create_thunk(context->gogo(),
- type, this->name_);
- if (thunk->is_erroneous())
+ Interface_field_reference_expression::lookup_thunk(type, this->name_);
+
+ // The thunk should have been created during the
+ // create_function_descriptors pass.
+ if (thunk == NULL || thunk->is_erroneous())
{
go_assert(saw_errors());
return context->backend()->error_expression();
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 9348354..92e8d8d 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -3405,6 +3405,10 @@ class Bound_method_expression : public Expression
static Named_object*
create_thunk(Gogo*, const Method* method, Named_object* function);
+ // Look up a thunk.
+ static Named_object*
+ lookup_thunk(Named_object* function);
+
protected:
int
do_traverse(Traverse*);
@@ -3578,6 +3582,10 @@ class Interface_field_reference_expression : public Expression
static Named_object*
create_thunk(Gogo*, Interface_type* type, const std::string& name);
+ // Look up a thunk.
+ static Named_object*
+ lookup_thunk(Interface_type* type, const std::string& name);
+
// Return an expression for the pointer to the function to call.
Expression*
get_function();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 95b76bd..290d294 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -3430,6 +3430,11 @@ Create_function_descriptors::expression(Expression** pexpr)
if (args->traverse(this) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
+
+ // Traverse the subexpressions of the function, if any.
+ if (fn->traverse_subexpressions(this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+
return TRAVERSE_SKIP_COMPONENTS;
}
}
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 e43b5f2..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.