j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
174 stars 14 forks source link

Intrinsics to return information on procedure name, source file name and line number #180

Open sblionel opened 3 years ago

sblionel commented 3 years ago

Many times in my career I saw users asking for a way to obtain the current procedure name, source file name and/or source file line number, for use in logging and error messages. Some compilers offer preprocessor macros for this, but it is not standardized and macros that result in a string are hard to use in Fortran.

Intrinsic module ISO_FORTRAN_ENV already has two intrinsic functions COMPILER_OPTIONS and COMPILER_VERSION that return strings known to the compiler. I propose adding three more - the names I show here are for discussion purposes and different names might be desirable.

PROCEDURE_NAME() returns a string that is the function-name or subroutine-name of the enclosing function or subroutine, upcased. (Case as it appears in the source file would be another choice.) A constraint would be that this can appear only in a subroutine or function. (If the procedure is in a module, does the module name also appear somehow? I think not.)

SOURCE_FILE_NAME() returns an implementation-dependent string that represents the name of the source file in which the call appears. This can get tricky - full path? What about sources that have no name or include files?

SOURCE_LINE_NUMBER() returns an integer representing the line number of the source file in which the call appears. Is it OK if it's just relative to the actual file (could be an include file)? Interaction with preprocessors (they have pragmas that can set the original line number.)

All of these would be valid in constant expressions.

cmacmackin commented 3 years ago

Taking this a step further, we could also consider a functions which would return this sort of information for the entire callstack. Obviously that would not be safe to use in a constant expression. Many of the same questions apply, of course. Presumably the easiest thing to do would be return mangled procedure names generated during compilation, although I wouldn't imagine it would be too difficult to have an option for the compiler unmangle them. Personally, I'd like it if there were a way to see module names as part of the procedure name (e.g., MODULE_NAME[::SUBMODULE_NAME]::PROCEDURE_NAME).

FortranFan commented 3 years ago

I think this will be very useful for Fortran practitioners.

As I inquired in the comp.lang.fortran thread where too this was mentioned, what technical concerns and possible objections can compiler writers and commercial vendors have with this?

In other words, in what way can this not be a no-brainer i.e., a just do it item?

jvdp1 commented 3 years ago

These would be very useful. I often use the macros FILE and LINE (with preprocessor) to get these info.

certik commented 3 years ago

I think these would be useful, thank you for proposing this @sblionel.

One objection from the committee that I can see coming is that the standard tries to describe Fortran in a way that is independent of the filesystem and filenames. I personally do not think that should be a problem, but it is one objection that might be raised against the SOURCE_FILE_NAME function.

sblionel commented 3 years ago

I would not be in favor of extending this to a run-time stack trace. Generally, procedure names are not kept around after compilation, and some implementations may not have a way of retrieving names of callers.

I can't think of any technical objection as this information is always available in the compilation phase where these would be processed. It would not require implementors to keep anything additional.

@certik , this could be handled similarly to INCLUDE - there would be something like "a processor-dependent string that represents the origin of the source text". The wording for INCLUDE has "An example of a possible valid interpretation is that char-literal-constant is the name of a file that contains the source text to be included." You're right that this needs to be carefully worded as to not imply a particular implementation. Indeed, some sources come from stdin or pipes. Maybe SOURCE_NAME would be a better choice. Certainly, a topic for discussion.

ashe2 commented 3 years ago

I think this will be very useful for Fortran practitioners.

As I inquired in the comp.lang.fortran thread where too this was mentioned, what technical concerns and possible objections can compiler writers and commercial vendors have with this?

In other words, in what way can this not be a no-brainer i.e., a just do it item?

The best way to show this is a no-brainer would be for someone to implement it in one of the open source compilers. Assuming that shows it is well-defined, straight-forward to implement, and useful, that would encourage the committee to standardize it and other implementors to implement it.

certik commented 3 years ago

@valtterib I agree and it is going to happen soon. I think @klausler and others might be very close to start implementing such prototypes in Flang, and we need few more months with LFortran to be able to do that also.

klausler commented 3 years ago

