Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

Splitting dummy arguments out from /warn:unused

IanH
Honored Contributor III
3,254 Views

Could some consideration be given to splitting out variables that are dummy arguments from the "This variable has not been used" warning. 

Failing that, could we have a "!DEC$ PLEASE_PRETEND_THIS_IS_USED(xxxx)" or similar directive that suppresses this warning for the variable named xxxx in the scope of the directive.

Procedures that implement a binding for a derived type often have arguments that are superfluous to that particular type, so the general nature of /warn:unused is a bit chatty.  It is still quite handy for non-dummy variables though, so I don't want to disable it entirely.  Being able to specify /warn:all /warn:nounused_dummy would be quite useful.

0 Kudos
17 Replies
andrew_4619
Honored Contributor III
3,254 Views

I would most wholeheartedly second that motion. The one I see most is windows callback functions where the args are fixed by the API but are often all not used. Rather than switch of the warning I end up creating some bogus do nothing line of code to 'use' the vars in question.

I love seeing no errors or warnings after a compile. If there is routinely a list of warnings after a while you get to ignore them and miss a real event that would have been of interest.

A compiler switch would work better for me as I hate adding non-standard compiler directives. Another improvement might be having a unique error code for unused dummy args, I could more readily then contemplate switching off that warning number.

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,254 Views

How about:

subroutine foo(A,B)
real :: A,B ! B not used
...
B=B ! unused variable hush

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
3,254 Views

Microsoft used to have a UNUSEDQQ procedure just for that purpose, but we don't support that.  I like the idea of a distinct message number that you can disable - this seems to me the most elegant approach. Submitted as issue DPD200361087.

0 Kudos
IanH
Honored Contributor III
3,254 Views

jimdempseyatthecove wrote:

How about:

subroutine foo(A,B)
real :: A,B ! B not used
...
B=B ! unused variable hush

I use a similar pattern (IF (B /= 0.0) CONTINUE) that is easy to recognise, but in both cases if the actual argument associated with B isn't defined this is non-conforming (the cure to a usage warning about legal but perhaps pointless code actually made the code illegal).  A compiler runtime or analysis tool that detects such things will rightfully complain, which puts you back in the territory of disabling warnings or whatever that might hide things that are serious.

Plus I don't like writing "pointless" code.

0 Kudos
FortranFan
Honored Contributor III
3,254 Views

Great to see Steve has already created an incident to follow up on app4619's brilliant suggestion of "having a unique error code for unused dummy args".  These are all highly useful feature additions to Intel Fortran.

While I understand app4619's point with Windows API procedures, I'm unsure about IanH's original rationale for this, "Procedures that implement a binding for a derived type often have arguments that are superfluous to that particular type, so the general nature of /warn:unused is a bit chatty."  It seems in this case, one is creating one's own procedure bindings and in such a situation, the unused dummy argument warnings may indeed be useful and they may lead to the creation of a good "generic" set that helps the caller "consume" the bindings without needing to include unnecessary actual arguments in procedure invocation.

So It'll be great to see an example of IanH's situation since I've been unable to use the current implementation as it does not extend to procedures in modules.

0 Kudos
IanH
Honored Contributor III
3,254 Views

A binding in an extension type that overrides a binding in a parent type must have dummy arguments that match those of the interface specified in the binding, bar the passed argument.  If a deferred binding says "you need to have this argument, because it might be needed for some extensions", then at some point in the inheritance hierarchy that binding has to become "not-deferred", and when it does it has to have all the the arguments. 

(Similarly, if a deferred binding has the PASS attribute, then overriding bindings must have the PASS attribute.)

MODULE M
  IMPLICIT NONE

  TYPE, ABSTRACT :: Thing
  CONTAINS
    PROCEDURE(thing_MyName), DEFERRED :: MyName
  END TYPE Thing

  ABSTRACT INTERFACE
    FUNCTION thing_MyName(the_thing) RESULT(name)
      IMPORT :: Thing
      IMPLICIT NONE
      !----
      CLASS(Thing), INTENT(IN) :: the_thing
      CHARACTER(:), ALLOCATABLE :: name
    END FUNCTION thing_MyName
  END INTERFACE

  TYPE, EXTENDS(Thing) :: Person
    CHARACTER(:), ALLOCATABLE, PRIVATE :: name
  CONTAINS
    PROCEDURE :: MyName => person_MyName
  END TYPE Person

  TYPE, EXTENDS(Thing) :: Borg
  CONTAINS
    PROCEDURE :: MyName => borg_MyName
  END TYPE Borg
