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
1bbf7edb
Commit
1bbf7edb
authored
Aug 29, 2011
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lower calls to bound method expressions.
From-SVN: r178264
parent
27311334
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
197 additions
and
220 deletions
+197
-220
gcc/go/gofrontend/expressions.cc
+181
-155
gcc/go/gofrontend/expressions.h
+6
-4
gcc/go/gofrontend/statements.cc
+10
-61
No files found.
gcc/go/gofrontend/expressions.cc
View file @
1bbf7edb
...
...
@@ -3845,7 +3845,7 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
go_assert
((
et
->
points_to
()
!=
NULL
&&
et
->
points_to
()
->
channel_type
()
!=
NULL
)
||
et
->
is_nil_type
());
else
if
(
t
->
is_unsafe_pointer_type
()
)
else
if
(
t
->
points_to
()
!=
NULL
)
go_assert
(
et
->
points_to
()
!=
NULL
||
et
->
is_nil_type
());
else
if
(
et
->
is_unsafe_pointer_type
())
go_assert
(
t
->
points_to
()
!=
NULL
);
...
...
@@ -3908,7 +3908,7 @@ class Unary_expression : public Expression
public
:
Unary_expression
(
Operator
op
,
Expression
*
expr
,
source_location
location
)
:
Expression
(
EXPRESSION_UNARY
,
location
),
op_
(
op
),
escapes_
(
true
),
expr_
(
expr
)
op_
(
op
),
escapes_
(
true
),
create_temp_
(
false
),
expr_
(
expr
)
{
}
// Return the operator.
...
...
@@ -3929,6 +3929,15 @@ class Unary_expression : public Expression
this
->
escapes_
=
false
;
}
// Record that this is an address expression which should create a
// temporary variable if necessary. This is used for method calls.
void
set_create_temp
()
{
go_assert
(
this
->
op_
==
OPERATOR_AND
);
this
->
create_temp_
=
true
;
}
// Apply unary opcode OP to UVAL, setting VAL. Return true if this
// could be done, false if not.
static
bool
...
...
@@ -4004,6 +4013,9 @@ class Unary_expression : public Expression
// Normally true. False if this is an address expression which does
// not escape the current function.
bool
escapes_
;
// True if this is an address expression which should create a
// temporary variable if necessary.
bool
create_temp_
;
// The operand.
Expression
*
expr_
;
};
...
...
@@ -4428,7 +4440,10 @@ Unary_expression::do_check_types(Gogo*)
case
OPERATOR_AND
:
if
(
!
this
->
expr_
->
is_addressable
())
this
->
report_error
(
_
(
"invalid operand for unary %<&%>"
));
{
if
(
!
this
->
create_temp_
)
this
->
report_error
(
_
(
"invalid operand for unary %<&%>"
));
}
else
this
->
expr_
->
address_taken
(
this
->
escapes_
);
break
;
...
...
@@ -4486,12 +4501,15 @@ Unary_expression::do_get_tree(Translate_context* context)
return
fold_build1_loc
(
loc
,
BIT_NOT_EXPR
,
TREE_TYPE
(
expr
),
expr
);
case
OPERATOR_AND
:
// We should not see a non-constant constructor here; cases
// where we would see one should have been moved onto the heap
// at parse time. Taking the address of a nonconstant
// constructor will not do what the programmer expects.
go_assert
(
TREE_CODE
(
expr
)
!=
CONSTRUCTOR
||
TREE_CONSTANT
(
expr
));
go_assert
(
TREE_CODE
(
expr
)
!=
ADDR_EXPR
);
if
(
!
this
->
create_temp_
)
{
// We should not see a non-constant constructor here; cases
// where we would see one should have been moved onto the
// heap at parse time. Taking the address of a nonconstant
// constructor will not do what the programmer expects.
go_assert
(
TREE_CODE
(
expr
)
!=
CONSTRUCTOR
||
TREE_CONSTANT
(
expr
));
go_assert
(
TREE_CODE
(
expr
)
!=
ADDR_EXPR
);
}
// Build a decl for a constant constructor.
if
(
TREE_CODE
(
expr
)
==
CONSTRUCTOR
&&
TREE_CONSTANT
(
expr
))
...
...
@@ -4510,6 +4528,22 @@ Unary_expression::do_get_tree(Translate_context* context)
expr
=
decl
;
}
if
(
this
->
create_temp_
&&
!
TREE_ADDRESSABLE
(
TREE_TYPE
(
expr
))
&&
!
DECL_P
(
expr
)
&&
TREE_CODE
(
expr
)
!=
INDIRECT_REF
&&
TREE_CODE
(
expr
)
!=
COMPONENT_REF
)
{
tree
tmp
=
create_tmp_var
(
TREE_TYPE
(
expr
),
get_name
(
expr
));
DECL_IGNORED_P
(
tmp
)
=
1
;
DECL_INITIAL
(
tmp
)
=
expr
;
TREE_ADDRESSABLE
(
tmp
)
=
1
;
return
build2_loc
(
loc
,
COMPOUND_EXPR
,
build_pointer_type
(
TREE_TYPE
(
expr
)),
build1_loc
(
loc
,
DECL_EXPR
,
void_type_node
,
tmp
),
build_fold_addr_expr_loc
(
loc
,
tmp
));
}
return
build_fold_addr_expr_loc
(
loc
,
expr
);
case
OPERATOR_MULT
:
...
...
@@ -7223,7 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
this
->
set_is_error
();
return
this
;
}
return
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
slice_type
,
2
);
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
slice_type
,
2
);
}
return
this
;
...
...
@@ -8805,12 +8839,14 @@ Expression*
Call_expression
::
do_lower
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
int
)
{
source_location
loc
=
this
->
location
();
// A type cast can look like a function call.
if
(
this
->
fn_
->
is_type_expression
()
&&
this
->
args_
!=
NULL
&&
this
->
args_
->
size
()
==
1
)
return
Expression
::
make_cast
(
this
->
fn_
->
type
(),
this
->
args_
->
front
(),
this
->
location
()
);
loc
);
// Recognize a call to a builtin function.
Func_expression
*
fne
=
this
->
fn_
->
func_expression
();
...
...
@@ -8818,7 +8854,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
&&
fne
->
named_object
()
->
is_function_declaration
()
&&
fne
->
named_object
()
->
func_declaration_value
()
->
type
()
->
is_builtin
())
return
new
Builtin_call_expression
(
gogo
,
this
->
fn_
,
this
->
args_
,
this
->
is_varargs_
,
this
->
location
()
);
this
->
is_varargs_
,
loc
);
// Handle an argument which is a call to a function which returns
// multiple results.
...
...
@@ -8862,8 +8898,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
++
p
)
{
Temporary_statement
*
temp
=
Statement
::
make_temporary
(
p
->
type
(),
NULL
,
p
->
location
());
NULL
,
loc
);
inserter
->
insert
(
temp
);
temps
->
push_back
(
temp
);
}
...
...
@@ -8879,8 +8914,58 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
const
Typed_identifier_list
*
parameters
=
fntype
->
parameters
();
go_assert
(
parameters
!=
NULL
&&
!
parameters
->
empty
());
Type
*
varargs_type
=
parameters
->
back
().
type
();
return
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
varargs_type
,
parameters
->
size
());
this
->
lower_varargs
(
gogo
,
function
,
inserter
,
varargs_type
,
parameters
->
size
());
}
// If this is call to a method, call the method directly passing the
// object as the first parameter.
Bound_method_expression
*
bme
=
this
->
fn_
->
bound_method_expression
();
if
(
bme
!=
NULL
)
{
Named_object
*
method
=
bme
->
method
();
Expression
*
first_arg
=
bme
->
first_argument
();
// We always pass a pointer when calling a method.
if
(
first_arg
->
type
()
->
points_to
()
==
NULL
&&
!
first_arg
->
type
()
->
is_error
())
{
first_arg
=
Expression
::
make_unary
(
OPERATOR_AND
,
first_arg
,
loc
);
// We may need to create a temporary variable so that we can
// take the address. We can't do that here because it will
// mess up the order of evaluation.
Unary_expression
*
ue
=
static_cast
<
Unary_expression
*>
(
first_arg
);
ue
->
set_create_temp
();
}
// If we are calling a method which was inherited from an
// embedded struct, and the method did not get a stub, then the
// first type may be wrong.
Type
*
fatype
=
bme
->
first_argument_type
();
if
(
fatype
!=
NULL
)
{
if
(
fatype
->
points_to
()
==
NULL
)
fatype
=
Type
::
make_pointer_type
(
fatype
);
first_arg
=
Expression
::
make_unsafe_cast
(
fatype
,
first_arg
,
loc
);
}
Expression_list
*
new_args
=
new
Expression_list
();
new_args
->
push_back
(
first_arg
);
if
(
this
->
args_
!=
NULL
)
{
for
(
Expression_list
::
const_iterator
p
=
this
->
args_
->
begin
();
p
!=
this
->
args_
->
end
();
++
p
)
new_args
->
push_back
(
*
p
);
}
// We have to change in place because this structure may be
// referenced by Call_result_expressions. We can't delete the
// old arguments, because we may be traversing them up in some
// caller. FIXME.
this
->
args_
=
new_args
;
this
->
fn_
=
Expression
::
make_func_reference
(
method
,
NULL
,
bme
->
location
());
}
return
this
;
...
...
@@ -8893,13 +8978,13 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
// calling; the last of these parameters will be the varargs
// parameter.
Expression
*
void
Call_expression
::
lower_varargs
(
Gogo
*
gogo
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
Type
*
varargs_type
,
size_t
param_count
)
{
if
(
this
->
varargs_are_lowered_
)
return
this
;
return
;
source_location
loc
=
this
->
location
();
...
...
@@ -8910,7 +8995,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
if
(
arg_count
<
param_count
-
1
)
{
// Not enough arguments; will be caught in check_types.
return
this
;
return
;
}
Expression_list
*
old_args
=
this
->
args_
;
...
...
@@ -8942,7 +9027,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
else
if
(
this
->
is_varargs_
)
{
this
->
report_error
(
_
(
"too many arguments"
));
return
this
;
return
;
}
else
{
...
...
@@ -8960,6 +9045,7 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
}
Expression
*
val
=
Expression
::
make_slice_composite_literal
(
varargs_type
,
vals
,
loc
);
gogo
->
lower_expression
(
function
,
inserter
,
&
val
);
new_args
->
push_back
(
val
);
}
}
...
...
@@ -8973,12 +9059,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
// Builtin_call_expression which refer to them. FIXME.
this
->
args_
=
new_args
;
this
->
varargs_are_lowered_
=
true
;
// Lower all the new subexpressions.
Expression
*
ret
=
this
;
gogo
->
lower_expression
(
function
,
inserter
,
&
ret
);
go_assert
(
ret
==
this
);
return
ret
;
}
// Get the function type. This can return NULL in error cases.
...
...
@@ -9102,10 +9182,28 @@ Call_expression::do_determine_type(const Type_context*)
Typed_identifier_list
::
const_iterator
pt
;
if
(
parameters
!=
NULL
)
pt
=
parameters
->
begin
();
bool
first
=
true
;
for
(
Expression_list
::
const_iterator
pa
=
this
->
args_
->
begin
();
pa
!=
this
->
args_
->
end
();
++
pa
)
{
if
(
first
)
{
first
=
false
;
// If this is a method, the first argument is the
// receiver.
if
(
fntype
!=
NULL
&&
fntype
->
is_method
())
{
Type
*
rtype
=
fntype
->
receiver
()
->
type
();
// The receiver is always passed as a pointer.
if
(
rtype
->
points_to
()
==
NULL
)
rtype
=
Type
::
make_pointer_type
(
rtype
);
Type_context
subcontext
(
rtype
,
false
);
(
*
pa
)
->
determine_type
(
&
subcontext
);
continue
;
}
}
if
(
parameters
!=
NULL
&&
pt
!=
parameters
->
end
())
{
Type_context
subcontext
(
pt
->
type
(),
false
);
...
...
@@ -9172,35 +9270,28 @@ Call_expression::do_check_types(Gogo*)
return
;
}
if
(
fntype
->
is_method
())
bool
is_method
=
fntype
->
is_method
();
if
(
is_method
)
{
// We don't support pointers to methods, so the function has to
// be a bound method expression.
Bound_method_expression
*
bme
=
this
->
fn_
->
bound_method_expression
();
if
(
bme
==
NULL
)
{
this
->
report_error
(
_
(
"method call without object"
));
retur
n
;
}
Type
*
first_arg_type
=
bme
->
first_argument
()
->
type
();
if
(
first_arg_type
->
points_to
()
==
NULL
)
go_assert
(
this
->
args_
!=
NULL
&&
!
this
->
args_
->
empty
());
Type
*
rtype
=
fntype
->
receiver
()
->
type
();
Expression
*
first_arg
=
this
->
args_
->
front
();
// The language permits copying hidden fields for a method
// receiver. We dereference the values since receivers are
// always passed as pointers.
std
::
string
reaso
n
;
if
(
!
Type
::
are_assignable_hidden_ok
(
rtype
->
deref
(),
first_arg
->
type
()
->
deref
(),
&
reason
)
)
{
// When passing a value, we need to check that we are
// permitted to copy it. The language permits copying
// hidden fields for a method receiver.
std
::
string
reason
;
if
(
!
Type
::
are_assignable_hidden_ok
(
fntype
->
receiver
()
->
type
(),
first_arg_type
,
&
reason
))
if
(
reason
.
empty
())
this
->
report_error
(
_
(
"incompatible type for receiver"
));
else
{
if
(
reason
.
empty
())
this
->
report_error
(
_
(
"incompatible type for receiver"
));
else
{
error_at
(
this
->
location
(),
"incompatible type for receiver (%s)"
,
reason
.
c_str
());
this
->
set_is_error
();
}
error_at
(
this
->
location
(),
"incompatible type for receiver (%s)"
,
reason
.
c_str
());
this
->
set_is_error
();
}
}
}
...
...
@@ -9215,25 +9306,30 @@ Call_expression::do_check_types(Gogo*)
this
->
report_error
(
_
(
"not enough arguments"
));
}
else
if
(
parameters
==
NULL
)
this
->
report_error
(
_
(
"too many arguments"
));
{
if
(
!
is_method
||
this
->
args_
->
size
()
>
1
)
this
->
report_error
(
_
(
"too many arguments"
));
}
else
{
int
i
=
0
;
Typed_identifier_list
::
const_iterator
pt
=
parameters
->
begin
();
for
(
Expression_list
::
const_iterator
pa
=
this
->
args_
->
begin
();
pa
!=
this
->
args_
->
end
();
++
pa
,
++
pt
,
++
i
)
{
if
(
pt
==
parameters
->
end
())
Expression_list
::
const_iterator
pa
=
this
->
args_
->
begin
();
if
(
is_method
)
++
pa
;
for
(
Typed_identifier_list
::
const_iterator
pt
=
parameters
->
begin
();
pt
!=
parameters
->
end
();
++
pt
,
++
pa
,
++
i
)
{
if
(
pa
==
this
->
args_
->
end
())
{
this
->
report_error
(
_
(
"
too many
arguments"
));
this
->
report_error
(
_
(
"
not enough
arguments"
));
return
;
}
this
->
check_argument_type
(
i
+
1
,
pt
->
type
(),
(
*
pa
)
->
type
(),
(
*
pa
)
->
location
(),
false
);
}
if
(
p
t
!=
parameters
->
end
())
this
->
report_error
(
_
(
"
not enough
arguments"
));
if
(
p
a
!=
this
->
args_
->
end
())
this
->
report_error
(
_
(
"
too many
arguments"
));
}
}
...
...
@@ -9247,83 +9343,6 @@ Call_expression::do_must_eval_in_order() const
return
this
->
result_count
()
>
0
;
}
// Get the function and the first argument to use when calling a bound
// method.
tree
Call_expression
::
bound_method_function
(
Translate_context
*
context
,
Bound_method_expression
*
bound_method
,
tree
*
first_arg_ptr
)
{
Gogo
*
gogo
=
context
->
gogo
();
source_location
loc
=
this
->
location
();
Expression
*
first_argument
=
bound_method
->
first_argument
();
tree
first_arg
=
first_argument
->
get_tree
(
context
);
if
(
first_arg
==
error_mark_node
)
return
error_mark_node
;
// We always pass a pointer to the first argument when calling a
// method.
if
(
first_argument
->
type
()
->
points_to
()
==
NULL
)
{
tree
pointer_to_arg_type
=
build_pointer_type
(
TREE_TYPE
(
first_arg
));
if
(
TREE_ADDRESSABLE
(
TREE_TYPE
(
first_arg
))
||
DECL_P
(
first_arg
)
||
TREE_CODE
(
first_arg
)
==
INDIRECT_REF
||
TREE_CODE
(
first_arg
)
==
COMPONENT_REF
)
{
first_arg
=
build_fold_addr_expr_loc
(
loc
,
first_arg
);
if
(
DECL_P
(
first_arg
))
TREE_ADDRESSABLE
(
first_arg
)
=
1
;
}
else
{
tree
tmp
=
create_tmp_var
(
TREE_TYPE
(
first_arg
),
get_name
(
first_arg
));
DECL_IGNORED_P
(
tmp
)
=
0
;
DECL_INITIAL
(
tmp
)
=
first_arg
;
first_arg
=
build2_loc
(
loc
,
COMPOUND_EXPR
,
pointer_to_arg_type
,
build1_loc
(
loc
,
DECL_EXPR
,
void_type_node
,
tmp
),
build_fold_addr_expr_loc
(
loc
,
tmp
));
TREE_ADDRESSABLE
(
tmp
)
=
1
;
}
if
(
first_arg
==
error_mark_node
)
return
error_mark_node
;
}
Type
*
fatype
=
bound_method
->
first_argument_type
();
if
(
fatype
!=
NULL
)
{
if
(
fatype
->
points_to
()
==
NULL
)
fatype
=
Type
::
make_pointer_type
(
fatype
);
Btype
*
bfatype
=
fatype
->
get_backend
(
gogo
);
first_arg
=
fold_convert_loc
(
loc
,
type_to_tree
(
bfatype
),
first_arg
);
if
(
first_arg
==
error_mark_node
||
TREE_TYPE
(
first_arg
)
==
error_mark_node
)
return
error_mark_node
;
}
*
first_arg_ptr
=
first_arg
;
Named_object
*
method
=
bound_method
->
method
();
tree
id
=
method
->
get_id
(
gogo
);
if
(
id
==
error_mark_node
)
return
error_mark_node
;
tree
fndecl
;
if
(
method
->
is_function
())
fndecl
=
method
->
func_value
()
->
get_or_make_decl
(
gogo
,
method
,
id
);
else
if
(
method
->
is_function_declaration
())
fndecl
=
method
->
func_declaration_value
()
->
get_or_make_decl
(
gogo
,
method
,
id
);
else
go_unreachable
();
return
build_fold_addr_expr_loc
(
loc
,
fndecl
);
}
// Get the function and the first argument to use when calling an
// interface method.
...
...
@@ -9363,35 +9382,46 @@ Call_expression::do_get_tree(Translate_context* context)
source_location
location
=
this
->
location
();
Func_expression
*
func
=
this
->
fn_
->
func_expression
();
Bound_method_expression
*
bound_method
=
this
->
fn_
->
bound_method_expression
();
Interface_field_reference_expression
*
interface_method
=
this
->
fn_
->
interface_field_reference_expression
();
const
bool
has_closure
=
func
!=
NULL
&&
func
->
closure
()
!=
NULL
;
const
bool
is_method
=
bound_method
!=
NULL
||
interface_method
!=
NULL
;
go_assert
(
!
fntype
->
is_method
()
||
is_method
);
const
bool
is_interface_method
=
interface_method
!=
NULL
;
int
nargs
;
tree
*
args
;
if
(
this
->
args_
==
NULL
||
this
->
args_
->
empty
())
{
nargs
=
is_method
?
1
:
0
;
nargs
=
is_
interface_
method
?
1
:
0
;
args
=
nargs
==
0
?
NULL
:
new
tree
[
nargs
];
}
else
if
(
fntype
->
parameters
()
==
NULL
||
fntype
->
parameters
()
->
empty
())
{
// Passing a receiver parameter.
go_assert
(
!
is_interface_method
&&
fntype
->
is_method
()
&&
this
->
args_
->
size
()
==
1
);
nargs
=
1
;
args
=
new
tree
[
nargs
];
args
[
0
]
=
this
->
args_
->
front
()
->
get_tree
(
context
);
}
else
{
const
Typed_identifier_list
*
params
=
fntype
->
parameters
();
go_assert
(
params
!=
NULL
);
nargs
=
this
->
args_
->
size
();
int
i
=
is_method
?
1
:
0
;
int
i
=
is_
interface_
method
?
1
:
0
;
nargs
+=
i
;
args
=
new
tree
[
nargs
];
Typed_identifier_list
::
const_iterator
pp
=
params
->
begin
();
Expression_list
::
const_iterator
pe
;
for
(
pe
=
this
->
args_
->
begin
();
pe
!=
this
->
args_
->
end
();
++
pe
,
++
pp
,
++
i
)
Expression_list
::
const_iterator
pe
=
this
->
args_
->
begin
();
if
(
!
is_interface_method
&&
fntype
->
is_method
())
{
args
[
i
]
=
(
*
pe
)
->
get_tree
(
context
);
++
pe
;
++
i
;
}
for
(;
pe
!=
this
->
args_
->
end
();
++
pe
,
++
pp
,
++
i
)
{
go_assert
(
pp
!=
params
->
end
());
tree
arg_val
=
(
*
pe
)
->
get_tree
(
context
);
...
...
@@ -9420,14 +9450,10 @@ Call_expression::do_get_tree(Translate_context* context)
tree
fn
;
if
(
has_closure
)
fn
=
func
->
get_tree_without_closure
(
gogo
);
else
if
(
!
is_method
)
else
if
(
!
is_
interface_
method
)
fn
=
this
->
fn_
->
get_tree
(
context
);
else
if
(
bound_method
!=
NULL
)
fn
=
this
->
bound_method_function
(
context
,
bound_method
,
&
args
[
0
]);
else
if
(
interface_method
!=
NULL
)
fn
=
this
->
interface_method_function
(
context
,
interface_method
,
&
args
[
0
]);
else
go_unreachable
(
);
fn
=
this
->
interface_method_function
(
context
,
interface_method
,
&
args
[
0
]
);
if
(
fn
==
error_mark_node
||
TREE_TYPE
(
fn
)
==
error_mark_node
)
{
...
...
gcc/go/gofrontend/expressions.h
View file @
1bbf7edb
...
...
@@ -1244,6 +1244,11 @@ class Call_expression : public Expression
is_varargs
()
const
{
return
this
->
is_varargs_
;
}
// Note that varargs have already been lowered.
void
set_varargs_are_lowered
()
{
this
->
varargs_are_lowered_
=
true
;
}
// Whether this call is being deferred.
bool
is_deferred
()
const
...
...
@@ -1307,7 +1312,7 @@ class Call_expression : public Expression
{
this
->
args_
=
args
;
}
// Let a builtin expression lower varargs.
Expression
*
void
lower_varargs
(
Gogo
*
,
Named_object
*
function
,
Statement_inserter
*
inserter
,
Type
*
varargs_type
,
size_t
param_count
);
...
...
@@ -1324,9 +1329,6 @@ class Call_expression : public Expression
check_argument_type
(
int
,
const
Type
*
,
const
Type
*
,
source_location
,
bool
);
tree
bound_method_function
(
Translate_context
*
,
Bound_method_expression
*
,
tree
*
);
tree
interface_method_function
(
Translate_context
*
,
Interface_field_reference_expression
*
,
tree
*
);
...
...
gcc/go/gofrontend/statements.cc
View file @
1bbf7edb
...
...
@@ -1858,8 +1858,7 @@ Thunk_statement::is_simple(Function_type* fntype) const
// If this calls something which is not a simple function, then we
// need a thunk.
Expression
*
fn
=
this
->
call_
->
call_expression
()
->
fn
();
if
(
fn
->
bound_method_expression
()
!=
NULL
||
fn
->
interface_field_reference_expression
()
!=
NULL
)
if
(
fn
->
interface_field_reference_expression
()
!=
NULL
)
return
false
;
return
true
;
...
...
@@ -1914,14 +1913,6 @@ Thunk_statement::do_check_types(Gogo*)
this
->
report_error
(
"expected call expression"
);
return
;
}
Function_type
*
fntype
=
ce
->
get_function_type
();
if
(
fntype
!=
NULL
&&
fntype
->
is_method
())
{
Expression
*
fn
=
ce
->
fn
();
if
(
fn
->
bound_method_expression
()
==
NULL
&&
fn
->
interface_field_reference_expression
()
==
NULL
)
this
->
report_error
(
_
(
"no object for method call"
));
}
}
// The Traverse class used to find and simplify thunk statements.
...
...
@@ -2005,8 +1996,7 @@ Thunk_statement::is_constant_function() const
Expression
*
fn
=
ce
->
fn
();
if
(
fn
->
func_expression
()
!=
NULL
)
return
fn
->
func_expression
()
->
closure
()
==
NULL
;
if
(
fn
->
bound_method_expression
()
!=
NULL
||
fn
->
interface_field_reference_expression
()
!=
NULL
)
if
(
fn
->
interface_field_reference_expression
()
!=
NULL
)
return
true
;
return
false
;
}
...
...
@@ -2048,7 +2038,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
return
false
;
Expression
*
fn
=
ce
->
fn
();
Bound_method_expression
*
bound_method
=
fn
->
bound_method_expression
();
Interface_field_reference_expression
*
interface_method
=
fn
->
interface_field_reference_expression
();
...
...
@@ -2071,30 +2060,6 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
if
(
interface_method
!=
NULL
)
vals
->
push_back
(
interface_method
->
expr
());
if
(
bound_method
!=
NULL
)
{
Expression
*
first_arg
=
bound_method
->
first_argument
();
// We always pass a pointer when calling a method.
if
(
first_arg
->
type
()
->
points_to
()
==
NULL
)
first_arg
=
Expression
::
make_unary
(
OPERATOR_AND
,
first_arg
,
location
);
// If we are calling a method which was inherited from an
// embedded struct, and the method did not get a stub, then the
// first type may be wrong.
Type
*
fatype
=
bound_method
->
first_argument_type
();
if
(
fatype
!=
NULL
)
{
if
(
fatype
->
points_to
()
==
NULL
)
fatype
=
Type
::
make_pointer_type
(
fatype
);
Type
*
unsafe
=
Type
::
make_pointer_type
(
Type
::
make_void_type
());
first_arg
=
Expression
::
make_cast
(
unsafe
,
first_arg
,
location
);
first_arg
=
Expression
::
make_cast
(
fatype
,
first_arg
,
location
);
}
vals
->
push_back
(
first_arg
);
}
if
(
ce
->
args
()
!=
NULL
)
{
for
(
Expression_list
::
const_iterator
p
=
ce
->
args
()
->
begin
();
...
...
@@ -2186,19 +2151,6 @@ Thunk_statement::build_struct(Function_type* fntype)
fields
->
push_back
(
Struct_field
(
tid
));
}
// If this is a method call, pass down the expression we are
// calling.
if
(
fn
->
bound_method_expression
()
!=
NULL
)
{
go_assert
(
fntype
->
is_method
());
Type
*
rtype
=
fntype
->
receiver
()
->
type
();
// We always pass the receiver as a pointer.
if
(
rtype
->
points_to
()
==
NULL
)
rtype
=
Type
::
make_pointer_type
(
rtype
);
Typed_identifier
tid
(
"receiver"
,
rtype
,
location
);
fields
->
push_back
(
Struct_field
(
tid
));
}
// The predeclared recover function has no argument. However, we
// add an argument when building recover thunks. Handle that here.
if
(
ce
->
is_recover_call
())
...
...
@@ -2317,7 +2269,6 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
thunk_parameter
=
Expression
::
make_unary
(
OPERATOR_MULT
,
thunk_parameter
,
location
);
Bound_method_expression
*
bound_method
=
ce
->
fn
()
->
bound_method_expression
();
Interface_field_reference_expression
*
interface_method
=
ce
->
fn
()
->
interface_field_reference_expression
();
...
...
@@ -2335,16 +2286,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
next_index
=
1
;
}
if
(
bound_method
!=
NULL
)
{
go_assert
(
next_index
==
0
);
Expression
*
r
=
Expression
::
make_field_reference
(
thunk_parameter
,
0
,
location
);
func_to_call
=
Expression
::
make_bound_method
(
r
,
bound_method
->
method
(),
location
);
next_index
=
1
;
}
else
if
(
interface_method
!=
NULL
)
if
(
interface_method
!=
NULL
)
{
// The main program passes the interface object.
go_assert
(
next_index
==
0
);
...
...
@@ -2389,6 +2331,13 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
Call_expression
*
call
=
Expression
::
make_call
(
func_to_call
,
call_params
,
false
,
location
);
// This call expression was already lowered before entering the
// thunk statement. Don't try to lower varargs again, as that will
// cause confusion for, e.g., method calls which already have a
// receiver parameter.
call
->
set_varargs_are_lowered
();
Statement
*
call_statement
=
Statement
::
make_statement
(
call
);
gogo
->
add_statement
(
call_statement
);
...
...
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