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
8586635c
Commit
8586635c
authored
Aug 01, 2011
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use temporary variables for calls with multiple results.
From-SVN: r176998
parent
c469244e
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
584 additions
and
256 deletions
+584
-256
gcc/go/gofrontend/expressions.cc
+157
-57
gcc/go/gofrontend/expressions.h
+56
-20
gcc/go/gofrontend/gogo.cc
+193
-105
gcc/go/gofrontend/gogo.h
+44
-3
gcc/go/gofrontend/statements.cc
+119
-62
gcc/go/gofrontend/statements.h
+15
-9
No files found.
gcc/go/gofrontend/expressions.cc
View file @
8586635c
...
@@ -926,7 +926,8 @@ Parser_expression::do_type()
...
@@ -926,7 +926,8 @@ Parser_expression::do_type()
// if necessary.
// if necessary.
Expression
*
Expression
*
Var_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
int
)
Var_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
int
)
{
{
if
(
this
->
variable_
->
is_variable
())
if
(
this
->
variable_
->
is_variable
())
{
{
...
@@ -935,8 +936,11 @@ Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -935,8 +936,11 @@ Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
// reference to a variable which is local to an enclosing
// reference to a variable which is local to an enclosing
// function will be a reference to a field in a closure.
// function will be a reference to a field in a closure.
if
(
var
->
is_global
())
if
(
var
->
is_global
())
{
function
=
NULL
;
function
=
NULL
;
var
->
lower_init_expression
(
gogo
,
function
);
inserter
=
NULL
;
}
var
->
lower_init_expression
(
gogo
,
function
,
inserter
);
}
}
return
this
;
return
this
;
}
}
...
@@ -1061,7 +1065,9 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
...
@@ -1061,7 +1065,9 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
// that here by adding a type cast. We need to use base() to push
// that here by adding a type cast. We need to use base() to push
// the circularity down one level.
// the circularity down one level.
tree
ret
=
var_to_tree
(
bvar
);
tree
ret
=
var_to_tree
(
bvar
);
if
(
POINTER_TYPE_P
(
TREE_TYPE
(
ret
))
&&
VOID_TYPE_P
(
TREE_TYPE
(
TREE_TYPE
(
ret
))))
if
(
!
this
->
is_lvalue_
&&
POINTER_TYPE_P
(
TREE_TYPE
(
ret
))
&&
VOID_TYPE_P
(
TREE_TYPE
(
TREE_TYPE
(
ret
))))
{
{
Btype
*
type_btype
=
this
->
type
()
->
base
()
->
get_backend
(
context
->
gogo
());
Btype
*
type_btype
=
this
->
type
()
->
base
()
->
get_backend
(
context
->
gogo
());
tree
type_tree
=
type_to_tree
(
type_btype
);
tree
type_tree
=
type_to_tree
(
type_btype
);
...
@@ -1072,7 +1078,7 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
...
@@ -1072,7 +1078,7 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
// Make a reference to a temporary variable.
// Make a reference to a temporary variable.
E
xpression
*
Temporary_reference_e
xpression
*
Expression
::
make_temporary_reference
(
Temporary_statement
*
statement
,
Expression
::
make_temporary_reference
(
Temporary_statement
*
statement
,
source_location
location
)
source_location
location
)
{
{
...
@@ -1302,7 +1308,7 @@ Unknown_expression::name() const
...
@@ -1302,7 +1308,7 @@ Unknown_expression::name() const
// Lower a reference to an unknown name.
// Lower a reference to an unknown name.
Expression
*
Expression
*
Unknown_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
Unknown_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
source_location
location
=
this
->
location
();
source_location
location
=
this
->
location
();
Named_object
*
no
=
this
->
named_object_
;
Named_object
*
no
=
this
->
named_object_
;
...
@@ -2394,7 +2400,7 @@ class Const_expression : public Expression
...
@@ -2394,7 +2400,7 @@ class Const_expression : public Expression
do_traverse
(
Traverse
*
);
do_traverse
(
Traverse
*
);
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
bool
bool
do_is_constant
()
const
do_is_constant
()
const
...
@@ -2462,7 +2468,8 @@ Const_expression::do_traverse(Traverse* traverse)
...
@@ -2462,7 +2468,8 @@ Const_expression::do_traverse(Traverse* traverse)
// predeclared constant iota into an integer value.
// predeclared constant iota into an integer value.
Expression
*
Expression
*
Const_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
int
iota_value
)
Const_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
Statement_inserter
*
,
int
iota_value
)
{
{
if
(
this
->
constant_
->
const_value
()
->
expr
()
->
classification
()
if
(
this
->
constant_
->
const_value
()
->
expr
()
->
classification
()
==
EXPRESSION_IOTA
)
==
EXPRESSION_IOTA
)
...
@@ -2931,7 +2938,7 @@ class Iota_expression : public Parser_expression
...
@@ -2931,7 +2938,7 @@ class Iota_expression : public Parser_expression
protected
:
protected
:
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
go_unreachable
();
}
{
go_unreachable
();
}
// There should only ever be one of these.
// There should only ever be one of these.
...
@@ -2988,7 +2995,7 @@ class Type_conversion_expression : public Expression
...
@@ -2988,7 +2995,7 @@ class Type_conversion_expression : public Expression
do_traverse
(
Traverse
*
traverse
);
do_traverse
(
Traverse
*
traverse
);
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
bool
bool
do_is_constant
()
const
do_is_constant
()
const
...
@@ -3057,7 +3064,8 @@ Type_conversion_expression::do_traverse(Traverse* traverse)
...
@@ -3057,7 +3064,8 @@ Type_conversion_expression::do_traverse(Traverse* traverse)
// Convert to a constant at lowering time.
// Convert to a constant at lowering time.
Expression
*
Expression
*
Type_conversion_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
Type_conversion_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
Type
*
type
=
this
->
type_
;
Type
*
type
=
this
->
type_
;
Expression
*
val
=
this
->
expr_
;
Expression
*
val
=
this
->
expr_
;
...
@@ -3753,7 +3761,7 @@ class Unary_expression : public Expression
...
@@ -3753,7 +3761,7 @@ class Unary_expression : public Expression
{
return
Expression
::
traverse
(
&
this
->
expr_
,
traverse
);
}
{
return
Expression
::
traverse
(
&
this
->
expr_
,
traverse
);
}
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
bool
bool
do_is_constant
()
const
;
do_is_constant
()
const
;
...
@@ -3808,7 +3816,7 @@ class Unary_expression : public Expression
...
@@ -3808,7 +3816,7 @@ class Unary_expression : public Expression
// instead.
// instead.
Expression
*
Expression
*
Unary_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
Unary_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
Operator
op
=
this
->
op_
;
Operator
op
=
this
->
op_
;
...
@@ -5137,7 +5145,7 @@ Binary_expression::eval_complex(Operator op, Type* left_type,
...
@@ -5137,7 +5145,7 @@ Binary_expression::eval_complex(Operator op, Type* left_type,
// constants.
// constants.
Expression
*
Expression
*
Binary_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
Binary_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
source_location
location
=
this
->
location
();
source_location
location
=
this
->
location
();
Operator
op
=
this
->
op_
;
Operator
op
=
this
->
op_
;
...
@@ -6656,7 +6664,7 @@ class Builtin_call_expression : public Call_expression
...
@@ -6656,7 +6664,7 @@ class Builtin_call_expression : public Call_expression
protected
:
protected
:
// This overrides Call_expression::do_lower.
// This overrides Call_expression::do_lower.
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
bool
bool
do_is_constant
()
const
;
do_is_constant
()
const
;
...
@@ -6864,7 +6872,8 @@ Find_call_expression::expression(Expression** pexpr)
...
@@ -6864,7 +6872,8 @@ Find_call_expression::expression(Expression** pexpr)
// specific expressions. We also convert to a constant if we can.
// specific expressions. We also convert to a constant if we can.
Expression
*
Expression
*
Builtin_call_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
int
)
Builtin_call_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
int
)
{
{
if
(
this
->
classification
()
==
EXPRESSION_ERROR
)
if
(
this
->
classification
()
==
EXPRESSION_ERROR
)
return
this
;
return
this
;
...
@@ -6974,7 +6983,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -6974,7 +6983,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
this
->
set_is_error
();
this
->
set_is_error
();
return
this
;
return
this
;
}
}
return
this
->
lower_varargs
(
gogo
,
function
,
slice_type
,
2
);
return
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
slice_type
,
2
);
}
}
return
this
;
return
this
;
...
@@ -8553,9 +8562,10 @@ Call_expression::do_traverse(Traverse* traverse)
...
@@ -8553,9 +8562,10 @@ Call_expression::do_traverse(Traverse* traverse)
// Lower a call statement.
// Lower a call statement.
Expression
*
Expression
*
Call_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
int
)
Call_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
int
)
{
{
// A type cas
e
can look like a function call.
// A type cas
t
can look like a function call.
if
(
this
->
fn_
->
is_type_expression
()
if
(
this
->
fn_
->
is_type_expression
()
&&
this
->
args_
!=
NULL
&&
this
->
args_
!=
NULL
&&
this
->
args_
->
size
()
==
1
)
&&
this
->
args_
->
size
()
==
1
)
...
@@ -8597,6 +8607,29 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -8597,6 +8607,29 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
}
}
}
}
// If this call returns multiple results, create a temporary
// variable for each result.
size_t
rc
=
this
->
result_count
();
if
(
rc
>
1
&&
this
->
results_
==
NULL
)
{
std
::
vector
<
Temporary_statement
*>*
temps
=
new
std
::
vector
<
Temporary_statement
*>
;
temps
->
reserve
(
rc
);
const
Typed_identifier_list
*
results
=
this
->
fn_
->
type
()
->
function_type
()
->
results
();
for
(
Typed_identifier_list
::
const_iterator
p
=
results
->
begin
();
p
!=
results
->
end
();
++
p
)
{
Temporary_statement
*
temp
=
Statement
::
make_temporary
(
p
->
type
(),
NULL
,
p
->
location
());
inserter
->
insert
(
temp
);
temps
->
push_back
(
temp
);
}
this
->
results_
=
temps
;
}
// Handle a call to a varargs function by packaging up the extra
// Handle a call to a varargs function by packaging up the extra
// parameters.
// parameters.
if
(
this
->
fn_
->
type
()
->
function_type
()
!=
NULL
if
(
this
->
fn_
->
type
()
->
function_type
()
!=
NULL
...
@@ -8606,7 +8639,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -8606,7 +8639,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
const
Typed_identifier_list
*
parameters
=
fntype
->
parameters
();
const
Typed_identifier_list
*
parameters
=
fntype
->
parameters
();
go_assert
(
parameters
!=
NULL
&&
!
parameters
->
empty
());
go_assert
(
parameters
!=
NULL
&&
!
parameters
->
empty
());
Type
*
varargs_type
=
parameters
->
back
().
type
();
Type
*
varargs_type
=
parameters
->
back
().
type
();
return
this
->
lower_varargs
(
gogo
,
function
,
varargs_type
,
return
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
varargs_type
,
parameters
->
size
());
parameters
->
size
());
}
}
...
@@ -8622,6 +8655,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -8622,6 +8655,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
Expression
*
Expression
*
Call_expression
::
lower_varargs
(
Gogo
*
gogo
,
Named_object
*
function
,
Call_expression
::
lower_varargs
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
Type
*
varargs_type
,
size_t
param_count
)
Type
*
varargs_type
,
size_t
param_count
)
{
{
if
(
this
->
varargs_are_lowered_
)
if
(
this
->
varargs_are_lowered_
)
...
@@ -8702,13 +8736,12 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
...
@@ -8702,13 +8736,12 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
// Lower all the new subexpressions.
// Lower all the new subexpressions.
Expression
*
ret
=
this
;
Expression
*
ret
=
this
;
gogo
->
lower_expression
(
function
,
&
ret
);
gogo
->
lower_expression
(
function
,
inserter
,
&
ret
);
go_assert
(
ret
==
this
);
go_assert
(
ret
==
this
);
return
ret
;
return
ret
;
}
}
// Get the function type. Returns NULL if we don't know the type. If
// Get the function type. This can return NULL in error cases.
// this returns NULL, and if_ERROR is true, issues an error.
Function_type
*
Function_type
*
Call_expression
::
get_function_type
()
const
Call_expression
::
get_function_type
()
const
...
@@ -8729,6 +8762,16 @@ Call_expression::result_count() const
...
@@ -8729,6 +8762,16 @@ Call_expression::result_count() const
return
fntype
->
results
()
->
size
();
return
fntype
->
results
()
->
size
();
}
}
// Return the temporary which holds a result.
Temporary_statement
*
Call_expression
::
result
(
size_t
i
)
const
{
go_assert
(
this
->
results_
!=
NULL
&&
this
->
results_
->
size
()
>
i
);
return
(
*
this
->
results_
)[
i
];
}
// Return whether this is a call to the predeclared function recover.
// Return whether this is a call to the predeclared function recover.
bool
bool
...
@@ -8759,6 +8802,21 @@ Call_expression::do_set_recover_arg(Expression*)
...
@@ -8759,6 +8802,21 @@ Call_expression::do_set_recover_arg(Expression*)
go_unreachable
();
go_unreachable
();
}
}
// We have found an error with this call expression; return true if
// we should report it.
bool
Call_expression
::
issue_error
()
{
if
(
this
->
issued_error_
)
return
false
;
else
{
this
->
issued_error_
=
true
;
return
true
;
}
}
// Get the type.
// Get the type.
Type
*
Type
*
...
@@ -8941,15 +8999,12 @@ Call_expression::do_check_types(Gogo*)
...
@@ -8941,15 +8999,12 @@ Call_expression::do_check_types(Gogo*)
// Return whether we have to use a temporary variable to ensure that
// Return whether we have to use a temporary variable to ensure that
// we evaluate this call expression in order. If the call returns no
// we evaluate this call expression in order. If the call returns no
// results then it will inevitably be executed last. If the call
// results then it will inevitably be executed last.
// returns more than one result then it will be used with Call_result
// expressions. So we only have to use a temporary variable if the
// call returns exactly one result.
bool
bool
Call_expression
::
do_must_eval_in_order
()
const
Call_expression
::
do_must_eval_in_order
()
const
{
{
return
this
->
result_count
()
==
1
;
return
this
->
result_count
()
>
0
;
}
}
// Get the function and the first argument to use when calling a bound
// Get the function and the first argument to use when calling a bound
...
@@ -9193,16 +9248,56 @@ Call_expression::do_get_tree(Translate_context* context)
...
@@ -9193,16 +9248,56 @@ Call_expression::do_get_tree(Translate_context* context)
ret
=
build1
(
NOP_EXPR
,
rettype
,
ret
);
ret
=
build1
(
NOP_EXPR
,
rettype
,
ret
);
}
}
// If there is more than one result, we will refer to the call
if
(
this
->
results_
!=
NULL
)
// multiple times.
ret
=
this
->
set_results
(
context
,
ret
);
if
(
fntype
->
results
()
!=
NULL
&&
fntype
->
results
()
->
size
()
>
1
)
ret
=
save_expr
(
ret
);
this
->
tree_
=
ret
;
this
->
tree_
=
ret
;
return
ret
;
return
ret
;
}
}
// Set the result variables if this call returns multiple results.
tree
Call_expression
::
set_results
(
Translate_context
*
context
,
tree
call_tree
)
{
tree
stmt_list
=
NULL_TREE
;
call_tree
=
save_expr
(
call_tree
);
if
(
TREE_CODE
(
TREE_TYPE
(
call_tree
))
!=
RECORD_TYPE
)
{
go_assert
(
saw_errors
());
return
call_tree
;
}
source_location
loc
=
this
->
location
();
tree
field
=
TYPE_FIELDS
(
TREE_TYPE
(
call_tree
));
size_t
rc
=
this
->
result_count
();
for
(
size_t
i
=
0
;
i
<
rc
;
++
i
,
field
=
DECL_CHAIN
(
field
))
{
go_assert
(
field
!=
NULL_TREE
);
Temporary_statement
*
temp
=
this
->
result
(
i
);
Temporary_reference_expression
*
ref
=
Expression
::
make_temporary_reference
(
temp
,
loc
);
ref
->
set_is_lvalue
();
tree
temp_tree
=
ref
->
get_tree
(
context
);
if
(
temp_tree
==
error_mark_node
)
continue
;
tree
val_tree
=
build3_loc
(
loc
,
COMPONENT_REF
,
TREE_TYPE
(
field
),
call_tree
,
field
,
NULL_TREE
);
tree
set_tree
=
build2_loc
(
loc
,
MODIFY_EXPR
,
void_type_node
,
temp_tree
,
val_tree
);
append_to_statement_list
(
set_tree
,
&
stmt_list
);
}
go_assert
(
field
==
NULL_TREE
);
return
save_expr
(
stmt_list
);
}
// Make a call expression.
// Make a call expression.
Call_expression
*
Call_expression
*
...
@@ -9292,8 +9387,9 @@ Call_result_expression::do_type()
...
@@ -9292,8 +9387,9 @@ Call_result_expression::do_type()
return
Type
::
make_error_type
();
return
Type
::
make_error_type
();
}
}
const
Typed_identifier_list
*
results
=
fntype
->
results
();
const
Typed_identifier_list
*
results
=
fntype
->
results
();
if
(
results
==
NULL
)
if
(
results
==
NULL
||
results
->
size
()
<
2
)
{
{
if
(
ce
->
issue_error
())
this
->
report_error
(
_
(
"number of results does not match "
this
->
report_error
(
_
(
"number of results does not match "
"number of values"
));
"number of values"
));
return
Type
::
make_error_type
();
return
Type
::
make_error_type
();
...
@@ -9307,6 +9403,7 @@ Call_result_expression::do_type()
...
@@ -9307,6 +9403,7 @@ Call_result_expression::do_type()
}
}
if
(
pr
==
results
->
end
())
if
(
pr
==
results
->
end
())
{
{
if
(
ce
->
issue_error
())
this
->
report_error
(
_
(
"number of results does not match "
this
->
report_error
(
_
(
"number of results does not match "
"number of values"
));
"number of values"
));
return
Type
::
make_error_type
();
return
Type
::
make_error_type
();
...
@@ -9332,27 +9429,18 @@ Call_result_expression::do_determine_type(const Type_context*)
...
@@ -9332,27 +9429,18 @@ Call_result_expression::do_determine_type(const Type_context*)
this
->
call_
->
determine_type_no_context
();
this
->
call_
->
determine_type_no_context
();
}
}
// Return the tree.
// Return the tree. We just refer to the temporary set by the call
// expression. We don't do this at lowering time because it makes it
// hard to evaluate the call at the right time.
tree
tree
Call_result_expression
::
do_get_tree
(
Translate_context
*
context
)
Call_result_expression
::
do_get_tree
(
Translate_context
*
context
)
{
{
tree
call_tree
=
this
->
call_
->
get_tree
(
context
);
Call_expression
*
ce
=
this
->
call_
->
call_expression
();
if
(
call_tree
==
error_mark_node
)
go_assert
(
ce
!=
NULL
);
return
error_mark_node
;
Temporary_statement
*
ts
=
ce
->
result
(
this
->
index_
);
if
(
TREE_CODE
(
TREE_TYPE
(
call_tree
))
!=
RECORD_TYPE
)
Expression
*
ref
=
Expression
::
make_temporary_reference
(
ts
,
this
->
location
());
{
return
ref
->
get_tree
(
context
);
go_assert
(
saw_errors
());
return
error_mark_node
;
}
tree
field
=
TYPE_FIELDS
(
TREE_TYPE
(
call_tree
));
for
(
unsigned
int
i
=
0
;
i
<
this
->
index_
;
++
i
)
{
go_assert
(
field
!=
NULL_TREE
);
field
=
DECL_CHAIN
(
field
);
}
go_assert
(
field
!=
NULL_TREE
);
return
build3
(
COMPONENT_REF
,
TREE_TYPE
(
field
),
call_tree
,
field
,
NULL_TREE
);
}
}
// Make a reference to a single result of a call which returns
// Make a reference to a single result of a call which returns
...
@@ -9383,7 +9471,7 @@ Index_expression::do_traverse(Traverse* traverse)
...
@@ -9383,7 +9471,7 @@ Index_expression::do_traverse(Traverse* traverse)
// expression into an array index, a string index, or a map index.
// expression into an array index, a string index, or a map index.
Expression
*
Expression
*
Index_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
Index_expression
::
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
source_location
location
=
this
->
location
();
source_location
location
=
this
->
location
();
Expression
*
left
=
this
->
left_
;
Expression
*
left
=
this
->
left_
;
...
@@ -10542,7 +10630,7 @@ class Selector_expression : public Parser_expression
...
@@ -10542,7 +10630,7 @@ class Selector_expression : public Parser_expression
{
return
Expression
::
traverse
(
&
this
->
left_
,
traverse
);
}
{
return
Expression
::
traverse
(
&
this
->
left_
,
traverse
);
}
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Expression
*
Expression
*
do_copy
()
do_copy
()
...
@@ -10565,7 +10653,8 @@ class Selector_expression : public Parser_expression
...
@@ -10565,7 +10653,8 @@ class Selector_expression : public Parser_expression
// hand side.
// hand side.
Expression
*
Expression
*
Selector_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
int
)
Selector_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
{
Expression
*
left
=
this
->
left_
;
Expression
*
left
=
this
->
left_
;
if
(
left
->
is_type_expression
())
if
(
left
->
is_type_expression
())
...
@@ -10734,6 +10823,8 @@ Selector_expression::lower_method_expression(Gogo* gogo)
...
@@ -10734,6 +10823,8 @@ Selector_expression::lower_method_expression(Gogo* gogo)
}
}
}
}
gogo
->
start_block
(
location
);
Call_expression
*
call
=
Expression
::
make_call
(
bm
,
args
,
Call_expression
*
call
=
Expression
::
make_call
(
bm
,
args
,
method_type
->
is_varargs
(),
method_type
->
is_varargs
(),
location
);
location
);
...
@@ -10756,6 +10847,13 @@ Selector_expression::lower_method_expression(Gogo* gogo)
...
@@ -10756,6 +10847,13 @@ Selector_expression::lower_method_expression(Gogo* gogo)
}
}
gogo
->
add_statement
(
s
);
gogo
->
add_statement
(
s
);
Block
*
b
=
gogo
->
finish_block
(
location
);
gogo
->
add_block
(
b
,
location
);
// Lower the call in case there are multiple results.
gogo
->
lower_block
(
no
,
b
);
gogo
->
finish_function
(
location
);
gogo
->
finish_function
(
location
);
return
Expression
::
make_func_reference
(
no
,
NULL
,
location
);
return
Expression
::
make_func_reference
(
no
,
NULL
,
location
);
...
@@ -11860,7 +11958,7 @@ class Composite_literal_expression : public Parser_expression
...
@@ -11860,7 +11958,7 @@ class Composite_literal_expression : public Parser_expression
do_traverse
(
Traverse
*
traverse
);
do_traverse
(
Traverse
*
traverse
);
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Expression
*
Expression
*
do_copy
()
do_copy
()
...
@@ -11884,7 +11982,7 @@ class Composite_literal_expression : public Parser_expression
...
@@ -11884,7 +11982,7 @@ class Composite_literal_expression : public Parser_expression
make_array
(
Type
*
,
Expression_list
*
);
make_array
(
Type
*
,
Expression_list
*
);
Expression
*
Expression
*
lower_map
(
Gogo
*
,
Named_object
*
,
Type
*
);
lower_map
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
Type
*
);
// The type of the composite literal.
// The type of the composite literal.
Type
*
type_
;
Type
*
type_
;
...
@@ -11913,7 +12011,8 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
...
@@ -11913,7 +12011,8 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
// the type.
// the type.
Expression
*
Expression
*
Composite_literal_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
int
)
Composite_literal_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
int
)
{
{
Type
*
type
=
this
->
type_
;
Type
*
type
=
this
->
type_
;
...
@@ -11940,7 +12039,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
...
@@ -11940,7 +12039,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
else
if
(
type
->
array_type
()
!=
NULL
)
else
if
(
type
->
array_type
()
!=
NULL
)
return
this
->
lower_array
(
type
);
return
this
->
lower_array
(
type
);
else
if
(
type
->
map_type
()
!=
NULL
)
else
if
(
type
->
map_type
()
!=
NULL
)
return
this
->
lower_map
(
gogo
,
function
,
type
);
return
this
->
lower_map
(
gogo
,
function
,
inserter
,
type
);
else
else
{
{
error_at
(
this
->
location
(),
error_at
(
this
->
location
(),
...
@@ -12244,6 +12343,7 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
...
@@ -12244,6 +12343,7 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
Expression
*
Expression
*
Composite_literal_expression
::
lower_map
(
Gogo
*
gogo
,
Named_object
*
function
,
Composite_literal_expression
::
lower_map
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
Type
*
type
)
Type
*
type
)
{
{
source_location
location
=
this
->
location
();
source_location
location
=
this
->
location
();
...
@@ -12272,7 +12372,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
...
@@ -12272,7 +12372,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
if
((
*
p
)
->
unknown_expression
()
!=
NULL
)
if
((
*
p
)
->
unknown_expression
()
!=
NULL
)
{
{
(
*
p
)
->
unknown_expression
()
->
clear_is_composite_literal_key
();
(
*
p
)
->
unknown_expression
()
->
clear_is_composite_literal_key
();
gogo
->
lower_expression
(
function
,
&*
p
);
gogo
->
lower_expression
(
function
,
inserter
,
&*
p
);
go_assert
((
*
p
)
->
is_error_expression
());
go_assert
((
*
p
)
->
is_error_expression
());
return
Expression
::
make_error
(
location
);
return
Expression
::
make_error
(
location
);
}
}
...
...
gcc/go/gofrontend/expressions.h
View file @
8586635c
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
class
Gogo
;
class
Gogo
;
class
Translate_context
;
class
Translate_context
;
class
Traverse
;
class
Traverse
;
class
Statement_inserter
;
class
Type
;
class
Type
;
struct
Type_context
;
struct
Type_context
;
class
Function_type
;
class
Function_type
;
...
@@ -128,7 +129,7 @@ class Expression
...
@@ -128,7 +129,7 @@ class Expression
// Make a reference to a temporary variable. Temporary variables
// Make a reference to a temporary variable. Temporary variables
// are always created by a single statement, which is what we use to
// are always created by a single statement, which is what we use to
// refer to them.
// refer to them.
static
E
xpression
*
static
Temporary_reference_e
xpression
*
make_temporary_reference
(
Temporary_statement
*
,
source_location
);
make_temporary_reference
(
Temporary_statement
*
,
source_location
);
// Make a sink expression--a reference to the blank identifier _.
// Make a sink expression--a reference to the blank identifier _.
...
@@ -521,13 +522,18 @@ class Expression
...
@@ -521,13 +522,18 @@ class Expression
traverse_subexpressions
(
Traverse
*
);
traverse_subexpressions
(
Traverse
*
);
// Lower an expression. This is called immediately after parsing.
// Lower an expression. This is called immediately after parsing.
// IOTA_VALUE is the value that we should give to any iota
// FUNCTION is the function we are in; it will be NULL for an
// expressions. This function must resolve expressions which could
// expression initializing a global variable. INSERTER may be used
// not be fully parsed into their final form. It returns the same
// to insert statements before the statement or initializer
// Expression or a new one.
// containing this expression; it is normally used to create
// temporary variables. IOTA_VALUE is the value that we should give
// to any iota expressions. This function must resolve expressions
// which could not be fully parsed into their final form. It
// returns the same Expression or a new one.
Expression
*
Expression
*
lower
(
Gogo
*
gogo
,
Named_object
*
function
,
int
iota_value
)
lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
{
return
this
->
do_lower
(
gogo
,
function
,
iota_value
);
}
int
iota_value
)
{
return
this
->
do_lower
(
gogo
,
function
,
inserter
,
iota_value
);
}
// Determine the real type of an expression with abstract integer,
// Determine the real type of an expression with abstract integer,
// floating point, or complex type. TYPE_CONTEXT describes the
// floating point, or complex type. TYPE_CONTEXT describes the
...
@@ -636,7 +642,7 @@ class Expression
...
@@ -636,7 +642,7 @@ class Expression
// Return a lowered expression.
// Return a lowered expression.
virtual
Expression
*
virtual
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
{
return
this
;
}
{
return
this
;
}
// Return whether this is a constant expression.
// Return whether this is a constant expression.
...
@@ -871,7 +877,7 @@ class Parser_expression : public Expression
...
@@ -871,7 +877,7 @@ class Parser_expression : public Expression
protected
:
protected
:
virtual
Expression
*
virtual
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
)
=
0
;
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
)
=
0
;
Type
*
Type
*
do_type
();
do_type
();
...
@@ -906,7 +912,7 @@ class Var_expression : public Expression
...
@@ -906,7 +912,7 @@ class Var_expression : public Expression
protected
:
protected
:
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Type
*
Type
*
do_type
();
do_type
();
...
@@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression
...
@@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression
Temporary_reference_expression
(
Temporary_statement
*
statement
,
Temporary_reference_expression
(
Temporary_statement
*
statement
,
source_location
location
)
source_location
location
)
:
Expression
(
EXPRESSION_TEMPORARY_REFERENCE
,
location
),
:
Expression
(
EXPRESSION_TEMPORARY_REFERENCE
,
location
),
statement_
(
statement
)
statement_
(
statement
)
,
is_lvalue_
(
false
)
{
}
{
}
// Indicate that this reference appears on the left hand side of an
// assignment statement.
void
set_is_lvalue
()
{
this
->
is_lvalue_
=
true
;
}
protected
:
protected
:
Type
*
Type
*
do_type
();
do_type
();
...
@@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression
...
@@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression
private
:
private
:
// The statement where the temporary variable is defined.
// The statement where the temporary variable is defined.
Temporary_statement
*
statement_
;
Temporary_statement
*
statement_
;
// Whether this reference appears on the left hand side of an
// assignment statement.
bool
is_lvalue_
;
};
};
// A string expression.
// A string expression.
...
@@ -1099,7 +1114,7 @@ class Binary_expression : public Expression
...
@@ -1099,7 +1114,7 @@ class Binary_expression : public Expression
do_traverse
(
Traverse
*
traverse
);
do_traverse
(
Traverse
*
traverse
);
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
bool
bool
do_is_constant
()
const
do_is_constant
()
const
...
@@ -1156,9 +1171,9 @@ class Call_expression : public Expression
...
@@ -1156,9 +1171,9 @@ class Call_expression : public Expression
Call_expression
(
Expression
*
fn
,
Expression_list
*
args
,
bool
is_varargs
,
Call_expression
(
Expression
*
fn
,
Expression_list
*
args
,
bool
is_varargs
,
source_location
location
)
source_location
location
)
:
Expression
(
EXPRESSION_CALL
,
location
),
:
Expression
(
EXPRESSION_CALL
,
location
),
fn_
(
fn
),
args_
(
args
),
type_
(
NULL
),
tree_
(
NULL
),
is_varargs_
(
is_varargs
),
fn_
(
fn
),
args_
(
args
),
type_
(
NULL
),
results_
(
NULL
),
tree_
(
NULL
),
varargs_are_lowered_
(
false
),
types_are_determin
ed_
(
false
),
is_varargs_
(
is_varargs
),
varargs_are_lower
ed_
(
false
),
is_deferred
_
(
false
)
types_are_determined_
(
false
),
is_deferred_
(
false
),
issued_error
_
(
false
)
{
}
{
}
// The function to call.
// The function to call.
...
@@ -1183,6 +1198,12 @@ class Call_expression : public Expression
...
@@ -1183,6 +1198,12 @@ class Call_expression : public Expression
size_t
size_t
result_count
()
const
;
result_count
()
const
;
// Return the temporary variable which holds result I. This is only
// valid after the expression has been lowered, and is only valid
// for calls which return multiple results.
Temporary_statement
*
result
(
size_t
i
)
const
;
// Return whether this is a call to the predeclared function
// Return whether this is a call to the predeclared function
// recover.
// recover.
bool
bool
...
@@ -1207,12 +1228,17 @@ class Call_expression : public Expression
...
@@ -1207,12 +1228,17 @@ class Call_expression : public Expression
set_is_deferred
()
set_is_deferred
()
{
this
->
is_deferred_
=
true
;
}
{
this
->
is_deferred_
=
true
;
}
// We have found an error with this call expression; return true if
// we should report it.
bool
issue_error
();
protected
:
protected
:
int
int
do_traverse
(
Traverse
*
);
do_traverse
(
Traverse
*
);
virtual
Expression
*
virtual
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
void
void
do_discarding_value
()
do_discarding_value
()
...
@@ -1256,8 +1282,8 @@ class Call_expression : public Expression
...
@@ -1256,8 +1282,8 @@ class Call_expression : public Expression
// Let a builtin expression lower varargs.
// Let a builtin expression lower varargs.
Expression
*
Expression
*
lower_varargs
(
Gogo
*
,
Named_object
*
function
,
Type
*
varargs_type
,
lower_varargs
(
Gogo
*
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
size_t
param_count
);
Type
*
varargs_type
,
size_t
param_count
);
// Let a builtin expression check whether types have been
// Let a builtin expression check whether types have been
// determined.
// determined.
...
@@ -1276,6 +1302,9 @@ class Call_expression : public Expression
...
@@ -1276,6 +1302,9 @@ class Call_expression : public Expression
Interface_field_reference_expression
*
,
Interface_field_reference_expression
*
,
tree
*
);
tree
*
);
tree
set_results
(
Translate_context
*
,
tree
);
// The function to call.
// The function to call.
Expression
*
fn_
;
Expression
*
fn_
;
// The arguments to pass. This may be NULL if there are no
// The arguments to pass. This may be NULL if there are no
...
@@ -1283,6 +1312,9 @@ class Call_expression : public Expression
...
@@ -1283,6 +1312,9 @@ class Call_expression : public Expression
Expression_list
*
args_
;
Expression_list
*
args_
;
// The type of the expression, to avoid recomputing it.
// The type of the expression, to avoid recomputing it.
Type
*
type_
;
Type
*
type_
;
// The list of temporaries which will hold the results if the
// function returns a tuple.
std
::
vector
<
Temporary_statement
*>*
results_
;
// The tree for the call, used for a call which returns a tuple.
// The tree for the call, used for a call which returns a tuple.
tree
tree_
;
tree
tree_
;
// True if the last argument is a varargs argument (f(a...)).
// True if the last argument is a varargs argument (f(a...)).
...
@@ -1293,6 +1325,10 @@ class Call_expression : public Expression
...
@@ -1293,6 +1325,10 @@ class Call_expression : public Expression
bool
types_are_determined_
;
bool
types_are_determined_
;
// True if the call is an argument to a defer statement.
// True if the call is an argument to a defer statement.
bool
is_deferred_
;
bool
is_deferred_
;
// True if we reported an error about a mismatch between call
// results and uses. This is to avoid producing multiple errors
// when there are multiple Call_result_expressions.
bool
issued_error_
;
};
};
// An expression which represents a pointer to a function.
// An expression which represents a pointer to a function.
...
@@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression
...
@@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression
protected
:
protected
:
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Expression
*
Expression
*
do_copy
()
do_copy
()
...
@@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression
...
@@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression
do_traverse
(
Traverse
*
);
do_traverse
(
Traverse
*
);
Expression
*
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
int
);
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Expression
*
Expression
*
do_copy
()
do_copy
()
...
...
gcc/go/gofrontend/gogo.cc
View file @
8586635c
...
@@ -1148,9 +1148,13 @@ class Lower_parse_tree : public Traverse
...
@@ -1148,9 +1148,13 @@ class Lower_parse_tree : public Traverse
|
traverse_functions
|
traverse_functions
|
traverse_statements
|
traverse_statements
|
traverse_expressions
),
|
traverse_expressions
),
gogo_
(
gogo
),
function_
(
function
),
iota_value_
(
-
1
)
gogo_
(
gogo
),
function_
(
function
),
iota_value_
(
-
1
)
,
inserter_
()
{
}
{
}
void
set_inserter
(
const
Statement_inserter
*
inserter
)
{
this
->
inserter_
=
*
inserter
;
}
int
int
variable
(
Named_object
*
);
variable
(
Named_object
*
);
...
@@ -1173,18 +1177,44 @@ class Lower_parse_tree : public Traverse
...
@@ -1173,18 +1177,44 @@ class Lower_parse_tree : public Traverse
Named_object
*
function_
;
Named_object
*
function_
;
// Value to use for the predeclared constant iota.
// Value to use for the predeclared constant iota.
int
iota_value_
;
int
iota_value_
;
// Current statement inserter for use by expressions.
Statement_inserter
inserter_
;
};
};
// Lower variables. We handle variables specially to break loops in
// Lower variables.
// which a variable initialization expression refers to itself. The
// loop breaking is in lower_init_expression.
int
int
Lower_parse_tree
::
variable
(
Named_object
*
no
)
Lower_parse_tree
::
variable
(
Named_object
*
no
)
{
{
if
(
no
->
is_variable
())
if
(
!
no
->
is_variable
())
no
->
var_value
()
->
lower_init_expression
(
this
->
gogo_
,
this
->
function_
);
return
TRAVERSE_CONTINUE
;
if
(
no
->
is_variable
()
&&
no
->
var_value
()
->
is_global
())
{
// Global variables can have loops in their initialization
// expressions. This is handled in lower_init_expression.
no
->
var_value
()
->
lower_init_expression
(
this
->
gogo_
,
this
->
function_
,
&
this
->
inserter_
);
return
TRAVERSE_CONTINUE
;
return
TRAVERSE_CONTINUE
;
}
// This is a local variable. We are going to return
// TRAVERSE_SKIP_COMPONENTS here because we want to traverse the
// initialization expression when we reach the variable declaration
// statement. However, that means that we need to traverse the type
// ourselves.
if
(
no
->
var_value
()
->
has_type
())
{
Type
*
type
=
no
->
var_value
()
->
type
();
if
(
type
!=
NULL
)
{
if
(
Type
::
traverse
(
type
,
this
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
}
go_assert
(
!
no
->
var_value
()
->
has_pre_init
());
return
TRAVERSE_SKIP_COMPONENTS
;
}
}
// Lower constants. We handle constants specially so that we can set
// Lower constants. We handle constants specially so that we can set
...
@@ -1238,27 +1268,38 @@ Lower_parse_tree::function(Named_object* no)
...
@@ -1238,27 +1268,38 @@ Lower_parse_tree::function(Named_object* no)
int
int
Lower_parse_tree
::
statement
(
Block
*
block
,
size_t
*
pindex
,
Statement
*
sorig
)
Lower_parse_tree
::
statement
(
Block
*
block
,
size_t
*
pindex
,
Statement
*
sorig
)
{
{
Statement_inserter
hold_inserter
(
this
->
inserter_
);
this
->
inserter_
=
Statement_inserter
(
block
,
pindex
);
// Lower the expressions first.
// Lower the expressions first.
int
t
=
sorig
->
traverse_contents
(
this
);
int
t
=
sorig
->
traverse_contents
(
this
);
if
(
t
==
TRAVERSE_EXIT
)
if
(
t
==
TRAVERSE_EXIT
)
{
this
->
inserter_
=
hold_inserter
;
return
t
;
return
t
;
}
// Keep lowering until nothing changes.
// Keep lowering until nothing changes.
Statement
*
s
=
sorig
;
Statement
*
s
=
sorig
;
while
(
true
)
while
(
true
)
{
{
Statement
*
snew
=
s
->
lower
(
this
->
gogo_
,
this
->
function_
,
block
);
Statement
*
snew
=
s
->
lower
(
this
->
gogo_
,
this
->
function_
,
block
,
&
this
->
inserter_
);
if
(
snew
==
s
)
if
(
snew
==
s
)
break
;
break
;
s
=
snew
;
s
=
snew
;
t
=
s
->
traverse_contents
(
this
);
t
=
s
->
traverse_contents
(
this
);
if
(
t
==
TRAVERSE_EXIT
)
if
(
t
==
TRAVERSE_EXIT
)
{
this
->
inserter_
=
hold_inserter
;
return
t
;
return
t
;
}
}
}
if
(
s
!=
sorig
)
if
(
s
!=
sorig
)
block
->
replace_statement
(
*
pindex
,
s
);
block
->
replace_statement
(
*
pindex
,
s
);
this
->
inserter_
=
hold_inserter
;
return
TRAVERSE_SKIP_COMPONENTS
;
return
TRAVERSE_SKIP_COMPONENTS
;
}
}
...
@@ -1277,7 +1318,7 @@ Lower_parse_tree::expression(Expression** pexpr)
...
@@ -1277,7 +1318,7 @@ Lower_parse_tree::expression(Expression** pexpr)
{
{
Expression
*
e
=
*
pexpr
;
Expression
*
e
=
*
pexpr
;
Expression
*
enew
=
e
->
lower
(
this
->
gogo_
,
this
->
function_
,
Expression
*
enew
=
e
->
lower
(
this
->
gogo_
,
this
->
function_
,
this
->
iota_value_
);
&
this
->
inserter_
,
this
->
iota_value_
);
if
(
enew
==
e
)
if
(
enew
==
e
)
break
;
break
;
*
pexpr
=
enew
;
*
pexpr
=
enew
;
...
@@ -1304,12 +1345,16 @@ Gogo::lower_block(Named_object* function, Block* block)
...
@@ -1304,12 +1345,16 @@ Gogo::lower_block(Named_object* function, Block* block)
block
->
traverse
(
&
lower_parse_tree
);
block
->
traverse
(
&
lower_parse_tree
);
}
}
// Lower an expression.
// Lower an expression. INSERTER may be NULL, in which case the
// expression had better not need to create any temporaries.
void
void
Gogo
::
lower_expression
(
Named_object
*
function
,
Expression
**
pexpr
)
Gogo
::
lower_expression
(
Named_object
*
function
,
Statement_inserter
*
inserter
,
Expression
**
pexpr
)
{
{
Lower_parse_tree
lower_parse_tree
(
this
,
function
);
Lower_parse_tree
lower_parse_tree
(
this
,
function
);
if
(
inserter
!=
NULL
)
lower_parse_tree
.
set_inserter
(
inserter
);
lower_parse_tree
.
expression
(
pexpr
);
lower_parse_tree
.
expression
(
pexpr
);
}
}
...
@@ -1951,12 +1996,27 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
...
@@ -1951,12 +1996,27 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
break
;
break
;
source_location
loc
=
(
*
pexpr
)
->
location
();
source_location
loc
=
(
*
pexpr
)
->
location
();
Temporary_statement
*
ts
=
Statement
::
make_temporary
(
NULL
,
*
pexpr
,
loc
);
Statement
*
s
;
block
->
insert_statement_before
(
*
pindex
,
ts
);
if
((
*
pexpr
)
->
call_expression
()
==
NULL
++*
pindex
;
||
(
*
pexpr
)
->
call_expression
()
->
result_count
()
<
2
)
{
Temporary_statement
*
ts
=
Statement
::
make_temporary
(
NULL
,
*
pexpr
,
loc
);
s
=
ts
;
*
pexpr
=
Expression
::
make_temporary_reference
(
ts
,
loc
);
*
pexpr
=
Expression
::
make_temporary_reference
(
ts
,
loc
);
}
}
else
{
// A call expression which returns multiple results needs to
// be handled specially. We can't create a temporary
// because there is no type to give it. Any actual uses of
// the values will be done via Call_result_expressions.
s
=
Statement
::
make_statement
(
*
pexpr
);
}
block
->
insert_statement_before
(
*
pindex
,
s
);
++*
pindex
;
}
if
(
init
!=
orig_init
)
if
(
init
!=
orig_init
)
vds
->
var
()
->
var_value
()
->
set_init
(
init
);
vds
->
var
()
->
var_value
()
->
set_init
(
init
);
...
@@ -1978,7 +2038,7 @@ Order_eval::variable(Named_object* no)
...
@@ -1978,7 +2038,7 @@ Order_eval::variable(Named_object* no)
return
TRAVERSE_CONTINUE
;
return
TRAVERSE_CONTINUE
;
Find_eval_ordering
find_eval_ordering
;
Find_eval_ordering
find_eval_ordering
;
init
->
traverse_subexpressions
(
&
find_eval_ordering
);
Expression
::
traverse
(
&
init
,
&
find_eval_ordering
);
if
(
find_eval_ordering
.
size
()
<=
1
)
if
(
find_eval_ordering
.
size
()
<=
1
)
{
{
...
@@ -1993,10 +2053,23 @@ Order_eval::variable(Named_object* no)
...
@@ -1993,10 +2053,23 @@ Order_eval::variable(Named_object* no)
{
{
Expression
**
pexpr
=
*
p
;
Expression
**
pexpr
=
*
p
;
source_location
loc
=
(
*
pexpr
)
->
location
();
source_location
loc
=
(
*
pexpr
)
->
location
();
Temporary_statement
*
ts
=
Statement
::
make_temporary
(
NULL
,
*
pexpr
,
loc
);
Statement
*
s
;
var
->
add_preinit_statement
(
this
->
gogo_
,
ts
);
if
((
*
pexpr
)
->
call_expression
()
==
NULL
||
(
*
pexpr
)
->
call_expression
()
->
result_count
()
<
2
)
{
Temporary_statement
*
ts
=
Statement
::
make_temporary
(
NULL
,
*
pexpr
,
loc
);
s
=
ts
;
*
pexpr
=
Expression
::
make_temporary_reference
(
ts
,
loc
);
*
pexpr
=
Expression
::
make_temporary_reference
(
ts
,
loc
);
}
}
else
{
// A call expression which returns multiple results needs to
// be handled specially.
s
=
Statement
::
make_statement
(
*
pexpr
);
}
var
->
add_preinit_statement
(
this
->
gogo_
,
s
);
}
return
TRAVERSE_SKIP_COMPONENTS
;
return
TRAVERSE_SKIP_COMPONENTS
;
}
}
...
@@ -2181,6 +2254,8 @@ Build_recover_thunks::function(Named_object* orig_no)
...
@@ -2181,6 +2254,8 @@ Build_recover_thunks::function(Named_object* orig_no)
}
}
args
->
push_back
(
this
->
can_recover_arg
(
location
));
args
->
push_back
(
this
->
can_recover_arg
(
location
));
gogo
->
start_block
(
location
);
Call_expression
*
call
=
Expression
::
make_call
(
fn
,
args
,
false
,
location
);
Call_expression
*
call
=
Expression
::
make_call
(
fn
,
args
,
false
,
location
);
Statement
*
s
;
Statement
*
s
;
...
@@ -2202,6 +2277,13 @@ Build_recover_thunks::function(Named_object* orig_no)
...
@@ -2202,6 +2277,13 @@ Build_recover_thunks::function(Named_object* orig_no)
s
->
determine_types
();
s
->
determine_types
();
gogo
->
add_statement
(
s
);
gogo
->
add_statement
(
s
);
Block
*
b
=
gogo
->
finish_block
(
location
);
gogo
->
add_block
(
b
,
location
);
// Lower the call in case it returns multiple results.
gogo
->
lower_block
(
new_no
,
b
);
gogo
->
finish_function
(
location
);
gogo
->
finish_function
(
location
);
// Swap the function bodies and types.
// Swap the function bodies and types.
...
@@ -3152,78 +3234,64 @@ Block::traverse(Traverse* traverse)
...
@@ -3152,78 +3234,64 @@ Block::traverse(Traverse* traverse)
|
Traverse
::
traverse_expressions
|
Traverse
::
traverse_expressions
|
Traverse
::
traverse_types
))
!=
0
)
|
Traverse
::
traverse_types
))
!=
0
)
{
{
const
unsigned
int
e_or_t
=
(
Traverse
::
traverse_expressions
|
Traverse
::
traverse_types
);
const
unsigned
int
e_or_t_or_s
=
(
e_or_t
|
Traverse
::
traverse_statements
);
for
(
Bindings
::
const_definitions_iterator
pb
=
for
(
Bindings
::
const_definitions_iterator
pb
=
this
->
bindings_
->
begin_definitions
();
this
->
bindings_
->
begin_definitions
();
pb
!=
this
->
bindings_
->
end_definitions
();
pb
!=
this
->
bindings_
->
end_definitions
();
++
pb
)
++
pb
)
{
{
int
t
=
TRAVERSE_CONTINUE
;
switch
((
*
pb
)
->
classification
())
switch
((
*
pb
)
->
classification
())
{
{
case
Named_object
:
:
NAMED_OBJECT_CONST
:
case
Named_object
:
:
NAMED_OBJECT_CONST
:
if
((
traverse_mask
&
Traverse
::
traverse_constants
)
!=
0
)
if
((
traverse_mask
&
Traverse
::
traverse_constants
)
!=
0
)
t
=
traverse
->
constant
(
*
pb
,
false
);
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t
)
!=
0
)
{
{
if
(
traverse
->
constant
(
*
pb
,
false
)
==
TRAVERSE_EXIT
)
Type
*
tc
=
(
*
pb
)
->
const_value
()
->
type
();
return
TRAVERSE_EXIT
;
if
(
tc
!=
NULL
}
&&
Type
::
traverse
(
tc
,
traverse
)
==
TRAVERSE_EXIT
)
if
((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
{
Type
*
t
=
(
*
pb
)
->
const_value
()
->
type
();
if
(
t
!=
NULL
&&
Type
::
traverse
(
t
,
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
if
((
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
)
{
if
((
*
pb
)
->
const_value
()
->
traverse_expression
(
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
t
=
(
*
pb
)
->
const_value
()
->
traverse_expression
(
traverse
);
}
}
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_RESULT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_RESULT_VAR
:
if
((
traverse_mask
&
Traverse
::
traverse_variables
)
!=
0
)
if
((
traverse_mask
&
Traverse
::
traverse_variables
)
!=
0
)
t
=
traverse
->
variable
(
*
pb
);
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t
)
!=
0
)
{
{
if
(
traverse
->
variable
(
*
pb
)
==
TRAVERSE_EXIT
)
if
((
*
pb
)
->
is_result_variable
()
return
TRAVERSE_EXIT
;
||
(
*
pb
)
->
var_value
()
->
has_type
())
}
if
(((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
&&
((
*
pb
)
->
is_result_variable
()
||
(
*
pb
)
->
var_value
()
->
has_type
()))
{
{
Type
*
t
=
((
*
pb
)
->
is_variable
()
Type
*
tv
=
((
*
pb
)
->
is_variable
()
?
(
*
pb
)
->
var_value
()
->
type
()
?
(
*
pb
)
->
var_value
()
->
type
()
:
(
*
pb
)
->
result_var_value
()
->
type
());
:
(
*
pb
)
->
result_var_value
()
->
type
());
if
(
t
!=
NULL
if
(
tv
!=
NULL
&&
Type
::
traverse
(
t
,
traverse
)
==
TRAVERSE_EXIT
)
&&
Type
::
traverse
(
tv
,
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
}
}
if
((
*
pb
)
->
is_variable
()
&&
((
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
))
{
if
((
*
pb
)
->
var_value
()
->
traverse_expression
(
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
}
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t_or_s
)
!=
0
&&
(
*
pb
)
->
is_variable
())
t
=
(
*
pb
)
->
var_value
()
->
traverse_expression
(
traverse
,
traverse_mask
);
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_FUNC
:
case
Named_object
:
:
NAMED_OBJECT_FUNC
:
case
Named_object
:
:
NAMED_OBJECT_FUNC_DECLARATION
:
case
Named_object
:
:
NAMED_OBJECT_FUNC_DECLARATION
:
// FIXME: Where will nested functions be found?
go_unreachable
();
go_unreachable
();
case
Named_object
:
:
NAMED_OBJECT_TYPE
:
case
Named_object
:
:
NAMED_OBJECT_TYPE
:
if
((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
if
((
traverse_mask
&
e_or_t
)
!=
0
)
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
t
=
Type
::
traverse
((
*
pb
)
->
type_value
(),
traverse
);
{
if
(
Type
::
traverse
((
*
pb
)
->
type_value
(),
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_TYPE_DECLARATION
:
case
Named_object
:
:
NAMED_OBJECT_TYPE_DECLARATION
:
...
@@ -3237,6 +3305,9 @@ Block::traverse(Traverse* traverse)
...
@@ -3237,6 +3305,9 @@ Block::traverse(Traverse* traverse)
default
:
default
:
go_unreachable
();
go_unreachable
();
}
}
if
(
t
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
}
}
}
...
@@ -3351,14 +3422,17 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
...
@@ -3351,14 +3422,17 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
// Traverse the initializer expression.
// Traverse the initializer expression.
int
int
Variable
::
traverse_expression
(
Traverse
*
traverse
)
Variable
::
traverse_expression
(
Traverse
*
traverse
,
unsigned
int
traverse_mask
)
{
{
if
(
this
->
preinit_
!=
NULL
)
if
(
this
->
preinit_
!=
NULL
)
{
{
if
(
this
->
preinit_
->
traverse
(
traverse
)
==
TRAVERSE_EXIT
)
if
(
this
->
preinit_
->
traverse
(
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
}
}
if
(
this
->
init_
!=
NULL
)
if
(
this
->
init_
!=
NULL
&&
((
traverse_mask
&
(
Traverse
::
traverse_expressions
|
Traverse
::
traverse_types
))
!=
0
))
{
{
if
(
Expression
::
traverse
(
&
this
->
init_
,
traverse
)
==
TRAVERSE_EXIT
)
if
(
Expression
::
traverse
(
&
this
->
init_
,
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
...
@@ -3369,7 +3443,8 @@ Variable::traverse_expression(Traverse* traverse)
...
@@ -3369,7 +3443,8 @@ Variable::traverse_expression(Traverse* traverse)
// Lower the initialization expression after parsing is complete.
// Lower the initialization expression after parsing is complete.
void
void
Variable
::
lower_init_expression
(
Gogo
*
gogo
,
Named_object
*
function
)
Variable
::
lower_init_expression
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
)
{
{
if
(
this
->
init_
!=
NULL
&&
!
this
->
init_is_lowered_
)
if
(
this
->
init_
!=
NULL
&&
!
this
->
init_is_lowered_
)
{
{
...
@@ -3381,7 +3456,14 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
...
@@ -3381,7 +3456,14 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
}
}
this
->
seen_
=
true
;
this
->
seen_
=
true
;
gogo
->
lower_expression
(
function
,
&
this
->
init_
);
Statement_inserter
global_inserter
;
if
(
this
->
is_global_
)
{
global_inserter
=
Statement_inserter
(
gogo
,
this
);
inserter
=
&
global_inserter
;
}
gogo
->
lower_expression
(
function
,
inserter
,
&
this
->
init_
);
this
->
seen_
=
false
;
this
->
seen_
=
false
;
...
@@ -4508,70 +4590,60 @@ Bindings::traverse(Traverse* traverse, bool is_global)
...
@@ -4508,70 +4590,60 @@ Bindings::traverse(Traverse* traverse, bool is_global)
// We don't use an iterator because we permit the traversal to add
// We don't use an iterator because we permit the traversal to add
// new global objects.
// new global objects.
const
unsigned
int
e_or_t
=
(
Traverse
::
traverse_expressions
|
Traverse
::
traverse_types
);
const
unsigned
int
e_or_t_or_s
=
(
e_or_t
|
Traverse
::
traverse_statements
);
for
(
size_t
i
=
0
;
i
<
this
->
named_objects_
.
size
();
++
i
)
for
(
size_t
i
=
0
;
i
<
this
->
named_objects_
.
size
();
++
i
)
{
{
Named_object
*
p
=
this
->
named_objects_
[
i
];
Named_object
*
p
=
this
->
named_objects_
[
i
];
int
t
=
TRAVERSE_CONTINUE
;
switch
(
p
->
classification
())
switch
(
p
->
classification
())
{
{
case
Named_object
:
:
NAMED_OBJECT_CONST
:
case
Named_object
:
:
NAMED_OBJECT_CONST
:
if
((
traverse_mask
&
Traverse
::
traverse_constants
)
!=
0
)
if
((
traverse_mask
&
Traverse
::
traverse_constants
)
!=
0
)
t
=
traverse
->
constant
(
p
,
is_global
);
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t
)
!=
0
)
{
{
if
(
traverse
->
constant
(
p
,
is_global
)
==
TRAVERSE_EXIT
)
Type
*
tc
=
p
->
const_value
()
->
type
();
return
TRAVERSE_EXIT
;
if
(
tc
!=
NULL
}
&&
Type
::
traverse
(
tc
,
traverse
)
==
TRAVERSE_EXIT
)
if
((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
{
Type
*
t
=
p
->
const_value
()
->
type
();
if
(
t
!=
NULL
&&
Type
::
traverse
(
t
,
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
if
(
p
->
const_value
()
->
traverse_expression
(
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
t
=
p
->
const_value
()
->
traverse_expression
(
traverse
);
}
}
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_RESULT_VAR
:
case
Named_object
:
:
NAMED_OBJECT_RESULT_VAR
:
if
((
traverse_mask
&
Traverse
::
traverse_variables
)
!=
0
)
if
((
traverse_mask
&
Traverse
::
traverse_variables
)
!=
0
)
t
=
traverse
->
variable
(
p
);
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t
)
!=
0
)
{
{
if
(
traverse
->
variable
(
p
)
==
TRAVERSE_EXIT
)
if
(
p
->
is_result_variable
()
return
TRAVERSE_EXIT
;
||
p
->
var_value
()
->
has_type
())
}
if
(((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
&&
(
p
->
is_result_variable
()
||
p
->
var_value
()
->
has_type
()))
{
{
Type
*
t
=
(
p
->
is_variable
()
Type
*
tv
=
(
p
->
is_variable
()
?
p
->
var_value
()
->
type
()
?
p
->
var_value
()
->
type
()
:
p
->
result_var_value
()
->
type
());
:
p
->
result_var_value
()
->
type
());
if
(
t
!=
NULL
if
(
tv
!=
NULL
&&
Type
::
traverse
(
t
,
traverse
)
==
TRAVERSE_EXIT
)
&&
Type
::
traverse
(
tv
,
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
return
TRAVERSE_EXIT
;
}
}
if
(
p
->
is_variable
()
&&
((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
))
{
if
(
p
->
var_value
()
->
traverse_expression
(
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
}
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
e_or_t_or_s
)
!=
0
&&
p
->
is_variable
())
t
=
p
->
var_value
()
->
traverse_expression
(
traverse
,
traverse_mask
);
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_FUNC
:
case
Named_object
:
:
NAMED_OBJECT_FUNC
:
if
((
traverse_mask
&
Traverse
::
traverse_functions
)
!=
0
)
if
((
traverse_mask
&
Traverse
::
traverse_functions
)
!=
0
)
{
t
=
traverse
->
function
(
p
);
int
t
=
traverse
->
function
(
p
);
if
(
t
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
else
if
(
t
==
TRAVERSE_SKIP_COMPONENTS
)
break
;
}
if
((
traverse_mask
if
(
t
==
TRAVERSE_CONTINUE
&&
(
traverse_mask
&
(
Traverse
::
traverse_variables
&
(
Traverse
::
traverse_variables
|
Traverse
::
traverse_constants
|
Traverse
::
traverse_constants
|
Traverse
::
traverse_functions
|
Traverse
::
traverse_functions
...
@@ -4591,12 +4663,8 @@ Bindings::traverse(Traverse* traverse, bool is_global)
...
@@ -4591,12 +4663,8 @@ Bindings::traverse(Traverse* traverse, bool is_global)
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_TYPE
:
case
Named_object
:
:
NAMED_OBJECT_TYPE
:
if
((
traverse_mask
&
Traverse
::
traverse_types
)
!=
0
if
((
traverse_mask
&
e_or_t
)
!=
0
)
||
(
traverse_mask
&
Traverse
::
traverse_expressions
)
!=
0
)
t
=
Type
::
traverse
(
p
->
type_value
(),
traverse
);
{
if
(
Type
::
traverse
(
p
->
type_value
(),
traverse
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
break
;
break
;
case
Named_object
:
:
NAMED_OBJECT_TYPE_DECLARATION
:
case
Named_object
:
:
NAMED_OBJECT_TYPE_DECLARATION
:
...
@@ -4608,6 +4676,9 @@ Bindings::traverse(Traverse* traverse, bool is_global)
...
@@ -4608,6 +4676,9 @@ Bindings::traverse(Traverse* traverse, bool is_global)
default
:
default
:
go_unreachable
();
go_unreachable
();
}
}
if
(
t
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
}
return
TRAVERSE_CONTINUE
;
return
TRAVERSE_CONTINUE
;
...
@@ -4805,3 +4876,20 @@ Traverse::type(Type*)
...
@@ -4805,3 +4876,20 @@ Traverse::type(Type*)
{
{
go_unreachable
();
go_unreachable
();
}
}
// Class Statement_inserter.
void
Statement_inserter
::
insert
(
Statement
*
s
)
{
if
(
this
->
block_
!=
NULL
)
{
go_assert
(
this
->
pindex_
!=
NULL
);
this
->
block_
->
insert_statement_before
(
*
this
->
pindex_
,
s
);
++*
this
->
pindex_
;
}
else
if
(
this
->
var_
!=
NULL
)
this
->
var_
->
add_preinit_statement
(
this
->
gogo_
,
s
);
else
go_unreachable
();
}
gcc/go/gofrontend/gogo.h
View file @
8586635c
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
#define GO_GOGO_H
#define GO_GOGO_H
class
Traverse
;
class
Traverse
;
class
Statement_inserter
;
class
Type
;
class
Type
;
class
Type_hash_identical
;
class
Type_hash_identical
;
class
Type_equal
;
class
Type_equal
;
...
@@ -366,7 +367,7 @@ class Gogo
...
@@ -366,7 +367,7 @@ class Gogo
// Lower an expression.
// Lower an expression.
void
void
lower_expression
(
Named_object
*
function
,
Expression
**
);
lower_expression
(
Named_object
*
function
,
Statement_inserter
*
,
Expression
**
);
// Lower a constant.
// Lower a constant.
void
void
...
@@ -1157,7 +1158,7 @@ class Variable
...
@@ -1157,7 +1158,7 @@ class Variable
// Lower the initialization expression after parsing is complete.
// Lower the initialization expression after parsing is complete.
void
void
lower_init_expression
(
Gogo
*
,
Named_object
*
);
lower_init_expression
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
);
// A special case: the init value is used only to determine the
// A special case: the init value is used only to determine the
// type. This is used if the variable is defined using := with the
// type. This is used if the variable is defined using := with the
...
@@ -1208,7 +1209,7 @@ class Variable
...
@@ -1208,7 +1209,7 @@ class Variable
// Traverse the initializer expression.
// Traverse the initializer expression.
int
int
traverse_expression
(
Traverse
*
);
traverse_expression
(
Traverse
*
,
unsigned
int
traverse_mask
);
// Determine the type of the variable if necessary.
// Determine the type of the variable if necessary.
void
void
...
@@ -2463,6 +2464,46 @@ class Traverse
...
@@ -2463,6 +2464,46 @@ class Traverse
Expressions_seen
*
expressions_seen_
;
Expressions_seen
*
expressions_seen_
;
};
};
// A class which makes it easier to insert new statements before the
// current statement during a traversal.
class
Statement_inserter
{
public
:
// Empty constructor.
Statement_inserter
()
:
block_
(
NULL
),
pindex_
(
NULL
),
gogo_
(
NULL
),
var_
(
NULL
)
{
}
// Constructor for a statement in a block.
Statement_inserter
(
Block
*
block
,
size_t
*
pindex
)
:
block_
(
block
),
pindex_
(
pindex
),
gogo_
(
NULL
),
var_
(
NULL
)
{
}
// Constructor for a global variable.
Statement_inserter
(
Gogo
*
gogo
,
Variable
*
var
)
:
block_
(
NULL
),
pindex_
(
NULL
),
gogo_
(
gogo
),
var_
(
var
)
{
go_assert
(
var
->
is_global
());
}
// We use the default copy constructor and assignment operator.
// Insert S before the statement we are traversing, or before the
// initialization expression of a global variable.
void
insert
(
Statement
*
s
);
private
:
// The block that the statement is in.
Block
*
block_
;
// The index of the statement that we are traversing.
size_t
*
pindex_
;
// The IR, needed when looking at an initializer expression for a
// global variable.
Gogo
*
gogo_
;
// The global variable, when looking at an initializer expression.
Variable
*
var_
;
};
// When translating the gogo IR into the backend data structure, this
// When translating the gogo IR into the backend data structure, this
// is the context we pass down the blocks and statements.
// is the context we pass down the blocks and statements.
...
...
gcc/go/gofrontend/statements.cc
View file @
8586635c
...
@@ -217,6 +217,16 @@ Variable_declaration_statement::do_traverse_assignments(
...
@@ -217,6 +217,16 @@ Variable_declaration_statement::do_traverse_assignments(
return
true
;
return
true
;
}
}
// Lower the variable's initialization expression.
Statement
*
Variable_declaration_statement
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Block
*
,
Statement_inserter
*
inserter
)
{
this
->
var_
->
var_value
()
->
lower_init_expression
(
gogo
,
function
,
inserter
);
return
this
;
}
// Convert a variable declaration to the backend representation.
// Convert a variable declaration to the backend representation.
Bstatement
*
Bstatement
*
...
@@ -244,7 +254,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
...
@@ -244,7 +254,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
Expression_list
*
params
=
new
Expression_list
();
Expression_list
*
params
=
new
Expression_list
();
params
->
push_back
(
Expression
::
make_type
(
var
->
type
(),
loc
));
params
->
push_back
(
Expression
::
make_type
(
var
->
type
(),
loc
));
Expression
*
call
=
Expression
::
make_call
(
func
,
params
,
false
,
loc
);
Expression
*
call
=
Expression
::
make_call
(
func
,
params
,
false
,
loc
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
call
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
call
);
Temporary_statement
*
temp
=
Statement
::
make_temporary
(
NULL
,
call
,
loc
);
Temporary_statement
*
temp
=
Statement
::
make_temporary
(
NULL
,
call
,
loc
);
Bstatement
*
btemp
=
temp
->
get_backend
(
context
);
Bstatement
*
btemp
=
temp
->
get_backend
(
context
);
...
@@ -386,7 +396,7 @@ Temporary_statement::do_get_backend(Translate_context* context)
...
@@ -386,7 +396,7 @@ Temporary_statement::do_get_backend(Translate_context* context)
{
{
Expression
*
init
=
Expression
::
make_cast
(
this
->
type_
,
this
->
init_
,
Expression
*
init
=
Expression
::
make_cast
(
this
->
type_
,
this
->
init_
,
this
->
location
());
this
->
location
());
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
init
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
init
);
binit
=
tree_to_expr
(
init
->
get_tree
(
context
));
binit
=
tree_to_expr
(
init
->
get_tree
(
context
));
}
}
...
@@ -598,7 +608,7 @@ class Assignment_operation_statement : public Statement
...
@@ -598,7 +608,7 @@ class Assignment_operation_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -628,7 +638,7 @@ Assignment_operation_statement::do_traverse(Traverse* traverse)
...
@@ -628,7 +638,7 @@ Assignment_operation_statement::do_traverse(Traverse* traverse)
Statement
*
Statement
*
Assignment_operation_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Assignment_operation_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -725,7 +735,7 @@ class Tuple_assignment_statement : public Statement
...
@@ -725,7 +735,7 @@ class Tuple_assignment_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -752,7 +762,8 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse)
...
@@ -752,7 +762,8 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse)
// up into a set of single assignments.
// up into a set of single assignments.
Statement
*
Statement
*
Tuple_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Tuple_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -852,7 +863,7 @@ public:
...
@@ -852,7 +863,7 @@ public:
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -882,7 +893,7 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
...
@@ -882,7 +893,7 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
Statement
*
Statement
*
Tuple_map_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Tuple_map_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -923,7 +934,8 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
...
@@ -923,7 +934,8 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
b
->
add_statement
(
present_temp
);
b
->
add_statement
(
present_temp
);
// present_temp = mapaccess2(MAP, &key_temp, &val_temp)
// present_temp = mapaccess2(MAP, &key_temp, &val_temp)
Expression
*
ref
=
Expression
::
make_temporary_reference
(
key_temp
,
loc
);
Temporary_reference_expression
*
ref
=
Expression
::
make_temporary_reference
(
key_temp
,
loc
);
Expression
*
a1
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
Expression
*
a1
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
val_temp
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
val_temp
,
loc
);
Expression
*
a2
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
Expression
*
a2
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
...
@@ -931,6 +943,7 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
...
@@ -931,6 +943,7 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
map_index
->
map
(),
a1
,
a2
);
map_index
->
map
(),
a1
,
a2
);
ref
=
Expression
::
make_temporary_reference
(
present_temp
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
present_temp
,
loc
);
ref
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
b
->
add_statement
(
s
);
b
->
add_statement
(
s
);
...
@@ -979,7 +992,7 @@ class Map_assignment_statement : public Statement
...
@@ -979,7 +992,7 @@ class Map_assignment_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1008,7 +1021,8 @@ Map_assignment_statement::do_traverse(Traverse* traverse)
...
@@ -1008,7 +1021,8 @@ Map_assignment_statement::do_traverse(Traverse* traverse)
// Lower a map assignment to a function call.
// Lower a map assignment to a function call.
Statement
*
Statement
*
Map_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Map_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -1093,7 +1107,7 @@ class Tuple_receive_assignment_statement : public Statement
...
@@ -1093,7 +1107,7 @@ class Tuple_receive_assignment_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1125,7 +1139,8 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
...
@@ -1125,7 +1139,8 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
Statement
*
Statement
*
Tuple_receive_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Tuple_receive_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -1160,13 +1175,15 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
...
@@ -1160,13 +1175,15 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
b
->
add_statement
(
closed_temp
);
b
->
add_statement
(
closed_temp
);
// closed_temp = chanrecv[23](channel, &val_temp)
// closed_temp = chanrecv[23](channel, &val_temp)
Expression
*
ref
=
Expression
::
make_temporary_reference
(
val_temp
,
loc
);
Temporary_reference_expression
*
ref
=
Expression
::
make_temporary_reference
(
val_temp
,
loc
);
Expression
*
p2
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
Expression
*
p2
=
Expression
::
make_unary
(
OPERATOR_AND
,
ref
,
loc
);
Expression
*
call
=
Runtime
::
make_call
((
this
->
for_select_
Expression
*
call
=
Runtime
::
make_call
((
this
->
for_select_
?
Runtime
::
CHANRECV3
?
Runtime
::
CHANRECV3
:
Runtime
::
CHANRECV2
),
:
Runtime
::
CHANRECV2
),
loc
,
2
,
this
->
channel_
,
p2
);
loc
,
2
,
this
->
channel_
,
p2
);
ref
=
Expression
::
make_temporary_reference
(
closed_temp
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
closed_temp
,
loc
);
ref
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
b
->
add_statement
(
s
);
b
->
add_statement
(
s
);
...
@@ -1217,7 +1234,7 @@ class Tuple_type_guard_assignment_statement : public Statement
...
@@ -1217,7 +1234,7 @@ class Tuple_type_guard_assignment_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1256,7 +1273,8 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
...
@@ -1256,7 +1273,8 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
Statement
*
Statement
*
Tuple_type_guard_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Tuple_type_guard_assignment_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -1378,6 +1396,10 @@ class Expression_statement : public Statement
...
@@ -1378,6 +1396,10 @@ class Expression_statement : public Statement
expr_
(
expr
)
expr_
(
expr
)
{
}
{
}
Expression
*
expr
()
{
return
this
->
expr_
;
}
protected
:
protected
:
int
int
do_traverse
(
Traverse
*
traverse
)
do_traverse
(
Traverse
*
traverse
)
...
@@ -1513,7 +1535,7 @@ class Inc_dec_statement : public Statement
...
@@ -1513,7 +1535,7 @@ class Inc_dec_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1529,7 +1551,7 @@ class Inc_dec_statement : public Statement
...
@@ -1529,7 +1551,7 @@ class Inc_dec_statement : public Statement
// Lower to += or -=.
// Lower to += or -=.
Statement
*
Statement
*
Inc_dec_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
)
Inc_dec_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -2017,6 +2039,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
...
@@ -2017,6 +2039,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
Named_object
*
function
=
gogo
->
start_function
(
thunk_name
,
thunk_type
,
true
,
Named_object
*
function
=
gogo
->
start_function
(
thunk_name
,
thunk_type
,
true
,
location
);
location
);
gogo
->
start_block
(
location
);
// For a defer statement, start with a call to
// For a defer statement, start with a call to
// __go_set_defer_retaddr. */
// __go_set_defer_retaddr. */
Label
*
retaddr_label
=
NULL
;
Label
*
retaddr_label
=
NULL
;
...
@@ -2122,26 +2146,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
...
@@ -2122,26 +2146,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
call_params
=
NULL
;
call_params
=
NULL
;
}
}
Expression
*
call
=
Expression
::
make_call
(
func_to_call
,
call_params
,
false
,
Call_expression
*
call
=
Expression
::
make_call
(
func_to_call
,
call_params
,
location
);
false
,
location
);
// We need to lower in case this is a builtin function.
call
=
call
->
lower
(
gogo
,
function
,
-
1
);
Call_expression
*
call_ce
=
call
->
call_expression
();
if
(
call_ce
!=
NULL
&&
may_call_recover
)
call_ce
->
set_is_deferred
();
Statement
*
call_statement
=
Statement
::
make_statement
(
call
);
Statement
*
call_statement
=
Statement
::
make_statement
(
call
);
// We already ran the determine_types pass, so we need to run it
// just for this statement now.
call_statement
->
determine_types
();
// Sanity check.
call
->
check_types
(
gogo
);
if
(
call_ce
!=
NULL
&&
recover_arg
!=
NULL
)
call_ce
->
set_recover_arg
(
recover_arg
);
gogo
->
add_statement
(
call_statement
);
gogo
->
add_statement
(
call_statement
);
// If this is a defer statement, the label comes immediately after
// If this is a defer statement, the label comes immediately after
...
@@ -2155,6 +2163,31 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
...
@@ -2155,6 +2163,31 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
gogo
->
add_statement
(
Statement
::
make_return_statement
(
vals
,
location
));
gogo
->
add_statement
(
Statement
::
make_return_statement
(
vals
,
location
));
}
}
Block
*
b
=
gogo
->
finish_block
(
location
);
gogo
->
add_block
(
b
,
location
);
gogo
->
lower_block
(
function
,
b
);
// We already ran the determine_types pass, so we need to run it
// just for the call statement now. The other types are known.
call_statement
->
determine_types
();
if
(
may_call_recover
||
recover_arg
!=
NULL
)
{
// Dig up the call expression, which may have been changed
// during lowering.
go_assert
(
call_statement
->
classification
()
==
STATEMENT_EXPRESSION
);
Expression_statement
*
es
=
static_cast
<
Expression_statement
*>
(
call_statement
);
Call_expression
*
ce
=
es
->
expr
()
->
call_expression
();
go_assert
(
ce
!=
NULL
);
if
(
may_call_recover
)
ce
->
set_is_deferred
();
if
(
recover_arg
!=
NULL
)
ce
->
set_recover_arg
(
recover_arg
);
}
// That is all the thunk has to do.
// That is all the thunk has to do.
gogo
->
finish_function
(
location
);
gogo
->
finish_function
(
location
);
}
}
...
@@ -2265,7 +2298,8 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
...
@@ -2265,7 +2298,8 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
// panic/recover work correctly.
// panic/recover work correctly.
Statement
*
Statement
*
Return_statement
::
do_lower
(
Gogo
*
,
Named_object
*
function
,
Block
*
enclosing
)
Return_statement
::
do_lower
(
Gogo
*
,
Named_object
*
function
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
if
(
this
->
is_lowered_
)
if
(
this
->
is_lowered_
)
return
this
;
return
this
;
...
@@ -3305,7 +3339,8 @@ Switch_statement::do_traverse(Traverse* traverse)
...
@@ -3305,7 +3339,8 @@ Switch_statement::do_traverse(Traverse* traverse)
// of if statements.
// of if statements.
Statement
*
Statement
*
Switch_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Switch_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -3578,7 +3613,8 @@ Type_switch_statement::do_traverse(Traverse* traverse)
...
@@ -3578,7 +3613,8 @@ Type_switch_statement::do_traverse(Traverse* traverse)
// equality testing.
// equality testing.
Statement
*
Statement
*
Type_switch_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
Type_switch_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
const
source_location
loc
=
this
->
location
();
const
source_location
loc
=
this
->
location
();
...
@@ -3629,8 +3665,9 @@ Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
...
@@ -3629,8 +3665,9 @@ Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
?
Runtime
::
EFACETYPE
?
Runtime
::
EFACETYPE
:
Runtime
::
IFACETYPE
),
:
Runtime
::
IFACETYPE
),
loc
,
1
,
ref
);
loc
,
1
,
ref
);
Expression
*
lhs
=
Expression
::
make_temporary_reference
(
descriptor_temp
,
Temporary_reference_expression
*
lhs
=
loc
);
Expression
::
make_temporary_reference
(
descriptor_temp
,
loc
);
lhs
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_assignment
(
lhs
,
call
,
loc
);
Statement
*
s
=
Statement
::
make_assignment
(
lhs
,
call
,
loc
);
b
->
add_statement
(
s
);
b
->
add_statement
(
s
);
}
}
...
@@ -3815,7 +3852,7 @@ Send_statement::do_get_backend(Translate_context* context)
...
@@ -3815,7 +3852,7 @@ Send_statement::do_get_backend(Translate_context* context)
call
=
Runtime
::
make_call
(
code
,
loc
,
3
,
this
->
channel_
,
val
,
call
=
Runtime
::
make_call
(
code
,
loc
,
3
,
this
->
channel_
,
val
,
Expression
::
make_boolean
(
this
->
for_select_
,
loc
));
Expression
::
make_boolean
(
this
->
for_select_
,
loc
));
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
call
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
call
);
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
Bstatement
*
s
=
context
->
backend
()
->
expression_statement
(
bcall
);
Bstatement
*
s
=
context
->
backend
()
->
expression_statement
(
bcall
);
...
@@ -4154,7 +4191,7 @@ Select_clauses::get_backend(Translate_context* context,
...
@@ -4154,7 +4191,7 @@ Select_clauses::get_backend(Translate_context* context,
Expression
*
nil2
=
nil1
->
copy
();
Expression
*
nil2
=
nil1
->
copy
();
Expression
*
call
=
Runtime
::
make_call
(
Runtime
::
SELECT
,
location
,
4
,
Expression
*
call
=
Runtime
::
make_call
(
Runtime
::
SELECT
,
location
,
4
,
zero
,
default_arg
,
nil1
,
nil2
);
zero
,
default_arg
,
nil1
,
nil2
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
call
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
call
);
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
s
=
context
->
backend
()
->
expression_statement
(
bcall
);
s
=
context
->
backend
()
->
expression_statement
(
bcall
);
}
}
...
@@ -4175,7 +4212,7 @@ Select_clauses::get_backend(Translate_context* context,
...
@@ -4175,7 +4212,7 @@ Select_clauses::get_backend(Translate_context* context,
Expression
*
chans
=
Expression
::
make_composite_literal
(
chan_array_type
,
0
,
Expression
*
chans
=
Expression
::
make_composite_literal
(
chan_array_type
,
0
,
false
,
chan_init
,
false
,
chan_init
,
location
);
location
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
chans
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
chans
);
Temporary_statement
*
chan_temp
=
Statement
::
make_temporary
(
chan_array_type
,
Temporary_statement
*
chan_temp
=
Statement
::
make_temporary
(
chan_array_type
,
chans
,
chans
,
location
);
location
);
...
@@ -4187,7 +4224,7 @@ Select_clauses::get_backend(Translate_context* context,
...
@@ -4187,7 +4224,7 @@ Select_clauses::get_backend(Translate_context* context,
0
,
false
,
0
,
false
,
is_send_init
,
is_send_init
,
location
);
location
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
is_sends
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
is_sends
);
Temporary_statement
*
is_send_temp
=
Temporary_statement
*
is_send_temp
=
Statement
::
make_temporary
(
is_send_array_type
,
is_sends
,
location
);
Statement
::
make_temporary
(
is_send_array_type
,
is_sends
,
location
);
statements
.
push_back
(
is_send_temp
->
get_backend
(
context
));
statements
.
push_back
(
is_send_temp
->
get_backend
(
context
));
...
@@ -4213,7 +4250,7 @@ Select_clauses::get_backend(Translate_context* context,
...
@@ -4213,7 +4250,7 @@ Select_clauses::get_backend(Translate_context* context,
Expression
*
call
=
Runtime
::
make_call
(
Runtime
::
SELECT
,
location
,
4
,
Expression
*
call
=
Runtime
::
make_call
(
Runtime
::
SELECT
,
location
,
4
,
ecount
->
copy
(),
default_arg
,
ecount
->
copy
(),
default_arg
,
chan_arg
,
is_send_arg
);
chan_arg
,
is_send_arg
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
&
call
);
context
->
gogo
()
->
lower_expression
(
context
->
function
(),
NULL
,
&
call
);
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
Bexpression
*
bcall
=
tree_to_expr
(
call
->
get_tree
(
context
));
std
::
vector
<
std
::
vector
<
Bexpression
*>
>
cases
;
std
::
vector
<
std
::
vector
<
Bexpression
*>
>
cases
;
...
@@ -4309,7 +4346,7 @@ Select_statement::break_label()
...
@@ -4309,7 +4346,7 @@ Select_statement::break_label()
Statement
*
Statement
*
Select_statement
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Select_statement
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Block
*
enclosing
)
Block
*
enclosing
,
Statement_inserter
*
)
{
{
if
(
this
->
is_lowered_
)
if
(
this
->
is_lowered_
)
return
this
;
return
this
;
...
@@ -4366,7 +4403,8 @@ For_statement::do_traverse(Traverse* traverse)
...
@@ -4366,7 +4403,8 @@ For_statement::do_traverse(Traverse* traverse)
// complex statements make it easier to handle garbage collection.
// complex statements make it easier to handle garbage collection.
Statement
*
Statement
*
For_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
)
For_statement
::
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
Statement
*
s
;
Statement
*
s
;
source_location
loc
=
this
->
location
();
source_location
loc
=
this
->
location
();
...
@@ -4497,7 +4535,8 @@ For_range_statement::do_traverse(Traverse* traverse)
...
@@ -4497,7 +4535,8 @@ For_range_statement::do_traverse(Traverse* traverse)
// statements.
// statements.
Statement
*
Statement
*
For_range_statement
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
Block
*
enclosing
)
For_range_statement
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
,
Block
*
enclosing
,
Statement_inserter
*
)
{
{
Type
*
range_type
=
this
->
range_
->
type
();
Type
*
range_type
=
this
->
range_
->
type
();
if
(
range_type
->
points_to
()
!=
NULL
if
(
range_type
->
points_to
()
!=
NULL
...
@@ -4711,8 +4750,10 @@ For_range_statement::lower_range_array(Gogo* gogo,
...
@@ -4711,8 +4750,10 @@ For_range_statement::lower_range_array(Gogo* gogo,
Expression
*
zexpr
=
Expression
::
make_integer
(
&
zval
,
NULL
,
loc
);
Expression
*
zexpr
=
Expression
::
make_integer
(
&
zval
,
NULL
,
loc
);
mpz_clear
(
zval
);
mpz_clear
(
zval
);
ref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Temporary_reference_expression
*
tref
=
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
zexpr
,
loc
);
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
tref
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_assignment
(
tref
,
zexpr
,
loc
);
init
->
add_statement
(
s
);
init
->
add_statement
(
s
);
*
pinit
=
init
;
*
pinit
=
init
;
...
@@ -4738,8 +4779,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
...
@@ -4738,8 +4779,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
Expression
*
ref2
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Expression
*
ref2
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Expression
*
index
=
Expression
::
make_index
(
ref
,
ref2
,
NULL
,
loc
);
Expression
*
index
=
Expression
::
make_index
(
ref
,
ref2
,
NULL
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
value_temp
,
loc
);
tref
=
Expression
::
make_temporary_reference
(
value_temp
,
loc
);
s
=
Statement
::
make_assignment
(
ref
,
index
,
loc
);
tref
->
set_is_lvalue
();
s
=
Statement
::
make_assignment
(
tref
,
index
,
loc
);
iter_init
->
add_statement
(
s
);
iter_init
->
add_statement
(
s
);
}
}
...
@@ -4749,8 +4791,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
...
@@ -4749,8 +4791,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
// index_temp++
// index_temp++
Block
*
post
=
new
Block
(
enclosing
,
loc
);
Block
*
post
=
new
Block
(
enclosing
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
tref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
s
=
Statement
::
make_inc_statement
(
ref
);
tref
->
set_is_lvalue
();
s
=
Statement
::
make_inc_statement
(
tref
);
post
->
add_statement
(
s
);
post
->
add_statement
(
s
);
*
ppost
=
post
;
*
ppost
=
post
;
}
}
...
@@ -4798,7 +4841,9 @@ For_range_statement::lower_range_string(Gogo*,
...
@@ -4798,7 +4841,9 @@ For_range_statement::lower_range_string(Gogo*,
mpz_init_set_ui
(
zval
,
0UL
);
mpz_init_set_ui
(
zval
,
0UL
);
Expression
*
zexpr
=
Expression
::
make_integer
(
&
zval
,
NULL
,
loc
);
Expression
*
zexpr
=
Expression
::
make_integer
(
&
zval
,
NULL
,
loc
);
Expression
*
ref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Temporary_reference_expression
*
ref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
ref
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
zexpr
,
loc
);
Statement
*
s
=
Statement
::
make_assignment
(
ref
,
zexpr
,
loc
);
init
->
add_statement
(
s
);
init
->
add_statement
(
s
);
...
@@ -4829,14 +4874,20 @@ For_range_statement::lower_range_string(Gogo*,
...
@@ -4829,14 +4874,20 @@ For_range_statement::lower_range_string(Gogo*,
if
(
value_temp
==
NULL
)
if
(
value_temp
==
NULL
)
{
{
ref
=
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
);
ref
=
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
);
ref
->
set_is_lvalue
();
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
s
=
Statement
::
make_assignment
(
ref
,
call
,
loc
);
}
}
else
else
{
{
Expression_list
*
lhs
=
new
Expression_list
();
Expression_list
*
lhs
=
new
Expression_list
();
lhs
->
push_back
(
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
));
ref
=
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
);
lhs
->
push_back
(
Expression
::
make_temporary_reference
(
value_temp
,
loc
));
ref
->
set_is_lvalue
();
lhs
->
push_back
(
ref
);
ref
=
Expression
::
make_temporary_reference
(
value_temp
,
loc
);
ref
->
set_is_lvalue
();
lhs
->
push_back
(
ref
);
Expression_list
*
rhs
=
new
Expression_list
();
Expression_list
*
rhs
=
new
Expression_list
();
rhs
->
push_back
(
Expression
::
make_call_result
(
call
,
0
));
rhs
->
push_back
(
Expression
::
make_call_result
(
call
,
0
));
...
@@ -4865,7 +4916,9 @@ For_range_statement::lower_range_string(Gogo*,
...
@@ -4865,7 +4916,9 @@ For_range_statement::lower_range_string(Gogo*,
Block
*
post
=
new
Block
(
enclosing
,
loc
);
Block
*
post
=
new
Block
(
enclosing
,
loc
);
Expression
*
lhs
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Temporary_reference_expression
*
lhs
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
lhs
->
set_is_lvalue
();
Expression
*
rhs
=
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
);
Expression
*
rhs
=
Expression
::
make_temporary_reference
(
next_index_temp
,
loc
);
s
=
Statement
::
make_assignment
(
lhs
,
rhs
,
loc
);
s
=
Statement
::
make_assignment
(
lhs
,
rhs
,
loc
);
...
@@ -5024,8 +5077,12 @@ For_range_statement::lower_range_channel(Gogo*,
...
@@ -5024,8 +5077,12 @@ For_range_statement::lower_range_channel(Gogo*,
iter_init
->
add_statement
(
ok_temp
);
iter_init
->
add_statement
(
ok_temp
);
Expression
*
cref
=
this
->
make_range_ref
(
range_object
,
range_temp
,
loc
);
Expression
*
cref
=
this
->
make_range_ref
(
range_object
,
range_temp
,
loc
);
Expression
*
iref
=
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
Temporary_reference_expression
*
iref
=
Expression
*
oref
=
Expression
::
make_temporary_reference
(
ok_temp
,
loc
);
Expression
::
make_temporary_reference
(
index_temp
,
loc
);
iref
->
set_is_lvalue
();
Temporary_reference_expression
*
oref
=
Expression
::
make_temporary_reference
(
ok_temp
,
loc
);
oref
->
set_is_lvalue
();
Statement
*
s
=
Statement
::
make_tuple_receive_assignment
(
iref
,
oref
,
cref
,
Statement
*
s
=
Statement
::
make_tuple_receive_assignment
(
iref
,
oref
,
cref
,
false
,
loc
);
false
,
loc
);
iter_init
->
add_statement
(
s
);
iter_init
->
add_statement
(
s
);
...
...
gcc/go/gofrontend/statements.h
View file @
8586635c
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
class
Gogo
;
class
Gogo
;
class
Traverse
;
class
Traverse
;
class
Statement_inserter
;
class
Block
;
class
Block
;
class
Function
;
class
Function
;
class
Unnamed_label
;
class
Unnamed_label
;
...
@@ -290,9 +291,11 @@ class Statement
...
@@ -290,9 +291,11 @@ class Statement
// simplify statements for further processing. It returns the same
// simplify statements for further processing. It returns the same
// Statement or a new one. FUNCTION is the function containing this
// Statement or a new one. FUNCTION is the function containing this
// statement. BLOCK is the block containing this statement.
// statement. BLOCK is the block containing this statement.
// INSERTER can be used to insert new statements before this one.
Statement
*
Statement
*
lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Block
*
block
)
lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Block
*
block
,
{
return
this
->
do_lower
(
gogo
,
function
,
block
);
}
Statement_inserter
*
inserter
)
{
return
this
->
do_lower
(
gogo
,
function
,
block
,
inserter
);
}
// Set type information for unnamed constants.
// Set type information for unnamed constants.
void
void
...
@@ -385,7 +388,7 @@ class Statement
...
@@ -385,7 +388,7 @@ class Statement
// Implemented by the child class: lower this statement to a simpler
// Implemented by the child class: lower this statement to a simpler
// one.
// one.
virtual
Statement
*
virtual
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
)
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
)
{
return
this
;
}
{
return
this
;
}
// Implemented by child class: set type information for unnamed
// Implemented by child class: set type information for unnamed
...
@@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement
...
@@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement
bool
bool
do_traverse_assignments
(
Traverse_assignments
*
);
do_traverse_assignments
(
Traverse_assignments
*
);
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
);
do_get_backend
(
Translate_context
*
);
...
@@ -566,7 +572,7 @@ class Return_statement : public Statement
...
@@ -566,7 +572,7 @@ class Return_statement : public Statement
do_traverse_assignments
(
Traverse_assignments
*
);
do_traverse_assignments
(
Traverse_assignments
*
);
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
bool
bool
do_may_fall_through
()
const
do_may_fall_through
()
const
...
@@ -806,7 +812,7 @@ class Select_statement : public Statement
...
@@ -806,7 +812,7 @@ class Select_statement : public Statement
{
return
this
->
clauses_
->
traverse
(
traverse
);
}
{
return
this
->
clauses_
->
traverse
(
traverse
);
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
void
void
do_determine_types
()
do_determine_types
()
...
@@ -993,7 +999,7 @@ class For_statement : public Statement
...
@@ -993,7 +999,7 @@ class For_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1051,7 +1057,7 @@ class For_range_statement : public Statement
...
@@ -1051,7 +1057,7 @@ class For_range_statement : public Statement
{
go_unreachable
();
}
{
go_unreachable
();
}
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1280,7 +1286,7 @@ class Switch_statement : public Statement
...
@@ -1280,7 +1286,7 @@ class Switch_statement : public Statement
do_traverse
(
Traverse
*
);
do_traverse
(
Traverse
*
);
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
@@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement
...
@@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement
do_traverse
(
Traverse
*
);
do_traverse
(
Traverse
*
);
Statement
*
Statement
*
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
);
do_lower
(
Gogo
*
,
Named_object
*
,
Block
*
,
Statement_inserter
*
);
Bstatement
*
Bstatement
*
do_get_backend
(
Translate_context
*
)
do_get_backend
(
Translate_context
*
)
...
...
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