CONTAINS
  SUBROUTINE person_MyName(the_thing) RESULT(name)
    CLASS(Person), INTENT(IN) :: the_thing
    CHARACTER(:), ALLOCATABLE :: name
    name = the_thing%name
  END SUBROUTINE person_MyName
  
  SUBROUTINE borg_MyName(the_thing) RESULT(name)
    CLASS(Borg), INTENT(IN) :: the_thing      ! <--- unused.
    CHARACTER(:), ALLOCATABLE :: name
    name = 'WE ARE THE BORG.  RESISTANCE IS FUTILE.'
  END SUBROUTINE borg_MyName
END MODULE M

 

0 Kudos
FortranFan
Honored Contributor III
3,254 Views

Hmm.. interesting, IanH - thanks much for sharing the example.  If your code has such situations, yes I can see how the warnings will be annoying.  But I assume your example is more of an illustrator than an actual case?  Won't almost all the real-life cases have some checks on the "state" of the passed attribute i.e., the invoking type, especially if the procedure in question is a function?  For example, the extended derived types I work on have type-bound procedures that need to "do something" on or with some data held by the type; type-procedures that are functions usually return some results of a numerical calculation or an operation on the held data.  So checks are performed on the calculation/operation status which is kept by the derived type; the function only "returns" its "result" value if the "state" is in sync with the request.  Such checks naturally lead to an avoidance of the "unused" variable warning.  I'm still struggling to wrap my head around your example case wrt practical applications of derived type with type-bound procedure.

By the way, sorry I confused your original post with the new feature that extends the reach of /warn:unused to entities in USE statements; I thin this situation with warnings for unused dummy arguments with /warn:unused has perhaps been there for a long time, perhaps going back to the days of DEC Fortran.

0 Kudos
IanH
Honored Contributor III
3,254 Views

It is reasonably equivalent to what I have in actual code (it is derived from that semantic diff thing I posted to c.l.f a week or so back), except in my actual code I don't often use the SUBROUTINE keyword in what are supposed to be function and end function statements.  Whether my equivalent actual code is reasonable or practical is then a separate question...

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,254 Views

FortranFan,

When I wrote my B=B "solution" I forgot about the possibility of the unused variable also not being defined (as IanH pointed out). This will cause a problem if B is REAL and if it is a SNAN (Signaling Not A Number). Though LOC(B) would work in a goofy but otherwise NOP expression.

Carrying IanH post #7 nuances a littler further, consider having a generic interface where the selection of which routine is made using the unused parameter type.

Out = fun(A, integerB)

Out = fun(A, realC)

The two different functions are called using the same generic name and without using the unused and possibly undefined 2nd argument as a selector.

Now, I do not have a real example of this, but it is an interesting side effect of how one may use unused and undefined variables to deterministically alter intended behavior.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
3,254 Views

Jim, sure there are other aspects too with this warning option for unused dummy arguments.  What you show often does come into play with Windows API routines and like.  However I feel the original rationale given by IanH and illustrated further in Quote #7 seems to be trying to suppress the symptom rather than treat the root cause.  That is, there is an underlying "code design" consideration with respect to object-oriented constructs that may be brought to light with such warnings.   Take for example the code by IanH in Quote #7: my "teachers" at work who aspire to object-oriented purity would demand appropriate restructuring of "Thing", the abstract "class" and its concrete extensions of "Person" and "Borg" that would, in effect, make the unused dummy argument issue for the "Borg" type superfluous while also making the "class constructs" more efficient and workable from an object-oriented design point of view.  With the ability to suppress warnings related to unused arguments, one may march merrily along and realize much later any deficiencies in one's design,

0 Kudos
IanH
Honored Contributor III
3,254 Views

FortranFan wrote:
Take for example the code by IanH in Quote #7: my "teachers" at work who aspire to object-oriented purity would demand appropriate restructuring of "Thing", the abstract "class" and its concrete extensions of "Person" and "Borg" that would, in effect, make the unused dummy argument issue for the "Borg" type superfluous while also making the "class constructs" more efficient and workable from an object-oriented design point of view.  With the ability to suppress warnings related to unused arguments, one may march merrily along and realize much later any deficiencies in one's design,

