Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
29f31724
Commit
29f31724
authored
May 03, 2012
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiler: Fix order of initialization bug with global var a, b = f().
From-SVN: r187103
parent
0fe5522f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
85 additions
and
18 deletions
+85
-18
gcc/go/gofrontend/gogo-tree.cc
+39
-15
gcc/go/gofrontend/gogo.cc
+5
-0
gcc/go/gofrontend/gogo.h
+24
-2
gcc/go/gofrontend/parse.cc
+17
-1
No files found.
gcc/go/gofrontend/gogo-tree.cc
View file @
29f31724
...
@@ -590,10 +590,11 @@ Find_var::expression(Expression** pexpr)
...
@@ -590,10 +590,11 @@ Find_var::expression(Expression** pexpr)
return
TRAVERSE_CONTINUE
;
return
TRAVERSE_CONTINUE
;
}
}
// Return true if EXPR refers to VAR.
// Return true if EXPR
, PREINIT, or DEP
refers to VAR.
static
bool
static
bool
expression_requires
(
Expression
*
expr
,
Block
*
preinit
,
Named_object
*
var
)
expression_requires
(
Expression
*
expr
,
Block
*
preinit
,
Named_object
*
dep
,
Named_object
*
var
)
{
{
Find_var
::
Seen_objects
seen_objects
;
Find_var
::
Seen_objects
seen_objects
;
Find_var
find_var
(
var
,
&
seen_objects
);
Find_var
find_var
(
var
,
&
seen_objects
);
...
@@ -601,7 +602,15 @@ expression_requires(Expression* expr, Block* preinit, Named_object* var)
...
@@ -601,7 +602,15 @@ expression_requires(Expression* expr, Block* preinit, Named_object* var)
Expression
::
traverse
(
&
expr
,
&
find_var
);
Expression
::
traverse
(
&
expr
,
&
find_var
);
if
(
preinit
!=
NULL
)
if
(
preinit
!=
NULL
)
preinit
->
traverse
(
&
find_var
);
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
();
return
find_var
.
found
();
}
}
...
@@ -658,7 +667,7 @@ typedef std::list<Var_init> Var_inits;
...
@@ -658,7 +667,7 @@ typedef std::list<Var_init> Var_inits;
// variable V2 then we initialize V1 after V2.
// variable V2 then we initialize V1 after V2.
static
void
static
void
sort_var_inits
(
Var_inits
*
var_inits
)
sort_var_inits
(
Gogo
*
gogo
,
Var_inits
*
var_inits
)
{
{
Var_inits
ready
;
Var_inits
ready
;
while
(
!
var_inits
->
empty
())
while
(
!
var_inits
->
empty
())
...
@@ -667,6 +676,7 @@ sort_var_inits(Var_inits* var_inits)
...
@@ -667,6 +676,7 @@ sort_var_inits(Var_inits* var_inits)
Named_object
*
var
=
p1
->
var
();
Named_object
*
var
=
p1
->
var
();
Expression
*
init
=
var
->
var_value
()
->
init
();
Expression
*
init
=
var
->
var_value
()
->
init
();
Block
*
preinit
=
var
->
var_value
()
->
preinit
();
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
// Start walking through the list to see which variables VAR
// needs to wait for. We can skip P1->WAITING variables--that
// needs to wait for. We can skip P1->WAITING variables--that
...
@@ -678,20 +688,22 @@ sort_var_inits(Var_inits* var_inits)
...
@@ -678,20 +688,22 @@ sort_var_inits(Var_inits* var_inits)
for
(;
p2
!=
var_inits
->
end
();
++
p2
)
for
(;
p2
!=
var_inits
->
end
();
++
p2
)
{
{
if
(
expression_requires
(
init
,
preinit
,
p2
->
var
()))
Named_object
*
p2var
=
p2
->
var
();
if
(
expression_requires
(
init
,
preinit
,
dep
,
p2var
))
{
{
// Check for cycles.
// Check for cycles.
if
(
expression_requires
(
p2
->
var
()
->
var_value
()
->
init
(),
if
(
expression_requires
(
p2var
->
var_value
()
->
init
(),
p2
->
var
()
->
var_value
()
->
preinit
(),
p2var
->
var_value
()
->
preinit
(),
gogo
->
var_depends_on
(
p2var
->
var_value
()),
var
))
var
))
{
{
error_at
(
var
->
location
(),
error_at
(
var
->
location
(),
(
"initialization expressions for %qs and "
(
"initialization expressions for %qs and "
"%qs depend upon each other"
),
"%qs depend upon each other"
),
var
->
message_name
().
c_str
(),
var
->
message_name
().
c_str
(),
p2
->
var
()
->
message_name
().
c_str
());
p2
var
->
message_name
().
c_str
());
inform
(
p2
->
var
()
->
location
(),
"%qs defined here"
,
inform
(
p2
->
var
()
->
location
(),
"%qs defined here"
,
p2
->
var
()
->
message_name
().
c_str
());
p2
var
->
message_name
().
c_str
());
p2
=
var_inits
->
end
();
p2
=
var_inits
->
end
();
}
}
else
else
...
@@ -714,9 +726,11 @@ sort_var_inits(Var_inits* var_inits)
...
@@ -714,9 +726,11 @@ sort_var_inits(Var_inits* var_inits)
// VAR does not depends upon any other initialization expressions.
// VAR does not depends upon any other initialization expressions.
// Check for a loop of VAR on itself. We only do this if
// Check for a loop of VAR on itself. We only do this if
// INIT is not NULL; when INIT is NULL, it means that
// INIT is not NULL and there is no dependency; when INIT is
// PREINIT sets VAR, which we will interpret as a loop.
// NULL, it means that PREINIT sets VAR, which we will
if
(
init
!=
NULL
&&
expression_requires
(
init
,
preinit
,
var
))
// interpret as a loop.
if
(
init
!=
NULL
&&
dep
==
NULL
&&
expression_requires
(
init
,
preinit
,
NULL
,
var
))
error_at
(
var
->
location
(),
error_at
(
var
->
location
(),
"initialization expression for %qs depends upon itself"
,
"initialization expression for %qs depends upon itself"
,
var
->
message_name
().
c_str
());
var
->
message_name
().
c_str
());
...
@@ -783,7 +797,7 @@ Gogo::write_globals()
...
@@ -783,7 +797,7 @@ Gogo::write_globals()
}
}
// There is nothing useful we can output for constants which
// There is nothing useful we can output for constants which
// have ideal or non-integ
e
ral type.
// have ideal or non-integral type.
if
(
no
->
is_const
())
if
(
no
->
is_const
())
{
{
Type
*
type
=
no
->
const_value
()
->
type
();
Type
*
type
=
no
->
const_value
()
->
type
();
...
@@ -834,7 +848,9 @@ Gogo::write_globals()
...
@@ -834,7 +848,9 @@ Gogo::write_globals()
;
;
else
if
(
TREE_CONSTANT
(
init
))
else
if
(
TREE_CONSTANT
(
init
))
{
{
if
(
expression_requires
(
no
->
var_value
()
->
init
(),
NULL
,
no
))
if
(
expression_requires
(
no
->
var_value
()
->
init
(),
NULL
,
this
->
var_depends_on
(
no
->
var_value
()),
no
))
error_at
(
no
->
location
(),
error_at
(
no
->
location
(),
"initialization expression for %qs depends "
"initialization expression for %qs depends "
"upon itself"
,
"upon itself"
,
...
@@ -879,6 +895,14 @@ Gogo::write_globals()
...
@@ -879,6 +895,14 @@ Gogo::write_globals()
else
else
var_inits
.
push_back
(
Var_init
(
no
,
var_init_tree
));
var_inits
.
push_back
(
Var_init
(
no
,
var_init_tree
));
}
}
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.
var_inits
.
push_back
(
Var_init
(
no
,
integer_zero_node
));
}
if
(
!
is_sink
&&
no
->
var_value
()
->
type
()
->
has_pointer
())
if
(
!
is_sink
&&
no
->
var_value
()
->
type
()
->
has_pointer
())
var_gc
.
push_back
(
no
);
var_gc
.
push_back
(
no
);
...
@@ -896,7 +920,7 @@ Gogo::write_globals()
...
@@ -896,7 +920,7 @@ Gogo::write_globals()
// workable order.
// workable order.
if
(
!
var_inits
.
empty
())
if
(
!
var_inits
.
empty
())
{
{
sort_var_inits
(
&
var_inits
);
sort_var_inits
(
this
,
&
var_inits
);
for
(
Var_inits
::
const_iterator
p
=
var_inits
.
begin
();
for
(
Var_inits
::
const_iterator
p
=
var_inits
.
begin
();
p
!=
var_inits
.
end
();
p
!=
var_inits
.
end
();
++
p
)
++
p
)
...
...
gcc/go/gofrontend/gogo.cc
View file @
29f31724
...
@@ -32,6 +32,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
...
@@ -32,6 +32,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
imported_unsafe_
(
false
),
imported_unsafe_
(
false
),
packages_
(),
packages_
(),
init_functions_
(),
init_functions_
(),
var_deps_
(),
need_init_fn_
(
false
),
need_init_fn_
(
false
),
init_fn_name_
(),
init_fn_name_
(),
imported_init_fns_
(),
imported_init_fns_
(),
...
@@ -3820,6 +3821,10 @@ void
...
@@ -3820,6 +3821,10 @@ void
Variable
::
lower_init_expression
(
Gogo
*
gogo
,
Named_object
*
function
,
Variable
::
lower_init_expression
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
)
Statement_inserter
*
inserter
)
{
{
Named_object
*
dep
=
gogo
->
var_depends_on
(
this
);
if
(
dep
!=
NULL
&&
dep
->
is_variable
())
dep
->
var_value
()
->
lower_init_expression
(
gogo
,
function
,
inserter
);
if
(
this
->
init_
!=
NULL
&&
!
this
->
init_is_lowered_
)
if
(
this
->
init_
!=
NULL
&&
!
this
->
init_is_lowered_
)
{
{
if
(
this
->
seen_
)
if
(
this
->
seen_
)
...
...
gcc/go/gofrontend/gogo.h
View file @
29f31724
...
@@ -384,6 +384,23 @@ class Gogo
...
@@ -384,6 +384,23 @@ class Gogo
void
void
clear_file_scope
();
clear_file_scope
();
// Record that VAR1 must be initialized after VAR2. This is used
// when VAR2 does not appear in VAR1's INIT or PREINIT.
void
record_var_depends_on
(
Variable
*
var1
,
Named_object
*
var2
)
{
go_assert
(
this
->
var_deps_
.
find
(
var1
)
==
this
->
var_deps_
.
end
());
this
->
var_deps_
[
var1
]
=
var2
;
}
// Return the variable that VAR depends on, or NULL if none.
Named_object
*
var_depends_on
(
Variable
*
var
)
const
{
Var_deps
::
const_iterator
p
=
this
->
var_deps_
.
find
(
var
);
return
p
!=
this
->
var_deps_
.
end
()
?
p
->
second
:
NULL
;
}
// Queue up a type-specific function to be written out. This is
// Queue up a type-specific function to be written out. This is
// used when a type-specific function is needed when not at the top
// used when a type-specific function is needed when not at the top
// level.
// level.
...
@@ -639,8 +656,9 @@ class Gogo
...
@@ -639,8 +656,9 @@ class Gogo
// Type used to map package names to packages.
// Type used to map package names to packages.
typedef
std
::
map
<
std
::
string
,
Package
*>
Packages
;
typedef
std
::
map
<
std
::
string
,
Package
*>
Packages
;
// Type used to map special names in the sys package.
// Type used to map variables to the function calls that set them.
typedef
std
::
map
<
std
::
string
,
std
::
string
>
Sys_names
;
// This is used for initialization dependency analysis.
typedef
std
::
map
<
Variable
*
,
Named_object
*>
Var_deps
;
// Type used to queue writing a type specific function.
// Type used to queue writing a type specific function.
struct
Specific_type_function
struct
Specific_type_function
...
@@ -683,6 +701,10 @@ class Gogo
...
@@ -683,6 +701,10 @@ class Gogo
Packages
packages_
;
Packages
packages_
;
// The functions named "init", if there are any.
// The functions named "init", if there are any.
std
::
vector
<
Named_object
*>
init_functions_
;
std
::
vector
<
Named_object
*>
init_functions_
;
// A mapping from variables to the function calls that initialize
// them, if it is not stored in the variable's init or preinit.
// This is used for dependency analysis.
Var_deps
var_deps_
;
// Whether we need a magic initialization function.
// Whether we need a magic initialization function.
bool
need_init_fn_
;
bool
need_init_fn_
;
// The name of the magic initialization function.
// The name of the magic initialization function.
...
...
gcc/go/gofrontend/parse.cc
View file @
29f31724
...
@@ -1667,6 +1667,7 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
...
@@ -1667,6 +1667,7 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
// the right number of values, but it might. Declare the variables,
// the right number of values, but it might. Declare the variables,
// and then assign the results of the call to them.
// and then assign the results of the call to them.
Named_object
*
first_var
=
NULL
;
unsigned
int
index
=
0
;
unsigned
int
index
=
0
;
bool
any_new
=
false
;
bool
any_new
=
false
;
for
(
Typed_identifier_list
::
const_iterator
pv
=
vars
->
begin
();
for
(
Typed_identifier_list
::
const_iterator
pv
=
vars
->
begin
();
...
@@ -1674,7 +1675,22 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
...
@@ -1674,7 +1675,22 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
++
pv
,
++
index
)
++
pv
,
++
index
)
{
{
Expression
*
init
=
Expression
::
make_call_result
(
call
,
index
);
Expression
*
init
=
Expression
::
make_call_result
(
call
,
index
);
this
->
init_var
(
*
pv
,
type
,
init
,
is_coloneq
,
false
,
&
any_new
);
Named_object
*
no
=
this
->
init_var
(
*
pv
,
type
,
init
,
is_coloneq
,
false
,
&
any_new
);
if
(
this
->
gogo_
->
in_global_scope
()
&&
no
->
is_variable
())
{
if
(
first_var
==
NULL
)
first_var
=
no
;
else
{
// The subsequent vars have an implicit dependency on
// the first one, so that everything gets initialized in
// the right order and so that we detect cycles
// correctly.
this
->
gogo_
->
record_var_depends_on
(
no
->
var_value
(),
first_var
);
}
}
}
}
if
(
is_coloneq
&&
!
any_new
)
if
(
is_coloneq
&&
!
any_new
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment