fold-const.c (make_range): Do not access operand 1 for a zero-operand operator.

* fold-const.c (make_range): Do not access operand 1 for a
	zero-operand operator.

2003-07-08  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.def (NON_DEPENDENT_EXPR): New node.
	* cp-tree.h (build_call_from_tree): Remove.
	(build_member_call): Likewise.
	(dependent_template_arg_p): Remove.
	(any_dependent_template_arguments_p): New function.
	(dependent_template_id_p): Likewise.
	(any_type_dependent_arguments_p): Likewise.
	(build_non_dependent_expr): Likewise.
	(build_non_dependent_args): Likewise.
	(build_x_compound_expr): Adjust prototype.
	* call.c (build_new_method_call): Handle non-dependent expressions
	correctly.
	* decl2.c (grok_array_decl): Likewise.
	(build_offset_ref_call_from_tree): Likewise.
	(build_call_from_tree): Remove.
	* error.c (dump_decl): Handle NON_DEPENDENT_EXPR.
	(dump_expr): Likewise.
	* init.c (build_member_call): Remove.
	* mangle.c (write_expression): Update handling for template-ids.
	* parser.c (cp_parser_primary_expression): Use
	any_dependent_template_arguments_p.  Update constant-expression
	handling.
	(cp_parser_postfix_expression): Use
	any_type_dependent_arguments_p.  Simplify call processing.
	(cp_parser_unary_expression): Simplify.
	(cp_parser_expression): Adjust for changes to
	build_x_compound_expr.
	(cp_parser_template_argument): Implement standard-conforming
	parsing of non-type template arguments.
	(cp_parser_direct_declarator): Use
	cp_parser_fold_non_dependent_expr.
	(cp_parser_fold_non_dependent_expr): New function.
	(cp_parser_next_token_ends_template_argument_p): Likewise.
	* pt.c (convert_template_argument): Do not call
	maybe_fold_nontype_arg.
	(tsubst_baselink): Likewise.
	(tsubst_copy_and_build): Share common code.  Make sizeof/alignof
	processing work correctly for non-dependent expressions.  Adjust
	handling of COMPOUND_EXPR.  Simplify call processing.
	(value_dependent_expression_p): Deal with functional casts and
	sizeof/alignof correctly.
	(type_dependent_expression_p): Handle overloaded functions.
	(any_type_dependent_arguments_p): New function.
	(any_dependent_template_arguments_p): Likewise.
	(dependent_template_p): Treat SCOPE_REFs as dependent.
	(dependent_template_id_p): Simplify.
	(build_non_dependent_expr): New function.
	(build_non_dependent_args): Likewise.
	* semantics.c (finish_stmt_expr): Don't make dependent
	statement-expresions have void type.
	(finish_call_expr): Handle non-dependent expressions
	correctly.
	* tree.c (lvalue_p_1): Treat NON_DEPENDENT_EXPRs as lvalues.
	* typeck.c (cxx_sizeof_or_alignof_type): Give the expression
	type size_t, even in templates.
	(expr_sizeof): Likewise.
	(finish_class_member_access_expr): Handle non-dependent expressions
	correctly.
	(build_x_indirect_ref): Likewise.
	(build_x_binary_op): Likewise.
	(build_x_unary_op): Likewise.
	(build_x_conditional_expr): Likewise.
	(build_x_compound_expr): Likewise.
	* typeck2.c (build_x_arrow): Likewise.

2003-07-08  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/mangle17.C: Make sure template expressions are
	dependent.
	* g++.dg/abi/mangle4.C: Mark erroneous casts.
	* g++.dg/debug/debug7.C: Mark erronous new-declarator.
	* g++.dg/opt/stack1.C: Remove erroneous code.
	* g++.dg/parse/template7.C: New test.
	* g++.dg/template/dependent-expr1.C: Mark erroneous code.
	* g++.old-deja/g++.pt/crash4.C: Likewise.

2003-07-09  Mark Mitchell  <mark@codesourcery.com>

	* gcj/array.h (JvPrimClass): Don't parenthesize the output.

From-SVN: r69130
This commit is contained in:
Mark Mitchell 2003-07-09 08:48:08 +00:00 committed by Mark Mitchell
parent 844c00ed16
commit d17811fd1a
26 changed files with 945 additions and 840 deletions

View File

@ -1,3 +1,8 @@
2003-07-08 Mark Mitchell <mark@codesourcery.com>
* fold-const.c (make_range): Do not access operand 1 for a
zero-operand operator.
2003-07-09 Neil Booth <neil@daikokuya.co.uk> 2003-07-09 Neil Booth <neil@daikokuya.co.uk>
* toplev.c (warn_dummy, W_options): Die. * toplev.c (warn_dummy, W_options): Die.

View File

@ -1,3 +1,70 @@
2003-07-08 Mark Mitchell <mark@codesourcery.com>
* cp-tree.def (NON_DEPENDENT_EXPR): New node.
* cp-tree.h (build_call_from_tree): Remove.
(build_member_call): Likewise.
(dependent_template_arg_p): Remove.
(any_dependent_template_arguments_p): New function.
(dependent_template_id_p): Likewise.
(any_type_dependent_arguments_p): Likewise.
(build_non_dependent_expr): Likewise.
(build_non_dependent_args): Likewise.
(build_x_compound_expr): Adjust prototype.
* call.c (build_new_method_call): Handle non-dependent expressions
correctly.
* decl2.c (grok_array_decl): Likewise.
(build_offset_ref_call_from_tree): Likewise.
(build_call_from_tree): Remove.
* error.c (dump_decl): Handle NON_DEPENDENT_EXPR.
(dump_expr): Likewise.
* init.c (build_member_call): Remove.
* mangle.c (write_expression): Update handling for template-ids.
* parser.c (cp_parser_primary_expression): Use
any_dependent_template_arguments_p. Update constant-expression
handling.
(cp_parser_postfix_expression): Use
any_type_dependent_arguments_p. Simplify call processing.
(cp_parser_unary_expression): Simplify.
(cp_parser_expression): Adjust for changes to
build_x_compound_expr.
(cp_parser_template_argument): Implement standard-conforming
parsing of non-type template arguments.
(cp_parser_direct_declarator): Use
cp_parser_fold_non_dependent_expr.
(cp_parser_fold_non_dependent_expr): New function.
(cp_parser_next_token_ends_template_argument_p): Likewise.
* pt.c (convert_template_argument): Do not call
maybe_fold_nontype_arg.
(tsubst_baselink): Likewise.
(tsubst_copy_and_build): Share common code. Make sizeof/alignof
processing work correctly for non-dependent expressions. Adjust
handling of COMPOUND_EXPR. Simplify call processing.
(value_dependent_expression_p): Deal with functional casts and
sizeof/alignof correctly.
(type_dependent_expression_p): Handle overloaded functions.
(any_type_dependent_arguments_p): New function.
(any_dependent_template_arguments_p): Likewise.
(dependent_template_p): Treat SCOPE_REFs as dependent.
(dependent_template_id_p): Simplify.
(build_non_dependent_expr): New function.
(build_non_dependent_args): Likewise.
* semantics.c (finish_stmt_expr): Don't make dependent
statement-expresions have void type.
(finish_call_expr): Handle non-dependent expressions
correctly.
* tree.c (lvalue_p_1): Treat NON_DEPENDENT_EXPRs as lvalues.
* typeck.c (cxx_sizeof_or_alignof_type): Give the expression
type size_t, even in templates.
(expr_sizeof): Likewise.
(finish_class_member_access_expr): Handle non-dependent expressions
correctly.
(build_x_indirect_ref): Likewise.
(build_x_binary_op): Likewise.
(build_x_unary_op): Likewise.
(build_x_conditional_expr): Likewise.
(build_x_compound_expr): Likewise.
* typeck2.c (build_x_arrow): Likewise.
Wed Jul 9 02:28:39 CEST 2003 Jan Hubicka <jh@suse.cz> Wed Jul 9 02:28:39 CEST 2003 Jan Hubicka <jh@suse.cz>
* cp-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): New. * cp-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): New.
@ -210,13 +277,13 @@ Wed Jul 9 02:28:39 CEST 2003 Jan Hubicka <jh@suse.cz>
(build_conditional_expr): Likewise. (build_conditional_expr): Likewise.
(build_new_method_call): Likewise. (build_new_method_call): Likewise.
* cp-tree.def (OFFSET_REF): Update documentation. * cp-tree.def (OFFSET_REF): Update documentation.
(cp_convert_to_pointer): Update handling of conversions from * cvt.c (cp_convert_to_pointer): Update handling of conversions from
pointers to members to pointers. pointers to members to pointers.
(ocp_convert): Do not call resolve_offset_ref. (ocp_convert): Do not call resolve_offset_ref.
(convert_to_void): Likewise. (convert_to_void): Likewise.
(build_expr_type_conversion): Likewise. (build_expr_type_conversion): Likewise.
(delete_sanity): Likewise. * decl2.c (delete_sanity): Likewise.
(resolve_offset_ref): Simplify greatly. * init.c (resolve_offset_ref): Simplify greatly.
(build_vec_delete): Do not call resolve_offset_ref. (build_vec_delete): Do not call resolve_offset_ref.
* parser.c (cp_parser_postfix_expression): Call resolve_offset_ref * parser.c (cp_parser_postfix_expression): Call resolve_offset_ref
if appropriate. if appropriate.

View File

@ -325,8 +325,7 @@ build_call (tree function, tree parms)
BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE
down to the real instance type to use for access checking. We need this down to the real instance type to use for access checking. We need this
information to get protected accesses correct. This parameter is used information to get protected accesses correct.
by build_member_call.
FLAGS is the logical disjunction of zero or more LOOKUP_ FLAGS is the logical disjunction of zero or more LOOKUP_
flags. See cp-tree.h for more info. flags. See cp-tree.h for more info.
@ -4883,6 +4882,9 @@ build_new_method_call (tree instance, tree fns, tree args,
tree class_type; tree class_type;
int template_only = 0; int template_only = 0;
bool any_viable_p; bool any_viable_p;
tree orig_instance;
tree orig_fns;
tree orig_args;
my_friendly_assert (instance != NULL_TREE, 20020729); my_friendly_assert (instance != NULL_TREE, 20020729);
@ -4891,6 +4893,20 @@ build_new_method_call (tree instance, tree fns, tree args,
|| args == error_mark_node) || args == error_mark_node)
return error_mark_node; return error_mark_node;
orig_instance = instance;
orig_fns = fns;
orig_args = args;
if (processing_template_decl)
{
instance = build_non_dependent_expr (instance);
if (!BASELINK_P (fns)
&& TREE_CODE (fns) != PSEUDO_DTOR_EXPR
&& TREE_TYPE (fns) != unknown_type_node)
fns = build_non_dependent_expr (fns);
args = build_non_dependent_args (orig_args);
}
/* Process the argument list. */ /* Process the argument list. */
user_args = args; user_args = args;
args = resolve_args (args); args = resolve_args (args);
@ -5068,6 +5084,13 @@ build_new_method_call (tree instance, tree fns, tree args,
call = build (COMPOUND_EXPR, TREE_TYPE (call), instance, call); call = build (COMPOUND_EXPR, TREE_TYPE (call), instance, call);
} }
if (processing_template_decl && call != error_mark_node)
return build_min (CALL_EXPR,
TREE_TYPE (call),
build_min_nt (COMPONENT_REF,
orig_instance,
orig_fns),
orig_args);
return call; return call;
} }

View File

@ -238,6 +238,16 @@ DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", 'e', 2)
DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1) DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1)
DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3) DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3)
/* A placeholder for an expression that is not type-dependent, but
does occur in a template. When an expression that is not
type-dependent appears in a larger expression, we must compute the
type of that larger expression. That computation would normally
modify the original expression, which would change the mangling of
that expression if it appeared in a template argument list. In
that situation, we create a NON_DEPENDENT_EXPR to take the place of
the original expression. */
DEFTREECODE (NON_DEPENDENT_EXPR, "non_dependent_expr", 'e', 0)
/* CTOR_INITIALIZER is a placeholder in template code for a call to /* CTOR_INITIALIZER is a placeholder in template code for a call to
setup_vtbl_pointer (and appears in all functions, not just ctors). */ setup_vtbl_pointer (and appears in all functions, not just ctors). */
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1) DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1)