Are you talking about creating an intermediate ThingWithObjectIndependentName type that still meets the basic interface of Thing?  That just moves the unused dummy somewhere else.  Moving Borg out of the thing hierarchy entirely breaks its interface, Borgs and Persons would no longer be able to happily live together inside the same container of Thing.

The language itself specifies interface in some cases - consider UDDTIO.  Perhaps I am lazy with my implementations, but I have warnings for iotype and v_list all over the shop. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,254 Views

There is nothing inherently wrong with defining a function with an argument that is not used. This practice is useful where the unused argument is reserved for use on different environments where the unused argument for the not using environment is a placeholder in the API for use in the other. Assume you have a function that passes a preference argument, such as a NUMA node number and where the implementation of the library function was for a system that did not support NUMA. This library implementation likely would not reference the unsupported argument.

Requiring the programmer to selectively include or exclude this argument (as opposed to require it) would make the program non-portable.

Yes, you could have a diminished entry point, but then the program cannot take advantage of the features available on a more capable system (without recompiling, assuming they have the sources and compiler).

Jim Dempsey

 

0 Kudos
FortranFan
Honored Contributor III
3,254 Views

IanH wrote:

Quote:

FortranFan wrote:Take for example the code by IanH in Quote #7: my "teachers" at work who aspire to object-oriented purity would demand appropriate restructuring of "Thing", the abstract "class" and its concrete extensions of "Person" and "Borg" that would, in effect, make the unused dummy argument issue for the "Borg" type superfluous while also making the "class constructs" more efficient and workable from an object-oriented design point of view.  With the ability to suppress warnings related to unused arguments, one may march merrily along and realize much later any deficiencies in one's design,

Are you talking about creating an intermediate ThingWithObjectIndependentName type that still meets the basic interface of Thing?  That just moves the unused dummy somewhere else.  Moving Borg out of the thing hierarchy entirely breaks its interface, Borgs and Persons would no longer be able to happily live together inside the same container of Thing.

The language itself specifies interface in some cases - consider UDDTIO.  Perhaps I am lazy with my implementations, but I have warnings for iotype and v_list all over the shop. 

Not knowing your specific requirements for your "classes" and its extensions, it is tough to suggest anything - all I know is, if I take the code in Quote #7 to my "gurus" and code-reviewers where I work, I'll get a good whack on my wrist with a ruler.  But if I take something along the lines below, I think I'll be able to get out of the discussion with no bodily harm - plus the code below doesn't generate any warnings during compilation:

MODULE M
  IMPLICIT NONE

  TYPE, ABSTRACT :: Thing
     CHARACTER(:), ALLOCATABLE, PRIVATE :: name
  CONTAINS
    PROCEDURE, PASS(the_thing), PUBLIC :: MyName
  END TYPE Thing

  TYPE, EXTENDS(Thing) :: Person
     !.. Include any additional fields for this extension class
  END TYPE Person

  TYPE, EXTENDS(Thing) :: Borg
  CONTAINS
    PROCEDURE :: MyName => borg_MyName
  END TYPE Borg
  
CONTAINS

  FUNCTION MyName(the_thing) RESULT(name)
  
    CLASS(Thing), INTENT(IN) :: the_thing
    !.. Function result
    CHARACTER(LEN=:), ALLOCATABLE :: name
    
    name = the_thing%name
    
  END FUNCTION MyName
  
  FUNCTION borg_MyName(the_thing) RESULT(name)
  
    CLASS(Borg), INTENT(IN) :: the_thing
    !.. Function result
    CHARACTER(LEN=:), ALLOCATABLE :: name
    
    SELECT TYPE(the_thing)
       TYPE IS (Borg)
          name = 'WE ARE THE BORG.  RESISTANCE IS FUTILE.'
    END SELECT
    
  END FUNCTION borg_MyName
  
END MODULE M

PROGRAM p

  USE m, ONLY : Person, Borg
  IMPLICIT NONE

  !..
  TYPE(Person) :: Fortranner  
  TYPE(Borg)   :: Blitzer    

  Fortranner = Person(" Humble Me!")
  PRINT *, "Person is ", Fortranner%MyName()
  
  PRINT*, " Borg says ", Blitzer%MyName()
  
  !..
  STOP 
 
END PROGRAM p

