mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-27 19:25:51 +08:00
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:
parent
ba0b8436b0
commit
b4c4a9ecbe
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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. */
|
||||
|
1895
gcc/cp/parse.c
1895
gcc/cp/parse.c
File diff suppressed because it is too large
Load Diff
343
gcc/cp/parse.y
343
gcc/cp/parse.y
@ -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;
|
||||
|
21
gcc/cp/pt.c
21
gcc/cp/pt.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
21
gcc/testsuite/g++.old-deja/g++.pt/spec16.C
Normal file
21
gcc/testsuite/g++.old-deja/g++.pt/spec16.C
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user