View File

@ -215,6 +215,7 @@ struct diagnostic_context;
#define abi_version_at_least(N) \ #define abi_version_at_least(N) \
(flag_abi_version == 0 || flag_abi_version >= (N)) (flag_abi_version == 0 || flag_abi_version >= (N))
/* Language-dependent contents of an identifier. */ /* Language-dependent contents of an identifier. */
@ -3775,7 +3776,6 @@ extern void import_export_tinfo (tree, tree, bool);
extern void finish_file (void); extern void finish_file (void);
extern tree build_cleanup (tree); extern tree build_cleanup (tree);
extern tree build_offset_ref_call_from_tree (tree, tree); extern tree build_offset_ref_call_from_tree (tree, tree);
extern tree build_call_from_tree (tree, tree, bool);
extern void set_decl_namespace (tree, tree, bool); extern void set_decl_namespace (tree, tree, bool);
extern tree current_decl_namespace (void); extern tree current_decl_namespace (void);
extern void push_decl_namespace (tree); extern void push_decl_namespace (tree);
@ -3853,7 +3853,6 @@ extern int is_aggr_type (tree, int);
extern tree get_aggr_from_typedef (tree, int); extern tree get_aggr_from_typedef (tree, int);
extern tree get_type_value (tree); extern tree get_type_value (tree);
extern tree build_zero_init (tree, tree, bool); extern tree build_zero_init (tree, tree, bool);
extern tree build_member_call (tree, tree, tree);
extern tree build_offset_ref (tree, tree); extern tree build_offset_ref (tree, tree);
extern tree resolve_offset_ref (tree); extern tree resolve_offset_ref (tree);
extern tree build_new (tree, tree, tree, int); extern tree build_new (tree, tree, tree, int);
@ -3974,12 +3973,16 @@ extern tree current_instantiation (void);
extern tree maybe_get_template_decl_from_type_decl (tree); extern tree maybe_get_template_decl_from_type_decl (tree);
extern int processing_template_parmlist; extern int processing_template_parmlist;
extern bool dependent_type_p (tree); extern bool dependent_type_p (tree);
extern bool dependent_template_arg_p (tree); extern bool any_dependent_template_arguments_p (tree);
extern bool dependent_template_p (tree); extern bool dependent_template_p (tree);
extern bool dependent_template_id_p (tree, tree);
extern bool type_dependent_expression_p (tree); extern bool type_dependent_expression_p (tree);
extern bool any_type_dependent_arguments_p (tree);
extern bool value_dependent_expression_p (tree); extern bool value_dependent_expression_p (tree);
extern tree resolve_typename_type (tree, bool); extern tree resolve_typename_type (tree, bool);
extern tree template_for_substitution (tree); extern tree template_for_substitution (tree);
extern tree build_non_dependent_expr (tree);
extern tree build_non_dependent_args (tree);
/* in repo.c */ /* in repo.c */
extern void repo_template_used (tree); extern void repo_template_used (tree);
@ -4267,7 +4270,7 @@ extern tree build_x_binary_op (enum tree_code, tree, tree);
extern tree build_x_unary_op (enum tree_code, tree); extern tree build_x_unary_op (enum tree_code, tree);
extern tree unary_complex_lvalue (enum tree_code, tree); extern tree unary_complex_lvalue (enum tree_code, tree);
extern tree build_x_conditional_expr (tree, tree, tree); extern tree build_x_conditional_expr (tree, tree, tree);
extern tree build_x_compound_expr (tree); extern tree build_x_compound_expr (tree, tree);
extern tree build_compound_expr (tree); extern tree build_compound_expr (tree);
extern tree build_static_cast (tree, tree); extern tree build_static_cast (tree, tree);
extern tree build_reinterpret_cast (tree, tree); extern tree build_reinterpret_cast (tree, tree);

View File

