pt.c (tsubst): Clear TREE_USED for new FUNCTION_DECLs.

* pt.c (tsubst): Clear TREE_USED for new FUNCTION_DECLs.
	* pt.c (instantiate_class_template): Make sure template
	arguments are permanent.
	* init.c (resolve_offset_ref): Don't go looking around in
	template types.
	* semantics.c: Add routines to handle expressions, and some
	declaration processing.
	* parse.y: Use them.
	(current_class_depth): Move declaration to cp-tree.h.
	* parse.c: Regenerated.
	* cp-tree.h: Use them.
	(current_class_depth): Declare.
	* pt.c (tsubst_copy): Use begin_stmt_expr and finish_stmt_expr.

From-SVN: r18882
This commit is contained in:
Mark Mitchell 1998-03-28 17:47:07 +00:00 committed by Mark Mitchell
parent ba0b8436b0
commit b4c4a9ecbe
8 changed files with 1242 additions and 1382 deletions

View File

@ -1,3 +1,21 @@
Sat Mar 28 17:43:52 1998 Mark Mitchell <mmitchell@usa.net>
* pt.c (tsubst): Clear TREE_USED for new FUNCTION_DECLs.
* pt.c (instantiate_class_template): Make sure template
arguments are permanent.
* init.c (resolve_offset_ref): Don't go looking around in
template types.
* semantics.c: Add routines to handle expressions, and some
declaration processing.
* parse.y: Use them.
(current_class_depth): Move declaration to cp-tree.h.
* parse.c: Regenerated.
* cp-tree.h: Use them.
(current_class_depth): Declare.
* pt.c (tsubst_copy): Use begin_stmt_expr and finish_stmt_expr.
Fri Mar 27 20:23:18 1998 Mark Mitchell <mmitchell@usa.net>
* error.c (dump_decl): Be a bit more explicit with template

View File

@ -1684,6 +1684,7 @@ extern tree current_class_type;
extern tree current_class_ptr;
extern tree previous_class_type;
extern tree current_class_ref;
extern int current_class_depth;
extern tree current_lang_name, lang_name_cplusplus, lang_name_c;
@ -2580,6 +2581,22 @@ extern void finish_handler PROTO((tree));
extern tree begin_compound_stmt PROTO((int));
extern tree finish_compound_stmt PROTO((int, tree));
extern void finish_asm_stmt PROTO((tree, tree, tree, tree, tree));
extern tree finish_parenthesized_expr PROTO((tree));
extern tree begin_stmt_expr PROTO((void));
extern tree finish_stmt_expr PROTO((tree, tree));
extern tree finish_call_expr PROTO((tree, tree));
extern tree finish_increment_expr PROTO((tree, enum tree_code));
extern tree finish_this_expr PROTO((void));
extern tree finish_object_call_expr PROTO((tree, tree, tree));
extern tree finish_qualified_object_call_expr PROTO((tree, tree, tree));
extern tree finish_pseudo_destructor_call_expr PROTO((tree, tree, tree));
extern tree finish_globally_qualified_member_call_expr PROTO ((tree, tree));
extern tree finish_label_address_expr PROTO((tree));
extern int begin_function_definition PROTO((tree, tree));
extern tree begin_constructor_declarator PROTO((tree, tree));
extern tree finish_template_type_parm PROTO((tree, tree));
extern tree finish_template_template_parm PROTO((tree, tree));
/* in sig.c */
extern tree build_signature_pointer_type PROTO((tree, int, int));
extern tree build_signature_reference_type PROTO((tree, int, int));

View File

