diff options
author | Chris Manghane <cmang@google.com> | 2014-04-26 03:38:34 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-04-26 03:38:34 +0000 |
commit | 036165d8116610b18861941fed4080a93783f954 (patch) | |
tree | 93a36b3f34bf901b1b63907441f2986c34fe7d4e /gcc/go/gofrontend/gogo-tree.cc | |
parent | 10695c6a1da3fef02b6842f10b8586ad38a94763 (diff) | |
download | gcc-036165d8116610b18861941fed4080a93783f954.zip gcc-036165d8116610b18861941fed4080a93783f954.tar.gz gcc-036165d8116610b18861941fed4080a93783f954.tar.bz2 |
compiler: Use backend interface for defining global declarations.
* go-gcc.cc: Include "cgraph.h" and "gimplify.h".
(Gcc_backend::return_statement): Push and pop function.
(Gcc_backend::label): Likewise.
(Gcc_backend::function_defer_statement): Likewise.
(Gcc_backend::switch_statement): Add function parameter.
(Gcc_backend::block): Don't permit function to be NULL.
(Gcc_backend::temporary_variable): Change go_assert to
gcc_assert.
(Gcc_backend::gc_root_variable): New function.
(Gcc_backend::write_global_definitions): New function.
From-SVN: r209819
Diffstat (limited to 'gcc/go/gofrontend/gogo-tree.cc')
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 882 |
1 files changed, 0 insertions, 882 deletions
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index c00e7d1..6b19a1d 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -236,830 +236,6 @@ Gogo::define_builtin_function_trees() false); } -// Add statements to INIT_STMT_LIST which run the initialization -// functions for imported packages. This is only used for the "main" -// package. - -void -Gogo::init_imports(tree* init_stmt_list) -{ - go_assert(this->is_main_package()); - - if (this->imported_init_fns_.empty()) - return; - - tree fntype = build_function_type(void_type_node, void_list_node); - - // We must call them in increasing priority order. - std::vector<Import_init> v; - for (std::set<Import_init>::const_iterator p = - this->imported_init_fns_.begin(); - p != this->imported_init_fns_.end(); - ++p) - v.push_back(*p); - std::sort(v.begin(), v.end()); - - for (std::vector<Import_init>::const_iterator p = v.begin(); - p != v.end(); - ++p) - { - std::string user_name = p->package_name() + ".init"; - tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL, - get_identifier_from_string(user_name), - fntype); - const std::string& init_name(p->init_name()); - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name)); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - append_to_statement_list(build_call_expr(decl, 0), init_stmt_list); - } -} - -// Register global variables with the garbage collector. We need to -// register all variables which can hold a pointer value. They become -// roots during the mark phase. We build a struct that is easy to -// hook into a list of roots. - -// struct __go_gc_root_list -// { -// struct __go_gc_root_list* __next; -// struct __go_gc_root -// { -// void* __decl; -// size_t __size; -// } __roots[]; -// }; - -// The last entry in the roots array has a NULL decl field. - -void -Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, - tree* init_stmt_list) -{ - if (var_gc.empty()) - return; - - size_t count = var_gc.size(); - - tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2, - "__next", - ptr_type_node, - "__size", - sizetype); - - tree index_type = build_index_type(size_int(count)); - tree array_type = build_array_type(root_type, index_type); - - tree root_list_type = make_node(RECORD_TYPE); - root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list", - root_list_type, 2, - "__next", - build_pointer_type(root_list_type), - "__roots", - array_type); - - // Build an initialier for the __roots array. - - vec<constructor_elt, va_gc> *roots_init; - vec_alloc(roots_init, count + 1); - - size_t i = 0; - for (std::vector<Named_object*>::const_iterator p = var_gc.begin(); - p != var_gc.end(); - ++p, ++i) - { - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - Bvariable* bvar = (*p)->get_backend_variable(this, NULL); - tree decl = var_to_tree(bvar); - go_assert(TREE_CODE(decl) == VAR_DECL); - elt->value = build_fold_addr_expr(decl); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = DECL_SIZE_UNIT(decl); - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - } - - // The list ends with a NULL entry. - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = size_zero_node; - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - - // Build a constructor for the struct. - - vec<constructor_elt, va_gc> *root_list_init; - vec_alloc(root_list_init, 2); - - elt = root_list_init->quick_push(empty); - field = TYPE_FIELDS(root_list_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = root_list_init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = build_constructor(array_type, roots_init); - - // Build a decl to register. - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, - create_tmp_var_name("gc"), root_list_type); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init); - rest_of_decl_compilation(decl, 1, 0); - - static tree register_gc_fndecl; - tree call = Gogo::call_builtin(®ister_gc_fndecl, - Linemap::predeclared_location(), - "__go_register_gc_roots", - 1, - void_type_node, - build_pointer_type(root_list_type), - build_fold_addr_expr(decl)); - if (call != error_mark_node) - append_to_statement_list(call, init_stmt_list); -} - -// Create the magic initialization function. INIT_STMT_LIST is the -// code that it needs to run. - -void -Gogo::write_initialization_function(Named_object* initfn, tree init_stmt_list) -{ - // Make sure that we thought we needed an initialization function, - // as otherwise we will not have reported it in the export data. - go_assert(this->is_main_package() || this->need_init_fn_); - - if (initfn == NULL) - initfn = this->initialization_function_decl(); - - Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn); - Location loc = this->package_->location(); - std::vector<Bvariable*> vars; - this->backend()->block(fndecl, NULL, vars, loc, loc); - - if (!this->backend()->function_set_body(fndecl, tree_to_stat(init_stmt_list))) - { - go_assert(saw_errors()); - return; - } - gimplify_function_tree(function_to_tree(fndecl)); - cgraph_add_new_function(function_to_tree(fndecl), false); -} - -// Search for references to VAR in any statements or called functions. - -class Find_var : public Traverse -{ - public: - // A hash table we use to avoid looping. The index is the name of a - // named object. We only look through objects defined in this - // package. - typedef Unordered_set(const void*) Seen_objects; - - Find_var(Named_object* var, Seen_objects* seen_objects) - : Traverse(traverse_expressions), - var_(var), seen_objects_(seen_objects), found_(false) - { } - - // Whether the variable was found. - bool - found() const - { return this->found_; } - - int - expression(Expression**); - - private: - // The variable we are looking for. - Named_object* var_; - // Names of objects we have already seen. - Seen_objects* seen_objects_; - // True if the variable was found. - bool found_; -}; - -// See if EXPR refers to VAR, looking through function calls and -// variable initializations. - -int -Find_var::expression(Expression** pexpr) -{ - Expression* e = *pexpr; - - Var_expression* ve = e->var_expression(); - if (ve != NULL) - { - Named_object* v = ve->named_object(); - if (v == this->var_) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - - if (v->is_variable() && v->package() == NULL) - { - Expression* init = v->var_value()->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(v); - if (ins.second) - { - // This is the first time we have seen this name. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - } - - // We traverse the code of any function we see. Note that this - // means that we will traverse the code of a function whose address - // is taken even if it is not called. - Func_expression* fe = e->func_expression(); - if (fe != NULL) - { - const Named_object* f = fe->named_object(); - if (f->is_function() && f->package() == NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(f); - if (ins.second) - { - // This is the first time we have seen this name. - if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - Temporary_reference_expression* tre = e->temporary_reference_expression(); - if (tre != NULL) - { - Temporary_statement* ts = tre->statement(); - Expression* init = ts->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(ts); - if (ins.second) - { - // This is the first time we have seen this temporary - // statement. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - return TRAVERSE_CONTINUE; -} - -// Return true if EXPR, PREINIT, or DEP refers to VAR. - -static bool -expression_requires(Expression* expr, Block* preinit, Named_object* dep, - Named_object* var) -{ - Find_var::Seen_objects seen_objects; - Find_var find_var(var, &seen_objects); - if (expr != NULL) - Expression::traverse(&expr, &find_var); - if (preinit != NULL) - preinit->traverse(&find_var); - if (dep != NULL) - { - Expression* init = dep->var_value()->init(); - if (init != NULL) - Expression::traverse(&init, &find_var); - if (dep->var_value()->has_pre_init()) - dep->var_value()->preinit()->traverse(&find_var); - } - - return find_var.found(); -} - -// Sort variable initializations. If the initialization expression -// for variable A refers directly or indirectly to the initialization -// expression for variable B, then we must initialize B before A. - -class Var_init -{ - public: - Var_init() - : var_(NULL), init_(NULL) - { } - - Var_init(Named_object* var, Bstatement* init) - : var_(var), init_(init) - { } - - // Return the variable. - Named_object* - var() const - { return this->var_; } - - // Return the initialization expression. - Bstatement* - init() const - { return this->init_; } - - private: - // The variable being initialized. - Named_object* var_; - // The initialization statement. - Bstatement* init_; -}; - -typedef std::list<Var_init> Var_inits; - -// Sort the variable initializations. The rule we follow is that we -// emit them in the order they appear in the array, except that if the -// initialization expression for a variable V1 depends upon another -// variable V2 then we initialize V1 after V2. - -static void -sort_var_inits(Gogo* gogo, Var_inits* var_inits) -{ - typedef std::pair<Named_object*, Named_object*> No_no; - typedef std::map<No_no, bool> Cache; - Cache cache; - - Var_inits ready; - while (!var_inits->empty()) - { - Var_inits::iterator p1 = var_inits->begin(); - Named_object* var = p1->var(); - Expression* init = var->var_value()->init(); - Block* preinit = var->var_value()->preinit(); - Named_object* dep = gogo->var_depends_on(var->var_value()); - - // Start walking through the list to see which variables VAR - // needs to wait for. - Var_inits::iterator p2 = p1; - ++p2; - - for (; p2 != var_inits->end(); ++p2) - { - Named_object* p2var = p2->var(); - No_no key(var, p2var); - std::pair<Cache::iterator, bool> ins = - cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = expression_requires(init, preinit, dep, p2var); - if (ins.first->second) - { - // Check for cycles. - key = std::make_pair(p2var, var); - ins = cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = - expression_requires(p2var->var_value()->init(), - p2var->var_value()->preinit(), - gogo->var_depends_on(p2var->var_value()), - var); - if (ins.first->second) - { - error_at(var->location(), - ("initialization expressions for %qs and " - "%qs depend upon each other"), - var->message_name().c_str(), - p2var->message_name().c_str()); - inform(p2->var()->location(), "%qs defined here", - p2var->message_name().c_str()); - p2 = var_inits->end(); - } - else - { - // We can't emit P1 until P2 is emitted. Move P1. - Var_inits::iterator p3 = p2; - ++p3; - var_inits->splice(p3, *var_inits, p1); - } - break; - } - } - - if (p2 == var_inits->end()) - { - // VAR does not depends upon any other initialization expressions. - - // Check for a loop of VAR on itself. We only do this if - // INIT is not NULL and there is no dependency; when INIT is - // NULL, it means that PREINIT sets VAR, which we will - // interpret as a loop. - if (init != NULL && dep == NULL - && expression_requires(init, preinit, NULL, var)) - error_at(var->location(), - "initialization expression for %qs depends upon itself", - var->message_name().c_str()); - ready.splice(ready.end(), *var_inits, p1); - } - } - - // Now READY is the list in the desired initialization order. - var_inits->swap(ready); -} - -// Write out the global definitions. - -void -Gogo::write_globals() -{ - this->build_interface_method_tables(); - - Bindings* bindings = this->current_bindings(); - - for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - { - // If any function declarations needed a descriptor, make sure - // we build it. - Named_object* no = p->second; - if (no->is_function_declaration()) - no->func_declaration_value()->build_backend_descriptor(this); - } - - size_t count_definitions = bindings->size_definitions(); - size_t count = count_definitions; - - tree* vec = new tree[count]; - - Named_object* init_fndecl = NULL; - tree init_stmt_list = NULL_TREE; - - if (this->is_main_package()) - this->init_imports(&init_stmt_list); - - // A list of variable initializations. - Var_inits var_inits; - - // A list of variables which need to be registered with the garbage - // collector. - std::vector<Named_object*> var_gc; - var_gc.reserve(count); - - tree var_init_stmt_list = NULL_TREE; - size_t i = 0; - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p, ++i) - { - Named_object* no = *p; - - go_assert(i < count); - - go_assert(!no->is_type_declaration() && !no->is_function_declaration()); - // There is nothing to do for a package. - if (no->is_package()) - { - --i; - --count; - continue; - } - - // There is nothing to do for an object which was imported from - // a different package into the global scope. - if (no->package() != NULL) - { - --i; - --count; - continue; - } - - // Skip blank named functions and constants. - if ((no->is_function() && no->func_value()->is_sink()) - || (no->is_const() && no->const_value()->is_sink())) - { - --i; - --count; - continue; - } - - // There is nothing useful we can output for constants which - // have ideal or non-integral type. - if (no->is_const()) - { - Type* type = no->const_value()->type(); - if (type == NULL) - type = no->const_value()->expr()->type(); - if (type->is_abstract() || type->integer_type() == NULL) - { - --i; - --count; - continue; - } - } - - if (!no->is_variable()) - { - vec[i] = no->get_tree(this, NULL); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - } - else - { - Bvariable* var = no->get_backend_variable(this, NULL); - vec[i] = var_to_tree(var); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - - // Check for a sink variable, which may be used to run an - // initializer purely for its side effects. - bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; - - Bstatement* var_init_stmt = NULL; - if (!no->var_value()->has_pre_init()) - { - Bexpression* var_binit = no->var_value()->get_init(this, NULL); - if (var_binit == NULL) - ; - else if (TREE_CONSTANT(expr_to_tree(var_binit))) - { - if (expression_requires(no->var_value()->init(), NULL, - this->var_depends_on(no->var_value()), - no)) - error_at(no->location(), - "initialization expression for %qs depends " - "upon itself", - no->message_name().c_str()); - this->backend()->global_variable_set_init(var, var_binit); - } - else if (is_sink) - var_init_stmt = - this->backend()->expression_statement(var_binit); - else - { - Location loc = no->var_value()->location(); - Bexpression* var_expr = - this->backend()->var_expression(var, loc); - var_init_stmt = - this->backend()->assignment_statement(var_expr, var_binit, - loc); - } - } - else - { - // We are going to create temporary variables which - // means that we need an fndecl. - if (init_fndecl == NULL) - init_fndecl = this->initialization_function_decl(); - - Bvariable* var_decl = is_sink ? NULL : var; - var_init_stmt = - no->var_value()->get_init_block(this, init_fndecl, var_decl); - } - - if (var_init_stmt != NULL) - { - if (no->var_value()->init() == NULL - && !no->var_value()->has_pre_init()) - append_to_statement_list(stat_to_tree(var_init_stmt), - &var_init_stmt_list); - else - var_inits.push_back(Var_init(no, var_init_stmt)); - } - else if (this->var_depends_on(no->var_value()) != NULL) - { - // This variable is initialized from something that is - // not in its init or preinit. This variable needs to - // participate in dependency analysis sorting, in case - // some other variable depends on this one. - Btype* int_btype = - Type::lookup_integer_type("int")->get_backend(this); - Bexpression* zero = this->backend()->zero_expression(int_btype); - Bstatement* zero_stmt = - this->backend()->expression_statement(zero); - var_inits.push_back(Var_init(no, zero_stmt)); - } - - if (!is_sink && no->var_value()->type()->has_pointer()) - var_gc.push_back(no); - } - } - - // Register global variables with the garbage collector. - this->register_gc_vars(var_gc, &init_stmt_list); - - // Simple variable initializations, after all variables are - // registered. - append_to_statement_list(var_init_stmt_list, &init_stmt_list); - - // Complex variable initializations, first sorting them into a - // workable order. - if (!var_inits.empty()) - { - sort_var_inits(this, &var_inits); - for (Var_inits::const_iterator p = var_inits.begin(); - p != var_inits.end(); - ++p) - append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list); - } - - // After all the variables are initialized, call the "init" - // functions if there are any. - for (std::vector<Named_object*>::const_iterator p = - this->init_functions_.begin(); - p != this->init_functions_.end(); - ++p) - { - tree decl = (*p)->get_tree(this, NULL); - tree call = build_call_expr(decl, 0); - append_to_statement_list(call, &init_stmt_list); - } - - // Set up a magic function to do all the initialization actions. - // This will be called if this package is imported. - if (init_stmt_list != NULL - || this->need_init_fn_ - || this->is_main_package()) - this->write_initialization_function(init_fndecl, init_stmt_list); - - // We should not have seen any new bindings created during the - // conversion. - go_assert(count_definitions == this->current_bindings()->size_definitions()); - - // Pass everything back to the middle-end. - - wrapup_global_declarations(vec, count); - - finalize_compilation_unit(); - - check_global_declarations(vec, count); - emit_debug_global_declarations(vec, count); - - delete[] vec; -} - -// Get a tree for a named object. - -tree -Named_object::get_tree(Gogo* gogo, Named_object* function) -{ - if (this->tree_ != NULL_TREE) - return this->tree_; - - if (Gogo::is_erroneous_name(this->name_)) - { - this->tree_ = error_mark_node; - return error_mark_node; - } - - tree decl; - switch (this->classification_) - { - case NAMED_OBJECT_CONST: - { - Translate_context subcontext(gogo, function, NULL, NULL); - Type* type = this->u_.const_value->type(); - Location loc = this->location(); - - Expression* const_ref = Expression::make_const_reference(this, loc); - Bexpression* const_decl = - tree_to_expr(const_ref->get_tree(&subcontext)); - if (type != NULL && type->is_numeric_type()) - { - Btype* btype = type->get_backend(gogo); - std::string name = this->get_id(gogo); - const_decl = - gogo->backend()->named_constant_expression(btype, name, - const_decl, loc); - } - decl = expr_to_tree(const_decl); - } - break; - - case NAMED_OBJECT_TYPE: - { - Named_type* named_type = this->u_.type_value; - tree type_tree = type_to_tree(named_type->get_backend(gogo)); - if (type_tree == error_mark_node) - decl = error_mark_node; - else - { - decl = TYPE_NAME(type_tree); - go_assert(decl != NULL_TREE); - - // We need to produce a type descriptor for every named - // type, and for a pointer to every named type, since - // other files or packages might refer to them. We need - // to do this even for hidden types, because they might - // still be returned by some function. Simply calling the - // type_descriptor method is enough to create the type - // descriptor, even though we don't do anything with it. - if (this->package_ == NULL) - { - named_type-> - type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - Type* pn = Type::make_pointer_type(named_type); - pn->type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - } - } - } - break; - - case NAMED_OBJECT_TYPE_DECLARATION: - error("reference to undefined type %qs", - this->message_name().c_str()); - return error_mark_node; - - case NAMED_OBJECT_VAR: - case NAMED_OBJECT_RESULT_VAR: - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - { - Function* func = this->u_.func_value; - decl = function_to_tree(func->get_or_make_decl(gogo, this)); - if (decl != error_mark_node) - { - if (func->block() != NULL) - { - if (DECL_STRUCT_FUNCTION(decl) == NULL) - push_struct_function(decl); - else - push_cfun(DECL_STRUCT_FUNCTION(decl)); - - cfun->function_start_locus = func->location().gcc_location(); - cfun->function_end_locus = - func->block()->end_location().gcc_location(); - - func->build(gogo, this); - - gimplify_function_tree(decl); - - cgraph_finalize_function(decl, true); - - pop_cfun(); - } - } - } - break; - - case NAMED_OBJECT_ERRONEOUS: - decl = error_mark_node; - break; - - default: - go_unreachable(); - } - - if (TREE_TYPE(decl) == error_mark_node) - decl = error_mark_node; - - tree ret = decl; - - this->tree_ = ret; - - if (ret != error_mark_node) - go_preserve_from_gc(ret); - - return ret; -} - // Get the backend representation. Bfunction* @@ -1106,15 +282,6 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) return this->fndecl_; } -// Return the function's decl after it has been built. - -tree -Function::get_decl() const -{ - go_assert(this->fndecl_ != NULL); - return function_to_tree(this->fndecl_); -} - // Build the descriptor for a function declaration. This won't // necessarily happen if the package has just a declaration for the // function and no other reference to it, but we may still need the @@ -1214,55 +381,6 @@ go_type_for_mode(enum machine_mode mode, int unsignedp) return NULL_TREE; } -// Build a builtin struct with a list of fields. The name is -// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE -// node; this exists so that the struct can have fields which point to -// itself. If PTYPE is not NULL, store the result in *PTYPE. There -// are NFIELDS fields. Each field is a name (a const char*) followed -// by a type (a tree). - -tree -Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...) -{ - if (ptype != NULL && *ptype != NULL_TREE) - return *ptype; - - va_list ap; - va_start(ap, nfields); - - tree fields = NULL_TREE; - for (int i = 0; i < nfields; ++i) - { - const char* field_name = va_arg(ap, const char*); - tree type = va_arg(ap, tree); - if (type == error_mark_node) - { - if (ptype != NULL) - *ptype = error_mark_node; - return error_mark_node; - } - tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, - get_identifier(field_name), type); - DECL_CHAIN(field) = fields; - fields = field; - } - - va_end(ap); - - if (struct_type == NULL_TREE) - struct_type = make_node(RECORD_TYPE); - finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE); - - if (ptype != NULL) - { - go_preserve_from_gc(struct_type); - *ptype = struct_type; - } - - return struct_type; -} - // Build a constructor for a slice. SLICE_TYPE_TREE is the type of // the slice. VALUES is the value pointer and COUNT is the number of // entries. If CAPACITY is not NULL, it is the capacity; otherwise |