@ -398,59 +398,77 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags, tree quals)
tree tree
grok_array_decl (tree array_expr, tree index_exp) grok_array_decl (tree array_expr, tree index_exp)
{ {
tree type = TREE_TYPE (array_expr); tree type;
tree p1, p2, i1, i2; tree expr;
tree orig_array_expr = array_expr;
tree orig_index_exp = index_exp;
if (type == error_mark_node || index_exp == error_mark_node) if (error_operand_p (array_expr) || error_operand_p (index_exp))
return error_mark_node; return error_mark_node;
if (processing_template_decl) if (processing_template_decl)
return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE, {
array_expr, index_exp); if (type_dependent_expression_p (array_expr)
|| type_dependent_expression_p (index_exp))
return build_min_nt (ARRAY_REF, array_expr, index_exp);
array_expr = build_non_dependent_expr (array_expr);
index_exp = build_non_dependent_expr (index_exp);
}
type = TREE_TYPE (array_expr);
my_friendly_assert (type, 20030626); my_friendly_assert (type, 20030626);
type = non_reference (type); type = non_reference (type);
/* If they have an `operator[]', use that. */ /* If they have an `operator[]', use that. */
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp))) if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
return build_new_op (ARRAY_REF, LOOKUP_NORMAL, expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE); array_expr, index_exp, NULL_TREE);
/* Otherwise, create an ARRAY_REF for a pointer or array type. It
is a little-known fact that, if `a' is an array and `i' is an
int, you can write `i[a]', which means the same thing as `a[i]'. */
if (TREE_CODE (type) == ARRAY_TYPE)
p1 = array_expr;
else
p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false);
if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
p2 = index_exp;
else
p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false);
i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, false);
i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, false);
if ((p1 && i2) && (i1 && p2))
error ("ambiguous conversion for array subscript");
if (p1 && i2)
array_expr = p1, index_exp = i2;
else if (i1 && p2)
array_expr = p2, index_exp = i1;
else else
{ {
error ("invalid types `%T[%T]' for array subscript", tree p1, p2, i1, i2;
type, TREE_TYPE (index_exp));
return error_mark_node; /* Otherwise, create an ARRAY_REF for a pointer or array type.
It is a little-known fact that, if `a' is an array and `i' is
an int, you can write `i[a]', which means the same thing as
`a[i]'. */
if (TREE_CODE (type) == ARRAY_TYPE)
p1 = array_expr;
else
p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false);
if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
p2 = index_exp;
else
p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false);
i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr,
false);
i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp,
false);
if ((p1 && i2) && (i1 && p2))
error ("ambiguous conversion for array subscript");
if (p1 && i2)
array_expr = p1, index_exp = i2;
else if (i1 && p2)
array_expr = p2, index_exp = i1;
else
{
error ("invalid types `%T[%T]' for array subscript",
type, TREE_TYPE (index_exp));
return error_mark_node;
}
if (array_expr == error_mark_node || index_exp == error_mark_node)
error ("ambiguous conversion for array subscript");
expr = build_array_ref (array_expr, index_exp);
} }
if (processing_template_decl && expr != error_mark_node)
if (array_expr == error_mark_node || index_exp == error_mark_node) return build_min (ARRAY_REF, TREE_TYPE (expr), orig_array_expr,
error ("ambiguous conversion for array subscript"); orig_index_exp);
return expr;
return build_array_ref (array_expr, index_exp);
} }
/* Given the cast expression EXP, checking out its validity. Either return /* Given the cast expression EXP, checking out its validity. Either return
@ -2949,8 +2967,37 @@ tree
build_offset_ref_call_from_tree (tree fn, tree args) build_offset_ref_call_from_tree (tree fn, tree args)
{ {
tree object_addr; tree object_addr;
tree orig_fn;
tree orig_args;
tree expr;
my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725); orig_fn = fn;
orig_args = args;
if (processing_template_decl)
{
tree object;
tree object_type;
my_friendly_assert (TREE_CODE (fn) == DOTSTAR_EXPR
|| TREE_CODE (fn) == MEMBER_REF,
20030708);
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args))
return build_min_nt (CALL_EXPR, fn, args);
/* Transform the arguments and add the implicit "this"
parameter. That must be done before the FN is transformed
because we depend on the form of FN. */
args = build_non_dependent_args (args);
object_type = TREE_TYPE (TREE_OPERAND (fn, 0));
if (TREE_CODE (fn) == DOTSTAR_EXPR)
object_type = build_pointer_type (non_reference (object_type));
object = build (NON_DEPENDENT_EXPR, object_type);
args = tree_cons (NULL_TREE, object, args);
/* Now that the arguments are done, transform FN. */
fn = build_non_dependent_expr (fn);
}
/* A qualified name corresponding to a bound pointer-to-member is /* A qualified name corresponding to a bound pointer-to-member is
represented as an OFFSET_REF: represented as an OFFSET_REF:
@ -2958,79 +3005,18 @@ build_offset_ref_call_from_tree (tree fn, tree args)
struct B { void g(); }; struct B { void g(); };
void (B::*p)(); void (B::*p)();
void B::g() { (this->*p)(); } */ void B::g() { (this->*p)(); } */
if (TREE_CODE (TREE_OPERAND (fn, 1)) == FIELD_DECL) if (TREE_CODE (fn) == OFFSET_REF)
/* This case should now be handled elsewhere. */
abort ();
else
{ {
object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0); object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0);
fn = TREE_OPERAND (fn, 1); fn = TREE_OPERAND (fn, 1);
fn = get_member_function_from_ptrfunc (&object_addr, fn); fn = get_member_function_from_ptrfunc (&object_addr, fn);
args = tree_cons (NULL_TREE, object_addr, args); args = tree_cons (NULL_TREE, object_addr, args);
} }
return build_function_call (fn, args);
}
/* FN indicates the function to call. Name resolution has been expr = build_function_call (fn, args);
performed on FN. ARGS are the arguments to the function. They if (processing_template_decl && expr != error_mark_node)
have already been semantically analyzed. DISALLOW_VIRTUAL is true return build_min (CALL_EXPR, TREE_TYPE (expr), orig_fn, orig_args);
if the function call should be determined at compile time, even if return expr;
FN is virtual. */
tree
build_call_from_tree (tree fn, tree args, bool disallow_virtual)
{
tree template_args;
tree template_id;
tree f;
/* Check to see that name lookup has already been performed. */
my_friendly_assert (TREE_CODE (fn) != OFFSET_REF, 20020725);
my_friendly_assert (TREE_CODE (fn) != SCOPE_REF, 20020725);
/* In the future all of this should be eliminated. Instead,
name-lookup for a member function should simply return a
baselink, instead of a FUNCTION_DECL, TEMPLATE_DECL, or
TEMPLATE_ID_EXPR. */
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
{
template_id = fn;
template_args = TREE_OPERAND (fn, 1);
fn = TREE_OPERAND (fn, 0);
}
else
{
template_id = NULL_TREE;
template_args = NULL_TREE;
}
f = (TREE_CODE (fn) == OVERLOAD) ? get_first_fn (fn) : fn;
/* Make sure we have a baselink (rather than simply a
FUNCTION_DECL) for a member function. */
if (current_class_type
&& ((TREE_CODE (f) == FUNCTION_DECL
&& DECL_FUNCTION_MEMBER_P (f))
|| (DECL_FUNCTION_TEMPLATE_P (f)
&& DECL_FUNCTION_MEMBER_P (f))))
{
f = lookup_member (current_class_type, DECL_NAME (f),
/*protect=*/1, /*want_type=*/false);
if (f)
fn = f;
}
if (template_id)
{
if (BASELINK_P (fn))
BASELINK_FUNCTIONS (fn) = build_nt (TEMPLATE_ID_EXPR,
BASELINK_FUNCTIONS (fn),
template_args);
else
fn = template_id;
}
return finish_call_expr (fn, args, disallow_virtual);
} }
/* Returns true if ROOT (a namespace, class, or function) encloses /* Returns true if ROOT (a namespace, class, or function) encloses

View File

@ -988,6 +988,10 @@ dump_decl (tree t, int flags)
dump_decl (BASELINK_FUNCTIONS (t), flags); dump_decl (BASELINK_FUNCTIONS (t), flags);
break; break;
case NON_DEPENDENT_EXPR:
dump_expr (t, flags);
break;
default: default:
sorry_for_unsupported_tree (t); sorry_for_unsupported_tree (t);
/* Fallthrough to error. */ /* Fallthrough to error. */
@ -2028,7 +2032,11 @@ dump_expr (tree t, int flags)
dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS); dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
break; break;
/* else fall through */ case NON_DEPENDENT_EXPR:
output_add_string (scratch_buffer, "<expression of type ");
dump_type (TREE_TYPE (t), flags);
output_add_character (scratch_buffer, '>');
break;
/* This list is incomplete, but should suffice for now. /* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call It is very important that `sorry' does not call

View File

@ -1337,157 +1337,6 @@ get_type_value (tree name)
return NULL_TREE; return NULL_TREE;
} }
/* This code could just as well go in `class.c', but is placed here for
modularity. */
/* For an expression of the form TYPE :: NAME (PARMLIST), build
the appropriate function call. */
tree
build_member_call (tree type, tree name, tree parmlist)
{
tree t;
tree method_name;
tree fns;
int dtor = 0;
tree basetype_path, decl;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR
&& TREE_CODE (type) == NAMESPACE_DECL)
{
/* 'name' already refers to the decls from the namespace, since we
hit do_identifier for template_ids. */
method_name = TREE_OPERAND (name, 0);
/* FIXME: Since we don't do independent names right yet, the
name might also be a LOOKUP_EXPR. Once we resolve this to a
real decl earlier, this can go. This may happen during
tsubst'ing. */
if (TREE_CODE (method_name) == LOOKUP_EXPR)
{
method_name = lookup_namespace_name
(type, TREE_OPERAND (method_name, 0));
TREE_OPERAND (name, 0) = method_name;
}
my_friendly_assert (is_overloaded_fn (method_name), 980519);
return finish_call_expr (name, parmlist, /*disallow_virtual=*/true);
}
if (DECL_P (name))
name = DECL_NAME (name);
if (TREE_CODE (type) == NAMESPACE_DECL)
return finish_call_expr (lookup_namespace_name (type, name),
parmlist,
/*disallow_virtual=*/true);
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
method_name = TREE_OPERAND (name, 0);
if (TREE_CODE (method_name) == COMPONENT_REF)
method_name = TREE_OPERAND (method_name, 1);
if (is_overloaded_fn (method_name))
method_name = DECL_NAME (OVL_CURRENT (method_name));
TREE_OPERAND (name, 0) = method_name;
}
else
method_name = name;
if (TREE_CODE (method_name) == BIT_NOT_EXPR)
{
method_name = TREE_OPERAND (method_name, 0);
dtor = 1;
}
/* This shouldn't be here, and build_member_call shouldn't appear in
parse.y! (mrs) */
if (type && TREE_CODE (type) == IDENTIFIER_NODE
&& get_aggr_from_typedef (type, 0) == 0)
{
tree ns = lookup_name (type, 0);
if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
return finish_call_expr (lookup_namespace_name (ns, name),
parmlist,
/*disallow_virtual=*/true);
}
if (type == NULL_TREE || ! is_aggr_type (type, 1))
return error_mark_node;
/* An operator we did not like. */
if (name == NULL_TREE)
return error_mark_node;
if (dtor)
{
error ("cannot call destructor `%T::~%T' without object", type,
method_name);
return error_mark_node;
}
decl = maybe_dummy_object (type, &basetype_path);
fns = lookup_fnfields (basetype_path, method_name, 0);
if (fns)
{
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
BASELINK_FUNCTIONS (fns) = build_nt (TEMPLATE_ID_EXPR,
BASELINK_FUNCTIONS (fns),
TREE_OPERAND (name, 1));
return build_new_method_call (decl, fns, parmlist,
/*conversion_path=*/NULL_TREE,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
}
/* Convert 'this' to the specified type to disambiguate conversion
to the function's context. */
if (decl == current_class_ref
/* ??? this is wrong, but if this conversion is invalid we need to
defer it until we know whether we are calling a static or
non-static member function. Be conservative for now. */
&& ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type))
{
basetype_path = NULL_TREE;
decl = build_scoped_ref (decl, type, &basetype_path);
if (decl == error_mark_node)
return error_mark_node;
}
if (constructor_name_p (method_name, type))
return build_functional_cast (type, parmlist);
if (TREE_CODE (name) == IDENTIFIER_NODE
&& ((t = lookup_field (TYPE_BINFO (type), name, 1, false))))
{
if (t == error_mark_node)
return error_mark_node;
if (TREE_CODE (t) == FIELD_DECL)
{
if (is_dummy_object (decl))
{
error ("invalid use of non-static field `%D'", t);
return error_mark_node;
}
decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
}
else if (TREE_CODE (t) == VAR_DECL)
decl = t;
else
{
error ("invalid use of member `%D'", t);
return error_mark_node;
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl,
parmlist, NULL_TREE);
return build_function_call (decl, parmlist);
}
else
{
error ("no method `%T::%D'", type, name);
return error_mark_node;
}
}
/* Build a reference to a member of an aggregate. This is not a /* Build a reference to a member of an aggregate. This is not a
C++ `&', but really something which can have its address taken, C++ `&', but really something which can have its address taken,
and then act as a pointer to member, for example TYPE :: FIELD and then act as a pointer to member, for example TYPE :: FIELD

View File

@ -2019,6 +2019,19 @@ write_expression (tree expr)
write_type (TREE_OPERAND (expr, 0)); write_type (TREE_OPERAND (expr, 0));
if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE) if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
write_source_name (TREE_OPERAND (expr, 1)); write_source_name (TREE_OPERAND (expr, 1));
else if (TREE_CODE (TREE_OPERAND (expr, 1)) == TEMPLATE_ID_EXPR)
{
tree template_id;
tree name;
template_id = TREE_OPERAND (expr, 1);
name = TREE_OPERAND (template_id, 0);
/* FIXME: What about operators? */
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
20030707);
write_source_name (TREE_OPERAND (template_id, 0));
write_template_args (TREE_OPERAND (template_id, 1));
}
else else
{ {
/* G++ 3.2 incorrectly put out both the "sr" code and /* G++ 3.2 incorrectly put out both the "sr" code and

View File

@ -1651,6 +1651,8 @@ static tree cp_parser_sizeof_operand
(cp_parser *, enum rid); (cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p static bool cp_parser_declares_only_class_p
(cp_parser *); (cp_parser *);
static tree cp_parser_fold_non_dependent_expr
(tree);
static bool cp_parser_friend_p static bool cp_parser_friend_p
(tree); (tree);
static cp_token *cp_parser_require static cp_token *cp_parser_require
@ -1661,6 +1663,8 @@ static bool cp_parser_token_starts_function_definition_p
(cp_token *); (cp_token *);
static bool cp_parser_next_token_starts_class_definition_p static bool cp_parser_next_token_starts_class_definition_p
(cp_parser *); (cp_parser *);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static enum tag_types cp_parser_token_is_class_key static enum tag_types cp_parser_token_is_class_key
(cp_token *); (cp_token *);
static void cp_parser_check_class_key static void cp_parser_check_class_key
@ -2381,7 +2385,6 @@ cp_parser_primary_expression (cp_parser *parser,
cp_parser_error (parser, "expected primary-expression"); cp_parser_error (parser, "expected primary-expression");
return error_mark_node; return error_mark_node;
} }
/* Fall through. */
/* An id-expression can start with either an identifier, a /* An id-expression can start with either an identifier, a
`::' as the beginning of a qualified-id, or the "operator" `::' as the beginning of a qualified-id, or the "operator"
@ -2600,30 +2603,7 @@ cp_parser_primary_expression (cp_parser *parser,
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR) if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{ {
tree args = TREE_OPERAND (fns, 1); tree args = TREE_OPERAND (fns, 1);
dependent_p = any_dependent_template_arguments_p (args);
if (args && TREE_CODE (args) == TREE_LIST)
{
while (args)
{
if (dependent_template_arg_p (TREE_VALUE (args)))
{
dependent_p = true;
break;
}
args = TREE_CHAIN (args);
}
}
else if (args && TREE_CODE (args) == TREE_VEC)
{
int i;
for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
{
dependent_p = true;
break;
}
}
/* The functions are those referred to by the /* The functions are those referred to by the
template-id. */ template-id. */
fns = TREE_OPERAND (fns, 0); fns = TREE_OPERAND (fns, 0);
@ -2687,27 +2667,34 @@ cp_parser_primary_expression (cp_parser *parser,
/* Only certain kinds of names are allowed in constant /* Only certain kinds of names are allowed in constant
expression. Enumerators have already been handled expression. Enumerators have already been handled
above. */ above. */
if (parser->constant_expression_p if (parser->constant_expression_p)
{
/* Non-type template parameters of integral or /* Non-type template parameters of integral or
enumeration type. */ enumeration type are OK. */
&& !(TREE_CODE (decl) == TEMPLATE_PARM_INDEX if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))) && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
;
/* Const variables or static data members of integral /* Const variables or static data members of integral
or enumeration types initialized with constant or enumeration types initialized with constant
expressions (or dependent expressions - in this case expressions are OK. We also accept dependent
the check will be done at instantiation time). */ initializers; they may turn out to be constant at
&& !(TREE_CODE (decl) == VAR_DECL instantiation-time. */
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)) else if (TREE_CODE (decl) == VAR_DECL
&& DECL_INITIAL (decl) && CP_TYPE_CONST_P (TREE_TYPE (decl))
&& (TREE_CONSTANT (DECL_INITIAL (decl)) && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
|| type_dependent_expression_p && DECL_INITIAL (decl)
(DECL_INITIAL (decl)) && (TREE_CONSTANT (DECL_INITIAL (decl))
|| value_dependent_expression_p || type_dependent_expression_p (DECL_INITIAL
(DECL_INITIAL (decl))))) (decl))
{ || value_dependent_expression_p (DECL_INITIAL
if (!parser->allow_non_constant_expression_p) (decl))))
return cp_parser_non_constant_id_expression (decl); ;
parser->non_constant_expression_p = true; else
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_id_expression (decl);
parser->non_constant_expression_p = true;
}
} }
if (parser->scope) if (parser->scope)
@ -3792,7 +3779,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE) || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
&& args) && args)
{ {
tree arg;
tree identifier = NULL_TREE; tree identifier = NULL_TREE;
tree functions = NULL_TREE; tree functions = NULL_TREE;
@ -3815,10 +3801,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
Do Koenig lookup -- unless any of the arguments are Do Koenig lookup -- unless any of the arguments are
type-dependent. */ type-dependent. */
for (arg = args; arg; arg = TREE_CHAIN (arg)) if (!any_type_dependent_arguments_p (args))
if (type_dependent_expression_p (TREE_VALUE (arg)))
break;
if (!arg)
{ {
postfix_expression postfix_expression
= lookup_arg_dependent (identifier, functions, args); = lookup_arg_dependent (identifier, functions, args);
@ -3827,14 +3810,12 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
/* The unqualified name could not be resolved. */ /* The unqualified name could not be resolved. */
unqualified_name_lookup_error (identifier); unqualified_name_lookup_error (identifier);
postfix_expression = error_mark_node; postfix_expression = error_mark_node;
break;
} }
postfix_expression
= build_call_from_tree (postfix_expression, args,
/*diallow_virtual=*/false);
break;
} }
postfix_expression = build_min_nt (LOOKUP_EXPR, else
identifier); postfix_expression = build_min_nt (LOOKUP_EXPR,
identifier);
} }
else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE) && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
@ -3845,25 +3826,31 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
break; break;
} }
/* In the body of a template, no further processing is
required. */
if (processing_template_decl)
{
postfix_expression = build_nt (CALL_EXPR,
postfix_expression,
args);
break;
}
if (TREE_CODE (postfix_expression) == COMPONENT_REF) if (TREE_CODE (postfix_expression) == COMPONENT_REF)
postfix_expression {
= (build_new_method_call tree instance = TREE_OPERAND (postfix_expression, 0);
(TREE_OPERAND (postfix_expression, 0), tree fn = TREE_OPERAND (postfix_expression, 1);
TREE_OPERAND (postfix_expression, 1),
args, NULL_TREE, if (processing_template_decl
(idk == CP_PARSER_ID_KIND_QUALIFIED && (type_dependent_expression_p (instance)
? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL))); || (!BASELINK_P (fn)
else if (TREE_CODE (postfix_expression) == OFFSET_REF) && TREE_CODE (fn) != FIELD_DECL)
|| any_type_dependent_arguments_p (args)))
{
postfix_expression
= build_min_nt (CALL_EXPR, postfix_expression, args);
break;
}
postfix_expression
= (build_new_method_call
(instance, fn, args, NULL_TREE,
(idk == CP_PARSER_ID_KIND_QUALIFIED
? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
}
else if (TREE_CODE (postfix_expression) == OFFSET_REF
|| TREE_CODE (postfix_expression) == MEMBER_REF
|| TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
postfix_expression = (build_offset_ref_call_from_tree postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, args)); (postfix_expression, args));
else if (idk == CP_PARSER_ID_KIND_QUALIFIED) else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
@ -3968,7 +3955,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
template <typename T> void f(T* t) { t->X::f(); } template <typename T> void f(T* t) { t->X::f(); }
Even though "t" is dependent, "X::f" is not and has Even though "t" is dependent, "X::f" is not and has
except that for a BASELINK there is no need to been resolved to a BASELINK; there is no need to
include scope information. */ include scope information. */
/* But we do need to remember that there was an explicit /* But we do need to remember that there was an explicit
@ -4336,7 +4323,8 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p)
return build_x_indirect_ref (cast_expression, "unary *"); return build_x_indirect_ref (cast_expression, "unary *");
case ADDR_EXPR: case ADDR_EXPR:
return build_x_unary_op (ADDR_EXPR, cast_expression); case BIT_NOT_EXPR:
return build_x_unary_op (unary_operator, cast_expression);
case PREINCREMENT_EXPR: case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR: case PREDECREMENT_EXPR:
@ -4354,9 +4342,6 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p)
case TRUTH_NOT_EXPR: case TRUTH_NOT_EXPR:
return finish_unary_op_expr (unary_operator, cast_expression); return finish_unary_op_expr (unary_operator, cast_expression);
case BIT_NOT_EXPR:
return build_x_unary_op (BIT_NOT_EXPR, cast_expression);
default: default:
abort (); abort ();
return error_mark_node; return error_mark_node;
@ -5293,7 +5278,6 @@ static tree
cp_parser_expression (cp_parser* parser) cp_parser_expression (cp_parser* parser)
{ {
tree expression = NULL_TREE; tree expression = NULL_TREE;
bool saw_comma_p = false;
while (true) while (true)
{ {
@ -5306,45 +5290,23 @@ cp_parser_expression (cp_parser* parser)
save it away. */ save it away. */
if (!expression) if (!expression)
expression = assignment_expression; expression = assignment_expression;
/* Otherwise, chain the expressions together. It is unclear why
we do not simply build COMPOUND_EXPRs as we go. */
else else
expression = tree_cons (NULL_TREE, expression = build_x_compound_expr (expression,
assignment_expression, assignment_expression);
expression);
/* If the next token is not a comma, then we are done with the /* If the next token is not a comma, then we are done with the
expression. */ expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break; break;
/* Consume the `,'. */ /* Consume the `,'. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
/* The first time we see a `,', we must take special action
because the representation used for a single expression is
different from that used for a list containing the single
expression. */
if (!saw_comma_p)
{
/* Remember that this expression has a `,' in it. */
saw_comma_p = true;
/* Turn the EXPRESSION into a TREE_LIST so that we can link
additional expressions to it. */
expression = build_tree_list (NULL_TREE, expression);
}
}
/* Build a COMPOUND_EXPR to represent the entire expression, if
necessary. We built up the list in reverse order, so we must
straighten it out here. */
if (saw_comma_p)
{
/* A comma operator cannot appear in a constant-expression. */ /* A comma operator cannot appear in a constant-expression. */
if (parser->constant_expression_p) if (parser->constant_expression_p)
{ {
if (!parser->allow_non_constant_expression_p) if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("a comma operator"); expression
= cp_parser_non_constant_expression ("a comma operator");
parser->non_constant_expression_p = true; parser->non_constant_expression_p = true;
} }
expression = build_x_compound_expr (nreverse (expression));
} }
return expression; return expression;
@ -5356,8 +5318,9 @@ cp_parser_expression (cp_parser* parser)
conditional-expression conditional-expression
If ALLOW_NON_CONSTANT_P a non-constant expression is silently If ALLOW_NON_CONSTANT_P a non-constant expression is silently
accepted. In that case *NON_CONSTANT_P is set to TRUE. If accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not
ALLOW_NON_CONSTANT_P is false, NON_CONSTANT_P should be NULL. */ constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P
is false, NON_CONSTANT_P should be NULL. */
static tree static tree
cp_parser_constant_expression (cp_parser* parser, cp_parser_constant_expression (cp_parser* parser,
@ -5547,7 +5510,7 @@ cp_parser_labeled_statement (cp_parser* parser)
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */ /* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser, expr = cp_parser_constant_expression (parser,
/*allow_non_constant=*/false, /*allow_non_constant_p=*/false,
NULL); NULL);
/* Create the label. */ /* Create the label. */
statement = finish_case_label (expr, NULL_TREE); statement = finish_case_label (expr, NULL_TREE);
@ -8051,13 +8014,21 @@ cp_parser_template_argument_list (cp_parser* parser)
The representation is that of an assignment-expression, type-id, or The representation is that of an assignment-expression, type-id, or
id-expression -- except that the qualified id-expression is id-expression -- except that the qualified id-expression is
evaluated, so that the value returned is either a DECL or an evaluated, so that the value returned is either a DECL or an
OVERLOAD. */ OVERLOAD.
Although the standard says "assignment-expression", it forbids
throw-expressions or assignments in the template argument.
Therefore, we use "conditional-expression" instead. */
static tree static tree
cp_parser_template_argument (cp_parser* parser) cp_parser_template_argument (cp_parser* parser)
{ {
tree argument; tree argument;
bool template_p; bool template_p;
bool address_p;
cp_token *token;
cp_parser_id_kind idk;
tree qualifying_class;
/* There's really no way to know what we're looking at, so we just /* There's really no way to know what we're looking at, so we just
try each alternative in order. try each alternative in order.
@ -8073,8 +8044,7 @@ cp_parser_template_argument (cp_parser* parser)
argument = cp_parser_type_id (parser); argument = cp_parser_type_id (parser);
/* If the next token isn't a `,' or a `>', then this argument wasn't /* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */ really finished. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) if (!cp_parser_next_token_ends_template_argument_p (parser))
&& cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
cp_parser_error (parser, "expected template-argument"); cp_parser_error (parser, "expected template-argument");
/* If that worked, we're done. */ /* If that worked, we're done. */
if (cp_parser_parse_definitely (parser)) if (cp_parser_parse_definitely (parser))
@ -8088,8 +8058,7 @@ cp_parser_template_argument (cp_parser* parser)
&template_p); &template_p);
/* If the next token isn't a `,' or a `>', then this argument wasn't /* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */ really finished. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) if (!cp_parser_next_token_ends_template_argument_p (parser))
&& cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
cp_parser_error (parser, "expected template-argument"); cp_parser_error (parser, "expected template-argument");
if (!cp_parser_error_occurred (parser)) if (!cp_parser_error_occurred (parser))
{ {
@ -8104,8 +8073,101 @@ cp_parser_template_argument (cp_parser* parser)
} }
if (cp_parser_parse_definitely (parser)) if (cp_parser_parse_definitely (parser))
return argument; return argument;
/* It must be an assignment-expression. */ /* It must be a non-type argument. There permitted cases are given
return cp_parser_assignment_expression (parser); in [temp.arg.nontype]:
-- an integral constant-expression of integral or enumeration
type; or
-- the name of a non-type template-parameter; or
-- the name of an object or function with external linkage...
-- the address of an object or function with external linkage...
-- a pointer to member... */
/* Look for a non-type template parameter. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_simulate_error (parser);
if (cp_parser_parse_definitely (parser))
return argument;
}
/* If the next token is "&", the argument must be the address of an
object or function with external linkage. */
address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND);
if (address_p)
cp_lexer_consume_token (parser->lexer);
/* See if we might have an id-expression. */
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME
|| token->keyword == RID_OPERATOR
|| token->type == CPP_SCOPE
|| token->type == CPP_TEMPLATE_ID
|| token->type == CPP_NESTED_NAME_SPECIFIER)
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
if (cp_parser_error_occurred (parser)
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_abort_tentative_parse (parser);
else
{
if (qualifying_class)
argument = finish_qualified_id_expr (qualifying_class,
argument,
/*done=*/true,
address_p);
if (TREE_CODE (argument) == VAR_DECL)
{
/* A variable without external linkage might still be a
valid constant-expression, so no error is issued here
if the external-linkage check fails. */
if (!DECL_EXTERNAL_LINKAGE_P (argument))
cp_parser_simulate_error (parser);
}
else if (is_overloaded_fn (argument))
/* All overloaded functions are allowed; if the external
linkage test does not pass, an error will be issued
later. */
;
else if (address_p
&& (TREE_CODE (argument) == OFFSET_REF
|| TREE_CODE (argument) == SCOPE_REF))
/* A pointer-to-member. */
;
else
cp_parser_simulate_error (parser);
if (cp_parser_parse_definitely (parser))
{
if (address_p)
argument = build_x_unary_op (ADDR_EXPR, argument);
return argument;
}
}
}
/* If the argument started with "&", there are no other valid
alternatives at this point. */
if (address_p)
{
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
/* The argument must be a constant-expression. */
argument = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/NULL);
/* If it's non-dependent, simplify it. */
return cp_parser_fold_non_dependent_expr (argument);
} }
/* Parse an explicit-instantiation. /* Parse an explicit-instantiation.
@ -8914,7 +8976,7 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
/* Parse the value. */ /* Parse the value. */
value = cp_parser_constant_expression (parser, value = cp_parser_constant_expression (parser,
/*allow_non_constant=*/false, /*allow_non_constant_p=*/false,
NULL); NULL);
} }
else else
@ -9919,29 +9981,8 @@ cp_parser_direct_declarator (cp_parser* parser,
= cp_parser_constant_expression (parser, = cp_parser_constant_expression (parser,
/*allow_non_constant=*/true, /*allow_non_constant=*/true,
&non_constant_p); &non_constant_p);
/* If we're in a template, but the constant-expression if (!non_constant_p)
isn't value dependent, simplify it. We're supposed bounds = cp_parser_fold_non_dependent_expr (bounds);
to treat:
template <typename T> void f(T[1 + 1]);
template <typename T> void f(T[2]);
as two declarations of the same function, for
example. */
if (processing_template_decl
&& !non_constant_p
&& !value_dependent_expression_p (bounds))
{
HOST_WIDE_INT saved_processing_template_decl;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
bounds = tsubst_copy_and_build (bounds,
/*args=*/NULL_TREE,
tf_error,
/*in_decl=*/NULL_TREE);
processing_template_decl = saved_processing_template_decl;
}
} }
else else
bounds = NULL_TREE; bounds = NULL_TREE;
@ -14129,6 +14170,36 @@ cp_parser_declares_only_class_p (cp_parser *parser)
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA)); || cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
} }
/* Simplify EXPR if it is a non-dependent expression. Returns the
(possibly simplified) expression. */
static tree
cp_parser_fold_non_dependent_expr (tree expr)
{
/* If we're in a template, but EXPR isn't value dependent, simplify
it. We're supposed to treat:
template <typename T> void f(T[1 + 1]);
template <typename T> void f(T[2]);
as two declarations of the same function, for example. */
if (processing_template_decl
&& !type_dependent_expression_p (expr)
&& !value_dependent_expression_p (expr))
{
HOST_WIDE_INT saved_processing_template_decl;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
expr = tsubst_copy_and_build (expr,
/*args=*/NULL_TREE,
tf_error,
/*in_decl=*/NULL_TREE);
processing_template_decl = saved_processing_template_decl;
}
return expr;
}
/* DECL_SPECIFIERS is the representation of a decl-specifier-seq. /* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */ Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */
@ -14274,6 +14345,18 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON); return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
} }
/* Returns TRUE iff the next token is the "," or ">" ending a
template-argument. */
static bool
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
return (token->type == CPP_COMMA || token->type == CPP_GREATER);
}
/* Returns the kind of tag indicated by TOKEN, if it is a class-key, /* Returns the kind of tag indicated by TOKEN, if it is a class-key,
or none_type otherwise. */ or none_type otherwise. */

