aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/go-gcc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/go-gcc.cc')
-rw-r--r--gcc/go/go-gcc.cc91
1 files changed, 77 insertions, 14 deletions
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 059706e..6bac84f 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -389,9 +389,16 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
- implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
+ implicit_variable(const std::string&, Btype*, bool, bool, bool,
size_t);
+ void
+ implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
+ bool, bool, bool, Bexpression*);
+
+ Bvariable*
+ implicit_variable_reference(const std::string&, Btype*);
+
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
@@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Bvariable*
Gcc_backend::implicit_variable(const std::string& name, Btype* type,
- Bexpression* init, bool is_constant,
+ bool is_hidden, bool is_constant,
bool is_common, size_t alignment)
{
tree type_tree = type->get_tree();
- tree init_tree;
- if (init == NULL)
- init_tree = NULL_TREE;
- else
- init_tree = init->get_tree();
- if (type_tree == error_mark_node || init_tree == error_mark_node)
+ if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
+ TREE_PUBLIC(decl) = !is_hidden;
TREE_STATIC(decl) = 1;
+ TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
if (is_common)
{
DECL_COMMON(decl) = 1;
- TREE_PUBLIC(decl) = 1;
- gcc_assert(init_tree == NULL_TREE);
+
+ // When the initializer for one implicit_variable refers to another,
+ // it needs to know the visibility of the referenced struct so that
+ // compute_reloc_for_constant will return the right value. On many
+ // systems calling make_decl_one_only will mark the decl as weak,
+ // which will change the return value of compute_reloc_for_constant.
+ // We can't reliably call make_decl_one_only yet, because we don't
+ // yet know the initializer. This issue doesn't arise in C because
+ // Go initializers, unlike C initializers, can be indirectly
+ // recursive. To ensure that compute_reloc_for_constant computes
+ // the right value if some other initializer refers to this one, we
+ // mark this symbol as weak here. We undo that below in
+ // immutable_struct_set_init before calling mark_decl_one_only.
+ DECL_WEAK(decl) = 1;
}
- else if (is_constant)
+ if (is_constant)
{
TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1;
}
- DECL_INITIAL(decl) = init_tree;
-
if (alignment != 0)
{
DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
DECL_USER_ALIGN(decl) = 1;
}
+ go_preserve_from_gc(decl);
+ return new Bvariable(decl);
+}
+
+// Set the initalizer for a variable created by implicit_variable.
+// This is where we finish compiling the variable.
+
+void
+Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
+ Btype*, bool, bool, bool is_common,
+ Bexpression* init)
+{
+ tree decl = var->get_tree();
+ tree init_tree;
+ if (init == NULL)
+ init_tree = NULL_TREE;
+ else
+ init_tree = init->get_tree();
+ if (decl == error_mark_node || init_tree == error_mark_node)
+ return;
+
+ DECL_INITIAL(decl) = init_tree;
+
+ // Now that DECL_INITIAL is set, we can't call make_decl_one_only.
+ // See the comment where DECL_WEAK is set in implicit_variable.
+ if (is_common)
+ {
+ DECL_WEAK(decl) = 0;
+ make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+ }
+
+ resolve_unique_section(decl, 2, 1);
+
rest_of_decl_compilation(decl, 1, 0);
+}
+// Return a reference to an implicit variable defined in another package.
+
+Bvariable*
+Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+
+ tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+ get_identifier_from_string(name), type_tree);
+ DECL_EXTERNAL(decl) = 0;
+ TREE_PUBLIC(decl) = 1;
+ TREE_STATIC(decl) = 1;
+ DECL_ARTIFICIAL(decl) = 1;
+ go_preserve_from_gc(decl);
return new Bvariable(decl);
}