diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d5ee8c611e1..e5cf6bba078 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2003-07-08 Mark Mitchell + + * fold-const.c (make_range): Do not access operand 1 for a + zero-operand operator. + 2003-07-09 Neil Booth * toplev.c (warn_dummy, W_options): Die. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a4b9aea4535..8d83247f636 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,70 @@ +2003-07-08 Mark Mitchell + + * cp-tree.def (NON_DEPENDENT_EXPR): New node. + * cp-tree.h (build_call_from_tree): Remove. + (build_member_call): Likewise. + (dependent_template_arg_p): Remove. + (any_dependent_template_arguments_p): New function. + (dependent_template_id_p): Likewise. + (any_type_dependent_arguments_p): Likewise. + (build_non_dependent_expr): Likewise. + (build_non_dependent_args): Likewise. + (build_x_compound_expr): Adjust prototype. + * call.c (build_new_method_call): Handle non-dependent expressions + correctly. + * decl2.c (grok_array_decl): Likewise. + (build_offset_ref_call_from_tree): Likewise. + (build_call_from_tree): Remove. + * error.c (dump_decl): Handle NON_DEPENDENT_EXPR. + (dump_expr): Likewise. + * init.c (build_member_call): Remove. + * mangle.c (write_expression): Update handling for template-ids. + * parser.c (cp_parser_primary_expression): Use + any_dependent_template_arguments_p. Update constant-expression + handling. + (cp_parser_postfix_expression): Use + any_type_dependent_arguments_p. Simplify call processing. + (cp_parser_unary_expression): Simplify. + (cp_parser_expression): Adjust for changes to + build_x_compound_expr. + (cp_parser_template_argument): Implement standard-conforming + parsing of non-type template arguments. + (cp_parser_direct_declarator): Use + cp_parser_fold_non_dependent_expr. + (cp_parser_fold_non_dependent_expr): New function. + (cp_parser_next_token_ends_template_argument_p): Likewise. + * pt.c (convert_template_argument): Do not call + maybe_fold_nontype_arg. + (tsubst_baselink): Likewise. + (tsubst_copy_and_build): Share common code. Make sizeof/alignof + processing work correctly for non-dependent expressions. Adjust + handling of COMPOUND_EXPR. Simplify call processing. + (value_dependent_expression_p): Deal with functional casts and + sizeof/alignof correctly. + (type_dependent_expression_p): Handle overloaded functions. + (any_type_dependent_arguments_p): New function. + (any_dependent_template_arguments_p): Likewise. + (dependent_template_p): Treat SCOPE_REFs as dependent. + (dependent_template_id_p): Simplify. + (build_non_dependent_expr): New function. + (build_non_dependent_args): Likewise. + * semantics.c (finish_stmt_expr): Don't make dependent + statement-expresions have void type. + (finish_call_expr): Handle non-dependent expressions + correctly. + * tree.c (lvalue_p_1): Treat NON_DEPENDENT_EXPRs as lvalues. + * typeck.c (cxx_sizeof_or_alignof_type): Give the expression + type size_t, even in templates. + (expr_sizeof): Likewise. + (finish_class_member_access_expr): Handle non-dependent expressions + correctly. + (build_x_indirect_ref): Likewise. + (build_x_binary_op): Likewise. + (build_x_unary_op): Likewise. + (build_x_conditional_expr): Likewise. + (build_x_compound_expr): Likewise. + * typeck2.c (build_x_arrow): Likewise. + Wed Jul 9 02:28:39 CEST 2003 Jan Hubicka * cp-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): New. @@ -210,13 +277,13 @@ Wed Jul 9 02:28:39 CEST 2003 Jan Hubicka (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 + * 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. - (delete_sanity): Likewise. - (resolve_offset_ref): Simplify greatly. + * 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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index fbf5c06a32f..6659592b22d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -325,8 +325,7 @@ build_call (tree function, tree parms) 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. + information to get protected accesses correct. FLAGS is the logical disjunction of zero or more LOOKUP_ flags. See cp-tree.h for more info. @@ -4883,6 +4882,9 @@ build_new_method_call (tree instance, tree fns, tree args, tree class_type; int template_only = 0; bool any_viable_p; + tree orig_instance; + tree orig_fns; + tree orig_args; my_friendly_assert (instance != NULL_TREE, 20020729); @@ -4891,6 +4893,20 @@ build_new_method_call (tree instance, tree fns, tree args, || args == error_mark_node) 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); @@ -5068,6 +5084,13 @@ build_new_method_call (tree instance, tree fns, tree args, 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; } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index e988a4e25f9..f9819ec1cad 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -238,6 +238,16 @@ 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) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9d383cf24ae..58eabc3a396 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -215,6 +215,7 @@ struct diagnostic_context; #define abi_version_at_least(N) \ (flag_abi_version == 0 || flag_abi_version >= (N)) + /* Language-dependent contents of an identifier. */ @@ -3775,7 +3776,6 @@ 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); @@ -3853,7 +3853,6 @@ 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); @@ -3974,12 +3973,16 @@ 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 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); @@ -4267,7 +4270,7 @@ extern tree build_x_binary_op (enum tree_code, tree, tree); extern tree build_x_unary_op (enum tree_code, tree); extern tree 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_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); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 7a2399a6016..c77e5039fb9 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -398,59 +398,77 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags, tree quals) tree grok_array_decl (tree array_expr, tree index_exp) { - tree type = TREE_TYPE (array_expr); - tree p1, p2, i1, i2; + tree type; + tree expr; + tree orig_array_expr = array_expr; + tree orig_index_exp = index_exp; - if (type == error_mark_node || index_exp == error_mark_node) + if (error_operand_p (array_expr) || error_operand_p (index_exp)) return error_mark_node; + if (processing_template_decl) - return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE, - array_expr, index_exp); + { + if (type_dependent_expression_p (array_expr) + || type_dependent_expression_p (index_exp)) + return build_min_nt (ARRAY_REF, array_expr, index_exp); + array_expr = build_non_dependent_expr (array_expr); + index_exp = build_non_dependent_expr (index_exp); + } + type = TREE_TYPE (array_expr); my_friendly_assert (type, 20030626); - 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, + expr = 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; + 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 (array_expr == error_mark_node || index_exp == error_mark_node) - error ("ambiguous conversion for array subscript"); - - return 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 @@ -2949,8 +2967,37 @@ tree build_offset_ref_call_from_tree (tree fn, tree args) { tree object_addr; + tree orig_fn; + tree orig_args; + tree expr; - my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725); + orig_fn = fn; + orig_args = args; + + if (processing_template_decl) + { + tree object; + tree object_type; + + my_friendly_assert (TREE_CODE (fn) == DOTSTAR_EXPR + || TREE_CODE (fn) == MEMBER_REF, + 20030708); + if (type_dependent_expression_p (fn) + || any_type_dependent_arguments_p (args)) + return build_min_nt (CALL_EXPR, fn, args); + + /* Transform the arguments and add the implicit "this" + parameter. That must be done before the FN is transformed + because we depend on the form of FN. */ + args = build_non_dependent_args (args); + object_type = TREE_TYPE (TREE_OPERAND (fn, 0)); + if (TREE_CODE (fn) == DOTSTAR_EXPR) + object_type = build_pointer_type (non_reference (object_type)); + object = build (NON_DEPENDENT_EXPR, object_type); + args = tree_cons (NULL_TREE, object, args); + /* Now that the arguments are done, transform FN. */ + fn = build_non_dependent_expr (fn); + } /* A qualified name corresponding to a bound pointer-to-member is represented as an OFFSET_REF: @@ -2958,79 +3005,18 @@ build_offset_ref_call_from_tree (tree fn, tree args) 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 + 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); } - 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); + 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 diff --git a/gcc/cp/error.c b/gcc/cp/error.c index a9f5b15834a..79803d2dfff 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -988,6 +988,10 @@ dump_decl (tree t, int flags) 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. */ @@ -2028,7 +2032,11 @@ dump_expr (tree t, int flags) dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS); break; - /* else fall through */ + case NON_DEPENDENT_EXPR: + output_add_string (scratch_buffer, "'); + break; /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call diff --git a/gcc/cp/init.c b/gcc/cp/init.c index f89b4248e65..4a11b4319fa 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1337,157 +1337,6 @@ get_type_value (tree name) 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 diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 63c58baf059..29fd523c727 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2019,6 +2019,19 @@ write_expression (tree expr) 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 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 27e73cb967f..19f55f40a8e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1651,6 +1651,8 @@ 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 @@ -1661,6 +1663,8 @@ 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 @@ -2381,7 +2385,6 @@ cp_parser_primary_expression (cp_parser *parser, 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" @@ -2600,30 +2603,7 @@ cp_parser_primary_expression (cp_parser *parser, 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; - } - } - + dependent_p = any_dependent_template_arguments_p (args); /* The functions are those referred to by the template-id. */ fns = TREE_OPERAND (fns, 0); @@ -2687,27 +2667,34 @@ cp_parser_primary_expression (cp_parser *parser, /* Only certain kinds of names are allowed in constant expression. Enumerators have already been handled above. */ - if (parser->constant_expression_p + 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))) + 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 (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; + 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) @@ -3792,7 +3779,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) || TREE_CODE (postfix_expression) == IDENTIFIER_NODE) && args) { - tree arg; tree identifier = NULL_TREE; tree functions = NULL_TREE; @@ -3815,10 +3801,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) Do Koenig lookup -- unless any of the arguments are type-dependent. */ - for (arg = args; arg; arg = TREE_CHAIN (arg)) - if (type_dependent_expression_p (TREE_VALUE (arg))) - break; - if (!arg) + if (!any_type_dependent_arguments_p (args)) { postfix_expression = lookup_arg_dependent (identifier, functions, args); @@ -3827,14 +3810,12 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) /* The unqualified name could not be resolved. */ unqualified_name_lookup_error (identifier); postfix_expression = error_mark_node; + break; } - postfix_expression - = build_call_from_tree (postfix_expression, args, - /*diallow_virtual=*/false); - break; } - postfix_expression = build_min_nt (LOOKUP_EXPR, - identifier); + else + postfix_expression = build_min_nt (LOOKUP_EXPR, + identifier); } else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED && TREE_CODE (postfix_expression) == IDENTIFIER_NODE) @@ -3845,25 +3826,31 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) 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) + { + 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) @@ -3967,8 +3954,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) struct X { void f(); }; template 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 + 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 @@ -4336,7 +4323,8 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p) return build_x_indirect_ref (cast_expression, "unary *"); case ADDR_EXPR: - return build_x_unary_op (ADDR_EXPR, cast_expression); + case BIT_NOT_EXPR: + return build_x_unary_op (unary_operator, cast_expression); case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: @@ -4354,9 +4342,6 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p) 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; @@ -5293,7 +5278,6 @@ static tree cp_parser_expression (cp_parser* parser) { tree expression = NULL_TREE; - bool saw_comma_p = false; while (true) { @@ -5306,45 +5290,23 @@ cp_parser_expression (cp_parser* parser) 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); + 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); - /* 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"); + expression + = cp_parser_non_constant_expression ("a comma operator"); parser->non_constant_expression_p = true; } - expression = build_x_compound_expr (nreverse (expression)); } return expression; @@ -5356,8 +5318,9 @@ cp_parser_expression (cp_parser* parser) 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. */ + 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, @@ -5547,7 +5510,7 @@ cp_parser_labeled_statement (cp_parser* parser) cp_lexer_consume_token (parser->lexer); /* Parse the constant-expression. */ expr = cp_parser_constant_expression (parser, - /*allow_non_constant=*/false, + /*allow_non_constant_p=*/false, NULL); /* Create the label. */ statement = finish_case_label (expr, NULL_TREE); @@ -8051,13 +8014,21 @@ cp_parser_template_argument_list (cp_parser* parser) The representation is that of an assignment-expression, type-id, or id-expression -- except that the qualified id-expression is evaluated, so that the value returned is either a DECL or an - OVERLOAD. */ + OVERLOAD. + + Although the standard says "assignment-expression", it forbids + throw-expressions or assignments in the template argument. + Therefore, we use "conditional-expression" instead. */ static tree 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. @@ -8073,8 +8044,7 @@ cp_parser_template_argument (cp_parser* 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)) + 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)) @@ -8088,8 +8058,7 @@ cp_parser_template_argument (cp_parser* parser) &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)) + if (!cp_parser_next_token_ends_template_argument_p (parser)) cp_parser_error (parser, "expected template-argument"); if (!cp_parser_error_occurred (parser)) { @@ -8104,8 +8073,101 @@ cp_parser_template_argument (cp_parser* parser) } if (cp_parser_parse_definitely (parser)) return argument; - /* It must be an assignment-expression. */ - return cp_parser_assignment_expression (parser); + /* 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. @@ -8914,7 +8976,7 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type) cp_lexer_consume_token (parser->lexer); /* Parse the value. */ value = cp_parser_constant_expression (parser, - /*allow_non_constant=*/false, + /*allow_non_constant_p=*/false, NULL); } else @@ -9919,29 +9981,8 @@ cp_parser_direct_declarator (cp_parser* parser, = 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 void f(T[1 + 1]); - template 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; - } + if (!non_constant_p) + bounds = cp_parser_fold_non_dependent_expr (bounds); } else bounds = NULL_TREE; @@ -14129,6 +14170,36 @@ cp_parser_declares_only_class_p (cp_parser *parser) || cp_lexer_next_token_is (parser->lexer, CPP_COMMA)); } +/* 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 void f(T[1 + 1]); + template 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. */ @@ -14274,6 +14345,18 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser) return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON); } +/* 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. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index abb51b25b7d..4d650c5e23d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -167,7 +167,6 @@ static void copy_default_args_to_explicit_spec (tree); static int invalid_nontype_parm_type_p (tree, tsubst_flags_t); static int 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); @@ -3594,9 +3593,6 @@ convert_template_argument (tree parm, 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 @@ -7108,9 +7104,8 @@ tsubst_baselink (tree baselink, tree object_type, 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); + 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); @@ -8003,30 +7998,17 @@ tsubst_copy_and_build (tree t, 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 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); @@ -8037,18 +8019,6 @@ tsubst_copy_and_build (tree t, 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: @@ -8119,15 +8089,25 @@ tsubst_copy_and_build (tree t, 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); - } + 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 @@ -8162,15 +8142,11 @@ tsubst_copy_and_build (tree 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 (); - } + 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: { @@ -8210,25 +8186,23 @@ tsubst_copy_and_build (tree t, 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); + qualified_p = 1; - 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); - } + 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: @@ -8389,6 +8363,11 @@ tsubst_copy_and_build (tree t, 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: @@ -11491,26 +11470,46 @@ value_dependent_expression_p (tree expression) with an expression that is value-dependent. */ if (TREE_CODE (expression) == VAR_DECL && DECL_INITIAL (expression) - && INTEGRAL_OR_ENUMERATION_TYPE_P (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) - && (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; + 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)))) @@ -11574,10 +11573,11 @@ type_dependent_expression_p (tree expression) || 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) + 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 @@ -11601,12 +11601,53 @@ type_dependent_expression_p (tree 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. */ -bool +static bool dependent_template_arg_p (tree arg) { if (!processing_template_decl) @@ -11622,18 +11663,36 @@ dependent_template_arg_p (tree arg) || value_dependent_expression_p (arg)); } -/* Returns TRUE if the specialization TMPL is dependent. */ +/* Returns true if ARGS (a collection of template arguments) contains + any dependent arguments. */ -static bool -dependent_template_id_p (tree tmpl, tree args) +bool +any_dependent_template_arguments_p (tree args) { - int i; + if (!args) + return false; + + my_friendly_assert (TREE_CODE (args) == TREE_LIST + || TREE_CODE (args) == TREE_VEC, + 20030707); + + if (TREE_CODE (args) == TREE_LIST) + { + while (args) + { + if (dependent_template_arg_p (TREE_VALUE (args))) + return true; + args = TREE_CHAIN (args); + } + } + else + { + int i; + for (i = 0; i < TREE_VEC_LENGTH (args); ++i) + if (dependent_template_arg_p (TREE_VEC_ELT (args, i))) + return true; + } - if (dependent_template_p (tmpl)) - return true; - for (i = 0; i < TREE_VEC_LENGTH (args); ++i) - if (dependent_template_arg_p (TREE_VEC_ELT (args, i))) - return true; return false; } @@ -11646,12 +11705,24 @@ dependent_template_p (tree tmpl) 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 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 @@ -11730,4 +11801,54 @@ resolve_typename_type (tree type, bool only_current_p) 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 void f() { 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" 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" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index cc1e2ea3e9c..db9e4d2791b 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1449,8 +1449,12 @@ 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) + 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; @@ -1482,16 +1486,32 @@ finish_stmt_expr (tree rtl_expr) 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; - 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); + 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. */ @@ -1512,6 +1532,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) } } + result = NULL_TREE; if (BASELINK_P (fn)) { tree object; @@ -1551,17 +1572,22 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) object = build_dummy_object (DECL_CONTEXT (representative_fn)); } - return build_new_method_call (object, fn, args, NULL_TREE, - (disallow_virtual - ? LOOKUP_NONVIRTUAL : 0)); + 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. */ - return build_new_function_call (fn, args); + result = 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 @@ -1570,20 +1596,18 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) 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; - } + /* 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); - /* A call where the function is unknown. */ - return 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 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 975c396c2be..366ea3ab01a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -174,6 +174,14 @@ lvalue_p_1 (tree ref, 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; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e6abb3df57f..6d499d6c35f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1417,7 +1417,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, int complain) my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720); if (processing_template_decl) - return build_min_nt (op, type); + return build_min (op, size_type_node, type); op_name = operator_name_info[(int) op].name; @@ -1446,7 +1446,7 @@ tree expr_sizeof (tree e) { if (processing_template_decl) - return build_min_nt (SIZEOF_EXPR, e); + return build_min (SIZEOF_EXPR, size_type_node, e); if (TREE_CODE (e) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1))) @@ -2015,17 +2015,36 @@ lookup_destructor (tree object, tree scope, tree dtor_name) 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; - if (processing_template_decl) - return build_min_nt (COMPONENT_REF, object, name); - 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", 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); @@ -2057,6 +2076,7 @@ finish_class_member_access_expr (tree object, tree name) { bool is_template_id = false; tree template_args = NULL_TREE; + tree scope; if (TREE_CODE (name) == TEMPLATE_ID_EXPR) { @@ -2067,8 +2087,6 @@ finish_class_member_access_expr (tree object, tree name) if (TREE_CODE (name) == SCOPE_REF) { - 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 @@ -2095,57 +2113,35 @@ finish_class_member_access_expr (tree object, tree name) 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) + else { - /* An unqualified name. */ - member = lookup_member (object_type, name, /*protect=*/1, + 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; } - else if (member == error_mark_node) + 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); + template = lookup_template_function (template, template_args); else { error ("`%D' is not a member template function", name); @@ -2157,8 +2153,12 @@ finish_class_member_access_expr (tree object, tree name) if (TREE_DEPRECATED (member)) warn_deprecated_use (member); - return build_class_member_access_expr (object, member, access_path, + expr = build_class_member_access_expr (object, member, access_path, /*preserve_reference=*/false); + 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 @@ -2196,18 +2196,27 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name) Must also handle REFERENCE_TYPEs for C++. */ tree -build_x_indirect_ref (tree ptr, const char *errorstring) +build_x_indirect_ref (tree expr, const char *errorstring) { + tree orig_expr = expr; tree rval; if (processing_template_decl) - return build_min_nt (INDIRECT_REF, ptr); + { + if (type_dependent_expression_p (expr)) + return build_min_nt (INDIRECT_REF, expr); + expr = build_non_dependent_expr (expr); + } - rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, + rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE, NULL_TREE); - if (rval) + if (!rval) + rval = build_indirect_ref (expr, errorstring); + + if (processing_template_decl && rval != error_mark_node) + return build_min (INDIRECT_REF, TREE_TYPE (rval), orig_expr); + else return rval; - return build_indirect_ref (ptr, errorstring); } tree @@ -2826,192 +2835,33 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags) 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) - return build_min_nt (code, arg1, arg2); + { + 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) - 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; + expr = build_m_component_ref (arg1, arg2); else - { - struct z_candidate *cand; - tree op0_type; - tree op1_type; - tree op2_type; + expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE); - /* 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 - void f() { S 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 - void f(S); - - 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; - } - } + if (processing_template_decl && expr != error_mark_node) + return build_min (code, TREE_TYPE (expr), orig_arg1, orig_arg2); - return build_min (code, type, op0, op1, op2, NULL_TREE); + return expr; } -#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: @@ -3839,11 +3689,18 @@ pointer_diff (register tree op0, register tree op1, register tree ptrtype) tree build_x_unary_op (enum tree_code code, tree xarg) { + tree orig_expr = xarg; tree exp; int ptrmem = 0; if (processing_template_decl) - return build_min_nt (code, xarg, NULL_TREE); + { + if (type_dependent_expression_p (xarg)) + return build_min_nt (code, xarg, NULL_TREE); + xarg = build_non_dependent_expr (xarg); + } + + exp = NULL_TREE; /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an error message. */ @@ -3854,15 +3711,8 @@ build_x_unary_op (enum tree_code code, tree 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) + 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. */ @@ -3896,16 +3746,17 @@ build_x_unary_op (enum tree_code code, tree 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; } - exp = build_unary_op (code, xarg, 0); - if (TREE_CODE (exp) == ADDR_EXPR) - PTRMEM_OK_P (exp) = ptrmem; + if (processing_template_decl && exp != error_mark_node) + return build_min (code, TREE_TYPE (exp), orig_expr); return exp; } @@ -4631,53 +4482,76 @@ cxx_mark_addressable (tree exp) tree build_x_conditional_expr (tree ifexp, tree op1, tree op2) { - if (processing_template_decl) - return build_min_nt (COND_EXPR, ifexp, op1, op2); + tree orig_ifexp = ifexp; + tree orig_op1 = op1; + tree orig_op2 = op2; + tree expr; - return build_conditional_expr (ifexp, op1, op2); + if (processing_template_decl) + { + /* The standard says that the expression is type-dependent if + IFEXP is type-dependent, even though the eventual type of the + expression doesn't dependent on IFEXP. */ + if (type_dependent_expression_p (ifexp) + || type_dependent_expression_p (op1) + || type_dependent_expression_p (op2)) + return build_min_nt (COND_EXPR, ifexp, op1, op2); + ifexp = build_non_dependent_expr (ifexp); + op1 = build_non_dependent_expr (op1); + op2 = build_non_dependent_expr (op2); + } + + expr = build_conditional_expr (ifexp, op1, op2); + if (processing_template_decl && expr != error_mark_node) + return build_min (COND_EXPR, TREE_TYPE (expr), + orig_ifexp, orig_op1, orig_op2); + return expr; } /* Handle overloading of the ',' operator when needed. Otherwise, this function just builds an expression list. */ tree -build_x_compound_expr (tree list) +build_x_compound_expr (tree op1, tree op2) { - tree rest = TREE_CHAIN (list); tree result; + tree orig_op1 = op1; + tree orig_op2 = op2; 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 (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); } -#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)))); + 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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index edb9f5d5b21..6a14fecb4a9 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -980,44 +980,48 @@ build_scoped_ref (tree datum, tree basetype, tree* binfo_p) delegation is detected. */ tree -build_x_arrow (tree datum) +build_x_arrow (tree expr) { + tree orig_expr = expr; tree types_memoized = NULL_TREE; - register tree rval = datum; - tree type = TREE_TYPE (rval); + tree type = TREE_TYPE (expr); 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 (type_dependent_expression_p (expr)) + return build_min_nt (ARROW_EXPR, expr); + expr = build_non_dependent_expr (expr); + } if (TREE_CODE (type) == REFERENCE_TYPE) { - rval = convert_from_reference (rval); - type = TREE_TYPE (rval); + expr = convert_from_reference (expr); + type = TREE_TYPE (expr); } if (IS_AGGR_TYPE (type)) { - while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval, + while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr, NULL_TREE, NULL_TREE))) { - if (rval == error_mark_node) + if (expr == error_mark_node) return error_mark_node; - if (value_member (TREE_TYPE (rval), types_memoized)) + if (value_member (TREE_TYPE (expr), types_memoized)) { error ("circular pointer delegation detected"); return error_mark_node; } else { - types_memoized = tree_cons (NULL_TREE, TREE_TYPE (rval), + types_memoized = tree_cons (NULL_TREE, TREE_TYPE (expr), types_memoized); } - last_rval = rval; + last_rval = expr; } if (last_rval == NULL_TREE) @@ -1030,10 +1034,17 @@ build_x_arrow (tree datum) last_rval = convert_from_reference (last_rval); } else - last_rval = decay_conversion (rval); + last_rval = decay_conversion (expr); if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE) - return build_indirect_ref (last_rval, NULL); + { + if (processing_template_decl) + return build_min (ARROW_EXPR, + TREE_TYPE (TREE_TYPE (last_rval)), + orig_expr); + + return build_indirect_ref (last_rval, NULL); + } if (types_memoized) error ("result of `operator->()' yields non-pointer result"); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index e4f57b8cfa3..e268055cb8e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2908,7 +2908,8 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh) if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) { - arg0 = TREE_OPERAND (exp, 0); + if (first_rtl_op (code) > 0) + arg0 = TREE_OPERAND (exp, 0); if (TREE_CODE_CLASS (code) == '<' || TREE_CODE_CLASS (code) == '1' || TREE_CODE_CLASS (code) == '2') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9ee1e57f751..859e8a5059a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2003-07-08 Mark Mitchell + + * g++.dg/abi/mangle17.C: Make sure template expressions are + dependent. + * g++.dg/abi/mangle4.C: Mark erroneous casts. + * g++.dg/debug/debug7.C: Mark erronous new-declarator. + * g++.dg/opt/stack1.C: Remove erroneous code. + * g++.dg/parse/template7.C: New test. + * g++.dg/template/dependent-expr1.C: Mark erroneous code. + * g++.old-deja/g++.pt/crash4.C: Likewise. + 2003-07-09 John David Anglin * gcc.dg/const-elim-1.c (dg-final): Change regexp to match labels diff --git a/gcc/testsuite/g++.dg/abi/mangle17.C b/gcc/testsuite/g++.dg/abi/mangle17.C index 1da6dea632b..6f8e387e1d7 100644 --- a/gcc/testsuite/g++.dg/abi/mangle17.C +++ b/gcc/testsuite/g++.dg/abi/mangle17.C @@ -4,8 +4,8 @@ enum E { e = 3 }; template struct S {}; -template void f (S) {} -template void f<7>(S); // { dg-warning "mangle" } +template void f (S) {} +template void f<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" } -template void g (S) {} -template void g<7>(S); // { dg-warning "mangle" } +template void g (S) {} +template void g<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" } diff --git a/gcc/testsuite/g++.dg/abi/mangle4.C b/gcc/testsuite/g++.dg/abi/mangle4.C index ec65654e8e2..d4b5936825c 100644 --- a/gcc/testsuite/g++.dg/abi/mangle4.C +++ b/gcc/testsuite/g++.dg/abi/mangle4.C @@ -8,19 +8,17 @@ template class C {}; template class D {}; template class E {}; -template void f(D &, C(b)> &) {} -template void g(D &, E(b)> &) {} +template void f(D &, C(b)> &) {} // { dg-error "" } +template void g(D &, E(b)> &) {} // { dg-error "" } B b; int main() { - C(&b)> c; + C(&b)> c; // { dg-error "" } D<&b> d; - E(&b)> e; - f(d, c); - g(d, e); + E(&b)> e; // { dg-error "" } + f(d, c); // { dg-error "" } + g(d, e); // { dg-error "" } } -// { dg-final { scan-assembler "\n_?_Z1fIXadL_Z1bEEEvR1DIXT_EER1CIXcvPK1AT_EE\[: \t\n\]" } } -// { dg-final { scan-assembler "\n_?_Z1gIXadL_Z1bEEEvR1DIXT_EER1EIXcvP1BT_EE\[: \t\n\]" } } diff --git a/gcc/testsuite/g++.dg/debug/debug7.C b/gcc/testsuite/g++.dg/debug/debug7.C index 78faa20ff03..31d47eda78f 100644 --- a/gcc/testsuite/g++.dg/debug/debug7.C +++ b/gcc/testsuite/g++.dg/debug/debug7.C @@ -7,7 +7,7 @@ main() { int a = 4; int b = 5; - int (*x)[b] = new int[a][b]; + int (*x)[b] = new int[a][b]; // { dg-error "" } x[2][1] = 7; diff --git a/gcc/testsuite/g++.dg/opt/stack1.C b/gcc/testsuite/g++.dg/opt/stack1.C index bb6159c568e..7fac18dac03 100644 --- a/gcc/testsuite/g++.dg/opt/stack1.C +++ b/gcc/testsuite/g++.dg/opt/stack1.C @@ -68,7 +68,7 @@ template struct adaptor { adaptor (matrix<> &m) : m(&m), upper_ (1) {} - int size1 () const { return m->size1 (); } + int size1 () const; int size2 () const { return 3; } int lower () const { return 1; } int upper () const { return upper_; } diff --git a/gcc/testsuite/g++.dg/parse/template7.C b/gcc/testsuite/g++.dg/parse/template7.C new file mode 100644 index 00000000000..b13e3eccde4 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/template7.C @@ -0,0 +1,4 @@ +template +void f(); + +void g() { f<(3, 2)>(); } // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/template/dependent-expr1.C b/gcc/testsuite/g++.dg/template/dependent-expr1.C index 079f033611b..e29b76d42d0 100644 --- a/gcc/testsuite/g++.dg/template/dependent-expr1.C +++ b/gcc/testsuite/g++.dg/template/dependent-expr1.C @@ -21,9 +21,9 @@ namespace std Foo (__alignof__ (x)); Foo (x->~I ()); // Foo (typeid (I)); - Foo (delete x); - Foo (delete[] x); - Foo (throw x); + Foo (delete x); // { dg-error "" } + Foo (delete[] x); // { dg-error "" } + Foo (throw x); // { dg-error "" } } } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash41.C b/gcc/testsuite/g++.old-deja/g++.pt/crash41.C index a3d8088a2cd..fc7f7b51497 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/crash41.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash41.C @@ -1,4 +1,4 @@ -// { dg-do assemble } +// { dg-do compile } // Origin: Mark Mitchell template struct S1{}; @@ -7,5 +7,5 @@ struct S2 { int i; }; template void f(S2 s2) { - S1 s1; + S1 s1; // { dg-error "" } } diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 351b77f74f0..f1cdea21ff8 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,7 @@ +2003-07-09 Mark Mitchell + + * gcj/array.h (JvPrimClass): Don't parenthesize the output. + 2003-07-09 Michael Koch * gnu/java/awt/peer/gtk/GtkComponentPeer.java, diff --git a/libjava/gcj/array.h b/libjava/gcj/array.h index 33ea038df93..4f134f33c5c 100644 --- a/libjava/gcj/array.h +++ b/libjava/gcj/array.h @@ -71,7 +71,9 @@ typedef JArray *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) +/* 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);