From fc74d562dee21346405b9bb4a7fe3bd0f2c43758 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 27 Nov 2018 20:07:15 +0000 Subject: [PATCH] compiler: change expression importing to use Import_expression Change expression importing to use a new abstract interface class Import_expression, so that we can more easily import expressions from inlinable function bodies. This is a refactoring with no affect on compiler behavior. Reviewed-on: https://go-review.googlesource.com/c/150065 From-SVN: r266526 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 22 ++--- gcc/go/gofrontend/expressions.h | 12 +-- gcc/go/gofrontend/gogo.cc | 13 +-- gcc/go/gofrontend/gogo.h | 9 +- gcc/go/gofrontend/import.cc | 164 ++++++++++++++++++++++++------- gcc/go/gofrontend/import.h | 143 +++++++++++++++++++++++++-- 7 files changed, 296 insertions(+), 69 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 71c7fcff227..7aebeb10333 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -75d48ff977a2865d12b03857362ea48016a4b885 +6e0974fc6c9aa6ef19f72fbb5698e4b3734a4220 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 391eb663be4..9292b5c4d2f 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1583,7 +1583,7 @@ class Boolean_expression : public Expression { } static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); protected: bool @@ -1649,7 +1649,7 @@ Boolean_expression::do_determine_type(const Type_context* context) // Import a boolean constant. Expression* -Boolean_expression::do_import(Import* imp, Location loc) +Boolean_expression::do_import(Import_expression* imp, Location loc) { if (imp->peek_char() == 't') { @@ -1768,7 +1768,7 @@ String_expression::do_export(Export_function_body* efb) const // Import a string expression. Expression* -String_expression::do_import(Import* imp, Location loc) +String_expression::do_import(Import_expression* imp, Location loc) { imp->require_c_string("\""); std::string val; @@ -1944,7 +1944,7 @@ class Integer_expression : public Expression { mpz_init_set(this->val_, *val); } static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); // Write VAL to string dump. static void @@ -2151,7 +2151,7 @@ Integer_expression::do_export(Export_function_body* efb) const // all these types because they all start with digits. Expression* -Integer_expression::do_import(Import* imp, Location loc) +Integer_expression::do_import(Import_expression* imp, Location loc) { std::string num = imp->read_identifier(); imp->require_c_string(" "); @@ -3133,7 +3133,7 @@ class Nil_expression : public Expression { } static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); protected: bool @@ -3172,7 +3172,7 @@ class Nil_expression : public Expression // Import a nil expression. Expression* -Nil_expression::do_import(Import* imp, Location loc) +Nil_expression::do_import(Import_expression* imp, Location loc) { imp->require_c_string("nil"); return Expression::make_nil(loc); @@ -3623,7 +3623,7 @@ Type_conversion_expression::do_export(Export_function_body* efb) const // Import a type conversion or a struct construction. Expression* -Type_conversion_expression::do_import(Import* imp, Location loc) +Type_conversion_expression::do_import(Import_expression* imp, Location loc) { imp->require_c_string("convert("); Type* type = imp->read_type(); @@ -4634,7 +4634,7 @@ Unary_expression::do_export(Export_function_body* efb) const // Import a unary expression. Expression* -Unary_expression::do_import(Import* imp, Location loc) +Unary_expression::do_import(Import_expression* imp, Location loc) { Operator op; switch (imp->get_char()) @@ -6403,7 +6403,7 @@ Binary_expression::do_export(Export_function_body* efb) const // Import a binary expression. Expression* -Binary_expression::do_import(Import* imp, Location loc) +Binary_expression::do_import(Import_expression* imp, Location loc) { imp->require_c_string("("); @@ -16138,7 +16138,7 @@ Expression::make_backend(Bexpression* bexpr, Type* type, Location location) // various class definitions. Expression* -Expression::import_expression(Import* imp, Location loc) +Expression::import_expression(Import_expression* imp, Location loc) { int c = imp->peek_char(); if (imp->match_c_string("- ") diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 3641b03239e..70616571922 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -66,7 +66,7 @@ class Compound_expression; class Numeric_constant; class Named_object; class Export_function_body; -class Import; +class Import_expression; class Temporary_statement; class Label; class Ast_dump_context; @@ -1018,7 +1018,7 @@ class Expression // returned expression. Errors should be reported using the // Import's location method. static Expression* - import_expression(Import*, Location); + import_expression(Import_expression*, Location); // Return an expression which checks that VAL, of arbitrary integer type, // is non-negative and is not more than the maximum integer value. @@ -1567,7 +1567,7 @@ class String_expression : public Expression { return this->val_; } static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); protected: bool @@ -1646,7 +1646,7 @@ class Type_conversion_expression : public Expression // Import a type conversion expression. static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); protected: int @@ -1817,7 +1817,7 @@ class Unary_expression : public Expression Location, Numeric_constant* nc, bool *issued_error); static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); // Declare that this deref does or does not require an explicit nil check. void @@ -1966,7 +1966,7 @@ class Binary_expression : public Expression bool* result); static Expression* - do_import(Import*, Location); + do_import(Import_expression*, Location); // Report an error if OP can not be applied to TYPE. Return whether // it can. OTYPE is the type of the other operand. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 79d92e559d8..eb0297bc2db 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -527,9 +527,9 @@ Gogo::import_package(const std::string& filename, return; } - Import imp(stream, location); - imp.register_builtin_types(this); - Package* package = imp.import(this, local_name, is_local_name_exported); + Import* imp = new Import(stream, location); + imp->register_builtin_types(this); + Package* package = imp->import(this, local_name, is_local_name_exported); if (package != NULL) { if (package->pkgpath() == this->pkgpath()) @@ -540,7 +540,10 @@ Gogo::import_package(const std::string& filename, this->imports_.insert(std::make_pair(filename, package)); } + imp->clear_stream(); delete stream; + + // FIXME: we never delete imp; we may need it for inlinable functions. } Import_init * @@ -6763,8 +6766,6 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no) const std::string& body(this->imported_body_); go_assert(!body.empty()); - Location orig_loc = no->location(); - // Read the "//FILE:LINE" comment starts the export data. size_t indent = 1; @@ -6877,7 +6878,7 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no) no = rtype->add_method(no->name(), fn); } - Import_function_body ifb(gogo, orig_loc, no, body, nl + 1, outer, indent); + Import_function_body ifb(gogo, this->imp_, no, body, nl + 1, outer, indent); if (!Block::import_block(outer, &ifb, start_loc)) return; diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 1c79f6fda57..8ca567ca13c 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1691,8 +1691,11 @@ class Function_declaration // Record the imported body of this function. void - set_imported_body(const std::string& imported_body) - { this->imported_body_ = imported_body; } + set_imported_body(Import* imp, const std::string& imported_body) + { + this->imp_ = imp; + this->imported_body_ = imported_body; + } // Whether this declaration is on the list of inlinable functions. bool @@ -1756,6 +1759,8 @@ class Function_declaration Bfunction* fndecl_; // Pragmas for this function. This is a set of GOPRAGMA bits. unsigned int pragmas_; + // Importer for function body if imported from a different package. + Import* imp_; // Export data for function body if imported from a different package. std::string imported_body_; // Whether this declaration is already on the list of inlinable functions. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 7ee3cb6f991..524e739f21c 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -790,7 +790,7 @@ Import::import_func(Package* package) if (nointerface) no->func_declaration_value()->set_nointerface(); if (!body.empty() && !no->func_declaration_value()->has_imported_body()) - no->func_declaration_value()->set_imported_body(body); + no->func_declaration_value()->set_imported_body(this, body); return no; } @@ -886,41 +886,7 @@ Import::read_type() if (c == '>') { // A reference to a type defined earlier. - - if (index >= 0 && !this->type_data_.empty()) - { - if (static_cast(index) >= this->type_offsets_.size()) - { - go_error_at(this->location_, - ("error in import data at %d: " - "bad type index %d >= %d"), - stream->pos(), index, - static_cast(this->type_offsets_.size())); - stream->set_saw_error(); - return Type::make_error_type(); - } - - if (this->types_[index] == NULL) - { - if (!this->parse_type(index)) - return Type::make_error_type(); - } - } - - if (index < 0 - ? (static_cast(- index) >= this->builtin_types_.size() - || this->builtin_types_[- index] == NULL) - : (static_cast(index) >= this->types_.size() - || this->types_[index] == NULL)) - { - go_error_at(this->location_, - "error in import data at %d: bad type index %d", - stream->pos(), index); - stream->set_saw_error(); - return Type::make_error_type(); - } - - return index < 0 ? this->builtin_types_[- index] : this->types_[index]; + return this->type_for_index(index, "import data", stream->pos()); } if (this->version_ >= EXPORT_FORMAT_V3) @@ -1126,6 +1092,47 @@ Import::read_named_type(int index) return type; } +// Return the type given an index. + +Type* +Import::type_for_index(int index, const std::string& input_name, + size_t input_offset) +{ + if (index >= 0 && !this->type_data_.empty()) + { + if (static_cast(index) >= this->type_offsets_.size()) + { + go_error_at(this->location_, + "error in %s at %lu: bad type index %d >= %d", + input_name.c_str(), + static_cast(input_offset), + index, static_cast(this->type_offsets_.size())); + return Type::make_error_type(); + } + + if (this->types_[index] == NULL) + { + if (!this->parse_type(index)) + return Type::make_error_type(); + } + } + + if (index < 0 + ? (static_cast(- index) >= this->builtin_types_.size() + || this->builtin_types_[- index] == NULL) + : (static_cast(index) >= this->types_.size() + || this->types_[index] == NULL)) + { + go_error_at(this->location_, + "error in %s at %lu: bad type index %d", + input_name.c_str(), + static_cast(input_offset), index); + return Type::make_error_type(); + } + + return index < 0 ? this->builtin_types_[- index] : this->types_[index]; +} + // Read an escape note. std::string @@ -1408,3 +1415,88 @@ Import_function_body::name() const { return this->named_object_->name(); } + +// Class Import_function_body. + +// Require that the next bytes match STR, issuing an error if not. +// Advance past the string. + +void +Import_function_body::require_c_string(const char* str) +{ + if (!this->match_c_string(str)) + { + if (!this->saw_error_) + go_error_at(this->location(), + "invalid export data for %qs: expected %qs at %lu", + this->name().c_str(), str, + static_cast(this->off_)); + this->saw_error_ = true; + return; + } + this->advance(strlen(str)); +} + +// Read an identifier. + +std::string +Import_function_body::read_identifier() +{ + size_t start = this->off_; + for (size_t i = start; i < this->body_.length(); i++) + { + int c = static_cast(this->body_[i]); + if (c == ' ' || c == '\n' || c == ';') + { + this->off_ = i; + return this->body_.substr(start, i - start); + } + } + this->off_ = this->body_.length(); + return this->body_.substr(start); +} + +// Read a type. + +Type* +Import_function_body::read_type() +{ + this->require_c_string("off_; + size_t i; + int c = '\0'; + for (i = start; i < this->body_.length(); ++i) + { + c = static_cast(this->body_[i]); + if (c != '-' && (c < '0' || c > '9')) + break; + } + this->off_ = i + 1; + + char *end; + long val = strtol(this->body_.substr(start, i - start).c_str(), &end, 10); + if (*end != '\0' || i > 0x7fffffff) + { + if (!this->saw_error_) + go_error_at(this->location(), + "invalid export data for %qs: expected integer at %lu", + this->name().c_str(), + static_cast(start)); + this->saw_error_ = true; + return Type::make_error_type(); + } + + if (c != '>') + { + if (!this->saw_error_) + go_error_at(this->location(), + "invalid export data for %qs: expected %<>%> at %lu", + this->name().c_str(), + static_cast(i)); + this->saw_error_ = true; + return Type::make_error_type(); + } + + return this->imp_->type_for_index(static_cast(val), this->name(), + static_cast(start)); +} diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index 3fc05dfcaa7..c2120c9afd2 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -17,10 +17,65 @@ class Type; class Named_object; class Named_type; class Expression; +class Import_function_body; + +// Expressions can be imported either directly from import data (for +// simple constant expressions that can appear in a const declaration +// or as an array length in a type definition) or from an exported +// function body (for an inlinable function). These two cases happen +// at different points in the compilation and have different +// requirements, so it's not easy to unify them. Import_expression is +// an abstract interface that permits the expression import code to +// work at either point. When importing expressions that only occur +// for an inlinable function, the ifb method is available to get the +// full Import_function_body. + +class Import_expression +{ + public: + // Return the import function body. This should only be called for + // expressions that can not appear outside of an inlinable function + // body. + virtual Import_function_body* + ifb() = 0; + + // The location to report in an error message. + virtual Location + location() const = 0; + + // Peek at the next character in the input, returning a value from 0 + // to 0xff. Returns -1 at end of stream. + virtual int + peek_char() = 0; + + // Return the next character and advance. + virtual int + get_char() = 0; + + // Return true if the next bytes match STR. + virtual bool + match_c_string(const char* str) = 0; + + // Require that the next bytes match STR. + virtual void + require_c_string(const char* str) = 0; + + // Advance the stream SKIP bytes. + virtual void + advance(size_t skip) = 0; + + // Read an identifier. + virtual std::string + read_identifier() = 0; + + // Read a type. + virtual Type* + read_type() = 0; +}; // This class manages importing Go declarations. -class Import +class Import : public Import_expression { public: // The Stream class is an interface used to read the data. The @@ -138,6 +193,9 @@ class Import // Constructor. Import(Stream*, Location); + virtual ~Import() + {} + // Register the builtin types. void register_builtin_types(Gogo*); @@ -217,10 +275,26 @@ class Import Type* read_type(); + // Return the type for a type index. INPUT_NAME and INPUT_OFFSET + // are only for error reporting. + Type* + type_for_index(int index, const std::string& input_name, + size_t input_offset); + // Read an escape note. std::string read_escape(); + // Clear the stream when it is no longer accessible. + void + clear_stream() + { this->stream_ = NULL; } + + // Just so that Import implements Import_expression. + Import_function_body* + ifb() + { return NULL; } + private: static Stream* try_package_in_directory(const std::string&, Location); @@ -468,13 +542,13 @@ class Stream_from_string_ref : public Import::Stream // Class to manage importing a function body. This is passed around // to Statements and Expressions. It parses the function into the IR. -class Import_function_body +class Import_function_body : public Import_expression { public: - Import_function_body(Gogo* gogo, Location loc, Named_object* named_object, + Import_function_body(Gogo* gogo, Import* imp, Named_object* named_object, const std::string& body, size_t off, Block* block, int indent) - : gogo_(gogo), loc_(loc), named_object_(named_object), body_(body), + : gogo_(gogo), imp_(imp), named_object_(named_object), body_(body), off_(off), block_(block), indent_(indent) { } @@ -486,7 +560,7 @@ class Import_function_body // The location to report in an error message. Location location() const - { return this->loc_; } + { return this->imp_->location(); } // A reference to the body we are reading. const std::string& @@ -503,6 +577,11 @@ class Import_function_body set_off(size_t off) { this->off_ = off; } + // Advance the offset by SKIP bytes. + void + advance(size_t skip) + { this->off_ += skip; } + // The current block. Block* block() @@ -517,11 +596,58 @@ class Import_function_body const std::string& name() const; + // Return the next character in the input stream, or -1 at the end. + int + peek_char() + { + if (this->body_.length() <= this->off_) + return -1; + return static_cast(this->body_[this->off_]); + } + + // Return the next character and advance. + int + get_char() + { + if (this->body_.length() <= this->off_) + return -1; + int c = static_cast(this->body_[this->off_]); + this->off_++; + return c; + } + + // Return whether the C string matches the current body position. + bool + match_c_string(const char* str) + { + size_t len = strlen(str); + return (this->body_.length() >= this->off_ + len + && this->body_.compare(this->off_, len, str) == 0); + } + + // Give an error if the next bytes do not match STR. Advance the + // offset by the length of STR. + void + require_c_string(const char* str); + + // Read an identifier. + std::string + read_identifier(); + + // Read a type. + Type* + read_type(); + + // Implement Import_expression. + Import_function_body* + ifb() + { return this; } + private: // The IR. Gogo* gogo_; - // The location to report in an error message. - Location loc_; + // The importer. + Import* imp_; // The function we are parsing. Named_object* named_object_; // The exported data we are parsing. Note that this is a reference; @@ -533,6 +659,9 @@ class Import_function_body Block* block_; // Current expected indentation level. int indent_; + // Whether we've seen an error. Used to avoid reporting excess + // errors. + bool saw_error_; }; #endif // !defined(GO_IMPORT_H) -- 2.30.2