View File

@ -167,7 +167,6 @@ static void copy_default_args_to_explicit_spec (tree);
static int invalid_nontype_parm_type_p (tree, tsubst_flags_t); static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
static int eq_local_specializations (const void *, const void *); static int eq_local_specializations (const void *, const void *);
static bool dependent_type_p_r (tree); static bool dependent_type_p_r (tree);
static bool dependent_template_id_p (tree, tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree); static tree tsubst (tree, tree, tsubst_flags_t, tree);
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree); static tree tsubst_expr (tree, tree, tsubst_flags_t, tree);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
@ -3594,9 +3593,6 @@ convert_template_argument (tree parm,
if (invalid_nontype_parm_type_p (t, complain)) if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node; return error_mark_node;
if (processing_template_decl)
arg = maybe_fold_nontype_arg (arg);
if (!uses_template_parms (arg) && !uses_template_parms (t)) if (!uses_template_parms (arg) && !uses_template_parms (t))
/* We used to call digest_init here. However, digest_init /* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain will report errors, which we don't want when complain
@ -7108,9 +7104,8 @@ tsubst_baselink (tree baselink, tree object_type,
template_id_p = true; template_id_p = true;
template_args = TREE_OPERAND (fns, 1); template_args = TREE_OPERAND (fns, 1);
fns = TREE_OPERAND (fns, 0); fns = TREE_OPERAND (fns, 0);
template_args = tsubst_copy (template_args, args, template_args = tsubst_copy_and_build (template_args, args,
complain, in_decl); complain, in_decl);
maybe_fold_nontype_args (template_args);
} }
name = DECL_NAME (get_first_fn (fns)); name = DECL_NAME (get_first_fn (fns));
baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1); baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
@ -8003,30 +7998,17 @@ tsubst_copy_and_build (tree t,
case PREDECREMENT_EXPR: case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR: case PREINCREMENT_EXPR:
if (TREE_TYPE (t))
return tsubst_copy (t, args, complain, in_decl);
else
return build_x_unary_op
(TREE_CODE (t),
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
in_decl));
case NEGATE_EXPR: case NEGATE_EXPR:
case BIT_NOT_EXPR: case BIT_NOT_EXPR:
if (TREE_TYPE (t))
return tsubst_copy (t, args, complain, in_decl);
else
return build_x_unary_op
(TREE_CODE (t),
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
in_decl));
case ABS_EXPR: case ABS_EXPR:
if (TREE_TYPE (t)) case TRUTH_NOT_EXPR:
return t; case CONVERT_EXPR: /* Unary + */
return build_x_unary_op case REALPART_EXPR:
(TREE_CODE (t), case IMAGPART_EXPR:
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl)); return (build_x_unary_op
(TREE_CODE (t),
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
in_decl)));
case ADDR_EXPR: case ADDR_EXPR:
op1 = TREE_OPERAND (t, 0); op1 = TREE_OPERAND (t, 0);
@ -8037,18 +8019,6 @@ tsubst_copy_and_build (tree t,
op1 = tsubst_copy_and_build (op1, args, complain, in_decl); op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
return build_x_unary_op (ADDR_EXPR, op1); return build_x_unary_op (ADDR_EXPR, op1);
case TRUTH_NOT_EXPR:
case CONVERT_EXPR: /* Unary + */
case REALPART_EXPR:
case IMAGPART_EXPR:
if (TREE_TYPE (t))
return tsubst_copy (t, args, complain, in_decl);
else
return build_x_unary_op
(TREE_CODE (t),
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
in_decl));
case PLUS_EXPR: case PLUS_EXPR:
case MINUS_EXPR: case MINUS_EXPR:
case MULT_EXPR: case MULT_EXPR:
@ -8119,15 +8089,25 @@ tsubst_copy_and_build (tree t,
case SIZEOF_EXPR: case SIZEOF_EXPR:
case ALIGNOF_EXPR: case ALIGNOF_EXPR:
{ op1 = TREE_OPERAND (t, 0);
tree r = if (!args)
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl); {
if (!TYPE_P (r)) /* When there are no ARGS, we are trying to evaluate a
return TREE_CODE (t) == SIZEOF_EXPR ? non-dependent expression from the parser. Trying to do
expr_sizeof (r) : c_alignof_expr (r); the substitutions may not work. */
else if (!TYPE_P (op1))
return cxx_sizeof_or_alignof_type (r, TREE_CODE (t), true); op1 = TREE_TYPE (op1);
} }
else
{
++skip_evaluation;
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
--skip_evaluation;
}
if (TREE_CODE (t) == SIZEOF_EXPR)
return finish_sizeof (op1);
else
return finish_alignof (op1);
case MODOP_EXPR: case MODOP_EXPR:
return build_x_modify_expr return build_x_modify_expr
@ -8162,15 +8142,11 @@ tsubst_copy_and_build (tree t,
DELETE_EXPR_USE_GLOBAL (t)); DELETE_EXPR_USE_GLOBAL (t));
case COMPOUND_EXPR: case COMPOUND_EXPR:
{ return (build_x_compound_expr
if (tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl) (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
== NULL_TREE) in_decl),
return build_x_compound_expr tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl)));
in_decl));
else
abort ();
}
case CALL_EXPR: case CALL_EXPR:
{ {
@ -8210,25 +8186,23 @@ tsubst_copy_and_build (tree t,
complain, in_decl); complain, in_decl);
if (BASELINK_P (function)) if (BASELINK_P (function))
return build_call_from_tree (function, call_args, 1); qualified_p = 1;
else
{
if (call_args != NULL_TREE && koenig_name)
function = lookup_arg_dependent (koenig_name,
function,
call_args);
if (TREE_CODE (function) == OFFSET_REF) if (call_args != NULL_TREE && koenig_name)
return build_offset_ref_call_from_tree (function, call_args); function = lookup_arg_dependent (koenig_name,
if (TREE_CODE (function) == COMPONENT_REF) function,
return (build_new_method_call call_args);
(TREE_OPERAND (function, 0),
TREE_OPERAND (function, 1), if (TREE_CODE (function) == OFFSET_REF)
call_args, NULL_TREE, return build_offset_ref_call_from_tree (function, call_args);
qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)); if (TREE_CODE (function) == COMPONENT_REF)
return finish_call_expr (function, call_args, return (build_new_method_call
/*disallow_virtual=*/qualified_p); (TREE_OPERAND (function, 0),
} TREE_OPERAND (function, 1),
call_args, NULL_TREE,
qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
return finish_call_expr (function, call_args,
/*disallow_virtual=*/qualified_p);
} }
case COND_EXPR: case COND_EXPR:
@ -8389,6 +8363,11 @@ tsubst_copy_and_build (tree t,
case VAR_DECL: case VAR_DECL:
if (args) if (args)
t = tsubst_copy (t, args, complain, in_decl); t = tsubst_copy (t, args, complain, in_decl);
else
/* If there are no ARGS, then we are evaluating a
non-dependent expression. If the expression is
non-dependent, the variable must be a constant. */
t = DECL_INITIAL (t);
return convert_from_reference (t); return convert_from_reference (t);
case VA_ARG_EXPR: case VA_ARG_EXPR:
@ -11491,26 +11470,46 @@ value_dependent_expression_p (tree expression)
with an expression that is value-dependent. */ with an expression that is value-dependent. */
if (TREE_CODE (expression) == VAR_DECL if (TREE_CODE (expression) == VAR_DECL
&& DECL_INITIAL (expression) && DECL_INITIAL (expression)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (expression) && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (expression))
&& value_dependent_expression_p (DECL_INITIAL (expression))) && value_dependent_expression_p (DECL_INITIAL (expression)))
return true; return true;
/* These expressions are value-dependent if the type to which the /* These expressions are value-dependent if the type to which the
cast occurs is dependent or the expression being casted is cast occurs is dependent or the expression being casted is
value-dependent. */ value-dependent. */
if ((TREE_CODE (expression) == DYNAMIC_CAST_EXPR if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
|| TREE_CODE (expression) == STATIC_CAST_EXPR || TREE_CODE (expression) == STATIC_CAST_EXPR
|| TREE_CODE (expression) == CONST_CAST_EXPR || TREE_CODE (expression) == CONST_CAST_EXPR
|| TREE_CODE (expression) == REINTERPRET_CAST_EXPR || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
|| TREE_CODE (expression) == CAST_EXPR) || TREE_CODE (expression) == CAST_EXPR)
&& (dependent_type_p (TREE_TYPE (expression)) {
|| value_dependent_expression_p (TREE_OPERAND (expression, 0)))) if (dependent_type_p (TREE_TYPE (expression)))
return true; return true;
/* A `sizeof' expression where the sizeof operand is a type is /* A functional cast has a list of operands. */
value-dependent if the type is dependent. If the type was not expression = TREE_OPERAND (expression, 0);
dependent, we would no longer have a SIZEOF_EXPR, so any if (TREE_CODE (expression) == TREE_LIST)
SIZEOF_EXPR is dependent. */ {
if (TREE_CODE (expression) == SIZEOF_EXPR) do
return true; {
if (value_dependent_expression_p (TREE_VALUE (expression)))
return true;
expression = TREE_CHAIN (expression);
}
while (expression);
return false;
}
else
return value_dependent_expression_p (expression);
}
/* A `sizeof' expression is value-dependent if the operand is
type-dependent. */
if (TREE_CODE (expression) == SIZEOF_EXPR
|| TREE_CODE (expression) == ALIGNOF_EXPR)
{
expression = TREE_OPERAND (expression, 0);
if (TYPE_P (expression))
return dependent_type_p (expression);
return type_dependent_expression_p (expression);
}
/* A constant expression is value-dependent if any subexpression is /* A constant expression is value-dependent if any subexpression is
value-dependent. */ value-dependent. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression)))) if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
@ -11574,10 +11573,11 @@ type_dependent_expression_p (tree expression)
|| TREE_CODE (expression) == REINTERPRET_CAST_EXPR || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
|| TREE_CODE (expression) == CAST_EXPR) || TREE_CODE (expression) == CAST_EXPR)
return dependent_type_p (TREE_TYPE (expression)); return dependent_type_p (TREE_TYPE (expression));
/* The types of these expressions depends only on the type created /* The types of these expressions depends only on the type created
by the expression. */ by the expression. */
else if (TREE_CODE (expression) == NEW_EXPR if (TREE_CODE (expression) == NEW_EXPR
|| TREE_CODE (expression) == VEC_NEW_EXPR) || TREE_CODE (expression) == VEC_NEW_EXPR)
{ {
/* For NEW_EXPR tree nodes created inside a template, either /* For NEW_EXPR tree nodes created inside a template, either
the object type itself or a TREE_LIST may appear as the the object type itself or a TREE_LIST may appear as the
@ -11601,12 +11601,53 @@ type_dependent_expression_p (tree expression)
INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression))))) INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
return true; return true;
if (TREE_TYPE (expression) == unknown_type_node)
{
if (TREE_CODE (expression) == ADDR_EXPR)
return type_dependent_expression_p (TREE_OPERAND (expression, 0));
if (TREE_CODE (expression) == BASELINK)
expression = BASELINK_FUNCTIONS (expression);
if (TREE_CODE (expression) == TEMPLATE_ID_EXPR)
{
if (any_dependent_template_arguments_p (TREE_OPERAND (expression,
1)))
return true;
expression = TREE_OPERAND (expression, 0);
}
if (TREE_CODE (expression) == OVERLOAD)
{
while (expression)
{
if (type_dependent_expression_p (OVL_CURRENT (expression)))
return true;
expression = OVL_NEXT (expression);
}
return false;
}
abort ();
}
return (dependent_type_p (TREE_TYPE (expression))); return (dependent_type_p (TREE_TYPE (expression)));
} }
/* Returns TRUE if ARGS (a TREE_LIST of arguments to a function call)
contains a type-dependent expression. */
bool
any_type_dependent_arguments_p (tree args)
{
while (args)
{
if (type_dependent_expression_p (TREE_VALUE (args)))
return true;
args = TREE_CHAIN (args);
}
return false;
}
/* Returns TRUE if the ARG (a template argument) is dependent. */ /* Returns TRUE if the ARG (a template argument) is dependent. */
bool static bool
dependent_template_arg_p (tree arg) dependent_template_arg_p (tree arg)
{ {
if (!processing_template_decl) if (!processing_template_decl)
@ -11622,18 +11663,36 @@ dependent_template_arg_p (tree arg)
|| value_dependent_expression_p (arg)); || value_dependent_expression_p (arg));
} }
/* Returns TRUE if the specialization TMPL<ARGS> is dependent. */ /* Returns true if ARGS (a collection of template arguments) contains
any dependent arguments. */
static bool bool
dependent_template_id_p (tree tmpl, tree args) any_dependent_template_arguments_p (tree args)
{ {
int i; if (!args)
return false;
my_friendly_assert (TREE_CODE (args) == TREE_LIST
|| TREE_CODE (args) == TREE_VEC,
20030707);
if (TREE_CODE (args) == TREE_LIST)
{
while (args)
{
if (dependent_template_arg_p (TREE_VALUE (args)))
return true;
args = TREE_CHAIN (args);
}
}
else
{
int i;
for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
return true;
}
if (dependent_template_p (tmpl))
return true;
for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
return true;
return false; return false;
} }
@ -11646,12 +11705,24 @@ dependent_template_p (tree tmpl)
if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl) if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
|| TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM) || TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
return true; return true;
/* So are qualified names that have not been looked up. */
if (TREE_CODE (tmpl) == SCOPE_REF)
return true;
/* So are member templates of dependent classes. */ /* So are member templates of dependent classes. */
if (TYPE_P (CP_DECL_CONTEXT (tmpl))) if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
return dependent_type_p (DECL_CONTEXT (tmpl)); return dependent_type_p (DECL_CONTEXT (tmpl));
return false; return false;
} }
/* Returns TRUE if the specialization TMPL<ARGS> is dependent. */
bool
dependent_template_id_p (tree tmpl, tree args)
{
return (dependent_template_p (tmpl)
|| any_dependent_template_arguments_p (args));
}
/* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the /* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the
TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE
can be found. Note that this function peers inside uninstantiated can be found. Note that this function peers inside uninstantiated
@ -11730,4 +11801,54 @@ resolve_typename_type (tree type, bool only_current_p)
return type; return type;
} }
/* EXPR is an expression which is not type-dependent. Return a proxy
for EXPR that can be used to compute the types of larger
expressions containing EXPR. */
tree
build_non_dependent_expr (tree expr)
{
/* Preserve null pointer constants so that the type of things like
"p == 0" where "p" is a pointer can be determined. */
if (null_ptr_cst_p (expr))
return expr;
/* Preserve OVERLOADs; the functions must be available to resolve
types. */
if (TREE_CODE (expr) == OVERLOAD)
return expr;
/* Otherwise, build a NON_DEPENDENT_EXPR.
REFERENCE_TYPEs are not stripped for expressions in templates
because doing so would play havoc with mangling. Consider, for
example:
template <typename T> void f<T& g>() { g(); }
In the body of "f", the expression for "g" will have
REFERENCE_TYPE, even though the standard says that it should
not. The reason is that we must preserve the syntactic form of
the expression so that mangling (say) "f<g>" inside the body of
"f" works out correctly. Therefore, the REFERENCE_TYPE is
stripped here. */
return build (NON_DEPENDENT_EXPR, non_reference (TREE_TYPE (expr)));
}
/* ARGS is a TREE_LIST of expressions as arguments to a function call.
Return a new TREE_LIST with the various arguments replaced with
equivalent non-dependent expressions. */
tree
build_non_dependent_args (tree args)
{
tree a;
tree new_args;
new_args = NULL_TREE;
for (a = args; a; a = TREE_CHAIN (a))
new_args = tree_cons (NULL_TREE,
build_non_dependent_expr (TREE_VALUE (a)),
new_args);
return nreverse (new_args);
}
#include "gt-cp-pt.h" #include "gt-cp-pt.h"

