OK, I played a bit myself to see what the "right way" would look like, and I 
came up with the attached patch, which is complicated, and not even correct. 
And indeed, it plays with allocatable and pointer stuff.
So your approach makes some sense now.

I do here some propositions for comment and error messages which IMO explain 
better where the problem lies (Iff I have understood the problem correctly). 
They are quite verbose however, and possibly not correct english (many 
negations). 
One could consider separating the "is LOCK_TYPE type" and "type has type 
LOCK_TYPE components" cases to make the diagnostic easier to read, but that 
would make the code even more complex.
Anyway comments and propositions welcome. 

review, 2nd try:
> diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
> index 2910ab5..9f732e5 100644
> --- a/gcc/fortran/parse.c
> +++ b/gcc/fortran/parse.c
> @@ -2148,15 +2157,61 @@ endType:
>  
>        /* Looking for coarray components.  */
>        if (c->attr.codimension
> -       || (c->attr.coarray_comp && !c->attr.pointer && !c->attr.allocatable))
> -     sym->attr.coarray_comp = 1;
> +       || (c->ts.type == BT_CLASS && c->attr.class_ok
> +           && CLASS_DATA (c)->attr.codimension))
> +     {
> +       coarray = true;
> +       sym->attr.coarray_comp = 1;
> +     }
> +     
> +      if (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.codimension)
- Err, is the codimension attribute on the derived type?
Or did you mean [...] && c->ts.u.derived->attr.coarray_comp (to match the code 
removed)?
> +     {
> +       coarray = true;
> +       if (!pointer && !allocatable)
> +         sym->attr.coarray_comp = 1;
> +     }
>  
>        /* Looking for lock_type components.  */
> -      if (c->attr.lock_comp
> -       || (sym->ts.type == BT_DERIVED
> +      if ((c->ts.type == BT_DERIVED
>             && c->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
> -           && c->ts.u.derived->intmod_sym_id == ISOFORTRAN_LOCK_TYPE))
> -     sym->attr.lock_comp = 1;
> +           && c->ts.u.derived->intmod_sym_id == ISOFORTRAN_LOCK_TYPE)
> +       || (c->ts.type == BT_CLASS && c->attr.class_ok
> +           && CLASS_DATA (c)->ts.u.derived->from_intmod
> +              == INTMOD_ISO_FORTRAN_ENV
> +           && CLASS_DATA (c)->ts.u.derived->intmod_sym_id
> +              == ISOFORTRAN_LOCK_TYPE)
> +       || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.lock_comp
> +           && !allocatable && !pointer))
> +     {
> +       lock_type = 1;
> +       lock_comp = c;
> +       sym->attr.lock_comp = 1;
> +     }
> +
> +      /* F2008, C1302.  */
> +
Additional comment:
/* 5.3.14: An entity with the pointer attribute shall not be a coarray.
   2.4.7: A subobject of a coarray is a coarray if it doesn't have any pointer
   component selection.  */
> +      if (pointer && !coarray && (lock_type
> +                               || (c->ts.type == BT_DERIVED
> +                                   && c->ts.u.derived->attr.lock_comp)))
> +     gfc_error ("Component %s at %L of type LOCK_TYPE or with subcomponent "
> +                "of type LOCK_TYPE is a pointer but not a coarray",
> +                c->name, &c->loc);
"Component %s at %L can be neither a coarray as it is a pointer, nor a non-
coarray as it would be a non-coarray of type LOCK_TYPE or would have a non-
coarray subcomponent of type LOCK_TYPE", c->name, &c->loc

> +
/* 2.4.7: A subobject of a coarray is a coarray if it doesn't have any
   allocatable component selection. 
   Thus, an allocatable component has to be a coarray for its subcomponents to
   be coarrays.  */
> +      if (lock_type && allocatable && !coarray)
- If lock_type && allocatable is true, then subcomponents of type LOCK_TYPE 
are discarded (cf the condition above for lock_type = 1), is that right?
I don't think you have this case in the tests you proposed.

> +     gfc_error ("Component %s at %L of type LOCK_TYPE or with subcomponent "
> +                "of type LOCK_TYPE is allocatable but not a "
> +                "coarray", c->name, &c->loc);
"Allocatable component %s at %L can't be a non-coarray as it would be a non-
coarray of type LOCK_TYPE or it would have a non-coarray sub-component of type 
LOCK_TYPE"

> +
/* 5.3.6: An entity whose type has a coarray ultimate component shall not be a
   coarray.  */
> +      if (sym->attr.coarray_comp && !coarray && lock_type)
> +     gfc_error ("Component %s at %L of type LOCK_TYPE or with subcomponent "
> +                "of type LOCK_TYPE is not a coarray, but other coarray "
> +                "components exist", c->name, &c->loc);
"An entity of type %s at %L can be neither a coarray as it has a coarray 
sub-component, nor a non-coarray as its sub-component %s would be a non-
coarray of type LOCK_TYPE or would have a non-coarray sub-component of type 
LOCK_TYPE"

> +
> +      if (sym->attr.lock_comp && coarray && !lock_type)
> +     gfc_error ("Component %s at %L of type LOCK_TYPE or with subcomponent "
> +                "of type LOCK_TYPE has to be a coarray as %s at %L has a "
> +                "codimension", lock_comp->name, &lock_comp->loc, c->name,
> +                &c->loc);
"An entity of type %s at %L can be neither a coarray as its component %s at %L 
has a codimension, nor a non-coarray as its component %s at %L would be a
non-coarray of type LOCK_TYPE or would have a non-coarray sub-component of 
type LOCK_TYPE"

