- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've run into a possible bug with derived type IO when I have a derived type with a private component array of derived types. I've included a example code snippet below that should reproduce the problem (I'm using ifort version 14.0.2.114). To summarize the problem, when I try to write my derived type using a formatted write statement it output the public component of the derived type, as expected, and then it outputs the first n-1 values of the component derived type, which is both private and not called in the main formatted write statement.
In the sample code below the write statement should output:
1.0000
but instead outputs
1.0000
2.0000
2.0000
2.0000
2.0000
Sample code:
module DTIO
implicit none
! derived types:
type T1
private
real :: x
contains
procedure, private :: T1_write_formatted
generic :: write(formatted) => T1_write_formatted
end type T1
type T2
private
real :: x
type(T1) :: y(5)
contains
procedure, private :: T2_write_formatted
generic :: write(formatted) => T2_write_formatted
end type T2
! interfaces:
interface T1
module procedure :: T1_constructor
end interface T1
interface T2
module procedure :: T2_constructor
end interface T2
contains
pure function T1_constructor( x ) result( val )
real, intent(in) :: x
type(T1) :: val
val%x = x
end function T1_constructor
pure function T2_constructor( x ) result( val )
real, intent(in) :: x
type(T2) :: val
val%x = x
val%y = T1(2.0*x)
end function T2_constructor
subroutine T1_write_formatted( self, unit, iotype, v_list, iostat, iomsg )
class(T1), intent(in) :: self
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
! local variables:
character(:), allocatable :: fmt
! determine format
if (len_trim(iotype) > 0) then
if (iotype(1:2) == 'DT') then
if (len_trim(iotype) > 2) then
fmt = '('//iotype(3:)//')'
write(unit, fmt=fmt, iostat=iostat, iomsg=iomsg) self%x
deallocate(fmt)
else
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
end if
else if (iotype == 'LISTDIRECTED') then
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
else if (iotype == 'NAMELIST') then
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
end if
end if
end subroutine T1_write_formatted
subroutine T2_write_formatted( self, unit, iotype, v_list, iostat, iomsg )
class(T2), intent(in) :: self
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
! local variables:
character(:), allocatable :: fmt
! determine format
if (len_trim(iotype) > 0) then
if (iotype(1:2) == 'DT') then
if (len_trim(iotype) > 2) then
fmt = '('//iotype(3:)//')'
write(unit, fmt=fmt, iostat=iostat, iomsg=iomsg) self%x
deallocate(fmt)
else
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
end if
else if (iotype == 'LISTDIRECTED') then
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
else if (iotype == 'NAMELIST') then
write(unit, *, iostat=iostat, iomsg=iomsg) self%x
end if
end if
end subroutine T2_write_formatted
end module DTIO
program main
use DTIO
implicit none
! local parameters:
type(T2) :: var
var = T2(1.0)
write(*,'(A)') 'formatting: unspecified'
write(*,*) var
write(*,'(A)') ''
write(*,'(A)') 'formatting: specified'
write(*,'(DT"F10.4")') var
end program main
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This source has several syntactic errors. Please clear these up and post the corrected version.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fixed source code
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think the behavior is correct. Since defined I/O procedures process the derived type and those procedures are in the module defining the type, all components are accessible.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Isn't the problem here is that these private components (even though accessible) should actually not be printed, according to the I/O procedures in Thomas' example?
And, strangely, they are not accessible for the DTIO in ifort 15.0.1, which refuses to compile the reduced version of Thomas' example code (error #5521: A derived-type object in an input/output list cannot have private components unless a suitable user-defined input/output procedure is available.)
module DTIO
implicit none
type T1
logical, private :: private_component
end type
type T2
type(T1) :: has_private_component
end type
interface write(formatted)
module procedure T2_write_formatted
end interface
contains
subroutine T2_write_formatted( self, unit, iotype, v_list, iostat, iomsg )
class(T2), intent(in) :: self
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, dimension(:), intent(in) :: v_list
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
end subroutine
end module DTIO
program main
use DTIO
implicit none
type(T2) :: var
write (*, '(DT)') var
end program main
Generally, I have the feeling that DTIO (esp. formatted) is not fully supported yet on ifort 15.0.1. Is this true? Is there significant improvement with ifort 15.0.2?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ferdinand T. wrote:
Isn't the problem here is that these private components (even though accessible) should actually not be printed, according to the I/O procedures in Thomas' example?
And, strangely, they are not accessible for the DTIO in ifort 15.0.1, which refuses to compile the reduced version of Thomas' example code (error #5521: A derived-type object in an input/output list cannot have private components unless a suitable user-defined input/output procedure is available.)
What is especially strange to me is that it only prints four of the five T1 components. If the behavior was intended, i.e., printing the component derived types even though they are private, then why not print all five elements of the array?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The accessibility is irrelevant in the case where the list item is processed by a DTIO procedure. I am not aware of any outstanding issues with DTIO in 15.0.
However, that there are only four of the five array elements is not right and I will look into that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel wrote:
[...] The accessibility is irrelevant in the case where the list item is processed by a DTIO procedure. [...]
But why does the compiler trigger that error? (Code in my prior post - there is a DTIO procedure defined). I think that is incorrect.
EDIT: Is it intentional that the user-id is displayed per
user-id wrote:
...instead of the user-name when quoting a post?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok. The error message is incorrect. I have escalated that as issue DPD200367665. Still working on the other one.
And yeah, the quoting is not right - I will let the forum folks know.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel wrote:
Ok. The error message is incorrect. I have escalated that as issue DPD200367665. Still working on the other one.
And yeah, the quoting is not right - I will let the forum folks know.
Thanks for looking into this Steve. I looked through one of the working drafts for the Fortran 2008 standard (WD 1539-1) which specifies on page 237:
If a list item of derived type in a formatted input/output statement is not processed by a defined input/output procedure, that list item is treated as if all of the components of the list item were specified in the list in component order; those components shall be accessible in the scoping unit containing the input/output statement and shall not be pointers or allocatable.
Which seems to imply that this behavior of printing all components of a derived type when a user specified output procedure is present regardless of what that output procedure does is incorrect (unfortunately I couldn't find anything more explicit on the topic). Also it's worth noting that if I change my type(T1) component array to an array of any intrinsic type (integer, real, ...) the output works as I would expect, i.e., it only outputs component x and not component y.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The text relates to what happens if the derived type is NOT processed by a user-defined I/O procedure, which is not the case here. If the type IS processed by a user procedure, then the normal rules of accessibility in that procedure apply.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel wrote:
The text relates to what happens if the derived type is NOT processed by a user-defined I/O procedure, which is not the case here. If the type IS processed by a user procedure, then the normal rules of accessibility in that procedure apply.
Right. It specifies the behavior we're seeing (minus printing only n-1 array components) explicitly for the case this isn't. Which would imply that for this case a different way of handling the output should be applied, unfortunately I couldn't find a spot where it explicitly says how this case should be handled in my brief search.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, I was mistaken in my original claim that the first program executes correctly, and you are absolutely right that the output should be the same in both cases. I think I know what is happening - in the explicit format case, the compiler has to anticipate the possibility that var might not be handled by a DTIO routine, so it generates alternate code to list out all the components. This isn't working properly - it should give a run-time error in the case the DTIO wasn't used since there are private components, but it is somehow falling into the "list all components" case and not doing that right either. Escalated as issue DPD200367669.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The bug that produced the error message for the program in post #5 (DPD200367665) has been fixed - I expect the fix to appear in 16.0.1. The run-time issue (DPD200367669) is still being worked on, but the basic problem is understood.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page