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
b67d701b
Commit
b67d701b
authored
Oct 12, 1998
by
Per Bothner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merge from Cygnus internal source tree.
From-SVN: r23023
parent
7e673aba
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1261 additions
and
357 deletions
+1261
-357
gcc/java/parse.y
+1261
-357
No files found.
gcc/java/parse.y
View file @
b67d701b
...
@@ -98,7 +98,16 @@ static enum tree_code binop_lookup[19] =
...
@@ -98,7 +98,16 @@ static enum tree_code binop_lookup[19] =
static tree wfl_operator = NULL_TREE;
static tree wfl_operator = NULL_TREE;
/* The "$L" identifier we use to create labels. */
/* The "$L" identifier we use to create labels. */
static tree label_id;
static tree label_id = NULL_TREE;
/* The "StringBuffer" identifier used for the String `+'
operator
.
*/
static
tree
wfl_string_buffer
=
NULL_TREE
;
/*
The
"append"
identifier
used
for
String
`+
' operator. */
static tree wfl_append = NULL_TREE;
/* The "toString" identifier used for String `+'
operator
.
*/
static
tree
wfl_to_string
=
NULL_TREE
;
%}
%}
%
union
{
%
union
{
...
@@ -219,6 +228,12 @@ static tree label_id;
...
@@ -219,6 +228,12 @@ static tree label_id;
conditional_expression
assignment_expression
conditional_expression
assignment_expression
left_hand_side
assignment
for_header
for_begin
left_hand_side
assignment
for_header
for_begin
constant_expression
do_statement_begin
empty_statement
constant_expression
do_statement_begin
empty_statement
switch_statement
synchronized_statement
throw_statement
try_statement
switch_expression
switch_block
switch_block_statement_groups
switch_labels
switch_block_statement_group
switch_label
group_of_labels
catches
catch_clause
catch_clause_parameter
finally
%
type
<
node
>
return_statement
break_statement
continue_statement
%
type
<
node
>
return_statement
break_statement
continue_statement
%
type
<
operator
>
ASSIGN_TK
MULT_ASSIGN_TK
DIV_ASSIGN_TK
%
type
<
operator
>
ASSIGN_TK
MULT_ASSIGN_TK
DIV_ASSIGN_TK
...
@@ -231,7 +246,7 @@ static tree label_id;
...
@@ -231,7 +246,7 @@ static tree label_id;
%
token
<
operator
>
DECR_TK
MINUS_TK
MULT_TK
DIV_TK
XOR_TK
REM_TK
NEQ_TK
%
token
<
operator
>
DECR_TK
MINUS_TK
MULT_TK
DIV_TK
XOR_TK
REM_TK
NEQ_TK
%
token
<
operator
>
NEG_TK
REL_QM_TK
REL_CL_TK
NOT_TK
LT_TK
%
token
<
operator
>
NEG_TK
REL_QM_TK
REL_CL_TK
NOT_TK
LT_TK
%
token
<
operator
>
OP_TK
OSB_TK
DOT_TK
%
token
<
operator
>
OP_TK
OSB_TK
DOT_TK
%type <operator> THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK
%
type
<
operator
>
THIS_TK
SUPER_TK
RETURN_TK
BREAK_TK
CONTINUE_TK
CASE_TK
%
type
<
operator
>
DEFAULT_TK
TRY_TK
CATCH_TK
%
type
<
node
>
method_body
%
type
<
node
>
method_body
...
@@ -539,13 +554,16 @@ class_body_declaration:
...
@@ -539,13 +554,16 @@ class_body_declaration:
|
static_initializer
|
static_initializer
|
constructor_declaration
|
constructor_declaration
|
block
/*
Added
,
JDK1
.1
,
instance
initializer
*/
|
block
/*
Added
,
JDK1
.1
,
instance
initializer
*/
{
$$
=
parse_jdk1_1_error
(
"instance initializer"
);
}
;
;
class_member_declaration
:
class_member_declaration
:
field_declaration
field_declaration
|
method_declaration
|
method_declaration
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
{
$$
=
parse_jdk1_1_error
(
"inner classe declaration"
);
}
|
interface_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
|
interface_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
{
$$
=
parse_jdk1_1_error
(
"inner interface declaration"
);
}
;
;
/*
19.8.2
Productions
from
8.3
:
Field
Declarations
*/
/*
19.8.2
Productions
from
8.3
:
Field
Declarations
*/
...
@@ -701,10 +719,7 @@ formal_parameter:
...
@@ -701,10 +719,7 @@ formal_parameter:
$$ = build_tree_list ($2, $1);
$$ = build_tree_list ($2, $1);
}
}
| modifiers type variable_declarator_id /* Added, JDK1.1 final locals */
| modifiers type variable_declarator_id /* Added, JDK1.1 final locals */
{
{ $$ = parse_jdk1_1_error ("final local"); }
SOURCE_FRONTEND_DEBUG
((
"Modifiers: %d"
,
$
1
));
$$
=
NULL
;
/*
FIXME
*/
}
| type error
| type error
{yyerror ("Missing identifier"); RECOVER;}
{yyerror ("Missing identifier"); RECOVER;}
| modifiers type error
| modifiers type error
...
@@ -802,20 +817,23 @@ explicit_constructor_invocation:
...
@@ -802,20 +817,23 @@ explicit_constructor_invocation:
/* Added, JDK1.1 inner classes. Modified because the rule
/* Added, JDK1.1 inner classes. Modified because the rule
'
primary
' couldn'
t
work
.
*/
'
primary
' couldn'
t
work
.
*/
|
name
DOT_TK
SUPER_TK
OP_TK
argument_list
CP_TK
SC_TK
|
name
DOT_TK
SUPER_TK
OP_TK
argument_list
CP_TK
SC_TK
{$$
=
parse_jdk1_1_error
(
"explicit constructor invocation"
);
}
|
name
DOT_TK
SUPER_TK
OP_TK
CP_TK
SC_TK
|
name
DOT_TK
SUPER_TK
OP_TK
CP_TK
SC_TK
{
RULE ("explicit_constructor_invocation (X.super)");
}
{
$$
=
parse_jdk1_1_error
(
"explicit constructor invocation"
);
}
;
;
this_or_super
:
/*
Added
,
simplifies
error
diagnostics
*/
this_or_super
:
/*
Added
,
simplifies
error
diagnostics
*/
THIS_TK
THIS_TK
{
{
tree wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0);
tree
wfl
=
build_wfl_node
(
this_identifier_node
,
input_filename
,
0
,
0
);
EXPR_WFL_LINECOL
(
wfl
)
=
$
1.l
ocation
;
EXPR_WFL_LINECOL
(
wfl
)
=
$
1.l
ocation
;
$$
=
wfl
;
$$
=
wfl
;
}
}
|
SUPER_TK
|
SUPER_TK
{
{
tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0);
tree
wfl
=
build_wfl_node
(
super_identifier_node
,
input_filename
,
0
,
0
);
EXPR_WFL_LINECOL
(
wfl
)
=
$
1.l
ocation
;
EXPR_WFL_LINECOL
(
wfl
)
=
$
1.l
ocation
;
$$
=
wfl
;
$$
=
wfl
;
}
}
...
@@ -887,7 +905,9 @@ interface_member_declaration:
...
@@ -887,7 +905,9 @@ interface_member_declaration:
constant_declaration
constant_declaration
|
abstract_method_declaration
|
abstract_method_declaration
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
{
$$
=
parse_jdk1_1_error
(
"inner class declaration"
);
}
|
interface_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
|
interface_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
{
$$
=
parse_jdk1_1_error
(
"inner interface declaration"
);
}
;
;
constant_declaration
:
constant_declaration
:
...
@@ -955,6 +975,7 @@ block_statement:
...
@@ -955,6 +975,7 @@ block_statement:
|
statement
|
statement
{
$$
=
java_method_add_stmt
(
current_function_decl
,
$
1
);
}
{
$$
=
java_method_add_stmt
(
current_function_decl
,
$
1
);
}
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
|
class_declaration
/*
Added
,
JDK1
.1
inner
classes
*/
{
$$
=
parse_jdk1_1_error
(
"inner class declaration"
);
}
;
;
local_variable_declaration_statement
:
local_variable_declaration_statement
:
...
@@ -971,13 +992,9 @@ local_variable_declaration:
...
@@ -971,13 +992,9 @@ local_variable_declaration:
statement:
statement:
statement_without_trailing_substatement
statement_without_trailing_substatement
| labeled_statement
| labeled_statement
{
RULE
(
"STATEMENT (labeled)"
);
}
| if_then_statement
| if_then_statement
{
RULE
(
"STATEMENT (if-then)"
);
}
| if_then_else_statement
| if_then_else_statement
{
RULE
(
"STATEMENT (if-then-else)"
);
}
| while_statement
| while_statement
{
RULE
(
"STATEMENT (while)"
);
}
| for_statement
| for_statement
{
{
/* If the for loop is unlabeled, we must return the
/* If the for loop is unlabeled, we must return the
...
@@ -991,37 +1008,23 @@ statement:
...
@@ -991,37 +1008,23 @@ statement:
statement_nsi:
statement_nsi:
statement_without_trailing_substatement
statement_without_trailing_substatement
| labeled_statement_nsi
| labeled_statement_nsi
{
RULE
(
"NSI STATEMENT (labeled)"
);
}
| if_then_else_statement_nsi
| if_then_else_statement_nsi
{
RULE
(
"NSI STATEMENT (if-then-else)"
);
}
| while_statement_nsi
| while_statement_nsi
{
RULE
(
"NSI STATEMENT (while)"
);
}
| for_statement_nsi
| for_statement_nsi
{
RULE
(
"NSI STATEMENT (for)"
);
}
;
;
statement_without_trailing_substatement:
statement_without_trailing_substatement:
block
block
{
RULE
(
"STATEMENT (block)"
);
}
| empty_statement
| empty_statement
{
RULE
(
"STATEMENT (empty)"
);
}
| expression_statement
| expression_statement
{
RULE
(
"STATEMENT (expression)"
);
}
| switch_statement
| switch_statement
{
RULE
(
"STATEMENT (switch)"
);
}
| do_statement
| do_statement
{
RULE
(
"STATEMENT (do)"
);
}
| break_statement
| break_statement
{
RULE
(
"STATEMENT (break)"
);
}
| continue_statement
| continue_statement
{
RULE
(
"STATEMENT (continue)"
);
}
| return_statement
| return_statement
| synchronized_statement
| synchronized_statement
{
RULE
(
"STATEMENT (synchronized)"
);
}
| throw_statement
| throw_statement
{
RULE
(
"STATEMENT (throw)"
);
}
| try_statement
| try_statement
{
RULE
(
"STATEMENT (try)"
);
}
;
;
empty_statement:
empty_statement:
...
@@ -1113,26 +1116,11 @@ expression_statement:
...
@@ -1113,26 +1116,11 @@ expression_statement:
statement_expression
:
statement_expression
:
assignment
assignment
|
pre_increment_expression
|
pre_increment_expression
{
RULE ("++INCREMENT");
}
|
pre_decrement_expression
|
pre_decrement_expression
{
RULE ("--DECREMENT");
}
|
post_increment_expression
|
post_increment_expression
{
RULE ("INCREMENT++");
}
|
post_decrement_expression
|
post_decrement_expression
{
RULE ("DECREMENT--");
}
|
method_invocation
|
method_invocation
|
class_instance_creation_expression
|
class_instance_creation_expression
{
RULE ("INSTANCE CREATION");
}
;
;
if_then_statement
:
if_then_statement
:
...
@@ -1157,7 +1145,19 @@ if_then_else_statement_nsi:
...
@@ -1157,7 +1145,19 @@ if_then_else_statement_nsi:
;
;
switch_statement
:
switch_statement
:
SWITCH_TK OP_TK expression CP_TK switch_block
switch_expression
switch_block
{
TREE_OPERAND
($
1
,
1
)
=
$
2
;
$$
=
build_debugable_stmt
(
EXPR_WFL_LINECOL
($
1
),
$
1
);
}
;
switch_expression
:
SWITCH_TK
OP_TK
expression
CP_TK
{
$$
=
build
(
SWITCH_EXPR
,
NULL_TREE
,
$
3
,
NULL_TREE
);
EXPR_WFL_LINECOL
($$)
=
$
2.l
ocation
;
}
|
SWITCH_TK
error
|
SWITCH_TK
error
{
yyerror
(
"'(' expected"
);
RECOVER
;}
{
yyerror
(
"'(' expected"
);
RECOVER
;}
|
SWITCH_TK
OP_TK
error
|
SWITCH_TK
OP_TK
error
...
@@ -1168,29 +1168,63 @@ switch_statement:
...
@@ -1168,29 +1168,63 @@ switch_statement:
switch_block
:
switch_block
:
OCB_TK
CCB_TK
OCB_TK
CCB_TK
{
$$
=
NULL_TREE
;
}
|
OCB_TK
switch_labels
CCB_TK
|
OCB_TK
switch_labels
CCB_TK
{
$$
=
build_tree_list
($
2
,
NULL_TREE
);
}
|
OCB_TK
switch_block_statement_groups
CCB_TK
|
OCB_TK
switch_block_statement_groups
CCB_TK
{
$$
=
$
2
;
}
|
OCB_TK
switch_block_statement_groups
switch_labels
CCB_TK
|
OCB_TK
switch_block_statement_groups
switch_labels
CCB_TK
{
/*
Switch
labels
alone
are
empty
switch
statements
*/
tree
sl
=
build_tree_list
($
3
,
NULL_TREE
);
TREE_CHAIN
(
sl
)
=
$
2
;
$$
=
sl
;
}
;
;
switch_block_statement_groups
:
switch_block_statement_groups
:
switch_block_statement_group
switch_block_statement_group
|
switch_block_statement_groups
switch_block_statement_group
|
switch_block_statement_groups
switch_block_statement_group
{
TREE_CHAIN
($
2
)
=
$
1
;
$$
=
$
2
;
}
;
;
switch_block_statement_group
:
switch_block_statement_group
:
switch_labels block_statements
group_of_labels
block_statements
{
$$
=
build_tree_list
($
1
,
exit_block
());
}
;
;
group_of_labels
:
switch_labels
{
/*
All
statements
attached
to
this
group
of
cases
will
be
stored
in
a
block
*/
enter_block
();
$$
=
$
1
;
}
switch_labels
:
switch_labels
:
switch_label
switch_label
|
switch_labels
switch_label
|
switch_labels
switch_label
{
TREE_CHAIN
($
2
)
=
$
1
;
$$
=
$
2
;
}
;
;
switch_label
:
switch_label
:
CASE_TK
constant_expression
REL_CL_TK
CASE_TK
constant_expression
REL_CL_TK
{
$$
=
build1
(
CASE_EXPR
,
NULL_TREE
,
$
2
);
EXPR_WFL_LINECOL
($$)
=
$
1.l
ocation
;
}
|
DEFAULT_TK
REL_CL_TK
|
DEFAULT_TK
REL_CL_TK
{
$$
=
build1
(
DEFAULT_EXPR
,
NULL_TREE
,
NULL_TREE
);
EXPR_WFL_LINECOL
($$)
=
$
1.l
ocation
;
}
|
CASE_TK
error
|
CASE_TK
error
{
yyerror
(
"Missing or invalid constant expression"
);
RECOVER
;}
{
yyerror
(
"Missing or invalid constant expression"
);
RECOVER
;}
|
CASE_TK
constant_expression
error
|
CASE_TK
constant_expression
error
...
@@ -1361,6 +1395,7 @@ return_statement:
...
@@ -1361,6 +1395,7 @@ return_statement:
throw_statement
:
throw_statement
:
THROW_TK
expression
SC_TK
THROW_TK
expression
SC_TK
{
$$
=
NULL_TREE
;
/*
FIXME
*/
}
|
THROW_TK
error
|
THROW_TK
error
{
yyerror
(
"Missing term"
);
RECOVER
;}
{
yyerror
(
"Missing term"
);
RECOVER
;}
|
THROW_TK
expression
error
|
THROW_TK
expression
error
...
@@ -1369,6 +1404,7 @@ throw_statement:
...
@@ -1369,6 +1404,7 @@ throw_statement:
synchronized_statement
:
synchronized_statement
:
synchronized
OP_TK
expression
CP_TK
block
synchronized
OP_TK
expression
CP_TK
block
{
$$
=
NULL_TREE
;
/*
FIXME
*/
}
|
synchronized
OP_TK
expression
CP_TK
error
|
synchronized
OP_TK
expression
CP_TK
error
{
yyerror
(
"'{' expected"
);
RECOVER
;}
{
yyerror
(
"'{' expected"
);
RECOVER
;}
|
synchronized
error
|
synchronized
error
...
@@ -1388,8 +1424,11 @@ synchronized: /* Test lval.sub_token here */
...
@@ -1388,8 +1424,11 @@ synchronized: /* Test lval.sub_token here */
try_statement
:
try_statement
:
TRY_TK
block
catches
TRY_TK
block
catches
{
$$
=
build_try_statement
($
1.l
ocation
,
$
2
,
$
3
,
NULL_TREE
);
}
|
TRY_TK
block
finally
|
TRY_TK
block
finally
{
$$
=
build_try_statement
($
1.l
ocation
,
$
2
,
NULL_TREE
,
$
3
);
}
|
TRY_TK
block
catches
finally
|
TRY_TK
block
catches
finally
{
$$
=
build_try_statement
($
1.l
ocation
,
$
2
,
$
3
,
$
4
);
}
|
TRY_TK
error
|
TRY_TK
error
{
yyerror
(
"'{' expected"
);
DRECOVER
(
try_statement
);}
{
yyerror
(
"'{' expected"
);
DRECOVER
(
try_statement
);}
;
;
...
@@ -1397,20 +1436,51 @@ try_statement:
...
@@ -1397,20 +1436,51 @@ try_statement:
catches
:
catches
:
catch_clause
catch_clause
|
catches
catch_clause
|
catches
catch_clause
{
TREE_CHAIN
($
2
)
=
$
1
;
$$
=
$
2
;
}
;
;
catch_clause
:
catch_clause
:
CATCH_TK OP_TK formal_parameter CP_TK block
catch_clause_parameter
block
{
java_method_add_stmt
(
current_function_decl
,
$
2
);
exit_block
();
$$
=
$
1
;
}
catch_clause_parameter
:
CATCH_TK
OP_TK
formal_parameter
CP_TK
{
/*
We
add
a
block
to
define
a
scope
for
formal_parameter
(
CCBP
).
The
formal
parameter
is
declared
initialized
by
the
appropriate
function
call
*/
tree
ccpb
=
enter_block
();
tree
init
=
build_assignment
(
ASSIGN_TK
,
$
2.l
ocation
,
TREE_PURPOSE
($
3
),
soft_exceptioninfo_call_node
);
declare_local_variables
(
0
,
TREE_VALUE
($
3
),
build_tree_list
(
TREE_PURPOSE
($
3
),
init
));
$$
=
build1
(
CATCH_EXPR
,
NULL_TREE
,
ccpb
);
EXPR_WFL_LINECOL
($$)
=
$
1.l
ocation
;
}
|
CATCH_TK
error
|
CATCH_TK
error
{
yyerror
(
"'(' expected"
);
RECOVER
;}
{
yyerror
(
"'(' expected"
);
RECOVER
;}
| CATCH_TK OP_TK error CP_TK /* That'
s
for
()
*/
{
yyerror
(
"Missing term"
);
DRECOVER
(
1
);}
|
CATCH_TK
OP_TK
error
|
CATCH_TK
OP_TK
error
{
yyerror
(
"Missing term"
);
DRECOVER
(
2
);}
{
yyerror
(
"Missing term or ')' expected"
);
DRECOVER
(
2
);}
|
CATCH_TK
OP_TK
error
CP_TK
/*
That
's for () */
{yyerror ("'
)
' expected"); DRECOVER (1);}
;
;
finally:
finally:
FINALLY_TK block
FINALLY_TK block
{
$$ = build (FINALLY_EXPR, NULL_TREE,
create_label_decl (generate_name ()), $2);
}
| FINALLY_TK error
| FINALLY_TK error
{yyerror ("'
{
' expected"); RECOVER; }
{yyerror ("'
{
' expected"); RECOVER; }
;
;
...
@@ -1435,12 +1505,16 @@ primary_no_new_array:
...
@@ -1435,12 +1505,16 @@ primary_no_new_array:
'type'
into
its
components
.
Missing
is
something
for
array
,
'type'
into
its
components
.
Missing
is
something
for
array
,
which
will
complete
the
reference_type
part
.
FIXME
*/
which
will
complete
the
reference_type
part
.
FIXME
*/
|
name
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
|
name
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
{
$$
=
parse_jdk1_1_error
(
"class literals"
);
}
|
primitive_type
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
|
primitive_type
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
{
$$
=
parse_jdk1_1_error
(
"class literals"
);
}
|
VOID_TK
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
|
VOID_TK
DOT_TK
CLASS_TK
/*
Added
,
JDK1
.1
class
literals
*/
{
$$
=
parse_jdk1_1_error
(
"class literals"
);
}
/*
Added
,
JDK1
.1
inner
classes
.
Documentation
is
wrong
/*
Added
,
JDK1
.1
inner
classes
.
Documentation
is
wrong
refering
to
a
'ClassName'
(
class_name
)
rule
that
doesn
't
refering
to
a
'ClassName'
(
class_name
)
rule
that
doesn
't
exist. Used name instead. */
exist. Used name instead. */
| name DOT_TK THIS_TK
| name DOT_TK THIS_TK
{ $$ = parse_jdk1_1_error ("class literals"); }
| OP_TK expression error
| OP_TK expression error
{yyerror ("'
)
' expected"); RECOVER;}
{yyerror ("'
)
' expected"); RECOVER;}
| name DOT_TK error
| name DOT_TK error
...
@@ -1453,22 +1527,16 @@ primary_no_new_array:
...
@@ -1453,22 +1527,16 @@ primary_no_new_array:
class_instance_creation_expression:
class_instance_creation_expression:
NEW_TK class_type OP_TK argument_list CP_TK
NEW_TK class_type OP_TK argument_list CP_TK
{
{ $$ = build_new_invocation ($2, $4); }
$$
=
build_method_invocation
($
2
,
$
4
);
TREE_SET_CODE
($$,
JAVA_NEW_CLASS_EXPR
);
}
| NEW_TK class_type OP_TK CP_TK
| NEW_TK class_type OP_TK CP_TK
{
{ $$ = build_new_invocation ($2, NULL_TREE); }
$$
=
build_method_invocation
($
2
,
NULL_TREE
);
TREE_SET_CODE
($$,
JAVA_NEW_CLASS_EXPR
);
}
/* Added, JDK1.1 inner classes but modified to use
/* Added, JDK1.1 inner classes but modified to use
'
class_type
' instead of '
TypeName
' (type_name) mentionned
'
class_type
' instead of '
TypeName
' (type_name) mentionned
in the documentation but doesn'
t
exist
.
*/
in the documentation but doesn'
t
exist
.
*/
|
NEW_TK
class_type
OP_TK
argument_list
CP_TK
class_body
|
NEW_TK
class_type
OP_TK
argument_list
CP_TK
class_body
{$$ = $2;
}
{
$$
=
parse_jdk1_1_error
(
"inner class instance creation"
);
}
|
NEW_TK
class_type
OP_TK
CP_TK
class_body
|
NEW_TK
class_type
OP_TK
CP_TK
class_body
{$$ = $2;
}
{
$$
=
parse_jdk1_1_error
(
"inner class instance creation"
);
}
/*
Added
,
JDK1
.1
inner
classes
,
modified
to
use
name
or
/*
Added
,
JDK1
.1
inner
classes
,
modified
to
use
name
or
primary
instead
of
primary
solely
which
couldn
't work in
primary
instead
of
primary
solely
which
couldn
't work in
all situations. */
all situations. */
...
@@ -1522,9 +1590,9 @@ array_creation_expression:
...
@@ -1522,9 +1590,9 @@ array_creation_expression:
/* Added, JDK1.1 anonymous array. Initial documentation rule
/* Added, JDK1.1 anonymous array. Initial documentation rule
modified */
modified */
| NEW_TK class_or_interface_type dims array_initializer
| NEW_TK class_or_interface_type dims array_initializer
{$$
=
$
2
;
}
{ $$ = parse_jdk1_1_error ("anonymous array");
}
| NEW_TK primitive_type dims array_initializer
| NEW_TK primitive_type dims array_initializer
{$$
=
$
2
;
}
{ $$ = parse_jdk1_1_error ("anonymous array");
}
| NEW_TK error CSB_TK
| NEW_TK error CSB_TK
{yyerror ("'
[
' expected"); DRECOVER ("]");}
{yyerror ("'
[
' expected"); DRECOVER ("]");}
| NEW_TK error OSB_TK
| NEW_TK error OSB_TK
...
@@ -1569,7 +1637,8 @@ field_access:
...
@@ -1569,7 +1637,8 @@ field_access:
| SUPER_TK DOT_TK identifier
| SUPER_TK DOT_TK identifier
{
{
tree super_wfl =
tree super_wfl =
build_wfl_node
(
super_identifier_node
,
input_filename
,
0
,
0
);
build_wfl_node (super_identifier_node,
input_filename, 0, 0);
EXPR_WFL_LINECOL (super_wfl) = $1.location;
EXPR_WFL_LINECOL (super_wfl) = $1.location;
$$ = make_qualified_name (super_wfl, $3, $2.location);
$$ = make_qualified_name (super_wfl, $3, $2.location);
}
}
...
@@ -1595,7 +1664,8 @@ method_invocation:
...
@@ -1595,7 +1664,8 @@ method_invocation:
| SUPER_TK DOT_TK identifier OP_TK CP_TK
| SUPER_TK DOT_TK identifier OP_TK CP_TK
{
{
tree invok;
tree invok;
tree
wfl
=
build_wfl_node
(
super_identifier_node
,
input_filename
,
0
,
0
);
tree wfl = build_wfl_node (super_identifier_node,
input_filename, 0, 0);
EXPR_WFL_LINECOL (wfl) = $1.location;
EXPR_WFL_LINECOL (wfl) = $1.location;
invok = build_method_invocation ($3, NULL_TREE);
invok = build_method_invocation ($3, NULL_TREE);
$$ = make_qualified_primary (wfl, invok, $2.location);
$$ = make_qualified_primary (wfl, invok, $2.location);
...
@@ -1603,7 +1673,8 @@ method_invocation:
...
@@ -1603,7 +1673,8 @@ method_invocation:
| SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK
| SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK
{
{
tree invok;
tree invok;
tree
wfl
=
build_wfl_node
(
super_identifier_node
,
input_filename
,
0
,
0
);
tree wfl = build_wfl_node (super_identifier_node,
input_filename, 0, 0);
EXPR_WFL_LINECOL (wfl) = $1.location;
EXPR_WFL_LINECOL (wfl) = $1.location;
invok = build_method_invocation ($3, $5);
invok = build_method_invocation ($3, $5);
$$ = make_qualified_primary (wfl, invok, $2.location);
$$ = make_qualified_primary (wfl, invok, $2.location);
...
@@ -2043,6 +2114,17 @@ java_pop_parser_context ()
...
@@ -2043,6 +2114,17 @@ java_pop_parser_context ()
free (toFree);
free (toFree);
}
}
/* Reporting JDK1.1 features not implemented */
static tree
parse_jdk1_1_error (msg)
char *msg;
{
sorry (": `%s'
JDK1
.1
(
TM
)
feature
", msg);
java_error_count++;
return size_zero_node;
}
static int do_warning = 0;
static int do_warning = 0;
void
void
...
@@ -2212,8 +2294,11 @@ java_accstring_lookup (flags)
...
@@ -2212,8 +2294,11 @@ java_accstring_lookup (flags)
#undef COPY_RETURN
#undef COPY_RETURN
}
}
/* Issuing error messages upon redefinition of classes, interfaces or
variables. */
static void
static void
redefinition_error
(
context
,
id
,
decl
,
cl
)
classitf_
redefinition_error (context, id, decl, cl)
char *context;
char *context;
tree id, decl, cl;
tree id, decl, cl;
{
{
...
@@ -2223,6 +2308,26 @@ redefinition_error (context, id, decl, cl)
...
@@ -2223,6 +2308,26 @@ redefinition_error (context, id, decl, cl)
/* Here we should point out where its redefined. It'
s
a
unicode
.
FIXME
*/
/* Here we should point out where its redefined. It'
s
a
unicode
.
FIXME
*/
}
}
static
void
variable_redefinition_error
(
context
,
name
,
type
,
line
)
tree
context
,
name
,
type
;
int
line
;
{
char
*
type_name
;
/*
Figure
a
proper
name
for
type
.
We
might
haven
't resolved it */
if (TREE_CODE (type) == TREE_LIST)
type_name = IDENTIFIER_POINTER (TYPE_NAME (TREE_PURPOSE (type)));
else
type_name = (char *)lang_printable_name (type);
parse_error_context (context,
"Variable `%s'
is
already
defined
in
this
method
and
"
"
was
declared
`%
s
%
s
' at line %d",
IDENTIFIER_POINTER (name),
type_name, IDENTIFIER_POINTER (name), line);
}
/* Build something that the type identifier resolver will identify as
/* Build something that the type identifier resolver will identify as
being an array to an unresolved type. TYPE_WFL is a WFL on a
being an array to an unresolved type. TYPE_WFL is a WFL on a
identifier. */
identifier. */
...
@@ -2311,7 +2416,7 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
...
@@ -2311,7 +2416,7 @@ check_class_interface_creation (is_interface, flags, raw_name, qualified_name, d
}
}
if (decl && CLASS_COMPLETE_P (decl))
if (decl && CLASS_COMPLETE_P (decl))
{
{
redefinition_error ((is_interface ? "
Interface
" : "
Class
"),
classitf_
redefinition_error ((is_interface ? "
Interface
" : "
Class
"),
qualified_name, decl, cl);
qualified_name, decl, cl);
return 1;
return 1;
}
}
...
@@ -2617,6 +2722,8 @@ register_fields (flags, type, variable_list)
...
@@ -2617,6 +2722,8 @@ register_fields (flags, type, variable_list)
must_chain = 1;
must_chain = 1;
}
}
}
}
if (!must_chain && TREE_CODE (type) == RECORD_TYPE)
type = promote_type (type);
for (current = variable_list; current; current = TREE_CHAIN (current))
for (current = variable_list; current; current = TREE_CHAIN (current))
{
{
...
@@ -3235,6 +3342,7 @@ java_complete_class ()
...
@@ -3235,6 +3342,7 @@ java_complete_class ()
tree
cclass
;
tree
cclass
;
jdeplist
*
cclassd
;
jdeplist
*
cclassd
;
int
error_found
;
int
error_found
;
tree
type
;
push_obstacks
(&
permanent_obstack
,
&
permanent_obstack
);
push_obstacks
(&
permanent_obstack
,
&
permanent_obstack
);
...
@@ -3276,9 +3384,7 @@ java_complete_class ()
...
@@ -3276,9 +3384,7 @@ java_complete_class ()
tree field_decl = JDEP_DECL (dep);
tree field_decl = JDEP_DECL (dep);
tree field_type = TREE_TYPE (decl);
tree field_type = TREE_TYPE (decl);
push_obstacks (&permanent_obstack, &permanent_obstack);
push_obstacks (&permanent_obstack, &permanent_obstack);
#if ! JAVA_PROMOTE_TO_INT
if (TREE_CODE (field_type) == RECORD_TYPE)
if (TREE_CODE (field_type) == RECORD_TYPE)
#endif
field_type = promote_type (field_type);
field_type = promote_type (field_type);
pop_obstacks ();
pop_obstacks ();
TREE_TYPE (field_decl) = field_type;
TREE_TYPE (field_decl) = field_type;
...
@@ -3295,7 +3401,9 @@ java_complete_class ()
...
@@ -3295,7 +3401,9 @@ java_complete_class ()
{
{
if (decl)
if (decl)
{
{
tree type = promote_type (TREE_TYPE(decl));
type = TREE_TYPE(decl);
if (TREE_CODE (type) == RECORD_TYPE)
type = promote_type (type);
JDEP_APPLY_PATCH (dep, type);
JDEP_APPLY_PATCH (dep, type);
SOURCE_FRONTEND_DEBUG
SOURCE_FRONTEND_DEBUG
(((JDEP_KIND (dep) == JDEP_METHOD_RETURN ?
(((JDEP_KIND (dep) == JDEP_METHOD_RETURN ?
...
@@ -3333,14 +3441,12 @@ java_complete_class ()
...
@@ -3333,14 +3441,12 @@ java_complete_class ()
parser_add_interface (JDEP_DECL (dep), decl, JDEP_WFL (dep));
parser_add_interface (JDEP_DECL (dep), decl, JDEP_WFL (dep));
break;
break;
case JDEP_PARM:
case JDEP_VARIABLE:
case JDEP_VARIABLE:
JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl)));
type = TREE_TYPE(decl);
SOURCE_FRONTEND_DEBUG
if (TREE_CODE (type) == RECORD_TYPE)
(("Completing variable `%s'
with
type
`%
s
'",
type = promote_type (type);
(TREE_CODE (JDEP_DECL_WFL (dep)) == EXPR_WITH_FILE_LOCATION ?
JDEP_APPLY_PATCH (dep, type);
IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))) :
IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL_WFL (dep)))),
IDENTIFIER_POINTER (DECL_NAME (decl))));
break;
break;
case JDEP_TYPE:
case JDEP_TYPE:
...
@@ -3350,14 +3456,6 @@ java_complete_class ()
...
@@ -3350,14 +3456,6 @@ java_complete_class ()
tree_code_name [TREE_CODE (JDEP_DECL (dep))]));
tree_code_name [TREE_CODE (JDEP_DECL (dep))]));
break;
break;
case JDEP_PARM:
JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl)));
SOURCE_FRONTEND_DEBUG
(("Completing parameter `%s'
with
type
`%
s
'",
IDENTIFIER_POINTER (JDEP_MISC (dep)),
IDENTIFIER_POINTER (DECL_NAME (decl))));
break;
default:
default:
fatal ("incomplete switch - java_complete_class");
fatal ("incomplete switch - java_complete_class");
}
}
...
@@ -3562,7 +3660,8 @@ complete_class_report_errors (dep)
...
@@ -3562,7 +3660,8 @@ complete_class_report_errors (dep)
parse_error_context
parse_error_context
(
JDEP_WFL
(
dep
),
"Type `%s' not found in the declaration of the "
(
JDEP_WFL
(
dep
),
"Type `%s' not found in the declaration of the "
"local variable `%s'"
,
"local variable `%s'"
,
purify_type_name
(
IDENTIFIER_POINTER
(
EXPR_WFL_NODE
(
JDEP_WFL
(
dep
)))),
purify_type_name
(
IDENTIFIER_POINTER
(
EXPR_WFL_NODE
(
JDEP_WFL
(
dep
)))),
IDENTIFIER_POINTER
(
DECL_NAME
(
JDEP_DECL
(
dep
))));
IDENTIFIER_POINTER
(
DECL_NAME
(
JDEP_DECL
(
dep
))));
break
;
break
;
}
}
...
@@ -4268,6 +4367,8 @@ declare_local_variables (modifier, type, vlist)
...
@@ -4268,6 +4367,8 @@ declare_local_variables (modifier, type, vlist)
must_chain
=
1
;
must_chain
=
1
;
}
}
}
}
if
(
!must_chain && TREE_CODE (type) == RECORD_TYPE)
type
=
promote_type
(
type
);
for
(
current
=
vlist
;
current
;
current
=
TREE_CHAIN
(
current
))
for
(
current
=
vlist
;
current
;
current
=
TREE_CHAIN
(
current
))
{
{
...
@@ -4281,15 +4382,10 @@ declare_local_variables (modifier, type, vlist)
...
@@ -4281,15 +4382,10 @@ declare_local_variables (modifier, type, vlist)
init = NULL_TREE;
init = NULL_TREE;
if (other)
if (other)
parse_error_context
variable_redefinition_error (wfl, name, TREE_TYPE (other),
(wfl, "Variable `%s'
is
already
defined
in
this
method
and
was
"
DECL_SOURCE_LINE (other));
"
declared
`%
s
%
s
' in line %d",
IDENTIFIER_POINTER (name), lang_printable_name (TREE_TYPE (other)),
IDENTIFIER_POINTER (name), DECL_SOURCE_LINE (other));
else
else
{
{
if (!must_chain && TREE_CODE (type) == RECORD_TYPE)
type = promote_type (type);
/* Never layout this decl. This will be done when its scope
/* Never layout this decl. This will be done when its scope
will be entered */
will be entered */
decl = build_decl_no_layout (VAR_DECL, name, type);
decl = build_decl_no_layout (VAR_DECL, name, type);
...
@@ -4382,7 +4478,13 @@ expand_start_java_method (fndecl)
...
@@ -4382,7 +4478,13 @@ expand_start_java_method (fndecl)
while
(
tem
)
while
(
tem
)
{
{
tree
next
=
TREE_CHAIN
(
tem
);
tree
next
=
TREE_CHAIN
(
tem
);
DECL_ARG_TYPE
(
tem
)
=
TREE_TYPE
(
tem
);
tree
type
=
TREE_TYPE
(
tem
);
#
ifdef
PROMOTE_PROTOTYPES
if
(
TYPE_PRECISION
(
type
)
<
TYPE_PRECISION
(
integer_type_node
)
&&
INTEGRAL_TYPE_P
(
type
))
type
=
integer_type_node
;
#
endif
DECL_ARG_TYPE
(
tem
)
=
type
;
layout_decl
(
tem
,
0
);
layout_decl
(
tem
,
0
);
pushdecl
(
tem
);
pushdecl
(
tem
);
INITIALIZED_P
(
tem
)
=
1
;
/*
Parms
are
initialized
*/
INITIALIZED_P
(
tem
)
=
1
;
/*
Parms
are
initialized
*/
...
@@ -4406,6 +4508,9 @@ source_end_java_method ()
...
@@ -4406,6 +4508,9 @@ source_end_java_method ()
java_parser_context_save_global
();
java_parser_context_save_global
();
lineno
=
ctxp
->
last_ccb_indent1
;
lineno
=
ctxp
->
last_ccb_indent1
;
/*
Set
EH
language
codes
*/
java_set_exception_lang_code
();
/*
Generate
function
's code */
/*
Generate
function
's code */
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))
if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))
&& ! flag_emit_class_files)
&& ! flag_emit_class_files)
...
@@ -4420,6 +4525,8 @@ source_end_java_method ()
...
@@ -4420,6 +4525,8 @@ source_end_java_method ()
if (! flag_emit_class_files)
if (! flag_emit_class_files)
{
{
lineno = DECL_SOURCE_LINE_LAST (fndecl);
lineno = DECL_SOURCE_LINE_LAST (fndecl);
/* Emit catch-finally clauses */
emit_handlers ();
expand_function_end (input_filename, lineno, 0);
expand_function_end (input_filename, lineno, 0);
/* Run the optimizers and output assembler code for this function. */
/* Run the optimizers and output assembler code for this function. */
...
@@ -4438,17 +4545,24 @@ tree
...
@@ -4438,17 +4545,24 @@ tree
java_method_add_stmt (fndecl, expr)
java_method_add_stmt (fndecl, expr)
tree fndecl, expr;
tree fndecl, expr;
{
{
tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl));
return add_stmt_to_block (DECL_FUNCTION_BODY (fndecl), NULL_TREE, expr);
tree node;
}
static tree
add_stmt_to_block (b, type, stmt)
tree b, type, stmt;
{
tree body = BLOCK_EXPR_BODY (b), c;
if (java_error_count)
if (java_error_count)
return body;
return body;
if ((node = add_stmt_to_compound (body, NULL_TREE, expr)) == body)
if ((c = add_stmt_to_compound (body, type, stmt)) == body)
return body;
return body;
BLOCK_EXPR_BODY (
DECL_FUNCTION_BODY (fndecl)) = node
;
BLOCK_EXPR_BODY (
b) = c
;
TREE_SIDE_EFFECTS (
node
) = 1;
TREE_SIDE_EFFECTS (
c
) = 1;
return
node
;
return
c
;
}
}
/* Add STMT to EXISTING if possible, otherwise create a new
/* Add STMT to EXISTING if possible, otherwise create a new
...
@@ -4637,7 +4751,7 @@ make_qualified_primary (primary, right, location)
...
@@ -4637,7 +4751,7 @@ make_qualified_primary (primary, right, location)
/*
We
want
to
process
THIS
.
xxx
symbolicaly
,
to
keep
it
consistent
/*
We
want
to
process
THIS
.
xxx
symbolicaly
,
to
keep
it
consistent
with
the
way
we
're processing SUPER. A THIS from a primary as a
with
the
way
we
're processing SUPER. A THIS from a primary as a
different form than a SUPER. Turn THIS into something symbolic */
different form than a SUPER. Turn THIS into something symbolic */
if (TREE_CODE (primary) ==
JAVA_
THIS_EXPR)
if (TREE_CODE (primary) == THIS_EXPR)
{
{
wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0);
wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0);
EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary);
EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary);
...
@@ -4880,7 +4994,7 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
...
@@ -4880,7 +4994,7 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
switch
(
TREE_CODE
(
qual_wfl
))
switch
(
TREE_CODE
(
qual_wfl
))
{
{
case
CALL_EXPR
:
case
CALL_EXPR
:
case
JAVA_
NEW_CLASS_EXPR
:
case
NEW_CLASS_EXPR
:
/*
If
the
access
to
the
function
call
is
a
non
static
field
,
/*
If
the
access
to
the
function
call
is
a
non
static
field
,
build
the
code
to
access
it
.
*/
build
the
code
to
access
it
.
*/
if
(
DECL_P
(
decl
)
&&
!FIELD_STATIC (decl))
if
(
DECL_P
(
decl
)
&&
!FIELD_STATIC (decl))
...
@@ -5027,7 +5141,10 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
...
@@ -5027,7 +5141,10 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
come. Don't do that when processing something after SUPER
come. Don't do that when processing something after SUPER
(we need more thing to be put in place below */
(we need more thing to be put in place below */
if (!from_super && QUAL_RESOLUTION (q))
if (!from_super && QUAL_RESOLUTION (q))
{
decl = QUAL_RESOLUTION (q);
decl = QUAL_RESOLUTION (q);
*type_found = type;
}
/* We have to search for a field, knowing the type of its
/* We have to search for a field, knowing the type of its
container. The flag FROM_TYPE indicates that we resolved
container. The flag FROM_TYPE indicates that we resolved
...
@@ -5108,7 +5225,6 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
...
@@ -5108,7 +5225,6 @@ resolve_qualified_expression_name (wfl, found_decl, where_found, type_found)
search from */
search from */
decl = field_decl;
decl = field_decl;
}
}
from_type = 0;
from_type = 0;
type = QUAL_DECL_TYPE (decl);
type = QUAL_DECL_TYPE (decl);
}
}
...
@@ -5540,7 +5656,8 @@ invocation_mode (method, super)
...
@@ -5540,7 +5656,8 @@ invocation_mode (method, super)
return INVOKE_VIRTUAL;
return INVOKE_VIRTUAL;
}
}
/* Retrieve a refined list of matching methods. */
/* Retrieve a refined list of matching methods. It covers the step
15.11.2 (Compile-Time Step 2) */
static tree
static tree
lookup_method_invoke (lc, cl, class, name, arg_list)
lookup_method_invoke (lc, cl, class, name, arg_list)
...
@@ -5551,22 +5668,22 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
...
@@ -5551,22 +5668,22 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
tree method = make_node (FUNCTION_TYPE);
tree method = make_node (FUNCTION_TYPE);
tree arg_type_list = NULL_TREE;
tree arg_type_list = NULL_TREE;
tree signature, list, node, scratch;
tree signature, list, node, scratch;
char *candidates; /* Used for error report */
for (node = arg_list; node; node = TREE_CHAIN (node))
for (node = arg_list; node; node = TREE_CHAIN (node))
{
{
tree current_arg;
tree current_arg = TREE_TYPE (TREE_VALUE (node));
current_arg =
if (TREE_CODE (current_arg) == RECORD_TYPE)
build_tree_list (NULL_TREE,
current_arg = promote_type (current_arg);
promote_type (TREE_TYPE (TREE_VALUE (node))));
arg_type_list = tree_cons (NULL_TREE, current_arg, arg_type_list);
arg_type_list = chainon (current_arg, arg_type_list);
}
}
TYPE_ARG_TYPES (method) = arg_type_list;
TYPE_ARG_TYPES (method) = arg_type_list;
if (!lc)
if (!lc)
{
{
signature = build_java_argument_signature (method);
list = find_applicable_accessible_methods_list (class, name,
list = match_java_method (class, name, signature
);
arg_type_list
);
list =
refine_accessible_methods_list (lc,
list);
list =
find_most_specific_methods_list (
list);
}
}
else
else
{
{
...
@@ -5575,132 +5692,181 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
...
@@ -5575,132 +5692,181 @@ lookup_method_invoke (lc, cl, class, name, arg_list)
list = lookup_java_constructor (class, signature);
list = lookup_java_constructor (class, signature);
}
}
if (!list)
if (lc && list)
{
parse_error_context (cl, "
Can
't find method `%s(%s)'
in
class
`%
s
'",
IDENTIFIER_POINTER (name),
IDENTIFIER_POINTER (signature),
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))));
return NULL_TREE;
}
if (lc)
return list;
return list;
if (list && !TREE_CHAIN (list))
return TREE_VALUE (list);
if (TREE_CHAIN (list))
/* Issue an error. List candidates if any. Candidates are listed
only if accessible (non accessible methods may end-up here for
the sake of a better error report). */
candidates = NULL;
if (list)
{
{
tree most_specific_list = NULL_TREE;
tree current;
tree current;
/* 15.11.2.2 Choose the Most Specific Method */
obstack_grow (&temporary_obstack, "
.
Candidates
are
:\
n
", 18);
for (current = list; current; current = TREE_CHAIN (current))
for (current = list; current; current = TREE_CHAIN (current))
{
{
tree rest;
tree cm = TREE_VALUE (current);
tree method = TREE_VALUE (list);
char string [4096];
tree class_from = DECL_CONTEXT (method);
if (!cm || not_accessible_p (class, cm, 0))
for (rest = TREE_CHAIN (current); rest; rest = TREE_CHAIN (rest))
continue;
{
signature = build_java_argument_signature (TREE_TYPE (cm));
tree other = TREE_VALUE (rest);
sprintf
(string, "
`%
s
(%
s
)
' in `%s'
%
s
",
/* METHOD can be declared more specific with regard to OTHER iif:
IDENTIFIER_POINTER (name),
IDENTIFIER_POINTER (signature),
- The class METHOD belongs can be converted to the
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (cm)))),
class OTHER belongs by method invocation conversion
(TREE_CHAIN (current) ? "
\
n
" : ""));
(5.3). Since we'
re
dealing
with
classes
here
,
it
is
obstack_grow (&temporary_obstack, string, strlen (string));
covered
by
the
identity
conversion
or
the
windening
primitive
conversion
.
-
The
types
of
the
arguments
of
METHOD
can
be
converted
to
the
types
of
the
arguments
of
OTHER
by
method
invocation
conversion
(
5.3
).
*/
if
(
valid_ref_assignconv_cast_p
(
class_from
,
DECL_CONTEXT
(
other
),
0
)
&&
1
)
/*
Test
on
args
non
implemented
*/
most_specific_list
=
tree_cons
(
NULL_TREE
,
method
,
most_specific_list
);
}
}
}
list
=
most_specific_list
;
obstack_1grow (&temporary_obstack, '
\0'
);
candidates = obstack_finish (&temporary_obstack);
}
}
/* Issue the error message */
if
(
!list || TREE_CHAIN (list))
signature = build_java_argument_signature (method);
{
parse_error_context (cl, "
Can
't find method `%s(%s)'
in
class
`%
s
'%s",
parse_error_context
(
cl
,
"Can't find method `%s(%s)' in class `%s'"
,
IDENTIFIER_POINTER (name),
IDENTIFIER_POINTER (name),
IDENTIFIER_POINTER (signature),
IDENTIFIER_POINTER (signature),
IDENTIFIER_POINTER
(
DECL_NAME
(
TYPE_NAME
(
class
))));
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))),
(candidates ? candidates : ""));
return NULL_TREE;
return NULL_TREE;
}
}
/* 15.11.2.1: Find Methods that are Applicable and Accessible */
static tree
find_applicable_accessible_methods_list (class, name, arglist)
tree class, name, arglist;
{
tree method;
tree list = NULL_TREE, all_list = NULL_TREE;
while (class != NULL_TREE)
{
for (method = TYPE_METHODS (class);
method != NULL_TREE; method = TREE_CHAIN (method))
{
/* Names have to match and we'
re
not
looking
for
constructor
*/
if
(
DECL_NAME
(
method
)
!= name
||
DECL_CONSTRUCTOR_P
(
method
))
continue
;
/*
15.11.3
Is
the
Chosen
Method
Appropriate
?
*/
if
(
argument_types_convertible
(
method
,
arglist
))
{
/*
Retain
accessible
methods
only
*/
if
(
!not_accessible_p (class, method, 0))
list
=
tree_cons
(
NULL_TREE
,
method
,
list
);
else
else
return
TREE_VALUE
(
list
);
/*
Also
retain
all
selected
method
here
*/
all_list
=
tree_cons
(
NULL_TREE
,
method
,
list
);
}
}
class
=
CLASSTYPE_SUPER
(
class
);
}
/*
Either
return
the
list
obtained
or
all
selected
(
but
inaccessible
)
methods
for
better
error
report
.
*/
return
(
!list ? all_list : list);
}
}
/*
Refine
accessible
methods
from
the
raw
matching
method
list
,
as
/*
15.11.2.2
Choose
the
Most
Specific
Method
*/
specified
in
15.11.4.3
.
Return
a
(
possibly
empty
)
new
method
list
.
*/
static
tree
static
tree
refine_accessible_methods_list
(
lc
,
list
)
find_most_specific_methods_list
(
list
)
int
lc
;
/*
Looking
for
Constructor
*/
tree
list
;
tree
list
;
{
{
#
define
ADD_TO_LIST_AND_CONTINUE
\
int
max
=
0
;
{
\
tree
current
,
new_list
=
NULL_TREE
;
refined_list
=
tree_cons
(
NULL_TREE
,
method
,
refined_list
);
\
for
(
current
=
list
;
current
;
current
=
TREE_CHAIN
(
current
))
continue
;
\
{
}
tree
method
;
tree
node
,
refined_list
=
NULL_TREE
;
DECL_SPECIFIC_COUNT
(
TREE_VALUE
(
current
))
=
0
;
tree
current_class_name
=
DECL_NAME
(
TYPE_NAME
(
current_class
));
for
(
node
=
list
;
node
;
node
=
TREE_CHAIN
(
node
))
for
(
method
=
list
;
method
;
method
=
TREE_CHAIN
(
method
))
{
{
int
access
,
identical
;
/*
Don
't test a method against itself */
tree
class_from
,
method
,
class_from_name
;
if (method == current)
continue;
/* Compare arguments and location where method where declared */
if (argument_types_convertible (TREE_VALUE (method),
TREE_VALUE (current))
&& valid_method_invocation_conversion_p
(DECL_CONTEXT (TREE_VALUE (method)),
DECL_CONTEXT (TREE_VALUE (current))))
{
int v = ++DECL_SPECIFIC_COUNT (TREE_VALUE (current));
max = (v > max ? v : max);
}
}
}
/* Review the list and select the maximally specific methods */
for (current = list; current; current = TREE_CHAIN (current))
if (DECL_SPECIFIC_COUNT (TREE_VALUE (current)) == max)
new_list = tree_cons (NULL_TREE, TREE_VALUE (current), new_list);
method
=
TREE_VALUE
(
node
);
/* If we can'
t
find
one
,
lower
expectations
and
try
to
gather
multiple
maximally
specific
methods
*/
while
(
!new_list)
{
while
(--
max
>
0
)
{
if
(
DECL_SPECIFIC_COUNT
(
TREE_VALUE
(
current
))
==
max
)
new_list
=
tree_cons
(
NULL_TREE
,
TREE_VALUE
(
current
),
new_list
);
}
return
new_list
;
}
/*
Constructor
not
retained
here
,
unless
were
specifically
return
new_list
;
looking
for
them
.
*/
}
if
(
lc
&&
DECL_CONSTRUCTOR_P
(
method
))
ADD_TO_LIST_AND_CONTINUE
;
access
=
get_access_flags_from_decl
(
method
);
/*
Make
sure
that
the
type
of
each
M2_OR_ARGLIST
arguments
can
be
class_from
=
DECL_CONTEXT
(
method
);
converted
by
method
invocation
conversion
(
5.3
)
to
the
type
of
the
class_from_name
=
DECL_NAME
(
TYPE_NAME
(
class_from
));
corresponding
parameter
of
M1
.
Implementation
expects
M2_OR_ARGLIST
to
change
less
often
than
M1
.
*/
identical
=
identical_subpath_p
(
current_class_name
,
class_from_name
);
static
int
argument_types_convertible
(
m1
,
m2_or_arglist
)
tree
m1
,
m2_or_arglist
;
{
static
tree
m2_arg_value
=
NULL_TREE
;
static
tree
m2_arg_cache
=
NULL_TREE
;
/*
Check
accessibility
of
class_from
from
the
current
one
:
This
register
tree
m1_arg
,
m2_arg
;
test
has
been
already
carried
out
when
qualify_ambiguous_name
tried
to
resolve
a
type
found
in
an
other
package
.
It
is
not
necessary
to
retest
things
here
,
the
error
has
been
already
reported
.
*/
/*
Public
method
are
always
OK
*/
m1_arg
=
TYPE_ARG_TYPES
(
TREE_TYPE
(
m1
));
if
(
access
&
ACC_PUBLIC
)
if
(
!METHOD_STATIC (m1)
)
ADD_TO_LIST_AND_CONTINUE
;
m1_arg
=
TREE_CHAIN
(
m1_arg
)
;
/*
Protected
method
access
is
OK
if
classes
are
from
the
if
(
m2_arg_value
==
m2_or_arglist
)
same
package
or
part
of
the
same
inheritance
lineage
*/
m2_arg
=
m2_arg_cache
;
if
((
access
&
ACC_PROTECTED
)
else
&&
(
inherits_from_p
(
current_class
,
class_from
)
||
identical
))
{
ADD_TO_LIST_AND_CONTINUE
;
/*
M2_OR_ARGLIST
can
be
a
function
DECL
or
a
raw
list
of
argument
types
*/
if
(
m2_or_arglist
&&
TREE_CODE
(
m2_or_arglist
)
==
FUNCTION_DECL
)
{
m2_arg
=
TYPE_ARG_TYPES
(
TREE_TYPE
(
m2_or_arglist
));
if
(
!METHOD_STATIC (m2_or_arglist))
m2_arg
=
TREE_CHAIN
(
m2_arg
);
}
else
m2_arg
=
m2_or_arglist
;
/*
Methods
with
default
(
package
)
access
are
OK
if
classes
are
m2_arg_value
=
m2_or_arglist
;
from
the
same
default
package
.
*/
m2_arg_cache
=
m2_arg
;
if
(
identical
||
}
(
!QUALIFIED_P (class_from_name) && !QUALIFIED_P (current_class_name)))
ADD_TO_LIST_AND_CONTINUE
;
/*
Private
method
accessible
iff
current
class
is
the
node
where
while
(
m1_arg
&&
m2_arg
)
the
method
is
defined
*/
{
if
((
access
&
ACC_PRIVATE
)
&&
(
class_from
==
current_class
))
if
(
!valid_method_invocation_conversion_p (TREE_VALUE (m1_arg),
ADD_TO_LIST_AND_CONTINUE
;
TREE_VALUE
(
m2_arg
)))
break
;
m1_arg
=
TREE_CHAIN
(
m1_arg
);
m2_arg
=
TREE_CHAIN
(
m2_arg
);
}
}
#
undef
ADD_TO_LIST_AND_CONTINUE
return
(
!m1_arg && !m2_arg ? 1 : 0);
return
refined_list
;
}
}
/*
Qualification
routines
*/
/*
Qualification
routines
*/
...
@@ -5738,7 +5904,7 @@ qualify_ambiguous_name (id)
...
@@ -5738,7 +5904,7 @@ qualify_ambiguous_name (id)
qual_wfl
=
QUAL_WFL
(
qual
);
qual_wfl
=
QUAL_WFL
(
qual
);
}
}
break
;
break
;
case
JAVA_
NEW_CLASS_EXPR
:
case
NEW_CLASS_EXPR
:
case
CONVERT_EXPR
:
case
CONVERT_EXPR
:
case
ARRAY_REF
:
case
ARRAY_REF
:
qual_wfl
=
TREE_OPERAND
(
qual_wfl
,
0
);
qual_wfl
=
TREE_OPERAND
(
qual_wfl
,
0
);
...
@@ -5908,10 +6074,10 @@ java_complete_tree (node)
...
@@ -5908,10 +6074,10 @@ java_complete_tree (node)
tree
node
;
tree
node
;
{
{
tree
nn
,
cn
,
wfl_op1
,
wfl_op2
;
tree
nn
,
cn
,
wfl_op1
,
wfl_op2
;
int
flag
,
location
;
int
flag
;
/*
CONVERT_EXPR
always
has
its
type
set
,
even
though
it
needs
to
be
/*
CONVERT_EXPR
always
has
its
type
set
,
even
though
it
needs
to
be
worked
out
*/
worked
out
.
*/
if
(
TREE_TYPE
(
node
)
&&
TREE_CODE
(
node
)
!= CONVERT_EXPR)
if
(
TREE_TYPE
(
node
)
&&
TREE_CODE
(
node
)
!= CONVERT_EXPR)
return
node
;
return
node
;
...
@@ -5946,6 +6112,10 @@ java_complete_tree (node)
...
@@ -5946,6 +6112,10 @@ java_complete_tree (node)
break
;
break
;
/*
2
-
They
are
expressions
but
ultimately
deal
with
statements
*/
/*
2
-
They
are
expressions
but
ultimately
deal
with
statements
*/
case
TRY_EXPR
:
return
patch_try_statement
(
node
);
case
LABELED_BLOCK_EXPR
:
case
LABELED_BLOCK_EXPR
:
PUSH_LABELED_BLOCK
(
node
);
PUSH_LABELED_BLOCK
(
node
);
if
(
LABELED_BLOCK_BODY
(
node
))
if
(
LABELED_BLOCK_BODY
(
node
))
...
@@ -5959,14 +6129,21 @@ java_complete_tree (node)
...
@@ -5959,14 +6129,21 @@ java_complete_tree (node)
the
EXIT_BLOCK_EXPR
which
doesn
't exist it Java */
the
EXIT_BLOCK_EXPR
which
doesn
't exist it Java */
return patch_bc_statement (node);
return patch_bc_statement (node);
case SWITCH_EXPR:
case LOOP_EXPR:
case LOOP_EXPR:
PUSH_LOOP (node);
PUSH_LOOP (node);
/* Check whether the loop was enclosed in a labeled
/* Check whether the loop was enclosed in a labeled
statement. If not, create one, insert the loop in it and
statement. If not, create one, insert the loop in it and
return the node */
return the node */
nn = patch_loop_statement (node);
nn = patch_loop_statement (node);
/* Anyways, walk the body of the loop */
/* Anyways, walk the body of the loop */
if (TREE_CODE (node) == LOOP_EXPR)
TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0));
TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0));
/* Switch statement: walk the switch expression and the cases */
else
node = patch_switch_statement (node);
if (TREE_OPERAND (node, 0) == error_mark_node)
if (TREE_OPERAND (node, 0) == error_mark_node)
return error_mark_node;
return error_mark_node;
TREE_TYPE (nn) = TREE_TYPE (node) = void_type_node;
TREE_TYPE (nn) = TREE_TYPE (node) = void_type_node;
...
@@ -6028,7 +6205,7 @@ java_complete_tree (node)
...
@@ -6028,7 +6205,7 @@ java_complete_tree (node)
}
}
break
;
break
;
case
JAVA_
NEW_ARRAY_EXPR
:
case
NEW_ARRAY_EXPR
:
/*
Patch
all
the
dimensions
*/
/*
Patch
all
the
dimensions
*/
flag
=
0
;
flag
=
0
;
for
(
cn
=
TREE_OPERAND
(
node
,
1
);
cn
;
cn
=
TREE_CHAIN
(
cn
))
for
(
cn
=
TREE_OPERAND
(
node
,
1
);
cn
;
cn
=
TREE_CHAIN
(
cn
))
...
@@ -6054,9 +6231,9 @@ java_complete_tree (node)
...
@@ -6054,9 +6231,9 @@ java_complete_tree (node)
were
found
.
*/
were
found
.
*/
return
(
flag
?
error_mark_node
:
patch_newarray
(
node
));
return
(
flag
?
error_mark_node
:
patch_newarray
(
node
));
case
JAVA_
NEW_CLASS_EXPR
:
case
NEW_CLASS_EXPR
:
case
CALL_EXPR
:
case
CALL_EXPR
:
/*
Complete
function
's argument first */
/*
Complete
function
's argument
(s)
first */
if (complete_function_arguments (node))
if (complete_function_arguments (node))
return error_mark_node;
return error_mark_node;
else
else
...
@@ -6102,6 +6279,12 @@ java_complete_tree (node)
...
@@ -6102,6 +6279,12 @@ java_complete_tree (node)
return
error_mark_node
;
return
error_mark_node
;
}
}
TREE_OPERAND
(
node
,
1
)
=
nn
;
TREE_OPERAND
(
node
,
1
)
=
nn
;
/*
In
case
we
're handling = with a String as a RHS, we need to
produce a String out of the RHS (it might still be a
STRING_CST or a StringBuffer at this stage */
if ((nn = patch_string (TREE_OPERAND (node, 1))))
TREE_OPERAND (node, 1) = nn;
return patch_assignment (node, wfl_op1, wfl_op2);
return patch_assignment (node, wfl_op1, wfl_op2);
case MULT_EXPR:
case MULT_EXPR:
...
@@ -6127,15 +6310,23 @@ java_complete_tree (node)
...
@@ -6127,15 +6310,23 @@ java_complete_tree (node)
knows how to handle those cases. */
knows how to handle those cases. */
wfl_op1 = TREE_OPERAND (node, 0);
wfl_op1 = TREE_OPERAND (node, 0);
wfl_op2 = TREE_OPERAND (node, 1);
wfl_op2 = TREE_OPERAND (node, 1);
/* Don'
t
complete
string
nodes
if
dealing
with
the
PLUS
operand
.
*/
if
(
TREE_CODE
(
node
)
!= PLUS_EXPR || !JSTRING_P (wfl_op1))
{
TREE_OPERAND
(
node
,
0
)
=
java_complete_tree
(
wfl_op1
);
TREE_OPERAND
(
node
,
0
)
=
java_complete_tree
(
wfl_op1
);
if
(
TREE_OPERAND
(
node
,
0
)
==
error_mark_node
)
if
(
TREE_OPERAND
(
node
,
0
)
==
error_mark_node
)
return
error_mark_node
;
return
error_mark_node
;
}
if
(
TREE_CODE
(
node
)
!= PLUS_EXPR || !JSTRING_P (wfl_op2))
{
TREE_OPERAND
(
node
,
1
)
=
java_complete_tree
(
wfl_op2
);
TREE_OPERAND
(
node
,
1
)
=
java_complete_tree
(
wfl_op2
);
if
(
TREE_OPERAND
(
node
,
1
)
==
error_mark_node
)
if
(
TREE_OPERAND
(
node
,
1
)
==
error_mark_node
)
return
error_mark_node
;
return
error_mark_node
;
}
return
patch_binop
(
node
,
wfl_op1
,
wfl_op2
);
return
patch_binop
(
node
,
wfl_op1
,
wfl_op2
);
case
JAVA_
UNARY_PLUS_EXPR
:
case
UNARY_PLUS_EXPR
:
case
NEGATE_EXPR
:
case
NEGATE_EXPR
:
case
TRUTH_NOT_EXPR
:
case
TRUTH_NOT_EXPR
:
case
BIT_NOT_EXPR
:
case
BIT_NOT_EXPR
:
...
@@ -6159,14 +6350,17 @@ java_complete_tree (node)
...
@@ -6159,14 +6350,17 @@ java_complete_tree (node)
TREE_OPERAND
(
node
,
0
)
=
java_complete_tree
(
wfl_op1
);
TREE_OPERAND
(
node
,
0
)
=
java_complete_tree
(
wfl_op1
);
if
(
TREE_OPERAND
(
node
,
0
)
==
error_mark_node
)
if
(
TREE_OPERAND
(
node
,
0
)
==
error_mark_node
)
return
error_mark_node
;
return
error_mark_node
;
if
(
!flag_emit_class_files)
TREE_OPERAND
(
node
,
0
)
=
save_expr
(
TREE_OPERAND
(
node
,
0
));
/*
The
same
applies
to
wfl_op2
*/
/*
The
same
applies
to
wfl_op2
*/
wfl_op2
=
TREE_OPERAND
(
node
,
1
);
wfl_op2
=
TREE_OPERAND
(
node
,
1
);
TREE_OPERAND
(
node
,
1
)
=
java_complete_tree
(
wfl_op2
);
TREE_OPERAND
(
node
,
1
)
=
java_complete_tree
(
wfl_op2
);
if
(
TREE_OPERAND
(
node
,
1
)
==
error_mark_node
)
if
(
TREE_OPERAND
(
node
,
1
)
==
error_mark_node
)
return
error_mark_node
;
return
error_mark_node
;
TREE_OPERAND
(
node
,
1
)
=
save_expr
(
TREE_OPERAND
(
node
,
1
));
return
patch_array_ref
(
node
,
wfl_op1
,
wfl_op2
);
return
patch_array_ref
(
node
,
wfl_op1
,
wfl_op2
);
case
JAVA_
THIS_EXPR
:
case
THIS_EXPR
:
/*
Can
't use THIS in a static environment */
/*
Can
't use THIS in a static environment */
if (!current_this)
if (!current_this)
{
{
...
@@ -6178,16 +6372,12 @@ java_complete_tree (node)
...
@@ -6178,16 +6372,12 @@ java_complete_tree (node)
}
}
return current_this;
return current_this;
case STRING_CST:
/* Build the internal string representation */
push_obstacks (&permanent_obstack, &permanent_obstack);
node = get_identifier (TREE_STRING_POINTER (node));
location = alloc_name_constant (CONSTANT_String, node);
node = build_ref_from_constant_pool (location);
TREE_TYPE (node) = promote_type (string_type_node);
return node;
default:
default:
/* Ok: may be we have a STRING_CST or a crafted `StringBuffer'
and it's time to turn it into the appropriate String object
*/
if ((node = patch_string (node)))
return node;
fatal ("
No
case
for
tree
code
`%
s
' - java_complete_tree\n",
fatal ("
No
case
for
tree
code
`%
s
' - java_complete_tree\n",
tree_code_name [TREE_CODE (node)]);
tree_code_name [TREE_CODE (node)]);
}
}
...
@@ -6206,13 +6396,19 @@ complete_function_arguments (node)
...
@@ -6206,13 +6396,19 @@ complete_function_arguments (node)
for
(
cn
=
TREE_OPERAND
(
node
,
1
);
cn
;
cn
=
TREE_CHAIN
(
cn
))
for
(
cn
=
TREE_OPERAND
(
node
,
1
);
cn
;
cn
=
TREE_CHAIN
(
cn
))
{
{
tree
wfl
=
TREE_VALUE
(
cn
),
parm
;
tree
wfl
=
TREE_VALUE
(
cn
),
parm
,
temp
;
parm
=
java_complete_tree
(
wfl
);
parm
=
java_complete_tree
(
wfl
);
if
(
parm
==
error_mark_node
)
if
(
parm
==
error_mark_node
)
{
{
flag
=
1
;
flag
=
1
;
continue
;
continue
;
}
}
/*
If
have
a
string
literal
that
we
haven
't transformed yet or a
crafted string buffer, as a result of use of the the String
`+'
operator
.
Build
`
parm
.
toString
()
' and expand it. */
if ((temp = patch_string (parm)))
parm = TREE_VALUE (cn) = temp;
if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE)
if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE)
TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm);
TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm);
else
else
...
@@ -6250,25 +6446,31 @@ build_expr_block (body, decls)
...
@@ -6250,25 +6446,31 @@ build_expr_block (body, decls)
{
{
tree node = make_node (BLOCK);
tree node = make_node (BLOCK);
BLOCK_EXPR_DECLS (node) = decls;
BLOCK_EXPR_DECLS (node) = decls;
BLOCK_EXPR_BODY
(
body
)
;
BLOCK_EXPR_BODY (
node) = body
;
if (body)
if (body)
TREE_TYPE (node) = TREE_TYPE (body);
TREE_TYPE (node) = TREE_TYPE (body);
TREE_SIDE_EFFECTS (node) = 1;
TREE_SIDE_EFFECTS (node) = 1;
return node;
return node;
}
}
/*
Create
a
new
function
block
and
link
its
supercontext
to
the
/* Create a new function block and link it approriately to current
previous
block
.
The
current
function
DECL
is
used
as
supercontext
function block chain */
when
enter_block
is
called
for
the
first
time
for
a
given
function
.
The
current
function
body
(
DECL_FUNCTION_BODY
)
is
set
to
the
newly
created
block
.
*/
static
block_level
=
0
;
static tree
static tree
enter_block ()
enter_block ()
{
{
tree
b
=
build_expr_block
(
NULL_TREE
,
NULL_TREE
);
return (enter_a_block (build_expr_block (NULL_TREE, NULL_TREE)));
}
/* Link block B supercontext to the previous block. The current
function DECL is used as supercontext when enter_a_block is called
for the first time for a given function. The current function body
(DECL_FUNCTION_BODY) is set to be block B. */
static tree
enter_a_block (b)
tree b;
{
tree fndecl = current_function_decl;
tree fndecl = current_function_decl;
if (!DECL_FUNCTION_BODY (fndecl))
if (!DECL_FUNCTION_BODY (fndecl))
...
@@ -6342,7 +6544,7 @@ maybe_absorb_scoping_blocks ()
...
@@ -6342,7 +6544,7 @@ maybe_absorb_scoping_blocks ()
are building incomplete tree nodes and the patch_* functions that
are building incomplete tree nodes and the patch_* functions that
are completing them. */
are completing them. */
/*
Build
an
incomplete
CALL_EXPR
node
.
Encapsulate
it
within
a
WFL
*/
/* Build an incomplete CALL_EXPR node. */
static tree
static tree
build_method_invocation (name, args)
build_method_invocation (name, args)
...
@@ -6351,7 +6553,18 @@ build_method_invocation (name, args)
...
@@ -6351,7 +6553,18 @@ build_method_invocation (name, args)
{
{
tree call = build (CALL_EXPR, NULL_TREE, name, args, NULL_TREE);
tree call = build (CALL_EXPR, NULL_TREE, name, args, NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
TREE_SIDE_EFFECTS (call) = 1;
/*
Check
on
cases
where
NAME
isn
't a WFL. FIXME */
EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name);
return call;
}
/* Build an incomplete new xxx(...) node. */
static tree
build_new_invocation (name, args)
tree name, args;
{
tree call = build (NEW_CLASS_EXPR, NULL_TREE, name, args, NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name);
EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name);
return call;
return call;
}
}
...
@@ -6413,7 +6626,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
...
@@ -6413,7 +6626,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
tree wfl_op1;
tree wfl_op1;
tree wfl_op2;
tree wfl_op2;
{
{
tree rhs = TREE_OPERAND (node, 1);
tree rhs = TREE_OPERAND (node, 1)
, temp
;
tree lvalue = TREE_OPERAND (node, 0);
tree lvalue = TREE_OPERAND (node, 0);
tree lhs_type, rhs_type, new_rhs = NULL_TREE;
tree lhs_type, rhs_type, new_rhs = NULL_TREE;
int all_primitive;
int all_primitive;
...
@@ -6458,69 +6671,27 @@ patch_assignment (node, wfl_op1, wfl_op2)
...
@@ -6458,69 +6671,27 @@ patch_assignment (node, wfl_op1, wfl_op2)
}
}
rhs_type
=
TREE_TYPE
(
rhs
);
rhs_type
=
TREE_TYPE
(
rhs
);
/*
5.1
Try
the
assignment
conversion
for
builtin
type
.
*/
if
((
new_rhs
=
try_builtin_assignconv
(
wfl_op1
,
lhs_type
,
rhs
)))
;
/*
5.2
Begin
Assignment
conversion
*/
/*
5.2
If
it
failed
,
try
a
reference
conversion
*/
if
(
!new_rhs &&
/*
5.1.1
Try
Identity
Conversion
*/
(
new_rhs
=
try_reference_assignconv
(
lhs_type
,
rhs
)))
if
(
lhs_type
==
rhs_type
)
lhs_type
=
promote_type
(
rhs_type
);
new_rhs
=
rhs
;
/*
5.1.2
Try
Widening
Primitive
Conversion
*/
/*
15.25.2
If
we
have
a
compound
assignment
,
convert
RHS
into
the
all_primitive
=
JPRIMITIVE_TYPE_P
(
lhs_type
)
&&
JPRIMITIVE_TYPE_P
(
rhs_type
);
type
of
the
LHS
*/
if
(
all_primitive
&&
JINTEGRAL_TYPE_P
(
rhs_type
)
else
if
(
COMPOUND_ASSIGN_P
(
TREE_OPERAND
(
node
,
1
)))
&&
((
TYPE_PRECISION
(
rhs_type
)
<
TYPE_PRECISION
(
lhs_type
))
||
(
JFLOAT_TYPE_P
(
lhs_type
)
&&
TYPE_PRECISION
(
rhs_type
)
==
TYPE_PRECISION
(
lhs_type
))))
new_rhs
=
convert
(
lhs_type
,
rhs
);
else
if
(
all_primitive
&&
JFLOAT_TYPE_P
(
rhs_type
)
&&
(
TYPE_PRECISION
(
rhs_type
)
<
TYPE_PRECISION
(
lhs_type
)))
new_rhs
=
convert
(
lhs_type
,
rhs
);
new_rhs
=
convert
(
lhs_type
,
rhs
);
/*
Try
a
narrowing
primitive
conversion
:
/*
Explicit
cast
required
.
This
is
an
error
*/
-
expression
is
a
constant
expression
of
type
int
AND
if
(
!new_rhs)
-
variable
is
byte
,
short
or
char
AND
-
The
value
of
the
expression
is
representable
in
the
type
of
the
variable
*/
else
if
(
rhs_type
==
int_type_node
&&
TREE_CONSTANT
(
rhs
)
&&
(
lhs_type
==
byte_type_node
||
lhs_type
==
char_type_node
||
lhs_type
==
short_type_node
))
{
{
if
(
int_fits_type_p
(
rhs
,
lhs_type
))
char
*
t1
=
strdup
((
char
*)
lang_printable_name
(
TREE_TYPE
(
rhs
)));
new_rhs
=
convert
(
lhs_type
,
rhs
);
char
*
t2
=
strdup
((
char
*)
lang_printable_name
(
lhs_type
));
else
tree
wfl
;
parse_warning_context
char
operation
[
32
];
/*
Max
size
known
*/
(
wfl_op1
,
"Constant expression `%s' to wide for narrowing "
"primitive conversion to `%s'"
,
print_int_node
(
rhs
),
lang_printable_name
(
lhs_type
));
/*
Reported
a
warning
that
will
turn
into
an
error
further
down
,
so
we
don
't return */
}
/* 5.2 Try a reference conversion */
else if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type))
{
/* `null'
may
be
assigned
to
any
reference
type
*/
if
(
rhs
==
null_pointer_node
)
new_rhs
=
null_pointer_node
;
/*
Try
the
reference
assignment
conversion
*/
else
if
(
valid_ref_assignconv_cast_p
(
rhs_type
,
lhs_type
,
0
))
new_rhs
=
rhs
;
if
(
new_rhs
)
lhs_type
=
promote_type
(
rhs_type
);
}
/*
15.25.2
If
we
have
a
compound
assignment
,
convert
RHS
into
the
type
of
the
LHS
*/
else
if
(
COMPOUND_ASSIGN_P
(
TREE_OPERAND
(
node
,
1
)))
new_rhs
=
convert
(
lhs_type
,
rhs
);
/*
Explicit
cast
required
.
This
is
an
error
*/
if
(
!new_rhs)
{
char
*
t1
=
strdup
((
char
*)
lang_printable_name
(
TREE_TYPE
(
rhs
)));
char
*
t2
=
strdup
((
char
*)
lang_printable_name
(
lhs_type
));
tree
wfl
;
char
operation
[
32
];
/*
Max
size
known
*/
/*
If
the
assignment
is
part
of
a
declaration
,
we
use
the
WFL
of
/*
If
the
assignment
is
part
of
a
declaration
,
we
use
the
WFL
of
the
declared
variable
to
point
out
the
error
and
call
it
a
the
declared
variable
to
point
out
the
error
and
call
it
a
...
@@ -6546,7 +6717,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
...
@@ -6546,7 +6717,7 @@ patch_assignment (node, wfl_op1, wfl_op2)
}
}
parse_error_context
parse_error_context
(wfl, (!
can
_cast_to_p (rhs_type, lhs_type) ?
(wfl, (!
valid
_cast_to_p (rhs_type, lhs_type) ?
"Incompatible type for %s. Can'
t
convert
`%
s
' to `%s'
" :
"Incompatible type for %s. Can'
t
convert
`%
s
' to `%s'
" :
"
Incompatible
type
for
%
s
.
Explicit
cast
"
"
Incompatible
type
for
%
s
.
Explicit
cast
"
"
needed
to
convert
`%
s
' to `%s'
"), operation, t1, t2);
"
needed
to
convert
`%
s
' to `%s'
"), operation, t1, t2);
...
@@ -6576,25 +6747,103 @@ patch_assignment (node, wfl_op1, wfl_op2)
...
@@ -6576,25 +6747,103 @@ patch_assignment (node, wfl_op1, wfl_op2)
return node;
return node;
}
}
/* Check that SOURCE can be converted into DEST, at least with a
/* Check that type SOURCE can be cast into type DEST. If the cast
cast. If the convertion can't occur at all, return 0 otherwise
can't occur at all, return 0 otherwise 1. This function is used to
1. This function is used to produce accurate error messages on the
produce accurate error messages on the reasons why an assignment
reasons why an assignment failed. */
failed. */
static tree
try_reference_assignconv (lhs_type, rhs)
tree lhs_type, rhs;
{
tree new_rhs = NULL_TREE;
tree rhs_type = TREE_TYPE (rhs);
if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type))
{
/* `null' may be assigned to any reference type */
if (rhs == null_pointer_node)
new_rhs = null_pointer_node;
/* Try the reference assignment conversion */
else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0))
new_rhs = rhs;
/* This is a magic assignment that we process differently */
else if (rhs == soft_exceptioninfo_call_node)
new_rhs = rhs;
}
return new_rhs;
}
/* Check that RHS can be converted into LHS_TYPE by the assignment
conversion (5.2), for the cases of RHS being a builtin type. Return
NULL_TREE if the conversion fails or if because RHS isn't of a
builtin type. Return a converted RHS if the conversion is possible. */
static tree
try_builtin_assignconv (wfl_op1, lhs_type, rhs)
tree wfl_op1, lhs_type, rhs;
{
tree new_rhs = NULL_TREE;
tree rhs_type = TREE_TYPE (rhs);
/* 5.1.1 Try Identity Conversion,
5.1.2 Try Widening Primitive Conversion */
if (valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type))
new_rhs = convert (lhs_type, rhs);
/* Try a narrowing primitive conversion (5.1.3):
- expression is a constant expression of type int AND
- variable is byte, short or char AND
- The value of the expression is representable in the type of the
variable */
else if (rhs_type == int_type_node && TREE_CONSTANT (rhs)
&& (lhs_type == byte_type_node || lhs_type == char_type_node
|| lhs_type == short_type_node))
{
if (int_fits_type_p (rhs, lhs_type))
new_rhs = convert (lhs_type, rhs);
else if (wfl_op1) /* Might be called with a NULL */
parse_warning_context
(wfl_op1, "
Constant
expression
`%
s
' to wide for narrowing "
"primitive conversion to `%s'
",
print_int_node (rhs), lang_printable_name (lhs_type));
/* Reported a warning that will turn into an error further
down, so we don't return */
}
return new_rhs;
}
/* Return 1 if RHS_TYPE can be converted to LHS_TYPE by identity
conversion (5.1.1) or widening primitve conversion (5.1.2). Return
0 is the conversion test fails. This implements parts the method
invocation convertion (5.3). */
static int
static int
can_cast_to_p (source, dest)
valid_builtin_assignconv_identity_widening_p (lhs_type, rhs_type)
tree source;
tree lhs_type, rhs_type;
tree dest;
{
{
if (TREE_CODE (source) == POINTER_TYPE)
int all_primitive =
source = TREE_TYPE (source);
JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type);
if (TREE_CODE (dest) == POINTER_TYPE)
dest = TREE_TYPE (dest);
if (
TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE
)
if (
!all_primitive
)
return
valid_ref_assignconv_cast_p (source, dest, 1)
;
return
0
;
else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest))
if (lhs_type == rhs_type)
return 1;
/* byte, even if it's smaller than a char can't be converted into a
char. Short can't too, but the < test below takes care of that */
if (lhs_type == char_type_node && rhs_type == byte_type_node)
return 0;
if (JINTEGRAL_TYPE_P (rhs_type)
&& ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))
|| (JFLOAT_TYPE_P (lhs_type) &&
TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type))))
return 1;
else if (JFLOAT_TYPE_P (rhs_type)
&& (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)))
return 1;
return 1;
return 0;
return 0;
...
@@ -6644,7 +6893,7 @@ valid_ref_assignconv_cast_p (source, dest, cast)
...
@@ -6644,7 +6893,7 @@ valid_ref_assignconv_cast_p (source, dest, cast)
return dest == object_type_node;
return dest == object_type_node;
/* We're doing a cast. The cast is always valid is class
/* We're doing a cast. The cast is always valid is class
DEST is not final, otherwise, DEST must implement SOURCE */
DEST is not final, otherwise, DEST must implement SOURCE */
else if (!CLASS_FINAL (TYPE_NAME (
source
)))
else if (!CLASS_FINAL (TYPE_NAME (
dest
)))
return 1;
return 1;
else
else
return interface_of_p (source, dest);
return interface_of_p (source, dest);
...
@@ -6704,6 +6953,41 @@ valid_ref_assignconv_cast_p (source, dest, cast)
...
@@ -6704,6 +6953,41 @@ valid_ref_assignconv_cast_p (source, dest, cast)
return 0;
return 0;
}
}
static int
valid_cast_to_p (source, dest)
tree source;
tree dest;
{
if (TREE_CODE (source) == POINTER_TYPE)
source = TREE_TYPE (source);
if (TREE_CODE (dest) == POINTER_TYPE)
dest = TREE_TYPE (dest);
if (TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE)
return valid_ref_assignconv_cast_p (source, dest, 1);
else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest))
return 1;
return 0;
}
/* Method invocation conversion test. Return 1 if type SOURCE can be
converted to type DEST through the methond invocation conversion
process (5.3) */
static int
valid_method_invocation_conversion_p (dest, source)
tree dest, source;
{
return ((JPRIMITIVE_TYPE_P (source)
&& JPRIMITIVE_TYPE_P (dest)
&& valid_builtin_assignconv_identity_widening_p (dest, source))
|| (JREFERENCE_TYPE_P (source)
&& JREFERENCE_TYPE_P (dest)
&& valid_ref_assignconv_cast_p (source, dest, 0)));
}
/* Build an incomplete binop expression. */
/* Build an incomplete binop expression. */
static tree
static tree
...
@@ -6712,15 +6996,9 @@ build_binop (op, op_location, op1, op2)
...
@@ -6712,15 +6996,9 @@ build_binop (op, op_location, op1, op2)
int op_location;
int op_location;
tree op1, op2;
tree op1, op2;
{
{
tree wfl;
tree wfl, binop, merge;
/* URSHIFT_EXPR is not part of what GCC understands, we can't directly build
a node with it */
tree binop =
build ((op == URSHIFT_EXPR ? RSHIFT_EXPR : op), NULL_TREE, op1, op2);
if (op == URSHIFT_EXPR)
TREE_SET_CODE (binop, op);
binop = build (op, NULL_TREE, op1, op2);
TREE_SIDE_EFFECTS (binop) = 1;
TREE_SIDE_EFFECTS (binop) = 1;
/* Store the location of the operator, for better error report. The
/* Store the location of the operator, for better error report. The
string of the operator will be rebuild based on the OP value. */
string of the operator will be rebuild based on the OP value. */
...
@@ -6766,7 +7044,7 @@ operator_string (node)
...
@@ -6766,7 +7044,7 @@ operator_string (node)
case
GE_EXPR
:
BUILD_OPERATOR_STRING
(
">="
);
case
GE_EXPR
:
BUILD_OPERATOR_STRING
(
">="
);
case
LT_EXPR
:
BUILD_OPERATOR_STRING
(
"<"
);
case
LT_EXPR
:
BUILD_OPERATOR_STRING
(
"<"
);
case
LE_EXPR
:
BUILD_OPERATOR_STRING
(
"<="
);
case
LE_EXPR
:
BUILD_OPERATOR_STRING
(
"<="
);
case
JAVA_
UNARY_PLUS_EXPR
:
BUILD_OPERATOR_STRING
(
"+"
);
case
UNARY_PLUS_EXPR
:
BUILD_OPERATOR_STRING
(
"+"
);
case
NEGATE_EXPR
:
BUILD_OPERATOR_STRING
(
"-"
);
case
NEGATE_EXPR
:
BUILD_OPERATOR_STRING
(
"-"
);
case
TRUTH_NOT_EXPR
:
BUILD_OPERATOR_STRING
(
"!"
);
case
TRUTH_NOT_EXPR
:
BUILD_OPERATOR_STRING
(
"!"
);
case
BIT_NOT_EXPR
:
BUILD_OPERATOR_STRING
(
"~"
);
case
BIT_NOT_EXPR
:
BUILD_OPERATOR_STRING
(
"~"
);
...
@@ -6800,6 +7078,7 @@ patch_binop (node, wfl_op1, wfl_op2)
...
@@ -6800,6 +7078,7 @@ patch_binop (node, wfl_op1, wfl_op2)
tree op2_type = TREE_TYPE (op2);
tree op2_type = TREE_TYPE (op2);
tree prom_type;
tree prom_type;
int code = TREE_CODE (node);
int code = TREE_CODE (node);
/* If 1, tell the routine that we have to return error_mark_node
/* If 1, tell the routine that we have to return error_mark_node
after checking for the initialization of the RHS */
after checking for the initialization of the RHS */
int error_found = 0;
int error_found = 0;
...
@@ -6850,8 +7129,20 @@ patch_binop (node, wfl_op1, wfl_op2)
...
@@ -6850,8 +7129,20 @@ patch_binop (node, wfl_op1, wfl_op2)
/* 15.17 Additive Operators */
/* 15.17 Additive Operators */
case PLUS_EXPR: /* 15.17.1 String Concatenation Operator + */
case PLUS_EXPR: /* 15.17.1 String Concatenation Operator + */
if (JSTRING_TYPE_P (op1_type) || JSTRING_TYPE_P (op2_type))
fatal ("operator `+'
non
implemented
on
String
-
patch_binop
");
/* Operation is valid if either one argument is a string
constant, a String object or a StringBuffer crafted for the
purpose of the a previous usage of the String concatenation
operator */
if (TREE_CODE (op1) == STRING_CST
|| TREE_CODE (op2) == STRING_CST
|| JSTRING_TYPE_P (op1_type)
|| JSTRING_TYPE_P (op2_type)
|| IS_CRAFTED_STRING_BUFFER_P (op1)
|| IS_CRAFTED_STRING_BUFFER_P (op2))
return build_string_concatenation (op1, op2);
case MINUS_EXPR: /* 15.17.2 Additive Operators (+ and -) for
case MINUS_EXPR: /* 15.17.2 Additive Operators (+ and -) for
Numeric Types */
Numeric Types */
if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type))
if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type))
...
@@ -7002,7 +7293,7 @@ patch_binop (node, wfl_op1, wfl_op2)
...
@@ -7002,7 +7293,7 @@ patch_binop (node, wfl_op1, wfl_op2)
|| JREFERENCE_TYPE_P (op1_type)
|| JREFERENCE_TYPE_P (op1_type)
|| JREFERENCE_TYPE_P (op2_type))
|| JREFERENCE_TYPE_P (op2_type))
&& ((op1_type == op2_type)
&& ((op1_type == op2_type)
/*
The
should
use
a
can
_cast_to_p
()
*/
/* The
re should use a valid
_cast_to_p() */
))
))
; /* Nothing to do here */
; /* Nothing to do here */
...
@@ -7044,10 +7335,195 @@ patch_binop (node, wfl_op1, wfl_op2)
...
@@ -7044,10 +7335,195 @@ patch_binop (node, wfl_op1, wfl_op2)
return fold (node);
return fold (node);
}
}
/*
Build
an
incomplete
unary
operator
expression
.
Unary
`+
' node is
/* Concatenate the STRING_CST CSTE and STRING. When AFTER is a non
build as a CONV_EXPR, even though its tree code is overridden by a
zero value, the value of CSTE comes after the valude of STRING */
JAVA_UNARY_PLUS_EXPR that isn'
t
a
tree
code
,
to
differentiate
it
during
the
walk
.
*/
static tree
do_merge_string_cste (cste, string, string_len, after)
tree cste;
char *string;
int string_len, after;
{
int len = TREE_STRING_LENGTH (cste) + string_len;
char *old = TREE_STRING_POINTER (cste);
TREE_STRING_LENGTH (cste) = len;
TREE_STRING_POINTER (cste) = obstack_alloc (expression_obstack, len+1);
if (after)
{
strcpy (TREE_STRING_POINTER (cste), string);
strcat (TREE_STRING_POINTER (cste), old);
}
else
{
strcpy (TREE_STRING_POINTER (cste), old);
strcat (TREE_STRING_POINTER (cste), string);
}
return cste;
}
/* Tries to merge OP1 (a STRING_CST) and OP2 (if suitable). Return a
new STRING_CST on success, NULL_TREE on failure */
static tree
merge_string_cste (op1, op2, after)
tree op1, op2;
int after;
{
/* Handle two string constants right away */
if (TREE_CODE (op2) == STRING_CST)
return do_merge_string_cste (op1, TREE_STRING_POINTER (op2),
TREE_STRING_LENGTH (op2), after);
/* Reasonable integer constant can be treated right away */
if (TREE_CODE (op2) == INTEGER_CST && !TREE_CONSTANT_OVERFLOW (op2))
{
static char *boolean_true = "
true
";
static char *boolean_false = "
false
";
static char *null_pointer = "
null
";
char ch[3];
char *string;
if (op2 == boolean_true_node)
string = boolean_true;
else if (op2 == boolean_false_node)
string = boolean_false;
else if (op2 == null_pointer_node)
string = null_pointer;
else if (TREE_TYPE (op2) == char_type_node)
{
ch[0] = (char )TREE_INT_CST_LOW (op2);
ch[1] = '
\0'
;
string = ch;
}
else
string = print_int_node (op2);
return do_merge_string_cste (op1, string, strlen (string), after);
}
return NULL_TREE;
}
/* Tries to statically concatenate OP1 and OP2 if possible. Either one
has to be a STRING_CST and the other part must be a STRING_CST or a
INTEGRAL constant. Return a new STRING_CST if the operation
succeed, NULL_TREE otherwise.
If the case we want to optimize for space, we might want to return
NULL_TREE for each invocation of this routine. FIXME */
static tree
string_constant_concatenation (op1, op2)
tree op1, op2;
{
if (TREE_CODE (op1) == STRING_CST || (TREE_CODE (op2) == STRING_CST))
{
tree string, rest, result;
int invert;
string = (TREE_CODE (op1) == STRING_CST ? op1 : op2);
rest = (string == op1 ? op2 : op1);
invert = (string == op1 ? 0 : 1 );
/* Walk REST, only if it looks reasonable */
if (TREE_CODE (rest) != STRING_CST
&& !IS_CRAFTED_STRING_BUFFER_P (rest)
&& !JSTRING_TYPE_P (TREE_TYPE (rest))
&& TREE_CODE (rest) == EXPR_WITH_FILE_LOCATION)
{
rest = java_complete_tree (rest);
if (rest == error_mark_node)
return error_mark_node;
rest = fold (rest);
}
return merge_string_cste (string, rest, invert);
}
return NULL_TREE;
}
/* Implement the `+' operator. Does static optimization if possible,
otherwise create (if necessary) and append elements to a
StringBuffer. The StringBuffer will be carried around until it is
used for a function call or an assignment. Then toString() will be
called on it to turn it into a String object. */
static tree
build_string_concatenation (op1, op2)
tree op1, op2;
{
tree result;
/* Try to do some static optimization */
if ((result = string_constant_concatenation (op1, op2)))
return result;
/* If operands are string constant, turn then into object references */
if (TREE_CODE (op1) == STRING_CST)
op1 = patch_string_cst (op1);
if (TREE_CODE (op2) == STRING_CST)
op2 = patch_string_cst (op2);
/* If OP1 isn't already a StringBuffer, create and
initialize a new one */
if (!IS_CRAFTED_STRING_BUFFER_P (op1))
{
/* Two solutions here:
1) OP1 is a string reference, we call new StringBuffer(OP1)
2) Op2 is something else, we call new StringBuffer().append(OP1). */
if (JSTRING_TYPE_P (TREE_TYPE (op1)))
op1 = BUILD_STRING_BUFFER (op1);
else
{
tree aNew = BUILD_STRING_BUFFER (NULL_TREE);
op1 = make_qualified_primary (aNew, BUILD_APPEND (op1), 0);
}
}
/* No longer the last node holding a crafted StringBuffer */
IS_CRAFTED_STRING_BUFFER_P (op1) = 0;
/* Create a node for `{new...,xxx}.append (op2)' */
op1 = make_qualified_primary (op1, BUILD_APPEND (op2), 0);
/* Mark the last node holding a crafted StringBuffer */
IS_CRAFTED_STRING_BUFFER_P (op1) = 1;
return op1;
}
/* Patch the string node NODE. NODE can be a STRING_CST of a crafted
StringBuffer. If no string were found to be patched, return
NULL. */
static tree
patch_string (node)
tree node;
{
if (TREE_CODE (node) == STRING_CST)
return patch_string_cst (node);
else if (IS_CRAFTED_STRING_BUFFER_P (node))
{
tree invoke = build_method_invocation (wfl_to_string, NULL_TREE);
return java_complete_tree (make_qualified_primary (node, invoke, 0));
}
return NULL_TREE;
}
/* Build the internal representation of a string constant. */
static tree
patch_string_cst (node)
tree node;
{
int location;
push_obstacks (&permanent_obstack, &permanent_obstack);
node = get_identifier (TREE_STRING_POINTER (node));
location = alloc_name_constant (CONSTANT_String, node);
node = build_ref_from_constant_pool (location);
TREE_TYPE (node) = promote_type (string_type_node);
TREE_CONSTANT (node) = 1;
return node;
}
/* Build an incomplete unary operator expression. */
static tree
static tree
build_unaryop (op_token, op_location, op1)
build_unaryop (op_token, op_location, op1)
...
@@ -7058,7 +7534,7 @@ build_unaryop (op_token, op_location, op1)
...
@@ -7058,7 +7534,7 @@ build_unaryop (op_token, op_location, op1)
tree unaryop;
tree unaryop;
switch (op_token)
switch (op_token)
{
{
case
PLUS_TK
:
op
=
CONVERT
_EXPR
;
break
;
case PLUS_TK: op =
UNARY_PLUS
_EXPR; break;
case MINUS_TK: op = NEGATE_EXPR; break;
case MINUS_TK: op = NEGATE_EXPR; break;
case NEG_TK: op = TRUTH_NOT_EXPR; break;
case NEG_TK: op = TRUTH_NOT_EXPR; break;
case NOT_TK: op = BIT_NOT_EXPR; break;
case NOT_TK: op = BIT_NOT_EXPR; break;
...
@@ -7067,9 +7543,6 @@ build_unaryop (op_token, op_location, op1)
...
@@ -7067,9 +7543,6 @@ build_unaryop (op_token, op_location, op1)
}
}
unaryop = build1 (op, NULL_TREE, op1);
unaryop = build1 (op, NULL_TREE, op1);
if
(
op_token
==
PLUS_TK
)
TREE_SET_CODE
(
unaryop
,
JAVA_UNARY_PLUS_EXPR
);
TREE_SIDE_EFFECTS (unaryop) = 1;
TREE_SIDE_EFFECTS (unaryop) = 1;
/* Store the location of the operator, for better error report. The
/* Store the location of the operator, for better error report. The
string of the operator will be rebuild based on the OP value. */
string of the operator will be rebuild based on the OP value. */
...
@@ -7142,7 +7615,8 @@ patch_unaryop (node, wfl_op)
...
@@ -7142,7 +7615,8 @@ patch_unaryop (node, wfl_op)
case PREINCREMENT_EXPR:
case PREINCREMENT_EXPR:
/* 15.14.2 Prefix Decrement Operator -- */
/* 15.14.2 Prefix Decrement Operator -- */
case PREDECREMENT_EXPR:
case PREDECREMENT_EXPR:
if
(
!DECL_P (op))
if (!DECL_P (op) && !(TREE_CODE (op) == INDIRECT_REF
&& JPRIMITIVE_TYPE_P (TREE_TYPE (op))))
{
{
parse_error_context (wfl_operator, "Invalid argument to `%s'
",
parse_error_context (wfl_operator, "Invalid argument to `%s'
",
operator_string (node));
operator_string (node));
...
@@ -7181,7 +7655,7 @@ patch_unaryop (node, wfl_op)
...
@@ -7181,7 +7655,7 @@ patch_unaryop (node, wfl_op)
break;
break;
/* 15.14.3 Unary Plus Operator + */
/* 15.14.3 Unary Plus Operator + */
case
JAVA_
UNARY_PLUS_EXPR
:
case UNARY_PLUS_EXPR:
/* 15.14.4 Unary Minus Operator - */
/* 15.14.4 Unary Minus Operator - */
case NEGATE_EXPR:
case NEGATE_EXPR:
if (!JNUMERIC_TYPE_P (op_type))
if (!JNUMERIC_TYPE_P (op_type))
...
@@ -7195,7 +7669,7 @@ patch_unaryop (node, wfl_op)
...
@@ -7195,7 +7669,7 @@ patch_unaryop (node, wfl_op)
{
{
prom_type = promote_type (op_type);
prom_type = promote_type (op_type);
op = convert (prom_type, op);
op = convert (prom_type, op);
if
(
code
==
JAVA_
UNARY_PLUS_EXPR
)
if (code == UNARY_PLUS_EXPR)
node = op;
node = op;
}
}
break;
break;
...
@@ -7249,8 +7723,8 @@ patch_unaryop (node, wfl_op)
...
@@ -7249,8 +7723,8 @@ patch_unaryop (node, wfl_op)
if (error_found)
if (error_found)
return error_mark_node;
return error_mark_node;
/*
In
the
case
of
JAVA_
UNARY_PLUS_EXPR
,
we
replaced
NODE
by
a
new
one
*/
/* In the case of UNARY_PLUS_EXPR, we replaced NODE by a new one */
else
if
(
code
!=
JAVA_
UNARY_PLUS_EXPR && code != CONVERT_EXPR)
else if (code != UNARY_PLUS_EXPR && code != CONVERT_EXPR)
{
{
TREE_OPERAND (node, 0) = op;
TREE_OPERAND (node, 0) = op;
TREE_TYPE (node) = prom_type;
TREE_TYPE (node) = prom_type;
...
@@ -7316,7 +7790,7 @@ patch_cast (node, wfl_op, wfl_operator)
...
@@ -7316,7 +7790,7 @@ patch_cast (node, wfl_op, wfl_operator)
/* The remaining legal casts involve conversion between reference
/* The remaining legal casts involve conversion between reference
types. Check for their compile time correctness. */
types. Check for their compile time correctness. */
if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type)
if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type)
&&
valid_ref_assignconv_cast_p
(
op_type
,
cast
_type
,
1
))
&& valid_ref_assignconv_cast_p (
cast_type, op
_type, 1))
{
{
TREE_TYPE (node) = promote_type (cast_type);
TREE_TYPE (node) = promote_type (cast_type);
/* Now, the case can be determined correct at compile time if
/* Now, the case can be determined correct at compile time if
...
@@ -7374,8 +7848,6 @@ patch_array_ref (node, wfl_array, wfl_index)
...
@@ -7374,8 +7848,6 @@ patch_array_ref (node, wfl_array, wfl_index)
ERROR_VARIABLE_NOT_INITIALIZED
(
wfl_array
,
DECL_NAME
(
array
));
ERROR_VARIABLE_NOT_INITIALIZED
(
wfl_array
,
DECL_NAME
(
array
));
INITIALIZED_P
(
array
)
=
1
;
INITIALIZED_P
(
array
)
=
1
;
}
}
if (! flag_emit_class_files)
array = save_expr (array);
if
(
TREE_CODE
(
array_type
)
==
POINTER_TYPE
)
if
(
TREE_CODE
(
array_type
)
==
POINTER_TYPE
)
array_type
=
TREE_TYPE
(
array_type
);
array_type
=
TREE_TYPE
(
array_type
);
...
@@ -7395,7 +7867,7 @@ patch_array_ref (node, wfl_array, wfl_index)
...
@@ -7395,7 +7867,7 @@ patch_array_ref (node, wfl_array, wfl_index)
promoted_index_type
=
promote_type
(
index_type
);
promoted_index_type
=
promote_type
(
index_type
);
if
(
promoted_index_type
!= int_type_node)
if
(
promoted_index_type
!= int_type_node)
{
{
int could_cast =
can
_cast_to_p (index_type, int_type_node);
int
could_cast
=
valid
_cast_to_p
(
index_type
,
int_type_node
);
parse_error_context
parse_error_context
(
wfl_operator
,
(
wfl_operator
,
(
could_cast
?
"Incompatible type for `[]'. Explicit cast needed to "
(
could_cast
?
"Incompatible type for `[]'. Explicit cast needed to "
...
@@ -7439,9 +7911,8 @@ build_newarray_node (type, dims, extra_dims)
...
@@ -7439,9 +7911,8 @@ build_newarray_node (type, dims, extra_dims)
int
extra_dims
;
int
extra_dims
;
{
{
tree
node
=
tree
node
=
build (
CALL
_EXPR, NULL_TREE, type, nreverse (dims),
build
(
NEW_ARRAY
_EXPR
,
NULL_TREE
,
type
,
nreverse
(
dims
),
build_int_2
(
extra_dims
,
0
));
build_int_2
(
extra_dims
,
0
));
TREE_SET_CODE (node, JAVA_NEW_ARRAY_EXPR);
return
node
;
return
node
;
}
}
...
@@ -7487,7 +7958,7 @@ patch_newarray (node)
...
@@ -7487,7 +7958,7 @@ patch_newarray (node)
(TREE_PURPOSE (cdim),
(TREE_PURPOSE (cdim),
"Incompatible type for dimension in array creation expression. "
"Incompatible type for dimension in array creation expression. "
"%s convert `%s'
to
`
int
'",
"%s convert `%s'
to
`
int
'",
(
can
_cast_to_p
(
TREE_TYPE
(
dim
),
int_type_node
)
?
(
valid
_cast_to_p (TREE_TYPE (dim), int_type_node) ?
"Explicit cast needed to" : "Can'
t
"),
"Explicit cast needed to" : "Can'
t
"),
lang_printable_name (TREE_TYPE (dim)));
lang_printable_name (TREE_TYPE (dim)));
error_found = 1;
error_found = 1;
...
@@ -7578,7 +8049,7 @@ build_this (location)
...
@@ -7578,7 +8049,7 @@ build_this (location)
int location;
int location;
{
{
tree node = build_wfl_node (this_identifier_node, input_filename, 0, 0);
tree node = build_wfl_node (this_identifier_node, input_filename, 0, 0);
TREE_SET_CODE (node,
JAVA_
THIS_EXPR);
TREE_SET_CODE (node, THIS_EXPR);
EXPR_WFL_LINECOL (node) = location;
EXPR_WFL_LINECOL (node) = location;
return node;
return node;
}
}
...
@@ -7594,6 +8065,7 @@ build_return (location, op)
...
@@ -7594,6 +8065,7 @@ build_return (location, op)
{
{
tree node = build1 (RETURN_EXPR, NULL_TREE, op);
tree node = build1 (RETURN_EXPR, NULL_TREE, op);
EXPR_WFL_LINECOL (node) = location;
EXPR_WFL_LINECOL (node) = location;
node = build_debugable_stmt (location, node);
return node;
return node;
}
}
...
@@ -7663,6 +8135,7 @@ build_if_else_statement (location, expression, if_body, else_body)
...
@@ -7663,6 +8135,7 @@ build_if_else_statement (location, expression, if_body, else_body)
else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE);
else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE);
node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body);
node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body);
EXPR_WFL_LINECOL (node) = location;
EXPR_WFL_LINECOL (node) = location;
node = build_debugable_stmt (location, node);
return node;
return node;
}
}
...
@@ -7676,7 +8149,8 @@ patch_if_else_statement (node)
...
@@ -7676,7 +8149,8 @@ patch_if_else_statement (node)
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
/* The type of expression must be boolean */
/* The type of expression must be boolean */
if (TREE_TYPE (expression) != boolean_type_node)
if (TREE_TYPE (expression) != boolean_type_node
&& TREE_TYPE (expression) != promoted_boolean_type_node)
{
{
parse_error_context
parse_error_context
(wfl_operator,
(wfl_operator,
...
@@ -7734,17 +8208,10 @@ build_labeled_block (location, label, wfl)
...
@@ -7734,17 +8208,10 @@ build_labeled_block (location, label, wfl)
static
tree
static
tree
generate_labeled_block
()
generate_labeled_block
()
{
{
static int l_number = 0;
return
build_labeled_block
(
0
,
generate_name
(),
NULL_TREE
);
char buf [20];
tree label_name;
sprintf (buf, "
$
a
%
d
", l_number++);
return build_labeled_block (0, get_identifier (buf), NULL_TREE);
}
}
/* A labeled statement LBE is attached a statement. If the statement
/*
A
labeled
statement
LBE
is
attached
a
statement
.
*/
happens to be a loop, a link from the loop back to the label is
installed. */
static
tree
static
tree
complete_labeled_statement
(
lbe
,
statement
)
complete_labeled_statement
(
lbe
,
statement
)
...
@@ -7791,7 +8258,15 @@ build_new_loop (loop_body)
...
@@ -7791,7 +8258,15 @@ build_new_loop (loop_body)
INCREMENT
(
if
any
)
INCREMENT
(
if
any
)
REVERSED
,
if
non
zero
,
tells
that
the
loop
condition
expr
comes
REVERSED
,
if
non
zero
,
tells
that
the
loop
condition
expr
comes
after the body, like in the do-while loop. */
after
the
body
,
like
in
the
do
-
while
loop
.
To
obtain
a
loop
,
the
loop
body
structure
described
above
is
encapsulated
within
a
LOOP_EXPR
surrounded
by
a
LABELED_BLOCK_EXPR
:
LABELED_BLOCK_EXPR
LABEL_DECL
(
use
this
label
to
exit
the
loop
)
LOOP_EXPR
<
structure
described
above
>
*/
static
tree
static
tree
build_loop_body
(
location
,
condition
,
reversed
)
build_loop_body
(
location
,
condition
,
reversed
)
...
@@ -7912,6 +8387,7 @@ build_bc_statement (location, is_break, name)
...
@@ -7912,6 +8387,7 @@ build_bc_statement (location, is_break, name)
IS_BREAK_STMT_P (break_continue) = is_break;
IS_BREAK_STMT_P (break_continue) = is_break;
TREE_SIDE_EFFECTS (break_continue) = 1;
TREE_SIDE_EFFECTS (break_continue) = 1;
EXPR_WFL_LINECOL (break_continue) = location;
EXPR_WFL_LINECOL (break_continue) = location;
break_continue = build_debugable_stmt (location, break_continue);
return break_continue;
return break_continue;
}
}
...
@@ -7926,22 +8402,28 @@ patch_bc_statement (node)
...
@@ -7926,22 +8402,28 @@ patch_bc_statement (node)
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node);
/* Not having a target means that the break/continue statement is
/* Not having a target means that the break/continue statement is
unlabeled. We try to find a de
s
cent label for it */
unlabeled. We try to find a decent label for it */
if (!bc_label)
if (!bc_label)
{
{
is_unlabeled = 1;
is_unlabeled = 1;
/* There should be a loop to branch to */
/* There should be a loop
/switch
to branch to */
if (ctxp->current_loop)
if (ctxp->current_loop)
{
{
if (TREE_CODE (ctxp->current_loop) == LOOP_EXPR)
{
/* At that stage, we'
re
in
the
loop
body
,
which
is
/* At that stage, we'
re
in
the
loop
body
,
which
is
encapsulated
around
a
LABELED_BLOCK_EXPR
.
So
searching
encapsulated
around
a
LABELED_BLOCK_EXPR
.
So
searching
the
current
loop
label
requires
us
to
consider
the
the
current
loop
label
requires
us
to
consider
the
labeled
block
before
the
current
one
.
*/
labeled
block
before
the
current
one
.
*/
if
(
!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop))
if
(
!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop))
fatal ("
unlabeled
loop
has
not
installed
label
--
"
fatal
(
"unlabeled loop has no
installed label -- "
"patch_bc_statement"
);
"patch_bc_statement"
);
bc_label
=
TREE_CHAIN
(
ctxp
->
current_labeled_block
);
bc_label
=
TREE_CHAIN
(
ctxp
->
current_labeled_block
);
}
}
/*
For
a
SWITCH
statement
,
this
is
the
current
one
*/
else
bc_label
=
ctxp
->
current_labeled_block
;
}
/*
Not
having
a
loop
to
break
/
continue
to
is
an
error
*/
/*
Not
having
a
loop
to
break
/
continue
to
is
an
error
*/
else
else
{
{
...
@@ -7970,7 +8452,7 @@ patch_bc_statement (node)
...
@@ -7970,7 +8452,7 @@ patch_bc_statement (node)
while/do/for/switch */
while/do/for/switch */
if (is_unlabeled &&
if (is_unlabeled &&
!(TREE_CODE (target_stmt) == LOOP_EXPR /* do/while/for */
!(TREE_CODE (target_stmt) == LOOP_EXPR /* do/while/for */
||
0))
/* switch FIXME */
||
TREE_CODE (target_stmt) == SWITCH_EXPR))
/* switch FIXME */
{
{
parse_error_context (wfl_operator,
parse_error_context (wfl_operator,
"`break'
must
be
in
loop
or
switch
");
"`break'
must
be
in
loop
or
switch
");
...
@@ -8033,3 +8515,425 @@ patch_exit_expr (node)
...
@@ -8033,3 +8515,425 @@ patch_exit_expr (node)
TREE_TYPE
(
node
)
=
void_type_node
;
TREE_TYPE
(
node
)
=
void_type_node
;
return
node
;
return
node
;
}
}
/*
14.9
Switch
statement
*/
static
tree
patch_switch_statement
(
node
)
tree
node
;
{
int
error_found
=
0
;
tree
se
=
TREE_OPERAND
(
node
,
0
),
se_type
,
sb
;
tree
default_found
=
NULL_TREE
;
/*
Complete
the
switch
expression
*/
se
=
TREE_OPERAND
(
node
,
0
)
=
java_complete_tree
(
se
);
se_type
=
TREE_TYPE
(
se
);
/*
The
type
of
the
switch
expression
must
be
char
,
byte
,
short
or
int
*/
if
(
!JINTEGRAL_TYPE_P (se_type))
{
EXPR_WFL_LINECOL
(
wfl_operator
)
=
EXPR_WFL_LINECOL
(
node
);
parse_error_context
(
wfl_operator
,
"Incompatible type for `switch'. "
"Can't convert `%s' to `int'"
,
lang_printable_name
(
se_type
));
/*
This
is
what
java_complete_tree
will
check
*/
TREE_OPERAND
(
node
,
0
)
=
error_mark_node
;
return
error_mark_node
;
}
/*
Process
the
switch
body
.
We
should
have
a
list
of
TREE_LIST
.
The
PURPOSE
of
each
node
should
be
a
list
of
case
values
,
VALUE
should
be
the
associated
block
.
We
try
to
process
all
cases
and
defaults
before
returning
,
possibly
finding
errors
.
*/
TREE_OPERAND
(
node
,
1
)
=
nreverse
(
TREE_OPERAND
(
node
,
1
));
for
(
sb
=
TREE_OPERAND
(
node
,
1
);
sb
;
sb
=
TREE_CHAIN
(
sb
))
{
tree
label
;
/*
If
we
don
't have a TREE_LIST here, we have a statement inside
the switch that isn'
t
tied
to
a
label
.
This
error
is
caught
by
the
parser
and
we
don
't have to report it here. */
TREE_PURPOSE (sb) = nreverse (TREE_PURPOSE (sb));
for (label = TREE_PURPOSE (sb); label; label = TREE_CHAIN (label))
{
tree case_expr;
/* Verification of the default label */
if (TREE_CODE (label) == DEFAULT_EXPR)
{
/* Only one default label is allowed per switch
statement */
if (default_found)
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
parse_error_context (wfl_operator,
"Duplicate case label: `default'
");
error_found = 1;
}
else
default_found = label;
continue;
}
/* Verification of case labels */
else
{
case_expr = java_complete_tree (TREE_OPERAND (label, 0));
if (case_expr == error_mark_node)
continue;
/* First, the case expression must be constant */
case_expr = fold (case_expr);
if (!TREE_CONSTANT (case_expr))
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
parse_error_context (label, "
Constant
expression
required
");
error_found = 1;
break;
}
/* It must be assignable to the type of the switch
expression. */
if (!try_builtin_assignconv (NULL_TREE, se_type, case_expr))
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
parse_error_context
(wfl_operator,
"
Incompatible
type
for
case
.
Can
't convert `%s'
to
`
int
'",
lang_printable_name (TREE_TYPE (case_expr)));
error_found = 1;
break;
}
/* Multiple instance of a case label bearing the same
value is checked during code generation. The case
expression is allright so far. */
TREE_OPERAND (label, 0) = case_expr;
}
}
/* First TREE_VALUE should be the block tied to this list of
cases. Check that this block exists and the walk it */
if (TREE_VALUE (sb))
{
TREE_VALUE (sb) = java_complete_tree (TREE_VALUE (sb));
if (TREE_VALUE (sb) == error_mark_node)
error_found = 1;
}
}
/* Ready to return */
if (error_found)
{
TREE_TYPE (node) = error_mark_node;
return error_mark_node;
}
TREE_TYPE (node) = void_type_node;
TREE_SIDE_EFFECTS (node) = 1;
return node;
}
/* Do the expansion of a Java switch. With Gcc, switches are front-end
dependant things, but they rely on gcc routines. This function is
placed here because it uses things defined locally in parse.y. */
static tree
case_identity (t, v)
tree t, v;
{
return v;
}
void
java_expand_switch (exp)
tree exp;
{
tree sb;
expand_start_case (0, TREE_OPERAND (exp, 0), int_type_node, "switch");
for (sb = TREE_OPERAND (exp, 1); sb; sb = TREE_CHAIN (sb))
{
/* We have a list of TREE_LIST. PURPOSE is the case value, and
when it exists, VALUE is the associated block */
/* The first CASE element should contain the associated block,
if any. All other should be case statements related to the
same block */
tree label;
for (label = TREE_PURPOSE (sb); label; label = TREE_CHAIN (label))
{
tree label_decl = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
if (TREE_CODE (label) == CASE_EXPR)
{
tree duplicate;
if (pushcase (TREE_OPERAND (label, 0), case_identity,
label_decl, &duplicate) == 2)
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (label);
parse_error_context
(wfl_operator, "Duplicate case label: `%s'
",
print_int_node (TREE_OPERAND (label, 0)));
}
}
else
pushcase (NULL_TREE, 0, label_decl, NULL);
}
/* Expand the associated block, if any */
if (TREE_VALUE (sb))
expand_expr_stmt (TREE_VALUE (sb));
}
expand_end_case (TREE_OPERAND (exp, 0));
}
/* 14.18 The try statement */
/* Wrap BLOCK around a LABELED_BLOCK, set DECL to the newly generated
exit labeld and issue a jump to FINALLY_LABEL:
LABELED_BLOCK
BLOCK
<orignal_statments>
DECL = &LABEL_DECL
GOTO_EXPR
FINALLY_LABEL
LABEL_DECL */
static tree
build_jump_to_finally (block, decl, finally_label, type)
tree block, decl, finally_label, type;
{
tree stmt;
tree new_block = build (LABELED_BLOCK_EXPR, type,
create_label_decl (generate_name ()), block);
stmt = build (MODIFY_EXPR, void_type_node, decl,
build_address_of (LABELED_BLOCK_LABEL (new_block)));
TREE_SIDE_EFFECTS (stmt) = 1;
add_stmt_to_block (block, type, stmt);
stmt = build (GOTO_EXPR, void_type_node, finally_label);
TREE_SIDE_EFFECTS (stmt) = 1;
add_stmt_to_block (block, type, stmt);
return new_block;
}
static tree
build_try_statement (location, try_block, catches, finally)
int location;
tree try_block, catches, finally;
{
tree node, rff;
if (finally)
{
/* This block defines a scope for the entire try[-catch]-finally
sequence. It hold a local variable used to return from the
finally using a computed goto. We call it
return_from_finally (RFF). */
rff = build_decl_no_layout (VAR_DECL, generate_name (),
return_address_type_node);
/* Modification of the try block. */
try_block = build_jump_to_finally (try_block, rff,
FINALLY_EXPR_LABEL (finally),
NULL_TREE);
/* To the finally block: add the computed goto */
add_stmt_to_block (FINALLY_EXPR_BLOCK (finally), NULL_TREE,
build (GOTO_EXPR, void_type_node, rff));
/* Modification of each catch blocks, if any */
if (catches)
{
tree catch, catch_decl, catch_block, stmt;
for (catch = catches; catch; catch = TREE_CHAIN (catch))
TREE_OPERAND (catch, 0) =
build_jump_to_finally (TREE_OPERAND (catch, 0), rff,
FINALLY_EXPR_LABEL (finally),
NULL_TREE);
/* Plus, at the end of the list, we add the catch clause that
will catch an uncaught exception, call finally and rethrow it:
BLOCK
void *exception_parameter; (catch_decl)
LABELED_BLOCK
BLOCK
exception_parameter = _Jv_exception_info ();
RFF = &LABEL_DECL;
goto finally;
LABEL_DECL;
CALL_EXPR
Jv_ReThrow
exception_parameter */
catch_decl = build_decl_no_layout (VAR_DECL, generate_name (),
ptr_type_node);
stmt = build (MODIFY_EXPR, void_type_node, catch_decl,
soft_exceptioninfo_call_node);
TREE_SIDE_EFFECTS (stmt) = 1;
catch_block = build_expr_block (stmt, NULL_TREE);
catch_block = build_jump_to_finally (catch_block, rff,
FINALLY_EXPR_LABEL (finally),
void_type_node);
stmt = build (CALL_EXPR, void_type_node,
build_address_of (throw_node),
build_tree_list (NULL_TREE, catch_decl), NULL_TREE);
catch_block = build_expr_block (catch_block, catch_decl);
TREE_SIDE_EFFECTS (stmt) = 1;
add_stmt_to_block (catch_block, void_type_node, stmt);
/* Link the new handler to the existing list as the first
entry. It will be the last one to be generated. */
catch = build1 (CATCH_EXPR, void_type_node, catch_block);
TREE_CHAIN (catch) = catches;
catches = catch;
}
}
node = build (TRY_EXPR, NULL_TREE, try_block, catches, finally);
EXPR_WFL_LINECOL (node) = location;
/* If we have a finally, surround this whole thing by a block where
the RFF local variable is defined. */
return (finally ? build_expr_block (node, rff) : node);
}
/* Get the catch clause block from an element of the catch clause
list. If depends on whether a finally clause exists or node (in
which case the original catch clause was surrounded by a
LABELED_BLOCK_EXPR. */
tree
java_get_catch_block (node, finally_present_p)
tree node;
int finally_present_p;
{
return (CATCH_EXPR_GET_EXPR (TREE_OPERAND (node, 0), finally_present_p));
}
static tree
patch_try_statement (node)
tree node;
{
int error_found = 0;
tree try = TREE_OPERAND (node, 0);
/* Exception handlers are considered in left to right order */
tree catch = nreverse (TREE_OPERAND (node, 1));
tree finally = TREE_OPERAND (node, 2);
int finally_p = (finally ? 1 : 0);
tree current;
/* Walk the try block */
if ((try = java_complete_tree (try)) == error_mark_node)
error_found = 1;
/* Check catch clauses, if any. Every time we find an error, we try
to process the next catch clause. */
for (current = catch; current; current = TREE_CHAIN (current))
{
tree carg_decl, carg_type;
tree sub_current, catch_block, catch_clause;
int unreachable;
/* Always detect the last catch clause if a finally is
present. This is the catch-all handler and it just needs to
be walked. */
if (!TREE_CHAIN (current) && finally)
{
TREE_OPERAND (current, 0) =
java_complete_tree (TREE_OPERAND (current, 0));
continue;
}
/* At this point, the structure of the catch clause is
LABELED_BLOCK_EXPR (if we have a finally)
CATCH_EXPR (catch node)
BLOCK (with the decl of the parameter)
COMPOUND_EXPR
MODIFIY_EXPR (assignemnt of the catch parameter)
BLOCK (catch clause block)
LABEL_DECL (where to return after finally (if any))
Since the structure of the catch clause depends on the
presence of a finally, we use a function call to get to the
cath clause */
catch_clause = java_get_catch_block (current, finally_p);
carg_decl = BLOCK_EXPR_DECLS (catch_clause);
carg_type = TREE_TYPE (TREE_TYPE (carg_decl));
/* Catch clauses can't have more than one parameter declared,
but it's already enforced by the grammar. Make sure that the
only parameter of the clause statement in of class Throwable
or a subclass of Throwable, but that was done earlier. The
catch clause parameter type has also been resolved. */
/* Just make sure that the catch clause parameter type inherits
from java.lang.Throwable */
if (!inherits_from_p (carg_type, throwable_type_node))
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (current);
parse_error_context (wfl_operator,
"
Can
't catch class `%s'
.
Catch
clause
"
"
parameter
type
must
be
a
subclass
of
"
"
class
`
java
.
lang
.
Throwable
'",
lang_printable_name (carg_type));
error_found = 1;
continue;
}
/* Partial check for unreachable catch statement: The catch
clause is reachable iff is no earlier catch block A in
the try statement such that the type of the catch
clause'
s
parameter
is
the
same
as
or
a
subclass
of
the
type
of
A
's parameter */
unreachable = 0;
for (sub_current = catch;
sub_current != current; sub_current = TREE_CHAIN (sub_current))
{
tree sub_catch_clause, decl;
sub_catch_clause = java_get_catch_block (sub_current, finally_p);
decl = BLOCK_EXPR_DECLS (sub_catch_clause);
if (inherits_from_p (carg_type, TREE_TYPE (TREE_TYPE (decl))))
{
EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (current);
parse_error_context
(wfl_operator, "`catch'
not
reached
because
of
the
catch
"
"
clause
at
line
%
d
", EXPR_WFL_LINENO (sub_current));
unreachable = error_found = 1;
break;
}
}
if (unreachable)
continue;
/* Complete the catch clause block */
catch_block = java_complete_tree (TREE_OPERAND (current, 0));
if (catch_block == error_mark_node)
{
error_found = 1;
continue;
}
TREE_OPERAND (current, 0) = catch_block;
}
/* Process finally */
if (finally)
{
FINALLY_EXPR_BLOCK (finally) =
java_complete_tree (FINALLY_EXPR_BLOCK (finally));
if (FINALLY_EXPR_BLOCK (finally) == error_mark_node)
error_found = 1;
}
/* Verification ends here */
if (error_found)
return error_mark_node;
TREE_OPERAND (node, 0) = try;
TREE_OPERAND (node, 1) = catch;
TREE_OPERAND (node, 2) = finally;
TREE_TYPE (node) = void_type_node;
return node;
}
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