>  
>        /* Look for private components.  */
>        if (sym->component_access == ACCESS_PRIVATE

The rest looks good.

Mikael
diff --git a/gfortran.h b/gfortran.h
index acfa9d4..e03f172 100644
--- a/gfortran.h
+++ b/gfortran.h
@@ -786,6 +786,8 @@ typedef struct
 
   /* The namespace where the attribute has been set.  */
   struct gfc_namespace *volatile_ns, *asynchronous_ns;
+
+  const char *lock_comp_ref, *noncoarray_lock_comp_ref;
 }
 symbol_attribute;
 
diff --git a/resolve.c b/resolve.c
index b8a8ebb..fedad13 100644
--- a/resolve.c
+++ b/resolve.c
@@ -12087,6 +12087,112 @@ resolve_fl_parameter (gfc_symbol *sym)
 }
 
 
+static bool
+is_type_lock_type (gfc_typespec *ts)
+{
+  return (ts->type == BT_DERIVED
+	  && ts->u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
+	  && ts->u.derived->intmod_sym_id == ISOFORTRAN_LOCK_TYPE);
+}
+
+
+static const char *
+set_subref_str (const char **dest, const char *base_name,
+		const char *subref)
+{
+  const unsigned int bufflen = strlen(base_name) + strlen(subref) + 2;
+  char *str;
+
+  if (subref == NULL || !strcmp (subref, ""))
+    return NULL;
+    
+  str = XCNEWVEC (char, bufflen);
+  snprintf (str, bufflen, "%s%%%s", base_name, subref);
+  *dest = str;
+  return *dest;
+}
+
+
+static const char *comp_pick_lock_comp (gfc_component *);
+
+static const char *
+type_pick_lock_comp (gfc_symbol *derived)
+{
+  gfc_component *c;
+  const char *str;
+
+  if (derived->attr.lock_comp_ref != NULL)
+    return derived->attr.lock_comp_ref;
+
+  for (c = derived->components; c; c = c->next)
+    {
+      str = set_subref_str (&c->attr.lock_comp_ref, c->name,
+			    comp_pick_lock_comp (c));
+      if (str != NULL)
+	return str;
+    }
+
+  derived->attr.lock_comp_ref = "";
+  return derived->attr.lock_comp_ref;
+}
+
+
+static const char *
+type_pick_noncoarray_lock_comp (gfc_symbol *derived)
+{
+  gfc_component *c;
+  gfc_typespec *ts;
+  const char *str;
+
+  if (derived->attr.noncoarray_lock_comp_ref != NULL)
+    return derived->attr.noncoarray_lock_comp_ref;
+
+  for (c = derived->components; c; c = c->next)
+    {
+      ts = &c->ts;
+      if (ts->type != BT_DERIVED)
+	continue;
+
+      if (!c->attr.codimension && is_type_lock_type (&c->ts))
+	{
+	  c->attr.noncoarray_lock_comp_ref = gfc_get_string (c->name);
+	  return c->attr.noncoarray_lock_comp_ref;
+	}
+
+      if (c->attr.pointer || c->attr.allocatable)
+	{
+	  str = set_subref_str (&c->attr.noncoarray_lock_comp_ref, 
+				c->name, comp_pick_lock_comp (c));
+	  if (str != NULL)
+	    return str;
+	}
+      else
+	{
+	  str = set_subref_str (&c->attr.noncoarray_lock_comp_ref, c->name,
+				type_pick_noncoarray_lock_comp (c->ts.u.derived));
+	  if (str != NULL)
+	    return str;
+	}
+    }
+
+  derived->attr.noncoarray_lock_comp_ref = "";
+  return derived->attr.noncoarray_lock_comp_ref;
+}
+
+
+static const char *
+comp_pick_lock_comp (gfc_component *comp)
+{
+  if (comp->ts.type != BT_DERIVED)
+    return NULL;
+
+  if (is_type_lock_type (&comp->ts))
+    return gfc_get_string (comp->name);
+
+  return type_pick_lock_comp (comp->ts.u.derived);
+}
+
+
 /* Do anything necessary to resolve a symbol.  Right now, we just
    assume that an otherwise unknown symbol is a variable.  This sort
    of thing commonly happens for symbols in module.  */
@@ -12403,15 +12509,28 @@ resolve_symbol (gfc_symbol *sym)
 			 sym->ts.u.derived->name) == FAILURE)
     return;
 
-  /* F2008, C1302.  */
-  if (sym->ts.type == BT_DERIVED
-      && sym->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
-      && sym->ts.u.derived->intmod_sym_id == ISOFORTRAN_LOCK_TYPE
-      && !sym->attr.codimension)
+  if (!sym->attr.codimension)
     {
-      gfc_error ("Variable '%s' at %L of type LOCK_TYPE must be a coarray",
-		 sym->name, &sym->declared_at);
-      return;
+      if (is_type_lock_type (&sym->ts))
+	{
+	  gfc_error ("Variable '%s' at %L must be a coarray as it is of type "
+		     "LOCK_TYPE", sym->name, &sym->declared_at);
+	  return;
+	}
+      else if (sym->ts.type == BT_DERIVED)
+	{
+	  const char *comp_ref =
+		  type_pick_noncoarray_lock_comp (sym->ts.u.derived);
+	
+	  if (strcmp (comp_ref, "") != 0) 
+	    {
+	      gfc_error ("Variable '%s' at %L must be a coarray as its "
+			 "sub-component '%s%%%s' is a non-coarray of type "
+			 "LOCK_TYPE.", sym->name, &sym->declared_at, sym->name,
+			 comp_ref);
+	      return;
+	    }
+	}
     }
 
   /* An assumed-size array with INTENT(OUT) shall not be of a type for which

Reply via email to