Commit 4a44a72d by Daniel Kraft Committed by Daniel Kraft

re PR fortran/37425 (Fortran 2003: GENERIC bindings as operators)

2009-08-27  Daniel Kraft  <d@domob.eu>

	PR fortran/37425
	* gfortran.h (gfc_expr): Optionally store base-object in compcall value
	and add a new flag to distinguish assign-calls generated.
	(gfc_find_typebound_proc): Add locus argument.
	(gfc_find_typebound_user_op), (gfc_find_typebound_intrinsic_op): Ditto.
	(gfc_extend_expr): Return if failure was by a real error.
	* interface.c (matching_typebound_op): New routine.
	(build_compcall_for_operator): New routine.
	(gfc_extend_expr): Handle type-bound operators, some clean-up and
	return if failure was by a real error or just by not finding an
	appropriate operator definition.
	(gfc_extend_assign): Handle type-bound assignments.
	* module.c (MOD_VERSION): Incremented.
	(mio_intrinsic_op): New routine.
	(mio_full_typebound_tree): New routine to make typebound-procedures IO
	code reusable for type-bound user operators.
	(mio_f2k_derived): IO of type-bound operators.
	* primary.c (gfc_match_varspec): Initialize new fields in gfc_expr and
	pass locus to gfc_find_typebound_proc.
	* resolve.c (resolve_operator): Only output error about no matching
	interface if gfc_extend_expr did not already fail with an error.
	(extract_compcall_passed_object): Use specified base-object if present.
	(update_compcall_arglist): Handle ignore_pass field.
	(resolve_ordinary_assign): Update to handle extended code for
	type-bound assignments, too.
	(resolve_code): Handle EXEC_ASSIGN_CALL statement code.
	(resolve_tb_generic_targets): Pass locus to gfc_find_typebound_proc.
	(resolve_typebound_generic), (resolve_typebound_procedure): Ditto.
	(resolve_typebound_intrinsic_op), (resolve_typebound_user_op): Ditto.
	(ensure_not_abstract_walker), (resolve_fl_derived): Ditto.
	(resolve_typebound_procedures): Remove not-implemented error.
	(resolve_typebound_call): Handle assign-call flag.
	* symbol.c (find_typebound_proc_uop): New argument to pass locus for
	error message about PRIVATE, verify that a found procedure is not marked
	as erraneous.
	(gfc_find_typebound_intrinsic_op): Ditto.
	(gfc_find_typebound_proc), (gfc_find_typebound_user_op): New locus arg.

2009-08-27  Daniel Kraft  <d@domob.eu>

	PR fortran/37425
	* gfortran.dg/impure_assignment_1.f90: Change expected error message.
	* gfortran.dg/typebound_operator_1.f03: Remove check for not-implemented
	error and fix problem with recursive assignment.
	* gfortran.dg/typebound_operator_2.f03: No not-implemented check.
	* gfortran.dg/typebound_operator_3.f03: New test.
	* gfortran.dg/typebound_operator_4.f03: New test.

