diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-01-30 07:24:02 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-01-30 07:24:02 +0000 |
commit | 5f6526e1c1d8af5b373ddab9ed2a6ef200914ad6 (patch) | |
tree | 9b52cc234bf9b52b7127dba18c43be2715c995b2 /gcc/cp | |
parent | 0924aa1d55504c9c44ee33530ff04805640c758c (diff) | |
download | gcc-5f6526e1c1d8af5b373ddab9ed2a6ef200914ad6.tar.gz |
* c-common.c (builtin_define_float_constants): Define
__<TYPE>_HAS_INFINITY__ and __<TYPE>_HAS_QUIET_NAN__.
* call.c (build_field_call): Use build_new_op, not build_opfncall.
(prep_operand): New function.
(build_new_op): Use it. Remove dead code.
* class.c (pushclass): Change "modify" parameter type from int to
bool.
(currently_open_class): Use same_type_p, not pointer equality.
(push_nested_class): Adjust calls to pushclass, remove modify
parameter.
* cp-tree.h (INTEGRAL_OR_ENUMERATION_TYPE_P): New macro.
(pushclass): Change prototype.
(push_nested_class): Likewise.
(grokoptypename): Remove.
(build_opfncall): Remove.
(value_dependent_expression_p): Declare.
(resolve_typename_type): Likewise.
(resolve_typename_type_in_current_instantiation): Likewise.
(enter_scope_of): Remove.
(tsubst): Remove.
(tsubst_expr): Likewise.
(tsubst_copy): Likewise.
(tsubst_copy_and_build): Likewise.
* decl.c (warn_about_implicit_typename_lookup): Remove.
(finish_case_label): Return error_mark_node for erroneous labels.
(start_decl): Adjust calls to push_nested_class.
(grokfndecl): Call push_scope/pop_scope around call to
duplicate_decls.
(grokdeclarator): Do not call tsubst.
(start_function): Adjust calls to push_nested_class.
* decl2.c (grok_array_decl): Use build_new_op, not build_opfncall.
(check_classfn): Use push_scope/pop_scope around type comparisions.
(grokoptypename): Remove.
(push_sscope): Adjust call to push_nested_class.
* error.c (dump_type): Show cv-qualification of typename types.
* init.c (build_member_call): Use build_new_op, not
build_opfncall.
* method.c (build_opfncall): Remove.
* parser.c (cp_parser): Add allow_non_constant_expression_p and
non_constant_expression_p.
(cp_parser_constant_expression): Adjust prototype.
(cp_parser_resolve_typename_type): Remove.
(cp_parser_non_constant_expression): New function.
(cp_parser_non_constant_id_expression): Likewise.
(cp_parser_new): Set allow_non_constant_expression_p and
non_constant_expression_p.
(cp_parser_primary_expression): Reject `this' and `va_arg' in
constant-expressions. Note that dependent names aren't really
constant.
(cp_parser_postfix_expression): Reject conversions to non-integral
types in constant-expressions. Neither are increments or
decrements.
(cp_parser_unary_expression): Reject increments and decrements in
constant-expressions.
(cp_parser_direct_new_declarator): Adjust call to
cp_parser_constant_expression.
(cp_parser_cast_expression): Reject conversions to non-integral
types in constant-expressions.
(cp_parser_assignment_expression): Rejects assignments in
constant-expressions.
(cp_parser_expression): Reject commas in constant-expressions.
(cp_parser_labeled_statement): Adjust call to
cp_parser_constant_expression.
(cp_parser_direct_declarator): Simplify array bounds, even in
templates, when they are non-dependent. Use
resolve_typename_type, not cp_parser_resolve_typename_type.
(cp_parser_class_head): Use resolve_typename_type, not
cp_parser_resolve_typename_type.
(cp_parser_member_declaration): Adjust call to
cp_parser_constant_expression.
(cp_parser_constant_initializer): Likewise.
(cp_parser_constructor_declarator): Use resolve_typename_type, not
cp_parser_resolve_typename_type.
(cp_parser_late_parsing_default_args): Adjust call to
push_nested_class.
* pt.c (tsubst): Give it internal linkage.
(tsubst_expr): Likewise.
(tsubst_copy): Likewise.
(tsubst_copy_and_build): Likewise.
(push_access_scope_real): Likewise.
(tsubst_friend_class): Likewise.
(instantiate_class_template): Adjust call to pushclass.
(value_dependent_expression_p): Give it external linkage.
Robustify.
(resolve_typename_type): New function.
* semantics.c (finish_call_expr): Use build_new_op, not
build_opfncall.
(begin_constructor_declarator): Remove.
(begin_class_definition): Adjust call to pushclass.
(enter_scope_of): Remove.
* typeck.c (comptypes): Resolve typename types as appropriate.
(build_x_indirect_ref): Use build_new_op, not build_opfncall.
(build_x_compound_expr): Likewise.
(build_modify_expr): Likewise.
(build_x_modify_expr): Likewise.
* typeck2.c (build_x_arrow): Likewise.
* g++.dg/parser/constant1.C: New test.
* include/std/std_limits.h (numeric_limits<float>::has_infinity):
Use __FLT_HAS_INIFINITY__ to initialize.
(numeric_limits<float>::has_quiet_NaN): Likewise.
(numeric_limits<double>::has_infinity): Use __DBL_HAS_INIFINITY__
to initialize.
(numeric_limits<double>::has_quiet_NaN): Likewise.
(numeric_limits<long double>::has_infinity): Use
__LDBL_HAS_INIFINITY__ to initialize.
(numeric_limits<long_double>::has_quiet_NaN): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@62130 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 97 | ||||
-rw-r--r-- | gcc/cp/call.c | 63 | ||||
-rw-r--r-- | gcc/cp/class.c | 22 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 19 | ||||
-rw-r--r-- | gcc/cp/decl.c | 64 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 36 | ||||
-rw-r--r-- | gcc/cp/error.c | 1 | ||||
-rw-r--r-- | gcc/cp/init.c | 4 | ||||
-rw-r--r-- | gcc/cp/method.c | 30 | ||||
-rw-r--r-- | gcc/cp/parser.c | 380 | ||||
-rw-r--r-- | gcc/cp/pt.c | 123 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 45 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 200 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 4 |
14 files changed, 742 insertions, 346 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 64adf911c0a..1b00808fa83 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,100 @@ +2003-01-29 Mark Mitchell <mark@codesourcery.com> + + * call.c (build_field_call): Use build_new_op, not build_opfncall. + (prep_operand): New function. + (build_new_op): Use it. Remove dead code. + * class.c (pushclass): Change "modify" parameter type from int to + bool. + (currently_open_class): Use same_type_p, not pointer equality. + (push_nested_class): Adjust calls to pushclass, remove modify + parameter. + * cp-tree.h (INTEGRAL_OR_ENUMERATION_TYPE_P): New macro. + (pushclass): Change prototype. + (push_nested_class): Likewise. + (grokoptypename): Remove. + (build_opfncall): Remove. + (value_dependent_expression_p): Declare. + (resolve_typename_type): Likewise. + (resolve_typename_type_in_current_instantiation): Likewise. + (enter_scope_of): Remove. + (tsubst): Remove. + (tsubst_expr): Likewise. + (tsubst_copy): Likewise. + (tsubst_copy_and_build): Likewise. + * decl.c (warn_about_implicit_typename_lookup): Remove. + (finish_case_label): Return error_mark_node for erroneous labels. + (start_decl): Adjust calls to push_nested_class. + (grokfndecl): Call push_scope/pop_scope around call to + duplicate_decls. + (grokdeclarator): Do not call tsubst. + (start_function): Adjust calls to push_nested_class. + * decl2.c (grok_array_decl): Use build_new_op, not build_opfncall. + (check_classfn): Use push_scope/pop_scope around type comparisions. + (grokoptypename): Remove. + (push_sscope): Adjust call to push_nested_class. + * error.c (dump_type): Show cv-qualification of typename types. + * init.c (build_member_call): Use build_new_op, not + build_opfncall. + * method.c (build_opfncall): Remove. + * parser.c (cp_parser): Add allow_non_constant_expression_p and + non_constant_expression_p. + (cp_parser_constant_expression): Adjust prototype. + (cp_parser_resolve_typename_type): Remove. + (cp_parser_non_constant_expression): New function. + (cp_parser_non_constant_id_expression): Likewise. + (cp_parser_new): Set allow_non_constant_expression_p and + non_constant_expression_p. + (cp_parser_primary_expression): Reject `this' and `va_arg' in + constant-expressions. Note that dependent names aren't really + constant. + (cp_parser_postfix_expression): Reject conversions to non-integral + types in constant-expressions. Neither are increments or + decrements. + (cp_parser_unary_expression): Reject increments and decrements in + constant-expressions. + (cp_parser_direct_new_declarator): Adjust call to + cp_parser_constant_expression. + (cp_parser_cast_expression): Reject conversions to non-integral + types in constant-expressions. + (cp_parser_assignment_expression): Rejects assignments in + constant-expressions. + (cp_parser_expression): Reject commas in constant-expressions. + (cp_parser_labeled_statement): Adjust call to + cp_parser_constant_expression. + (cp_parser_direct_declarator): Simplify array bounds, even in + templates, when they are non-dependent. Use + resolve_typename_type, not cp_parser_resolve_typename_type. + (cp_parser_class_head): Use resolve_typename_type, not + cp_parser_resolve_typename_type. + (cp_parser_member_declaration): Adjust call to + cp_parser_constant_expression. + (cp_parser_constant_initializer): Likewise. + (cp_parser_constructor_declarator): Use resolve_typename_type, not + cp_parser_resolve_typename_type. + (cp_parser_late_parsing_default_args): Adjust call to + push_nested_class. + * pt.c (tsubst): Give it internal linkage. + (tsubst_expr): Likewise. + (tsubst_copy): Likewise. + (tsubst_copy_and_build): Likewise. + (push_access_scope_real): Likewise. + (tsubst_friend_class): Likewise. + (instantiate_class_template): Adjust call to pushclass. + (value_dependent_expression_p): Give it external linkage. + Robustify. + (resolve_typename_type): New function. + * semantics.c (finish_call_expr): Use build_new_op, not + build_opfncall. + (begin_constructor_declarator): Remove. + (begin_class_definition): Adjust call to pushclass. + (enter_scope_of): Remove. + * typeck.c (comptypes): Resolve typename types as appropriate. + (build_x_indirect_ref): Use build_new_op, not build_opfncall. + (build_x_compound_expr): Likewise. + (build_modify_expr): Likewise. + (build_x_modify_expr): Likewise. + * typeck2.c (build_x_arrow): Likewise. + 2003-01-29 Fariborz Jahanian <fjahanian@apple.com> * pt.c (last_pending_template) Declare GTY(). diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cb0d351069a..440d58a0a22 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -103,6 +103,7 @@ static bool promoted_arithmetic_type_p (tree); static tree conditional_conversion (tree, tree); static char *name_as_c_string (tree, tree, bool *); static tree call_builtin_trap (void); +static tree prep_operand (tree); tree build_vfield_ref (tree datum, tree type) @@ -145,8 +146,8 @@ build_field_call (tree instance_ptr, tree decl, tree parms) return error_mark_node; if (IS_AGGR_TYPE (TREE_TYPE (instance))) - return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, - instance, parms, NULL_TREE); + return build_new_op (CALL_EXPR, LOOKUP_NORMAL, + instance, parms, NULL_TREE); else if (TREE_CODE (TREE_TYPE (instance)) == FUNCTION_TYPE || (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) @@ -3295,6 +3296,27 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3) return result; } +/* OPERAND is an operand to an expression. Perform necessary steps + required before using it. If OPERAND is NULL_TREE, NULL_TREE is + returned. */ + +static tree +prep_operand (tree operand) +{ + if (operand) + { + if (TREE_CODE (operand) == OFFSET_REF) + operand = resolve_offset_ref (operand); + operand = convert_from_reference (operand); + if (CLASS_TYPE_P (TREE_TYPE (operand)) + && CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (operand))) + /* Make sure the template type is instantiated now. */ + instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (operand))); + } + + return operand; +} + tree build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3) { @@ -3310,14 +3332,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3) || error_operand_p (arg3)) return error_mark_node; - /* This can happen if a template takes all non-type parameters, e.g. - undeclared_template<1, 5, 72>a; */ - if (code == LT_EXPR && TREE_CODE (arg1) == TEMPLATE_DECL) - { - error ("`%D' must be declared before use", arg1); - return error_mark_node; - } - if (code == MODIFY_EXPR) { code2 = TREE_CODE (arg3); @@ -3327,13 +3341,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3) else fnname = ansi_opname (code); - if (TREE_CODE (arg1) == OFFSET_REF) - arg1 = resolve_offset_ref (arg1); - arg1 = convert_from_reference (arg1); - if (CLASS_TYPE_P (TREE_TYPE (arg1)) - && CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg1))) - /* Make sure the template type is instantiated now. */ - instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg1))); + arg1 = prep_operand (arg1); switch (code) { @@ -3351,24 +3359,8 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3) break; } - if (arg2) - { - if (TREE_CODE (arg2) == OFFSET_REF) - arg2 = resolve_offset_ref (arg2); - arg2 = convert_from_reference (arg2); - if (CLASS_TYPE_P (TREE_TYPE (arg2)) - && CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg2))) - instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg2))); - } - if (arg3) - { - if (TREE_CODE (arg3) == OFFSET_REF) - arg3 = resolve_offset_ref (arg3); - arg3 = convert_from_reference (arg3); - if (CLASS_TYPE_P (TREE_TYPE (arg3)) - && CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg3))) - instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg3))); - } + arg2 = prep_operand (arg2); + arg3 = prep_operand (arg3); if (code == COND_EXPR) { @@ -3553,7 +3545,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3) if (TREE_CODE (cand->fn) == FUNCTION_DECL) { - extern int warn_synth; if (warn_synth && fnname == ansi_assopname (NOP_EXPR) && DECL_ARTIFICIAL (cand->fn) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6cdcb9a5b78..378c637a60d 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5758,7 +5758,7 @@ init_class_processing (void) that name becomes `error_mark_node'. */ void -pushclass (tree type, int modify) +pushclass (tree type, bool modify) { type = TYPE_MAIN_VARIANT (type); @@ -5880,10 +5880,11 @@ int currently_open_class (tree t) { int i; - if (t == current_class_type) + if (current_class_type && same_type_p (t, current_class_type)) return 1; for (i = 1; i < current_class_depth; ++i) - if (current_class_stack [i].type == t) + if (current_class_stack[i].type + && same_type_p (current_class_stack [i].type, t)) return 1; return 0; } @@ -5912,14 +5913,13 @@ currently_open_derived_class (tree t) } /* When entering a class scope, all enclosing class scopes' names with - static meaning (static variables, static functions, types and enumerators) - have to be visible. This recursive function calls pushclass for all - enclosing class contexts until global or a local scope is reached. - TYPE is the enclosed class and MODIFY is equivalent with the pushclass - formal of the same name. */ + static meaning (static variables, static functions, types and + enumerators) have to be visible. This recursive function calls + pushclass for all enclosing class contexts until global or a local + scope is reached. TYPE is the enclosed class. */ void -push_nested_class (tree type, int modify) +push_nested_class (tree type) { tree context; @@ -5935,8 +5935,8 @@ push_nested_class (tree type, int modify) context = DECL_CONTEXT (TYPE_MAIN_DECL (type)); if (context && CLASS_TYPE_P (context)) - push_nested_class (context, 2); - pushclass (type, modify); + push_nested_class (context); + pushclass (type, true); } /* Undoes a push_nested_class call. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fa73d67ba51..e8d8acff0cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2477,6 +2477,10 @@ struct lang_decl GTY(()) (TREE_CODE (TYPE) == BOOLEAN_TYPE \ || TREE_CODE (TYPE) == INTEGER_TYPE) +/* Returns true if TYPE is an integral or enumeration name. */ +#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \ + (CP_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == ENUMERAL_TYPE) + /* [basic.fundamental] Integral and floating types are collectively called arithmetic @@ -3642,9 +3646,9 @@ extern void finish_struct_1 (tree); extern int resolves_to_fixed_type_p (tree, int *); extern void init_class_processing (void); extern int is_empty_class (tree); -extern void pushclass (tree, int); +extern void pushclass (tree, bool); extern void popclass (void); -extern void push_nested_class (tree, int); +extern void push_nested_class (tree); extern void pop_nested_class (void); extern int current_lang_depth (void); extern void push_lang_context (tree); @@ -3854,7 +3858,6 @@ extern void check_member_template (tree); extern tree grokfield (tree, tree, tree, tree, tree); extern tree grokbitfield (tree, tree, tree); extern tree groktypefield (tree, tree); -extern tree grokoptypename (tree, tree, tree); extern void cplus_decl_attributes (tree *, tree, int); extern tree constructor_name_full (tree); extern tree constructor_name (tree); @@ -4009,7 +4012,6 @@ extern void cxx_init_options (void); /* in method.c */ extern void init_method (void); extern void set_mangled_name_for_decl (tree); -extern tree build_opfncall (enum tree_code, int, tree, tree, tree); extern tree hack_identifier (tree, tree); extern tree make_thunk (tree, bool, tree, tree); extern void finish_thunk (tree); @@ -4026,10 +4028,6 @@ extern bool maybe_clone_body (tree); /* in pt.c */ extern void check_template_shadow (tree); extern tree get_innermost_template_args (tree, int); -extern tree tsubst (tree, tree, tsubst_flags_t, tree); -extern tree tsubst_expr (tree, tree, tsubst_flags_t, tree); -extern tree tsubst_copy (tree, tree, tsubst_flags_t, tree); -extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree); extern void maybe_begin_member_template_processing (tree); extern void maybe_end_member_template_processing (void); extern tree finish_member_template_decl (tree); @@ -4086,6 +4084,9 @@ 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 resolve_typename_type_in_current_instantiation (tree); /* in repo.c */ extern void repo_template_used (tree); @@ -4226,7 +4227,6 @@ extern tree finish_unary_op_expr (enum tree_code, tree); extern tree finish_compound_literal (tree, tree); extern tree finish_fname (tree); extern int begin_function_definition (tree, tree, tree); -extern tree begin_constructor_declarator (tree, tree); extern tree finish_declarator (tree, tree, tree, tree, int); extern void finish_translation_unit (void); extern tree finish_template_type_parm (tree, tree); @@ -4238,7 +4238,6 @@ extern void finish_default_args (void); extern tree finish_member_class_template (tree); extern void finish_template_decl (tree); extern tree finish_template_type (tree, tree, int); -extern void enter_scope_of (tree); extern tree finish_base_specifier (tree, tree); extern void finish_member_declaration (tree); extern void check_multiple_declarators (void); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index d2b7527ee8f..9078da64ed1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -105,7 +105,6 @@ static tree record_builtin_java_type (const char *, int); static const char *tag_name (enum tag_types code); static void find_class_binding_level (void); static struct cp_binding_level *innermost_nonclass_level (void); -static void warn_about_implicit_typename_lookup (tree, tree); static int walk_namespaces_r (tree, walk_namespaces_fn, void *); static int walk_globals_r (tree, void*); static int walk_vtables_r (tree, void*); @@ -5072,8 +5071,6 @@ finish_case_label (tree low_value, tree high_value) cond = TREE_VALUE (cond); r = c_add_case_label (switch_stack->cases, cond, low_value, high_value); - if (r == error_mark_node) - r = NULL_TREE; check_switch_goto (switch_stack->level); @@ -5785,30 +5782,6 @@ qualify_lookup (tree val, int flags) return val; } -/* Any other BINDING overrides an implicit TYPENAME. Warn about - that. */ - -static void -warn_about_implicit_typename_lookup (tree typename, tree binding) -{ - tree subtype = TREE_TYPE (TREE_TYPE (typename)); - tree name = DECL_NAME (typename); - - if (! (TREE_CODE (binding) == TEMPLATE_DECL - && CLASSTYPE_TEMPLATE_INFO (subtype) - && CLASSTYPE_TI_TEMPLATE (subtype) == binding) - && ! (TREE_CODE (binding) == TYPE_DECL - && same_type_p (TREE_TYPE (binding), subtype))) - { - warning ("lookup of `%D' finds `%#D'", - name, binding); - warning (" instead of `%D' from dependent base class", - typename); - warning (" (use `typename %T::%D' if that's what you meant)", - constructor_name (current_class_type), name); - } -} - /* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL or a class TYPE). If IS_TYPE_P is TRUE, then ignore non-type bindings. @@ -7078,7 +7051,7 @@ start_decl (tree declarator, if (context && COMPLETE_TYPE_P (complete_type (context))) { - push_nested_class (context, 2); + push_nested_class (context); if (TREE_CODE (decl) == VAR_DECL) { @@ -9086,9 +9059,11 @@ grokfndecl (tree ctype, /* Attempt to merge the declarations. This can fail, in the case of some invalid specialization declarations. */ + push_scope (ctype); if (!duplicate_decls (decl, old_decl)) error ("no `%#D' member function declared in class `%T'", decl, ctype); + pop_scope (ctype); return old_decl; } } @@ -11055,35 +11030,6 @@ grokdeclarator (tree declarator, attrlist = &returned_attrs; } - /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq that refer - to ctype. They couldn't be resolved earlier because we hadn't - pushed into the class yet. - - For example, consider: - - template <typename T> - struct S { - typedef T X; - X f(); - }; - - template <typename T> - typename S<T>::X f() {} - - When parsing the decl-specifier-seq for the definition of `f', - we construct a TYPENAME_TYPE for `S<T>::X'. By substituting - here, we resolve it to the correct type. */ - if (scope && CLASS_TYPE_P (scope) - && current_template_parms - && uses_template_parms (scope)) - { - tree args = current_template_args (); - push_scope (scope); - type = tsubst (type, args, tf_error | tf_warning, - NULL_TREE); - pop_scope (scope); - } - /* Now TYPE has the actual type. */ /* Did array size calculations overflow? */ @@ -13470,9 +13416,9 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags) /* Set up current_class_type, and enter the scope of the class, if appropriate. */ if (ctype) - push_nested_class (ctype, 1); + push_nested_class (ctype); else if (DECL_STATIC_FUNCTION_P (decl1)) - push_nested_class (DECL_CONTEXT (decl1), 2); + push_nested_class (DECL_CONTEXT (decl1)); /* Now that we have entered the scope of the class, we must restore the bindings for any template parameters surrounding DECL1, if it diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 4401dccb20f..63240dd7f58 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -423,8 +423,8 @@ grok_array_decl (tree array_expr, tree index_exp) /* If they have an `operator[]', use that. */ if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp))) - return build_opfncall (ARRAY_REF, LOOKUP_NORMAL, - array_expr, index_exp, NULL_TREE); + 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 @@ -685,6 +685,7 @@ check_classfn (tree ctype, tree function) bool is_conv_op; const char *format = NULL; + push_scope (ctype); for (fndecls = TREE_VEC_ELT (methods, ix); fndecls; fndecls = OVL_NEXT (fndecls)) { @@ -713,8 +714,11 @@ check_classfn (tree ctype, tree function) && (!DECL_TEMPLATE_SPECIALIZATION (function) || (DECL_TI_TEMPLATE (function) == DECL_TI_TEMPLATE (fndecl)))) - return fndecl; + break; } + pop_scope (ctype); + if (fndecls) + return OVL_CURRENT (fndecls); error ("prototype for `%#D' does not match any in class `%T'", function, ctype); is_conv_op = DECL_CONV_FN_P (fndecl); @@ -1071,30 +1075,6 @@ grokbitfield (tree declarator, tree declspecs, tree width) return value; } -/* Convert a conversion operator name to an identifier. SCOPE is the - scope of the conversion operator, if explicit. */ - -tree -grokoptypename (tree declspecs, tree declarator, tree scope) -{ - tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL); - - /* Resolve any TYPENAME_TYPEs that refer to SCOPE, before mangling - the name, so that we mangle the right thing. */ - if (scope && current_template_parms - && uses_template_parms (t) - && uses_template_parms (scope)) - { - tree args = current_template_args (); - - push_scope (scope); - t = tsubst (t, args, tf_error | tf_warning, NULL_TREE); - pop_scope (scope); - } - - return mangle_conv_op_name_for_type (t); -} - /* When a function is declared with an initializer, do the right thing. Currently, there are two possibilities: @@ -3749,7 +3729,7 @@ push_scope (tree t) if (TREE_CODE (t) == NAMESPACE_DECL) push_decl_namespace (t); else if CLASS_TYPE_P (t) - push_nested_class (t, 2); + push_nested_class (t); } /* Leave scope pushed by push_scope. */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index d53943f3715..9fe4167483e 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -454,6 +454,7 @@ dump_type (t, flags) break; } case TYPENAME_TYPE: + dump_qualifiers (t, after); output_add_string (scratch_buffer, "typename "); dump_typename (t, flags); break; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 493f9b8e918..c2661e8fa1f 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1511,8 +1511,8 @@ build_member_call (type, name, parmlist) return error_mark_node; } if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl))) - return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl, - parmlist, NULL_TREE); + return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl, + parmlist, NULL_TREE); return build_function_call (decl, parmlist); } else diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 883a81f73fd..a60b75f1cbf 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -85,36 +85,6 @@ set_mangled_name_for_decl (tree decl) } -/* Given a tree_code CODE, and some arguments (at least one), - attempt to use an overloaded operator on the arguments. - - For unary operators, only the first argument need be checked. - For binary operators, both arguments may need to be checked. - - Member functions can convert class references to class pointers, - for one-level deep indirection. More than that is not supported. - Operators [](), ()(), and ->() must be member functions. - - We call function call building calls with LOOKUP_COMPLAIN if they - are our only hope. This is true when we see a vanilla operator - applied to something of aggregate type. If this fails, we are free - to return `error_mark_node', because we will have reported the - error. - - Operators NEW and DELETE overload in funny ways: operator new takes - a single `size' parameter, and operator delete takes a pointer to the - storage being deleted. When overloading these operators, success is - assumed. If there is a failure, report an error message and return - `error_mark_node'. */ - -/* NOSTRICT */ -tree -build_opfncall (enum tree_code code, int flags, - tree xarg1, tree xarg2, tree arg3) -{ - return build_new_op (code, flags, xarg1, xarg2, arg3); -} - /* This function takes an identifier, ID, and attempts to figure out what it means. There are a number of possible scenarios, presented in increasing order of hair: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index da9a92fa126..fab1ef4760b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1275,9 +1275,18 @@ typedef struct cp_parser GTY(()) /* TRUE if we are parsing an integral constant-expression. See [expr.const] for a precise definition. */ - /* FIXME: Need to implement code that checks this flag. */ bool constant_expression_p; + /* TRUE if we are parsing an integral constant-expression -- but a + non-constant expression should be permitted as well. This flag + is used when parsing an array bound so that GNU variable-length + arrays are tolerated. */ + bool allow_non_constant_expression_p; + + /* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has + been seen that makes the expression non-constant. */ + bool non_constant_expression_p; + /* TRUE if local variable names and `this' are forbidden in the current context. */ bool local_variables_forbidden_p; @@ -1422,7 +1431,7 @@ static enum tree_code cp_parser_assignment_operator_opt static tree cp_parser_expression (cp_parser *); static tree cp_parser_constant_expression - (cp_parser *); + (cp_parser *, bool, bool *); /* Statements [gram.stmt.stmt] */ @@ -1658,8 +1667,6 @@ static tree cp_parser_lookup_name (cp_parser *, tree, bool, bool, bool, bool); static tree cp_parser_lookup_name_simple (cp_parser *, tree); -static tree cp_parser_resolve_typename_type - (cp_parser *, tree); static tree cp_parser_maybe_treat_template_as_class (tree, bool); static bool cp_parser_check_declarator_template_parameters @@ -1728,6 +1735,10 @@ static bool cp_parser_simulate_error (cp_parser *); static void cp_parser_check_type_definition (cp_parser *); +static tree cp_parser_non_constant_expression + (const char *); +static tree cp_parser_non_constant_id_expression + (tree); static bool cp_parser_diagnose_invalid_type_name (cp_parser *); static bool cp_parser_skip_to_closing_parenthesis @@ -1875,6 +1886,26 @@ cp_parser_check_type_definition (cp_parser* parser) error ("%s", parser->type_definition_forbidden_message); } +/* Issue an eror message about the fact that THING appeared in a + constant-expression. Returns ERROR_MARK_NODE. */ + +static tree +cp_parser_non_constant_expression (const char *thing) +{ + error ("%s cannot appear in a constant-expression", thing); + return error_mark_node; +} + +/* Issue an eror message about the fact that DECL appeared in a + constant-expression. Returns ERROR_MARK_NODE. */ + +static tree +cp_parser_non_constant_id_expression (tree decl) +{ + error ("`%D' cannot appear in a constant-expression", decl); + return error_mark_node; +} + /* Check for a common situation where a type-name should be present, but is not, and issue a sensible error message. Returns true if an invalid type-name was detected. */ @@ -2182,6 +2213,8 @@ cp_parser_new (void) /* We are not parsing a constant-expression. */ parser->constant_expression_p = false; + parser->allow_non_constant_expression_p = false; + parser->non_constant_expression_p = false; /* Local variable names are not forbidden. */ parser->local_variables_forbidden_p = false; @@ -2395,6 +2428,13 @@ cp_parser_primary_expression (cp_parser *parser, error ("`this' may not be used in this context"); return error_mark_node; } + /* Pointers cannot appear in constant-expressions. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("`this'"); + parser->non_constant_expression_p = true; + } return finish_this_expr (); /* The `operator' keyword can be the beginning of an @@ -2434,7 +2474,14 @@ cp_parser_primary_expression (cp_parser *parser, type = cp_parser_type_id (parser); /* Look for the closing `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); - + /* Using `va_arg' in a constant-expression is not + allowed. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("`va_arg'"); + parser->non_constant_expression_p = true; + } return build_x_va_arg (expression, type); } @@ -2481,6 +2528,11 @@ cp_parser_primary_expression (cp_parser *parser, { if (TYPE_P (TREE_OPERAND (decl, 0))) *qualifying_class = TREE_OPERAND (decl, 0); + /* Since this name was dependent, the expression isn't + constant -- yet. No error is issued because it + might be constant when things are instantiated. */ + if (parser->constant_expression_p) + parser->non_constant_expression_p = true; return decl; } /* Check to see if DECL is a local variable in a context @@ -2704,6 +2756,11 @@ cp_parser_primary_expression (cp_parser *parser, { if (TYPE_P (parser->scope)) *qualifying_class = parser->scope; + /* Since this name was dependent, the expression isn't + constant -- yet. No error is issued because it + might be constant when things are instantiated. */ + if (parser->constant_expression_p) + parser->non_constant_expression_p = true; return build_nt (SCOPE_REF, parser->scope, id_expression); @@ -2712,10 +2769,36 @@ cp_parser_primary_expression (cp_parser *parser, we need. */ if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR) return id_expression; + /* Since this name was dependent, the expression isn't + constant -- yet. No error is issued because it + might be constant when things are instantiated. */ + if (parser->constant_expression_p) + parser->non_constant_expression_p = true; /* Create a LOOKUP_EXPR for other unqualified names. */ return build_min_nt (LOOKUP_EXPR, id_expression); } + /* 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. */ + && !(TREE_CODE (decl) == VAR_DECL + && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)) + && DECL_INITIAL (decl) + && TREE_CONSTANT (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 @@ -3520,6 +3603,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) expression = cp_parser_expression (parser); cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Only type conversions to integral or enumeration types + can be used in constant-expressions. */ + if (parser->constant_expression_p + && !dependent_type_p (type) + && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)) + { + if (!parser->allow_non_constant_expression_p) + return (cp_parser_non_constant_expression + ("a cast to a type other than an integral or " + "enumeration type")); + parser->non_constant_expression_p = true; + } + switch (keyword) { case RID_DYNCAST: @@ -3645,32 +3741,32 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) /* If the functional-cast didn't work out, try a compound-literal. */ - if (cp_parser_allow_gnu_extensions_p (parser)) + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { tree initializer_list = NULL_TREE; cp_parser_parse_tentatively (parser); - /* Look for the `('. */ - if (cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) + /* Consume the `('. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the type. */ + type = cp_parser_type_id (parser); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Look for the `{'. */ + cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); + /* If things aren't going well, there's no need to + keep going. */ + if (!cp_parser_error_occurred (parser)) { - type = cp_parser_type_id (parser); - /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); - /* Look for the `{'. */ - cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); - /* If things aren't going well, there's no need to - keep going. */ - if (!cp_parser_error_occurred (parser)) - { - /* Parse the initializer-list. */ - initializer_list - = cp_parser_initializer_list (parser); - /* Allow a trailing `,'. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) - cp_lexer_consume_token (parser->lexer); - /* Look for the final `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); - } + /* Parse the initializer-list. */ + initializer_list + = cp_parser_initializer_list (parser); + /* Allow a trailing `,'. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + /* Look for the final `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); } /* If that worked, we're definitely looking at a compound-literal expression. */ @@ -3806,6 +3902,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) args = NULL_TREE; /* Look for the closing `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + /* Function calls are not permitted in + constant-expressions. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("a function call"); + parser->non_constant_expression_p = true; + } if (idk == CP_PARSER_ID_KIND_UNQUALIFIED && (is_overloaded_fn (postfix_expression) @@ -4029,6 +4133,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) /* postfix-expression ++ */ /* Consume the `++' token. */ cp_lexer_consume_token (parser->lexer); + /* Increments may not appear in constant-expressions. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("an increment"); + parser->non_constant_expression_p = true; + } /* Generate a reprsentation for the complete expression. */ postfix_expression = finish_increment_expr (postfix_expression, @@ -4040,6 +4151,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) /* postfix-expression -- */ /* Consume the `--' token. */ cp_lexer_consume_token (parser->lexer); + /* Decrements may not appear in constant-expressions. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("a decrement"); + parser->non_constant_expression_p = true; + } /* Generate a reprsentation for the complete expression. */ postfix_expression = finish_increment_expr (postfix_expression, @@ -4341,11 +4459,20 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p) case ADDR_EXPR: return build_x_unary_op (ADDR_EXPR, cast_expression); + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression (PREINCREMENT_EXPR + ? "an increment" + : "a decrement"); + parser->non_constant_expression_p = true; + } + /* Fall through. */ case CONVERT_EXPR: case NEGATE_EXPR: case TRUTH_NOT_EXPR: - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: return finish_unary_op_expr (unary_operator, cast_expression); case BIT_NOT_EXPR: @@ -4597,7 +4724,10 @@ cp_parser_direct_new_declarator (cp_parser* parser) } /* But all the other expressions must be. */ else - expression = cp_parser_constant_expression (parser); + expression + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); /* Look for the closing `]'. */ cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"); @@ -4766,7 +4896,19 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p) && !VOID_TYPE_P (type) && current_lang_name != lang_name_c) warning ("use of old-style cast"); - + + /* Only type conversions to integral or enumeration types + can be used in constant-expressions. */ + if (parser->constant_expression_p + && !dependent_type_p (type) + && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)) + { + if (!parser->allow_non_constant_expression_p) + return (cp_parser_non_constant_expression + ("a casts to a type other than an integral or " + "enumeration type")); + parser->non_constant_expression_p = true; + } /* Perform the cast. */ expr = build_c_cast (type, expr); return expr; @@ -5176,6 +5318,14 @@ cp_parser_assignment_expression (cp_parser* parser) /* Parse the right-hand side of the assignment. */ rhs = cp_parser_assignment_expression (parser); + /* An assignment may not appear in a + constant-expression. */ + if (parser->constant_expression_p) + { + if (!parser->allow_non_constant_expression_p) + return cp_parser_non_constant_expression ("an assignment"); + parser->non_constant_expression_p = true; + } /* Build the asignment expression. */ expr = build_x_modify_expr (expr, assignment_operator, @@ -5334,7 +5484,16 @@ cp_parser_expression (cp_parser* parser) necessary. We built up the list in reverse order, so we must straighten it out here. */ if (saw_comma_p) - expression = build_x_compound_expr (nreverse (expression)); + { + /* 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; } @@ -5342,12 +5501,20 @@ cp_parser_expression (cp_parser* parser) /* Parse a constant-expression. constant-expression: - conditional-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) +cp_parser_constant_expression (cp_parser* parser, + bool allow_non_constant_p, + bool *non_constant_p) { bool saved_constant_expression_p; + bool saved_allow_non_constant_expression_p; + bool saved_non_constant_expression_p; tree expression; /* It might seem that we could simply parse the @@ -5367,14 +5534,24 @@ cp_parser_constant_expression (cp_parser* parser) constant-expression. However, GCC's constant-folding machinery will fold this operation to an INTEGER_CST for `3'. */ - /* Save the old setting of CONSTANT_EXPRESSION_P. */ + /* Save the old settings. */ saved_constant_expression_p = parser->constant_expression_p; + saved_allow_non_constant_expression_p + = parser->allow_non_constant_expression_p; + saved_non_constant_expression_p = parser->non_constant_expression_p; /* We are now parsing a constant-expression. */ parser->constant_expression_p = true; + parser->allow_non_constant_expression_p = allow_non_constant_p; + parser->non_constant_expression_p = false; /* Parse the conditional-expression. */ expression = cp_parser_conditional_expression (parser); - /* Restore the old setting of CONSTANT_EXPRESSION_P. */ + /* Restore the old settings. */ parser->constant_expression_p = saved_constant_expression_p; + parser->allow_non_constant_expression_p + = saved_allow_non_constant_expression_p; + if (allow_non_constant_p) + *non_constant_p = parser->non_constant_expression_p; + parser->non_constant_expression_p = saved_non_constant_expression_p; return expression; } @@ -5517,7 +5694,9 @@ cp_parser_labeled_statement (cp_parser* parser) /* Consume the `case' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the constant-expression. */ - expr = cp_parser_constant_expression (parser); + expr = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); /* Create the label. */ statement = finish_case_label (expr, NULL_TREE); } @@ -8875,7 +9054,9 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type) /* Consume the `=' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the value. */ - value = cp_parser_constant_expression (parser); + value = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); } else value = NULL_TREE; @@ -9870,7 +10051,34 @@ cp_parser_direct_declarator (cp_parser* parser, /* If the next token is `]', then there is no constant-expression. */ if (token->type != CPP_CLOSE_SQUARE) - bounds = cp_parser_constant_expression (parser); + { + bool non_constant_p; + + 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 = build_expr_from_tree (bounds); + processing_template_decl = saved_processing_template_decl; + } + } else bounds = NULL_TREE; /* Look for the closing `]'. */ @@ -9924,11 +10132,14 @@ cp_parser_direct_declarator (cp_parser* parser, is no harm in resolving the types here. */ if (TREE_CODE (scope) == TYPENAME_TYPE) { + tree type; + /* Resolve the TYPENAME_TYPE. */ - scope = cp_parser_resolve_typename_type (parser, scope); + type = resolve_typename_type (scope, + /*only_current_p=*/false); /* If that failed, the declarator is invalid. */ - if (scope == error_mark_node) - return error_mark_node; + if (type != error_mark_node) + scope = type; /* Build a new DECLARATOR. */ declarator = build_nt (SCOPE_REF, scope, @@ -11549,16 +11760,22 @@ cp_parser_class_head (cp_parser* parser, /* Given: template <typename T> struct S { struct T }; - template <typename T> struct S::T { }; + template <typename T> struct S<T>::T { }; we will get a TYPENAME_TYPE when processing the definition of `S::T'. We need to resolve it to the actual type before we try to define it. */ if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE) { - type = cp_parser_resolve_typename_type (parser, TREE_TYPE (type)); - if (type != error_mark_node) - type = TYPE_NAME (type); + class_type = resolve_typename_type (TREE_TYPE (type), + /*only_current_p=*/false); + if (class_type != error_mark_node) + type = TYPE_NAME (class_type); + else + { + cp_parser_error (parser, "could not resolve typename type"); + type = error_mark_node; + } } maybe_process_partial_specialization (TREE_TYPE (type)); @@ -11889,7 +12106,10 @@ cp_parser_member_declaration (cp_parser* parser) /* Consume the `:' token. */ cp_lexer_consume_token (parser->lexer); /* Get the width of the bitfield. */ - width = cp_parser_constant_expression (parser); + width + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); /* Look for attributes that apply to the bitfield. */ attributes = cp_parser_attributes_opt (parser); @@ -12112,7 +12332,9 @@ cp_parser_constant_initializer (cp_parser* parser) return error_mark_node; } - return cp_parser_constant_expression (parser); + return cp_parser_constant_expression (parser, + /*allow_non_constant=*/false, + NULL); } /* Derived classes [gram.class.derived] */ @@ -13148,58 +13370,6 @@ cp_parser_lookup_name_simple (cp_parser* parser, tree name) /*check_dependency=*/true); } -/* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the - TYPENAME_TYPE corresponds. Note that this function peers inside - uninstantiated templates and therefore should be used only in - extremely limited situations. */ - -static tree -cp_parser_resolve_typename_type (cp_parser* parser, tree type) -{ - tree scope; - tree name; - tree decl; - - my_friendly_assert (TREE_CODE (type) == TYPENAME_TYPE, - 20010702); - - scope = TYPE_CONTEXT (type); - name = TYPE_IDENTIFIER (type); - - /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve - it first before we can figure out what NAME refers to. */ - if (TREE_CODE (scope) == TYPENAME_TYPE) - scope = cp_parser_resolve_typename_type (parser, scope); - /* If we don't know what SCOPE refers to, then we cannot resolve the - TYPENAME_TYPE. */ - if (scope == error_mark_node || TREE_CODE (scope) == TYPENAME_TYPE) - return error_mark_node; - /* If the SCOPE is a template type parameter, we have no way of - resolving the name. */ - if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM) - return type; - /* Enter the SCOPE so that name lookup will be resolved as if we - were in the class definition. In particular, SCOPE will no - longer be considered a dependent type. */ - push_scope (scope); - /* Look up the declaration. */ - decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/1); - /* If all went well, we got a TYPE_DECL for a non-typename. */ - if (!decl - || TREE_CODE (decl) != TYPE_DECL - || TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE) - { - cp_parser_error (parser, "could not resolve typename type"); - type = error_mark_node; - } - else - type = TREE_TYPE (decl); - /* Leave the SCOPE. */ - pop_scope (scope); - - return type; -} - /* If DECL is a TEMPLATE_DECL that can be treated like a TYPE_DECL in the current context, return the TYPE_DECL. If TAG_NAME_P is true, the DECL indicates the class being defined in a class-head, @@ -13547,7 +13717,15 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) { type = TREE_TYPE (type_decl); if (TREE_CODE (type) == TYPENAME_TYPE) - type = cp_parser_resolve_typename_type (parser, type); + { + type = resolve_typename_type (type, + /*only_current_p=*/false); + if (type == error_mark_node) + { + cp_parser_abort_tentative_parse (parser); + return false; + } + } push_scope (type); } /* Look for the type-specifier. */ @@ -13978,7 +14156,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn) parser->local_variables_forbidden_p = true; /* Parse the assignment-expression. */ if (DECL_CONTEXT (fn)) - push_nested_class (DECL_CONTEXT (fn), 1); + push_nested_class (DECL_CONTEXT (fn)); TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser); if (DECL_CONTEXT (fn)) pop_nested_class (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b3b81063ce0..2429f7f788e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -171,8 +171,11 @@ static void copy_default_args_to_explicit_spec PARAMS ((tree)); static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t)); static int eq_local_specializations (const void *, const void *); static tree template_for_substitution (tree); -static bool value_dependent_expression_p (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); +static tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -215,7 +218,7 @@ push_access_scope_real (t, args, context) if (!context) context = DECL_CONTEXT (t); if (context && TYPE_P (context)) - push_nested_class (context, 2); + push_nested_class (context); else push_to_top_level (); @@ -5043,7 +5046,7 @@ tsubst_friend_class (friend_tmpl, args) if (TREE_CODE (context) == NAMESPACE_DECL) push_nested_namespace (context); else - push_nested_class (tsubst (context, args, tf_none, NULL_TREE), 2); + push_nested_class (tsubst (context, args, tf_none, NULL_TREE)); } /* First, we look for a class template. */ @@ -5328,7 +5331,7 @@ instantiate_class_template (type) correctly. This is precisely analogous to what we do in begin_class_definition when defining an ordinary non-template class. */ - pushclass (type, 1); + pushclass (type, true); /* Now members are processed in the order of declaration. */ for (member = CLASSTYPE_DECL_LIST (pattern); member; member = TREE_CHAIN (member)) @@ -6467,7 +6470,7 @@ tsubst_call_declarator_parms (parms, args, complain, in_decl) This function is used for dealing with types, decls and the like; for expressions, use tsubst_expr or tsubst_copy. */ -tree +static tree tsubst (t, args, complain, in_decl) tree t, args; tsubst_flags_t complain; @@ -7103,7 +7106,7 @@ tsubst (t, args, complain, in_decl) template parms; to finish processing the resultant expression, use tsubst_expr. */ -tree +static tree tsubst_copy (t, args, complain, in_decl) tree t, args; tsubst_flags_t complain; @@ -7505,7 +7508,7 @@ tsubst_copy (t, args, complain, in_decl) /* Like tsubst_copy for expressions, etc. but also does semantic processing. */ -tree +static tree tsubst_expr (t, args, complain, in_decl) tree t, args; tsubst_flags_t complain; @@ -7832,7 +7835,7 @@ tsubst_expr (t, args, complain, in_decl) /* Like tsubst but deals with expressions and performs semantic analysis. */ -tree +static tree tsubst_copy_and_build (t, args, complain, in_decl) tree t, args; tsubst_flags_t complain; @@ -11314,15 +11317,16 @@ dependent_type_p (type) /* Returns TRUE if the EXPRESSION is value-dependent. */ -static bool +bool value_dependent_expression_p (tree expression) { if (!processing_template_decl) return false; /* A name declared with a dependent type. */ - if (DECL_P (expression) - && dependent_type_p (TREE_TYPE (expression))) + if (TREE_CODE (expression) == LOOKUP_EXPR + || (DECL_P (expression) + && dependent_type_p (TREE_TYPE (expression)))) return true; /* A non-type template parameter. */ if ((TREE_CODE (expression) == CONST_DECL @@ -11370,11 +11374,14 @@ value_dependent_expression_p (tree expression) case 'e': { int i; - for (i = 0; - i < TREE_CODE_LENGTH (TREE_CODE (expression)); - ++i) - if (value_dependent_expression_p - (TREE_OPERAND (expression, i))) + for (i = 0; i < first_rtl_op (TREE_CODE (expression)); ++i) + /* In some cases, some of the operands may be missing. + (For example, in the case of PREDECREMENT_EXPR, the + amount to increment by may be missing.) That doesn't + make the expression dependent. */ + if (TREE_OPERAND (expression, i) + && (value_dependent_expression_p + (TREE_OPERAND (expression, i)))) return true; return false; } @@ -11478,4 +11485,88 @@ dependent_template_p (tree tmpl) return false; } +/* 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. */ + +tree +resolve_typename_type (tree type, bool only_current_p) +{ + tree scope; + tree name; + tree decl; + int quals; + + my_friendly_assert (TREE_CODE (type) == TYPENAME_TYPE, + 20010702); + + scope = TYPE_CONTEXT (type); + name = TYPE_IDENTIFIER (type); + + /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve + it first before we can figure out what NAME refers to. */ + if (TREE_CODE (scope) == TYPENAME_TYPE) + scope = resolve_typename_type (scope, only_current_p); + /* If we don't know what SCOPE refers to, then we cannot resolve the + TYPENAME_TYPE. */ + if (scope == error_mark_node || TREE_CODE (scope) == TYPENAME_TYPE) + return error_mark_node; + /* If the SCOPE is a template type parameter, we have no way of + resolving the name. */ + if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM) + return type; + /* If the SCOPE is not the current instantiation, there's no reason + to look inside it. */ + if (only_current_p && !currently_open_class (scope)) + return error_mark_node; + /* Enter the SCOPE so that name lookup will be resolved as if we + were in the class definition. In particular, SCOPE will no + longer be considered a dependent type. */ + push_scope (scope); + /* Look up the declaration. */ + decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/1); + /* Obtain the set of qualifiers applied to the TYPE. */ + quals = cp_type_quals (type); + /* For a TYPENAME_TYPE like "typename X::template Y<T>", we want to + find a TEMPLATE_DECL. Otherwise, we want to find a TYPE_DECL. */ + if (!decl) + type = error_mark_node; + else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == IDENTIFIER_NODE + && TREE_CODE (decl) == TYPE_DECL) + type = TREE_TYPE (decl); + else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR + && DECL_CLASS_TEMPLATE_P (decl)) + { + tree tmpl; + tree args; + /* Obtain the template and the arguments. */ + tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0); + args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1); + /* Instantiate the template. */ + type = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE, + /*entering_scope=*/0, + tf_error); + } + else + type = error_mark_node; + /* Qualify the resulting type. */ + if (type != error_mark_node && quals) + type = cp_build_qualified_type (type, quals); + /* Leave the SCOPE. */ + pop_scope (scope); + + return type; +} + +tree +resolve_typename_type_in_current_instantiation (tree type) +{ + tree t; + + t = resolve_typename_type (type, /*only_current_p=*/true); + return (t != error_mark_node) ? t : type; +} + #include "gt-cp-pt.h" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fb6f25d116f..9c0b28b6b13 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1434,7 +1434,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) /* If the "function" is really an object of class type, it might have an overloaded `operator ()'. */ tree result; - result = build_opfncall (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE); + result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE); if (result) return result; } @@ -1665,19 +1665,6 @@ begin_function_definition (decl_specs, attributes, declarator) return 1; } -/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns - a SCOPE_REF. */ - -tree -begin_constructor_declarator (scope, name) - tree scope; - tree name; -{ - tree result = build_nt (SCOPE_REF, scope, name); - enter_scope_of (result); - return result; -} - /* Finish an init-declarator. Returns a DECL. */ tree @@ -1831,7 +1818,7 @@ begin_class_definition (t) pushtag (TYPE_IDENTIFIER (t), t, 0); } maybe_process_partial_specialization (t); - pushclass (t, 1); + pushclass (t, true); TYPE_BEING_DEFINED (t) = 1; TYPE_PACKED (t) = flag_pack_struct; /* Reset the interface data, at the earliest possible @@ -2044,34 +2031,6 @@ finish_template_type (name, args, entering_scope) return decl; } -/* SR is a SCOPE_REF node. Enter the scope of SR, whether it is a - namespace scope or a class scope. */ - -void -enter_scope_of (sr) - tree sr; -{ - tree scope = TREE_OPERAND (sr, 0); - - if (TREE_CODE (scope) == NAMESPACE_DECL) - { - push_decl_namespace (scope); - TREE_COMPLEXITY (sr) = -1; - } - else if (scope != current_class_type) - { - if (TREE_CODE (scope) == TYPENAME_TYPE) - { - /* In a declarator for a template class member, the scope will - get here as an implicit typename, a TYPENAME_TYPE with a type. */ - scope = TREE_TYPE (scope); - TREE_OPERAND (sr, 0) = scope; - } - push_nested_class (scope, 3); - TREE_COMPLEXITY (sr) = current_class_depth; - } -} - /* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER. Return a TREE_LIST containing the ACCESS_SPECIFIER and the BASE_CLASS, or NULL_TREE if an error occurred. The diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 57d95ad231f..9d11262b88c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -946,6 +946,13 @@ comptypes (t1, t2, strict) if (TYPE_PTRMEMFUNC_P (t2)) t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2); + /* TYPENAME_TYPEs should be resolved if the qualifying scope is the + current instantiation. */ + if (TREE_CODE (t1) == TYPENAME_TYPE) + t1 = resolve_typename_type_in_current_instantiation (t1); + if (TREE_CODE (t2) == TYPENAME_TYPE) + t2 = resolve_typename_type_in_current_instantiation (t2); + /* Different classes of types can't be compatible. */ if (TREE_CODE (t1) != TREE_CODE (t2)) return 0; @@ -2301,8 +2308,8 @@ build_x_indirect_ref (ptr, errorstring) if (processing_template_decl) return build_min_nt (INDIRECT_REF, ptr); - rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, - NULL_TREE); + rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, + NULL_TREE); if (rval) return rval; return build_indirect_ref (ptr, errorstring); @@ -2973,6 +2980,183 @@ build_x_binary_op (code, 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 conditioanl + 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: @@ -4602,8 +4786,8 @@ build_x_compound_expr (list) if (rest == NULL_TREE) return build_compound_expr (list); - result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL, - TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE); + 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))); @@ -5235,8 +5419,8 @@ build_modify_expr (lhs, modifycode, rhs) /* Do the default thing */; else { - result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, - lhs, rhs, make_node (NOP_EXPR)); + result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, + lhs, rhs, make_node (NOP_EXPR)); if (result == NULL_TREE) return error_mark_node; return result; @@ -5488,8 +5672,8 @@ build_x_modify_expr (lhs, modifycode, rhs) if (modifycode != NOP_EXPR) { - tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, - make_node (modifycode)); + tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, + make_node (modifycode)); if (rval) return rval; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 0a5b4dc9a9d..c7dcb527b82 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1044,8 +1044,8 @@ build_x_arrow (datum) if (IS_AGGR_TYPE (type)) { - while ((rval = build_opfncall (COMPONENT_REF, LOOKUP_NORMAL, rval, - NULL_TREE, NULL_TREE))) + while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval, + NULL_TREE, NULL_TREE))) { if (rval == error_mark_node) return error_mark_node; |