+2000-12-20 Jason Merrill <jason@redhat.com>
+
+ * pt.c (tsubst_decl): A FUNCTION_DECL has DECL_RESULT, not
+ DECL_TEMPLATE_RESULT.
+
+ * search.c (lookup_field_r): Call lookup_fnfields_1, not
+ lookup_fnfields_here.
+
+ * parse.y (typename_sub2): Return the TYPE_DECL, not the type.
+
+ * call.c (build_object_call): Also allow conversions that return
+ reference to pointer to function.
+ (add_conv_candidate): Handle totype being ref to ptr to fn.
+ (build_field_call): Also allow members of type reference to function.
+ Lose support for calling pointer to METHOD_TYPE fields.
+
+ * error.c (dump_expr): Handle *_CAST_EXPR.
+
+ * typeck2.c (build_scoped_ref): Always convert to the naming class.
+
+ * tree.c (break_out_cleanups): Lose.
+ * cp-tree.h: Remove prototype.
+ * typeck.c (build_component_ref): Don't break_out_cleanups.
+ (build_compound_expr): Likewise.
+ * semantics.c (finish_expr_stmt): Likewise.
+
2000-12-20 Richard Henderson <rth@redhat.com>
* cp-tree.h: Update declarations.
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
instance, parms, NULL_TREE);
- else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
- {
- if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
- return build_function_call (instance, parms);
- else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance)))
- == METHOD_TYPE)
- return build_function_call
- (instance, tree_cons (NULL_TREE, instance_ptr, parms));
- }
+ else if (TREE_CODE (TREE_TYPE (instance)) == FUNCTION_TYPE
+ || (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (instance)))
+ == FUNCTION_TYPE)))
+ return build_function_call (instance, parms);
}
return NULL_TREE;
tree fn, obj, arglist;
{
tree totype = TREE_TYPE (TREE_TYPE (fn));
- tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (totype));
- int i, len = list_length (arglist) + 1;
- tree convs = make_tree_vec (len);
- tree parmnode = parmlist;
- tree argnode = arglist;
- int viable = 1;
- int flags = LOOKUP_NORMAL;
+ int i, len, viable, flags;
+ tree parmlist, convs, parmnode, argnode;
+
+ for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
+ parmlist = TREE_TYPE (parmlist);
+ parmlist = TYPE_ARG_TYPES (parmlist);
+
+ len = list_length (arglist) + 1;
+ convs = make_tree_vec (len);
+ parmnode = parmlist;
+ argnode = arglist;
+ viable = 1;
+ flags = LOOKUP_NORMAL;
/* Don't bother looking up the same type twice. */
if (candidates && candidates->fn == totype)
tree totype = TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns)));
if ((TREE_CODE (totype) == POINTER_TYPE
- || TREE_CODE (totype) == REFERENCE_TYPE)
- && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+ && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+ || (TREE_CODE (totype) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+ || (TREE_CODE (totype) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (totype)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (totype))) == FUNCTION_TYPE))
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
extern int lvalue_or_else PARAMS ((tree, const char *));
extern tree build_cplus_new PARAMS ((tree, tree));
extern tree get_target_expr PARAMS ((tree));
-extern tree break_out_cleanups PARAMS ((tree));
extern tree break_out_calls PARAMS ((tree));
extern tree build_cplus_method_type PARAMS ((tree, tree, tree));
extern tree build_cplus_staticfn_type PARAMS ((tree, tree, tree));
}
break;
+ case STATIC_CAST_EXPR:
+ output_add_string (scratch_buffer, "static_cast<");
+ goto cast;
+ case REINTERPRET_CAST_EXPR:
+ output_add_string (scratch_buffer, "reinterpret_cast<");
+ goto cast;
+ case CONST_CAST_EXPR:
+ output_add_string (scratch_buffer, "const_cast<");
+ goto cast;
+ case DYNAMIC_CAST_EXPR:
+ output_add_string (scratch_buffer, "dynamic_cast<");
+ cast:
+ dump_type (TREE_TYPE (t), flags);
+ output_add_string (scratch_buffer, ">(");
+ dump_expr (TREE_OPERAND (t, 0), flags);
+ print_right_paren (scratch_buffer);
+ break;
+
case LOOKUP_EXPR:
print_tree_identifier (scratch_buffer, TREE_OPERAND (t, 0));
break;
{
if (TREE_CODE ($1) == IDENTIFIER_NODE)
cp_error ("`%T' is not a class or namespace", $1);
+ else if (TREE_CODE ($1) == TYPE_DECL)
+ $$ = TREE_TYPE ($1);
}
| typename_sub1 typename_sub2
{
= make_typename_type ($1, $3, /*complain=*/1); }
;
+/* This needs to return a TYPE_DECL for simple names so that we don't
+ forget what name was used. */
typename_sub2:
TYPENAME SCOPE
{
- if (TREE_CODE ($1) != IDENTIFIER_NODE)
- $1 = lastiddecl;
+ if (TREE_CODE ($1) != TYPE_DECL)
+ $$ = lastiddecl;
/* Retrieve the type for the identifier, which might involve
some computation. */
- got_scope = $$ = complete_type (IDENTIFIER_TYPE_VALUE ($1));
+ got_scope = complete_type (TREE_TYPE ($$));
if ($$ == error_mark_node)
cp_error ("`%T' is not a class or namespace", $1);
}
| SELFNAME SCOPE
{
- if (TREE_CODE ($1) != IDENTIFIER_NODE)
+ if (TREE_CODE ($1) != TYPE_DECL)
$$ = lastiddecl;
- got_scope = $$ = complete_type (TREE_TYPE ($$));
+ got_scope = complete_type (TREE_TYPE ($$));
}
| template_type SCOPE
{ got_scope = $$ = complete_type (TREE_TYPE ($$)); }
DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args,
/*complain=*/1, t);
- DECL_TEMPLATE_RESULT (r) = NULL_TREE;
+ DECL_RESULT (r) = NULL_TREE;
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
/* Very similar to lookup_fnfields_1 but it ensures that at least one
function was declared inside the class given by TYPE. It really should
- only return functions that match the given TYPE. */
+ only return functions that match the given TYPE. Therefore, it should
+ only be called for situations that ignore using-declarations, such as
+ determining overrides. */
static int
lookup_fnfields_here (type, name)
with the same name, the type is hidden by the function. */
if (!lfi->want_type)
{
- int idx = lookup_fnfields_here (type, lfi->name);
+ int idx = lookup_fnfields_1 (type, lfi->name);
if (idx >= 0)
nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
}
if (stmts_are_full_exprs_p ())
expr = convert_to_void (expr, "statement");
- if (!processing_template_decl)
- expr = break_out_cleanups (expr);
-
r = add_stmt (build_stmt (EXPR_STMT, expr));
}
return build_target_expr_with_type (init, TREE_TYPE (init));
}
-/* Recursively search EXP for CALL_EXPRs that need cleanups and replace
- these CALL_EXPRs with tree nodes that will perform the cleanups. */
-
-tree
-break_out_cleanups (exp)
- tree exp;
-{
- tree tmp = exp;
-
- if (TREE_CODE (tmp) == CALL_EXPR
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (tmp)))
- return build_cplus_new (TREE_TYPE (tmp), tmp);
-
- while (TREE_CODE (tmp) == NOP_EXPR
- || TREE_CODE (tmp) == CONVERT_EXPR
- || TREE_CODE (tmp) == NON_LVALUE_EXPR)
- {
- if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
- {
- TREE_OPERAND (tmp, 0)
- = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
- TREE_OPERAND (tmp, 0));
- break;
- }
- else
- tmp = TREE_OPERAND (tmp, 0);
- }
- return exp;
-}
-
/* Recursively perform a preorder search EXP for CALL_EXPRs, making
copies where they are found. Returns a deep copy all nodes transitively
containing CALL_EXPRs. */
field_type = cp_build_qualified_type (field_type, type_quals);
}
- ref = fold (build (COMPONENT_REF, field_type,
- break_out_cleanups (datum), field));
+ ref = fold (build (COMPONENT_REF, field_type, datum, field));
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
if (! TREE_SIDE_EFFECTS (first) && ! pedantic)
return rest;
- return build (COMPOUND_EXPR, TREE_TYPE (rest),
- break_out_cleanups (first), rest);
+ return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest);
}
tree
the A part of the C object named by X. In this case,
DATUM would be x, and BASETYPE would be A.
- Note that this is nonconformant; the standard specifies that first
- we look up ii in A, then convert x to an L& and pull out the ii part.
- But narrowing seems to be standard practice, so let's do it anyway. */
+ I used to think that this was nonconformant, that the standard specified
+ that first we look up ii in A, then convert x to an L& and pull out the
+ ii part. But in fact, it does say that we convert x to an A&; A here
+ is known as the "naming class". (jason 2000-12-19) */
tree
build_scoped_ref (datum, basetype)
tree basetype;
{
tree ref;
- tree type = TREE_TYPE (datum);
if (datum == error_mark_node)
return error_mark_node;
- /* Don't do this if it would cause an error or if we're being pedantic. */
- if (! ACCESSIBLY_UNIQUELY_DERIVED_P (basetype, type)
- || pedantic)
- return datum;
-
ref = build_unary_op (ADDR_EXPR, datum, 0);
ref = convert_pointer_to (basetype, ref);
void foo() {
// straight call
C x;
- x.A::ii = 5; // ERROR - L is ambiguous base
- x.A::foo(x.A::ii); // ERROR - L is ambiguous base
+ x.A::ii = 5;
+ x.A::foo(x.A::ii);
// 5.1 Primary expressions
// p 8
struct C : public A {
};
struct D : public C, public B {
- void fun() { C::aa = 10; } // ERROR - conversion to A is ambiguous
+ void fun() { C::aa = 10; }
};
--- /dev/null
+// Test that various calls to non-functions work.
+
+void f () { }
+
+typedef void (*fptr)();
+typedef void (&fref)();
+fptr p = f;
+fref r = f;
+const fptr &pr = p;
+
+struct A {
+ fptr p;
+
+ A (fptr n): p(n) { }
+ operator fptr () { return p; }
+};
+
+struct B {
+ fref r;
+
+ B (fptr n): r(*n) { }
+ operator const fref () { return r; }
+};
+
+struct C {
+ const fptr ≺
+
+ C (fptr n): pr(n) { }
+ operator const fptr& () { return pr; }
+};
+
+int main ()
+{
+ f();
+
+ p();
+ r();
+ pr();
+
+ A a (f);
+ a();
+ a.p();
+
+ B b (f);
+ b();
+ b.r();
+
+ C c (f);
+ c();
+ c.pr();
+}
-// Test that referring to an ambiguous base in name lookup does not
-// interfere with accessing the field, which is not ambiguous.
+// Test that referring to an ambiguous base in name lookup prevents
+// access to the field, even though the field is not ambiguous.
// Build don't link:
};
void E::f() {
- B::i = 0;
+ B::i = 0; // ERROR - B is ambiguous
}
void f () {
E e;
- e.B::i = 0;
+ e.B::i = 0; // ERROR - B is ambiguous
}
--- /dev/null
+// Bug: typename_sub2 returned the type, so we tried to look up "A" in B.
+// Build don't link:
+
+struct A { struct A1 { }; };
+
+struct B {
+ typedef A Q;
+};
+
+struct C: public B::Q::A1 { };
--- /dev/null
+// Test that we can represent static_casts in template arg lists.
+// Build don't link:
+
+template <int I> struct A { };
+
+template <class T> struct B {
+ A<static_cast<T>(3.14)> a;
+};