+2012-02-07 Ian Lance Taylor <iant@google.com>
+
+ * gccgo.texi (Function Names): Document //extern instead of
+ __asm__.
+
2012-02-01 Jakub Jelinek <jakub@redhat.com>
PR target/52079
@node Function Names
@section Function Names
-@cindex @code{__asm__}
+@cindex @code{extern}
+@cindex external names
Go code can call C functions directly using a Go extension implemented
-in @command{gccgo}: a function declaration may be followed by
-@code{__asm__ ("@var{name}")}. For example, here is how the C function
-@code{open} can be declared in Go:
+in @command{gccgo}: a function declaration may be preceded by a
+comment giving the external name. The comment must be at the
+beginning of the line and must start with @code{//extern}. This must
+be followed by a space and then the external name of the function.
+The function declaration must be on the line immediately after the
+comment. For example, here is how the C function @code{open} can be
+declared in Go:
@smallexample
-func c_open(name *byte, mode int, perm int) int __asm__ ("open");
+//extern open
+func c_open(name *byte, mode int, perm int) int
@end smallexample
The C function naturally expects a nul terminated string, which in Go
@option{-fgo-prefix} option used when the package is compiled; if the
option is not used, the default is simply @code{go}. To call the
function from C you must set the name using the @command{gcc}
-extension similar to the @command{gccgo} extension.
+@code{__asm__} extension.
@smallexample
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
Lex::Lex(const char* input_file_name, FILE* input_file, Linemap* linemap)
: input_file_name_(input_file_name), input_file_(input_file),
linemap_(linemap), linebuf_(NULL), linebufsize_(120), linesize_(0),
- lineoff_(0), lineno_(0), add_semi_at_eol_(false)
+ lineoff_(0), lineno_(0), add_semi_at_eol_(false), extern_()
{
this->linebuf_ = new char[this->linebufsize_];
this->linemap_->start_file(input_file_name, 0);
Token
Lex::next_token()
{
+ bool saw_cpp_comment = false;
while (true)
{
if (!this->require_line())
return this->make_eof_token();
}
+ if (!saw_cpp_comment)
+ this->extern_.clear();
+ saw_cpp_comment = false;
+
const char* p = this->linebuf_ + this->lineoff_;
const char* pend = this->linebuf_ + this->linesize_;
p = pend;
if (p[-1] == '\n' && this->add_semi_at_eol_)
--p;
+ saw_cpp_comment = true;
}
else if (p[1] == '*')
{
void
Lex::skip_cpp_comment()
{
+ // Ensure that if EXTERN_ is set, it means that we just saw a
+ // //extern comment.
+ this->extern_.clear();
+
const char* p = this->linebuf_ + this->lineoff_;
const char* pend = this->linebuf_ + this->linesize_;
}
}
+ // As a special gccgo extension, a C++ comment at the start of the
+ // line of the form
+ // //extern NAME
+ // which immediately precedes a function declaration means that the
+ // external name of the function declaration is NAME. This is
+ // normally used to permit Go code to call a C function.
+ if (this->lineoff_ == 2
+ && pend - p > 7
+ && memcmp(p, "extern ", 7) == 0)
+ {
+ p += 7;
+ while (p < pend && (*p == ' ' || *p == '\t'))
+ ++p;
+ const char* plend = pend;
+ while (plend > p
+ && (plend[-1] == ' ' || plend[-1] == '\t' || plend[-1] == '\n'))
+ --plend;
+ if (plend > p)
+ this->extern_ = std::string(p, plend - p);
+ }
+
while (p < pend)
{
this->lineoff_ = p - this->linebuf_;
unsigned int c;
bool issued_error;
p = this->advance_one_utf8_char(p, &c, &issued_error);
+ if (issued_error)
+ this->extern_.clear();
}
}
Token
next_token();
+ // Return the contents of any current //extern comment.
+ const std::string&
+ extern_name() const
+ { return this->extern_; }
+
// Return whether the identifier NAME should be exported. NAME is a
// mangled name which includes only ASCII characters.
static bool
size_t lineno_;
// Whether to add a semicolon if we see a newline now.
bool add_semi_at_eol_;
+ // The external name to use for a function declaration, from a magic
+ // //extern comment.
+ std::string extern_;
};
#endif // !defined(GO_LEX_H)
// FunctionDecl = "func" identifier Signature [ Block ] .
// MethodDecl = "func" Receiver identifier Signature [ Block ] .
-// gcc extension:
+// Deprecated gcc extension:
// FunctionDecl = "func" identifier Signature
// __asm__ "(" string_lit ")" .
// This extension means a function whose real name is the identifier
-// inside the asm.
+// inside the asm. This extension will be removed at some future
+// date. It has been replaced with //extern comments.
void
Parse::function_decl()
{
go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
Location location = this->location();
+ std::string extern_name = this->lex_->extern_name();
const Token* token = this->advance_token();
Typed_identifier* rec = NULL;
{
if (named_object == NULL && !Gogo::is_sink_name(name))
{
- if (fntype != NULL)
- this->gogo_->declare_function(name, fntype, location);
- else
+ if (fntype == NULL)
this->gogo_->add_erroneous_name(name);
+ else
+ {
+ named_object = this->gogo_->declare_function(name, fntype,
+ location);
+ if (!extern_name.empty()
+ && named_object->is_function_declaration())
+ {
+ Function_declaration* fd =
+ named_object->func_declaration_value();
+ fd->set_asm_name(extern_name);
+ }
+ }
}
}
else
return err
}
-func ioctl(int, int, unsafe.Pointer) int __asm__("ioctl")
+//extern ioctl
+func ioctl(int, int, unsafe.Pointer) int
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
// Special cases are:
// Abs(±Inf) = +Inf
// Abs(NaN) = NaN
-func libc_fabs(float64) float64 __asm__("fabs")
+
+//extern fabs
+func libc_fabs(float64) float64
+
func Abs(x float64) float64 {
return libc_fabs(x)
}
// Special cases are:
// Asin(±0) = ±0
// Asin(x) = NaN if x < -1 or x > 1
-func libc_asin(float64) float64 __asm__("asin")
+
+//extern asin
+func libc_asin(float64) float64
+
func Asin(x float64) float64 {
return libc_asin(x)
}
//
// Special case is:
// Acos(x) = NaN if x < -1 or x > 1
-func libc_acos(float64) float64 __asm__("acos")
+
+//extern acos
+func libc_acos(float64) float64
+
func Acos(x float64) float64 {
return libc_acos(x)
}
// Special cases are:
// Atan(±0) = ±0
// Atan(±Inf) = ±Pi/2
-func libc_atan(float64) float64 __asm__("atan")
+
+//extern atan
+func libc_atan(float64) float64
+
func Atan(x float64) float64 {
return libc_atan(x)
}
// Atan2(y<0, -Inf) = -Pi
// Atan2(+Inf, x) = +Pi/2
// Atan2(-Inf, x) = -Pi/2
-func libc_atan2(float64, float64) float64 __asm__("atan2")
+
+//extern atan2
+func libc_atan2(float64, float64) float64
+
func Atan2(y, x float64) float64 {
return libc_atan2(y, x)
}
// Exp(NaN) = NaN
// Very large values overflow to 0 or +Inf.
// Very small values underflow to 1.
-func libc_exp(float64) float64 __asm__("exp")
+
+//extern exp
+func libc_exp(float64) float64
+
func Exp(x float64) float64 {
return libc_exp(x)
}
// Expm1(-Inf) = -1
// Expm1(NaN) = NaN
// Very large values overflow to -1 or +Inf.
-func libc_expm1(float64) float64 __asm__("expm1")
+
+//extern expm1
+func libc_expm1(float64) float64
+
func Expm1(x float64) float64 {
return libc_expm1(x)
}
// Floor(±0) = ±0
// Floor(±Inf) = ±Inf
// Floor(NaN) = NaN
-func libc_floor(float64) float64 __asm__("floor")
+
+//extern floor
+func libc_floor(float64) float64
+
func Floor(x float64) float64 {
return libc_floor(x)
}
// Ceil(±0) = ±0
// Ceil(±Inf) = ±Inf
// Ceil(NaN) = NaN
-func libc_ceil(float64) float64 __asm__("ceil")
+
+//extern ceil
+func libc_ceil(float64) float64
+
func Ceil(x float64) float64 {
return libc_ceil(x)
}
// Trunc(±0) = ±0
// Trunc(±Inf) = ±Inf
// Trunc(NaN) = NaN
-func libc_trunc(float64) float64 __asm__("trunc")
+
+//extern trunc
+func libc_trunc(float64) float64
+
func Trunc(x float64) float64 {
return libc_trunc(x)
}
// Ldexp(±0, exp) = ±0
// Ldexp(±Inf, exp) = ±Inf
// Ldexp(NaN, exp) = NaN
-func libc_ldexp(float64, int) float64 __asm__("ldexp")
+
+//extern ldexp
+func libc_ldexp(float64, int) float64
+
func Ldexp(frac float64, exp int) float64 {
return libc_ldexp(frac, exp)
}
// Log(0) = -Inf
// Log(x < 0) = NaN
// Log(NaN) = NaN
-func libc_log(float64) float64 __asm__("log")
+
+//extern log
+func libc_log(float64) float64
+
func Log(x float64) float64 {
return libc_log(x)
}
// Log10 returns the decimal logarithm of x.
// The special cases are the same as for Log.
-func libc_log10(float64) float64 __asm__("log10")
+
+//extern log10
+func libc_log10(float64) float64
+
func Log10(x float64) float64 {
return libc_log10(x)
}
// Log2 returns the binary logarithm of x.
// The special cases are the same as for Log.
-func libc_log2(float64) float64 __asm__("log2")
+
+//extern log2
+func libc_log2(float64) float64
+
func Log2(x float64) float64 {
return libc_log2(x)
}
// Log1p(-1) = -Inf
// Log1p(x < -1) = NaN
// Log1p(NaN) = NaN
-func libc_log1p(float64) float64 __asm__("log1p")
+
+//extern log1p
+func libc_log1p(float64) float64
+
func Log1p(x float64) float64 {
return libc_log1p(x)
}
// Mod(x, 0) = NaN
// Mod(x, ±Inf) = x
// Mod(x, NaN) = NaN
-func libc_fmod(float64, float64) float64 __asm__("fmod")
+
+//extern fmod
+func libc_fmod(float64, float64) float64
+
func Mod(x, y float64) float64 {
return libc_fmod(x, y)
}
// Special cases are:
// Cos(±Inf) = NaN
// Cos(NaN) = NaN
-func libc_cos(float64) float64 __asm__("cos")
+
+//extern cos
+func libc_cos(float64) float64
+
func Cos(x float64) float64 {
return libc_cos(x)
}
// Sin(±0) = ±0
// Sin(±Inf) = NaN
// Sin(NaN) = NaN
-func libc_sin(float64) float64 __asm__("sin")
+
+//extern sin
+func libc_sin(float64) float64
+
func Sin(x float64) float64 {
return libc_sin(x)
}
// Sqrt(±0) = ±0
// Sqrt(x < 0) = NaN
// Sqrt(NaN) = NaN
-func libc_sqrt(float64) float64 __asm__("sqrt")
+
+//extern sqrt
+func libc_sqrt(float64) float64
+
func Sqrt(x float64) float64 {
return libc_sqrt(x)
}
// Tan(±0) = ±0
// Tan(±Inf) = NaN
// Tan(NaN) = NaN
-func libc_tan(float64) float64 __asm__("tan")
+
+//extern tan
+func libc_tan(float64) float64
+
func Tan(x float64) float64 {
return libc_tan(x)
}
"unsafe"
)
-func libc_getaddrinfo(node *byte, service *byte, hints *syscall.Addrinfo, res **syscall.Addrinfo) int __asm__ ("getaddrinfo")
-func libc_freeaddrinfo(res *syscall.Addrinfo) __asm__ ("freeaddrinfo")
-func libc_gai_strerror(errcode int) *byte __asm__ ("gai_strerror")
+//extern getaddrinfo
+func libc_getaddrinfo(node *byte, service *byte, hints *syscall.Addrinfo, res **syscall.Addrinfo) int
+
+//extern freeaddrinfo
+func libc_freeaddrinfo(res *syscall.Addrinfo)
+
+//extern gai_strerror
+func libc_gai_strerror(errcode int) *byte
// bytePtrToString takes a NUL-terminated array of bytes and convert
// it to a Go string.
"unsafe"
)
-func libc_dup(fd int) int __asm__ ("dup")
-func libc_opendir(*byte) *syscall.DIR __asm__ ("opendir")
-func libc_closedir(*syscall.DIR) int __asm__ ("closedir")
+//extern opendir
+func libc_opendir(*byte) *syscall.DIR
+
+//extern closedir
+func libc_closedir(*syscall.DIR) int
// FIXME: pathconf returns long, not int.
-func libc_pathconf(*byte, int) int __asm__ ("pathconf")
+//extern pathconf
+func libc_pathconf(*byte, int) int
func clen(n []byte) int {
for i := 0; i < len(n); i++ {
return len(n)
}
-var elen int;
+var elen int
func (file *File) readdirnames(n int) (names []string, err error) {
if elen == 0 {
- var dummy syscall.Dirent;
+ var dummy syscall.Dirent
elen = (unsafe.Offsetof(dummy.Name) +
- libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
- 1);
+ libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
+ 1)
}
if file.dirinfo == nil {
dir := file.dirinfo.dir
if dir == nil {
return names, NewSyscallError("opendir", syscall.GetErrno())
- }
+ }
for n != 0 {
var result *syscall.Dirent
break // EOF
}
var name = string(result.Name[0:clen(result.Name[0:])])
- if name == "." || name == ".." { // Useless names
+ if name == "." || name == ".." { // Useless names
continue
}
names = append(names, name)
import "syscall"
-func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno __asm__ ("readdir64_r")
+//extern readdir64_r
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno
import "syscall"
-func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno __asm__ ("readdir_r")
+// extern readdir_r
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno
}
*/
-func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwnam_r")
-func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwuid_r")
+//extern getpwnam_r
+func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
+
+//extern getpwuid_r
+func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
// bytePtrToString takes a NUL-terminated array of bytes and convert
// it to a Go string.
cfnresult = line
printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
- printf("func c_%s(%s) %s%s__asm__(\"%s\")\n",
- cfnname, cfnparams, cfnresult, cfnresult == "" ? "" : " ", cfnname)
+ printf("//extern %s\n", cfnname)
+ printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
printf("func %s(%s) %s%s%s%s{\n",
gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")
Stderr = 2
)
-func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 __asm__ ("syscall");
-func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("syscall");
+//extern syscall
+func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32
+
+//extern syscall
+func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64
const darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64"
var r uintptr
if unsafe.Sizeof(r) == 4 {
r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
- int32(a4), int32(a5), int32(a6))
+ int32(a4), int32(a5), int32(a6))
r = uintptr(r1)
} else {
r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
var r uintptr
if unsafe.Sizeof(r) == 4 {
r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
- int32(a4), int32(a5), int32(a6))
+ int32(a4), int32(a5), int32(a6))
r = uintptr(r1)
} else {
r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),