aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2011-02-18 19:52:16 +0000
committerMichael Matz <matz@gcc.gnu.org>2011-02-18 19:52:16 +0000
commitb3c1b8a1d6838854acf96be354339a62ff27599e (patch)
treeed9bae538119f7a14e04f53cad9c5316df51293e /gcc/fortran
parent430aa86819b6a4e6a806220886a77a08e5afc0f8 (diff)
downloadgcc-b3c1b8a1d6838854acf96be354339a62ff27599e.zip
gcc-b3c1b8a1d6838854acf96be354339a62ff27599e.tar.gz
gcc-b3c1b8a1d6838854acf96be354339a62ff27599e.tar.bz2
re PR fortran/45586 (ICE non-trivial conversion at assignment)
PR fortran/45586 * gfortran.h (struct gfc_component): Add norestrict_decl member. * trans.h (struct lang_type): Add nonrestricted_type member. * trans-expr.c (gfc_conv_component_ref): Search fields with correct parent type. * trans-types.c (mirror_fields, gfc_nonrestricted_type): New. (gfc_sym_type): Use it. testsuite/ PR fortran/45586 * gfortran.dg/lto/pr45586_0.f90: New test. * gfortran.dg/typebound_proc_20.f90: Ditto. * gfortran.dg/typebound_proc_21.f90: Ditto. From-SVN: r170284
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog10
-rw-r--r--gcc/fortran/gfortran.h4
-rw-r--r--gcc/fortran/trans-expr.c20
-rw-r--r--gcc/fortran/trans-types.c168
-rw-r--r--gcc/fortran/trans.h1
5 files changed, 203 insertions, 0 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 31ed636..c0b8d5a 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,13 @@
+2011-02-18 Michael Matz <matz@suse.de>
+
+ PR fortran/45586
+ * gfortran.h (struct gfc_component): Add norestrict_decl member.
+ * trans.h (struct lang_type): Add nonrestricted_type member.
+ * trans-expr.c (gfc_conv_component_ref): Search fields with correct
+ parent type.
+ * trans-types.c (mirror_fields, gfc_nonrestricted_type): New.
+ (gfc_sym_type): Use it.
+
2011-02-18 Janus Weil <janus@gcc.gnu.org>
PR fortran/47768
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index ae12534..b64fa20 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -934,6 +934,10 @@ typedef struct gfc_component
gfc_array_spec *as;
tree backend_decl;
+ /* Used to cache a FIELD_DECL matching this same component
+ but applied to a different backend containing type that was
+ generated by gfc_nonrestricted_type. */
+ tree norestrict_decl;
locus loc;
struct gfc_expr *initializer;
struct gfc_component *next;
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index b7d7ed9..3cf8df5 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -504,6 +504,26 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref)
field = c->backend_decl;
gcc_assert (TREE_CODE (field) == FIELD_DECL);
decl = se->expr;
+
+ /* Components can correspond to fields of different containing
+ types, as components are created without context, whereas
+ a concrete use of a component has the type of decl as context.
+ So, if the type doesn't match, we search the corresponding
+ FIELD_DECL in the parent type. To not waste too much time
+ we cache this result in norestrict_decl. */
+
+ if (DECL_FIELD_CONTEXT (field) != TREE_TYPE (decl))
+ {
+ tree f2 = c->norestrict_decl;
+ if (!f2 || DECL_FIELD_CONTEXT (f2) != TREE_TYPE (decl))
+ for (f2 = TYPE_FIELDS (TREE_TYPE (decl)); f2; f2 = DECL_CHAIN (f2))
+ if (TREE_CODE (f2) == FIELD_DECL
+ && DECL_NAME (f2) == DECL_NAME (field))
+ break;
+ gcc_assert (f2);
+ c->norestrict_decl = f2;
+ field = f2;
+ }
tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
decl, field, NULL_TREE);
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 7c29974..0626a87 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -1746,6 +1746,171 @@ gfc_build_pointer_type (gfc_symbol * sym, tree type)
else
return build_pointer_type (type);
}
+
+static tree gfc_nonrestricted_type (tree t);
+/* Given two record or union type nodes TO and FROM, ensure
+ that all fields in FROM have a corresponding field in TO,
+ their type being nonrestrict variants. This accepts a TO
+ node that already has a prefix of the fields in FROM. */
+static void
+mirror_fields (tree to, tree from)
+{
+ tree fto, ffrom;
+ tree *chain;
+
+ /* Forward to the end of TOs fields. */
+ fto = TYPE_FIELDS (to);
+ ffrom = TYPE_FIELDS (from);
+ chain = &TYPE_FIELDS (to);
+ while (fto)
+ {
+ gcc_assert (ffrom && DECL_NAME (fto) == DECL_NAME (ffrom));
+ chain = &DECL_CHAIN (fto);
+ fto = DECL_CHAIN (fto);
+ ffrom = DECL_CHAIN (ffrom);
+ }
+
+ /* Now add all fields remaining in FROM (starting with ffrom). */
+ for (; ffrom; ffrom = DECL_CHAIN (ffrom))
+ {
+ tree newfield = copy_node (ffrom);
+ DECL_CONTEXT (newfield) = to;
+ /* The store to DECL_CHAIN might seem redundant with the
+ stores to *chain, but not clearing it here would mean
+ leaving a chain into the old fields. If ever
+ our called functions would look at them confusion
+ will arise. */
+ DECL_CHAIN (newfield) = NULL_TREE;
+ *chain = newfield;
+ chain = &DECL_CHAIN (newfield);
+
+ if (TREE_CODE (ffrom) == FIELD_DECL)
+ {
+ tree elemtype = gfc_nonrestricted_type (TREE_TYPE (ffrom));
+ TREE_TYPE (newfield) = elemtype;
+ }
+ }
+ *chain = NULL_TREE;
+}
+
+/* Given a type T, returns a different type of the same structure,
+ except that all types it refers to (recursively) are always
+ non-restrict qualified types. */
+static tree
+gfc_nonrestricted_type (tree t)
+{
+ tree ret = t;
+
+ /* If the type isn't layed out yet, don't copy it. If something
+ needs it for real it should wait until the type got finished. */
+ if (!TYPE_SIZE (t))
+ return t;
+
+ if (!TYPE_LANG_SPECIFIC (t))
+ TYPE_LANG_SPECIFIC (t)
+ = ggc_alloc_cleared_lang_type (sizeof (struct lang_type));
+ /* If we're dealing with this very node already further up
+ the call chain (recursion via pointers and struct members)
+ we haven't yet determined if we really need a new type node.
+ Assume we don't, return T itself. */
+ if (TYPE_LANG_SPECIFIC (t)->nonrestricted_type == error_mark_node)
+ return t;
+
+ /* If we have calculated this all already, just return it. */
+ if (TYPE_LANG_SPECIFIC (t)->nonrestricted_type)
+ return TYPE_LANG_SPECIFIC (t)->nonrestricted_type;
+
+ /* Mark this type. */
+ TYPE_LANG_SPECIFIC (t)->nonrestricted_type = error_mark_node;
+
+ switch (TREE_CODE (t))
+ {
+ default:
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ {
+ tree totype = gfc_nonrestricted_type (TREE_TYPE (t));
+ if (totype == TREE_TYPE (t))
+ ret = t;
+ else if (TREE_CODE (t) == POINTER_TYPE)
+ ret = build_pointer_type (totype);
+ else
+ ret = build_reference_type (totype);
+ ret = build_qualified_type (ret,
+ TYPE_QUALS (t) & ~TYPE_QUAL_RESTRICT);
+ }
+ break;
+
+ case ARRAY_TYPE:
+ {
+ tree elemtype = gfc_nonrestricted_type (TREE_TYPE (t));
+ if (elemtype == TREE_TYPE (t))
+ ret = t;
+ else
+ {
+ ret = build_variant_type_copy (t);
+ TREE_TYPE (ret) = elemtype;
+ if (TYPE_LANG_SPECIFIC (t)
+ && GFC_TYPE_ARRAY_DATAPTR_TYPE (t))
+ {
+ tree dataptr_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (t);
+ dataptr_type = gfc_nonrestricted_type (dataptr_type);
+ if (dataptr_type != GFC_TYPE_ARRAY_DATAPTR_TYPE (t))
+ {
+ TYPE_LANG_SPECIFIC (ret)
+ = ggc_alloc_cleared_lang_type (sizeof (struct
+ lang_type));
+ *TYPE_LANG_SPECIFIC (ret) = *TYPE_LANG_SPECIFIC (t);
+ GFC_TYPE_ARRAY_DATAPTR_TYPE (ret) = dataptr_type;
+ }
+ }
+ }
+ }
+ break;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ tree field;
+ /* First determine if we need a new type at all.
+ Careful, the two calls to gfc_nonrestricted_type per field
+ might return different values. That happens exactly when
+ one of the fields reaches back to this very record type
+ (via pointers). The first calls will assume that we don't
+ need to copy T (see the error_mark_node marking). If there
+ are any reasons for copying T apart from having to copy T,
+ we'll indeed copy it, and the second calls to
+ gfc_nonrestricted_type will use that new node if they
+ reach back to T. */
+ for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ tree elemtype = gfc_nonrestricted_type (TREE_TYPE (field));
+ if (elemtype != TREE_TYPE (field))
+ break;
+ }
+ if (!field)
+ break;
+ ret = build_variant_type_copy (t);
+ TYPE_FIELDS (ret) = NULL_TREE;
+
+ /* Here we make sure that as soon as we know we have to copy
+ T, that also fields reaching back to us will use the new
+ copy. It's okay if that copy still contains the old fields,
+ we won't look at them. */
+ TYPE_LANG_SPECIFIC (t)->nonrestricted_type = ret;
+ mirror_fields (ret, t);
+ }
+ break;
+ }
+
+ TYPE_LANG_SPECIFIC (t)->nonrestricted_type = ret;
+ return ret;
+}
+
/* Return the type for a symbol. Special handling is required for character
types to get the correct level of indirection.
@@ -1796,6 +1961,9 @@ gfc_sym_type (gfc_symbol * sym)
restricted = !sym->attr.target && !sym->attr.pointer
&& !sym->attr.proc_pointer && !sym->attr.cray_pointee;
+ if (!restricted)
+ type = gfc_nonrestricted_type (type);
+
if (sym->attr.dimension)
{
if (gfc_is_nodesc_array (sym))
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 26ac003..9695c5a 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -700,6 +700,7 @@ struct GTY((variable_size)) lang_type {
tree dataptr_type;
tree span;
tree base_decl[2];
+ tree nonrestricted_type;
};
struct GTY((variable_size)) lang_decl {