@ -1625,7 +1625,7 @@ build_offset_ref (type, name)
if (type == std_node)
return do_scoped_id (name, 0);
if (processing_template_decl)
if (processing_template_decl || uses_template_parms (type))
return build_min_nt (SCOPE_REF, type, name);
/* Handle namespace names fully here. */

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,6 @@ extern int errno;
#endif
extern int end_of_file;
extern int current_class_depth;
/* Like YYERROR but do call yyerror. */
#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
@ -237,7 +236,7 @@ empty_parms ()
%token <ttype> TYPENAME_ELLIPSIS PTYPENAME
%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
%token <ttype> PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER
%type <ttype> fn.def1 /* Not really! */ component_constructor_declarator
%type <ttype> component_constructor_declarator
%type <ttype> fn.def2 return_id fn.defpen constructor_declarator
%type <itype> ctor_initializer_opt
%type <ttype> named_class_head named_class_head_sans_basetype
@ -479,36 +478,14 @@ maybe_identifier:
template_type_parm:
aggr maybe_identifier
{
$$ = build_tree_list ($1, $2);
if (TREE_PURPOSE ($$) == signature_type_node)
sorry ("signature as template type parameter");
else if (TREE_PURPOSE ($$) != class_type_node)
{
pedwarn ("template type parameters must use the keyword `class'");
TREE_PURPOSE ($$) = class_type_node;
}
}
{ $$ = finish_template_type_parm ($1, $2); }
| TYPENAME_KEYWORD maybe_identifier
{ $$ = build_tree_list (class_type_node, $2); }
{ $$ = finish_template_type_parm (class_type_node, $2); }
;
template_template_parm:
template_header aggr maybe_identifier
{
tree decl = build_decl (TYPE_DECL, $3, NULL_TREE);
tree tmpl = build_lang_decl (TEMPLATE_DECL, $3, NULL_TREE);
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_TEMPLATE_RESULT (tmpl) = decl;
SET_DECL_ARTIFICIAL (decl);
end_template_decl ();
if ($2 == signature_type_node)
sorry ("signature as template template parameter");
else if ($2 != class_type_node)
pedwarn ("template template parameters must use the keyword `class'");
$$ = build_tree_list (class_type_node, tmpl);
}
{ $$ = finish_template_template_parm ($2, $3); }
;
template_parm:
@ -613,123 +590,55 @@ fndef:
constructor_declarator:
nested_name_specifier SELFNAME '('
{
$$ = build_parse_node (SCOPE_REF, $1, $2);
if ($1 != current_class_type)
{
push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
{ $$ = begin_constructor_declarator ($1, $2); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
| nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
{
$$ = build_parse_node (SCOPE_REF, $1, $2);
if ($1 != current_class_type)
{
push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
{ $$ = begin_constructor_declarator ($1, $2);
$$ = make_call_declarator ($$, empty_parms (), $4, $5);
}
| global_scope nested_name_specifier SELFNAME '('
{
$$ = build_parse_node (SCOPE_REF, $2, $3);
if ($2 != current_class_type)
{
push_nested_class ($2, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
{ $$ = begin_constructor_declarator ($2, $3); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
| global_scope nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
{
$$ = build_parse_node (SCOPE_REF, $2, $3);
if ($2 != current_class_type)
{
push_nested_class ($2, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
{ $$ = begin_constructor_declarator ($2, $3);
$$ = make_call_declarator ($$, empty_parms (), $5, $6);
}
| nested_name_specifier self_template_type '('
{
$$ = build_parse_node (SCOPE_REF, $1, $2);
if ($1 != current_class_type)
{
push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
{ $$ = begin_constructor_declarator ($1, $2); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
| nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
{
$$ = build_parse_node (SCOPE_REF, $1, $2);
if ($1 != current_class_type)
{
push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
{ $$ = begin_constructor_declarator ($1, $2);
$$ = make_call_declarator ($$, empty_parms (), $4, $5);
}
| global_scope nested_name_specifier self_template_type '('
{
$$ = build_parse_node (SCOPE_REF, $2, $3);
if ($2 != current_class_type)
{
push_nested_class ($2, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
{ $$ = begin_constructor_declarator ($2, $3); }
parmlist ')' cv_qualifiers exception_specification_opt
{ $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
| global_scope nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
{
$$ = build_parse_node (SCOPE_REF, $2, $3);
if ($2 != current_class_type)
{
push_nested_class ($2, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
{ $$ = begin_constructor_declarator ($2, $3);
$$ = make_call_declarator ($$, empty_parms (), $5, $6);
}
;
fn.def1:
typed_declspecs declarator
{ tree specs, attrs;
split_specs_attrs ($1.t, &specs, &attrs);
if (! start_function (specs, $2, attrs, 0))
YYERROR1;
reinit_parse_for_function ();
$$ = NULL_TREE; }
{ if (!begin_function_definition ($1.t, $2))
YYERROR1; }
| declmods notype_declarator
{ tree specs, attrs;
split_specs_attrs ($1, &specs, &attrs);
if (! start_function (specs, $2, attrs, 0))
YYERROR1;
reinit_parse_for_function ();
$$ = NULL_TREE; }
{ if (!begin_function_definition ($1, $2))
YYERROR1; }
| notype_declarator
{ if (! start_function (NULL_TREE, $$, NULL_TREE, 0))
YYERROR1;
reinit_parse_for_function ();
$$ = NULL_TREE; }
{ if (!begin_function_definition (NULL_TREE, $1))
YYERROR1; }
| declmods constructor_declarator
{ tree specs, attrs;
split_specs_attrs ($1, &specs, &attrs);
if (! start_function (specs, $2, attrs, 0))
YYERROR1;
reinit_parse_for_function ();
$$ = NULL_TREE; }
{ if (!begin_function_definition ($1, $2))
YYERROR1; }
| constructor_declarator
{ if (! start_function (NULL_TREE, $$, NULL_TREE, 0))
YYERROR1;
reinit_parse_for_function ();
$$ = NULL_TREE; }
{ if (!begin_function_definition (NULL_TREE, $1))
YYERROR1; }
;
component_constructor_declarator:
@ -1109,18 +1018,9 @@ unary_expr:
}
/* Refer to the address of a label as a pointer. */
| ANDAND identifier
{ tree label = lookup_label ($2);
if (pedantic)
{ if (pedantic)
pedwarn ("ANSI C++ forbids `&&'");
if (label == NULL_TREE)
$$ = null_pointer_node;
else
{
TREE_USED (label) = 1;
$$ = build1 (ADDR_EXPR, ptr_type_node, label);
TREE_CONSTANT ($$) = 1;
}
}
$$ = finish_label_address_expr ($2); }
| SIZEOF unary_expr %prec UNARY
{ $$ = expr_sizeof ($2); }
| SIZEOF '(' type_id ')' %prec HYPERUNARY
@ -1389,21 +1289,10 @@ primary:
pop_obstacks ();
}
| '(' expr ')'
{ char class;
$$ = $2;
class = TREE_CODE_CLASS (TREE_CODE ($$));
if (class == 'e' || class == '1'
|| class == '2' || class == '<')
/* This inhibits warnings in truthvalue_conversion. */
C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
{ $$ = finish_parenthesized_expr ($2); }
| '(' expr_or_declarator ')'
{ char class;
$$ = reparse_decl_as_expr (NULL_TREE, $2);
class = TREE_CODE_CLASS (TREE_CODE ($$));
if (class == 'e' || class == '1'
|| class == '2' || class == '<')
/* This inhibits warnings in truthvalue_conversion. */
C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
{ $2 = reparse_decl_as_expr (NULL_TREE, $2);
$$ = finish_parenthesized_expr ($2); }
| '(' error ')'
{ $$ = error_mark_node; }
| '('
@ -1412,95 +1301,25 @@ primary:
error ("braced-group within expression allowed only inside a function");
YYERROR;
}
keep_next_level ();
if (!processing_template_decl)
$<ttype>$ = expand_start_stmt_expr ();
else
$<ttype>$ = NULL_TREE;
if (pedantic)
pedwarn ("ANSI C++ forbids braced-groups within expressions");
$<ttype>$ = begin_stmt_expr ();
}
compstmt ')'
{ tree rtl_exp;
if (pedantic)
pedwarn ("ANSI C++ forbids braced-groups within expressions");
if (!processing_template_decl)
{
rtl_exp = expand_end_stmt_expr ($<ttype>2);
/* The statements have side effects, so the
group does. */
TREE_SIDE_EFFECTS (rtl_exp) = 1;
}
if (TREE_CODE ($3) == BLOCK)
{
/* Make a BIND_EXPR for the BLOCK already made. */
if (processing_template_decl)
$$ = build (BIND_EXPR, NULL_TREE,
NULL_TREE, last_tree, $3);
else
$$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
NULL_TREE, rtl_exp, $3);
/* Remove the block from the tree at this point.
It gets put back at the proper place
when the BIND_EXPR is expanded. */
delete_block ($3);
}
else
$$ = $3;
}
{ $$ = finish_stmt_expr ($<ttype>2, $3); }
| primary '(' nonnull_exprlist ')'
{
$$ = build_x_function_call ($1, $3, current_class_ref);
if (TREE_CODE ($$) == CALL_EXPR
&& TREE_TYPE ($$) != void_type_node)
$$ = require_complete_type ($$);
}
{ $$ = finish_call_expr ($1, $3); }
| primary LEFT_RIGHT
{
$$ = build_x_function_call ($$, NULL_TREE, current_class_ref);
if (TREE_CODE ($$) == CALL_EXPR
&& TREE_TYPE ($$) != void_type_node)
$$ = require_complete_type ($$);
}
{ $$ = finish_call_expr ($1, NULL_TREE); }
| primary '[' expr ']'
{ $$ = grok_array_decl ($$, $3); }
| primary PLUSPLUS
{ /* If we get an OFFSET_REF, turn it into what it really
means (e.g., a COMPONENT_REF). This way if we've got,
say, a reference to a static member that's being operated
on, we don't end up trying to find a member operator for
the class it's in. */
if (TREE_CODE ($$) == OFFSET_REF)
$$ = resolve_offset_ref ($$);
$$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
{ $$ = finish_increment_expr ($1, POSTINCREMENT_EXPR); }
| primary MINUSMINUS
{ if (TREE_CODE ($$) == OFFSET_REF)
$$ = resolve_offset_ref ($$);
$$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
{ $$ = finish_increment_expr ($1, POSTDECREMENT_EXPR); }
/* C++ extensions */
| THIS
{ if (current_class_ptr)
{
#ifdef WARNING_ABOUT_CCD
TREE_USED (current_class_ptr) = 1;
#endif
$$ = current_class_ptr;
}
else if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
{
error ("`this' is unavailable for static member functions");
$$ = error_mark_node;
}
else
{
if (current_function_decl)
error ("invalid use of `this' in non-member function");
else
error ("invalid use of `this' at top level");
$$ = error_mark_node;
}
}
{ $$ = finish_this_expr (); }
| CV_QUALIFIER '(' nonnull_exprlist ')'
{
tree type = NULL_TREE;
@ -1581,30 +1400,17 @@ primary:
| overqualified_id %prec HYPERUNARY
{ $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
| overqualified_id '(' nonnull_exprlist ')'
{ if (processing_template_decl)
$$ = build_min_nt (CALL_EXPR, copy_to_permanent ($1), $3, NULL_TREE);
else
$$ = build_member_call (OP0 ($$), OP1 ($$), $3); }
{ $$ = finish_globally_qualified_member_call_expr ($1, $3); }
| overqualified_id LEFT_RIGHT
{ if (processing_template_decl)
$$ = build_min_nt (CALL_EXPR, copy_to_permanent ($1),
NULL_TREE, NULL_TREE);
else
$$ = build_member_call (OP0 ($$), OP1 ($$), NULL_TREE); }
{ $$ = finish_globally_qualified_member_call_expr ($1, NULL_TREE); }
| object object_template_id %prec UNARY
{
$$ = build_x_component_ref ($$, $2, NULL_TREE, 1);
}
| object object_template_id '(' nonnull_exprlist ')'
{
$$ = build_method_call ($1, $2, $4,
NULL_TREE, LOOKUP_NORMAL);
}
{ $$ = finish_object_call_expr ($2, $1, $4); }
| object object_template_id LEFT_RIGHT
{
$$ = build_method_call ($1, $2, NULL_TREE,
NULL_TREE, LOOKUP_NORMAL);
}
{ $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object unqualified_id %prec UNARY
{ $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); }
| object overqualified_id %prec UNARY
@ -1613,75 +1419,18 @@ primary:
else
$$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
| object unqualified_id '(' nonnull_exprlist ')'
{
#if 0
/* This is a future direction of this code, but because
build_x_function_call cannot always undo what is done
in build_component_ref entirely yet, we cannot do this. */
$$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), $4, current_class_ref);
if (TREE_CODE ($$) == CALL_EXPR
&& TREE_TYPE ($$) != void_type_node)
$$ = require_complete_type ($$);
#else
$$ = build_method_call ($$, $2, $4, NULL_TREE,
LOOKUP_NORMAL);
#endif
}
{ $$ = finish_object_call_expr ($2, $1, $4); }
| object unqualified_id LEFT_RIGHT
{
#if 0
/* This is a future direction of this code, but because
build_x_function_call cannot always undo what is done
in build_component_ref entirely yet, we cannot do this. */
$$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), NULL_TREE, current_class_ref);
if (TREE_CODE ($$) == CALL_EXPR
&& TREE_TYPE ($$) != void_type_node)
$$ = require_complete_type ($$);
#else
$$ = build_method_call ($$, $2, NULL_TREE, NULL_TREE,
LOOKUP_NORMAL);
#endif
}
{ $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object overqualified_id '(' nonnull_exprlist ')'
{
if (IS_SIGNATURE (OP0 ($2)))
{
warning ("signature name in scope resolution ignored");
$$ = build_method_call ($$, OP1 ($2), $4, NULL_TREE,
LOOKUP_NORMAL);
}
else
$$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), $4);
}
{ $$ = finish_qualified_object_call_expr ($2, $1, $4); }
| object overqualified_id LEFT_RIGHT
{
if (IS_SIGNATURE (OP0 ($2)))
{
warning ("signature name in scope resolution ignored");
$$ = build_method_call ($$, OP1 ($2), NULL_TREE, NULL_TREE,
LOOKUP_NORMAL);
}
else
$$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), NULL_TREE);
}
{ $$ = finish_qualified_object_call_expr ($2, $1, NULL_TREE); }
/* p->int::~int() is valid -- 12.4 */
| object '~' TYPESPEC LEFT_RIGHT
{
if (IDENTIFIER_GLOBAL_VALUE ($3)
&& (TREE_CODE (TREE_TYPE ($1))
!= TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($3)))))
cp_error ("`%E' is not of type `%T'", $1, $3);
$$ = cp_convert (void_type_node, $1);
}
{ $$ = finish_pseudo_destructor_call_expr ($1, NULL_TREE, $3); }
| object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT
{
if ($2 != $5)
cp_error ("destructor specifier `%T::~%T()' must have matching names", $2, $5);
if (TREE_CODE (TREE_TYPE ($1))
!= TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($2))))
cp_error ("`%E' is not of type `%T'", $1, $2);
$$ = cp_convert (void_type_node, $1);
}
{ $$ = finish_pseudo_destructor_call_expr ($1, $2, $5); }
| object error
{
$$ = error_mark_node;

View File

@ -3371,6 +3371,11 @@ instantiate_class_template (type)
value that results in a specialization being used. */
return type;
/* We must copy the arguments to the permanent obstack since
during the tsubst'ing below they may wind up in the
DECL_TI_ARGS of some instantiated member template. */
args = copy_to_permanent (args);
TYPE_BEING_DEFINED (type) = 1;
if (! push_tinst_level (type))
@ -4254,6 +4259,7 @@ tsubst (t, args, in_decl)
TREE_CHAIN (r) = NULL_TREE;
DECL_CHAIN (r) = NULL_TREE;
DECL_PENDING_INLINE_INFO (r) = 0;
TREE_USED (r) = 0;
if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
@ -4868,13 +4874,9 @@ tsubst_copy (t, args, in_decl)
inside them. Instead, it simply calls
build_expr_from_tree. So, we need to expand the
BIND_EXPR here. */
tree rtl_exp = expand_start_stmt_expr();
tree rtl_expr = begin_stmt_expr ();
tree block = tsubst_expr (TREE_OPERAND (r, 1), args, in_decl);
rtl_exp = expand_end_stmt_expr (rtl_exp);
TREE_SIDE_EFFECTS (rtl_exp) = 1;
r = build (BIND_EXPR, TREE_TYPE (rtl_exp),
NULL_TREE, rtl_exp, block);
delete_block (block);
r = finish_stmt_expr (rtl_expr, block);
}
return r;
@ -5907,11 +5909,8 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
return 1;
}
else
{
sorry ("use of `%s' in template type unification",
tree_code_name [(int) TREE_CODE (parm)]);
break;
}
sorry ("use of `%s' in template type unification",
tree_code_name [(int) TREE_CODE (parm)]);
return 1;
}

View File

@ -747,3 +747,310 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
finish_stmt ();
}
}
/* Finish a parenthesized expression EXPR. */
tree
finish_parenthesized_expr (expr)
tree expr;
{
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
/* This inhibits warnings in truthvalue_conversion. */
C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK);
return expr;
}
/* Begin a statement-expression. Returns a new RTL_EXPR if
appropriate. */
tree
begin_stmt_expr ()
{
keep_next_level ();
return processing_template_decl ? NULL_TREE : expand_start_stmt_expr();
}
/* Finish a statement-expression. RTL_EXPR should be the value
returned by the previous begin_stmt_expr; EXPR is the
statement-expression. Returns an expression representing the
statement-expression. */
tree
finish_stmt_expr (rtl_expr, expr)
tree rtl_expr;
tree expr;
{
tree result;
if (!processing_template_decl)
{
rtl_expr = expand_end_stmt_expr (rtl_expr);
/* The statements have side effects, so the group does. */
TREE_SIDE_EFFECTS (rtl_expr) = 1;
}
if (TREE_CODE (expr) == BLOCK)
{
/* Make a BIND_EXPR for the BLOCK already made. */
if (processing_template_decl)
result = build (BIND_EXPR, NULL_TREE,
NULL_TREE, last_tree, expr);
else
result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
NULL_TREE, rtl_expr, expr);
/* Remove the block from the tree at this point.
It gets put back at the proper place
when the BIND_EXPR is expanded. */
delete_block (expr);
}
else
result = expr;
return result;
}
/* Finish a call to FN with ARGS. Returns a representation of the
call. */
tree
finish_call_expr (fn, args)
tree fn;
tree args;
{
tree result = build_x_function_call (fn, args, current_class_ref);
if (TREE_CODE (result) == CALL_EXPR
&& TREE_TYPE (result) != void_type_node)
result = require_complete_type (result);
return result;
}
/* Finish a call to a postfix increment or decrement or EXPR. (Which
is indicated by CODE, which should be POSTINCREMENT_EXPR or
POSTDECREMENT_EXPR.) */
tree
finish_increment_expr (expr, code)
tree expr;
enum tree_code code;
{
/* If we get an OFFSET_REF, turn it into what it really means (e.g.,
a COMPONENT_REF). This way if we've got, say, a reference to a
static member that's being operated on, we don't end up trying to
find a member operator for the class it's in. */
if (TREE_CODE (expr) == OFFSET_REF)
expr = resolve_offset_ref (expr);
return build_x_unary_op (code, expr);
}
/* Finish a use of `this'. Returns an expression for `this'. */
tree
finish_this_expr ()
{
tree result;
if (current_class_ptr)
{
#ifdef WARNING_ABOUT_CCD
TREE_USED (current_class_ptr) = 1;
#endif
result = current_class_ptr;
}
else if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
{
error ("`this' is unavailable for static member functions");
result = error_mark_node;
}
else
{
if (current_function_decl)
error ("invalid use of `this' in non-member function");
else
error ("invalid use of `this' at top level");
result = error_mark_node;
}
return result;
}
/* Finish a member function call using OBJECT and ARGS as arguments to
FN. Returns an expression for the call. */
tree
finish_object_call_expr (fn, object, args)
tree fn;
tree object;
tree args;
{
#if 0
/* This is a future direction of this code, but because
build_x_function_call cannot always undo what is done in
build_component_ref entirely yet, we cannot do this. */
tree real_fn = build_component_ref (object, fn, NULL_TREE, 1);
return finish_call_expr (real_fn, args);
#else
return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
#endif
}
/* Finish a qualified member function call using OBJECT and ARGS as
arguments to FN. Returns an expressino for the call. */
tree
finish_qualified_object_call_expr (fn, object, args)
tree fn;
tree object;
tree args;
{
if (IS_SIGNATURE (TREE_OPERAND (fn, 0)))
{
warning ("signature name in scope resolution ignored");
return finish_object_call_expr (TREE_OPERAND (fn, 1), object, args);
}
else
return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
TREE_OPERAND (fn, 1), args);
}
/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
being the scope, if any, of DESTRUCTOR. Returns an expression for
the call. */
tree
finish_pseudo_destructor_call_expr (object, scope, destructor)
tree object;
tree scope;
tree destructor;
{
if (scope && scope != destructor)
cp_error ("destructor specifier `%T::~%T()' must have matching names",
scope, destructor);
if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
&& (TREE_CODE (TREE_TYPE (object)) !=
TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
cp_error ("`%E' is not of type `%T'", object, destructor);
return cp_convert (void_type_node, object);
}
/* Finish a call to a globally qualified member function FN using
ARGS. Returns an expression for the call. */
tree
finish_globally_qualified_member_call_expr (fn, args)
tree fn;
tree args;
{
if (processing_template_decl)
return build_min_nt (CALL_EXPR, copy_to_permanent (fn), args,
NULL_TREE);
else
return build_member_call (TREE_OPERAND (fn, 0),
TREE_OPERAND (fn, 1),
args);
}
/* Finish an expression taking the address of LABEL. Returns an
expression for the address. */
tree
finish_label_address_expr (label)
tree label;
{
tree result;
label = lookup_label (label);
if (label == NULL_TREE)
result = null_pointer_node;
else
{
TREE_USED (label) = 1;
result = build1 (ADDR_EXPR, ptr_type_node, label);
TREE_CONSTANT (result) = 1;
}
return result;
}
/* Begin a function defniition declared with DECL_SPECS and
DECLARATOR. Returns non-zero if the function-declaration is
legal. */
int
begin_function_definition (decl_specs, declarator)
tree decl_specs;
tree declarator;
{
tree specs;
tree attrs;
split_specs_attrs (decl_specs, &specs, &attrs);
if (!start_function (specs, declarator, attrs, 0))
return 0;
reinit_parse_for_function ();
return 1;
}
/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns
a SCOPE_REF. */
tree
begin_constructor_declarator (scope, name)
tree scope;
tree name;
{
tree result = build_parse_node (SCOPE_REF, scope, name);
if (scope != current_class_type)
{
push_nested_class (scope, 3);
TREE_COMPLEXITY (result) = current_class_depth;
}
return result;
}
/* Finish a template type parameter, specified as AGGR IDENTIFIER.
Returns the parameter. */
tree
finish_template_type_parm (aggr, identifier)
tree aggr;
tree identifier;
{
if (aggr == signature_type_node)
sorry ("signature as template type parameter");
else if (aggr != class_type_node)
{
pedwarn ("template type parameters must use the keyword `class' or `typename'");
aggr = class_type_node;
}
return build_tree_list (aggr, identifier);
}
/* Finish a template template parameter, specified as AGGR IDENTIFIER.
Returns the parameter. */
tree
finish_template_template_parm (aggr, identifier)
tree aggr;
tree identifier;
{
tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_TEMPLATE_RESULT (tmpl) = decl;
SET_DECL_ARTIFICIAL (decl);
end_template_decl ();
return finish_template_type_parm (aggr, tmpl);
}

View File

@ -0,0 +1,21 @@
// Build don't link:
template<class K>
struct A {
int foo(const K&);
int bar(const K&);
};
template<class K>
int
A<K>::bar(const K& k)
{
return(foo(k));
}
template<>
int
A<const char*>::foo(const char*const& k)
{
return((int)k);
}