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
571d3f91
Commit
571d3f91
authored
11 years ago
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiler: Add support for method values.
From-SVN: r200379
parent
39953c79
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
174 additions
and
105 deletions
+174
-105
gcc/go/gofrontend/expressions.cc
+0
-0
gcc/go/gofrontend/expressions.h
+52
-13
gcc/go/gofrontend/gogo.cc
+34
-71
gcc/go/gofrontend/statements.cc
+22
-0
gcc/go/gofrontend/statements.h
+7
-0
gcc/go/gofrontend/types.cc
+53
-21
gcc/go/gofrontend/types.h
+6
-0
No files found.
gcc/go/gofrontend/expressions.cc
View file @
571d3f91
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/expressions.h
View file @
571d3f91
...
...
@@ -16,6 +16,7 @@ class Translate_context;
class
Traverse
;
class
Statement_inserter
;
class
Type
;
class
Method
;
struct
Type_context
;
class
Integer_type
;
class
Float_type
;
...
...
@@ -224,9 +225,11 @@ class Expression
make_call_result
(
Call_expression
*
,
unsigned
int
index
);
// Make an expression which is a method bound to its first
// parameter.
// parameter. METHOD is the method being called, FUNCTION is the
// function to call.
static
Bound_method_expression
*
make_bound_method
(
Expression
*
object
,
Named_object
*
method
,
Location
);
make_bound_method
(
Expression
*
object
,
const
Method
*
method
,
Named_object
*
function
,
Location
);
// Make an index or slice expression. This is a parser expression
// which represents LEFT[START:END]. END may be NULL, meaning an
...
...
@@ -1079,8 +1082,7 @@ class Set_and_use_temporary_expression : public Expression
do_type
();
void
do_determine_type
(
const
Type_context
*
)
{
}
do_determine_type
(
const
Type_context
*
);
Expression
*
do_copy
()
...
...
@@ -1852,10 +1854,10 @@ class Map_index_expression : public Expression
class
Bound_method_expression
:
public
Expression
{
public
:
Bound_method_expression
(
Expression
*
expr
,
Named_object
*
method
,
Location
location
)
Bound_method_expression
(
Expression
*
expr
,
const
Method
*
method
,
Named_object
*
function
,
Location
location
)
:
Expression
(
EXPRESSION_BOUND_METHOD
,
location
),
expr_
(
expr
),
expr_type_
(
NULL
),
method_
(
method
)
expr_
(
expr
),
expr_type_
(
NULL
),
method_
(
method
)
,
function_
(
function
)
{
}
// Return the object which is the first argument.
...
...
@@ -1870,20 +1872,33 @@ class Bound_method_expression : public Expression
first_argument_type
()
const
{
return
this
->
expr_type_
;
}
// Return the method
function
.
Named_object
*
method
()
// Return the method.
const
Method
*
method
()
const
{
return
this
->
method_
;
}
// Return the function to call.
Named_object
*
function
()
const
{
return
this
->
function_
;
}
// Set the implicit type of the expression.
void
set_first_argument_type
(
Type
*
type
)
{
this
->
expr_type_
=
type
;
}
// Create a thunk to call FUNCTION, for METHOD, when it is used as
// part of a method value.
static
Named_object
*
create_thunk
(
Gogo
*
,
const
Method
*
method
,
Named_object
*
function
);
protected
:
int
do_traverse
(
Traverse
*
);
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Type
*
do_type
();
...
...
@@ -1897,7 +1912,7 @@ class Bound_method_expression : public Expression
do_copy
()
{
return
new
Bound_method_expression
(
this
->
expr_
->
copy
(),
this
->
method_
,
this
->
location
());
this
->
function_
,
this
->
location
());
}
tree
...
...
@@ -1907,6 +1922,11 @@ class Bound_method_expression : public Expression
do_dump_expression
(
Ast_dump_context
*
)
const
;
private
:
// A mapping from method functions to the thunks we have created for
// them.
typedef
Unordered_map
(
Named_object
*
,
Named_object
*
)
Method_value_thunks
;
static
Method_value_thunks
method_value_thunks
;
// The object used to find the method. This is passed to the method
// as the first argument.
Expression
*
expr_
;
...
...
@@ -1914,8 +1934,12 @@ class Bound_method_expression : public Expression
// NULL in the normal case, non-NULL when using a method from an
// anonymous field which does not require a stub.
Type
*
expr_type_
;
// The method itself.
Named_object
*
method_
;
// The method.
const
Method
*
method_
;
// The function to call. This is not the same as
// method_->named_object() when the method has a stub. This will be
// the real function rather than the stub.
Named_object
*
function_
;
};
// A reference to a field in a struct.
...
...
@@ -2031,6 +2055,11 @@ class Interface_field_reference_expression : public Expression
name
()
const
{
return
this
->
name_
;
}
// Create a thunk to call the method NAME in TYPE when it is used as
// part of a method value.
static
Named_object
*
create_thunk
(
Gogo
*
,
Interface_type
*
type
,
const
std
::
string
&
name
);
// Return a tree for the pointer to the function to call, given a
// tree for the expression.
tree
...
...
@@ -2046,6 +2075,9 @@ class Interface_field_reference_expression : public Expression
int
do_traverse
(
Traverse
*
traverse
);
Expression
*
do_lower
(
Gogo
*
,
Named_object
*
,
Statement_inserter
*
,
int
);
Type
*
do_type
();
...
...
@@ -2070,6 +2102,13 @@ class Interface_field_reference_expression : public Expression
do_dump_expression
(
Ast_dump_context
*
)
const
;
private
:
// A mapping from interface types to a list of thunks we have
// created for methods.
typedef
std
::
vector
<
std
::
pair
<
std
::
string
,
Named_object
*>
>
Method_thunks
;
typedef
Unordered_map
(
Interface_type
*
,
Method_thunks
*
)
Interface_method_thunks
;
static
Interface_method_thunks
interface_method_thunks
;
// The expression for the interface object. This should have a type
// of interface or pointer to interface.
Expression
*
expr_
;
...
...
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/gogo.cc
View file @
571d3f91
...
...
@@ -1795,11 +1795,36 @@ Create_function_descriptors::expression(Expression** pexpr)
return
TRAVERSE_CONTINUE
;
}
Bound_method_expression
*
bme
=
expr
->
bound_method_expression
();
if
(
bme
!=
NULL
)
{
// We would not get here for a call to this method, so this is a
// method value. We need to create a thunk.
Bound_method_expression
::
create_thunk
(
this
->
gogo_
,
bme
->
method
(),
bme
->
function
());
return
TRAVERSE_CONTINUE
;
}
Interface_field_reference_expression
*
ifre
=
expr
->
interface_field_reference_expression
();
if
(
ifre
!=
NULL
)
{
// We would not get here for a call to this interface method, so
// this is a method value. We need to create a thunk.
Interface_type
*
type
=
ifre
->
expr
()
->
type
()
->
interface_type
();
if
(
type
!=
NULL
)
Interface_field_reference_expression
::
create_thunk
(
this
->
gogo_
,
type
,
ifre
->
name
());
return
TRAVERSE_CONTINUE
;
}
Call_expression
*
ce
=
expr
->
call_expression
();
if
(
ce
!=
NULL
)
{
Expression
*
fn
=
ce
->
fn
();
if
(
fn
->
func_expression
()
!=
NULL
)
if
(
fn
->
func_expression
()
!=
NULL
||
fn
->
bound_method_expression
()
!=
NULL
||
fn
->
interface_field_reference_expression
()
!=
NULL
)
{
// Traverse the arguments but not the function.
Expression_list
*
args
=
ce
->
args
();
...
...
@@ -2806,22 +2831,7 @@ Build_recover_thunks::function(Named_object* orig_no)
// Any varargs call has already been lowered.
call
->
set_varargs_are_lowered
();
Statement
*
s
;
if
(
orig_fntype
->
results
()
==
NULL
||
orig_fntype
->
results
()
->
empty
())
s
=
Statement
::
make_statement
(
call
,
true
);
else
{
Expression_list
*
vals
=
new
Expression_list
();
size_t
rc
=
orig_fntype
->
results
()
->
size
();
if
(
rc
==
1
)
vals
->
push_back
(
call
);
else
{
for
(
size_t
i
=
0
;
i
<
rc
;
++
i
)
vals
->
push_back
(
Expression
::
make_call_result
(
call
,
i
));
}
s
=
Statement
::
make_return_statement
(
vals
,
location
);
}
Statement
*
s
=
Statement
::
make_return_from_call
(
call
,
location
);
s
->
determine_types
();
gogo
->
add_statement
(
s
);
...
...
@@ -3557,42 +3567,8 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
{
Location
loc
=
no
->
location
();
Typed_identifier_list
*
new_params
=
new
Typed_identifier_list
();
const
Typed_identifier_list
*
orig_params
=
orig_fntype
->
parameters
();
if
(
orig_params
!=
NULL
&&
!
orig_params
->
empty
())
{
static
int
count
;
char
buf
[
50
];
for
(
Typed_identifier_list
::
const_iterator
p
=
orig_params
->
begin
();
p
!=
orig_params
->
end
();
++
p
)
{
snprintf
(
buf
,
sizeof
buf
,
"pt.%u"
,
count
);
++
count
;
new_params
->
push_back
(
Typed_identifier
(
buf
,
p
->
type
(),
p
->
location
()));
}
}
Type
*
vt
=
Type
::
make_pointer_type
(
Type
::
make_void_type
());
new_params
->
push_back
(
Typed_identifier
(
"closure.0"
,
vt
,
loc
));
const
Typed_identifier_list
*
orig_results
=
orig_fntype
->
results
();
Typed_identifier_list
*
new_results
;
if
(
orig_results
==
NULL
||
orig_results
->
empty
())
new_results
=
NULL
;
else
{
new_results
=
new
Typed_identifier_list
();
for
(
Typed_identifier_list
::
const_iterator
p
=
orig_results
->
begin
();
p
!=
orig_results
->
end
();
++
p
)
new_results
->
push_back
(
Typed_identifier
(
""
,
p
->
type
(),
p
->
location
()));
}
Function_type
*
new_fntype
=
Type
::
make_function_type
(
NULL
,
new_params
,
new_results
,
loc
);
Function_type
*
new_fntype
=
orig_fntype
->
copy_with_closure
(
vt
);
std
::
string
name
=
no
->
name
()
+
"$descriptorfn"
;
Named_object
*
dno
=
gogo
->
start_function
(
name
,
new_fntype
,
false
,
loc
);
...
...
@@ -3602,13 +3578,16 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
Expression
*
fn
=
Expression
::
make_func_reference
(
no
,
NULL
,
loc
);
// Call the wrapper function, passing all of the arguments except
// for the last one (the last argument is the ignored closure).
// Call the function begin wrapped, passing all of the arguments
// except for the last one (the last argument is the ignored
// closure).
const
Typed_identifier_list
*
orig_params
=
orig_fntype
->
parameters
();
Expression_list
*
args
;
if
(
orig_params
==
NULL
||
orig_params
->
empty
())
args
=
NULL
;
else
{
const
Typed_identifier_list
*
new_params
=
new_fntype
->
parameters
();
args
=
new
Expression_list
();
for
(
Typed_identifier_list
::
const_iterator
p
=
new_params
->
begin
();
p
+
1
!=
new_params
->
end
();
...
...
@@ -3627,23 +3606,7 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
loc
);
call
->
set_varargs_are_lowered
();
Statement
*
s
;
if
(
orig_results
==
NULL
||
orig_results
->
empty
())
s
=
Statement
::
make_statement
(
call
,
true
);
else
{
Expression_list
*
vals
=
new
Expression_list
();
size_t
rc
=
orig_results
->
size
();
if
(
rc
==
1
)
vals
->
push_back
(
call
);
else
{
for
(
size_t
i
=
0
;
i
<
rc
;
++
i
)
vals
->
push_back
(
Expression
::
make_call_result
(
call
,
i
));
}
s
=
Statement
::
make_return_statement
(
vals
,
loc
);
}
Statement
*
s
=
Statement
::
make_return_from_call
(
call
,
loc
);
gogo
->
add_statement
(
s
);
Block
*
b
=
gogo
->
finish_block
(
loc
);
gogo
->
add_block
(
b
,
loc
);
...
...
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/statements.cc
View file @
571d3f91
...
...
@@ -2815,6 +2815,28 @@ Statement::make_return_statement(Expression_list* vals,
return
new
Return_statement
(
vals
,
location
);
}
// Make a statement that returns the result of a call expression.
Statement
*
Statement
::
make_return_from_call
(
Call_expression
*
call
,
Location
location
)
{
size_t
rc
=
call
->
result_count
();
if
(
rc
==
0
)
return
Statement
::
make_statement
(
call
,
true
);
else
{
Expression_list
*
vals
=
new
Expression_list
();
if
(
rc
==
1
)
vals
->
push_back
(
call
);
else
{
for
(
size_t
i
=
0
;
i
<
rc
;
++
i
)
vals
->
push_back
(
Expression
::
make_call_result
(
call
,
i
));
}
return
Statement
::
make_return_statement
(
vals
,
location
);
}
}
// A break or continue statement.
class
Bc_statement
:
public
Statement
...
...
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/statements.h
View file @
571d3f91
...
...
@@ -207,6 +207,13 @@ class Statement
static
Return_statement
*
make_return_statement
(
Expression_list
*
,
Location
);
// Make a statement that returns the result of a call expression.
// If the call does not return any results, this just returns the
// call expression as a statement, assuming that the function will
// end immediately afterward.
static
Statement
*
make_return_from_call
(
Call_expression
*
,
Location
);
// Make a break statement.
static
Statement
*
make_break_statement
(
Unnamed_label
*
label
,
Location
);
...
...
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/types.cc
View file @
571d3f91
...
...
@@ -3396,7 +3396,8 @@ Function_type::do_get_backend(Gogo* gogo)
// passed when invoking the function indirectly, via the struct.
Location
loc
=
this
->
location
();
Btype
*
struct_type
=
gogo
->
backend
()
->
placeholder_struct_type
(
""
,
loc
);
Btype
*
struct_type
=
gogo
->
backend
()
->
placeholder_struct_type
(
"__go_descriptor"
,
loc
);
Btype
*
ptr_struct_type
=
gogo
->
backend
()
->
pointer_type
(
struct_type
);
Backend
::
Btyped_identifier
breceiver
;
...
...
@@ -3835,6 +3836,49 @@ Function_type::copy_with_receiver(Type* receiver_type) const
return
ret
;
}
// Make a copy of a function type ignoring any receiver and adding a
// closure parameter.
Function_type
*
Function_type
::
copy_with_closure
(
Type
*
closure_type
)
const
{
Typed_identifier_list
*
new_params
=
new
Typed_identifier_list
();
const
Typed_identifier_list
*
orig_params
=
this
->
parameters_
;
if
(
orig_params
!=
NULL
&&
!
orig_params
->
empty
())
{
static
int
count
;
char
buf
[
50
];
for
(
Typed_identifier_list
::
const_iterator
p
=
orig_params
->
begin
();
p
!=
orig_params
->
end
();
++
p
)
{
snprintf
(
buf
,
sizeof
buf
,
"pt.%u"
,
count
);
++
count
;
new_params
->
push_back
(
Typed_identifier
(
buf
,
p
->
type
(),
p
->
location
()));
}
}
new_params
->
push_back
(
Typed_identifier
(
"closure.0"
,
closure_type
,
this
->
location_
));
const
Typed_identifier_list
*
orig_results
=
this
->
results_
;
Typed_identifier_list
*
new_results
;
if
(
orig_results
==
NULL
||
orig_results
->
empty
())
new_results
=
NULL
;
else
{
new_results
=
new
Typed_identifier_list
();
for
(
Typed_identifier_list
::
const_iterator
p
=
orig_results
->
begin
();
p
!=
orig_results
->
end
();
++
p
)
new_results
->
push_back
(
Typed_identifier
(
""
,
p
->
type
(),
p
->
location
()));
}
return
Type
::
make_function_type
(
NULL
,
new_params
,
new_results
,
this
->
location
());
}
// Make a function type.
Function_type
*
...
...
@@ -7580,7 +7624,7 @@ Method::bind_method(Expression* expr, Location location) const
// the child class.
return
this
->
do_bind_method
(
expr
,
location
);
}
return
Expression
::
make_bound_method
(
expr
,
this
->
stub_
,
location
);
return
Expression
::
make_bound_method
(
expr
,
this
,
this
->
stub_
,
location
);
}
// Return the named object associated with a method. This may only be
...
...
@@ -7623,8 +7667,8 @@ Expression*
Named_method
::
do_bind_method
(
Expression
*
expr
,
Location
location
)
const
{
Named_object
*
no
=
this
->
named_object_
;
Bound_method_expression
*
bme
=
Expression
::
make_bound_method
(
expr
,
no
,
location
);
Bound_method_expression
*
bme
=
Expression
::
make_bound_method
(
expr
,
this
,
no
,
location
);
// If this is not a local method, and it does not use a stub, then
// the real method expects a different type. We need to cast the
// first argument.
...
...
@@ -9002,28 +9046,16 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
Call_expression
*
call
=
Expression
::
make_call
(
func
,
arguments
,
is_varargs
,
location
);
call
->
set_hidden_fields_are_ok
();
size_t
count
=
call
->
result_count
();
if
(
count
==
0
)
gogo
->
add_statement
(
Statement
::
make_statement
(
call
,
true
));
else
{
Expression_list
*
retvals
=
new
Expression_list
();
if
(
count
<=
1
)
retvals
->
push_back
(
call
);
else
{
for
(
size_t
i
=
0
;
i
<
count
;
++
i
)
retvals
->
push_back
(
Expression
::
make_call_result
(
call
,
i
));
}
Return_statement
*
retstat
=
Statement
::
make_return_statement
(
retvals
,
location
);
Statement
*
s
=
Statement
::
make_return_from_call
(
call
,
location
);
Return_statement
*
retstat
=
s
->
return_statement
();
if
(
retstat
!=
NULL
)
{
// We can return values with hidden fields from a stub. This is
// necessary if the method is itself hidden.
retstat
->
set_hidden_fields_are_ok
();
gogo
->
add_statement
(
retstat
);
}
gogo
->
add_statement
(
s
);
}
// Apply FIELD_INDEXES to EXPR. The field indexes have to be applied
...
...
This diff is collapsed.
Click to expand it.
gcc/go/gofrontend/types.h
View file @
571d3f91
...
...
@@ -1789,6 +1789,12 @@ class Function_type : public Type
Function_type
*
copy_with_receiver
(
Type
*
)
const
;
// Return a copy of this type ignoring any receiver and adding a
// final closure parameter of type CLOSURE_TYPE. This is used when
// creating descriptors.
Function_type
*
copy_with_closure
(
Type
*
closure_type
)
const
;
static
Type
*
make_function_type_descriptor_type
();
...
...
This diff is collapsed.
Click to expand it.
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