compiler: support export/import of unsafe.Add/Slice
For golang/go#19367
For golang/go#40481
Change-Id: Id1aefd0696131842d480d9f9a5330c5ab221245a
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340549
Trust: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/go/export.cc b/go/export.cc
index e99c680..3d11334 100644
--- a/go/export.cc
+++ b/go/export.cc
@@ -106,11 +106,12 @@
{
public:
Collect_export_references(Export* exp,
+ const std::map<std::string, Package*>& packages,
Unordered_set(Named_object*)* exports,
Unordered_set(const Package*)* imports)
: Traverse(traverse_expressions
| traverse_types),
- exp_(exp), exports_(exports), imports_(imports),
+ exp_(exp), packages_(packages), exports_(exports), imports_(imports),
inline_fcn_worklist_(NULL), exports_finalized_(false)
{ }
@@ -150,6 +151,8 @@
// The exporter.
Export* exp_;
+ // The list of packages known to this compilation.
+ const std::map<std::string, Package*>& packages_;
// The set of named objects to export.
Unordered_set(Named_object*)* exports_;
// Set containing all directly and indirectly imported packages.
@@ -257,6 +260,24 @@
return TRAVERSE_CONTINUE;
}
+ const Call_expression* call = expr->call_expression();
+ if (call != NULL)
+ {
+ const Builtin_call_expression* bce = call->builtin_call_expression();
+ if (bce != NULL
+ && (bce->code() == Builtin_call_expression::BUILTIN_ADD
+ || bce->code() == Builtin_call_expression::BUILTIN_SLICE))
+ {
+ // This is a reference to unsafe.Add or unsafe.Slice. Make
+ // sure we list the "unsafe" package in the imports and give
+ // it a package index.
+ const std::map<std::string, Package*>::const_iterator p =
+ this->packages_.find("unsafe");
+ go_assert(p != this->packages_.end());
+ this->imports_->insert(p->second);
+ }
+ }
+
return TRAVERSE_CONTINUE;
}
@@ -589,7 +610,7 @@
// Track all imported packages mentioned in export data.
Unordered_set(const Package*) all_imports;
- Collect_export_references collect(this, &exports, &all_imports);
+ Collect_export_references collect(this, packages, &exports, &all_imports);
// Walk the set of inlinable routine bodies collected above. This
// can potentially expand the exports set.
@@ -1274,6 +1295,25 @@
return index;
}
+// Return the index of the "unsafe" package.
+
+int
+Export::unsafe_package_index() const
+{
+ for (Unordered_map(const Package*, int)::const_iterator p =
+ this->packages_.begin();
+ p != this->packages_.end();
+ ++p)
+ {
+ if (p->first->pkgpath() == "unsafe")
+ {
+ go_assert(p->second != 0);
+ return p->second;
+ }
+ }
+ go_unreachable();
+}
+
// Return the index of a type.
int
diff --git a/go/export.h b/go/export.h
index c93bced..1f61343 100644
--- a/go/export.h
+++ b/go/export.h
@@ -216,6 +216,11 @@
int
package_index(const Package* p) const;
+ // Return the index of the "unsafe" package, which must be one of
+ // the exported packages.
+ int
+ unsafe_package_index() const;
+
private:
Export(const Export&);
Export& operator=(const Export&);
@@ -377,6 +382,11 @@
package_index(const Package* p) const
{ return this->exp_->package_index(p); }
+ // Return the index of the "unsafe" package.
+ int
+ unsafe_package_index() const
+ { return this->exp_->unsafe_package_index(); }
+
// Record a temporary statement and return its index.
unsigned int
record_temporary(const Temporary_statement*);
diff --git a/go/expressions.cc b/go/expressions.cc
index 33177a7..f462b0e 100644
--- a/go/expressions.cc
+++ b/go/expressions.cc
@@ -11039,6 +11039,14 @@
// A trailing space lets us reliably identify the end of the number.
efb->write_c_string(" ");
}
+ else if (this->code_ == BUILTIN_ADD || this->code_ == BUILTIN_SLICE)
+ {
+ char buf[50];
+ snprintf(buf, sizeof buf, "<p%d>%s", efb->unsafe_package_index(),
+ (this->code_ == BUILTIN_ADD ? "Add" : "Slice"));
+ efb->write_c_string(buf);
+ this->export_arguments(efb);
+ }
else
{
const char *s = NULL;
diff --git a/go/expressions.h b/go/expressions.h
index 79a8785..9f8f4e9 100644
--- a/go/expressions.h
+++ b/go/expressions.h
@@ -732,6 +732,10 @@
call_expression()
{ return this->convert<Call_expression, EXPRESSION_CALL>(); }
+ const Call_expression*
+ call_expression() const
+ { return this->convert<const Call_expression, EXPRESSION_CALL>(); }
+
// If this is a call_result expression, return the Call_result_expression
// structure. Otherwise, return NULL. This is a controlled dynamic
// cast.
@@ -2460,13 +2464,16 @@
// Whether this is a call to builtin function.
virtual bool
- is_builtin()
+ is_builtin() const
{ return false; }
// Convert to a Builtin_call_expression, or return NULL.
inline Builtin_call_expression*
builtin_call_expression();
+ inline const Builtin_call_expression*
+ builtin_call_expression() const;
+
protected:
int
do_traverse(Traverse*);
@@ -2625,12 +2632,12 @@
};
Builtin_function_code
- code()
+ code() const
{ return this->code_; }
// This overrides Call_expression::is_builtin.
bool
- is_builtin()
+ is_builtin() const
{ return true; }
// Return whether EXPR, of array type, is a constant if passed to
@@ -2726,6 +2733,14 @@
: NULL);
}
+inline const Builtin_call_expression*
+Call_expression::builtin_call_expression() const
+{
+ return (this->is_builtin()
+ ? static_cast<const Builtin_call_expression*>(this)
+ : NULL);
+}
+
// A single result from a call which returns multiple results.
class Call_result_expression : public Expression
diff --git a/go/gogo.h b/go/gogo.h
index c49bc92..9ffd120 100644
--- a/go/gogo.h
+++ b/go/gogo.h
@@ -533,6 +533,10 @@
register_package(const std::string& pkgpath,
const std::string& pkgpath_symbol, Location);
+ // Add the unsafe bindings to the unsafe package.
+ void
+ add_unsafe_bindings(Package*);
+
// Look up a package by pkgpath, and return its pkgpath_symbol.
std::string
pkgpath_symbol_for_package(const std::string&);
diff --git a/go/import.cc b/go/import.cc
index f671416..6a5491b 100644
--- a/go/import.cc
+++ b/go/import.cc
@@ -497,6 +497,9 @@
p->set_package_name(package_name, this->location());
this->packages_.push_back(p);
+
+ if (pkgpath == "unsafe")
+ this->gogo_->add_unsafe_bindings(p);
}
// Read an indirectimport line.
@@ -515,6 +518,9 @@
p->set_package_name(package_name, this->location());
this->packages_.push_back(p);
+
+ if (pkgpath == "unsafe")
+ this->gogo_->add_unsafe_bindings(p);
}
// Read the list of import control functions and/or init graph.
diff --git a/go/unsafe.cc b/go/unsafe.cc
index 18bd99e..c4a9346 100644
--- a/go/unsafe.cc
+++ b/go/unsafe.cc
@@ -10,15 +10,12 @@
#include "types.h"
#include "gogo.h"
-// Set up the builtin unsafe package. This should probably be driven
-// by a table.
+// Set up the builtin unsafe package.
void
Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
Location location)
{
- Location bloc = Linemap::predeclared_location();
-
bool add_to_globals;
Package* package = this->add_imported_package("unsafe", local_name,
is_local_name_exported,
@@ -34,10 +31,40 @@
package->set_location(location);
this->imports_.insert(std::make_pair("unsafe", package));
+ this->add_unsafe_bindings(package);
+
+ Named_object* pointer_no = package->bindings()->lookup_local("Pointer");
+ pointer_no->type_value()->set_is_visible();
+
+ if (add_to_globals)
+ {
+ Bindings* bindings = package->bindings();
+ for (Bindings::const_declarations_iterator p =
+ bindings->begin_declarations();
+ p != bindings->end_declarations();
+ ++p)
+ this->add_dot_import_object(p->second);
+ }
+}
+
+// Add the unsafe bindings to the Package object. This should
+// probably be driven by a table.
+
+void
+Gogo::add_unsafe_bindings(Package* package)
+{
Bindings* bindings = package->bindings();
+ if (bindings->lookup_local("Sizeof") != NULL)
+ {
+ // Already done by an earlier import.
+ return;
+ }
+
+ Location bloc = Linemap::predeclared_location();
+
// The type may have already been created by an import.
- Named_object* no = package->bindings()->lookup("Pointer");
+ Named_object* no = bindings->lookup("Pointer");
if (no == NULL)
{
Type* type = Type::make_pointer_type(Type::make_void_type());
@@ -49,11 +76,12 @@
go_assert(no->package() == package);
go_assert(no->is_type());
go_assert(no->type_value()->is_unsafe_pointer_type());
- no->type_value()->set_is_visible();
}
Named_type* pointer_type = no->type_value();
- if (add_to_globals)
- this->add_named_type(pointer_type);
+
+ // This may be called during an import, so the type may not be
+ // visible yet.
+ pointer_type->clear_is_visible();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
@@ -62,9 +90,7 @@
results->push_back(Typed_identifier("", uintptr_type, bloc));
Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc);
fntype->set_is_builtin();
- no = bindings->add_function_declaration("Sizeof", package, fntype, bloc);
- if (add_to_globals)
- this->add_dot_import_object(no);
+ bindings->add_function_declaration("Sizeof", package, fntype, bloc);
// Offsetof.
results = new Typed_identifier_list;
@@ -72,9 +98,7 @@
fntype = Type::make_function_type(NULL, NULL, results, bloc);
fntype->set_is_varargs();
fntype->set_is_builtin();
- no = bindings->add_function_declaration("Offsetof", package, fntype, bloc);
- if (add_to_globals)
- this->add_dot_import_object(no);
+ bindings->add_function_declaration("Offsetof", package, fntype, bloc);
// Alignof.
results = new Typed_identifier_list;
@@ -82,25 +106,19 @@
fntype = Type::make_function_type(NULL, NULL, results, bloc);
fntype->set_is_varargs();
fntype->set_is_builtin();
- no = bindings->add_function_declaration("Alignof", package, fntype, bloc);
- if (add_to_globals)
- this->add_dot_import_object(no);
+ bindings->add_function_declaration("Alignof", package, fntype, bloc);
// Add.
results = new Typed_identifier_list;
results->push_back(Typed_identifier("", pointer_type, bloc));
fntype = Type::make_function_type(NULL, NULL, results, bloc);
fntype->set_is_builtin();
- no = bindings->add_function_declaration("Add", package, fntype, bloc);
- if (add_to_globals)
- this->add_dot_import_object(no);
+ bindings->add_function_declaration("Add", package, fntype, bloc);
// Slice.
fntype = Type::make_function_type(NULL, NULL, NULL, bloc);
fntype->set_is_builtin();
- no = bindings->add_function_declaration("Slice", package, fntype, bloc);
- if (add_to_globals)
- this->add_dot_import_object(no);
+ bindings->add_function_declaration("Slice", package, fntype, bloc);
if (!this->imported_unsafe_)
{