diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 42 | ||||
-rw-r--r-- | gcc/cp/class.c | 30 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 31 | ||||
-rw-r--r-- | gcc/cp/decl.c | 218 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 29 | ||||
-rw-r--r-- | gcc/cp/pt.c | 33 | ||||
-rw-r--r-- | gcc/cp/tree.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.eh/tmpl3.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.ns/crash3.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/expr1.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/lookup8.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/array2.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/memtemp81.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/overload11.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/ptrmem4.C | 28 |
15 files changed, 399 insertions, 126 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 84cc28fa1b7..78658fd0169 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +1998-12-14 Mark Mitchell <mark@markmitchell.com> + + * class.c (pushclass): Tweak handling of class-level bindings. + (resolve_address_of_overloaded_function): Update pointer-to-member + handling. + (instantiate_type): Likewise. + * cvt.c (cp_convert_to_pointer): Likewise. + * decl.c (pop_binding): Take the DECL to pop, not just the name. + Deal with `struct stat' hack. + (binding_level): Add to documentation. + (push_binding): Clear BINDING_TYPE. + (add_binding): New function. + (push_local_binding): Use it. + (push_class_binding): Likewise. + (poplevel): Adjust calls to pop_binding. + (poplevel_class): Likewise. + (pushdecl): Adjust handling of TYPE_DECLs; add bindings for hidden + declarations to current binding level. + (push_class_level_binding): Likewise. + (push_overloaded_decl): Adjust handling of OVERLOADs in local + bindings. + (lookup_namespace_name): Don't crash when confronted with a + TEMPLATE_DECL. + (lookup_name_real): Do `struct stat' hack in local binding + contexts. + (build_ptrmemfunc_type): Adjust documentation. + (grokdeclarator): Don't avoid building real array types when + processing templates unless really necessary. + (finish_method): Adjust calls to pop_binding. + * decl2.c (reparse_absdcl_as_expr): Recursively call ourselves, + not reparse_decl_as_expr. + (build_expr_from_tree): Deal with a template-id as the function to + call in a METHOD_CALL_EXPR. + * pt.c (convert_nontype_argument): Tweak pointer-to-member handling. + (maybe_adjust_types_For_deduction): Don't do peculiar things with + METHOD_TYPEs here. + (resolve_overloaded_unification): Handle COMPONENT_REFs. Build + pointer-to-member types where necessary. + * tree.c (build_cplus_array_type_1): Don't avoid building real + array types when processing templates unless really necessary. + (build_exception_variant): Compare the exception lists correctly. + 1998-12-13 Mark Mitchell <mark@markmitchell.com> * cp-tree.def (CPLUS_BINDING): Update documentation. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 5031b556917..e3f4544481b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4789,7 +4789,7 @@ pushclass (type, modify) for (item = previous_class_values; item; item = TREE_CHAIN (item)) { tree id = TREE_PURPOSE (item); - tree decl = IDENTIFIER_CLASS_VALUE (id); + tree decl = TREE_TYPE (item); push_class_binding (id, decl); if (TREE_CODE (decl) == TYPE_DECL) @@ -4808,8 +4808,6 @@ pushclass (type, modify) if (! (IS_AGGR_TYPE_CODE (TREE_CODE (tag_type)) && CLASSTYPE_IS_TEMPLATE (tag_type))) pushtag (TREE_PURPOSE (tags), tag_type, 0); - else - pushdecl_class_level (CLASSTYPE_TI_TEMPLATE (tag_type)); } current_function_decl = this_fndecl; @@ -5028,11 +5026,12 @@ resolve_address_of_overloaded_function (target_type, interoperability with most_specialized_instantiation. */ tree matches = NULL_TREE; - /* If the TARGET_TYPE is a pointer-to-a-method, we convert it to - proper pointer-to-member type here. */ - if (TREE_CODE (target_type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (target_type)) == METHOD_TYPE) - target_type = build_ptrmemfunc_type (target_type); + /* By the time we get here, we should be seeing only real + pointer-to-member types, not the internal POINTER_TYPE to + METHOD_TYPE representation. */ + my_friendly_assert (!(TREE_CODE (target_type) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (target_type)) + == METHOD_TYPE)), 0); /* Check that the TARGET_TYPE is reasonable. */ if (TYPE_PTRFN_P (target_type)) @@ -5475,15 +5474,20 @@ instantiate_type (lhstype, rhs, complain) if (fn == error_mark_node) return error_mark_node; mark_addressable (fn); - TREE_TYPE (rhs) = lhstype; TREE_OPERAND (rhs, 0) = fn; TREE_CONSTANT (rhs) = staticp (fn); - if (TREE_CODE (lhstype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE) + if (TYPE_PTRMEMFUNC_P (lhstype)) { - build_ptrmemfunc_type (lhstype); - rhs = build_ptrmemfunc (lhstype, rhs, 0); + /* We must use the POINTER_TYPE to METHOD_TYPE on RHS here + so that build_ptrmemfunc knows that RHS we have is not + already a pointer-to-member constant. Instead, it is + just a ADDR_EXPR over a FUNCTION_DECL. */ + TREE_TYPE (rhs) = TYPE_PTRMEMFUNC_FN_TYPE (lhstype); + rhs = build_ptrmemfunc (TREE_TYPE (rhs), rhs, 0); } + else + /* Here, things our simple; we have exactly what we need. */ + TREE_TYPE (rhs) = lhstype; } return rhs; diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index a5a91c16238..c8f9fcc57e9 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -95,9 +95,6 @@ cp_convert_to_pointer (type, expr) } } - if (TYPE_PTRMEMFUNC_P (type)) - type = TYPE_PTRMEMFUNC_FN_TYPE (type); - /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE @@ -128,16 +125,14 @@ cp_convert_to_pointer (type, expr) intype = TREE_TYPE (expr); } - if (TYPE_PTRMEMFUNC_P (intype)) - intype = TYPE_PTRMEMFUNC_FN_TYPE (intype); - form = TREE_CODE (intype); - if (form == POINTER_TYPE || form == REFERENCE_TYPE) + if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype + && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) @@ -181,12 +176,9 @@ cp_convert_to_pointer (type, expr) } } } - if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE - && TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE) - return build_ptrmemfunc (type, expr, 1); - if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE) { tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type)); @@ -205,10 +197,7 @@ cp_convert_to_pointer (type, expr) if (binfo && ! TREE_VIA_VIRTUAL (binfo)) expr = size_binop (code, expr, BINFO_OFFSET (binfo)); } - - if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE - || (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)) + else if (TYPE_PTRMEMFUNC_P (type)) { cp_error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); @@ -219,6 +208,14 @@ cp_convert_to_pointer (type, expr) TREE_CONSTANT (rval) = TREE_CONSTANT (expr); return rval; } + else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) + return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 1); + else if (TYPE_PTRMEMFUNC_P (intype)) + { + cp_error ("cannot convert `%E' from type `%T' to type `%T'", + expr, intype, type); + return error_mark_node; + } my_friendly_assert (form != OFFSET_TYPE, 186); @@ -228,7 +225,7 @@ cp_convert_to_pointer (type, expr) if (integer_zerop (expr)) { - if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE) + if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (type, expr, 0); expr = build_int_2 (0, 0); TREE_TYPE (expr) = type; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7c9a518e161..8940acb3ea0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -180,7 +180,8 @@ static void check_for_uninitialized_const_var PROTO((tree)); static unsigned long typename_hash PROTO((hash_table_key)); static boolean typename_compare PROTO((hash_table_key, hash_table_key)); static void push_binding PROTO((tree, tree, struct binding_level*)); -static void pop_binding PROTO((tree)); +static void add_binding PROTO((tree, tree)); +static void pop_binding PROTO((tree, tree)); #if defined (DEBUG_CP_BINDING_LEVELS) static void indent PROTO((void)); @@ -602,7 +603,10 @@ push_decl_level (stack, obstack) to catch class-local declarations. It is otherwise nonexistent. Also there may be binding levels that catch cleanups that must be - run when exceptions occur. */ + run when exceptions occur. Thus, to see whether a name is bound in + the current scope, it is not enough to look in the + CURRENT_BINDING_LEVEL. You should use lookup_name_current_level + instead. */ /* Note that the information in the `names' component of the global contour is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ @@ -637,7 +641,8 @@ struct binding_level is the name of an entity bound in the class; the TREE_VALUE is the IDENTIFIER_CLASS_VALUE before we entered the class. Thus, when leaving class scope, we can restore the - IDENTIFIER_CLASS_VALUE by walking this list. */ + IDENTIFIER_CLASS_VALUE by walking this list. The TREE_TYPE is + the DECL bound by this name in the class. */ tree class_shadowed; /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and @@ -1072,6 +1077,7 @@ push_binding (id, decl, level) /* Now, fill in the binding information. */ BINDING_VALUE (binding) = decl; + BINDING_TYPE (binding) = NULL_TREE; BINDING_LEVEL (binding) = level; LOCAL_BINDING_P (binding) = (level != class_binding_level); @@ -1080,6 +1086,38 @@ push_binding (id, decl, level) IDENTIFIER_BINDING (id) = binding; } +/* ID is already bound in the current scope. But, DECL is an + additional binding for ID in the same scope. This is the `struct + stat' hack whereby a non-typedef class-name or enum-name can be + bound at the same level as some other kind of entity. It's the + responsibility of the caller to check that inserting this name is + legal here. */ +static void +add_binding (id, decl) + tree id; + tree decl; +{ + tree binding = IDENTIFIER_BINDING (id); + + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + /* The new name is the type name. */ + BINDING_TYPE (binding) = decl; + else + { + /* The old name must be the type name. It was placed in + IDENTIFIER_VALUE because it was thought, at the point it + was declared, to be the only entity with such a name. */ + my_friendly_assert (TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL + && DECL_ARTIFICIAL (BINDING_VALUE (binding)), + 0); + + /* Move the type name into the type slot; it is now hidden by + the new binding. */ + BINDING_TYPE (binding) = BINDING_VALUE (binding); + BINDING_VALUE (binding) = decl; + } +} + /* Bind DECL to ID in the current_binding_level. */ void @@ -1087,15 +1125,19 @@ push_local_binding (id, decl) tree id; tree decl; { - tree d = decl;; + tree d = decl; if (TREE_CODE (decl) == OVERLOAD) /* We must put the OVERLOAD into a TREE_LIST since the TREE_CHAIN of an OVERLOAD is already used. */ decl = build_tree_list (NULL_TREE, decl); - /* Create a binding, hanging off of ID. */ - push_binding (id, d, current_binding_level); + if (lookup_name_current_level (id)) + /* Supplement the existing binding. */ + add_binding (id, decl); + else + /* Create a new binding. */ + push_binding (id, d, current_binding_level); /* And put DECL on the list of things declared by the current binding level. */ @@ -1110,32 +1152,63 @@ push_class_binding (id, decl) tree id; tree decl; { - push_binding (id, decl, class_binding_level); + if (IDENTIFIER_BINDING (id) + && BINDING_LEVEL (IDENTIFIER_BINDING (id)) == class_binding_level) + /* Supplement the existing binding. */ + add_binding (id, decl); + else + /* Create a new binding. */ + push_binding (id, decl, class_binding_level); + + /* Update the IDENTIFIER_CLASS_VALUE for this ID to be the + class-level declaration. Note that we do not use DECL here + because of the possibility of the `struct stat' hack; if DECL is + a class-name or enum-name we might prefer a field-name, or some + such. */ + IDENTIFIER_CLASS_VALUE (id) = BINDING_VALUE (IDENTIFIER_BINDING (id)); } -/* Remove the innermost binding for ID; it has gone out of scope. */ +/* Remove the binding for DECL which should be the innermost binding + for ID. */ static void -pop_binding (id) +pop_binding (id, decl) tree id; + tree decl; { tree binding; - + if (id == NULL_TREE) /* It's easiest to write the loops that call this function without checking whether or not the entities involved have names. We get here for such an entity. */ return; - my_friendly_assert (IDENTIFIER_BINDING (id) != NULL_TREE, 0); - - /* Unhook the innermost binding from the list of bindings. */ + /* Get the innermost binding for ID. */ binding = IDENTIFIER_BINDING (id); - IDENTIFIER_BINDING (id) = TREE_CHAIN (binding); - /* And place this list node on the free list. */ - TREE_CHAIN (binding) = free_binding_nodes; - free_binding_nodes = binding; + /* The name should be bound. */ + my_friendly_assert (binding != NULL_TREE, 0); + + /* The DECL will be either the ordinary binding or the type + binding for this identifier. Remove that binding. */ + if (BINDING_VALUE (binding) == decl) + BINDING_VALUE (binding) = NULL_TREE; + else if (BINDING_TYPE (binding) == decl) + BINDING_TYPE (binding) = NULL_TREE; + else + my_friendly_abort (0); + + if (!BINDING_VALUE (binding) && !BINDING_TYPE (binding)) + { + /* We're completely done with the innermost binding for this + identifier. Unhook it from the list of bindings. */ + IDENTIFIER_BINDING (id) = TREE_CHAIN (binding); + + /* And place it on the free list. */ + TREE_CHAIN (binding) = free_binding_nodes; + free_binding_nodes = binding; + } } /* Exit a binding level. @@ -1303,7 +1376,7 @@ poplevel (keep, reverse, functionbody) and we are leaving the `for' scope. There's no reason to keep the binding of the inner `i' in this case. */ - pop_binding (DECL_NAME (link)); + pop_binding (DECL_NAME (link), link); else if ((outer_binding && (TREE_CODE (BINDING_VALUE (outer_binding)) == TYPE_DECL)) @@ -1319,7 +1392,7 @@ poplevel (keep, reverse, functionbody) We must pop the for-scope binding so we know what's a type and what isn't. */ - pop_binding (DECL_NAME (link)); + pop_binding (DECL_NAME (link), link); else { /* Mark this VAR_DECL as dead so that we can tell we left it @@ -1350,10 +1423,11 @@ poplevel (keep, reverse, functionbody) { /* Remove the binding. */ if (TREE_CODE_CLASS (TREE_CODE (link)) == 'd') - pop_binding (DECL_NAME (link)); + pop_binding (DECL_NAME (link), link); else if (TREE_CODE (link) == TREE_LIST) - pop_binding (DECL_NAME (OVL_FUNCTION (TREE_VALUE (link)))); - else + pop_binding (DECL_NAME (OVL_FUNCTION (TREE_VALUE (link))), + TREE_VALUE (link)); + else my_friendly_abort (0); } } @@ -1362,7 +1436,7 @@ poplevel (keep, reverse, functionbody) that we kept around. */ for (link = current_binding_level->dead_vars_from_for; link; link = TREE_CHAIN (link)) - pop_binding (DECL_NAME (TREE_VALUE (link))); + pop_binding (DECL_NAME (TREE_VALUE (link)), TREE_VALUE (link)); /* Restore the IDENTIFIER_TYPE_VALUEs. */ for (link = current_binding_level->type_shadowed; @@ -1607,7 +1681,7 @@ poplevel_class (force) for (shadowed = level->class_shadowed; shadowed; shadowed = TREE_CHAIN (shadowed)) - pop_binding (TREE_PURPOSE (shadowed)); + pop_binding (TREE_PURPOSE (shadowed), TREE_TYPE (shadowed)); GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level, (HOST_WIDE_INT) class_binding_level->level_chain, @@ -3617,12 +3691,6 @@ pushdecl (x) set_identifier_type_value_with_scope (DECL_NAME (x), type, current_binding_level); - if (TREE_CODE (x) == TYPE_DECL - && DECL_ARTIFICIAL (x) - && t != NULL_TREE) - /* We don't want an artificial TYPE_DECL is we already - have another DECL with the same name. */ - need_new_binding = 0; } /* Multiple external decls of the same identifier ought to match. @@ -3663,7 +3731,8 @@ pushdecl (x) if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x)) TREE_PUBLIC (name) = 1; - if (need_new_binding) + if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x) + && t != NULL_TREE)) { if (TREE_CODE (x) == FUNCTION_DECL) my_friendly_assert @@ -3999,23 +4068,20 @@ push_class_level_binding (name, x) if (!class_binding_level) return; - if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x) - && purpose_member (name, class_binding_level->class_shadowed)) - return; - /* If this declaration shadows a declaration from an enclosing class, then we will need to restore IDENTIFIER_CLASS_VALUE when we leave this class. Record the shadowed declaration here. */ maybe_push_cache_obstack (); class_binding_level->class_shadowed - = tree_cons (name, IDENTIFIER_CLASS_VALUE (name), - class_binding_level->class_shadowed); + = tree_cons (name, IDENTIFIER_CLASS_VALUE (name), + class_binding_level->class_shadowed); + TREE_TYPE (class_binding_level->class_shadowed) + = x; pop_obstacks (); /* Put the binding on the stack of bindings for the identifier, and update IDENTIFIER_CLASS_VALUE. */ push_class_binding (name, x); - IDENTIFIER_CLASS_VALUE (name) = x; obstack_ptr_grow (&decl_obstack, x); } @@ -4155,8 +4221,8 @@ push_overloaded_decl (decl, forgettable) /* We only create an OVERLOAD if there was a previous binding at this level. In that case, we need to remove the old binding and replace it with the new binding. We must also run - through the NAMES on the current binding level to update the - chain. */ + through the NAMES on the binding level where the name was + bound to update the chain. */ if (TREE_CODE (new_binding) == OVERLOAD) { tree *d; @@ -4168,11 +4234,21 @@ push_overloaded_decl (decl, forgettable) || (TREE_CODE (*d) == TREE_LIST && TREE_VALUE (*d) == old)) { - *d = TREE_CHAIN (*d); - break; + if (TREE_CODE (*d) == TREE_LIST) + /* Just replace the old binding with the new. */ + TREE_VALUE (*d) = new_binding; + else + /* Build a TREE_LIST to wrap the OVERLOAD. */ + *d = build_tree_list (NULL_TREE, new_binding); + + /* And update the CPLUS_BINDING node. */ + BINDING_VALUE (IDENTIFIER_BINDING (name)) + = new_binding; + return decl; } - pop_binding (name); + /* We should always find a previous binding in this case. */ + my_friendly_abort (0); } /* Install the new binding. */ @@ -4887,9 +4963,16 @@ lookup_namespace_name (namespace, name) my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370); - /* This happens for A::B<int> when B is a namespace. */ if (TREE_CODE (name) == NAMESPACE_DECL) + /* This happens for A::B<int> when B is a namespace. */ return name; + else if (TREE_CODE (name) == TEMPLATE_DECL) + { + /* This happens for A::B where B is a template, and there are no + template arguments. */ + cp_error ("invalid use of `%D'", name); + return error_mark_node; + } my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373); @@ -5321,15 +5404,27 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only) else flags = lookup_flags (prefer_type, namespaces_only); - /* First, look in a non-global scope, carefully avoiding any - class-scope bindings if required. */ + /* First, look in non-namespace scopes. */ val = IDENTIFIER_BINDING (name); - while (val && nonclass && !LOCAL_BINDING_P (val)) - val = TREE_CHAIN (val); - - /* Get the DECL actually bound. */ - if (val) - val = BINDING_VALUE (val); + for (val = IDENTIFIER_BINDING (name); val; val = TREE_CHAIN (val)) + { + if (!LOCAL_BINDING_P (val) && nonclass) + /* We're not looking for class-scoped bindings, so keep going. */ + continue; + + /* If this is the kind of thing we're looking for, we're done. */ + if (qualify_lookup (BINDING_VALUE (val), flags)) + { + val = BINDING_VALUE (val); + break; + } + else if ((flags & LOOKUP_PREFER_TYPES) + && qualify_lookup (BINDING_TYPE (val), flags)) + { + val = BINDING_TYPE (val); + break; + } + } /* If VAL is a type from a dependent base, we're not really supposed to be able to see it; the fact that we can is the "implicit @@ -5342,10 +5437,6 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only) && uses_template_parms (current_class_type)) val = lookup_field (current_class_type, name, 0, 1); - /* Make sure that this binding is the sort of thing we're looking - for. */ - val = qualify_lookup (val, flags); - /* We don't put names from baseclasses onto the IDENTIFIER_BINDING list when we're defining a type. It would probably be simpler to do this, but we don't. So, we must lookup names from base @@ -5361,8 +5452,8 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only) } /* If we found a type from a dependent base class (using the - implicit typename extension), turn it into the TYPE_DECL for a - TYPENAME_TYPE here. */ + implicit typename extension) make sure that there's not some + global name which should be chosen instead. */ if (val && TREE_CODE (val) == TYPE_DECL && IMPLICIT_TYPENAME_P (TREE_TYPE (val))) { @@ -8575,7 +8666,8 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace) return decl; } -/* Create a canonical pointer to member function type. */ +/* Create and return a canonical pointer to member function type, for + TYPE, which is a POINTER_TYPE to a METHOD_TYPE. */ tree build_ptrmemfunc_type (type) @@ -9790,7 +9882,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) /* If this involves a template parameter, it'll be constant, but we don't know what the value is yet. */ - if (processing_template_decl) + if (uses_template_parms (size)) { /* Resolve a qualified reference to an enumerator or static const data member of ours. */ @@ -10141,9 +10233,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) type = build_reference_type (type); } else if (TREE_CODE (type) == METHOD_TYPE) - { - type = build_ptrmemfunc_type (build_pointer_type (type)); - } + type = build_ptrmemfunc_type (build_pointer_type (type)); else type = build_pointer_type (type); @@ -13976,7 +14066,7 @@ finish_method (decl) for (link = current_binding_level->names; link; link = TREE_CHAIN (link)) { if (DECL_NAME (link) != NULL_TREE) - pop_binding (DECL_NAME (link)); + pop_binding (DECL_NAME (link), link); my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163); DECL_CONTEXT (link) = NULL_TREE; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 630e262183f..fba06619cfb 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3547,7 +3547,7 @@ reparse_absdcl_as_expr (type, decl) return build_functional_cast (type, NULL_TREE); /* recurse */ - decl = reparse_decl_as_expr (type, TREE_OPERAND (decl, 0)); + decl = reparse_absdcl_as_expr (type, TREE_OPERAND (decl, 0)); decl = build_x_function_call (decl, NULL_TREE, current_class_ref); @@ -3770,11 +3770,28 @@ build_expr_from_tree (t) TREE_OPERAND (ref, 1), build_expr_from_tree (TREE_OPERAND (t, 2))); } - return build_method_call - (build_expr_from_tree (TREE_OPERAND (t, 1)), - TREE_OPERAND (t, 0), - build_expr_from_tree (TREE_OPERAND (t, 2)), - NULL_TREE, LOOKUP_NORMAL); + else + { + tree fn = TREE_OPERAND (t, 0); + + /* We can get a TEMPLATE_ID_EXPR here on code like: + + x->f<2>(); + + so we must resolve that. However, we can also get things + like a BIT_NOT_EXPR here, when referring to a destructor, + and things like that are not correctly resolved by + build_expr_from_tree. So, just use build_expr_from_tree + when we really need it. */ + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) + fn = build_expr_from_tree (fn); + + return build_method_call + (build_expr_from_tree (TREE_OPERAND (t, 1)), + fn, + build_expr_from_tree (TREE_OPERAND (t, 2)), + NULL_TREE, LOOKUP_NORMAL); + } case CALL_EXPR: if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bdf85dd760f..ece3f29c841 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2710,9 +2710,6 @@ convert_nontype_argument (type, expr) case RECORD_TYPE: { - tree fns; - tree fn; - if (!TYPE_PTRMEMFUNC_P (type)) /* This handles templates like template<class T, T t> void f(); @@ -2743,16 +2740,11 @@ convert_nontype_argument (type, expr) if (TREE_CODE (expr) != ADDR_EXPR) return error_mark_node; - fns = TREE_OPERAND (expr, 0); - - fn = instantiate_type (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)), - fns, 0); + expr = instantiate_type (type, expr, 0); - if (fn == error_mark_node) + if (expr == error_mark_node) return error_mark_node; - expr = build_unary_op (ADDR_EXPR, fn, 0); - my_friendly_assert (same_type_p (type, TREE_TYPE (expr)), 0); return expr; @@ -6972,8 +6964,7 @@ maybe_adjust_types_for_deduction (strict, parm, arg) deduction. */ if (TREE_CODE (*arg) == ARRAY_TYPE) *arg = build_pointer_type (TREE_TYPE (*arg)); - else if (TREE_CODE (*arg) == FUNCTION_TYPE - || TREE_CODE (*arg) == METHOD_TYPE) + else if (TREE_CODE (*arg) == FUNCTION_TYPE) *arg = build_pointer_type (*arg); else *arg = TYPE_MAIN_VARIANT (*arg); @@ -7163,6 +7154,11 @@ resolve_overloaded_unification (tparms, targs, parm, arg, strict, if (TREE_CODE (arg) == ADDR_EXPR) arg = TREE_OPERAND (arg, 0); + if (TREE_CODE (arg) == COMPONENT_REF) + /* Handle `&x' where `x' is some static or non-static member + function name. */ + arg = TREE_OPERAND (arg, 1); + /* Strip baselink information. */ while (TREE_CODE (arg) == TREE_LIST) arg = TREE_VALUE (arg); @@ -7188,6 +7184,8 @@ resolve_overloaded_unification (tparms, targs, parm, arg, strict, if (subargs) { elem = tsubst (TREE_TYPE (fn), subargs, NULL_TREE); + if (TREE_CODE (elem) == METHOD_TYPE) + elem = build_ptrmemfunc_type (build_pointer_type (elem)); good += try_one_overload (tparms, targs, tempargs, parm, elem, strict, sub_strict, explicit_mask); } @@ -7196,9 +7194,14 @@ resolve_overloaded_unification (tparms, targs, parm, arg, strict, else if (TREE_CODE (arg) == OVERLOAD) { for (; arg; arg = OVL_NEXT (arg)) - good += try_one_overload (tparms, targs, tempargs, parm, - TREE_TYPE (OVL_CURRENT (arg)), - strict, sub_strict, explicit_mask); + { + tree type = TREE_TYPE (OVL_CURRENT (arg)); + if (TREE_CODE (type) == METHOD_TYPE) + type = build_ptrmemfunc_type (build_pointer_type (type)); + good += try_one_overload (tparms, targs, tempargs, parm, + type, + strict, sub_strict, explicit_mask); + } } else my_friendly_abort (981006); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7660d386217..8bb750a6617 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -416,7 +416,7 @@ build_cplus_array_type_1 (elt_type, index_type) saveable_obstack = &permanent_obstack; } - if (processing_template_decl + if (uses_template_parms (elt_type) || uses_template_parms (index_type)) { t = make_node (ARRAY_TYPE); @@ -1467,15 +1467,20 @@ build_exception_variant (type, raises) for (; v; v = TYPE_NEXT_VARIANT (v)) { + tree t; + tree u; + if (TYPE_QUALS (v) != type_quals) continue; - /* @@ This should do set equality, not exact match. */ - if (simple_cst_list_equal (TYPE_RAISES_EXCEPTIONS (v), raises)) - /* List of exceptions raised matches previously found list. + for (t = TYPE_RAISES_EXCEPTIONS (v), u = raises; + t != NULL_TREE && u != NULL_TREE; + t = TREE_CHAIN (t), u = TREE_CHAIN (v)) + if (!same_type_p (TREE_VALUE (t), TREE_VALUE (u))) + break; - @@ Nice to free up storage used in consing up the - @@ list of exceptions raised. */ + if (!t && !u) + /* There's a memory leak here; RAISES is not freed. */ return v; } diff --git a/gcc/testsuite/g++.old-deja/g++.eh/tmpl3.C b/gcc/testsuite/g++.old-deja/g++.eh/tmpl3.C index 738e7d85825..521315e17e2 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/tmpl3.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/tmpl3.C @@ -3,9 +3,9 @@ // Posted by Trevor Taylor <ttaylor@powerup.com.au> template<class T> struct A { - void X() throw(T); // gets bogus error - previous decl - XFAIL *-*-* + void X() throw(T); }; template<class T> inline void A<T>::X() -throw(T) { } // gets bogus error - different throws - XFAIL *-*-* +throw(T) { } diff --git a/gcc/testsuite/g++.old-deja/g++.ns/crash3.C b/gcc/testsuite/g++.old-deja/g++.ns/crash3.C new file mode 100644 index 00000000000..842ed090bcc --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.ns/crash3.C @@ -0,0 +1,10 @@ +// Build don't link: + +namespace N { + template <class T> struct S; +}; + +void f() +{ + N::S(); // ERROR - invalid use of template +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/expr1.C b/gcc/testsuite/g++.old-deja/g++.other/expr1.C index 0f5fdcf12ee..fece8d48c29 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/expr1.C +++ b/gcc/testsuite/g++.old-deja/g++.other/expr1.C @@ -1,11 +1,9 @@ // Build don't link: -// crash test - XFAIL *-*-* - // Simplified from bug report by Trevor Taylor <ttaylor@powerup.com.au> struct T { - int operator()(int) { } + int operator()(int) { } // ERROR - candidate }; int main() { diff --git a/gcc/testsuite/g++.old-deja/g++.other/lookup8.C b/gcc/testsuite/g++.old-deja/g++.other/lookup8.C new file mode 100644 index 00000000000..f81572ab260 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/lookup8.C @@ -0,0 +1,14 @@ +// Build don't link: + +struct S { + int A; + struct A { + enum { a = 0 }; + }; + + void f(); +}; + +void S::f() { + A = A::a; +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/array2.C b/gcc/testsuite/g++.old-deja/g++.pt/array2.C new file mode 100644 index 00000000000..6c5810ed77b --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/array2.C @@ -0,0 +1,14 @@ +// Build don't link: + +template<int N, class C> +class Bar {}; + +template<class C> +class Huh {}; + +template<int N> +void foo(const Bar<N,Huh<float[1]> > &x) {} + +int main() { + foo(Bar<3,Huh<float[1]> >()); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp81.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp81.C new file mode 100644 index 00000000000..1584f88b802 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp81.C @@ -0,0 +1,24 @@ +// Build don't link: + +template <int i> class a +{ +public : +int k; + +template <int j> int f() const { return this->f<j-1>(); } + +int g() const { return f<i>(); }; +}; + +template <> +template <> +int a<2>::f<0>() const { + return 0; +} + +int main() +{ +a<2> x; +return x.g(); +} + diff --git a/gcc/testsuite/g++.old-deja/g++.pt/overload11.C b/gcc/testsuite/g++.old-deja/g++.pt/overload11.C new file mode 100644 index 00000000000..300d91ea2b8 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/overload11.C @@ -0,0 +1,27 @@ +// Build don't run: + +template <class T> +int f(int (*fn)(T)) +{ + return (*fn)(3); +} + +struct S { + static int g(int) { return 1; } + static void g(); + + int h(); +}; + +int S::h() +{ + return f(&g); +} + + +int main() +{ + S s; + if (s.h () != 1) + return 1; +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem4.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem4.C new file mode 100644 index 00000000000..139be923550 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem4.C @@ -0,0 +1,28 @@ +// Build don't run: + +template<class T,class T1> +int connect_to_method(T* receiver, + int (T1::*method)()) +{ + return (receiver->*method)(); +} + +class Gtk_Container +{ +public: + int remove_callback() { return 1; } + void remove_callback(int); + int f(); +}; + +int Gtk_Container::f() +{ + return connect_to_method(this, &Gtk_Container::remove_callback); +} + +int main() +{ + Gtk_Container gc; + if (gc.f () != 1) + return 1; +} |