From-SVN: r151140
parent c6a21142
2009-08-27 Daniel Kraft <d@domob.eu>
PR fortran/37425
* gfortran.h (gfc_expr): Optionally store base-object in compcall value
and add a new flag to distinguish assign-calls generated.
(gfc_find_typebound_proc): Add locus argument.
(gfc_find_typebound_user_op), (gfc_find_typebound_intrinsic_op): Ditto.
(gfc_extend_expr): Return if failure was by a real error.
* interface.c (matching_typebound_op): New routine.
(build_compcall_for_operator): New routine.
(gfc_extend_expr): Handle type-bound operators, some clean-up and
return if failure was by a real error or just by not finding an
appropriate operator definition.
(gfc_extend_assign): Handle type-bound assignments.
* module.c (MOD_VERSION): Incremented.
(mio_intrinsic_op): New routine.
(mio_full_typebound_tree): New routine to make typebound-procedures IO
code reusable for type-bound user operators.
(mio_f2k_derived): IO of type-bound operators.
* primary.c (gfc_match_varspec): Initialize new fields in gfc_expr and
pass locus to gfc_find_typebound_proc.
* resolve.c (resolve_operator): Only output error about no matching
interface if gfc_extend_expr did not already fail with an error.
(extract_compcall_passed_object): Use specified base-object if present.
(update_compcall_arglist): Handle ignore_pass field.
(resolve_ordinary_assign): Update to handle extended code for
type-bound assignments, too.
(resolve_code): Handle EXEC_ASSIGN_CALL statement code.
(resolve_tb_generic_targets): Pass locus to gfc_find_typebound_proc.
(resolve_typebound_generic), (resolve_typebound_procedure): Ditto.
(resolve_typebound_intrinsic_op), (resolve_typebound_user_op): Ditto.
(ensure_not_abstract_walker), (resolve_fl_derived): Ditto.
(resolve_typebound_procedures): Remove not-implemented error.
(resolve_typebound_call): Handle assign-call flag.
* symbol.c (find_typebound_proc_uop): New argument to pass locus for
error message about PRIVATE, verify that a found procedure is not marked
as erraneous.
(gfc_find_typebound_intrinsic_op): Ditto.
(gfc_find_typebound_proc), (gfc_find_typebound_user_op): New locus arg.
2009-08-22 Bud Davis <bdavis9659@sbcglobal.net> 2009-08-22 Bud Davis <bdavis9659@sbcglobal.net>
PR fortran/28093 PR fortran/28093
......
...@@ -1622,8 +1622,8 @@ typedef struct gfc_expr ...@@ -1622,8 +1622,8 @@ typedef struct gfc_expr
int rank; int rank;
mpz_t *shape; /* Can be NULL if shape is unknown at compile time */ mpz_t *shape; /* Can be NULL if shape is unknown at compile time */
/* Nonnull for functions and structure constructors, the base object for /* Nonnull for functions and structure constructors, may also used to hold the
component-calls. */ base-object for component calls. */
gfc_symtree *symtree; gfc_symtree *symtree;
gfc_ref *ref; gfc_ref *ref;
...@@ -1699,8 +1699,19 @@ typedef struct gfc_expr ...@@ -1699,8 +1699,19 @@ typedef struct gfc_expr
{ {
gfc_actual_arglist* actual; gfc_actual_arglist* actual;
const char* name; const char* name;
void* padding; /* Overlap gfc_typebound_proc with esym. */ /* Base-object, whose component was called. NULL means that it should
gfc_typebound_proc* tbp; be taken from symtree/ref. */
struct gfc_expr* base_object;
gfc_typebound_proc* tbp; /* Should overlap with esym. */
/* For type-bound operators, we want to call PASS procedures but already
have the full arglist; mark this, so that it is not extended by the
PASS argument. */
unsigned ignore_pass:1;
/* Do assign-calls rather than calls, that is appropriate dependency
checking. */
unsigned assign:1;
} }
compcall; compcall;
...@@ -2458,11 +2469,13 @@ gfc_gsymbol *gfc_find_gsymbol (gfc_gsymbol *, const char *); ...@@ -2458,11 +2469,13 @@ gfc_gsymbol *gfc_find_gsymbol (gfc_gsymbol *, const char *);
gfc_typebound_proc* gfc_get_typebound_proc (void); gfc_typebound_proc* gfc_get_typebound_proc (void);
gfc_symbol* gfc_get_derived_super_type (gfc_symbol*); gfc_symbol* gfc_get_derived_super_type (gfc_symbol*);
gfc_symtree* gfc_find_typebound_proc (gfc_symbol*, gfc_try*, const char*, bool); gfc_symtree* gfc_find_typebound_proc (gfc_symbol*, gfc_try*,
const char*, bool, locus*);
gfc_symtree* gfc_find_typebound_user_op (gfc_symbol*, gfc_try*, gfc_symtree* gfc_find_typebound_user_op (gfc_symbol*, gfc_try*,
const char*, bool); const char*, bool, locus*);
gfc_typebound_proc* gfc_find_typebound_intrinsic_op (gfc_symbol*, gfc_try*, gfc_typebound_proc* gfc_find_typebound_intrinsic_op (gfc_symbol*, gfc_try*,
gfc_intrinsic_op, bool); gfc_intrinsic_op, bool,
locus*);
gfc_symtree* gfc_get_tbp_symtree (gfc_symtree**, const char*); gfc_symtree* gfc_get_tbp_symtree (gfc_symtree**, const char*);
void gfc_copy_formal_args (gfc_symbol *, gfc_symbol *); void gfc_copy_formal_args (gfc_symbol *, gfc_symbol *);
...@@ -2643,7 +2656,7 @@ void gfc_procedure_use (gfc_symbol *, gfc_actual_arglist **, locus *); ...@@ -2643,7 +2656,7 @@ void gfc_procedure_use (gfc_symbol *, gfc_actual_arglist **, locus *);
void gfc_ppc_use (gfc_component *, gfc_actual_arglist **, locus *); void gfc_ppc_use (gfc_component *, gfc_actual_arglist **, locus *);
gfc_symbol *gfc_search_interface (gfc_interface *, int, gfc_symbol *gfc_search_interface (gfc_interface *, int,
gfc_actual_arglist **); gfc_actual_arglist **);
gfc_try gfc_extend_expr (gfc_expr *); gfc_try gfc_extend_expr (gfc_expr *, bool *);
void gfc_free_formal_arglist (gfc_formal_arglist *); void gfc_free_formal_arglist (gfc_formal_arglist *);
gfc_try gfc_extend_assign (gfc_code *, gfc_namespace *); gfc_try gfc_extend_assign (gfc_code *, gfc_namespace *);
gfc_try gfc_add_interface (gfc_symbol *); gfc_try gfc_add_interface (gfc_symbol *);
......
...@@ -2554,16 +2554,119 @@ gfc_find_sym_in_symtree (gfc_symbol *sym) ...@@ -2554,16 +2554,119 @@ gfc_find_sym_in_symtree (gfc_symbol *sym)
} }
/* See if the arglist to an operator-call contains a derived-type argument
with a matching type-bound operator. If so, return the matching specific
procedure defined as operator-target as well as the base-object to use
(which is the found derived-type argument with operator). */
static gfc_typebound_proc*
matching_typebound_op (gfc_expr** tb_base,
gfc_actual_arglist* args,
gfc_intrinsic_op op, const char* uop)
{
gfc_actual_arglist* base;
for (base = args; base; base = base->next)
if (base->expr->ts.type == BT_DERIVED)
{
gfc_typebound_proc* tb;
gfc_symbol* derived;
gfc_try result;
derived = base->expr->ts.u.derived;
if (op == INTRINSIC_USER)
{
gfc_symtree* tb_uop;
gcc_assert (uop);
tb_uop = gfc_find_typebound_user_op (derived, &result, uop,
false, NULL);
if (tb_uop)
tb = tb_uop->n.tb;
else
tb = NULL;
}
else
tb = gfc_find_typebound_intrinsic_op (derived, &result, op,
false, NULL);
/* This means we hit a PRIVATE operator which is use-associated and
should thus not be seen. */
if (result == FAILURE)
tb = NULL;
/* Look through the super-type hierarchy for a matching specific
binding. */
for (; tb; tb = tb->overridden)
{
gfc_tbp_generic* g;
gcc_assert (tb->is_generic);
for (g = tb->u.generic; g; g = g->next)
{
gfc_symbol* target;
gfc_actual_arglist* argcopy;
bool matches;
gcc_assert (g->specific);
if (g->specific->error)
continue;
target = g->specific->u.specific->n.sym;
/* Check if this arglist matches the formal. */
argcopy = gfc_copy_actual_arglist (args);
matches = gfc_arglist_matches_symbol (&argcopy, target);
gfc_free_actual_arglist (argcopy);
/* Return if we found a match. */
if (matches)
{
*tb_base = base->expr;
return g->specific;
}
}
}
}
return NULL;
}
/* For the 'actual arglist' of an operator call and a specific typebound
procedure that has been found the target of a type-bound operator, build the
appropriate EXPR_COMPCALL and resolve it. We take this indirection over
type-bound procedures rather than resolving type-bound operators 'directly'
so that we can reuse the existing logic. */
static void
build_compcall_for_operator (gfc_expr* e, gfc_actual_arglist* actual,
gfc_expr* base, gfc_typebound_proc* target)
{
e->expr_type = EXPR_COMPCALL;
e->value.compcall.tbp = target;
e->value.compcall.name = "operator"; /* Should not matter. */
e->value.compcall.actual = actual;
e->value.compcall.base_object = base;
e->value.compcall.ignore_pass = 1;
e->value.compcall.assign = 0;
}
/* This subroutine is called when an expression is being resolved. /* This subroutine is called when an expression is being resolved.
The expression node in question is either a user defined operator The expression node in question is either a user defined operator
or an intrinsic operator with arguments that aren't compatible or an intrinsic operator with arguments that aren't compatible
with the operator. This subroutine builds an actual argument list with the operator. This subroutine builds an actual argument list
corresponding to the operands, then searches for a compatible corresponding to the operands, then searches for a compatible
interface. If one is found, the expression node is replaced with interface. If one is found, the expression node is replaced with
the appropriate function call. */ the appropriate function call.
real_error is an additional output argument that specifies if FAILURE
is because of some real error and not because no match was found. */
gfc_try gfc_try
gfc_extend_expr (gfc_expr *e) gfc_extend_expr (gfc_expr *e, bool *real_error)
{ {
gfc_actual_arglist *actual; gfc_actual_arglist *actual;
gfc_symbol *sym; gfc_symbol *sym;
...@@ -2576,6 +2679,8 @@ gfc_extend_expr (gfc_expr *e) ...@@ -2576,6 +2679,8 @@ gfc_extend_expr (gfc_expr *e)
actual = gfc_get_actual_arglist (); actual = gfc_get_actual_arglist ();
actual->expr = e->value.op.op1; actual->expr = e->value.op.op1;
*real_error = false;
if (e->value.op.op2 != NULL) if (e->value.op.op2 != NULL)
{ {
actual->next = gfc_get_actual_arglist (); actual->next = gfc_get_actual_arglist ();
...@@ -2605,47 +2710,20 @@ gfc_extend_expr (gfc_expr *e) ...@@ -2605,47 +2710,20 @@ gfc_extend_expr (gfc_expr *e)
to check if either is defined. */ to check if either is defined. */
switch (i) switch (i)
{ {
case INTRINSIC_EQ: #define CHECK_OS_COMPARISON(comp) \
case INTRINSIC_EQ_OS: case INTRINSIC_##comp: \
sym = gfc_search_interface (ns->op[INTRINSIC_EQ], 0, &actual); case INTRINSIC_##comp##_OS: \
if (sym == NULL) sym = gfc_search_interface (ns->op[INTRINSIC_##comp], 0, &actual); \
sym = gfc_search_interface (ns->op[INTRINSIC_EQ_OS], 0, &actual); if (!sym) \
break; sym = gfc_search_interface (ns->op[INTRINSIC_##comp##_OS], 0, &actual); \
break;
case INTRINSIC_NE: CHECK_OS_COMPARISON(EQ)
case INTRINSIC_NE_OS: CHECK_OS_COMPARISON(NE)
sym = gfc_search_interface (ns->op[INTRINSIC_NE], 0, &actual); CHECK_OS_COMPARISON(GT)
if (sym == NULL) CHECK_OS_COMPARISON(GE)
sym = gfc_search_interface (ns->op[INTRINSIC_NE_OS], 0, &actual); CHECK_OS_COMPARISON(LT)
break; CHECK_OS_COMPARISON(LE)
#undef CHECK_OS_COMPARISON
case INTRINSIC_GT:
case INTRINSIC_GT_OS:
sym = gfc_search_interface (ns->op[INTRINSIC_GT], 0, &actual);
if (sym == NULL)
sym = gfc_search_interface (ns->op[INTRINSIC_GT_OS], 0, &actual);
break;
case INTRINSIC_GE:
case INTRINSIC_GE_OS:
sym = gfc_search_interface (ns->op[INTRINSIC_GE], 0, &actual);
if (sym == NULL)
sym = gfc_search_interface (ns->op[INTRINSIC_GE_OS], 0, &actual);
break;
case INTRINSIC_LT:
case INTRINSIC_LT_OS:
sym = gfc_search_interface (ns->op[INTRINSIC_LT], 0, &actual);
if (sym == NULL)
sym = gfc_search_interface (ns->op[INTRINSIC_LT_OS], 0, &actual);
break;
case INTRINSIC_LE:
case INTRINSIC_LE_OS:
sym = gfc_search_interface (ns->op[INTRINSIC_LE], 0, &actual);
if (sym == NULL)
sym = gfc_search_interface (ns->op[INTRINSIC_LE_OS], 0, &actual);
break;
default: default:
sym = gfc_search_interface (ns->op[i], 0, &actual); sym = gfc_search_interface (ns->op[i], 0, &actual);
...@@ -2656,8 +2734,59 @@ gfc_extend_expr (gfc_expr *e) ...@@ -2656,8 +2734,59 @@ gfc_extend_expr (gfc_expr *e)
} }
} }
/* TODO: Do an ambiguity-check and error if multiple matching interfaces are
found rather than just taking the first one and not checking further. */
if (sym == NULL) if (sym == NULL)
{ {
gfc_typebound_proc* tbo;
gfc_expr* tb_base;
/* See if we find a matching type-bound operator. */
if (i == INTRINSIC_USER)
tbo = matching_typebound_op (&tb_base, actual,
i, e->value.op.uop->name);
else
switch (i)
{
#define CHECK_OS_COMPARISON(comp) \
case INTRINSIC_##comp: \
case INTRINSIC_##comp##_OS: \
tbo = matching_typebound_op (&tb_base, actual, \
INTRINSIC_##comp, NULL); \
if (!tbo) \
tbo = matching_typebound_op (&tb_base, actual, \
INTRINSIC_##comp##_OS, NULL); \
break;
CHECK_OS_COMPARISON(EQ)
CHECK_OS_COMPARISON(NE)
CHECK_OS_COMPARISON(GT)
CHECK_OS_COMPARISON(GE)
CHECK_OS_COMPARISON(LT)
CHECK_OS_COMPARISON(LE)
#undef CHECK_OS_COMPARISON
default:
tbo = matching_typebound_op (&tb_base, actual, i, NULL);
break;
}
/* If there is a matching typebound-operator, replace the expression with
a call to it and succeed. */
if (tbo)
{
gfc_try result;
gcc_assert (tb_base);
build_compcall_for_operator (e, actual, tb_base, tbo);
result = gfc_resolve_expr (e);
if (result == FAILURE)
*real_error = true;
return result;
}
/* Don't use gfc_free_actual_arglist(). */ /* Don't use gfc_free_actual_arglist(). */
if (actual->next != NULL) if (actual->next != NULL)
gfc_free (actual->next); gfc_free (actual->next);
...@@ -2675,16 +2804,12 @@ gfc_extend_expr (gfc_expr *e) ...@@ -2675,16 +2804,12 @@ gfc_extend_expr (gfc_expr *e)
e->value.function.name = NULL; e->value.function.name = NULL;
e->user_operator = 1; e->user_operator = 1;
if (gfc_pure (NULL) && !gfc_pure (sym)) if (gfc_resolve_expr (e) == FAILURE)
{ {
gfc_error ("Function '%s' called in lieu of an operator at %L must " *real_error = true;
"be PURE", sym->name, &e->where);
return FAILURE; return FAILURE;
} }
if (gfc_resolve_expr (e) == FAILURE)
return FAILURE;
return SUCCESS; return SUCCESS;
} }
...@@ -2726,8 +2851,33 @@ gfc_extend_assign (gfc_code *c, gfc_namespace *ns) ...@@ -2726,8 +2851,33 @@ gfc_extend_assign (gfc_code *c, gfc_namespace *ns)
break; break;
} }
/* TODO: Ambiguity-check, see above for gfc_extend_expr. */
if (sym == NULL) if (sym == NULL)
{ {
gfc_typebound_proc* tbo;
gfc_expr* tb_base;
/* See if we find a matching type-bound assignment. */
tbo = matching_typebound_op (&tb_base, actual,
INTRINSIC_ASSIGN, NULL);
/* If there is one, replace the expression with a call to it and
succeed. */
if (tbo)
{
gcc_assert (tb_base);
c->expr1 = gfc_get_expr ();
build_compcall_for_operator (c->expr1, actual, tb_base, tbo);
c->expr1->value.compcall.assign = 1;
c->expr2 = NULL;
c->op = EXEC_COMPCALL;
/* c is resolved from the caller, so no need to do it here. */
return SUCCESS;
}
gfc_free (actual->next); gfc_free (actual->next);
gfc_free (actual); gfc_free (actual);
return FAILURE; return FAILURE;
......
...@@ -77,7 +77,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -77,7 +77,7 @@ along with GCC; see the file COPYING3. If not see
/* Don't put any single quote (') in MOD_VERSION, /* Don't put any single quote (') in MOD_VERSION,
if yout want it to be recognized. */ if yout want it to be recognized. */
#define MOD_VERSION "2" #define MOD_VERSION "3"
/* Structure that describes a position within a module file. */ /* Structure that describes a position within a module file. */
...@@ -1461,6 +1461,25 @@ mio_integer (int *ip) ...@@ -1461,6 +1461,25 @@ mio_integer (int *ip)
} }
/* Read or write a gfc_intrinsic_op value. */
static void
mio_intrinsic_op (gfc_intrinsic_op* op)
{
/* FIXME: Would be nicer to do this via the operators symbolic name. */
if (iomode == IO_OUTPUT)
{
int converted = (int) *op;
write_atom (ATOM_INTEGER, &converted);
}
else
{
require_atom (ATOM_INTEGER);
*op = (gfc_intrinsic_op) atom_int;
}
}
/* Read or write a character pointer that points to a string on the heap. */ /* Read or write a character pointer that points to a string on the heap. */
static const char * static const char *
...@@ -3324,6 +3343,7 @@ mio_typebound_proc (gfc_typebound_proc** proc) ...@@ -3324,6 +3343,7 @@ mio_typebound_proc (gfc_typebound_proc** proc)
mio_rparen (); mio_rparen ();
} }
/* Walker-callback function for this purpose. */
static void static void
mio_typebound_symtree (gfc_symtree* st) mio_typebound_symtree (gfc_symtree* st)
{ {
...@@ -3341,6 +3361,33 @@ mio_typebound_symtree (gfc_symtree* st) ...@@ -3341,6 +3361,33 @@ mio_typebound_symtree (gfc_symtree* st)
mio_rparen (); mio_rparen ();
} }
/* IO a full symtree (in all depth). */
static void
mio_full_typebound_tree (gfc_symtree** root)
{
mio_lparen ();
if (iomode == IO_OUTPUT)
gfc_traverse_symtree (*root, &mio_typebound_symtree);
else
{
while (peek_atom () == ATOM_LPAREN)
{
gfc_symtree* st;
mio_lparen ();
require_atom (ATOM_STRING);
st = gfc_get_tbp_symtree (root, atom_string);
gfc_free (atom_string);
mio_typebound_symtree (st);
}
}
mio_rparen ();
}
static void static void
mio_finalizer (gfc_finalizer **f) mio_finalizer (gfc_finalizer **f)
{ {
...@@ -3388,24 +3435,40 @@ mio_f2k_derived (gfc_namespace *f2k) ...@@ -3388,24 +3435,40 @@ mio_f2k_derived (gfc_namespace *f2k)
mio_rparen (); mio_rparen ();
/* Handle type-bound procedures. */ /* Handle type-bound procedures. */
mio_full_typebound_tree (&f2k->tb_sym_root);
/* Type-bound user operators. */
mio_full_typebound_tree (&f2k->tb_uop_root);
/* Type-bound intrinsic operators. */
mio_lparen (); mio_lparen ();
if (iomode == IO_OUTPUT) if (iomode == IO_OUTPUT)
gfc_traverse_symtree (f2k->tb_sym_root, &mio_typebound_symtree);
else
{ {
while (peek_atom () == ATOM_LPAREN) int op;
for (op = GFC_INTRINSIC_BEGIN; op != GFC_INTRINSIC_END; ++op)
{ {
gfc_symtree* st; gfc_intrinsic_op realop;
mio_lparen ();
require_atom (ATOM_STRING); if (op == INTRINSIC_USER || !f2k->tb_op[op])
st = gfc_get_tbp_symtree (&f2k->tb_sym_root, atom_string); continue;
gfc_free (atom_string);
mio_typebound_symtree (st); mio_lparen ();
realop = (gfc_intrinsic_op) op;
mio_intrinsic_op (&realop);
mio_typebound_proc (&f2k->tb_op[op]);
mio_rparen ();
} }
} }
else
while (peek_atom () != ATOM_RPAREN)
{
gfc_intrinsic_op op;
mio_lparen ();
mio_intrinsic_op (&op);
mio_typebound_proc (&f2k->tb_op[op]);
mio_rparen ();
}
mio_rparen (); mio_rparen ();
} }
......
...@@ -1783,7 +1783,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag, ...@@ -1783,7 +1783,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
if (m != MATCH_YES) if (m != MATCH_YES)
return MATCH_ERROR; return MATCH_ERROR;
tbp = gfc_find_typebound_proc (sym, &t, name, false); tbp = gfc_find_typebound_proc (sym, &t, name, false, &gfc_current_locus);
if (tbp) if (tbp)
{ {
gfc_symbol* tbp_sym; gfc_symbol* tbp_sym;
...@@ -1802,6 +1802,9 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag, ...@@ -1802,6 +1802,9 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
primary->expr_type = EXPR_COMPCALL; primary->expr_type = EXPR_COMPCALL;
primary->value.compcall.tbp = tbp->n.tb; primary->value.compcall.tbp = tbp->n.tb;
primary->value.compcall.name = tbp->name; primary->value.compcall.name = tbp->name;
primary->value.compcall.ignore_pass = 0;
primary->value.compcall.assign = 0;
primary->value.compcall.base_object = NULL;
gcc_assert (primary->symtree->n.sym->attr.referenced); gcc_assert (primary->symtree->n.sym->attr.referenced);
if (tbp_sym) if (tbp_sym)
primary->ts = tbp_sym->ts; primary->ts = tbp_sym->ts;
......
...@@ -3508,8 +3508,14 @@ resolve_operator (gfc_expr *e) ...@@ -3508,8 +3508,14 @@ resolve_operator (gfc_expr *e)
bad_op: bad_op:
if (gfc_extend_expr (e) == SUCCESS) {
return SUCCESS; bool real_error;
if (gfc_extend_expr (e, &real_error) == SUCCESS)
return SUCCESS;
if (real_error)
return FAILURE;
}
if (dual_locus_error) if (dual_locus_error)
gfc_error (msg, &op1->where, &op2->where); gfc_error (msg, &op1->where, &op2->where);
...@@ -4685,10 +4691,15 @@ extract_compcall_passed_object (gfc_expr* e) ...@@ -4685,10 +4691,15 @@ extract_compcall_passed_object (gfc_expr* e)
gcc_assert (e->expr_type == EXPR_COMPCALL); gcc_assert (e->expr_type == EXPR_COMPCALL);
po = gfc_get_expr (); if (e->value.compcall.base_object)
po->expr_type = EXPR_VARIABLE; po = gfc_copy_expr (e->value.compcall.base_object);
po->symtree = e->symtree; else
po->ref = gfc_copy_ref (e->ref); {
po = gfc_get_expr ();
po->expr_type = EXPR_VARIABLE;
po->symtree = e->symtree;
po->ref = gfc_copy_ref (e->ref);
}
if (gfc_resolve_expr (po) == FAILURE) if (gfc_resolve_expr (po) == FAILURE)
return NULL; return NULL;
...@@ -4721,7 +4732,7 @@ update_compcall_arglist (gfc_expr* e) ...@@ -4721,7 +4732,7 @@ update_compcall_arglist (gfc_expr* e)
return FAILURE; return FAILURE;
} }
if (tbp->nopass) if (tbp->nopass || e->value.compcall.ignore_pass)
{ {
gfc_free_expr (po); gfc_free_expr (po);
return SUCCESS; return SUCCESS;
...@@ -4957,7 +4968,7 @@ resolve_typebound_call (gfc_code* c) ...@@ -4957,7 +4968,7 @@ resolve_typebound_call (gfc_code* c)
c->ext.actual = newactual; c->ext.actual = newactual;
c->symtree = target; c->symtree = target;
c->op = EXEC_CALL; c->op = (c->expr1->value.compcall.assign ? EXEC_ASSIGN_CALL : EXEC_CALL);
gcc_assert (!c->expr1->ref && !c->expr1->value.compcall.actual); gcc_assert (!c->expr1->ref && !c->expr1->value.compcall.actual);
gfc_free_expr (c->expr1); gfc_free_expr (c->expr1);
...@@ -4983,6 +4994,9 @@ resolve_compcall (gfc_expr* e) ...@@ -4983,6 +4994,9 @@ resolve_compcall (gfc_expr* e)
return FAILURE; return FAILURE;
} }
/* These must not be assign-calls! */
gcc_assert (!e->value.compcall.assign);
if (check_typebound_baseobject (e) == FAILURE) if (check_typebound_baseobject (e) == FAILURE)
return FAILURE; return FAILURE;
...@@ -6909,24 +6923,40 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) ...@@ -6909,24 +6923,40 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
if (gfc_extend_assign (code, ns) == SUCCESS) if (gfc_extend_assign (code, ns) == SUCCESS)
{ {
lhs = code->ext.actual->expr; gfc_symbol* assign_proc;
rhs = code->ext.actual->next->expr; gfc_expr** rhsptr;
if (gfc_pure (NULL) && !gfc_pure (code->symtree->n.sym))
if (code->op == EXEC_ASSIGN_CALL)
{ {
gfc_error ("Subroutine '%s' called instead of assignment at " lhs = code->ext.actual->expr;
"%L must be PURE", code->symtree->n.sym->name, rhsptr = &code->ext.actual->next->expr;
&code->loc); assign_proc = code->symtree->n.sym;
return rval; }
else
{
gfc_actual_arglist* args;
gfc_typebound_proc* tbp;
gcc_assert (code->op == EXEC_COMPCALL);
args = code->expr1->value.compcall.actual;
lhs = args->expr;
rhsptr = &args->next->expr;
tbp = code->expr1->value.compcall.tbp;
gcc_assert (!tbp->is_generic);
assign_proc = tbp->u.specific->n.sym;
} }
/* Make a temporary rhs when there is a default initializer /* Make a temporary rhs when there is a default initializer
and rhs is the same symbol as the lhs. */ and rhs is the same symbol as the lhs. */
if (rhs->expr_type == EXPR_VARIABLE if ((*rhsptr)->expr_type == EXPR_VARIABLE
&& rhs->symtree->n.sym->ts.type == BT_DERIVED && (*rhsptr)->symtree->n.sym->ts.type == BT_DERIVED
&& has_default_initializer (rhs->symtree->n.sym->ts.u.derived) && has_default_initializer ((*rhsptr)->symtree->n.sym->ts.u.derived)
&& (lhs->symtree->n.sym == rhs->symtree->n.sym)) && (lhs->symtree->n.sym == (*rhsptr)->symtree->n.sym))
code->ext.actual->next->expr = gfc_get_parentheses (rhs); *rhsptr = gfc_get_parentheses (*rhsptr);
resolve_code (code, ns);
return true; return true;
} }
...@@ -6935,8 +6965,8 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) ...@@ -6935,8 +6965,8 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
if (rhs->is_boz if (rhs->is_boz
&& gfc_notify_std (GFC_STD_GNU, "Extension: BOZ literal at %L outside " && gfc_notify_std (GFC_STD_GNU, "Extension: BOZ literal at %L outside "
"a DATA statement and outside INT/REAL/DBLE/CMPLX", "a DATA statement and outside INT/REAL/DBLE/CMPLX",
&code->loc) == FAILURE) &code->loc) == FAILURE)
return false; return false;
/* Handle the case of a BOZ literal on the RHS. */ /* Handle the case of a BOZ literal on the RHS. */
...@@ -6981,7 +7011,7 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) ...@@ -6981,7 +7011,7 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
rlen = rhs->value.character.length; rlen = rhs->value.character.length;
else if (rhs->ts.u.cl != NULL else if (rhs->ts.u.cl != NULL
&& rhs->ts.u.cl->length != NULL && rhs->ts.u.cl->length != NULL
&& rhs->ts.u.cl->length->expr_type == EXPR_CONSTANT) && rhs->ts.u.cl->length->expr_type == EXPR_CONSTANT)
rlen = mpz_get_si (rhs->ts.u.cl->length->value.integer); rlen = mpz_get_si (rhs->ts.u.cl->length->value.integer);
...@@ -7115,6 +7145,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns) ...@@ -7115,6 +7145,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
case EXEC_EXIT: case EXEC_EXIT:
case EXEC_CONTINUE: case EXEC_CONTINUE:
case EXEC_DT_END: case EXEC_DT_END:
case EXEC_ASSIGN_CALL:
break; break;
case EXEC_ENTRY: case EXEC_ENTRY:
...@@ -8870,8 +8901,8 @@ resolve_tb_generic_targets (gfc_symbol* super_type, ...@@ -8870,8 +8901,8 @@ resolve_tb_generic_targets (gfc_symbol* super_type,
/* Look for an inherited specific binding. */ /* Look for an inherited specific binding. */
if (super_type) if (super_type)
{ {
inherited = gfc_find_typebound_proc (super_type, NULL, inherited = gfc_find_typebound_proc (super_type, NULL, target_name,
target_name, true); true, NULL);
if (inherited) if (inherited)
{ {
...@@ -8952,7 +8983,8 @@ resolve_typebound_generic (gfc_symbol* derived, gfc_symtree* st) ...@@ -8952,7 +8983,8 @@ resolve_typebound_generic (gfc_symbol* derived, gfc_symtree* st)
if (super_type) if (super_type)
{ {
gfc_symtree* overridden; gfc_symtree* overridden;
overridden = gfc_find_typebound_proc (super_type, NULL, st->name, true); overridden = gfc_find_typebound_proc (super_type, NULL, st->name,
true, NULL);
if (overridden && overridden->n.tb) if (overridden && overridden->n.tb)
st->n.tb->overridden = overridden->n.tb; st->n.tb->overridden = overridden->n.tb;
...@@ -9006,7 +9038,7 @@ resolve_typebound_intrinsic_op (gfc_symbol* derived, gfc_intrinsic_op op, ...@@ -9006,7 +9038,7 @@ resolve_typebound_intrinsic_op (gfc_symbol* derived, gfc_intrinsic_op op,
super_type = gfc_get_derived_super_type (derived); super_type = gfc_get_derived_super_type (derived);
if (super_type && super_type->f2k_derived) if (super_type && super_type->f2k_derived)
p->overridden = gfc_find_typebound_intrinsic_op (super_type, NULL, p->overridden = gfc_find_typebound_intrinsic_op (super_type, NULL,
op, true); op, true, NULL);
else else
p->overridden = NULL; p->overridden = NULL;
...@@ -9021,10 +9053,10 @@ resolve_typebound_intrinsic_op (gfc_symbol* derived, gfc_intrinsic_op op, ...@@ -9021,10 +9053,10 @@ resolve_typebound_intrinsic_op (gfc_symbol* derived, gfc_intrinsic_op op,
target_proc = get_checked_tb_operator_target (target, p->where); target_proc = get_checked_tb_operator_target (target, p->where);
if (!target_proc) if (!target_proc)
return FAILURE; goto error;
if (!gfc_check_operator_interface (target_proc, op, p->where)) if (!gfc_check_operator_interface (target_proc, op, p->where))
return FAILURE; goto error;
} }
return SUCCESS; return SUCCESS;
...@@ -9062,7 +9094,7 @@ resolve_typebound_user_op (gfc_symtree* stree) ...@@ -9062,7 +9094,7 @@ resolve_typebound_user_op (gfc_symtree* stree)
{ {
gfc_symtree* overridden; gfc_symtree* overridden;
overridden = gfc_find_typebound_user_op (super_type, NULL, overridden = gfc_find_typebound_user_op (super_type, NULL,
stree->name, true); stree->name, true, NULL);
if (overridden && overridden->n.tb) if (overridden && overridden->n.tb)
stree->n.tb->overridden = overridden->n.tb; stree->n.tb->overridden = overridden->n.tb;
...@@ -9225,7 +9257,7 @@ resolve_typebound_procedure (gfc_symtree* stree) ...@@ -9225,7 +9257,7 @@ resolve_typebound_procedure (gfc_symtree* stree)
{ {
gfc_symtree* overridden; gfc_symtree* overridden;
overridden = gfc_find_typebound_proc (super_type, NULL, overridden = gfc_find_typebound_proc (super_type, NULL,
stree->name, true); stree->name, true, NULL);
if (overridden && overridden->n.tb) if (overridden && overridden->n.tb)
stree->n.tb->overridden = overridden->n.tb; stree->n.tb->overridden = overridden->n.tb;
...@@ -9265,7 +9297,6 @@ static gfc_try ...@@ -9265,7 +9297,6 @@ static gfc_try
resolve_typebound_procedures (gfc_symbol* derived) resolve_typebound_procedures (gfc_symbol* derived)
{ {
int op; int op;
bool found_op;
if (!derived->f2k_derived || !derived->f2k_derived->tb_sym_root) if (!derived->f2k_derived || !derived->f2k_derived->tb_sym_root)
return SUCCESS; return SUCCESS;
...@@ -9277,7 +9308,6 @@ resolve_typebound_procedures (gfc_symbol* derived) ...@@ -9277,7 +9308,6 @@ resolve_typebound_procedures (gfc_symbol* derived)
gfc_traverse_symtree (derived->f2k_derived->tb_sym_root, gfc_traverse_symtree (derived->f2k_derived->tb_sym_root,
&resolve_typebound_procedure); &resolve_typebound_procedure);
found_op = (derived->f2k_derived->tb_uop_root != NULL);
if (derived->f2k_derived->tb_uop_root) if (derived->f2k_derived->tb_uop_root)
gfc_traverse_symtree (derived->f2k_derived->tb_uop_root, gfc_traverse_symtree (derived->f2k_derived->tb_uop_root,
&resolve_typebound_user_op); &resolve_typebound_user_op);
...@@ -9288,17 +9318,6 @@ resolve_typebound_procedures (gfc_symbol* derived) ...@@ -9288,17 +9318,6 @@ resolve_typebound_procedures (gfc_symbol* derived)
if (p && resolve_typebound_intrinsic_op (derived, (gfc_intrinsic_op) op, if (p && resolve_typebound_intrinsic_op (derived, (gfc_intrinsic_op) op,
p) == FAILURE) p) == FAILURE)
resolve_bindings_result = FAILURE; resolve_bindings_result = FAILURE;
if (p)
found_op = true;
}
/* FIXME: Remove this (and found_op) once calls are fully implemented. */
if (found_op)
{
gfc_error ("Derived type '%s' at %L contains type-bound OPERATOR's,"
" they are not yet implemented.",
derived->name, &derived->declared_at);
resolve_bindings_result = FAILURE;
} }
return resolve_bindings_result; return resolve_bindings_result;
...@@ -9343,7 +9362,7 @@ ensure_not_abstract_walker (gfc_symbol* sub, gfc_symtree* st) ...@@ -9343,7 +9362,7 @@ ensure_not_abstract_walker (gfc_symbol* sub, gfc_symtree* st)
if (st->n.tb && st->n.tb->deferred) if (st->n.tb && st->n.tb->deferred)
{ {
gfc_symtree* overriding; gfc_symtree* overriding;
overriding = gfc_find_typebound_proc (sub, NULL, st->name, true); overriding = gfc_find_typebound_proc (sub, NULL, st->name, true, NULL);
gcc_assert (overriding && overriding->n.tb); gcc_assert (overriding && overriding->n.tb);
if (overriding->n.tb->deferred) if (overriding->n.tb->deferred)
{ {
...@@ -9594,7 +9613,7 @@ resolve_fl_derived (gfc_symbol *sym) ...@@ -9594,7 +9613,7 @@ resolve_fl_derived (gfc_symbol *sym)
/* If this type is an extension, see if this component has the same name /* If this type is an extension, see if this component has the same name
as an inherited type-bound procedure. */ as an inherited type-bound procedure. */
if (super_type if (super_type
&& gfc_find_typebound_proc (super_type, NULL, c->name, true)) && gfc_find_typebound_proc (super_type, NULL, c->name, true, NULL))
{ {
gfc_error ("Component '%s' of '%s' at %L has the same name as an" gfc_error ("Component '%s' of '%s' at %L has the same name as an"
" inherited type-bound procedure", " inherited type-bound procedure",
......
...@@ -4539,7 +4539,8 @@ gfc_get_derived_super_type (gfc_symbol* derived) ...@@ -4539,7 +4539,8 @@ gfc_get_derived_super_type (gfc_symbol* derived)
static gfc_symtree* static gfc_symtree*
find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t, find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
const char* name, bool noaccess, bool uop) const char* name, bool noaccess, bool uop,
locus* where)
{ {
gfc_symtree* res; gfc_symtree* res;
gfc_symtree* root; gfc_symtree* root;
...@@ -4555,7 +4556,7 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t, ...@@ -4555,7 +4556,7 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
/* Try to find it in the current type's namespace. */ /* Try to find it in the current type's namespace. */
res = gfc_find_symtree (root, name); res = gfc_find_symtree (root, name);
if (res && res->n.tb) if (res && res->n.tb && !res->n.tb->error)
{ {
/* We found one. */ /* We found one. */
if (t) if (t)
...@@ -4564,7 +4565,9 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t, ...@@ -4564,7 +4565,9 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
if (!noaccess && derived->attr.use_assoc if (!noaccess && derived->attr.use_assoc
&& res->n.tb->access == ACCESS_PRIVATE) && res->n.tb->access == ACCESS_PRIVATE)
{ {
gfc_error ("'%s' of '%s' is PRIVATE at %C", name, derived->name); if (where)
gfc_error ("'%s' of '%s' is PRIVATE at %L",
name, derived->name, where);
if (t) if (t)
*t = FAILURE; *t = FAILURE;
} }
...@@ -4579,7 +4582,8 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t, ...@@ -4579,7 +4582,8 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
super_type = gfc_get_derived_super_type (derived); super_type = gfc_get_derived_super_type (derived);
gcc_assert (super_type); gcc_assert (super_type);
return find_typebound_proc_uop (super_type, t, name, noaccess, uop); return find_typebound_proc_uop (super_type, t, name,
noaccess, uop, where);
} }
/* Nothing found. */ /* Nothing found. */
...@@ -4592,16 +4596,16 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t, ...@@ -4592,16 +4596,16 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
gfc_symtree* gfc_symtree*
gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t, gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
const char* name, bool noaccess) const char* name, bool noaccess, locus* where)
{ {
return find_typebound_proc_uop (derived, t, name, noaccess, false); return find_typebound_proc_uop (derived, t, name, noaccess, false, where);
} }
gfc_symtree* gfc_symtree*
gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t, gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
const char* name, bool noaccess) const char* name, bool noaccess, locus* where)
{ {
return find_typebound_proc_uop (derived, t, name, noaccess, true); return find_typebound_proc_uop (derived, t, name, noaccess, true, where);
} }
...@@ -4610,7 +4614,8 @@ gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t, ...@@ -4610,7 +4614,8 @@ gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
gfc_typebound_proc* gfc_typebound_proc*
gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t, gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
gfc_intrinsic_op op, bool noaccess) gfc_intrinsic_op op, bool noaccess,
locus* where)
{ {
gfc_typebound_proc* res; gfc_typebound_proc* res;
...@@ -4625,7 +4630,7 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t, ...@@ -4625,7 +4630,7 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
res = NULL; res = NULL;
/* Check access. */ /* Check access. */
if (res) if (res && !res->error)
{ {
/* We found one. */ /* We found one. */
if (t) if (t)
...@@ -4634,8 +4639,9 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t, ...@@ -4634,8 +4639,9 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
if (!noaccess && derived->attr.use_assoc if (!noaccess && derived->attr.use_assoc
&& res->access == ACCESS_PRIVATE) && res->access == ACCESS_PRIVATE)
{ {
gfc_error ("'%s' of '%s' is PRIVATE at %C", if (where)
gfc_op2string (op), derived->name); gfc_error ("'%s' of '%s' is PRIVATE at %L",
gfc_op2string (op), derived->name, where);
if (t) if (t)
*t = FAILURE; *t = FAILURE;
} }
...@@ -4650,7 +4656,8 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t, ...@@ -4650,7 +4656,8 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
super_type = gfc_get_derived_super_type (derived); super_type = gfc_get_derived_super_type (derived);
gcc_assert (super_type); gcc_assert (super_type);
return gfc_find_typebound_intrinsic_op (super_type, t, op, noaccess); return gfc_find_typebound_intrinsic_op (super_type, t, op,
noaccess, where);
} }
/* Nothing found. */ /* Nothing found. */
......
2009-08-27 Daniel Kraft <d@domob.eu>
PR fortran/37425
* gfortran.dg/impure_assignment_1.f90: Change expected error message.
* gfortran.dg/typebound_operator_1.f03: Remove check for not-implemented
error and fix problem with recursive assignment.
* gfortran.dg/typebound_operator_2.f03: No not-implemented check.
* gfortran.dg/typebound_operator_3.f03: New test.
* gfortran.dg/typebound_operator_4.f03: New test.
2009-08-27 Dodji Seketeli <dodji@redhat.com> 2009-08-27 Dodji Seketeli <dodji@redhat.com>
PR debug/41770 PR debug/41770
......
...@@ -21,7 +21,7 @@ CONTAINS ...@@ -21,7 +21,7 @@ CONTAINS
PURE SUBROUTINE S2(I,J) PURE SUBROUTINE S2(I,J)
TYPE(T1), INTENT(OUT):: I TYPE(T1), INTENT(OUT):: I
TYPE(T1), INTENT(IN) :: J TYPE(T1), INTENT(IN) :: J
I=J ! { dg-error "must be PURE" } I=J ! { dg-error "is not PURE" }
END SUBROUTINE S2 END SUBROUTINE S2
END END
! { dg-final { cleanup-modules "M1" } } ! { dg-final { cleanup-modules "M1" } }
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
MODULE m MODULE m
IMPLICIT NONE IMPLICIT NONE
TYPE t ! { dg-error "not yet implemented" } TYPE t
LOGICAL :: x
CONTAINS CONTAINS
PROCEDURE, PASS :: onearg PROCEDURE, PASS :: onearg
PROCEDURE, PASS :: twoarg1 PROCEDURE, PASS :: twoarg1
...@@ -41,8 +42,8 @@ CONTAINS ...@@ -41,8 +42,8 @@ CONTAINS
SUBROUTINE assign_proc (me, b) SUBROUTINE assign_proc (me, b)
CLASS(t), INTENT(OUT) :: me CLASS(t), INTENT(OUT) :: me
CLASS(t), INTENT(IN) :: b LOGICAL, INTENT(IN) :: b
me = t () me%x = .NOT. b
END SUBROUTINE assign_proc END SUBROUTINE assign_proc
END MODULE m END MODULE m
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
MODULE m MODULE m
IMPLICIT NONE IMPLICIT NONE
TYPE t ! { dg-error "not yet implemented" } TYPE t
CONTAINS CONTAINS
PROCEDURE, PASS :: onearg PROCEDURE, PASS :: onearg
PROCEDURE, PASS :: onearg_alt => onearg PROCEDURE, PASS :: onearg_alt => onearg
......
! { dg-do run }
! { dg-options "-w" }
! FIXME: Remove -w when CLASS is fully implemented.
! Type-bound procedures
! Check they can actually be called and run correctly.
! This also checks for correct module save/restore.
! FIXME: Check that calls to inherited bindings work once CLASS allows that.
MODULE m
IMPLICIT NONE
TYPE mynum
REAL :: num_real
INTEGER :: num_int
CONTAINS
PROCEDURE, PASS, PRIVATE :: add_mynum ! Check that this may be PRIVATE.
PROCEDURE, PASS :: add_int
PROCEDURE, PASS :: add_real
PROCEDURE, PASS :: assign_int
PROCEDURE, PASS :: assign_real
PROCEDURE, PASS(from) :: assign_to_int
PROCEDURE, PASS(from) :: assign_to_real
PROCEDURE, PASS :: get_all
GENERIC :: OPERATOR(+) => add_mynum, add_int, add_real
GENERIC :: OPERATOR(.GET.) => get_all
GENERIC :: ASSIGNMENT(=) => assign_int, assign_real, &
assign_to_int, assign_to_real
END TYPE mynum
CONTAINS
TYPE(mynum) FUNCTION add_mynum (a, b)
CLASS(mynum), INTENT(IN) :: a, b
add_mynum = mynum (a%num_real + b%num_real, a%num_int + b%num_int)
END FUNCTION add_mynum
TYPE(mynum) FUNCTION add_int (a, b)
CLASS(mynum), INTENT(IN) :: a
INTEGER, INTENT(IN) :: b
add_int = mynum (a%num_real, a%num_int + b)
END FUNCTION add_int
TYPE(mynum) FUNCTION add_real (a, b)
CLASS(mynum), INTENT(IN) :: a
REAL, INTENT(IN) :: b
add_real = mynum (a%num_real + b, a%num_int)
END FUNCTION add_real
REAL FUNCTION get_all (me)
CLASS(mynum), INTENT(IN) :: me
get_all = me%num_real + me%num_int
END FUNCTION get_all
SUBROUTINE assign_real (dest, from)
CLASS(mynum), INTENT(INOUT) :: dest
REAL, INTENT(IN) :: from
dest%num_real = from
END SUBROUTINE assign_real
SUBROUTINE assign_int (dest, from)
CLASS(mynum), INTENT(INOUT) :: dest
INTEGER, INTENT(IN) :: from
dest%num_int = from
END SUBROUTINE assign_int
SUBROUTINE assign_to_real (dest, from)
REAL, INTENT(OUT) :: dest
CLASS(mynum), INTENT(IN) :: from
dest = from%num_real
END SUBROUTINE assign_to_real
SUBROUTINE assign_to_int (dest, from)
INTEGER, INTENT(OUT) :: dest
CLASS(mynum), INTENT(IN) :: from
dest = from%num_int
END SUBROUTINE assign_to_int
! Test it works basically within the module.
SUBROUTINE check_in_module ()
IMPLICIT NONE
TYPE(mynum) :: num
num = mynum (1.0, 2)
num = num + 7
IF (num%num_real /= 1.0 .OR. num%num_int /= 9) CALL abort ()
END SUBROUTINE check_in_module
END MODULE m
! Here we see it also works for use-associated operators loaded from a module.
PROGRAM main
USE m, ONLY: mynum, check_in_module
IMPLICIT NONE
TYPE(mynum) :: num1, num2, num3
REAL :: real_var
INTEGER :: int_var
CALL check_in_module ()
num1 = mynum (1.0, 2)
num2 = mynum (2.0, 3)
num3 = num1 + num2
IF (num3%num_real /= 3.0 .OR. num3%num_int /= 5) CALL abort ()
num3 = num1 + 5
IF (num3%num_real /= 1.0 .OR. num3%num_int /= 7) CALL abort ()
num3 = num1 + (-100.5)
IF (num3%num_real /= -99.5 .OR. num3%num_int /= 2) CALL abort ()
num3 = 42
num3 = -1.2
IF (num3%num_real /= -1.2 .OR. num3%num_int /= 42) CALL abort ()
real_var = num3
int_var = num3
IF (real_var /= -1.2 .OR. int_var /= 42) CALL abort ()
IF (.GET. num1 /= 3.0) CALL abort ()
END PROGRAM main
! { dg-final { cleanup-modules "m" } }
! { dg-do compile }
! { dg-options "-w" }
! FIXME: Remove -w when CLASS is fully implemented.
! Type-bound procedures
! Check for errors with operator calls.
MODULE m
IMPLICIT NONE
TYPE myint
INTEGER :: value
CONTAINS
PROCEDURE, PASS :: add_int
PROCEDURE, PASS :: assign_int
GENERIC, PRIVATE :: OPERATOR(.PLUS.) => add_int
GENERIC, PRIVATE :: OPERATOR(+) => add_int
GENERIC, PRIVATE :: ASSIGNMENT(=) => assign_int
END TYPE myint
TYPE myreal
REAL :: value
CONTAINS
PROCEDURE, PASS :: add_real
PROCEDURE, PASS :: assign_real
GENERIC :: OPERATOR(.PLUS.) => add_real
GENERIC :: OPERATOR(+) => add_real
GENERIC :: ASSIGNMENT(=) => assign_real
END TYPE myreal
CONTAINS
PURE TYPE(myint) FUNCTION add_int (a, b)
CLASS(myint), INTENT(IN) :: a
INTEGER, INTENT(IN) :: b
add_int = myint (a%value + b)
END FUNCTION add_int
PURE SUBROUTINE assign_int (dest, from)
CLASS(myint), INTENT(OUT) :: dest
INTEGER, INTENT(IN) :: from
dest = myint (from)
END SUBROUTINE assign_int
TYPE(myreal) FUNCTION add_real (a, b)
CLASS(myreal), INTENT(IN) :: a
REAL, INTENT(IN) :: b
add_real = myreal (a%value + b)
END FUNCTION add_real
SUBROUTINE assign_real (dest, from)
CLASS(myreal), INTENT(OUT) :: dest
REAL, INTENT(IN) :: from
dest = myreal (from)
END SUBROUTINE assign_real
SUBROUTINE in_module ()
TYPE(myint) :: x
x = 0 ! { dg-bogus "Can't convert" }
x = x + 42 ! { dg-bogus "Operands of" }
x = x .PLUS. 5 ! { dg-bogus "Unknown operator" }
END SUBROUTINE in_module
PURE SUBROUTINE iampure ()
TYPE(myint) :: x
x = 0 ! { dg-bogus "is not PURE" }
x = x + 42 ! { dg-bogus "to a non-PURE procedure" }
x = x .PLUS. 5 ! { dg-bogus "to a non-PURE procedure" }
END SUBROUTINE iampure
END MODULE m
PURE SUBROUTINE iampure2 ()
USE m
IMPLICIT NONE
TYPE(myreal) :: x
x = 0.0 ! { dg-error "is not PURE" }
x = x + 42.0 ! { dg-error "to a non-PURE procedure" }
x = x .PLUS. 5.0 ! { dg-error "to a non-PURE procedure" }
END SUBROUTINE iampure2
PROGRAM main
USE m
IMPLICIT NONE
TYPE(myint) :: x
x = 0 ! { dg-error "Can't convert" }
x = x + 42 ! { dg-error "Operands of" }
x = x .PLUS. 5 ! { dg-error "Unknown operator" }
END PROGRAM main
! { dg-final { cleanup-modules "m" } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment