diff options
author | Martin Liska <mliska@suse.cz> | 2021-11-16 15:50:04 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2021-11-16 15:50:04 +0100 |
commit | 42369195bef1204e5249f211d33cc64619530167 (patch) | |
tree | 9235842fd357e915b47b4a700821d3d9b2aa2230 /gcc/go | |
parent | 9345234b2a80fbb26342f8c72aa8714d673c7dad (diff) | |
parent | 8d8e8f3ad567c7bd1de708fcc841f691d9686c4d (diff) | |
download | gcc-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/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 57 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 5 | ||||
-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 |
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. |