This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Implement type-computation for non-dependent expressions
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 9 Jul 2003 02:01:45 -0700
- Subject: C++ PATCH: Implement type-computation for non-dependent expressions
- Reply-to: mark at codesourcery dot com
The standard says that we have to compute the types of expressions in
templates, where possible. For example, we have to know that in:
struct A { template <int I> void f(); };
struct B { int f; };
A* g(int);
B* g(double);
template <typename T> void h () { g(2)->f<3>(); }
"f<int>" is a template, and a not something involving less-than and
greater-than operators. In other words, we have to compute the type
of "g(2)" in order to parse the expression!
This patch implements that functionality.
It also fixes up several places where we accepted invalid programs; my
favorite is:
template <int> struct S1{};
struct S2 { int i; };
template <class T>
void f(S2 s2) {
S1<s2.i> s1;
}
which is in a test-case I contributed! Of course, "s2.i" is not a
valid template argument -- and now we notice that.
Tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
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-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.
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.277
diff -c -5 -p -r1.277 fold-const.c
*** fold-const.c 7 Jul 2003 19:11:55 -0000 1.277
--- fold-const.c 9 Jul 2003 08:30:13 -0000
*************** make_range (tree exp, int *pin_p, tree *
*** 2906,2916 ****
{
code = TREE_CODE (exp);
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{
! arg0 = TREE_OPERAND (exp, 0);
if (TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_CLASS (code) == '1'
|| TREE_CODE_CLASS (code) == '2')
type = TREE_TYPE (arg0);
if (TREE_CODE_CLASS (code) == '2'
--- 2906,2917 ----
{
code = TREE_CODE (exp);
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{
! if (first_rtl_op (code) > 0)
! arg0 = TREE_OPERAND (exp, 0);
if (TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_CLASS (code) == '1'
|| TREE_CODE_CLASS (code) == '2')
type = TREE_TYPE (arg0);
if (TREE_CODE_CLASS (code) == '2'
Index: cp/ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/ChangeLog,v
retrieving revision 1.3502
diff -c -5 -p -r1.3502 ChangeLog
*** cp/ChangeLog 9 Jul 2003 00:31:14 -0000 1.3502
--- cp/ChangeLog 9 Jul 2003 08:30:21 -0000
*************** Wed Jul 9 02:28:39 CEST 2003 Jan Hubic
*** 208,224 ****
resolve_offset_ref.
(resolve_args): Do not call resolve_offset_ref.
(build_conditional_expr): Likewise.
(build_new_method_call): Likewise.
* cp-tree.def (OFFSET_REF): Update documentation.
! (cp_convert_to_pointer): Update handling of conversions from
pointers to members to pointers.
(ocp_convert): Do not call resolve_offset_ref.
(convert_to_void): Likewise.
(build_expr_type_conversion): Likewise.
! (delete_sanity): Likewise.
! (resolve_offset_ref): Simplify greatly.
(build_vec_delete): Do not call resolve_offset_ref.
* parser.c (cp_parser_postfix_expression): Call resolve_offset_ref
if appropriate.
(cp_parser_unary_expression): Use
cp_parser_simple_cast_expression.
--- 208,224 ----
resolve_offset_ref.
(resolve_args): Do not call resolve_offset_ref.
(build_conditional_expr): Likewise.
(build_new_method_call): Likewise.
* cp-tree.def (OFFSET_REF): Update documentation.
! * cvt.c (cp_convert_to_pointer): Update handling of conversions from
pointers to members to pointers.
(ocp_convert): Do not call resolve_offset_ref.
(convert_to_void): Likewise.
(build_expr_type_conversion): Likewise.
! * decl2.c (delete_sanity): Likewise.
! * init.c (resolve_offset_ref): Simplify greatly.
(build_vec_delete): Do not call resolve_offset_ref.
* parser.c (cp_parser_postfix_expression): Call resolve_offset_ref
if appropriate.
(cp_parser_unary_expression): Use
cp_parser_simple_cast_expression.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.403
diff -c -5 -p -r1.403 call.c
*** cp/call.c 8 Jul 2003 01:38:41 -0000 1.403
--- cp/call.c 9 Jul 2003 08:30:22 -0000
*************** build_call (tree function, tree parms)
*** 323,334 ****
PARMS help to figure out what that NAME really refers to.
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
! information to get protected accesses correct. This parameter is used
! by build_member_call.
FLAGS is the logical disjunction of zero or more LOOKUP_
flags. See cp-tree.h for more info.
If this is all OK, calls build_function_call with the resolved
--- 323,333 ----
PARMS help to figure out what that NAME really refers to.
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
! information to get protected accesses correct.
FLAGS is the logical disjunction of zero or more LOOKUP_
flags. See cp-tree.h for more info.
If this is all OK, calls build_function_call with the resolved
*************** build_new_method_call (tree instance, tr
*** 4881,4898 ****
--- 4880,4914 ----
tree call;
tree fn;
tree class_type;
int template_only = 0;
bool any_viable_p;
+ tree orig_instance;
+ tree orig_fns;
+ tree orig_args;
my_friendly_assert (instance != NULL_TREE, 20020729);
if (error_operand_p (instance)
|| error_operand_p (fns)
|| args == 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. */
user_args = args;
args = resolve_args (args);
if (args == error_mark_node)
return error_mark_node;
*************** build_new_method_call (tree instance, tr
*** 5066,5075 ****
--- 5082,5098 ----
be a static member function, `a' is none-the-less evaluated. */
if (!is_dummy_object (instance_ptr) && TREE_SIDE_EFFECTS (instance))
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;
}
/* Returns true iff standard conversion sequence ICS1 is a proper
subsequence of ICS2. */
Index: cp/cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.75
diff -c -5 -p -r1.75 cp-tree.def
*** cp/cp-tree.def 4 Jul 2003 05:05:14 -0000 1.75
--- cp/cp-tree.def 9 Jul 2003 08:30:22 -0000
*************** DEFTREECODE (STATIC_CAST_EXPR, "static_c
*** 236,245 ****
--- 236,255 ----
DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", '1', 1)
DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", 'e', 2)
DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1)
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
setup_vtbl_pointer (and appears in all functions, not just ctors). */
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.870
diff -c -5 -p -r1.870 cp-tree.h
*** cp/cp-tree.h 8 Jul 2003 01:38:41 -0000 1.870
--- cp/cp-tree.h 9 Jul 2003 08:30:22 -0000
*************** struct diagnostic_context;
*** 213,222 ****
--- 213,223 ----
/* Returns TRUE if generated code should match ABI version N or
greater is in use. */
#define abi_version_at_least(N) \
(flag_abi_version == 0 || flag_abi_version >= (N))
+
/* Language-dependent contents of an identifier. */
struct lang_identifier GTY(())
{
*************** extern void import_export_vtable (tree,
*** 3773,3783 ****
extern void import_export_decl (tree);
extern void import_export_tinfo (tree, tree, bool);
extern void finish_file (void);
extern tree build_cleanup (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 tree current_decl_namespace (void);
extern void push_decl_namespace (tree);
extern void pop_decl_namespace (void);
extern void push_scope (tree);
--- 3774,3783 ----
*************** extern tree build_aggr_init (tree, tre
*** 3851,3861 ****
extern tree build_init (tree, tree, int);
extern int is_aggr_type (tree, int);
extern tree get_aggr_from_typedef (tree, int);
extern tree get_type_value (tree);
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 resolve_offset_ref (tree);
extern tree build_new (tree, tree, tree, int);
extern tree build_vec_init (tree, tree, tree, int);
extern tree build_x_delete (tree, int, tree);
--- 3851,3860 ----
*************** extern int problematic_instantiation_cha
*** 3972,3987 ****
extern void record_last_problematic_instantiation (void);
extern tree current_instantiation (void);
extern tree maybe_get_template_decl_from_type_decl (tree);
extern int processing_template_parmlist;
extern bool dependent_type_p (tree);
! extern bool dependent_template_arg_p (tree);
extern bool dependent_template_p (tree);
extern bool type_dependent_expression_p (tree);
extern bool value_dependent_expression_p (tree);
extern tree resolve_typename_type (tree, bool);
extern tree template_for_substitution (tree);
/* in repo.c */
extern void repo_template_used (tree);
extern void repo_template_instantiated (tree, bool);
extern void init_repo (const char *);
--- 3971,3990 ----
extern void record_last_problematic_instantiation (void);
extern tree current_instantiation (void);
extern tree maybe_get_template_decl_from_type_decl (tree);
extern int processing_template_parmlist;
extern bool dependent_type_p (tree);
! extern bool any_dependent_template_arguments_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 any_type_dependent_arguments_p (tree);
extern bool value_dependent_expression_p (tree);
extern tree resolve_typename_type (tree, bool);
extern tree template_for_substitution (tree);
+ extern tree build_non_dependent_expr (tree);
+ extern tree build_non_dependent_args (tree);
/* in repo.c */
extern void repo_template_used (tree);
extern void repo_template_instantiated (tree, bool);
extern void init_repo (const char *);
*************** extern tree get_member_function_from_ptr
*** 4265,4275 ****
extern tree convert_arguments (tree, tree, tree, int);
extern tree build_x_binary_op (enum tree_code, tree, tree);
extern tree build_x_unary_op (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_compound_expr (tree);
extern tree build_compound_expr (tree);
extern tree build_static_cast (tree, tree);
extern tree build_reinterpret_cast (tree, tree);
extern tree build_const_cast (tree, tree);
extern tree build_c_cast (tree, tree);
--- 4268,4278 ----
extern tree convert_arguments (tree, tree, tree, int);
extern tree build_x_binary_op (enum tree_code, tree, tree);
extern tree build_x_unary_op (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_compound_expr (tree, tree);
extern tree build_compound_expr (tree);
extern tree build_static_cast (tree, tree);
extern tree build_reinterpret_cast (tree, tree);
extern tree build_const_cast (tree, tree);
extern tree build_c_cast (tree, tree);
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.645
diff -c -5 -p -r1.645 decl2.c
*** cp/decl2.c 9 Jul 2003 00:31:15 -0000 1.645
--- cp/decl2.c 9 Jul 2003 08:30:22 -0000
*************** grokclassfn (tree ctype, tree function,
*** 396,458 ****
along the way. */
tree
grok_array_decl (tree array_expr, tree index_exp)
{
! tree type = TREE_TYPE (array_expr);
! tree p1, p2, i1, i2;
! if (type == error_mark_node || index_exp == error_mark_node)
return error_mark_node;
if (processing_template_decl)
! return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE,
! array_expr, index_exp);
my_friendly_assert (type, 20030626);
-
type = non_reference (type);
/* If they have an `operator[]', use that. */
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
! return build_new_op (ARRAY_REF, LOOKUP_NORMAL,
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
! {
! 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");
! return build_array_ref (array_expr, index_exp);
}
/* Given the cast expression EXP, checking out its validity. Either return
an error_mark_node if there was an unavoidable error, return a cast to
void for trying to delete a pointer w/ the value 0, or return the
--- 396,476 ----
along the way. */
tree
grok_array_decl (tree array_expr, tree index_exp)
{
! tree type;
! tree expr;
! tree orig_array_expr = array_expr;
! tree orig_index_exp = index_exp;
! if (error_operand_p (array_expr) || error_operand_p (index_exp))
return error_mark_node;
+
if (processing_template_decl)
! {
! 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);
type = non_reference (type);
/* If they have an `operator[]', use that. */
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
! expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE);
else
! {
! tree p1, p2, i1, i2;
! /* 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)
! return build_min (ARRAY_REF, TREE_TYPE (expr), orig_array_expr,
! orig_index_exp);
! return expr;
}
/* Given the cast expression EXP, checking out its validity. Either return
an error_mark_node if there was an unavoidable error, return a cast to
void for trying to delete a pointer w/ the value 0, or return the
*************** finish_file ()
*** 2947,3038 ****
tree
build_offset_ref_call_from_tree (tree fn, tree args)
{
tree object_addr;
! my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725);
/* A qualified name corresponding to a bound pointer-to-member is
represented as an OFFSET_REF:
struct B { void g(); };
void (B::*p)();
void B::g() { (this->*p)(); } */
! if (TREE_CODE (TREE_OPERAND (fn, 1)) == FIELD_DECL)
! /* This case should now be handled elsewhere. */
! abort ();
! else
{
object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0);
fn = TREE_OPERAND (fn, 1);
fn = get_member_function_from_ptrfunc (&object_addr, fn);
args = tree_cons (NULL_TREE, object_addr, args);
}
- return build_function_call (fn, args);
- }
-
- /* FN indicates the function to call. Name resolution has been
- performed on FN. ARGS are the arguments to the function. They
- have already been semantically analyzed. DISALLOW_VIRTUAL is true
- if the function call should be determined at compile time, even if
- 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
CHILD. CHILD may be either a class type or a namespace. */
--- 2965,3024 ----
tree
build_offset_ref_call_from_tree (tree fn, tree args)
{
tree object_addr;
+ tree orig_fn;
+ tree orig_args;
+ tree expr;
! 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
represented as an OFFSET_REF:
struct B { void g(); };
void (B::*p)();
void B::g() { (this->*p)(); } */
! if (TREE_CODE (fn) == OFFSET_REF)
{
object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0);
fn = TREE_OPERAND (fn, 1);
fn = get_member_function_from_ptrfunc (&object_addr, fn);
args = tree_cons (NULL_TREE, object_addr, args);
}
! expr = build_function_call (fn, args);
! if (processing_template_decl && expr != error_mark_node)
! return build_min (CALL_EXPR, TREE_TYPE (expr), orig_fn, orig_args);
! return expr;
}
/* Returns true if ROOT (a namespace, class, or function) encloses
CHILD. CHILD may be either a class type or a namespace. */
Index: cp/error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.219
diff -c -5 -p -r1.219 error.c
*** cp/error.c 8 Jul 2003 01:38:44 -0000 1.219
--- cp/error.c 9 Jul 2003 08:30:22 -0000
*************** dump_decl (tree t, int flags)
*** 986,995 ****
--- 986,999 ----
case BASELINK:
dump_decl (BASELINK_FUNCTIONS (t), flags);
break;
+ case NON_DEPENDENT_EXPR:
+ dump_expr (t, flags);
+ break;
+
default:
sorry_for_unsupported_tree (t);
/* Fallthrough to error. */
case ERROR_MARK:
*************** dump_expr (tree t, int flags)
*** 2026,2036 ****
case BASELINK:
dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
break;
! /* else fall through */
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
default:
--- 2030,2044 ----
case BASELINK:
dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
break;
! 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.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
default:
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.329
diff -c -5 -p -r1.329 init.c
*** cp/init.c 8 Jul 2003 01:38:44 -0000 1.329
--- cp/init.c 9 Jul 2003 08:30:22 -0000
*************** get_type_value (tree name)
*** 1335,1495 ****
return IDENTIFIER_TYPE_VALUE (name);
else
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
C++ `&', but really something which can have its address taken,
and then act as a pointer to member, for example TYPE :: FIELD
can have its address taken by saying & TYPE :: FIELD.
--- 1335,1344 ----
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.83
diff -c -5 -p -r1.83 mangle.c
*** cp/mangle.c 8 Jul 2003 01:38:44 -0000 1.83
--- cp/mangle.c 9 Jul 2003 08:30:23 -0000
*************** write_expression (tree expr)
*** 2017,2026 ****
--- 2017,2039 ----
/* Handle pointers-to-members specially. */
case SCOPE_REF:
write_type (TREE_OPERAND (expr, 0));
if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
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
{
/* G++ 3.2 incorrectly put out both the "sr" code and
the nested name of the qualified name. */
G.need_abi_warning = 1;
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.76
diff -c -5 -p -r1.76 parser.c
*** cp/parser.c 8 Jul 2003 01:38:44 -0000 1.76
--- cp/parser.c 9 Jul 2003 08:30:23 -0000
*************** static void cp_parser_late_parsing_defau
*** 1649,1668 ****
--- 1649,1672 ----
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
+ static tree cp_parser_fold_non_dependent_expr
+ (tree);
static bool cp_parser_friend_p
(tree);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, const char *);
static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, const char *);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
static bool cp_parser_next_token_starts_class_definition_p
(cp_parser *);
+ static bool cp_parser_next_token_ends_template_argument_p
+ (cp_parser *);
static enum tag_types cp_parser_token_is_class_key
(cp_token *);
static void cp_parser_check_class_key
(enum tag_types, tree type);
static bool cp_parser_optional_template_keyword
*************** cp_parser_primary_expression (cp_parser
*** 2379,2389 ****
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
- /* Fall through. */
/* An id-expression can start with either an identifier, a
`::' as the beginning of a qualified-id, or the "operator"
keyword. */
case CPP_NAME:
--- 2383,2392 ----
*************** cp_parser_primary_expression (cp_parser
*** 2598,2631 ****
/* For a template-id, check to see if the template
arguments are dependent. */
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
tree args = TREE_OPERAND (fns, 1);
!
! 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
template-id. */
fns = TREE_OPERAND (fns, 0);
}
--- 2601,2611 ----
/* For a template-id, check to see if the template
arguments are dependent. */
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
tree args = TREE_OPERAND (fns, 1);
! dependent_p = any_dependent_template_arguments_p (args);
/* The functions are those referred to by the
template-id. */
fns = TREE_OPERAND (fns, 0);
}
*************** cp_parser_primary_expression (cp_parser
*** 2685,2715 ****
}
/* Only certain kinds of names are allowed in constant
expression. Enumerators have already been handled
above. */
! if (parser->constant_expression_p
/* Non-type template parameters of integral or
! enumeration type. */
! && !(TREE_CODE (decl) == TEMPLATE_PARM_INDEX
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
/* Const variables or static data members of integral
or enumeration types initialized with constant
! expressions (or dependent expressions - in this case
! the check will be done at instantiation time). */
! && !(TREE_CODE (decl) == VAR_DECL
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! && DECL_INITIAL (decl)
! && (TREE_CONSTANT (DECL_INITIAL (decl))
! || type_dependent_expression_p
! (DECL_INITIAL (decl))
! || value_dependent_expression_p
! (DECL_INITIAL (decl)))))
! {
! if (!parser->allow_non_constant_expression_p)
! return cp_parser_non_constant_id_expression (decl);
! parser->non_constant_expression_p = true;
}
if (parser->scope)
{
decl = (adjust_result_of_qualified_name_lookup
--- 2665,2702 ----
}
/* Only certain kinds of names are allowed in constant
expression. Enumerators have already been handled
above. */
! if (parser->constant_expression_p)
! {
/* Non-type template parameters of integral or
! enumeration type are OK. */
! if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
! ;
/* Const variables or static data members of integral
or enumeration types initialized with constant
! expressions are OK. We also accept dependent
! initializers; they may turn out to be constant at
! instantiation-time. */
! else if (TREE_CODE (decl) == VAR_DECL
! && CP_TYPE_CONST_P (TREE_TYPE (decl))
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! && DECL_INITIAL (decl)
! && (TREE_CONSTANT (DECL_INITIAL (decl))
! || type_dependent_expression_p (DECL_INITIAL
! (decl))
! || value_dependent_expression_p (DECL_INITIAL
! (decl))))
! ;
! 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)
{
decl = (adjust_result_of_qualified_name_lookup
*************** cp_parser_postfix_expression (cp_parser
*** 3790,3800 ****
&& (is_overloaded_fn (postfix_expression)
|| DECL_P (postfix_expression)
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
&& args)
{
- tree arg;
tree identifier = NULL_TREE;
tree functions = NULL_TREE;
/* Find the name of the overloaded function. */
if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
--- 3777,3786 ----
*************** cp_parser_postfix_expression (cp_parser
*** 3813,3871 ****
/* A call to a namespace-scope function using an
unqualified name.
Do Koenig lookup -- unless any of the arguments are
type-dependent. */
! for (arg = args; arg; arg = TREE_CHAIN (arg))
! if (type_dependent_expression_p (TREE_VALUE (arg)))
! break;
! if (!arg)
{
postfix_expression
= lookup_arg_dependent (identifier, functions, args);
if (!postfix_expression)
{
/* The unqualified name could not be resolved. */
unqualified_name_lookup_error (identifier);
postfix_expression = error_mark_node;
}
- postfix_expression
- = build_call_from_tree (postfix_expression, args,
- /*diallow_virtual=*/false);
- break;
}
! postfix_expression = build_min_nt (LOOKUP_EXPR,
! identifier);
}
else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
{
/* The unqualified name could not be resolved. */
unqualified_name_lookup_error (postfix_expression);
postfix_expression = error_mark_node;
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)
! postfix_expression
! = (build_new_method_call
! (TREE_OPERAND (postfix_expression, 0),
! TREE_OPERAND (postfix_expression, 1),
! args, NULL_TREE,
! (idk == CP_PARSER_ID_KIND_QUALIFIED
! ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
! else if (TREE_CODE (postfix_expression) == OFFSET_REF)
postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, args));
else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
/* A call to a static class member, or a namespace-scope
function. */
--- 3799,3858 ----
/* A call to a namespace-scope function using an
unqualified name.
Do Koenig lookup -- unless any of the arguments are
type-dependent. */
! if (!any_type_dependent_arguments_p (args))
{
postfix_expression
= lookup_arg_dependent (identifier, functions, args);
if (!postfix_expression)
{
/* The unqualified name could not be resolved. */
unqualified_name_lookup_error (identifier);
postfix_expression = error_mark_node;
+ break;
}
}
! else
! postfix_expression = build_min_nt (LOOKUP_EXPR,
! identifier);
}
else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
{
/* The unqualified name could not be resolved. */
unqualified_name_lookup_error (postfix_expression);
postfix_expression = error_mark_node;
break;
}
! if (TREE_CODE (postfix_expression) == COMPONENT_REF)
{
! tree instance = TREE_OPERAND (postfix_expression, 0);
! tree fn = TREE_OPERAND (postfix_expression, 1);
! if (processing_template_decl
! && (type_dependent_expression_p (instance)
! || (!BASELINK_P (fn)
! && 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, args));
else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
/* A call to a static class member, or a namespace-scope
function. */
*************** cp_parser_postfix_expression (cp_parser
*** 3965,3976 ****
build the SCOPE_REF. For example;
struct X { void f(); };
template <typename T> void f(T* t) { t->X::f(); }
! Even though "t" is dependent, "X::f" is not and has
! except that for a BASELINK there is no need to
include scope information. */
/* But we do need to remember that there was an explicit
scope for virtual function calls. */
if (parser->scope)
--- 3952,3963 ----
build the SCOPE_REF. For example;
struct X { void f(); };
template <typename T> void f(T* t) { t->X::f(); }
! Even though "t" is dependent, "X::f" is not and has
! been resolved to a BASELINK; there is no need to
include scope information. */
/* But we do need to remember that there was an explicit
scope for virtual function calls. */
if (parser->scope)
*************** cp_parser_unary_expression (cp_parser *p
*** 4334,4344 ****
{
case INDIRECT_REF:
return build_x_indirect_ref (cast_expression, "unary *");
case ADDR_EXPR:
! return build_x_unary_op (ADDR_EXPR, cast_expression);
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
if (parser->constant_expression_p)
{
--- 4321,4332 ----
{
case INDIRECT_REF:
return build_x_indirect_ref (cast_expression, "unary *");
case ADDR_EXPR:
! case BIT_NOT_EXPR:
! return build_x_unary_op (unary_operator, cast_expression);
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
if (parser->constant_expression_p)
{
*************** cp_parser_unary_expression (cp_parser *p
*** 4352,4364 ****
case CONVERT_EXPR:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
return finish_unary_op_expr (unary_operator, cast_expression);
- case BIT_NOT_EXPR:
- return build_x_unary_op (BIT_NOT_EXPR, cast_expression);
-
default:
abort ();
return error_mark_node;
}
}
--- 4340,4349 ----
*************** cp_parser_assignment_operator_opt (cp_pa
*** 5291,5301 ****
static tree
cp_parser_expression (cp_parser* parser)
{
tree expression = NULL_TREE;
- bool saw_comma_p = false;
while (true)
{
tree assignment_expression;
--- 5276,5285 ----
*************** cp_parser_expression (cp_parser* parser)
*** 5304,5352 ****
= cp_parser_assignment_expression (parser);
/* If this is the first assignment-expression, we can just
save it away. */
if (!expression)
expression = assignment_expression;
- /* Otherwise, chain the expressions together. It is unclear why
- we do not simply build COMPOUND_EXPRs as we go. */
else
! expression = tree_cons (NULL_TREE,
! assignment_expression,
! expression);
/* If the next token is not a comma, then we are done with the
expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
/* Consume the `,'. */
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. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
! return cp_parser_non_constant_expression ("a comma operator");
parser->non_constant_expression_p = true;
}
- expression = build_x_compound_expr (nreverse (expression));
}
return expression;
}
--- 5288,5314 ----
= cp_parser_assignment_expression (parser);
/* If this is the first assignment-expression, we can just
save it away. */
if (!expression)
expression = assignment_expression;
else
! expression = build_x_compound_expr (expression,
! assignment_expression);
/* If the next token is not a comma, then we are done with the
expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
/* Consume the `,'. */
cp_lexer_consume_token (parser->lexer);
/* A comma operator cannot appear in a constant-expression. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
! expression
! = cp_parser_non_constant_expression ("a comma operator");
parser->non_constant_expression_p = true;
}
}
return expression;
}
*************** cp_parser_expression (cp_parser* parser)
*** 5354,5365 ****
constant-expression:
conditional-expression
If ALLOW_NON_CONSTANT_P a non-constant expression is silently
! accepted. In that case *NON_CONSTANT_P is set to TRUE. If
! ALLOW_NON_CONSTANT_P is false, NON_CONSTANT_P should be NULL. */
static tree
cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
bool *non_constant_p)
--- 5316,5328 ----
constant-expression:
conditional-expression
If ALLOW_NON_CONSTANT_P a non-constant expression is silently
! accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not
! constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P
! is false, NON_CONSTANT_P should be NULL. */
static tree
cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
bool *non_constant_p)
*************** cp_parser_labeled_statement (cp_parser*
*** 5545,5555 ****
/* Consume the `case' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser,
! /*allow_non_constant=*/false,
NULL);
/* Create the label. */
statement = finish_case_label (expr, NULL_TREE);
}
break;
--- 5508,5518 ----
/* Consume the `case' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser,
! /*allow_non_constant_p=*/false,
NULL);
/* Create the label. */
statement = finish_case_label (expr, NULL_TREE);
}
break;
*************** cp_parser_template_argument_list (cp_par
*** 8049,8065 ****
id-expression
The representation is that of an assignment-expression, type-id, or
id-expression -- except that the qualified id-expression is
evaluated, so that the value returned is either a DECL or an
! OVERLOAD. */
static tree
cp_parser_template_argument (cp_parser* parser)
{
tree argument;
bool template_p;
/* There's really no way to know what we're looking at, so we just
try each alternative in order.
[temp.arg]
--- 8012,8036 ----
id-expression
The representation is that of an assignment-expression, type-id, or
id-expression -- except that the qualified id-expression is
evaluated, so that the value returned is either a DECL or an
! 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
cp_parser_template_argument (cp_parser* parser)
{
tree argument;
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
try each alternative in order.
[temp.arg]
*************** cp_parser_template_argument (cp_parser*
*** 8071,8082 ****
Therefore, we try a type-id first. */
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
/* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */
! if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
! && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
cp_parser_error (parser, "expected template-argument");
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return argument;
/* We're still not sure what the argument will be. */
--- 8042,8052 ----
Therefore, we try a type-id first. */
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
/* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */
! if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return argument;
/* We're still not sure what the argument will be. */
*************** cp_parser_template_argument (cp_parser*
*** 8086,8097 ****
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
&template_p);
/* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */
! if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
! && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
cp_parser_error (parser, "expected template-argument");
if (!cp_parser_error_occurred (parser))
{
/* Figure out what is being referred to. */
argument = cp_parser_lookup_name_simple (parser, argument);
--- 8056,8066 ----
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
&template_p);
/* If the next token isn't a `,' or a `>', then this argument wasn't
really finished. */
! if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (!cp_parser_error_occurred (parser))
{
/* Figure out what is being referred to. */
argument = cp_parser_lookup_name_simple (parser, argument);
*************** cp_parser_template_argument (cp_parser*
*** 8102,8113 ****
else if (TREE_CODE (argument) != TEMPLATE_DECL)
cp_parser_error (parser, "expected template-name");
}
if (cp_parser_parse_definitely (parser))
return argument;
! /* It must be an assignment-expression. */
! return cp_parser_assignment_expression (parser);
}
/* Parse an explicit-instantiation.
explicit-instantiation:
--- 8071,8175 ----
else if (TREE_CODE (argument) != TEMPLATE_DECL)
cp_parser_error (parser, "expected template-name");
}
if (cp_parser_parse_definitely (parser))
return argument;
! /* It must be a non-type argument. There permitted cases are given
! 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.
explicit-instantiation:
*************** cp_parser_enumerator_definition (cp_pars
*** 8912,8922 ****
{
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the value. */
value = cp_parser_constant_expression (parser,
! /*allow_non_constant=*/false,
NULL);
}
else
value = NULL_TREE;
--- 8974,8984 ----
{
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the value. */
value = cp_parser_constant_expression (parser,
! /*allow_non_constant_p=*/false,
NULL);
}
else
value = NULL_TREE;
*************** cp_parser_direct_declarator (cp_parser*
*** 9917,9949 ****
bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
! /* If we're in a template, but the constant-expression
! 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
! && !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
bounds = NULL_TREE;
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
--- 9979,9990 ----
bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
! if (!non_constant_p)
! bounds = cp_parser_fold_non_dependent_expr (bounds);
}
else
bounds = NULL_TREE;
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
*************** cp_parser_declares_only_class_p (cp_pars
*** 14127,14136 ****
--- 14168,14207 ----
declarator. */
return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| 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.
Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */
static bool
cp_parser_friend_p (tree decl_specifiers)
*************** cp_parser_next_token_starts_class_defini
*** 14272,14281 ****
--- 14343,14364 ----
token = cp_lexer_peek_token (parser->lexer);
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,
or none_type otherwise. */
static enum tag_types
cp_parser_token_is_class_key (cp_token* token)
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.716
diff -c -5 -p -r1.716 pt.c
*** cp/pt.c 8 Jul 2003 15:35:48 -0000 1.716
--- cp/pt.c 9 Jul 2003 08:30:24 -0000
*************** static tree for_each_template_parm_r (tr
*** 165,175 ****
static tree copy_default_args_to_explicit_spec_1 (tree, tree);
static void copy_default_args_to_explicit_spec (tree);
static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
static int eq_local_specializations (const void *, const void *);
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_expr (tree, tree, tsubst_flags_t, tree);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
--- 165,174 ----
*************** convert_template_argument (tree parm,
*** 3592,3604 ****
tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node;
- if (processing_template_decl)
- arg = maybe_fold_nontype_arg (arg);
-
if (!uses_template_parms (arg) && !uses_template_parms (t))
/* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain
is zero. More importantly, digest_init will try too
hard to convert things: for example, `0' should not be
--- 3591,3600 ----
*************** tsubst_baselink (tree baselink, tree obj
*** 7106,7118 ****
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
template_id_p = true;
template_args = TREE_OPERAND (fns, 1);
fns = TREE_OPERAND (fns, 0);
! template_args = tsubst_copy (template_args, args,
! complain, in_decl);
! maybe_fold_nontype_args (template_args);
}
name = DECL_NAME (get_first_fn (fns));
baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
if (BASELINK_P (baselink) && template_id_p)
BASELINK_FUNCTIONS (baselink)
--- 7102,7113 ----
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
template_id_p = true;
template_args = TREE_OPERAND (fns, 1);
fns = TREE_OPERAND (fns, 0);
! template_args = tsubst_copy_and_build (template_args, args,
! complain, in_decl);
}
name = DECL_NAME (get_first_fn (fns));
baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
if (BASELINK_P (baselink) && template_id_p)
BASELINK_FUNCTIONS (baselink)
*************** tsubst_copy_and_build (tree t,
*** 8001,8056 ****
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
return build_x_unary_op (TREE_CODE (t), op1);
case PREDECREMENT_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 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:
! if (TREE_TYPE (t))
! return t;
! return build_x_unary_op
! (TREE_CODE (t),
! tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
case ADDR_EXPR:
op1 = TREE_OPERAND (t, 0);
if (TREE_CODE (op1) == SCOPE_REF)
op1 = tsubst_qualified_id (op1, args, complain, in_decl,
/*done=*/true, /*address_p=*/true);
else
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
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 MINUS_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
--- 7996,8026 ----
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
return build_x_unary_op (TREE_CODE (t), op1);
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case NEGATE_EXPR:
case BIT_NOT_EXPR:
case ABS_EXPR:
! case TRUTH_NOT_EXPR:
! case CONVERT_EXPR: /* Unary + */
! case REALPART_EXPR:
! case IMAGPART_EXPR:
! return (build_x_unary_op
! (TREE_CODE (t),
! tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! in_decl)));
case ADDR_EXPR:
op1 = TREE_OPERAND (t, 0);
if (TREE_CODE (op1) == SCOPE_REF)
op1 = tsubst_qualified_id (op1, args, complain, in_decl,
/*done=*/true, /*address_p=*/true);
else
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
return build_x_unary_op (ADDR_EXPR, op1);
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
*************** tsubst_copy_and_build (tree t,
*** 8117,8135 ****
args, complain,
in_decl));
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
! {
! tree r =
! tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl);
! if (!TYPE_P (r))
! return TREE_CODE (t) == SIZEOF_EXPR ?
! expr_sizeof (r) : c_alignof_expr (r);
! else
! return cxx_sizeof_or_alignof_type (r, TREE_CODE (t), true);
! }
case MODOP_EXPR:
return build_x_modify_expr
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
TREE_CODE (TREE_OPERAND (t, 1)),
--- 8087,8115 ----
args, complain,
in_decl));
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
! op1 = TREE_OPERAND (t, 0);
! if (!args)
! {
! /* When there are no ARGS, we are trying to evaluate a
! non-dependent expression from the parser. Trying to do
! the substitutions may not work. */
! if (!TYPE_P (op1))
! 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:
return build_x_modify_expr
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
TREE_CODE (TREE_OPERAND (t, 1)),
*************** tsubst_copy_and_build (tree t,
*** 8160,8178 ****
tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl),
DELETE_EXPR_USE_VEC (t),
DELETE_EXPR_USE_GLOBAL (t));
case COMPOUND_EXPR:
! {
! if (tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl)
! == NULL_TREE)
! return build_x_compound_expr
! (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! in_decl));
! else
! abort ();
! }
case CALL_EXPR:
{
tree function;
tree call_args;
--- 8140,8154 ----
tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl),
DELETE_EXPR_USE_VEC (t),
DELETE_EXPR_USE_GLOBAL (t));
case COMPOUND_EXPR:
! return (build_x_compound_expr
! (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! in_decl),
! tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
! in_decl)));
case CALL_EXPR:
{
tree function;
tree call_args;
*************** tsubst_copy_and_build (tree t,
*** 8208,8236 ****
call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
complain, in_decl);
if (BASELINK_P (function))
! return build_call_from_tree (function, call_args, 1);
! else
! {
! if (call_args != NULL_TREE && koenig_name)
! function = lookup_arg_dependent (koenig_name,
! function,
! call_args);
!
! if (TREE_CODE (function) == OFFSET_REF)
! return build_offset_ref_call_from_tree (function, call_args);
! if (TREE_CODE (function) == COMPONENT_REF)
! return (build_new_method_call
! (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:
return build_x_conditional_expr
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
--- 8184,8210 ----
call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
complain, in_decl);
if (BASELINK_P (function))
! qualified_p = 1;
!
! if (call_args != NULL_TREE && koenig_name)
! function = lookup_arg_dependent (koenig_name,
! function,
! call_args);
!
! if (TREE_CODE (function) == OFFSET_REF)
! return build_offset_ref_call_from_tree (function, call_args);
! if (TREE_CODE (function) == COMPONENT_REF)
! return (build_new_method_call
! (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:
return build_x_conditional_expr
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
*************** tsubst_copy_and_build (tree t,
*** 8387,8396 ****
--- 8361,8375 ----
return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
case VAR_DECL:
if (args)
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);
case VA_ARG_EXPR:
return build_x_va_arg
(tsubst_copy_and_build
*************** value_dependent_expression_p (tree expre
*** 11489,11518 ****
return true;
/* A constant with integral or enumeration type and is initialized
with an expression that is value-dependent. */
if (TREE_CODE (expression) == VAR_DECL
&& DECL_INITIAL (expression)
! && INTEGRAL_OR_ENUMERATION_TYPE_P (expression)
&& value_dependent_expression_p (DECL_INITIAL (expression)))
return true;
/* These expressions are value-dependent if the type to which the
cast occurs is dependent or the expression being casted is
value-dependent. */
! if ((TREE_CODE (expression) == DYNAMIC_CAST_EXPR
! || TREE_CODE (expression) == STATIC_CAST_EXPR
! || TREE_CODE (expression) == CONST_CAST_EXPR
! || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
! || TREE_CODE (expression) == CAST_EXPR)
! && (dependent_type_p (TREE_TYPE (expression))
! || value_dependent_expression_p (TREE_OPERAND (expression, 0))))
! return true;
! /* A `sizeof' expression where the sizeof operand is a type is
! value-dependent if the type is dependent. If the type was not
! dependent, we would no longer have a SIZEOF_EXPR, so any
! SIZEOF_EXPR is dependent. */
! if (TREE_CODE (expression) == SIZEOF_EXPR)
! return true;
/* A constant expression is value-dependent if any subexpression is
value-dependent. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
{
switch (TREE_CODE_CLASS (TREE_CODE (expression)))
--- 11468,11517 ----
return true;
/* A constant with integral or enumeration type and is initialized
with an expression that is value-dependent. */
if (TREE_CODE (expression) == VAR_DECL
&& DECL_INITIAL (expression)
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (expression))
&& value_dependent_expression_p (DECL_INITIAL (expression)))
return true;
/* These expressions are value-dependent if the type to which the
cast occurs is dependent or the expression being casted is
value-dependent. */
! if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
! || TREE_CODE (expression) == STATIC_CAST_EXPR
! || TREE_CODE (expression) == CONST_CAST_EXPR
! || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
! || TREE_CODE (expression) == CAST_EXPR)
! {
! if (dependent_type_p (TREE_TYPE (expression)))
! return true;
! /* A functional cast has a list of operands. */
! expression = TREE_OPERAND (expression, 0);
! if (TREE_CODE (expression) == TREE_LIST)
! {
! do
! {
! 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
value-dependent. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
{
switch (TREE_CODE_CLASS (TREE_CODE (expression)))
*************** type_dependent_expression_p (tree expres
*** 11572,11585 ****
|| TREE_CODE (expression) == STATIC_CAST_EXPR
|| TREE_CODE (expression) == CONST_CAST_EXPR
|| TREE_CODE (expression) == REINTERPRET_CAST_EXPR
|| TREE_CODE (expression) == CAST_EXPR)
return dependent_type_p (TREE_TYPE (expression));
/* The types of these expressions depends only on the type created
by the expression. */
! else if (TREE_CODE (expression) == NEW_EXPR
! || TREE_CODE (expression) == VEC_NEW_EXPR)
{
/* For NEW_EXPR tree nodes created inside a template, either
the object type itself or a TREE_LIST may appear as the
operand 1. */
tree type = TREE_OPERAND (expression, 1);
--- 11571,11585 ----
|| TREE_CODE (expression) == STATIC_CAST_EXPR
|| TREE_CODE (expression) == CONST_CAST_EXPR
|| TREE_CODE (expression) == REINTERPRET_CAST_EXPR
|| TREE_CODE (expression) == CAST_EXPR)
return dependent_type_p (TREE_TYPE (expression));
+
/* The types of these expressions depends only on the type created
by the expression. */
! if (TREE_CODE (expression) == NEW_EXPR
! || TREE_CODE (expression) == VEC_NEW_EXPR)
{
/* For NEW_EXPR tree nodes created inside a template, either
the object type itself or a TREE_LIST may appear as the
operand 1. */
tree type = TREE_OPERAND (expression, 1);
*************** type_dependent_expression_p (tree expres
*** 11599,11614 ****
&& (dependent_template_id_p
(DECL_TI_TEMPLATE (expression),
INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
return true;
return (dependent_type_p (TREE_TYPE (expression)));
}
! /* Returns TRUE if the ARG (a template argument) is dependent. */
bool
dependent_template_arg_p (tree arg)
{
if (!processing_template_decl)
return false;
--- 11599,11655 ----
&& (dependent_template_id_p
(DECL_TI_TEMPLATE (expression),
INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
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)));
}
! /* 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. */
+
+ static bool
dependent_template_arg_p (tree arg)
{
if (!processing_template_decl)
return false;
*************** dependent_template_arg_p (tree arg)
*** 11620,11641 ****
else
return (type_dependent_expression_p (arg)
|| value_dependent_expression_p (arg));
}
! /* Returns TRUE if the specialization TMPL<ARGS> is dependent. */
! static bool
! dependent_template_id_p (tree tmpl, tree args)
{
! int i;
- 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;
}
/* Returns TRUE if the template TMPL is dependent. */
--- 11661,11700 ----
else
return (type_dependent_expression_p (arg)
|| value_dependent_expression_p (arg));
}
! /* Returns true if ARGS (a collection of template arguments) contains
! any dependent arguments. */
! bool
! any_dependent_template_arguments_p (tree args)
{
! 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;
! }
return false;
}
/* Returns TRUE if the template TMPL is dependent. */
*************** dependent_template_p (tree tmpl)
*** 11644,11659 ****
--- 11703,11730 ----
{
/* Template template parameters are dependent. */
if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
|| TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
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. */
if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
return dependent_type_p (DECL_CONTEXT (tmpl));
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
TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE
can be found. Note that this function peers inside uninstantiated
templates and therefore should be used only in extremely limited
situations. */
*************** resolve_typename_type (tree type, bool o
*** 11726,11733 ****
--- 11797,11854 ----
type = cp_build_qualified_type (type, quals);
/* Leave the SCOPE. */
pop_scope (scope);
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"
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.324
diff -c -5 -p -r1.324 semantics.c
*** cp/semantics.c 8 Jul 2003 01:38:44 -0000 1.324
--- cp/semantics.c 9 Jul 2003 08:30:24 -0000
*************** tree
*** 1447,1458 ****
finish_stmt_expr (tree rtl_expr)
{
tree result;
/* If the last thing in the statement-expression was not an
! expression-statement, then it has type `void'. */
! if (!last_expr_type)
last_expr_type = void_type_node;
result = build_min (STMT_EXPR, last_expr_type, last_tree);
TREE_SIDE_EFFECTS (result) = 1;
/* Remove the compound statement from the tree structure; it is
--- 1447,1462 ----
finish_stmt_expr (tree rtl_expr)
{
tree result;
/* If the last thing in the statement-expression was not an
! expression-statement, then it has type `void'. In a template, we
! 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;
result = build_min (STMT_EXPR, last_expr_type, last_tree);
TREE_SIDE_EFFECTS (result) = 1;
/* Remove the compound statement from the tree structure; it is
*************** finish_stmt_expr (tree rtl_expr)
*** 1480,1499 ****
Returns code for the call. */
tree
finish_call_expr (tree fn, tree args, bool disallow_virtual)
{
if (fn == error_mark_node || args == 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. */
my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
20020712);
/* A reference to a member function will appear as an overloaded
function (rather than a BASELINK) if an unqualified name was used
to refer to it. */
if (!BASELINK_P (fn) && is_overloaded_fn (fn))
{
--- 1484,1519 ----
Returns code for the call. */
tree
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)
return error_mark_node;
/* ARGS should be a list of arguments. */
my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
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
function (rather than a BASELINK) if an unqualified name was used
to refer to it. */
if (!BASELINK_P (fn) && is_overloaded_fn (fn))
{
*************** finish_call_expr (tree fn, tree args, bo
*** 1510,1519 ****
--- 1530,1540 ----
TYPE_BINFO (type),
fn, /*optype=*/NULL_TREE);
}
}
+ result = NULL_TREE;
if (BASELINK_P (fn))
{
tree object;
/* A call to a member function. From [over.call.func]:
*************** finish_call_expr (tree fn, tree args, bo
*** 1549,1591 ****
representative_fn = TREE_OPERAND (representative_fn, 0);
representative_fn = get_first_fn (representative_fn);
object = build_dummy_object (DECL_CONTEXT (representative_fn));
}
! return build_new_method_call (object, fn, args, NULL_TREE,
! (disallow_virtual
! ? LOOKUP_NONVIRTUAL : 0));
}
else if (is_overloaded_fn (fn))
/* A call to a namespace-scope function. */
! return build_new_function_call (fn, args);
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{
- tree result;
-
if (args)
error ("arguments to destructor are not allowed");
/* Mark the pseudo-destructor call as having side-effects so
that we do not issue warnings about its use. */
result = build1 (NOP_EXPR,
void_type_node,
TREE_OPERAND (fn, 0));
TREE_SIDE_EFFECTS (result) = 1;
- return result;
}
else if (CLASS_TYPE_P (TREE_TYPE (fn)))
! {
! /* If the "function" is really an object of class type, it might
! have an overloaded `operator ()'. */
! tree result;
! result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
! if (result)
! return result;
! }
! /* A call where the function is unknown. */
! return build_function_call (fn, args);
}
/* Finish a call to a postfix increment or decrement or EXPR. (Which
is indicated by CODE, which should be POSTINCREMENT_EXPR or
POSTDECREMENT_EXPR.) */
--- 1570,1615 ----
representative_fn = TREE_OPERAND (representative_fn, 0);
representative_fn = get_first_fn (representative_fn);
object = build_dummy_object (DECL_CONTEXT (representative_fn));
}
! if (processing_template_decl)
! {
! 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))
/* A call to a namespace-scope function. */
! result = build_new_function_call (fn, args);
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{
if (args)
error ("arguments to destructor are not allowed");
/* Mark the pseudo-destructor call as having side-effects so
that we do not issue warnings about its use. */
result = build1 (NOP_EXPR,
void_type_node,
TREE_OPERAND (fn, 0));
TREE_SIDE_EFFECTS (result) = 1;
}
else if (CLASS_TYPE_P (TREE_TYPE (fn)))
! /* If the "function" is really an object of class type, it might
! have an overloaded `operator ()'. */
! result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
! if (!result)
! /* A call where the function is unknown. */
! result = build_function_call (fn, args);
! if (processing_template_decl)
! 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
is indicated by CODE, which should be POSTINCREMENT_EXPR or
POSTDECREMENT_EXPR.) */
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.334
diff -c -5 -p -r1.334 tree.c
*** cp/tree.c 5 Jul 2003 03:02:04 -0000 1.334
--- cp/tree.c 9 Jul 2003 08:30:24 -0000
*************** lvalue_p_1 (tree ref,
*** 172,181 ****
--- 172,189 ----
/* All functions (except non-static-member functions) are
lvalues. */
return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
? 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:
break;
}
/* If one operand is not an lvalue at all, then this expression is
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.476
diff -c -5 -p -r1.476 typeck.c
*** cp/typeck.c 8 Jul 2003 01:38:44 -0000 1.476
--- cp/typeck.c 9 Jul 2003 08:30:24 -0000
*************** cxx_sizeof_or_alignof_type (tree type, e
*** 1415,1425 ****
tree value;
const char *op_name;
my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
if (processing_template_decl)
! return build_min_nt (op, type);
op_name = operator_name_info[(int) op].name;
type = non_reference (type);
type_code = TREE_CODE (type);
--- 1415,1425 ----
tree value;
const char *op_name;
my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
if (processing_template_decl)
! return build_min (op, size_type_node, type);
op_name = operator_name_info[(int) op].name;
type = non_reference (type);
type_code = TREE_CODE (type);
*************** cxx_sizeof_or_alignof_type (tree type, e
*** 1444,1454 ****
tree
expr_sizeof (tree e)
{
if (processing_template_decl)
! return build_min_nt (SIZEOF_EXPR, e);
if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
error ("sizeof applied to a bit-field");
if (is_overloaded_fn (e))
--- 1444,1454 ----
tree
expr_sizeof (tree e)
{
if (processing_template_decl)
! return build_min (SIZEOF_EXPR, size_type_node, e);
if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
error ("sizeof applied to a bit-field");
if (is_overloaded_fn (e))
*************** lookup_destructor (tree object, tree sco
*** 2013,2033 ****
BASELINK. */
tree
finish_class_member_access_expr (tree object, tree name)
{
tree object_type;
tree member;
tree access_path = NULL_TREE;
if (object == error_mark_node || name == error_mark_node)
return error_mark_node;
if (processing_template_decl)
! return build_min_nt (COMPONENT_REF, object, name);
- object_type = TREE_TYPE (object);
if (TREE_CODE (object_type) == REFERENCE_TYPE)
{
object = convert_from_reference (object);
object_type = TREE_TYPE (object);
}
--- 2013,2052 ----
BASELINK. */
tree
finish_class_member_access_expr (tree object, tree name)
{
+ tree expr;
tree object_type;
tree member;
tree access_path = NULL_TREE;
+ tree orig_object = object;
+ tree orig_name = name;
if (object == error_mark_node || name == error_mark_node)
return error_mark_node;
+ 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)
{
object = convert_from_reference (object);
object_type = TREE_TYPE (object);
}
*************** finish_class_member_access_expr (tree ob
*** 2055,2076 ****
}
else
{
bool is_template_id = false;
tree template_args = NULL_TREE;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
is_template_id = true;
template_args = TREE_OPERAND (name, 1);
name = TREE_OPERAND (name, 0);
}
if (TREE_CODE (name) == SCOPE_REF)
{
- tree scope;
-
/* A qualified name. The qualifying class or namespace `S' has
already been looked up; it is either a TYPE or a
NAMESPACE_DECL. The member name is either an IDENTIFIER_NODE
or a BIT_NOT_EXPR. */
scope = TREE_OPERAND (name, 0);
--- 2074,2094 ----
}
else
{
bool is_template_id = false;
tree template_args = NULL_TREE;
+ tree scope;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
is_template_id = true;
template_args = TREE_OPERAND (name, 1);
name = TREE_OPERAND (name, 0);
}
if (TREE_CODE (name) == SCOPE_REF)
{
/* A qualified name. The qualifying class or namespace `S' has
already been looked up; it is either a TYPE or a
NAMESPACE_DECL. The member name is either an IDENTIFIER_NODE
or a BIT_NOT_EXPR. */
scope = TREE_OPERAND (name, 0);
*************** finish_class_member_access_expr (tree ob
*** 2093,2153 ****
/* Find the base of OBJECT_TYPE corresponding to SCOPE. */
access_path = lookup_base (object_type, scope, ba_check, NULL);
if (!access_path || access_path == 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)
! member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
! else if (TREE_CODE (name) == IDENTIFIER_NODE)
{
! /* An unqualified name. */
! member = lookup_member (object_type, name, /*protect=*/1,
/*want_type=*/false);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
return error_mark_node;
}
! else if (member == 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)
{
tree template = member;
if (BASELINK_P (template))
! BASELINK_FUNCTIONS (template)
! = build_nt (TEMPLATE_ID_EXPR,
! BASELINK_FUNCTIONS (template),
! template_args);
else
{
error ("`%D' is not a member template function", name);
return error_mark_node;
}
--- 2111,2149 ----
/* Find the base of OBJECT_TYPE corresponding to SCOPE. */
access_path = lookup_base (object_type, scope, ba_check, NULL);
if (!access_path || access_path == error_mark_node)
return error_mark_node;
}
! else
! {
! scope = NULL_TREE;
! 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);
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;
}
if (is_template_id)
{
tree template = member;
if (BASELINK_P (template))
! template = lookup_template_function (template, template_args);
else
{
error ("`%D' is not a member template function", name);
return error_mark_node;
}
*************** finish_class_member_access_expr (tree ob
*** 2155,2166 ****
}
if (TREE_DEPRECATED (member))
warn_deprecated_use (member);
! return build_class_member_access_expr (object, member, access_path,
/*preserve_reference=*/false);
}
/* Return an expression for the MEMBER_NAME field in the internal
representation of PTRMEM, a pointer-to-member function. (Each
pointer-to-member function type gets its own RECORD_TYPE so it is
--- 2151,2166 ----
}
if (TREE_DEPRECATED (member))
warn_deprecated_use (member);
! expr = build_class_member_access_expr (object, member, access_path,
/*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
representation of PTRMEM, a pointer-to-member function. (Each
pointer-to-member function type gets its own RECORD_TYPE so it is
*************** build_ptrmemfunc_access_expr (tree ptrme
*** 2194,2215 ****
This function may need to overload OPERATOR_FNNAME.
Must also handle REFERENCE_TYPEs for C++. */
tree
! build_x_indirect_ref (tree ptr, const char *errorstring)
{
tree rval;
if (processing_template_decl)
! return build_min_nt (INDIRECT_REF, ptr);
! rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
NULL_TREE);
! if (rval)
return rval;
- return build_indirect_ref (ptr, errorstring);
}
tree
build_indirect_ref (tree ptr, const char *errorstring)
{
--- 2194,2224 ----
This function may need to overload OPERATOR_FNNAME.
Must also handle REFERENCE_TYPEs for C++. */
tree
! build_x_indirect_ref (tree expr, const char *errorstring)
{
+ tree orig_expr = expr;
tree rval;
if (processing_template_decl)
! {
! 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, expr, NULL_TREE,
NULL_TREE);
! 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;
}
tree
build_indirect_ref (tree ptr, const char *errorstring)
{
*************** convert_arguments (tree typelist, tree v
*** 2824,3019 ****
conversions on the operands. CODE is the kind of expression to build. */
tree
build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
{
! 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;
! tree op0_type;
! tree op1_type;
! tree op2_type;
!
! /* 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);
}
- #endif
-
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
the data type of the result is computed and recorded in it,
warnings are generated if arg data types are invalid,
--- 2833,2869 ----
conversions on the operands. CODE is the kind of expression to build. */
tree
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 (type_dependent_expression_p (arg1)
! || type_dependent_expression_p (arg2))
! return build_min_nt (code, arg1, arg2);
! arg1 = build_non_dependent_expr (arg1);
! arg2 = build_non_dependent_expr (arg2);
}
+
+ if (code == DOTSTAR_EXPR)
+ expr = build_m_component_ref (arg1, arg2);
+ else
+ expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+
+ 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.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
the data type of the result is computed and recorded in it,
warnings are generated if arg data types are invalid,
*************** pointer_diff (register tree op0, registe
*** 3837,3870 ****
and XARG is the operand. */
tree
build_x_unary_op (enum tree_code code, tree xarg)
{
tree exp;
int ptrmem = 0;
if (processing_template_decl)
! return build_min_nt (code, xarg, NULL_TREE);
/* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
error message. */
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* don't look for a function */;
else
! {
! tree rval;
!
! 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
&X::mf. */
if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
&& (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
--- 3687,3720 ----
and XARG is the operand. */
tree
build_x_unary_op (enum tree_code code, tree xarg)
{
+ tree orig_expr = xarg;
tree exp;
int ptrmem = 0;
if (processing_template_decl)
! {
! 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
error message. */
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* don't look for a function */;
else
! exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
! if (!exp && code == ADDR_EXPR)
{
/* A pointer to member-function can be formed only by saying
&X::mf. */
if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
&& (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
*************** build_x_unary_op (enum tree_code code, t
*** 3894,3913 ****
pointer-to-member. */
xarg = build (OFFSET_REF, TREE_TYPE (xarg),
TREE_OPERAND (xarg, 0),
ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
PTRMEM_OK_P (xarg) = ptrmem;
! }
!
}
else if (TREE_CODE (xarg) == TARGET_EXPR)
warning ("taking address of temporary");
}
- exp = build_unary_op (code, xarg, 0);
- if (TREE_CODE (exp) == ADDR_EXPR)
- PTRMEM_OK_P (exp) = ptrmem;
return exp;
}
/* Like c_common_truthvalue_conversion, but handle pointer-to-member
constants, where a null value is represented by an INTEGER_CST of
--- 3744,3764 ----
pointer-to-member. */
xarg = build (OFFSET_REF, TREE_TYPE (xarg),
TREE_OPERAND (xarg, 0),
ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
PTRMEM_OK_P (xarg) = ptrmem;
! }
}
else if (TREE_CODE (xarg) == TARGET_EXPR)
warning ("taking address of temporary");
+ exp = build_unary_op (ADDR_EXPR, 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;
}
/* Like c_common_truthvalue_conversion, but handle pointer-to-member
constants, where a null value is represented by an INTEGER_CST of
*************** cxx_mark_addressable (tree exp)
*** 4629,4685 ****
/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
tree
build_x_conditional_expr (tree ifexp, tree op1, tree op2)
{
! if (processing_template_decl)
! return build_min_nt (COND_EXPR, ifexp, op1, op2);
! return build_conditional_expr (ifexp, op1, op2);
}
/* Handle overloading of the ',' operator when needed. Otherwise,
this function just builds an expression list. */
tree
! build_x_compound_expr (tree list)
{
- tree rest = TREE_CHAIN (list);
tree result;
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. */
! /* 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 (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
! (tree_cons (NULL_TREE, TREE_VALUE (list),
! build_tree_list (NULL_TREE,
! build_x_compound_expr (rest))));
}
/* Given a list of expressions, return a compound expression
that performs them all and returns the value of the last of them. */
--- 4480,4559 ----
/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
tree
build_x_conditional_expr (tree ifexp, tree op1, tree op2)
{
! tree orig_ifexp = ifexp;
! tree orig_op1 = op1;
! tree orig_op2 = op2;
! tree expr;
! 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,
this function just builds an expression list. */
tree
! build_x_compound_expr (tree op1, tree op2)
{
tree result;
+ tree orig_op1 = op1;
+ tree orig_op2 = op2;
if (processing_template_decl)
! {
! if (type_dependent_expression_p (op1)
! || type_dependent_expression_p (op2))
! return build_min_nt (COMPOUND_EXPR, op1, op2);
! op1 = build_non_dependent_expr (op1);
! op2 = build_non_dependent_expr (op2);
! }
!
! result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
! if (!result)
! {
! 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
that performs them all and returns the value of the last of them. */
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.143
diff -c -5 -p -r1.143 typeck2.c
*** cp/typeck2.c 6 Jul 2003 03:30:56 -0000 1.143
--- cp/typeck2.c 9 Jul 2003 08:30:24 -0000
*************** build_scoped_ref (tree datum, tree baset
*** 978,1025 ****
performed until an object which does not have the `->' operator
overloaded is found. An error is reported when circular pointer
delegation is detected. */
tree
! build_x_arrow (tree datum)
{
tree types_memoized = NULL_TREE;
! register tree rval = datum;
! tree type = TREE_TYPE (rval);
tree last_rval = NULL_TREE;
if (type == error_mark_node)
return error_mark_node;
if (processing_template_decl)
! return build_min_nt (ARROW_EXPR, rval);
if (TREE_CODE (type) == REFERENCE_TYPE)
{
! rval = convert_from_reference (rval);
! type = TREE_TYPE (rval);
}
if (IS_AGGR_TYPE (type))
{
! while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval,
NULL_TREE, NULL_TREE)))
{
! if (rval == error_mark_node)
return error_mark_node;
! if (value_member (TREE_TYPE (rval), types_memoized))
{
error ("circular pointer delegation detected");
return error_mark_node;
}
else
{
! types_memoized = tree_cons (NULL_TREE, TREE_TYPE (rval),
types_memoized);
}
! last_rval = rval;
}
if (last_rval == NULL_TREE)
{
error ("base operand of `->' has non-pointer type `%T'", type);
--- 978,1029 ----
performed until an object which does not have the `->' operator
overloaded is found. An error is reported when circular pointer
delegation is detected. */
tree
! build_x_arrow (tree expr)
{
+ tree orig_expr = expr;
tree types_memoized = NULL_TREE;
! tree type = TREE_TYPE (expr);
tree last_rval = NULL_TREE;
if (type == error_mark_node)
return error_mark_node;
if (processing_template_decl)
! {
! 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)
{
! expr = convert_from_reference (expr);
! type = TREE_TYPE (expr);
}
if (IS_AGGR_TYPE (type))
{
! while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
NULL_TREE, NULL_TREE)))
{
! if (expr == error_mark_node)
return error_mark_node;
! if (value_member (TREE_TYPE (expr), types_memoized))
{
error ("circular pointer delegation detected");
return error_mark_node;
}
else
{
! types_memoized = tree_cons (NULL_TREE, TREE_TYPE (expr),
types_memoized);
}
! last_rval = expr;
}
if (last_rval == NULL_TREE)
{
error ("base operand of `->' has non-pointer type `%T'", type);
*************** build_x_arrow (tree datum)
*** 1028,1041 ****
if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
last_rval = convert_from_reference (last_rval);
}
else
! last_rval = decay_conversion (rval);
if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
! return build_indirect_ref (last_rval, NULL);
if (types_memoized)
error ("result of `operator->()' yields non-pointer result");
else
error ("base operand of `->' is not a pointer");
--- 1032,1052 ----
if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
last_rval = convert_from_reference (last_rval);
}
else
! last_rval = decay_conversion (expr);
if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
! {
! 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)
error ("result of `operator->()' yields non-pointer result");
else
error ("base operand of `->' is not a pointer");
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.313
diff -c -5 -p -r1.313 invoke.texi
*** doc/invoke.texi 9 Jul 2003 01:20:24 -0000 1.313
--- doc/invoke.texi 9 Jul 2003 08:30:25 -0000
*************** Dump after running tracer, to @file{@var
*** 3215,3225 ****
@opindex du
Dump after null pointer elimination pass to @file{@var{file}.018.null}.
@item U
@opindex dU
Dump callgraph and unit-at-a-time optimization @file{@var{file}.00.unit}.
! @litem w
@opindex dw
Dump after the second flow pass, to @file{@var{file}.29.flow2}.
@item W
@opindex dW
Dump after SSA conditional constant propagation, to
--- 3215,3225 ----
@opindex du
Dump after null pointer elimination pass to @file{@var{file}.018.null}.
@item U
@opindex dU
Dump callgraph and unit-at-a-time optimization @file{@var{file}.00.unit}.
! @item w
@opindex dw
Dump after the second flow pass, to @file{@var{file}.29.flow2}.
@item W
@opindex dW
Dump after SSA conditional constant propagation, to
Index: testsuite/g++.dg/abi/mangle17.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle17.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 mangle17.C
*** testsuite/g++.dg/abi/mangle17.C 17 Oct 2002 02:07:44 -0000 1.1
--- testsuite/g++.dg/abi/mangle17.C 9 Jul 2003 08:30:26 -0000
***************
*** 2,11 ****
enum E { e = 3 };
template <int I> struct S {};
! template <int I> void f (S<e + int (3.7)>) {}
! template void f<7>(S<e + int (3.7)>); // { dg-warning "mangle" }
! template <int I> void g (S<e + int (3.7)>) {}
! template void g<7>(S<e + int (3.7)>); // { dg-warning "mangle" }
--- 2,11 ----
enum E { e = 3 };
template <int I> struct S {};
! template <int I> void f (S<I + e + int (3.7)>) {}
! template void f<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }
! template <int I> void g (S<I + e + int (3.7)>) {}
! template void g<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }
Index: testsuite/g++.dg/abi/mangle4.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle4.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 mangle4.C
*** testsuite/g++.dg/abi/mangle4.C 26 Jun 2003 00:07:50 -0000 1.2
--- testsuite/g++.dg/abi/mangle4.C 9 Jul 2003 08:30:26 -0000
*************** class B : public A {};
*** 6,26 ****
template<const A* a> class C {};
template<const B* b> class D {};
template<B* b> class E {};
! template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {}
! template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {}
B b;
int main()
{
! C<static_cast<const A*>(&b)> c;
D<&b> d;
! E<const_cast<B*>(&b)> e;
! f(d, c);
! g(d, e);
}
- // { dg-final { scan-assembler "\n_?_Z1fIXadL_Z1bEEEvR1DIXT_EER1CIXcvPK1AT_EE\[: \t\n\]" } }
- // { dg-final { scan-assembler "\n_?_Z1gIXadL_Z1bEEEvR1DIXT_EER1EIXcvP1BT_EE\[: \t\n\]" } }
--- 6,24 ----
template<const A* a> class C {};
template<const B* b> class D {};
template<B* b> class E {};
! 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)> &) {} // { dg-error "" }
B b;
int main()
{
! C<static_cast<const A*>(&b)> c; // { dg-error "" }
D<&b> d;
! E<const_cast<B*>(&b)> e; // { dg-error "" }
! f(d, c); // { dg-error "" }
! g(d, e); // { dg-error "" }
}
Index: testsuite/g++.dg/debug/debug7.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/debug/debug7.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 debug7.C
*** testsuite/g++.dg/debug/debug7.C 5 Jul 2002 16:40:01 -0000 1.2
--- testsuite/g++.dg/debug/debug7.C 9 Jul 2003 08:30:26 -0000
*************** void f (int);
*** 5,15 ****
int
main() {
int a = 4;
int b = 5;
! int (*x)[b] = new int[a][b];
x[2][1] = 7;
for (int i = 0; i < a; ++i)
for (int j = 0; j < b; ++j)
--- 5,15 ----
int
main() {
int a = 4;
int b = 5;
! int (*x)[b] = new int[a][b]; // { dg-error "" }
x[2][1] = 7;
for (int i = 0; i < a; ++i)
for (int j = 0; j < b; ++j)
Index: testsuite/g++.dg/opt/stack1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/opt/stack1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 stack1.C
*** testsuite/g++.dg/opt/stack1.C 7 Jul 2003 07:25:36 -0000 1.1
--- testsuite/g++.dg/opt/stack1.C 9 Jul 2003 08:30:26 -0000
*************** struct matrix {
*** 66,76 ****
template<typename=void>
struct adaptor {
adaptor (matrix<> &m) : m(&m), upper_ (1) {}
! int size1 () const { return m->size1 (); }
int size2 () const { return 3; }
int lower () const { return 1; }
int upper () const { return upper_; }
matrix<> &data () { return *m; }
--- 66,76 ----
template<typename=void>
struct adaptor {
adaptor (matrix<> &m) : m(&m), upper_ (1) {}
! int size1 () const;
int size2 () const { return 3; }
int lower () const { return 1; }
int upper () const { return upper_; }
matrix<> &data () { return *m; }
Index: testsuite/g++.dg/parse/template7.C
===================================================================
RCS file: testsuite/g++.dg/parse/template7.C
diff -N testsuite/g++.dg/parse/template7.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/template7.C 9 Jul 2003 08:30:26 -0000
***************
*** 0 ****
--- 1,4 ----
+ template <int I>
+ void f();
+
+ void g() { f<(3, 2)>(); } // { dg-error "" }
Index: testsuite/g++.dg/template/dependent-expr1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/dependent-expr1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 dependent-expr1.C
*** testsuite/g++.dg/template/dependent-expr1.C 2 Jul 2003 09:36:20 -0000 1.1
--- testsuite/g++.dg/template/dependent-expr1.C 9 Jul 2003 08:30:26 -0000
*************** namespace std
*** 19,29 ****
Foo (sizeof (x));
Foo (__alignof__ (I));
Foo (__alignof__ (x));
Foo (x->~I ());
// Foo (typeid (I));
! Foo (delete x);
! Foo (delete[] x);
! Foo (throw x);
}
}
--- 19,29 ----
Foo (sizeof (x));
Foo (__alignof__ (I));
Foo (__alignof__ (x));
Foo (x->~I ());
// Foo (typeid (I));
! Foo (delete x); // { dg-error "" }
! Foo (delete[] x); // { dg-error "" }
! Foo (throw x); // { dg-error "" }
}
}
Index: testsuite/g++.old-deja/g++.pt/crash41.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/crash41.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 crash41.C
*** testsuite/g++.old-deja/g++.pt/crash41.C 1 May 2003 02:02:53 -0000 1.3
--- testsuite/g++.old-deja/g++.pt/crash41.C 9 Jul 2003 08:30:26 -0000
***************
*** 1,11 ****
! // { dg-do assemble }
// Origin: Mark Mitchell <mark@codesourcery.com>
template <int> struct S1{};
struct S2 { int i; };
template <class T>
void f(S2 s2) {
! S1<s2.i> s1;
}
--- 1,11 ----
! // { dg-do compile }
// Origin: Mark Mitchell <mark@codesourcery.com>
template <int> struct S1{};
struct S2 { int i; };
template <class T>
void f(S2 s2) {
! S1<s2.i> s1; // { dg-error "" }
}
Index: gcj/array.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/array.h,v
retrieving revision 1.13
diff -c -5 -p -r1.13 array.h
*** gcj/array.h 28 Dec 2002 06:38:52 -0000 1.13
--- gcj/array.h 9 Jul 2003 08:44:56 -0000
*************** typedef JArray<jdouble> *jdoubleArray;
*** 69,79 ****
typedef JArray<jstring> *jstringArray;
extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
_Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
_Jv_doubleClass, _Jv_voidClass;
! #define JvPrimClass(TYPE) (& _Jv_##TYPE##Class)
extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);
extern inline jobjectArray
--- 69,81 ----
typedef JArray<jstring> *jstringArray;
extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
_Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
_Jv_doubleClass, _Jv_voidClass;
! /* 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" jobject _Jv_NewPrimArray (jclass eltype, jint count);
extern inline jobjectArray