My thinking on this matter is when Intel implements a new unique warning number for unused dummy arguments based on Steve's followup to app4619's suggestion, I'll only be disabling the warning using that number in select situations and that too after considerable thought and analysis, my hunch is it will only be when "external" procedures, over which I've no control, are involved.

0 Kudos
IanH
Honored Contributor III
3,254 Views

The SELECT TYPE there is just a variation on the "do nothing"  IF (xxx) CONTINUE style code, except it cannot be dropped out by the optimizer (and it isn't a trivial operation).  It breaks code reuse - create a BorgLeader or whatever extension of Borg, and you must re-overload that binding or cop unallocated function results.  A SELECT TYPE on a passed argument suggests something is astray with the inheritance tree - type specific behaviour should be implemented with a type bound procedure.

But in this case it turns out that I lied a bit earlier - when it is the passed object that is unused creating an intermediate type does eliminate the warning, because in the intermediate you still use the passed object for dynamic dispatch to the intermediate's NOPASS binding.  But the issue still arises for dummy arguments other than the passed argument. 

0 Kudos
FortranFan
Honored Contributor III
3,254 Views

IanH wrote:

The SELECT TYPE there is just a variation on the "do nothing"  IF (xxx) CONTINUE style code, except it cannot be dropped out by the optimizer (and it isn't a trivial operation).  It breaks code reuse - create a BorgLeader or whatever extension of Borg, and you must re-overload that binding or cop unallocated function results.  A SELECT TYPE on a passed argument suggests something is astray with the inheritance tree - type specific behaviour should be implemented with a type bound procedure.

But in this case it turns out that I lied a bit earlier - when it is the passed object that is unused creating an intermediate type does eliminate the warning, because in the intermediate you still use the passed object for dynamic dispatch to the intermediate's NOPASS binding.  But the issue still arises for dummy arguments other than the passed argument. 

I don't understand: "It breaks code reuse - create a BorgLeader or whatever extension of Borg, and you must re-overload that binding or cop unallocated function results" - no such issues below; reuse when one wants to or overload as needed.

MODULE M
  IMPLICIT NONE

  TYPE, ABSTRACT :: Thing
     CHARACTER(:), ALLOCATABLE, PRIVATE :: name
  CONTAINS
    PROCEDURE, PASS(the_thing), PUBLIC :: MyName
  END TYPE Thing

  TYPE, EXTENDS(Thing) :: Person
     !.. Include any additional fields for this extension class
  END TYPE Person

  TYPE, EXTENDS(Thing) :: Borg
  CONTAINS
    PROCEDURE :: MyName => borg_MyName
  END TYPE Borg
  
  TYPE, EXTENDS(Borg) :: SuperBorg
  END TYPE SuperBorg
  
  TYPE, EXTENDS(SuperBorg) :: EmperorBorg
  CONTAINS
    PROCEDURE :: MyName => EmperorBorgName
  END TYPE EmperorBorg
  
CONTAINS

  FUNCTION MyName(the_thing) RESULT(name)
  
    CLASS(Thing), INTENT(IN) :: the_thing
    !.. Function result
    CHARACTER(LEN=:), ALLOCATABLE :: name
    
    name = the_thing%name
    
  END FUNCTION MyName
  
  FUNCTION borg_MyName(the_thing) RESULT(name)
  
    CLASS(Borg), INTENT(IN) :: the_thing
    !.. Function result
    CHARACTER(LEN=:), ALLOCATABLE :: name
    
    SELECT TYPE(the_thing)
       CLASS IS (Borg)
          name = 'WE ARE THE BORG.  RESISTANCE IS FUTILE.'
    END SELECT
    
  END FUNCTION borg_MyName
  
  FUNCTION EmperorBorgName(the_thing) RESULT(name)
  
    CLASS(EmperorBorg), INTENT(IN) :: the_thing
    !.. Function result
    CHARACTER(LEN=:), ALLOCATABLE :: name
    
    SELECT TYPE(the_thing)
       TYPE IS (EmperorBorg)
          name = 'I reign supreme.'
    END SELECT
    
  END FUNCTION EmperorBorgName
  
END MODULE M

PROGRAM p

  USE m, ONLY : Person, Borg, SuperBorg, EmperorBorg
  IMPLICIT NONE

  !..
  TYPE(Person)      :: Fortranner  
  TYPE(Borg)        :: Blitzer    
  TYPE(SuperBorg)   :: SuperBlitzer    
  TYPE(EmperorBorg) :: Fuhrer    

  Fortranner = Person(" Humble Me!")
  PRINT *, "Person is ", Fortranner%MyName()
  
  PRINT*, " Blitzer says ", Blitzer%MyName()
  
  PRINT*, " SuperBlitzer says ", SuperBlitzer%MyName()
  
  PRINT*, " Fuhrer says ", Fuhrer%MyName()
  
  !..
  STOP 
 
END PROGRAM p
 Person is  Humble Me!
  Blitzer says WE ARE THE BORG.  RESISTANCE IS FUTILE.
  SuperBlitzer says WE ARE THE BORG.  RESISTANCE IS FUTILE.
  Fuhrer says I reign supreme.
Press any key to continue . . .

"suggests something is astray with the inheritance tree " - aha!  There you go!  That's the real issue with code in Quote #7; Quote #14 is just showing a quick way out; as I said, not knowing the underlying details, it is difficult to suggest changes.  Normally, one would do some good old-fashioned OOD analysis to better design the class structure first; compiler optimization would come into play afterward - the order shouldn't be the other way around.     

0 Kudos
IanH
Honored Contributor III
3,254 Views
>FF08Diff.exe before.f90 after.f90
before.f90(8,8)
after.f90(8,8)
  There are different token values in a /type-guard-stmt/.
The sets are semantically different.

(When you added the extension you changed TYPE to CLASS in the type guard statement in borg_MyName.  Without that change, an extension that did not override the MyName binding would have led to the relevant function returning an unallocated result.)

With the change to CLASS, the type guard statement is equivalent to using CLASS DEFAULT (the declared type of the selector is also the type designated in the CLASS IS type guard statement).  With no other options in the SELECT TYPE that becomes three statements of pointless code (you can delete the SELECT TYPE, the CLASS IS and the END SELECT statements in the new borg_MyName and it makes no difference to the semantics of the program).  A smart compiler might recognise the syntactic pointlessness and complain, but I think we are some distance from that in terms of current language support.

I appreciate that it is difficult to describe appropriate conceptual solutions to these sorts of problems without better specification of the problem, because details may matter - so bear with me if the examples mislead.  I have also derailed the discussion by using an example that "doesn't use" a passed argument (example solution without SELECT TYPE attached), but the problem still exists for dummy arguments in procedures for bindings that are not the passed argument.  Even in the case of unused passed arguments, writing intermediate types that achieve no increase in program function or practical source utility and really only serve to suppress compiler chattiness strikes me as a bit like putting the cart before the horse.

For an actual use case, see the linked zip, which is for the program in the opening snippet above with all my IF (xxx) CONTINUE hacks deleted.  The basic data structure in the program is a tree of "parts" (StNode from module StNodes), with each part also containing one or more "statements".  A tree traversal interface is provided (StNode%Query) where each node forwards information about itself and its children to a visitor object (StNodeQueryVisitor) executing some sort of operation.  The traversal interface doesn't know specifically what information (i.e. arguments) the visitor requires -  it is general in nature.  For some operations (extensions of StNodeQueryVisitor) not all the information is required - hence not all the arguments are used.  If compiled with /warn:all the last few messages you see are due to this.  There are other arguments for different interfaces that have the same issue - the nature of the interface is general, beyond what specific extensions may need.

(Most of the other "not used... [ST]" messages are due to a passed object that isn't required - as per my Borg example above.  That interface changed recently from being NOPASS to PASS because of an oversight on my part.  I could [have] implement[ed] an intermediate type to handle this case, but that has elements of cart before horse, as mentioned above, in terms of making a further change now.)

https://www.dropbox.com/s/cyrtd47gm5pfk3k/FF08Diff.zip?dl=0

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,253 Views

IanH,

From " A tree traversal interface is provided (StNode%Query) where each node forwards information about itself and its children to a visitor object (StNodeQueryVisitor) executing some sort of operation.  The traversal interface doesn't know specifically what information (i.e. arguments) the visitor requires -  it is general in nature."

This makes me form a conjecture that a similar situation will occur with list of filters. IOW each filter receives a common list of state variables/references, some of which may be unused and immaterial to the caller (other than that they are required for the interface).

Jim Dempsey

0 Kudos
Reply