Testers needed for ISO C Binding patch

Tobias Schlüter tobias.schlueter@physik.uni-muenchen.de
Thu Jun 7 16:02:00 GMT 2007


Between all the whitespace changes and no ChangeLog, I don't yet have a 
high-level overview of what the patch does, but here are a few local 
remarks.

Steve Kargl wrote:
> @@ -334,8 +334,8 @@ gfc_compare_derived_types (gfc_symbol *d
>    /* Special case for comparing derived types across namespaces.  If the
>       true names and module names are the same and the module name is
>       nonnull, then they are equal.  */
> -  if (strcmp (derived1->name, derived2->name) == 0
> -      && derived1 != NULL && derived2 != NULL
> +  if (derived1 != NULL && derived2 != NULL
> +      && strcmp (derived1->name, derived2->name) == 0
>        && derived1->module != NULL && derived2->module != NULL
>        && strcmp (derived1->module, derived2->module) == 0)
>      return 1;

I don't really understand under which circumstance both pointers could 
be NULL, but these strings are allocated via gfc_get_string, so you 
could just compare the pointers instead of using strcmp.

> +  if (expr != NULL && expr->ts.type == BT_DERIVED
> +      && expr->ts.is_iso_c && expr->ts.derived)
> +    if (expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_PTR
> +        || expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_FUNPTR)
> +      expr = gfc_int_expr (0);
> +  

A single if would be sufficient.

> +  /* We need to convert the expressions for the iso_c_binding derived types.
> +     C_NULL_PTR and C_NULL_FUNPTR will be made EXPR_NULL, which evaluates to
> +     null_pointer_node.  C_PTR and C_FUNPTR are converted to match the
> +     typespec for the C_PTR and C_FUNPTR symbols, which has already been
> +     updated to be an integer with a kind equal to the size of a (void *).  */
> +  if (expr->ts.type == BT_DERIVED && expr->ts.derived
> +      && expr->ts.derived->attr.is_iso_c)
> +    {
> +      if (expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_PTR
> +          || expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_FUNPTR)
> +        {
> +          /* Try simply setting expr_type to EXPR_NULL, which should result
> +             in null_pointer_node being used below.  */
> +          expr->expr_type = EXPR_NULL;

So, does it work or not? :-)

> +  if (sym->attr.is_bind_c == 1)
> +    {
> +      /* BIND(C) variables should not be implicitly declared.  */
> +      gfc_warning_now ("Implicitly declared BIND(C) variable '%s' at %L may "
> +                       "not be C interoperable", sym->name, &sym->declared_at);
> +      sym->ts.f90_type = sym->ts.type;
> +    }

I think "BIND(C)" is redundant in that message.

> +
> +  if (sym->attr.dummy != 0)
> +    {
> +      if (sym->ns->proc_name != NULL
> +	  && (sym->ns->proc_name->attr.subroutine != 0
> +	      || sym->ns->proc_name->attr.function != 0)
> +	  && sym->ns->proc_name->attr.is_bind_c != 0)
> +        {
> +          /* Dummy args to a BIND(C) routine may not be interoperable if
> +             they are implicitly typed.  */
> +          gfc_warning_now ("Implicity declared variable '%s' at %L may not "
> +                           "be C interoperable but it is a dummy argument to "
> +                           "the BIND(C) procedure '%s' at %L", sym->name,
> +                           &(sym->declared_at), sym->ns->proc_name->name,
> +                           &(sym->ns->proc_name->declared_at));
> +          sym->ts.f90_type = sym->ts.type;
> +        }
> +    }

Again, a single if is sufficient?  I'm also not a fan of comparing 
against zero.  I.e. I'd prefer
   if (sym->attr.dummy && sym->ns->proc_name && ...)
In the rest of the patch there are several places where 
sym->attr.something == 1 or != 1 is checked.  I think this is actually 
confusing.  They can only take the values 0 or 1, but the check looks 
like a vlaue of 2 might actually mean something different.

> @@ -596,6 +636,8 @@ check_conflict (symbol_attribute * attr,
>        conf2 (value);
>        conf2 (volatile_);
>        conf2 (threadprivate);
> +      /* TODO: hmm, double check this.  */
> +      conf2 (value);
>        break;
>  
>      default:

This condition is already checked in the first line of this hunk.

> @@ -637,8 +679,9 @@ conflict_std:
>  /* Mark a symbol as referenced.  */
>  
>  void
> -gfc_set_sym_referenced (gfc_symbol * sym)
> +gfc_set_sym_referenced (gfc_symbol *sym)
>  {
> +
>    if (sym->attr.referenced)
>      return;
>  

We don't require empty lines in the beginning of functions with no 
variable declarations.  In the interest of keeping the merge simple and 
since Brooks already merged these changes, I believe we should remove 
them at a later time.

> @@ -1435,6 +1514,19 @@ gfc_copy_attr (symbol_attribute * dest, 
>    if (src->intrinsic)
>      dest->intrinsic = 1;
>  
> +  is_proc_lang_bind_spec = (src->flavor == FL_PROCEDURE ? 1 : 0);

No need for the ternary here.

> @@ -1937,13 +2032,13 @@ compare_symtree (void * _st1, void * _st
>  /* Allocate a new symtree node and associate it with the new symbol.  */
>  
>  gfc_symtree *
> -gfc_new_symtree (gfc_symtree ** root, const char *name)
> +gfc_new_symtree (gfc_symtree **root, const char *name)
>  {
>    gfc_symtree *st;
>  
>    st = gfc_getmem (sizeof (gfc_symtree));
>    st->name = gfc_get_string (name);
> -
> +  

This looks like whitespace damage.

> @@ -2074,6 +2169,16 @@ gfc_new_symbol (const char *name, gfc_na
>      gfc_internal_error ("new_symbol(): Symbol name too long");
>  
>    p->name = gfc_get_string (name);
> +
> +  /* Make sure flags for symbol being C bound are clear initially.  */
> +  p->attr.is_bind_c = 0;
> +  p->attr.is_iso_c = 0;

These are handled by gfc_clear_attr ().

> +try
> +verify_bind_c_derived_type (gfc_symbol *derived_sym)
> +{
> +  gfc_component *curr_comp = NULL;
> +  try is_c_interop = FAILURE;
> +  try retval = SUCCESS;
> +   
> +  if (derived_sym == NULL)
> +    gfc_internal_error ("verify_bind_c_derived_type(): Given symbol is "
> +                        "unexpectedly NULL");
> +
> +  /* The derived type must have the BIND attribute to be interoperable
> +     J3/04-007, Section 15.2.3.  */
> +  if (derived_sym->attr.is_bind_c != 1)
> +    {
> +      derived_sym->ts.is_c_interop = 0;
> +      gfc_error_now ("Derived type '%s' declared at %L must have the BIND "
> +                     "attribute to be C interoperable", derived_sym->name,
> +                     &(derived_sym->declared_at));

In other places it's called the BIND(C) attribute.

> +  /* Initialize the derived type as being C interoperable.
> +     If we find an error in the components, this will be set false.  */
> +  derived_sym->ts.is_c_interop = 1;
> +  
> +  /* Loop through the list of components to verify that the kind of
> +     each is a C interoperable type.  */
> +  do
> +    {
> +      /* BIND(C) derived types can't have derived types in them unless
> +	 they're c_ptr or c_funptr. J3/04-007, Section 15.2.3, C1502.  */
> +      if (curr_comp->ts.type == BT_DERIVED
> +	  && curr_comp->ts.derived->ts.is_iso_c != 1)
> +        {
> +          /* This should be allowed; the draft says a derived-type can not
> +             have type parameters if it is has the BIND attribute.  Type
> +             parameters seem to be for making parameterized derived types.
> +             There's no need to verify the type if it is c_ptr/c_funptr.  */
> +          retval = verify_bind_c_derived_type (curr_comp->ts.derived);

This will break for POINTER components, unless I'm mistaken.
type t
   type (t), pointer :: next
end type t
-> infinite recursion
I also believe this will break for ALLOCATABLE array components -- they 
are not C interoperable, but I don't see it checked here.

Hm, reading forther I realize that zou have the appropriate checks, just 
not in place where they're are performed for derived type components: 
these two should be moved to hte beginning of the loop.

> +	  /* The components can not be pointers (fortran sense).  
> +	     J3/04-007, Section 15.2.3, C1505.	*/
> +	  if (curr_comp->pointer != 0)
> +	    {
> +	      gfc_error ("Component '%s' at %L cannot have the "
> +                         "POINTER attribute because it is a member "
> +                         "of the BIND(C) derived type '%s' at %L",
> +                         curr_comp->name, &(curr_comp->loc),
> +                         derived_sym->name, &(derived_sym->declared_at));
> +	      retval = FAILURE;
> +	    }
> +
> +	  /* The components can not be allocatable.
> +	     J3/04-007, Section 15.2.3, C1505.	*/
> +	  if (curr_comp->allocatable != 0)
> +	    {
> +	      gfc_error ("Component '%s' at %L cannot have the "
> +			 "ALLOCATABLE attribute because it is a member "
> +			 "of the BIND(C) derived type '%s' at %L",
> +			 curr_comp->name, &(curr_comp->loc),
> +			 derived_sym->name, &(derived_sym->declared_at));
> +	      retval = FAILURE;
> +	    }
> +	}
> +      
> +      curr_comp = curr_comp->next;
> +    } while (curr_comp != NULL); 

I'd prefer
   }
while (curr_comp = curr_comp->next);

Also note the whitespace change.

> +/* Generate symbols for the named constants c_null_ptr and c_null_funptr.  */
> +
> +static try
> +gen_special_c_interop_ptr (int ptr_id, const char *ptr_name,
...
> +      generate_isocbinding_symbol (module_name, ptr_id == ISOCBINDING_NULL_PTR 
> +                                   ? ISOCBINDING_PTR : ISOCBINDING_FUNPTR,
> +                                   (char *) (ptr_id == ISOCBINDING_NULL_PTR 
> +				   ? "_gfortran_iso_c_binding_c_ptr"
> +				   : "_gfortran_iso_c_binding_c_funptr"));

The cast to char * is wrong.  Instead, use const char * for 
generate_isocbinding_symbol's last argument and its name variable.

> +  /* Set the binding_label.  */
> +  sprintf (tmp_sym->binding_label, "%s_%s", module_name, tmp_sym->name);

This can overflow the target string by one character :-) 
gfc_symbol->binding_label should be a const char *, and you should be using
   tmp_sym->binding_label = gfc_get_string ("%s_%s", module_name,
                                            tmp_sym->name);
instead.  Be sure to remove the declaration of GFC_MAX_BINDING_LABEL_LEN 
at the same time.


I'll have to stop here for the moment.  I'll try to give the patch a 
thorough and complete look during the weekend.  Looking at my xterm I 
have bad news to report: my build on darwin-i386 failed with the 
following error:
libtool: compile: unable to infer tagged configuration
libtool: compile: specify a tag with `--tag'
make[6]: *** [iso_c_generated_procs.lo] Error 1
make[6]: *** Waiting for unfinished jobs....
libtool: compile: unable to infer tagged configuration
libtool: compile: specify a tag with `--tag'
make[6]: *** [iso_c_binding.lo] Error 1
make[5]: *** [all] Error 2
make[4]: *** [multi-do] Error 1
make[3]: *** [all-multi] Error 2
make[2]: *** [all] Error 2
make[1]: *** [all-target-libgfortran] Error 2
make: *** [all] Error 2


I'll try again with a clean build dir, and will report back.

Cheers,
- Tobi



More information about the Fortran mailing list