* Go patch committed: Support unsafe.Add and unsafe.Slice
@ 2021-08-02 22:23 Ian Lance Taylor
2021-08-07 20:38 ` Ian Lance Taylor
0 siblings, 1 reply; 2+ messages in thread
From: Ian Lance Taylor @ 2021-08-02 22:23 UTC (permalink / raw)
To: gcc-patches, gofrontend-dev
[-- Attachment #1: Type: text/plain, Size: 284 bytes --]
The upcoming Go 1.17 release adds two new functions to the unsafe
package: unsafe.Add and unsafe.Slice. These functions must be
implemented in the compiler. This patch implements them for gccgo.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed
to mainline.
Ian
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 14331 bytes --]
06d0437d4a5faca2b695918cbe1d54a61935c98b
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 5323e186eab..19fbd647840 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-920549b6382a2623538d31001271941f0e9e5a51
+ad667e7c70cea9fa5730660d72ad891b5753eb62
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 a0472acc209..46e71e5a13b 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -8252,12 +8252,16 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
this->code_ = BUILTIN_REAL;
else if (name == "recover")
this->code_ = BUILTIN_RECOVER;
+ else if (name == "Add")
+ this->code_ = BUILTIN_ADD;
else if (name == "Alignof")
this->code_ = BUILTIN_ALIGNOF;
else if (name == "Offsetof")
this->code_ = BUILTIN_OFFSETOF;
else if (name == "Sizeof")
this->code_ = BUILTIN_SIZEOF;
+ else if (name == "Slice")
+ this->code_ = BUILTIN_SLICE;
else
go_unreachable();
}
@@ -8694,6 +8698,119 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
return Runtime::make_call(code, loc, 3, e1, e2, e3);
}
+
+ case BUILTIN_ADD:
+ {
+ Expression* ptr = this->args()->front();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ ptr = Expression::make_cast(uintptr_type, ptr, loc);
+ Expression* len = this->args()->back();
+ len = Expression::make_cast(uintptr_type, len, loc);
+ Expression* add = Expression::make_binary(OPERATOR_PLUS, ptr, len,
+ loc);
+ return Expression::make_cast(this->args()->front()->type(), add, loc);
+ }
+
+ case BUILTIN_SLICE:
+ {
+ Expression* ptr = this->args()->front();
+ Temporary_statement* ptr_temp = NULL;
+ if (!ptr->is_multi_eval_safe())
+ {
+ ptr_temp = Statement::make_temporary(NULL, ptr, loc);
+ inserter->insert(ptr_temp);
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+ }
+
+ Expression* len = this->args()->back();
+ Temporary_statement* len_temp = NULL;
+ if (!len->is_multi_eval_safe())
+ {
+ len_temp = Statement::make_temporary(NULL, len, loc);
+ inserter->insert(len_temp);
+ len = Expression::make_temporary_reference(len_temp, loc);
+ }
+
+ bool fits_in_int;
+ Numeric_constant nc;
+ if (this->args()->back()->numeric_constant_value(&nc))
+ {
+ // We gave an error for constants that don't fit in int in
+ // check_types.
+ fits_in_int = true;
+ }
+ else
+ {
+ Integer_type* itype = this->args()->back()->type()->integer_type();
+ go_assert(itype != NULL);
+ int ebits = itype->bits();
+ int intbits =
+ Type::lookup_integer_type("int")->integer_type()->bits();
+
+ // We can treat ebits == intbits as small even for an
+ // unsigned integer type, because we will convert the
+ // value to int and then reject it in the runtime if it is
+ // negative.
+
+ fits_in_int = ebits <= intbits;
+ }
+
+ Runtime::Function code = (fits_in_int
+ ? Runtime::UNSAFESLICE
+ : Runtime::UNSAFESLICE64);
+ Expression* td =
+ Expression::make_type_descriptor(ptr->type()->points_to(), loc);
+ Expression* check = Runtime::make_call(code, loc, 3,
+ td, ptr, len);
+
+ if (ptr_temp == NULL)
+ ptr = ptr->copy();
+ else
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+ Expression* nil = Expression::make_nil(loc);
+ nil = Expression::make_cast(ptr->type(), nil, loc);
+ Expression* is_nil = Expression::make_binary(OPERATOR_EQEQ, ptr, nil,
+ loc);
+
+ if (len_temp == NULL)
+ len = len->copy();
+ else
+ len = Expression::make_temporary_reference(len_temp, loc);
+ Expression* zero = Expression::make_integer_ul(0, len->type(), loc);
+ Expression* is_zero = Expression::make_binary(OPERATOR_EQEQ, len, zero,
+ loc);
+
+ Expression* cond = Expression::make_binary(OPERATOR_ANDAND, is_nil,
+ is_zero, loc);
+
+ Type* slice_type = Type::make_array_type(ptr->type()->points_to(),
+ NULL);
+ nil = Expression::make_nil(loc);
+ Expression* nil_slice = Expression::make_cast(slice_type, nil, loc);
+
+ if (ptr_temp == NULL)
+ ptr = ptr->copy();
+ else
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+
+ if (len_temp == NULL)
+ len = len->copy();
+ else
+ len = Expression::make_temporary_reference(len_temp, loc);
+
+ Expression* cap;
+ if (len_temp == NULL)
+ cap = len->copy();
+ else
+ cap = Expression::make_temporary_reference(len_temp, loc);
+
+ Expression* slice = Expression::make_slice_value(slice_type, ptr,
+ len, cap, loc);
+
+ slice = Expression::make_conditional(cond, nil_slice, slice, loc);
+
+ return Expression::make_compound(check, slice, loc);
+ }
}
return this;
@@ -9781,9 +9898,11 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_MAKE:
case BUILTIN_NEW:
case BUILTIN_REAL:
+ case BUILTIN_ADD:
case BUILTIN_ALIGNOF:
case BUILTIN_OFFSETOF:
case BUILTIN_SIZEOF:
+ case BUILTIN_SLICE:
this->unused_value_error();
return false;
@@ -9890,6 +10009,18 @@ Builtin_call_expression::do_type()
t = Type::make_error_type();
return t;
}
+
+ case BUILTIN_ADD:
+ return Type::make_pointer_type(Type::make_void_type());
+
+ case BUILTIN_SLICE:
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() != 2)
+ return Type::make_error_type();
+ Type* pt = args->front()->type()->points_to();
+ if (pt == NULL)
+ return Type::make_error_type();
+ return Type::make_array_type(pt, NULL);
}
}
@@ -9954,6 +10085,28 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
is_print = false;
break;
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
+ // Both unsafe.Add and unsafe.Slice take two arguments, and the
+ // second arguments defaults to "int".
+ if (args != NULL && args->size() == 2)
+ {
+ if (this->code_ == BUILTIN_SLICE)
+ args->front()->determine_type_no_context();
+ else
+ {
+ Type* pointer = Type::make_pointer_type(Type::make_void_type());
+ Type_context subcontext(pointer, false);
+ args->front()->determine_type(&subcontext);
+ }
+ Type* int_type = Type::lookup_integer_type("int");
+ Type_context subcontext(int_type, false);
+ args->back()->determine_type(&subcontext);
+ return;
+ }
+ is_print = false;
+ break;
+
default:
is_print = false;
break;
@@ -10353,6 +10506,78 @@ Builtin_call_expression::do_check_types(Gogo*)
}
break;
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
+ {
+ Numeric_constant nc;
+ unsigned long v;
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() < 2)
+ this->report_error(_("not enough arguments"));
+ else if (args->size() > 2)
+ this->report_error(_("too many arguments"));
+ else if (args->front()->is_error_expression()
+ || args->front()->type()->is_error()
+ || args->back()->is_error_expression()
+ || args->back()->type()->is_error())
+ this->set_is_error();
+ else if (args->back()->type()->integer_type() == NULL
+ && (!args->back()->type()->is_abstract()
+ || !args->back()->numeric_constant_value(&nc)
+ || (nc.to_unsigned_long(&v)
+ == Numeric_constant::NC_UL_NOTINT)))
+ {
+ if (this->code_ == BUILTIN_ADD)
+ go_error_at(args->back()->location(), "non-integer offset");
+ else
+ go_error_at(args->back()->location(), "non-integer size");
+ }
+ else if (this->code_ == BUILTIN_ADD)
+ {
+ Type* pointer_type =
+ Type::make_pointer_type(Type::make_void_type());
+ std::string reason;
+ if (!Type::are_assignable(pointer_type, args->front()->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at(args->front()->location(),
+ "argument 1 has incompatible type");
+ else
+ go_error_at(args->front()->location(),
+ "argument 1 has incompatible type (%s)",
+ reason.c_str());
+ this->set_is_error();
+ }
+ }
+ else
+ {
+ if (args->front()->type()->points_to() == NULL)
+ {
+ go_error_at(args->front()->location(),
+ "argument 1 must be a pointer");
+ this->set_is_error();
+ }
+
+ unsigned int int_bits =
+ Type::lookup_integer_type("int")->integer_type()->bits();
+
+ mpz_t ival;
+ if (args->back()->numeric_constant_value(&nc) && nc.to_int(&ival))
+ {
+ if (mpz_sgn(ival) < 0
+ || mpz_sizeinbase(ival, 2) >= int_bits)
+ {
+ go_error_at(args->back()->location(),
+ "slice length out of range");
+ this->set_is_error();
+ }
+ mpz_clear(ival);
+ }
+ }
+ }
+ break;
+
default:
go_unreachable();
}
@@ -10397,6 +10622,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
case BUILTIN_INVALID:
case BUILTIN_NEW:
case BUILTIN_MAKE:
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
go_unreachable();
case BUILTIN_LEN:
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 57c974d3c70..492849bb33e 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -2608,9 +2608,11 @@ class Builtin_call_expression : public Call_expression
BUILTIN_RECOVER,
// Builtin functions from the unsafe package.
+ BUILTIN_ADD,
BUILTIN_ALIGNOF,
BUILTIN_OFFSETOF,
- BUILTIN_SIZEOF
+ BUILTIN_SIZEOF,
+ BUILTIN_SLICE
};
Builtin_function_code
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index ec01be0afe4..231d92d2661 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -489,6 +489,12 @@ DEF_GO_RUNTIME(ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1",
P3(POINTER, UINT8, INT32),
R1(UINT8))
+// Check the length of an unsafe slice.
+DEF_GO_RUNTIME(UNSAFESLICE, "runtime.unsafeslice",
+ P3(TYPE, POINTER, INT), R0())
+DEF_GO_RUNTIME(UNSAFESLICE64, "runtime.unsafeslice64",
+ P3(TYPE, POINTER, INT64), R0())
+
// Panic reporting a division by zero.
DEF_GO_RUNTIME(PANIC_DIVIDE, "runtime.panicdivide", P0(), R0())
diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc
index 9ed5b9d0d3c..18bd99eca15 100644
--- a/gcc/go/gofrontend/unsafe.cc
+++ b/gcc/go/gofrontend/unsafe.cc
@@ -86,6 +86,22 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
if (add_to_globals)
this->add_dot_import_object(no);
+ // 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);
+
+ // 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);
+
if (!this->imported_unsafe_)
{
go_imported_unsafe();
diff --git a/gcc/testsuite/go.test/test/unsafebuiltins.go b/gcc/testsuite/go.test/test/unsafebuiltins.go
new file mode 100644
index 00000000000..4c940aa8559
--- /dev/null
+++ b/gcc/testsuite/go.test/test/unsafebuiltins.go
@@ -0,0 +1,64 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "math"
+ "unsafe"
+)
+
+const maxUintptr = 1 << (8 * unsafe.Sizeof(uintptr(0)))
+
+func main() {
+ var p [10]byte
+
+ // unsafe.Add
+ {
+ p1 := unsafe.Pointer(&p[1])
+ assert(unsafe.Add(p1, 1) == unsafe.Pointer(&p[2]))
+ assert(unsafe.Add(p1, -1) == unsafe.Pointer(&p[0]))
+ }
+
+ // unsafe.Slice
+ {
+ s := unsafe.Slice(&p[0], len(p))
+ assert(&s[0] == &p[0])
+ assert(len(s) == len(p))
+ assert(cap(s) == len(p))
+
+ // nil pointer with zero length returns nil
+ assert(unsafe.Slice((*int)(nil), 0) == nil)
+
+ // nil pointer with positive length panics
+ mustPanic(func() { _ = unsafe.Slice((*int)(nil), 1) })
+
+ // negative length
+ var neg int = -1
+ mustPanic(func() { _ = unsafe.Slice(new(byte), neg) })
+
+ // length too large
+ var tooBig uint64 = math.MaxUint64
+ mustPanic(func() { _ = unsafe.Slice(new(byte), tooBig) })
+
+ // size overflows address space
+ mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8) })
+ mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8+1) })
+ }
+}
+
+func assert(ok bool) {
+ if !ok {
+ panic("FAIL")
+ }
+}
+
+func mustPanic(f func()) {
+ defer func() {
+ assert(recover() != nil)
+ }()
+ f()
+}
diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go
index 27a97773169..d4c0e9028b7 100644
--- a/libgo/go/runtime/slice.go
+++ b/libgo/go/runtime/slice.go
@@ -18,6 +18,8 @@ import (
//go:linkname checkMakeSlice
//go:linkname makeslice64
//go:linkname growslice
+//go:linkname unsafeslice
+//go:linkname unsafeslice64
type slice struct {
array unsafe.Pointer
@@ -127,6 +129,33 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
return makeslice(et, len, cap)
}
+func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
+ if len == 0 {
+ return
+ }
+
+ if ptr == nil {
+ panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+ }
+
+ mem, overflow := math.MulUintptr(et.size, uintptr(len))
+ if overflow || mem > maxAlloc || len < 0 {
+ panicunsafeslicelen()
+ }
+}
+
+func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
+ len := int(len64)
+ if int64(len) != len64 {
+ panicunsafeslicelen()
+ }
+ unsafeslice(et, ptr, len)
+}
+
+func panicunsafeslicelen() {
+ panic(errorString("unsafe.Slice: len out of range"))
+}
+
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Go patch committed: Support unsafe.Add and unsafe.Slice
2021-08-02 22:23 Go patch committed: Support unsafe.Add and unsafe.Slice Ian Lance Taylor
@ 2021-08-07 20:38 ` Ian Lance Taylor
0 siblings, 0 replies; 2+ messages in thread
From: Ian Lance Taylor @ 2021-08-07 20:38 UTC (permalink / raw)
To: gcc-patches, gofrontend-dev
[-- Attachment #1: Type: text/plain, Size: 570 bytes --]
On Mon, Aug 2, 2021 at 3:23 PM Ian Lance Taylor <iant@golang.org> wrote:
>
> The upcoming Go 1.17 release adds two new functions to the unsafe
> package: unsafe.Add and unsafe.Slice. These functions must be
> implemented in the compiler. This patch implements them for gccgo.
> Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed
> to mainline.
This patch makes unsafe.Add and unsafe.Slice work when they appear in
functions that can be inlined across packages. Bootstrapped and ran
Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 12858 bytes --]
b00c45d66d337e18a02674075ca792fd38094acf
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 9ed527f7eb4..b983fdab35c 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-747f3a2d78c073e9b03dd81914d0edb7ddc5be14
+d5d51242efc432fa62d4e9b141b01c280af32d19
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/export.cc b/gcc/go/gofrontend/export.cc
index e99c680f709..3d11334884d 100644
--- a/gcc/go/gofrontend/export.cc
+++ b/gcc/go/gofrontend/export.cc
@@ -106,11 +106,12 @@ class Collect_export_references : public Traverse
{
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 @@ class Collect_export_references : public Traverse
// 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 @@ Collect_export_references::expression(Expression** pexpr)
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 @@ Export::export_globals(const std::string& package_name,
// 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 @@ Export::package_index(const Package* pkg) const
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/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h
index c93bced4eb4..1f613434cab 100644
--- a/gcc/go/gofrontend/export.h
+++ b/gcc/go/gofrontend/export.h
@@ -216,6 +216,11 @@ class Export : public String_dump
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 @@ class Export_function_body : public String_dump
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/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 33177a709ab..f462b0e2a34 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -11039,6 +11039,14 @@ Builtin_call_expression::do_export(Export_function_body* efb) const
// 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/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 79a8785b69d..9f8f4e9255b 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -732,6 +732,10 @@ class Expression
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 @@ class Call_expression : public Expression
// 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 @@ class Builtin_call_expression : public Call_expression
};
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 @@ Call_expression::builtin_call_expression()
: 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/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index c49bc92b3e0..9ffd120290d 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -533,6 +533,10 @@ class Gogo
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/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index f671416a423..6a5491be949 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -497,6 +497,9 @@ Import::read_one_import()
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 @@ Import::read_one_indirect_import()
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/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc
index 18bd99eca15..c4a9346ca3e 100644
--- a/gcc/go/gofrontend/unsafe.cc
+++ b/gcc/go/gofrontend/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 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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_)
{
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-08-07 20:38 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-02 22:23 Go patch committed: Support unsafe.Add and unsafe.Slice Ian Lance Taylor
2021-08-07 20:38 ` Ian Lance Taylor
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).