We already have __FILE__ and __LINE__ in the preprocessors available in all serious compilers.

sblionel commented 3 years ago

As @klausler says, compilers already know how to do this from preprocessor macros. I don't think implementors need to be convinced that it's doable. Truly, the hard part is getting the words right in the standard. Some work is needed in a compiler to recognize an intrinsic module function as valid in a constant expression, but there is already precedent for that and compilers have their own ways of handling it.

klausler commented 3 years ago

But people can use __FILE__ and __LINE__ today. What's the ROI on defining new intrinsic functions in the 202Y standard, implementing and testing them in multiple compilers, and shaking out the bugs and incompatibilities, just to get the same facilities with a different redundant spelling to users sometime in the 2030s? Everyone would be better off if you just blessed the existing common preprocessor features already in use today.

sblionel commented 3 years ago

They're not standard and some compilers don't support preprocessor macros by default.

This proposal was triggered by a request on c.l.f for a way to retrieve the current procedure name - I threw in source file and line number as obvious parallels that were requests I had seen before. Also note my comment about how hard it is to use string macros as character literals.

klausler commented 3 years ago

What's the problem with using __FILE__ as a character literal?

septcolor commented 3 years ago

I think another point is that the value of __FILE__ and __LINE__ found in some output file may not be "in sync" with the current source codes. Although the same can be true for procedure names (i.e., new source codes may have different routine names), it is still much more informative to have procedure names rather than line numbers (which can even vary depending on newly added comments etc).

tskeith commented 3 years ago

I think the value of something like PROCEDURE_NAME() is limited if you can't uniquely identify the subprogram with it. That means you need some kind of fully-qualified name (at least optionally), or a way to get the names of the enclosing module, submodule, and host subprogram (if any).

klausler commented 3 years ago

I think another point is that the value of __FILE__ and __LINE__ found in some output file may not be "in sync" with the current source codes. Although the same can be true for procedure names (i.e., new source codes may have different routine names), it is still much more informative to have procedure names rather than line numbers (which can even vary depending on newly added comments etc).

__FILE__ and __LINE__ are, or should be, a pair of features that are not packaged with truly new capabilities that can extract the names of the containing program unit, its hosts, and its ancestor module. Those names can't be known at preprocessing time, and will eventually have to reflect the values of module parameters, once we have them in the language.

septcolor commented 3 years ago

FWIW, this is my (pretty old) post in comp.lang.fortran when I got stuck with printing __LINE__ in (custom) stop and assert macros. https://groups.google.com/d/msg/comp.lang.fortran/KFB_mlmrNNg/jtggiPY7BgAJ My last post there is like: "I would like to have more robust preprocessing features".

