mirror of git://gcc.gnu.org/git/gcc.git
compiler: add -fgo-c-header=FILE to create a C header
The new -fgo-c-header=FILE option will write a C header file defining
all the struct types and numeric const values in package scope. This
will be used when building the Go runtime package (libgo/go/runtime) to
generate a C header file that may be included by the C code in the C
runtime package (libgo/runtime).
This will ensure that the Go code and C code are working with the same
data structures as we convert the runtime from C to Go to upgrade to the
current GC runtime, notably the concurrent garbage collector.
Reviewed-on: https://go-review.googlesource.com/28000
* lang.opt (fgo-c-header, fgo-compiling-runtime): New options.
* go-c.h (struct go_create_gogo_args): Define.
(go_create_gogo): Change declaration to take struct pointer.
* go-lang.c (go_c_header): New static variable.
(go_langhook_init): Update call to go_create_gogo.
* gccgo.texi (Invoking gccgo): Document -fgo-c-header and
-fgo-compiling-runtime.
From-SVN: r239852
This commit is contained in:
parent
0b390d6089
commit
2adb671d18
|
|
@ -1,3 +1,13 @@
|
|||
2016-08-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* lang.opt (fgo-c-header, fgo-compiling-runtime): New options.
|
||||
* go-c.h (struct go_create_gogo_args): Define.
|
||||
(go_create_gogo): Change declaration to take struct pointer.
|
||||
* go-lang.c (go_c_header): New static variable.
|
||||
(go_langhook_init): Update call to go_create_gogo.
|
||||
* gccgo.texi (Invoking gccgo): Document -fgo-c-header and
|
||||
-fgo-compiling-runtime.
|
||||
|
||||
2016-08-09 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* gccgo.texi (Invoking gccgo): Document -fgo-optimize-allocs and
|
||||
|
|
|
|||
|
|
@ -239,6 +239,17 @@ heap when possible. In the future this may be the default.
|
|||
Output escape analysis debugging information. Larger values of
|
||||
@var{n} generate more information.
|
||||
|
||||
@item -fgo-c-header=@var{file}
|
||||
@cindex @option{-fgo-c-header}
|
||||
Write top-level named Go struct definitions to @var{file} as C code.
|
||||
This is used when compiling the runtime package.
|
||||
|
||||
@item -fgo-compiling-runtime
|
||||
@cindex @option{-fgo-compiling-runtime}
|
||||
Apply special rules for compiling the runtime package. Implicit
|
||||
memory allocation is forbidden. Some additional compiler directives
|
||||
are supported.
|
||||
|
||||
@item -g
|
||||
@cindex @option{-g for gccgo}
|
||||
This is the standard @command{gcc} option (@pxref{Debugging Options, ,
|
||||
|
|
|
|||
|
|
@ -31,11 +31,21 @@ extern int go_enable_optimize (const char*);
|
|||
|
||||
extern void go_add_search_path (const char*);
|
||||
|
||||
extern void go_create_gogo (int int_type_size, int pointer_size,
|
||||
const char* pkgpath, const char *prefix,
|
||||
const char *relative_import_path,
|
||||
bool check_divide_zero, bool check_divide_overflow,
|
||||
int debug_escape_level);
|
||||
struct go_create_gogo_args
|
||||
{
|
||||
int int_type_size;
|
||||
int pointer_size;
|
||||
const char* pkgpath;
|
||||
const char *prefix;
|
||||
const char *relative_import_path;
|
||||
const char *c_header;
|
||||
bool check_divide_by_zero;
|
||||
bool check_divide_overflow;
|
||||
bool compiling_runtime;
|
||||
int debug_escape_level;
|
||||
};
|
||||
|
||||
extern void go_create_gogo (const struct go_create_gogo_args*);
|
||||
|
||||
extern void go_parse_input_files (const char**, unsigned int,
|
||||
bool only_check_syntax,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ struct GTY(()) language_function
|
|||
static const char *go_pkgpath = NULL;
|
||||
static const char *go_prefix = NULL;
|
||||
static const char *go_relative_import_path = NULL;
|
||||
static const char *go_c_header = NULL;
|
||||
|
||||
/* Language hooks. */
|
||||
|
||||
|
|
@ -99,9 +100,18 @@ go_langhook_init (void)
|
|||
to, e.g., unsigned_char_type_node) but before calling
|
||||
build_common_builtin_nodes (because it calls, indirectly,
|
||||
go_type_for_size). */
|
||||
go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix,
|
||||
go_relative_import_path, go_check_divide_zero,
|
||||
go_check_divide_overflow, go_debug_escape_level);
|
||||
struct go_create_gogo_args args;
|
||||
args.int_type_size = INT_TYPE_SIZE;
|
||||
args.pointer_size = POINTER_SIZE;
|
||||
args.pkgpath = go_pkgpath;
|
||||
args.prefix = go_prefix;
|
||||
args.relative_import_path = go_relative_import_path;
|
||||
args.c_header = go_c_header;
|
||||
args.check_divide_by_zero = go_check_divide_zero;
|
||||
args.check_divide_overflow = go_check_divide_overflow;
|
||||
args.compiling_runtime = go_compiling_runtime;
|
||||
args.debug_escape_level = go_debug_escape_level;
|
||||
go_create_gogo (&args);
|
||||
|
||||
build_common_builtin_nodes ();
|
||||
|
||||
|
|
@ -247,6 +257,10 @@ go_langhook_handle_option (
|
|||
go_relative_import_path = arg;
|
||||
break;
|
||||
|
||||
case OPT_fgo_c_header_:
|
||||
go_c_header = arg;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Just return 1 to indicate that the option is valid. */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
0e505f5d191182abd8beb9b4c8232174bc116f97
|
||||
9c91e7eeb404b5b639cd6e80e2a38da948bb35ec
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
|||
|
|
@ -20,27 +20,29 @@ static Gogo* gogo;
|
|||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
|
||||
const char *prefix, const char *relative_import_path,
|
||||
bool check_divide_by_zero, bool check_divide_overflow,
|
||||
int debug_escape_level)
|
||||
go_create_gogo(const struct go_create_gogo_args* args)
|
||||
{
|
||||
go_assert(::gogo == NULL);
|
||||
Linemap* linemap = go_get_linemap();
|
||||
::gogo = new Gogo(go_get_backend(), linemap, int_type_size, pointer_size);
|
||||
::gogo = new Gogo(go_get_backend(), linemap, args->int_type_size,
|
||||
args->pointer_size);
|
||||
|
||||
if (pkgpath != NULL)
|
||||
::gogo->set_pkgpath(pkgpath);
|
||||
else if (prefix != NULL)
|
||||
::gogo->set_prefix(prefix);
|
||||
if (args->pkgpath != NULL)
|
||||
::gogo->set_pkgpath(args->pkgpath);
|
||||
else if (args->prefix != NULL)
|
||||
::gogo->set_prefix(args->prefix);
|
||||
|
||||
if (relative_import_path != NULL)
|
||||
::gogo->set_relative_import_path(relative_import_path);
|
||||
if (check_divide_by_zero)
|
||||
::gogo->set_check_divide_by_zero(check_divide_by_zero);
|
||||
if (check_divide_overflow)
|
||||
::gogo->set_check_divide_overflow(check_divide_overflow);
|
||||
::gogo->set_debug_escape_level(debug_escape_level);
|
||||
if (args->relative_import_path != NULL)
|
||||
::gogo->set_relative_import_path(args->relative_import_path);
|
||||
if (args->check_divide_by_zero)
|
||||
::gogo->set_check_divide_by_zero(args->check_divide_by_zero);
|
||||
if (args->check_divide_overflow)
|
||||
::gogo->set_check_divide_overflow(args->check_divide_overflow);
|
||||
if (args->compiling_runtime)
|
||||
::gogo->set_compiling_runtime(args->compiling_runtime);
|
||||
if (args->c_header != NULL)
|
||||
::gogo->set_c_header(args->c_header);
|
||||
::gogo->set_debug_escape_level(args->debug_escape_level);
|
||||
}
|
||||
|
||||
// Parse the input files.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "go-system.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "filenames.h"
|
||||
|
||||
#include "go-c.h"
|
||||
|
|
@ -4429,6 +4431,131 @@ Gogo::do_exports()
|
|||
: ""),
|
||||
this->imported_init_fns_,
|
||||
this->package_->bindings());
|
||||
|
||||
if (!this->c_header_.empty() && !saw_errors())
|
||||
this->write_c_header();
|
||||
}
|
||||
|
||||
// Write the top level named struct types in C format to a C header
|
||||
// file. This is used when building the runtime package, to share
|
||||
// struct definitions between C and Go.
|
||||
|
||||
void
|
||||
Gogo::write_c_header()
|
||||
{
|
||||
std::ofstream out;
|
||||
out.open(this->c_header_.c_str());
|
||||
if (out.fail())
|
||||
{
|
||||
error("cannot open %s: %m", this->c_header_.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<Named_object*> types;
|
||||
Bindings* top = this->package_->bindings();
|
||||
for (Bindings::const_definitions_iterator p = top->begin_definitions();
|
||||
p != top->end_definitions();
|
||||
++p)
|
||||
{
|
||||
Named_object* no = *p;
|
||||
if (no->is_type() && no->type_value()->struct_type() != NULL)
|
||||
types.push_back(no);
|
||||
if (no->is_const() && no->const_value()->type()->integer_type() != NULL)
|
||||
{
|
||||
Numeric_constant nc;
|
||||
unsigned long val;
|
||||
if (no->const_value()->expr()->numeric_constant_value(&nc)
|
||||
&& nc.to_unsigned_long(&val) == Numeric_constant::NC_UL_VALID)
|
||||
{
|
||||
out << "#define " << no->message_name() << ' ' << val
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const Named_object*> written;
|
||||
int loop = 0;
|
||||
while (!types.empty())
|
||||
{
|
||||
Named_object* no = types.front();
|
||||
types.pop_front();
|
||||
|
||||
std::vector<const Named_object*> requires;
|
||||
std::vector<const Named_object*> declare;
|
||||
if (!no->type_value()->struct_type()->can_write_to_c_header(&requires,
|
||||
&declare))
|
||||
continue;
|
||||
|
||||
bool ok = true;
|
||||
for (std::vector<const Named_object*>::const_iterator pr
|
||||
= requires.begin();
|
||||
pr != requires.end() && ok;
|
||||
++pr)
|
||||
{
|
||||
for (std::list<Named_object*>::const_iterator pt = types.begin();
|
||||
pt != types.end() && ok;
|
||||
++pt)
|
||||
if (*pr == *pt)
|
||||
ok = false;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
++loop;
|
||||
if (loop > 10000)
|
||||
{
|
||||
// This should be impossible since the code parsed and
|
||||
// type checked.
|
||||
go_unreachable();
|
||||
}
|
||||
|
||||
types.push_back(no);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (std::vector<const Named_object*>::const_iterator pd
|
||||
= declare.begin();
|
||||
pd != declare.end();
|
||||
++pd)
|
||||
{
|
||||
if (*pd == no)
|
||||
continue;
|
||||
|
||||
std::vector<const Named_object*> drequires;
|
||||
std::vector<const Named_object*> ddeclare;
|
||||
if (!(*pd)->type_value()->struct_type()->
|
||||
can_write_to_c_header(&drequires, &ddeclare))
|
||||
continue;
|
||||
|
||||
bool done = false;
|
||||
for (std::vector<const Named_object*>::const_iterator pw
|
||||
= written.begin();
|
||||
pw != written.end();
|
||||
++pw)
|
||||
{
|
||||
if (*pw == *pd)
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done)
|
||||
{
|
||||
out << std::endl;
|
||||
out << "struct " << (*pd)->message_name() << ";" << std::endl;
|
||||
written.push_back(*pd);
|
||||
}
|
||||
}
|
||||
|
||||
out << std::endl;
|
||||
out << "struct " << no->message_name() << " {" << std::endl;
|
||||
no->type_value()->struct_type()->write_to_c_header(out);
|
||||
out << "};" << std::endl;
|
||||
written.push_back(no);
|
||||
}
|
||||
|
||||
out.close();
|
||||
if (out.fail())
|
||||
error("error writing to %s: %m", this->c_header_.c_str());
|
||||
}
|
||||
|
||||
// Find the blocks in order to convert named types defined in blocks.
|
||||
|
|
|
|||
|
|
@ -250,6 +250,12 @@ class Gogo
|
|||
set_relative_import_path(const std::string& s)
|
||||
{ this->relative_import_path_ = s; }
|
||||
|
||||
// Set the C header file to write. This is used for the runtime
|
||||
// package.
|
||||
void
|
||||
set_c_header(const std::string& s)
|
||||
{ this->c_header_ = s; }
|
||||
|
||||
// Return whether to check for division by zero in binary operations.
|
||||
bool
|
||||
check_divide_by_zero() const
|
||||
|
|
@ -270,6 +276,16 @@ class Gogo
|
|||
set_check_divide_overflow(bool b)
|
||||
{ this->check_divide_overflow_ = b; }
|
||||
|
||||
// Return whether we are compiling the runtime package.
|
||||
bool
|
||||
compiling_runtime() const
|
||||
{ return this->compiling_runtime_; }
|
||||
|
||||
// Set whether we are compiling the runtime package.
|
||||
void
|
||||
set_compiling_runtime(bool b)
|
||||
{ this->compiling_runtime_ = b; }
|
||||
|
||||
// Return the level of escape analysis debug information to emit.
|
||||
int
|
||||
debug_escape_level() const
|
||||
|
|
@ -731,6 +747,9 @@ class Gogo
|
|||
const Bindings*
|
||||
current_bindings() const;
|
||||
|
||||
void
|
||||
write_c_header();
|
||||
|
||||
// Get the decl for the magic initialization function.
|
||||
Named_object*
|
||||
initialization_function_decl();
|
||||
|
|
@ -841,12 +860,17 @@ class Gogo
|
|||
// The relative import path, from the -fgo-relative-import-path
|
||||
// option.
|
||||
std::string relative_import_path_;
|
||||
// The C header file to write, from the -fgo-c-header option.
|
||||
std::string c_header_;
|
||||
// Whether or not to check for division by zero, from the
|
||||
// -fgo-check-divide-zero option.
|
||||
bool check_divide_by_zero_;
|
||||
// Whether or not to check for division overflow, from the
|
||||
// -fgo-check-divide-overflow option.
|
||||
bool check_divide_overflow_;
|
||||
// Whether we are compiling the runtime package, from the
|
||||
// -fgo-compiling-runtime option.
|
||||
bool compiling_runtime_;
|
||||
// The level of escape analysis debug information to emit, from the
|
||||
// -fgo-debug-escape option.
|
||||
int debug_escape_level_;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "go-system.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "go-c.h"
|
||||
#include "gogo.h"
|
||||
#include "operator.h"
|
||||
|
|
@ -5680,6 +5682,276 @@ Struct_type::do_import(Import* imp)
|
|||
return Type::make_struct_type(fields, imp->location());
|
||||
}
|
||||
|
||||
// Whether we can write this struct type to a C header file.
|
||||
// We can't if any of the fields are structs defined in a different package.
|
||||
|
||||
bool
|
||||
Struct_type::can_write_to_c_header(
|
||||
std::vector<const Named_object*>* requires,
|
||||
std::vector<const Named_object*>* declare) const
|
||||
{
|
||||
const Struct_field_list* fields = this->fields_;
|
||||
if (fields == NULL || fields->empty())
|
||||
return false;
|
||||
for (Struct_field_list::const_iterator p = fields->begin();
|
||||
p != fields->end();
|
||||
++p)
|
||||
{
|
||||
if (p->is_anonymous())
|
||||
return false;
|
||||
if (!this->can_write_type_to_c_header(p->type(), requires, declare))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Whether we can write the type T to a C header file.
|
||||
|
||||
bool
|
||||
Struct_type::can_write_type_to_c_header(
|
||||
const Type* t,
|
||||
std::vector<const Named_object*>* requires,
|
||||
std::vector<const Named_object*>* declare) const
|
||||
{
|
||||
t = t->forwarded();
|
||||
switch (t->classification())
|
||||
{
|
||||
case TYPE_ERROR:
|
||||
case TYPE_FORWARD:
|
||||
return false;
|
||||
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_INTEGER:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_COMPLEX:
|
||||
case TYPE_STRING:
|
||||
case TYPE_FUNCTION:
|
||||
case TYPE_MAP:
|
||||
case TYPE_CHANNEL:
|
||||
case TYPE_INTERFACE:
|
||||
return true;
|
||||
|
||||
case TYPE_POINTER:
|
||||
if (t->points_to()->named_type() != NULL
|
||||
&& t->points_to()->struct_type() != NULL)
|
||||
declare->push_back(t->points_to()->named_type()->named_object());
|
||||
return true;
|
||||
|
||||
case TYPE_STRUCT:
|
||||
return t->struct_type()->can_write_to_c_header(requires, declare);
|
||||
|
||||
case TYPE_ARRAY:
|
||||
if (t->is_slice_type())
|
||||
return true;
|
||||
return this->can_write_type_to_c_header(t->array_type()->element_type(),
|
||||
requires, declare);
|
||||
|
||||
case TYPE_NAMED:
|
||||
{
|
||||
const Named_object* no = t->named_type()->named_object();
|
||||
if (no->package() != NULL)
|
||||
{
|
||||
if (t->is_unsafe_pointer_type())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (t->struct_type() != NULL)
|
||||
{
|
||||
requires->push_back(no);
|
||||
return t->struct_type()->can_write_to_c_header(requires, declare);
|
||||
}
|
||||
return this->can_write_type_to_c_header(t->base(), requires, declare);
|
||||
}
|
||||
|
||||
case TYPE_CALL_MULTIPLE_RESULT:
|
||||
case TYPE_NIL:
|
||||
case TYPE_SINK:
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// Write this struct to a C header file.
|
||||
|
||||
void
|
||||
Struct_type::write_to_c_header(std::ostream& os) const
|
||||
{
|
||||
const Struct_field_list* fields = this->fields_;
|
||||
for (Struct_field_list::const_iterator p = fields->begin();
|
||||
p != fields->end();
|
||||
++p)
|
||||
{
|
||||
os << '\t';
|
||||
this->write_field_to_c_header(os, p->field_name(), p->type());
|
||||
os << ';' << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the type of a struct field to a C header file.
|
||||
|
||||
void
|
||||
Struct_type::write_field_to_c_header(std::ostream& os, const std::string& name,
|
||||
const Type *t) const
|
||||
{
|
||||
bool print_name = true;
|
||||
t = t->forwarded();
|
||||
switch (t->classification())
|
||||
{
|
||||
case TYPE_VOID:
|
||||
os << "void";
|
||||
break;
|
||||
|
||||
case TYPE_BOOLEAN:
|
||||
os << "_Bool";
|
||||
break;
|
||||
|
||||
case TYPE_INTEGER:
|
||||
{
|
||||
const Integer_type* it = t->integer_type();
|
||||
if (it->is_unsigned())
|
||||
os << 'u';
|
||||
os << "int" << it->bits() << "_t";
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_FLOAT:
|
||||
switch (t->float_type()->bits())
|
||||
{
|
||||
case 32:
|
||||
os << "float";
|
||||
break;
|
||||
case 64:
|
||||
os << "double";
|
||||
break;
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_COMPLEX:
|
||||
switch (t->complex_type()->bits())
|
||||
{
|
||||
case 64:
|
||||
os << "float _Complex";
|
||||
break;
|
||||
case 128:
|
||||
os << "double _Complex";
|
||||
break;
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
os << "String";
|
||||
break;
|
||||
|
||||
case TYPE_FUNCTION:
|
||||
os << "FuncVal";
|
||||
break;
|
||||
|
||||
case TYPE_POINTER:
|
||||
{
|
||||
std::vector<const Named_object*> requires;
|
||||
std::vector<const Named_object*> declare;
|
||||
if (!this->can_write_type_to_c_header(t->points_to(), &requires,
|
||||
&declare))
|
||||
os << "void*";
|
||||
else
|
||||
{
|
||||
this->write_field_to_c_header(os, "", t->points_to());
|
||||
os << '*';
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_MAP:
|
||||
os << "Map*";
|
||||
break;
|
||||
|
||||
case TYPE_CHANNEL:
|
||||
os << "Chan*";
|
||||
break;
|
||||
|
||||
case TYPE_INTERFACE:
|
||||
if (t->interface_type()->is_empty())
|
||||
os << "Eface";
|
||||
else
|
||||
os << "Iface";
|
||||
break;
|
||||
|
||||
case TYPE_STRUCT:
|
||||
os << "struct {" << std::endl;
|
||||
t->struct_type()->write_to_c_header(os);
|
||||
os << "\t}";
|
||||
break;
|
||||
|
||||
case TYPE_ARRAY:
|
||||
if (t->is_slice_type())
|
||||
os << "Slice";
|
||||
else
|
||||
{
|
||||
const Type *ele = t;
|
||||
std::vector<const Type*> array_types;
|
||||
while (ele->array_type() != NULL && !ele->is_slice_type())
|
||||
{
|
||||
array_types.push_back(ele);
|
||||
ele = ele->array_type()->element_type();
|
||||
}
|
||||
this->write_field_to_c_header(os, "", ele);
|
||||
os << ' ' << Gogo::message_name(name);
|
||||
print_name = false;
|
||||
while (!array_types.empty())
|
||||
{
|
||||
ele = array_types.back();
|
||||
array_types.pop_back();
|
||||
os << '[';
|
||||
Numeric_constant nc;
|
||||
if (!ele->array_type()->length()->numeric_constant_value(&nc))
|
||||
go_unreachable();
|
||||
mpz_t val;
|
||||
if (!nc.to_int(&val))
|
||||
go_unreachable();
|
||||
char* s = mpz_get_str(NULL, 10, val);
|
||||
os << s;
|
||||
free(s);
|
||||
mpz_clear(val);
|
||||
os << ']';
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_NAMED:
|
||||
{
|
||||
const Named_object* no = t->named_type()->named_object();
|
||||
if (t->struct_type() != NULL)
|
||||
os << "struct " << no->message_name();
|
||||
else if (t->is_unsafe_pointer_type())
|
||||
os << "void*";
|
||||
else if (t == Type::lookup_integer_type("uintptr"))
|
||||
os << "uintptr_t";
|
||||
else
|
||||
{
|
||||
this->write_field_to_c_header(os, name, t->base());
|
||||
print_name = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_ERROR:
|
||||
case TYPE_FORWARD:
|
||||
case TYPE_CALL_MULTIPLE_RESULT:
|
||||
case TYPE_NIL:
|
||||
case TYPE_SINK:
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
|
||||
if (print_name && !name.empty())
|
||||
os << ' ' << Gogo::message_name(name);
|
||||
}
|
||||
|
||||
// Make a struct type.
|
||||
|
||||
Struct_type*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef GO_TYPES_H
|
||||
#define GO_TYPES_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "go-linemap.h"
|
||||
#include "escape.h"
|
||||
|
||||
|
|
@ -2329,6 +2331,16 @@ class Struct_type : public Type
|
|||
void
|
||||
write_equal_function(Gogo*, Named_type*);
|
||||
|
||||
// Whether we can write this type to a C header file, to implement
|
||||
// -fgo-c-header.
|
||||
bool
|
||||
can_write_to_c_header(std::vector<const Named_object*>*,
|
||||
std::vector<const Named_object*>*) const;
|
||||
|
||||
// Write this type to a C header file, to implement -fgo-c-header.
|
||||
void
|
||||
write_to_c_header(std::ostream&) const;
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse*);
|
||||
|
|
@ -2364,6 +2376,14 @@ class Struct_type : public Type
|
|||
do_export(Export*) const;
|
||||
|
||||
private:
|
||||
bool
|
||||
can_write_type_to_c_header(const Type*,
|
||||
std::vector<const Named_object*>*,
|
||||
std::vector<const Named_object*>*) const;
|
||||
|
||||
void
|
||||
write_field_to_c_header(std::ostream&, const std::string&, const Type*) const;
|
||||
|
||||
// Used to merge method sets of identical unnamed structs.
|
||||
typedef Unordered_map_hash(Struct_type*, Struct_type*, Type_hash_identical,
|
||||
Type_identical) Identical_structs;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ Wall
|
|||
Go
|
||||
; Documented in c.opt
|
||||
|
||||
fgo-c-header=
|
||||
Go Joined RejectNegative
|
||||
-fgo-c-header=<file> Write Go struct definitions to file as C code.
|
||||
|
||||
fgo-check-divide-zero
|
||||
Go Var(go_check_divide_zero) Init(1)
|
||||
Add explicit checks for division by zero.
|
||||
|
|
@ -45,6 +49,10 @@ fgo-check-divide-overflow
|
|||
Go Var(go_check_divide_overflow) Init(1)
|
||||
Add explicit checks for division overflow in INT_MIN / -1.
|
||||
|
||||
fgo-compiling-runtime
|
||||
Go Var(go_compiling_runtime) Init(0)
|
||||
Apply special rules for compiling runtime package.
|
||||
|
||||
fgo-dump-
|
||||
Go Joined RejectNegative
|
||||
-fgo-dump-<type> Dump Go frontend internal information.
|
||||
|
|
|
|||
Loading…
Reference in New Issue