View File

@ -1449,8 +1449,12 @@ finish_stmt_expr (tree rtl_expr)
tree result; tree result;
/* If the last thing in the statement-expression was not an /* If the last thing in the statement-expression was not an
expression-statement, then it has type `void'. */ expression-statement, then it has type `void'. In a template, we
if (!last_expr_type) cannot distinguish the case where the last expression-statement
had a dependent type from the case where the last statement was
not an expression-statement. Therefore, we (incorrectly) treat
the STMT_EXPR as dependent in that case. */
if (!last_expr_type && !processing_template_decl)
last_expr_type = void_type_node; last_expr_type = void_type_node;
result = build_min (STMT_EXPR, last_expr_type, last_tree); result = build_min (STMT_EXPR, last_expr_type, last_tree);
TREE_SIDE_EFFECTS (result) = 1; TREE_SIDE_EFFECTS (result) = 1;
@ -1482,16 +1486,32 @@ finish_stmt_expr (tree rtl_expr)
tree tree
finish_call_expr (tree fn, tree args, bool disallow_virtual) finish_call_expr (tree fn, tree args, bool disallow_virtual)
{ {
tree result;
tree orig_fn;
tree orig_args;
if (fn == error_mark_node || args == error_mark_node) if (fn == error_mark_node || args == error_mark_node)
return error_mark_node; return error_mark_node;
if (processing_template_decl)
return build_nt (CALL_EXPR, fn, args, NULL_TREE);
/* ARGS should be a list of arguments. */ /* ARGS should be a list of arguments. */
my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST, my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
20020712); 20020712);
orig_fn = fn;
orig_args = args;
if (processing_template_decl)
{
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args))
return build_nt (CALL_EXPR, fn, args);
if (!BASELINK_P (fn)
&& TREE_CODE (fn) != PSEUDO_DTOR_EXPR
&& TREE_TYPE (fn) != unknown_type_node)
fn = build_non_dependent_expr (fn);
args = build_non_dependent_args (orig_args);
}
/* A reference to a member function will appear as an overloaded /* A reference to a member function will appear as an overloaded
function (rather than a BASELINK) if an unqualified name was used function (rather than a BASELINK) if an unqualified name was used
to refer to it. */ to refer to it. */
@ -1512,6 +1532,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
} }
} }
result = NULL_TREE;
if (BASELINK_P (fn)) if (BASELINK_P (fn))
{ {
tree object; tree object;
@ -1551,17 +1572,22 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
object = build_dummy_object (DECL_CONTEXT (representative_fn)); object = build_dummy_object (DECL_CONTEXT (representative_fn));
} }
return build_new_method_call (object, fn, args, NULL_TREE, if (processing_template_decl)
(disallow_virtual {
? LOOKUP_NONVIRTUAL : 0)); if (type_dependent_expression_p (object))
return build_nt (CALL_EXPR, orig_fn, orig_args);
object = build_non_dependent_expr (object);
}
result = build_new_method_call (object, fn, args, NULL_TREE,
(disallow_virtual
? LOOKUP_NONVIRTUAL : 0));
} }
else if (is_overloaded_fn (fn)) else if (is_overloaded_fn (fn))
/* A call to a namespace-scope function. */ /* A call to a namespace-scope function. */
return build_new_function_call (fn, args); result = build_new_function_call (fn, args);
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR) else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{ {
tree result;
if (args) if (args)
error ("arguments to destructor are not allowed"); error ("arguments to destructor are not allowed");
/* Mark the pseudo-destructor call as having side-effects so /* Mark the pseudo-destructor call as having side-effects so
@ -1570,20 +1596,18 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
void_type_node, void_type_node,
TREE_OPERAND (fn, 0)); TREE_OPERAND (fn, 0));
TREE_SIDE_EFFECTS (result) = 1; TREE_SIDE_EFFECTS (result) = 1;
return result;
} }
else if (CLASS_TYPE_P (TREE_TYPE (fn))) else if (CLASS_TYPE_P (TREE_TYPE (fn)))
{ /* If the "function" is really an object of class type, it might
/* If the "function" is really an object of class type, it might have an overloaded `operator ()'. */
have an overloaded `operator ()'. */ result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
tree result; if (!result)
result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE); /* A call where the function is unknown. */
if (result) result = build_function_call (fn, args);
return result;
}
/* A call where the function is unknown. */ if (processing_template_decl)
return build_function_call (fn, args); return build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args);
return result;
} }
/* Finish a call to a postfix increment or decrement or EXPR. (Which /* Finish a call to a postfix increment or decrement or EXPR. (Which

View File

@ -174,6 +174,14 @@ lvalue_p_1 (tree ref,
return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
? clk_none : clk_ordinary); ? clk_none : clk_ordinary);
case NON_DEPENDENT_EXPR:
/* We must consider NON_DEPENDENT_EXPRs to be lvalues so that
things like "&E" where "E" is an expression with a
non-dependent type work. It is safe to be lenient because an
error will be issued when the template is instantiated if "E"
is not an lvalue. */
return clk_ordinary;
default: default:
break; break;
} }

View File

@ -1417,7 +1417,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720); my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (op, type); return build_min (op, size_type_node, type);
op_name = operator_name_info[(int) op].name; op_name = operator_name_info[(int) op].name;
@ -1446,7 +1446,7 @@ tree
expr_sizeof (tree e) expr_sizeof (tree e)
{ {
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (SIZEOF_EXPR, e); return build_min (SIZEOF_EXPR, size_type_node, e);
if (TREE_CODE (e) == COMPONENT_REF if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1))) && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
@ -2015,17 +2015,36 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
tree tree
finish_class_member_access_expr (tree object, tree name) finish_class_member_access_expr (tree object, tree name)
{ {
tree expr;
tree object_type; tree object_type;
tree member; tree member;
tree access_path = NULL_TREE; tree access_path = NULL_TREE;
tree orig_object = object;
tree orig_name = name;
if (object == error_mark_node || name == error_mark_node) if (object == error_mark_node || name == error_mark_node)
return error_mark_node; return error_mark_node;
if (processing_template_decl)
return build_min_nt (COMPONENT_REF, object, name);
object_type = TREE_TYPE (object); object_type = TREE_TYPE (object);
if (processing_template_decl)
{
if (/* If OBJECT_TYPE is dependent, so is OBJECT.NAME. */
dependent_type_p (object_type)
/* If NAME is "f<args>", where either 'f' or 'args' is
dependent, then the expression is dependent. */
|| (TREE_CODE (name) == TEMPLATE_ID_EXPR
&& dependent_template_id_p (TREE_OPERAND (name, 0),
TREE_OPERAND (name, 1)))
/* If NAME is "T::X" where "T" is dependent, then the
expression is dependent. */
|| (TREE_CODE (name) == SCOPE_REF
&& TYPE_P (TREE_OPERAND (name, 0))
&& dependent_type_p (TREE_OPERAND (name, 0))))
return build_min_nt (COMPONENT_REF, object, name);
object = build_non_dependent_expr (object);
}
if (TREE_CODE (object_type) == REFERENCE_TYPE) if (TREE_CODE (object_type) == REFERENCE_TYPE)
{ {
object = convert_from_reference (object); object = convert_from_reference (object);
@ -2057,6 +2076,7 @@ finish_class_member_access_expr (tree object, tree name)
{ {
bool is_template_id = false; bool is_template_id = false;
tree template_args = NULL_TREE; tree template_args = NULL_TREE;
tree scope;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR) if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{ {
@ -2067,8 +2087,6 @@ finish_class_member_access_expr (tree object, tree name)
if (TREE_CODE (name) == SCOPE_REF) if (TREE_CODE (name) == SCOPE_REF)
{ {
tree scope;
/* A qualified name. The qualifying class or namespace `S' has /* A qualified name. The qualifying class or namespace `S' has
already been looked up; it is either a TYPE or a already been looked up; it is either a TYPE or a
NAMESPACE_DECL. The member name is either an IDENTIFIER_NODE NAMESPACE_DECL. The member name is either an IDENTIFIER_NODE
@ -2095,57 +2113,35 @@ finish_class_member_access_expr (tree object, tree name)
access_path = lookup_base (object_type, scope, ba_check, NULL); access_path = lookup_base (object_type, scope, ba_check, NULL);
if (!access_path || access_path == error_mark_node) if (!access_path || access_path == error_mark_node)
return error_mark_node; return error_mark_node;
if (TREE_CODE (name) == BIT_NOT_EXPR)
member = lookup_destructor (object, scope, name);
else
{
/* Look up the member. */
member = lookup_member (access_path, name, /*protect=*/1,
/*want_type=*/false);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
return error_mark_node;
}
if (member == error_mark_node)
return error_mark_node;
}
} }
else if (TREE_CODE (name) == BIT_NOT_EXPR) else
member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
else if (TREE_CODE (name) == IDENTIFIER_NODE)
{ {
/* An unqualified name. */ scope = NULL_TREE;
member = lookup_member (object_type, name, /*protect=*/1, access_path = object_type;
}
if (TREE_CODE (name) == BIT_NOT_EXPR)
member = lookup_destructor (object, scope, name);
else
{
/* Look up the member. */
member = lookup_member (access_path, name, /*protect=*/1,
/*want_type=*/false); /*want_type=*/false);
if (member == NULL_TREE) if (member == NULL_TREE)
{ {
error ("'%D' has no member named '%E'", object_type, name); error ("'%D' has no member named '%E'", object_type, name);
return error_mark_node; return error_mark_node;
} }
else if (member == error_mark_node) if (member == error_mark_node)
return error_mark_node; return error_mark_node;
} }
else
{
/* The YACC parser sometimes gives us things that are not names.
These always indicate errors. The recursive-descent parser
does not do this, so this code can go away once that parser
replaces the YACC parser. */
error ("invalid use of `%D'", name);
return error_mark_node;
}
if (is_template_id) if (is_template_id)
{ {
tree template = member; tree template = member;
if (BASELINK_P (template)) if (BASELINK_P (template))
BASELINK_FUNCTIONS (template) template = lookup_template_function (template, template_args);
= build_nt (TEMPLATE_ID_EXPR,
BASELINK_FUNCTIONS (template),
template_args);
else else
{ {
error ("`%D' is not a member template function", name); error ("`%D' is not a member template function", name);
@ -2157,8 +2153,12 @@ finish_class_member_access_expr (tree object, tree name)
if (TREE_DEPRECATED (member)) if (TREE_DEPRECATED (member))
warn_deprecated_use (member); warn_deprecated_use (member);
return build_class_member_access_expr (object, member, access_path, expr = build_class_member_access_expr (object, member, access_path,
/*preserve_reference=*/false); /*preserve_reference=*/false);
if (processing_template_decl && expr != error_mark_node)
return build_min (COMPONENT_REF, TREE_TYPE (expr), orig_object,
orig_name);
return expr;
} }
/* Return an expression for the MEMBER_NAME field in the internal /* Return an expression for the MEMBER_NAME field in the internal
@ -2196,18 +2196,27 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
Must also handle REFERENCE_TYPEs for C++. */ Must also handle REFERENCE_TYPEs for C++. */
tree tree
build_x_indirect_ref (tree ptr, const char *errorstring) build_x_indirect_ref (tree expr, const char *errorstring)
{ {
tree orig_expr = expr;
tree rval; tree rval;
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (INDIRECT_REF, ptr); {
if (type_dependent_expression_p (expr))
return build_min_nt (INDIRECT_REF, expr);
expr = build_non_dependent_expr (expr);
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
NULL_TREE); NULL_TREE);
if (rval) if (!rval)
rval = build_indirect_ref (expr, errorstring);
if (processing_template_decl && rval != error_mark_node)
return build_min (INDIRECT_REF, TREE_TYPE (rval), orig_expr);
else
return rval; return rval;
return build_indirect_ref (ptr, errorstring);
} }
tree tree
@ -2826,191 +2835,32 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
tree tree
build_x_binary_op (enum tree_code code, tree arg1, tree arg2) build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
{ {
tree orig_arg1;
tree orig_arg2;
tree expr;
orig_arg1 = arg1;
orig_arg2 = arg2;
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (code, arg1, arg2);
if (code == DOTSTAR_EXPR)
return build_m_component_ref (arg1, arg2);
return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
#if 0
tree
build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
{
tree type;
/* If any of the operands is erroneous the result is erroneous too. */
if (error_operand_p (op0)
|| (op1 && error_operand_p (op1))
|| (op2 && error_operand_p (op2)))
return error_mark_node;
if (dependent_type_p (TREE_TYPE (op0))
|| (op1 && dependent_type_p (TREE_TYPE (op1)))
|| (op2 && dependent_type_p (TREE_TYPE (op2))))
/* If at least one operand has a dependent type, we cannot
determine the type of the expression until instantiation time. */
type = NULL_TREE;
else
{ {
struct z_candidate *cand; if (type_dependent_expression_p (arg1)
tree op0_type; || type_dependent_expression_p (arg2))
tree op1_type; return build_min_nt (code, arg1, arg2);
tree op2_type; arg1 = build_non_dependent_expr (arg1);
arg2 = build_non_dependent_expr (arg2);
/* None of the operands is dependent, so we can compute the type
of the expression at this point. We must compute the type so
that in things like:
template <int I>
void f() { S<sizeof(I + 3)> s; ... }
we can tell that the type of "s" is non-dependent.
If we're processing a template argument, we do not want to
actually change the operands in any way. Adding conversions,
performing constant folding, etc., would all change mangled
names. For example, in:
template <int I>
void f(S<sizeof(3 + 4 + I)>);
we need to determine that "3 + 4 + I" has type "int", without
actually turning the expression into "7 + I". */
cand = find_overloaded_op (code, op0, op1, op2);
if (cand)
/* If an overloaded operator was found, the expression will
have the type returned by the function. */
type = non_reference (TREE_TYPE (cand->fn));
else
{
/* There is no overloaded operator so we can just use the
default rules for determining the type of the operand. */
op0_type = TREE_TYPE (op0);
op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
type = NULL_TREE;
switch (code)
{
case MODIFY_EXPR:
/* [expr.ass]
The result of the assignment operation is the value
stored in the left operand. */
type = op0_type;
break;
case COMPONENT_REF:
/* Implement this case. */
break;
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
/* [expr.post.incr]
The type of the result is the cv-unqualified version
of the type of the operand. */
type = TYPE_MAIN_VARIANT (op0_type);
break;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
/* [expr.pre.incr]
The value is the new value of the operand. */
type = op0_type;
break;
case INDIRECT_REF:
/* [expr.unary.op]
If the type of the expression is "pointer to T", the
type of the result is "T". */
type = TREE_TYPE (op0_type);
break;
case ADDR_EXPR:
/* [expr.unary.op]
If the type of the expression is "T", the type of the
result is "pointer to T". */
/* FIXME: Handle the pointer-to-member case. */
break;
case MEMBER_REF:
/* FIXME: Implement this case. */
break;
case LSHIFT_EXPR:
case RSHIFT_EXPR:
/* [expr.shift]
The type of the result is that of the promoted left
operand. */
break;
case PLUS_EXPR:
case MINUS_EXPR:
/* FIXME: Be careful of special pointer-arithmetic
cases. */
/* Fall through. */
case MAX_EXPR:
case MIN_EXPR:
/* These are GNU extensions; the result type is computed
as it would be for other arithmetic operators. */
/* Fall through. */
case BIT_AND_EXPR:
case BIT_XOR_EXPR:
case BIT_IOR_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case TRUNC_MOD_EXPR:
/* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
The usual arithmetic conversions are performed on the
operands and determine the type of the result. */
/* FIXME: Check that this is possible. */
type = type_after_usual_arithmetic_conversions (t1, t2);
break;
case GT_EXPR:
case LT_EXPR:
case GE_EXPR:
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
/* [expr.rel]
The type of the result is bool. */
type = boolean_type_node;
break;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
/* [expr.log.and], [expr.log.org]
The result is a bool. */
type = boolean_type_node;
break;
case COND_EXPR:
/* FIXME: Handle special rules for conditional
expressions. */
break;
case COMPOUND_EXPR:
type = op1_type;
break;
default:
abort ();
}
/* If the type of the expression could not be determined,
something is wrong. */
if (!type)
abort ();
/* If the type is erroneous, the expression is erroneous
too. */
if (type == error_mark_node)
return error_mark_node;
}
} }
return build_min (code, type, op0, op1, op2, NULL_TREE); if (code == DOTSTAR_EXPR)
} expr = build_m_component_ref (arg1, arg2);
else
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
#endif if (processing_template_decl && expr != error_mark_node)
return build_min (code, TREE_TYPE (expr), orig_arg1, orig_arg2);
return expr;
}
/* Build a binary-operation expression without default conversions. /* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build. CODE is the kind of expression to build.
@ -3839,11 +3689,18 @@ pointer_diff (register tree op0, register tree op1, register tree ptrtype)
tree tree
build_x_unary_op (enum tree_code code, tree xarg) build_x_unary_op (enum tree_code code, tree xarg)
{ {
tree orig_expr = xarg;
tree exp; tree exp;
int ptrmem = 0; int ptrmem = 0;
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (code, xarg, NULL_TREE); {
if (type_dependent_expression_p (xarg))
return build_min_nt (code, xarg, NULL_TREE);
xarg = build_non_dependent_expr (xarg);
}
exp = NULL_TREE;
/* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
error message. */ error message. */
@ -3854,15 +3711,8 @@ build_x_unary_op (enum tree_code code, tree xarg)
|| (TREE_CODE (xarg) == OFFSET_REF))) || (TREE_CODE (xarg) == OFFSET_REF)))
/* don't look for a function */; /* don't look for a function */;
else else
{ exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
tree rval; if (!exp && code == ADDR_EXPR)
rval = build_new_op (code, LOOKUP_NORMAL, xarg,
NULL_TREE, NULL_TREE);
if (rval || code != ADDR_EXPR)
return rval;
}
if (code == ADDR_EXPR)
{ {
/* A pointer to member-function can be formed only by saying /* A pointer to member-function can be formed only by saying
&X::mf. */ &X::mf. */
@ -3897,15 +3747,16 @@ build_x_unary_op (enum tree_code code, tree xarg)
ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE)); ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
PTRMEM_OK_P (xarg) = ptrmem; PTRMEM_OK_P (xarg) = ptrmem;
} }
} }
else if (TREE_CODE (xarg) == TARGET_EXPR) else if (TREE_CODE (xarg) == TARGET_EXPR)
warning ("taking address of temporary"); warning ("taking address of temporary");
exp = build_unary_op (ADDR_EXPR, xarg, 0);
if (TREE_CODE (exp) == ADDR_EXPR)
PTRMEM_OK_P (exp) = ptrmem;
} }
exp = build_unary_op (code, xarg, 0);
if (TREE_CODE (exp) == ADDR_EXPR)
PTRMEM_OK_P (exp) = ptrmem;
if (processing_template_decl && exp != error_mark_node)
return build_min (code, TREE_TYPE (exp), orig_expr);
return exp; return exp;
} }
@ -4631,53 +4482,76 @@ cxx_mark_addressable (tree exp)
tree tree
build_x_conditional_expr (tree ifexp, tree op1, tree op2) build_x_conditional_expr (tree ifexp, tree op1, tree op2)
{ {
if (processing_template_decl) tree orig_ifexp = ifexp;
return build_min_nt (COND_EXPR, ifexp, op1, op2); tree orig_op1 = op1;
tree orig_op2 = op2;
tree expr;
return build_conditional_expr (ifexp, op1, op2); if (processing_template_decl)
{
/* The standard says that the expression is type-dependent if
IFEXP is type-dependent, even though the eventual type of the
expression doesn't dependent on IFEXP. */
if (type_dependent_expression_p (ifexp)
|| type_dependent_expression_p (op1)
|| type_dependent_expression_p (op2))
return build_min_nt (COND_EXPR, ifexp, op1, op2);
ifexp = build_non_dependent_expr (ifexp);
op1 = build_non_dependent_expr (op1);
op2 = build_non_dependent_expr (op2);
}
expr = build_conditional_expr (ifexp, op1, op2);
if (processing_template_decl && expr != error_mark_node)
return build_min (COND_EXPR, TREE_TYPE (expr),
orig_ifexp, orig_op1, orig_op2);
return expr;
} }
/* Handle overloading of the ',' operator when needed. Otherwise, /* Handle overloading of the ',' operator when needed. Otherwise,
this function just builds an expression list. */ this function just builds an expression list. */
tree tree
build_x_compound_expr (tree list) build_x_compound_expr (tree op1, tree op2)
{ {
tree rest = TREE_CHAIN (list);
tree result; tree result;
tree orig_op1 = op1;
tree orig_op2 = op2;
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
if (rest == NULL_TREE)
return build_compound_expr (list);
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
return build_x_compound_expr (tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{ {
/* FIXME: This test should be in the implicit cast to void of the LHS. */ if (type_dependent_expression_p (op1)
/* the left-hand operand of a comma expression is like an expression || type_dependent_expression_p (op2))
statement: we should warn if it doesn't have any side-effects, return build_min_nt (COMPOUND_EXPR, op1, op2);
unless it was explicitly cast to (void). */ op1 = build_non_dependent_expr (op1);
if (warn_unused_value op2 = build_non_dependent_expr (op2);
&& !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE(list)))))
warning("left-hand operand of comma expression has no effect");
} }
#if 0 /* this requires a gcc backend patch to export warn_if_unused_value */
else if (warn_unused_value)
warn_if_unused_value (TREE_VALUE(list));
#endif
return build_compound_expr result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
(tree_cons (NULL_TREE, TREE_VALUE (list), if (!result)
build_tree_list (NULL_TREE, {
build_x_compound_expr (rest)))); if (! TREE_SIDE_EFFECTS (op1))
{
/* FIXME: This test should be in the implicit cast to void
of the LHS. */
/* the left-hand operand of a comma expression is like an expression
statement: we should warn if it doesn't have any side-effects,
unless it was explicitly cast to (void). */
if (warn_unused_value
&& !(TREE_CODE (op1) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (op1))))
warning("left-hand operand of comma expression has no effect");
}
result = build_compound_expr (tree_cons (NULL_TREE,
op1,
build_tree_list (NULL_TREE,
op2)));
}
if (processing_template_decl && result != error_mark_node)
return build_min (COMPOUND_EXPR, TREE_TYPE (result),
orig_op1, orig_op2);
return result;
} }
/* Given a list of expressions, return a compound expression /* Given a list of expressions, return a compound expression

View File

@ -980,44 +980,48 @@ build_scoped_ref (tree datum, tree basetype, tree* binfo_p)
delegation is detected. */ delegation is detected. */
tree tree
build_x_arrow (tree datum) build_x_arrow (tree expr)
{ {
tree orig_expr = expr;
tree types_memoized = NULL_TREE; tree types_memoized = NULL_TREE;
register tree rval = datum; tree type = TREE_TYPE (expr);
tree type = TREE_TYPE (rval);
tree last_rval = NULL_TREE; tree last_rval = NULL_TREE;
if (type == error_mark_node) if (type == error_mark_node)
return error_mark_node; return error_mark_node;
if (processing_template_decl) if (processing_template_decl)
return build_min_nt (ARROW_EXPR, rval); {
if (type_dependent_expression_p (expr))
return build_min_nt (ARROW_EXPR, expr);
expr = build_non_dependent_expr (expr);
}
if (TREE_CODE (type) == REFERENCE_TYPE) if (TREE_CODE (type) == REFERENCE_TYPE)
{ {
rval = convert_from_reference (rval); expr = convert_from_reference (expr);
type = TREE_TYPE (rval); type = TREE_TYPE (expr);
} }
if (IS_AGGR_TYPE (type)) if (IS_AGGR_TYPE (type))
{ {
while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval, while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
NULL_TREE, NULL_TREE))) NULL_TREE, NULL_TREE)))
{ {
if (rval == error_mark_node) if (expr == error_mark_node)
return error_mark_node; return error_mark_node;
if (value_member (TREE_TYPE (rval), types_memoized)) if (value_member (TREE_TYPE (expr), types_memoized))
{ {
error ("circular pointer delegation detected"); error ("circular pointer delegation detected");
return error_mark_node; return error_mark_node;
} }
else else
{ {
types_memoized = tree_cons (NULL_TREE, TREE_TYPE (rval), types_memoized = tree_cons (NULL_TREE, TREE_TYPE (expr),
types_memoized); types_memoized);
} }
last_rval = rval; last_rval = expr;
} }
if (last_rval == NULL_TREE) if (last_rval == NULL_TREE)
@ -1030,10 +1034,17 @@ build_x_arrow (tree datum)
last_rval = convert_from_reference (last_rval); last_rval = convert_from_reference (last_rval);
} }
else else
last_rval = decay_conversion (rval); last_rval = decay_conversion (expr);
if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE) if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
return build_indirect_ref (last_rval, NULL); {
if (processing_template_decl)
return build_min (ARROW_EXPR,
TREE_TYPE (TREE_TYPE (last_rval)),
orig_expr);
return build_indirect_ref (last_rval, NULL);
}
if (types_memoized) if (types_memoized)
error ("result of `operator->()' yields non-pointer result"); error ("result of `operator->()' yields non-pointer result");

