+2004-03-19 Mark Mitchell <mark@codesourcery.com>
+
+ * call.c (build_op_delete_call): Do not forget the placement
+ arguments when iterating through mutiple delete operators.
+
+ * cp-tree.h (svaed_scope): Remove last_parms.
+ (NEW_DELETE_OPNAME_P): New macro.
+ (last_function_parms): Remove.
+ (do_friend): Adjust prototype.
+ * decl.c (grokparms): Return the PARM_DECLs directly, rather than
+ using last_function_parms.
+ (grokfndecl): Take the PARM_DECLs as an argument, rather than
+ using last_function_parms.
+ (grokdeclarator): Adjust accordingly. Do not form METHOD_TYPEs
+ for class-specific operator new and operator delete.
+ (grok_op_properties): Do not look for allocation functions with
+ METHOD_TYPEs.
+ (start_function): Use DECL_ARGUMENTS instead of
+ last_function_parms.
+ * decl.h (last_function_parms): Do not declare.
+ * decl2.c (grokclassfn): Do not use last_function_parms.
+ * friend.c (do_friend): Remove parmdecls parameter.
+ * name-lookup.c (push_to_top_level): Do not save last_function_parms.
+ (pop_from_top_level): Do not restore it.
+ * pt.c (check_explicit_specialization): Do not adjust
+ last_function_parms.
+
+ * name-lookup.c (do_local_using_decl): Create a local binding for
+ types brought in via using declarations.
+
+ * name-lookup.c (lookup_arg_dependent): Handle block-scope
+ function declarations correctly.
+
+ * semantics.c (finish_id_expression): Correct handling of
+ conversion operators to dependent types.
+
+ * typeck.c (lookup_destructor): Allow the use of destructors from
+ base classes.
+
2004-03-19 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* cxx-pretty-print.c (pp_cxx_unqualified_id): Use
/* On the first pass, check the rest of the arguments. */
if (pass == 0)
{
- while (argtypes && t)
+ tree a = argtypes;
+ while (a && t)
{
- if (!same_type_p (TREE_VALUE (argtypes),
- TREE_VALUE (t)))
+ if (!same_type_p (TREE_VALUE (a), TREE_VALUE (t)))
break;
- argtypes = TREE_CHAIN (argtypes);
+ a = TREE_CHAIN (a);
t = TREE_CHAIN (t);
}
- if (!argtypes && !t)
+ if (!a && !t)
break;
}
/* On the second pass, the second argument must be
tree x_previous_class_type;
tree x_previous_class_values;
tree x_saved_tree;
- tree last_parms;
HOST_WIDE_INT x_processing_template_decl;
int x_processing_specialization;
#define current_function_return_value \
(cp_function_chain->x_return_value)
+/* True if NAME is the IDENTIFIER_NODE for an overloaded "operator
+ new" or "operator delete". */
+#define NEW_DELETE_OPNAME_P(NAME) \
+ ((NAME) == ansi_opname (NEW_EXPR) \
+ || (NAME) == ansi_opname (VEC_NEW_EXPR) \
+ || (NAME) == ansi_opname (DELETE_EXPR) \
+ || (NAME) == ansi_opname (VEC_DELETE_EXPR))
+
#define ansi_opname(CODE) \
(operator_name_info[(int) (CODE)].identifier)
#define ansi_assopname(CODE) \
extern void warn_extern_redeclared_static (tree, tree);
extern bool have_extern_spec;
-extern GTY(()) tree last_function_parms;
/* in decl2.c */
extern bool check_java_method (tree);
extern int is_friend (tree, tree);
extern void make_friend_class (tree, tree, bool);
extern void add_friend (tree, tree, bool);
-extern tree do_friend (tree, tree, tree, tree, tree, enum overload_flags, tree, int);
+extern tree do_friend (tree, tree, tree, tree, enum overload_flags, tree, int);
/* in init.c */
extern tree expand_member_init (tree);
#include "debug.h"
#include "timevar.h"
-static tree grokparms (tree);
+static tree grokparms (tree, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
static int unary_op_p (enum tree_code);
static void push_local_name (tree);
static tree grok_reference_init (tree, tree, tree, tree *);
-static tree grokfndecl (tree, tree, tree, tree, int,
+static tree grokfndecl (tree, tree, tree, tree, tree, int,
enum overload_flags, tree,
tree, int, int, int, int, int, int, tree);
static tree grokvardecl (tree, tree, RID_BIT_TYPE *, int, int, tree);
tree integer_two_node, integer_three_node;
-/* Similar, for last_function_parm_tags. */
-tree last_function_parms;
-
/* A list of all LABEL_DECLs in the function that have names. Here so
we can clear out their names' definitions at the end of the
function, and so we can check the validity of jumps to these labels. */
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
DECLARATOR is the function's name.
+ PARMS is a chain of PARM_DECLs for the function.
VIRTUALP is truthvalue of whether the function is virtual or not.
FLAGS are to be passed through to `grokclassfn'.
QUALS are qualifiers indicating whether the function is `const'
grokfndecl (tree ctype,
tree type,
tree declarator,
+ tree parms,
tree orig_declarator,
int virtualp,
enum overload_flags flags,
type = build_exception_variant (type, raises);
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
+ DECL_ARGUMENTS (decl) = parms;
/* Propagate volatile out from type to decl. */
if (TYPE_VOLATILE (type))
TREE_THIS_VOLATILE (decl) = 1;
if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
- {
- /* Remove the `this' parm added by grokclassfn.
- XXX Isn't this done in start_function, too? */
- revert_static_member_fn (decl);
- last_function_parms = TREE_CHAIN (last_function_parms);
- }
+ /* Remove the `this' parm added by grokclassfn.
+ XXX Isn't this done in start_function, too? */
+ revert_static_member_fn (decl);
if (old_decl && DECL_ARTIFICIAL (old_decl))
error ("definition of implicitly-declared `%D'", old_decl);
tree in_namespace = NULL_TREE;
tree returned_attrs = NULL_TREE;
tree scope = NULL_TREE;
+ tree parms = NULL_TREE;
RIDBIT_RESET_ALL (specbits);
if (decl_context == FUNCDEF)
declarator = TREE_OPERAND (declarator, 0);
- arg_types = grokparms (inner_parms);
+ arg_types = grokparms (inner_parms, &parms);
if (declarator && flags == DTOR_FLAG)
{
{
error ("destructors may not have parameters");
arg_types = void_list_node;
- last_function_parms = NULL_TREE;
+ parms = NULL_TREE;
}
}
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
- if (current_class_type == NULL_TREE || friendp)
+ if (NEW_DELETE_OPNAME_P (sname))
+ /* Overloaded operator new and operator delete
+ are always static functions. */
+ ;
+ else if (current_class_type == NULL_TREE || friendp)
type
= build_method_type_directly (ctype,
TREE_TYPE (type),
type = build_cplus_array_type (TREE_TYPE (type), NULL_TREE);
/* Detect where we're using a typedef of function type to declare a
- function. last_function_parms will not be set, so we must create
- it now. */
+ function. PARMS will not be set, so we must create it now. */
if (type == typedef_type && TREE_CODE (type) == FUNCTION_TYPE)
{
decls = decl;
}
- last_function_parms = nreverse (decls);
+ parms = nreverse (decls);
}
/* If this is a type name (such as, in a cast or sizeof),
return void_type_node;
}
- if (declarator == ansi_opname (NEW_EXPR)
- || declarator == ansi_opname (VEC_NEW_EXPR)
- || declarator == ansi_opname (DELETE_EXPR)
- || declarator == ansi_opname (VEC_DELETE_EXPR))
+ if (NEW_DELETE_OPNAME_P (declarator))
{
if (virtualp)
{
decl = grokfndecl (ctype, type,
TREE_CODE (declarator) != TEMPLATE_ID_EXPR
? declarator : dname,
+ parms,
declarator,
virtualp, flags, quals, raises,
friendp ? -1 : 0, friendp, publicp, inlinep,
decl = grokfndecl (ctype, type,
TREE_CODE (declarator) != TEMPLATE_ID_EXPR
? declarator : dname,
+ parms,
declarator,
virtualp, flags, quals, raises,
friendp ? -1 : 0, friendp, 1, 0, funcdef_flag,
}
decl = do_friend (ctype, declarator, decl,
- last_function_parms, *attrlist,
- flags, quals, funcdef_flag);
+ *attrlist, flags, quals, funcdef_flag);
return decl;
}
else
virtualp = 0;
}
}
- else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
+ else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
+ && !NEW_DELETE_OPNAME_P (original_name))
type = build_method_type_directly (ctype,
TREE_TYPE (type),
TYPE_ARG_TYPES (type));
|| RIDBIT_SETP (RID_EXTERN, specbits)
|| !RIDBIT_SETP (RID_STATIC, specbits));
- decl = grokfndecl (ctype, type, original_name, declarator,
+ decl = grokfndecl (ctype, type, original_name, parms, declarator,
virtualp, flags, quals, raises,
1, friendp,
publicp, inlinep, funcdef_flag,
flag. If unset, we append void_list_node. A parmlist declared
as `(void)' is accepted as the empty parmlist.
- Also set last_function_parms to the chain of PARM_DECLs. */
+ *PARMS is set to the chain of PARM_DECLs created. */
static tree
-grokparms (tree first_parm)
+grokparms (tree first_parm, tree *parms)
{
tree result = NULL_TREE;
tree decls = NULL_TREE;
result = nreverse (result);
if (!ellipsis)
result = chainon (result, void_list_node);
- last_function_parms = decls;
+ *parms = decls;
return result;
}
}
if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR)
- {
- /* When the compiler encounters the definition of A::operator new, it
- doesn't look at the class declaration to find out if it's static. */
- if (methodp)
- revert_static_member_fn (decl);
-
- TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
- }
+ TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
else if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
- {
- if (methodp)
- revert_static_member_fn (decl);
-
- TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
- }
+ TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
else
{
/* An operator function must either be a non-static member function
else
doing_friend = 1;
}
-
- last_function_parms = DECL_ARGUMENTS (decl1);
}
else
{
&& TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
{
revert_static_member_fn (decl1);
- last_function_parms = TREE_CHAIN (last_function_parms);
ctype = NULL_TREE;
}
/* Save the parm names or decls from this function's declarator
where store_parm_decls will find them. */
- current_function_parms = last_function_parms;
+ current_function_parms = DECL_ARGUMENTS (decl1);
/* Make sure the parameter and return types are reasonable. When
you declare a function, these types can be incomplete, but they
/* We need this in here to get the decl_context definition. */
extern tree grokdeclarator (tree, tree, enum decl_context, int, tree*);
-/* Parsing a function declarator leaves a list of parameter names
- or a chain or parameter decls here. */
-extern GTY(()) tree last_function_parms;
-
#ifdef DEBUG_CP_BINDING_LEVELS
/* Purely for debugging purposes. */
extern int debug_bindings_indentation;
qual_type = cp_build_qualified_type (type, this_quals);
parm = build_artificial_parm (this_identifier, qual_type);
c_apply_type_quals_to_decl (this_quals, parm);
- TREE_CHAIN (parm) = last_function_parms;
- last_function_parms = parm;
+ TREE_CHAIN (parm) = DECL_ARGUMENTS (function);
+ DECL_ARGUMENTS (function) = parm;
}
- DECL_ARGUMENTS (function) = last_function_parms;
DECL_CONTEXT (function) = ctype;
if (flags == DTOR_FLAG)
DECL is the FUNCTION_DECL that the friend is.
- In case we are parsing a friend which is part of an inline
- definition, we will need to store PARM_DECL chain that comes
- with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL.
-
FLAGS is just used for `grokclassfn'.
QUALS say what special qualifies should apply to the object
pointed to by `this'. */
tree
-do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
+do_friend (tree ctype, tree declarator, tree decl,
tree attrlist, enum overload_flags flags, tree quals,
int funcdef_flag)
{
Note that because classes all wind up being top-level
in their scope, their friend wind up in top-level scope as well. */
- DECL_ARGUMENTS (decl) = parmdecls;
if (funcdef_flag)
SET_DECL_FRIEND_CONTEXT (decl, current_class_type);
push_local_binding (name, newval, PUSH_USING);
}
if (newtype)
- set_identifier_type_value (name, newtype);
+ {
+ push_local_binding (name, newtype, PUSH_USING);
+ set_identifier_type_value (name, newtype);
+ }
/* Emit debug info. */
if (!processing_template_decl)
we found were brought into the current namespace via a using
declaration, we have not really checked the namespace from which
they came. Therefore, we check all namespaces here -- unless the
- function we have is from the current namespace. */
+ function we have is from the current namespace. Even then, we
+ must check all namespaces if the function is a local
+ declaration; any other declarations present at namespace scope
+ should be visible during argument-dependent lookup. */
if (fns)
fn = OVL_CURRENT (fns);
if (fn && TREE_CODE (fn) == FUNCTION_DECL
- && CP_DECL_CONTEXT (fn) != current_decl_namespace ())
+ && (CP_DECL_CONTEXT (fn) != current_decl_namespace ()
+ || DECL_LOCAL_FUNCTION_P (fn)))
k.namespaces = NULL_TREE;
else
/* Setting NAMESPACES is purely an optimization; it prevents
s->bindings = b;
s->need_pop_function_context = need_pop;
s->function_decl = current_function_decl;
- s->last_parms = last_function_parms;
scope_chain = s;
current_function_decl = NULL_TREE;
if (s->need_pop_function_context)
pop_function_context_from (NULL_TREE);
current_function_decl = s->function_decl;
- last_function_parms = s->last_parms;
timevar_pop (TV_NAME_LOOKUP);
}
/* If we thought that the DECL was a member function, but it
turns out to be specializing a static member function,
- make DECL a static member function as well. We also have
- to adjust last_function_parms to avoid confusing
- start_function later. */
+ make DECL a static member function as well. */
if (DECL_STATIC_FUNCTION_P (tmpl)
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
- {
- revert_static_member_fn (decl);
- last_function_parms = TREE_CHAIN (last_function_parms);
- }
+ revert_static_member_fn (decl);
/* If this is a specialization of a member template of a
template class. In we want to return the TEMPLATE_DECL,
if (decl == error_mark_node)
{
/* Name lookup failed. */
- if (scope && (!TYPE_P (scope) || !dependent_type_p (scope)))
+ if (scope
+ && (!TYPE_P (scope)
+ || (!dependent_type_p (scope)
+ && !(TREE_CODE (id_expression) == IDENTIFIER_NODE
+ && IDENTIFIER_TYPENAME_P (id_expression)
+ && dependent_type_p (TREE_TYPE (id_expression))))))
{
- /* Qualified name lookup failed, and the qualifying name
- was not a dependent type. That is always an
- error. */
+ /* If the qualifying type is non-dependent (and the name
+ does not name a conversion operator to a dependent
+ type), issue an error. */
qualified_name_lookup_error (scope, id_expression);
return error_mark_node;
}
*idk = CP_ID_KIND_UNQUALIFIED;
return id_expression;
}
+ else
+ decl = id_expression;
}
/* If DECL is a variable that would be out of scope under
ANSI/ISO rules, but in scope in the ARM, name lookup
{
tree object_type = TREE_TYPE (object);
tree dtor_type = TREE_OPERAND (dtor_name, 0);
+ tree expr;
if (scope && !check_dtor_name (scope, dtor_name))
{
scope, dtor_type);
return error_mark_node;
}
- if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
+ if (!DERIVED_FROM_P (dtor_type, TYPE_MAIN_VARIANT (object_type)))
{
error ("the type being destroyed is `%T', but the destructor refers to `%T'",
TYPE_MAIN_VARIANT (object_type), dtor_type);
return error_mark_node;
}
- if (!TYPE_HAS_DESTRUCTOR (object_type))
+ if (!TYPE_HAS_DESTRUCTOR (dtor_type))
return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
dtor_type);
- return lookup_member (object_type, complete_dtor_identifier,
+ expr = lookup_member (dtor_type, complete_dtor_identifier,
/*protect=*/1, /*want_type=*/false);
+ expr = (adjust_result_of_qualified_name_lookup
+ (expr, dtor_type, object_type));
+ return expr;
}
/* This function is called by the parser to process a class member
+2004-03-19 Mark Mitchell <mark@codesourcery.com>
+
+ * g++.dg/init/placement3.C: New test.
+
+ * g++.dg/template/spec13.C: New test.
+
+ * g++.dg/lookup/using11.C: New test.
+
+ * g++.dg/lookup/koenig3.C: New test.
+
+ * g++.dg/template/operator2.C: New test.
+
+ * g++.dg/expr/dtor3.C: New test.
+ * g++.old-deja/g++.brendan/crash15.C: Remove incorrect dg-error
+ marker.
+ * g++.old-deja/g++.law/visibility28.C: Likewise.
+
2004-03-19 Paolo Bonzini <bonzini@gnu.org>
* gcc.dg/altivec-6.c: Use vector_size attribute, not mode.
--- /dev/null
+struct B {
+ ~B();
+};
+struct D : public B {
+ ~D();
+};
+
+void f(D d) {
+ d.B::~B();
+}
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+extern "C" void *malloc (size_t);
+
+int i;
+
+struct S {
+ S(int) {
+ throw 3;
+ }
+
+ void *operator new(size_t s, int) {
+ ++i;
+ return malloc (s);
+ }
+
+ void operator delete(void *, int) {
+ --i;
+ }
+
+ void operator delete(void *, int, int) ;
+};
+
+int main () {
+ try {
+ new (7) S (12);
+ } catch (int) {
+ if (i)
+ return 1;
+ }
+}
--- /dev/null
+extern "C" void abort ();
+
+struct S {
+};
+void f(S, int) { abort(); }
+void f(S, double) {}
+
+S s;
+
+int main() {
+ extern void f(S, int);
+ f(s, 3.0);
+}
--- /dev/null
+namespace N1 {
+ enum e { a };
+ void e(char);
+}
+
+void f() {
+ using N1::e;
+ enum e x;
+}
--- /dev/null
+template <typename T> struct A {};
+
+struct B {
+ operator A<B>();
+};
+
+template <typename T>
+void f() { B::operator A<T>; }
--- /dev/null
+// { dg-options "-w" }
+
+template <typename T>
+struct S {
+ int i;
+ template <typename U> void f(U) {}
+};
+
+template<>
+template <typename U>
+void S<int>::f(U) { i; }
+
+void f() {
+ S<int> s;
+ s.f<int>(3);
+}
main() {
std::cout << "starting\n";
B b;
- b.~A();// { dg-error "" } destructor
+ b.~A();
std::cout << "done\n";
}
class D : public B {
public:
virtual ~D() { printf( "D::~D\n"); }
- void operator = ( int i) { this->~B(); }// { dg-error "" } D has no ~B part to it
+ void operator = ( int i) { this->~B(); }
};
int