RE additional information about module, submodule, and host subprogram (i.e., enclosing scopes), it seems that __PRETTY_FUNCTION__ and __MODULE__ etc do a nice job in other languages. (FWIW, I've posted a bit related example here) https://groups.google.com/forum/#!msg/comp.lang.fortran/HXdFCDagavs/7PDHF8T7AwAJ

klausler commented 3 years ago

FWIW, this is my (pretty old) post in comp.lang.fortran when I got stuck with printing __LINE__ in (custom) stop and assert macros. https://groups.google.com/d/msg/comp.lang.fortran/KFB_mlmrNNg/jtggiPY7BgAJ My last post there is like: "I would like to have more robust preprocessing features".

RE additional information about module, submodule, and host subprogram (i.e., enclosing scopes), it seems that __PRETTY_FUNCTION__ and __MODULE__ etc do a nice job in other languages. (FWIW, I've posted a bit related example here) https://groups.google.com/forum/#!msg/comp.lang.fortran/HXdFCDagavs/7PDHF8T7AwAJ

Looking at your comp.lang.fortran thread, I'm disappointed that stringizing doesn't work with gfortran:

#define TO_STR(x) #x
#define ASSERT(x) if (.not.(x)) error stop "ASSERT("//#x//") failed at "//__FILE__//" line "//TO_STR(__LINE__)
MichaelSiehl commented 3 years ago

https://github.com/j3-fortran/fortran_proposals/issues/180#issuecomment-691139368

I would not be in favor of extending this to a run-time stack trace. Generally, procedure names are not kept around after compilation, and some implementations may not have a way of retrieving names of callers.

subroutine essy00_UnpackEnumValue (Object, ...)
..
!
call glob_subSetProcedures ("essy00_UnpackEnumValue") ! this call does set the stack trace to this current subroutine
!
..  
!
call glob_subResetProcedures  ! this call does reset the stack trace to the calling subroutine or function
end subroutine essy00_UnpackEnumValue

In my own codes I am using this technique in each and every subroutine/function to feed an user-defined stack trace. (I am using a simple naming convention, using a unique source file prefix, to make the procedure names unique as well). An user-defined error handler then uses the information from the stack trace to get current, calling, and returning procedure names for its error messages.

With the coarray runtime, an user-defined stack trace and error handler will provide tracing information and error messages through coarrays for remote access. All this is important because we should not expect to be able to debug sophisticated coarray codes as we could with sequential codes.

So yes, this proposal here could definitely help to avoid mistakes with hand coding the procedure names as arguments with my calls to the user-defined stack trace's glob_subSetProcedure subroutine.

cheers

certik commented 3 years ago

I agree that stacktraces are important, but I think it should be the job of the compiler to give you those, you shouldn't need to store such subroutine information yourself.

On Wed, Sep 16, 2020, at 3:02 AM, Michael Siehl wrote:

180 (comment)

https://github.com/j3-fortran/fortran_proposals/issues/180#issuecomment-691139368

I would not be in favor of extending this to a run-time stack trace. Generally, procedure names are not kept around after compilation, and some implementations may not have a way of retrieving names of callers.

subroutine essy00_UnpackEnumValue (Object, ...) .. ! call glob_subSetProcedures ("essy00_UnpackEnumValue") ! this call does set the stack trace to this current subroutine ! ..
! call OOOGglob_subResetProcedures ! this call does reset the stack trace to the calling subroutine or function end subroutine OOOPessy00_UnpackEnumValue In my own codes I am using this technique in each and every subroutine/function to feed an user-defined stack trace. (I am using a simple naming convention, using a unique source file prefix, to make the procedure names unique as well). An user-defined error handler then uses the information from the stack trace to get current, calling, and returning procedure names for its error messages.

With the coarray runtime, an user-defined stack trace and error handler will provide tracing information and error messages through coarrays for remote access. All this is important because we should not expect to be able to debug sophisticated coarray codes as we could with sequential codes.

So yes, this proposal here could definitely help to avoid mistakes with hand coding the procedure names as arguments with my calls to the user-defined stack trace's glob_subSetProcedure subroutine.

cheers

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/180#issuecomment-693274705, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFAWDHY7WJZBLYUJGBGG3SGB5LTANCNFSM4RGFZEQA.

tskeith commented 3 years ago

I agree that stacktraces are important, but I think it should be the job of the compiler to give you those, you shouldn't need to store such subroutine information yourself.

Stack traces can be useful, but I don't think that feature should be part of this proposal. This one is simple and straight-forward and should stay that way.

A stack trace proposal would require analysis of the cost to programs that don't make use of the feature and a convincing argument that it adds enough value compared to, for example, using a debugger to get a stack trace.

MichaelSiehl commented 3 years ago

I agree that stacktraces are important, but I think it should be the job of the compiler to give you those, you shouldn't need to store such subroutine information yourself.

Stack traces can be useful, but I don't think that feature should be part of this proposal. This one is simple and straight-forward and should stay that way.

A stack trace proposal would require analysis of the cost to programs that don't make use of the feature and a convincing argument that it adds enough value compared to, for example, using a debugger to get a stack trace.

I agree. With Fortran, the topics of stack trace and error handling do extend to a distributed case and thus, can become much bigger than we could imagine yet. For example, error handling may become a mixture of local and distributed error handlers. To me, it is still to early to further think about such yet, since I'm struggling with ifort getting my working OpenCoarrays codes to compile.