View File

@ -2908,7 +2908,8 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{ {
arg0 = TREE_OPERAND (exp, 0); if (first_rtl_op (code) > 0)
arg0 = TREE_OPERAND (exp, 0);
if (TREE_CODE_CLASS (code) == '<' if (TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_CLASS (code) == '1' || TREE_CODE_CLASS (code) == '1'
|| TREE_CODE_CLASS (code) == '2') || TREE_CODE_CLASS (code) == '2')

View File

@ -1,3 +1,14 @@
2003-07-08 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/mangle17.C: Make sure template expressions are
dependent.
* g++.dg/abi/mangle4.C: Mark erroneous casts.
* g++.dg/debug/debug7.C: Mark erronous new-declarator.
* g++.dg/opt/stack1.C: Remove erroneous code.
* g++.dg/parse/template7.C: New test.
* g++.dg/template/dependent-expr1.C: Mark erroneous code.
* g++.old-deja/g++.pt/crash4.C: Likewise.
2003-07-09 John David Anglin <dave.anglin@nrc-cnrc.gc.ca> 2003-07-09 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* gcc.dg/const-elim-1.c (dg-final): Change regexp to match labels * gcc.dg/const-elim-1.c (dg-final): Change regexp to match labels

View File

@ -4,8 +4,8 @@ enum E { e = 3 };
template <int I> struct S {}; template <int I> struct S {};
template <int I> void f (S<e + int (3.7)>) {} template <int I> void f (S<I + e + int (3.7)>) {}
template void f<7>(S<e + int (3.7)>); // { dg-warning "mangle" } template void f<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }
template <int I> void g (S<e + int (3.7)>) {} template <int I> void g (S<I + e + int (3.7)>) {}
template void g<7>(S<e + int (3.7)>); // { dg-warning "mangle" } template void g<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }

View File

@ -8,19 +8,17 @@ template<const A* a> class C {};
template<const B* b> class D {}; template<const B* b> class D {};
template<B* b> class E {}; template<B* b> class E {};
template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" }
template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} // { dg-error "" }
B b; B b;
int main() int main()
{ {
C<static_cast<const A*>(&b)> c; C<static_cast<const A*>(&b)> c; // { dg-error "" }
D<&b> d; D<&b> d;
E<const_cast<B*>(&b)> e; E<const_cast<B*>(&b)> e; // { dg-error "" }
f(d, c); f(d, c); // { dg-error "" }
g(d, e); g(d, e); // { dg-error "" }
} }
// { dg-final { scan-assembler "\n_?_Z1fIXadL_Z1bEEEvR1DIXT_EER1CIXcvPK1AT_EE\[: \t\n\]" } }
// { dg-final { scan-assembler "\n_?_Z1gIXadL_Z1bEEEvR1DIXT_EER1EIXcvP1BT_EE\[: \t\n\]" } }

View File

@ -7,7 +7,7 @@ main() {
int a = 4; int a = 4;
int b = 5; int b = 5;
int (*x)[b] = new int[a][b]; int (*x)[b] = new int[a][b]; // { dg-error "" }
x[2][1] = 7; x[2][1] = 7;

View File

@ -68,7 +68,7 @@ template<typename=void>
struct adaptor { struct adaptor {
adaptor (matrix<> &m) : m(&m), upper_ (1) {} adaptor (matrix<> &m) : m(&m), upper_ (1) {}
int size1 () const { return m->size1 (); } int size1 () const;
int size2 () const { return 3; } int size2 () const { return 3; }
int lower () const { return 1; } int lower () const { return 1; }
int upper () const { return upper_; } int upper () const { return upper_; }

View File

@ -0,0 +1,4 @@
template <int I>
void f();
void g() { f<(3, 2)>(); } // { dg-error "" }

View File

@ -21,9 +21,9 @@ namespace std
Foo (__alignof__ (x)); Foo (__alignof__ (x));
Foo (x->~I ()); Foo (x->~I ());
// Foo (typeid (I)); // Foo (typeid (I));
Foo (delete x); Foo (delete x); // { dg-error "" }
Foo (delete[] x); Foo (delete[] x); // { dg-error "" }
Foo (throw x); Foo (throw x); // { dg-error "" }
} }
} }

View File

@ -1,4 +1,4 @@
// { dg-do assemble } // { dg-do compile }
// Origin: Mark Mitchell <mark@codesourcery.com> // Origin: Mark Mitchell <mark@codesourcery.com>
template <int> struct S1{}; template <int> struct S1{};
@ -7,5 +7,5 @@ struct S2 { int i; };
template <class T> template <class T>
void f(S2 s2) { void f(S2 s2) {
S1<s2.i> s1; S1<s2.i> s1; // { dg-error "" }
} }

View File

@ -1,3 +1,7 @@
2003-07-09 Mark Mitchell <mark@codesourcery.com>
* gcj/array.h (JvPrimClass): Don't parenthesize the output.
2003-07-09 Michael Koch <konqueror@gmx.de> 2003-07-09 Michael Koch <konqueror@gmx.de>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java, * gnu/java/awt/peer/gtk/GtkComponentPeer.java,

View File

@ -71,7 +71,9 @@ typedef JArray<jstring> *jstringArray;
extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass, extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
_Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass, _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
_Jv_doubleClass, _Jv_voidClass; _Jv_doubleClass, _Jv_voidClass;
#define JvPrimClass(TYPE) (& _Jv_##TYPE##Class) /* The definition of this macro cannot be enclosed in parentheses
because "JvPrimClass(x)" is used as a template argument. */
#define JvPrimClass(TYPE) & _Jv_##TYPE##Class
extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init); extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count); extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);