- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I am looking for some advice with the following assignment to the selector variable in a SELECT TYPE block.
The Intel compiler 13.1.3 compiles successfully, but version 14.0.1 produces a run-time error (see below):
[fortran]
program p
implicit none
! abstract
type, abstract :: abstract_type
integer :: nonempty
end type
! contains abstract allocatable
type :: container_type
integer :: nonempty
! fix: uncomment next line or use pointer instead
class(abstract_type), allocatable :: abstract_field
end type
type(container_type) :: rhs
class(container_type), allocatable :: polymorphic_lhs
! assign into polymorphic
select type (polymorphic_lhs)
type is (container_type)
! runtime error (ifort 14.0.1)
! problem with 'abstract_field' allocatable component
! (no matter it's allocation status in lhs and rhs)
polymorphic_lhs = rhs
end select
! output (ifort 13.1.3): F
print *, allocated(polymorphic_lhs%abstract_field)
end program
[/fortran]
Compilation and output:
$ ifort -g -O0 test.f90
$ ./a.out
forrtl: severe (122): invalid attempt to assign into a pointer that is not associated
My two questions here are:
- Do I violate some restrictions (read-only variable in the SELECT CASE association or something) here?
- How else can I achieve the desired assignment in the case where 'polymorphic_lhs' is a PASS'ed derived type dummy argument?
Thanks for any comments!
With regards, Ferdinand
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ferdinand,
Have you elided some code here, perhaps? Looking at this, I spot the immediate problem that a) polymorphic_lhs is unallocated upon entry to the select type construct, and therefore has no type and b) If polymorphic_lhs is unallocated, unless you specify -assume realloc_lhs, or perhaps the standard semantics flag with -stand f0[38] ifort does not implement the reallocation on assignment semantics of f03 and f08; you need to explicitly enable them. Finally, I recall there being some issues around polymorphic intrinsic assignment or reallocation on polymorphic assignment. I believe the F08 standard does allow one or both of these, but not the F03 standard, and I am unsure of the current implementation status of this/these F08 features. So I think the answer to your first question is "yes, you have written non standard complying code as its listed above."
As an aside, I am curious what would be the result if you changed 'type is' to 'class is' in your type guard statement. At runtime, if polymorphic_lhs is unallocated there is no way to determine its dynamic type, but, in theory the compiler could know that it was declared as class(container_type). However, I suspect that it is in violation of the standard to pass an unallocated object to the type guard statement.
As to your second question, I think we need to see more of your code. You reference the fact that polymorphic_lhs is a PASSed dummy argument, which implies that there are type bound procedures (TBPs). Are you using the default/implicit passing behavior wherein the object to which the TBP is bound is implicitly passes as the first actual argument corresponding to the first dummy argument? Something like polymorphic_lhs%DoSomething(stuff)? If this is the case, then polymorphic_lhs must be allocated before you can call TBPs.
Any way I hope this is helpful and that I haven't made any errors or led you astray. If you give a more complete example we can likely help more.
Good luck
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Something is definitely not right here - the SELECT TYPE should not be triggering a segfault. I see the same behavior in 13.1.3, however.
The program is correct as written. Since dynamic_lhs is not allocated, its "dynamic type" is the same as its "declared type", which is "container type". The TYPE IS guard statement would then be executed. However, it's not even getting to the assignment. I'll send this off to the developers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
Thanks for correcting me regarding the type guard statement, forums like this are quite helpful for learning the new language features. I don't doubt your assertion about something being wrong, but can you comment on whether or not -assume realloc_lhs is needed in the OPs original example and if ifort 14.x supports polymorphic assignment and reallocation on assignment?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ifort 14.0 does not support assignment to a polymorphic variable, which is a F2008 feature. But in the scope of the TYPE IS block, polymorphic_lhs is not polymorphic!
"Within the block following a TYPE IS type guard statement, the associating entity (16.5.5) is not polymorphic (4.3.1.3), has the type named in the type guard statement, and has the type parameter values of the selector." (F2008, page 185, paragraph 5)
As best as I can tell, -assume realloc_lhs would not be required here. My tests show that the assignment (with a type, not class) works without it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve and Zaak, thank you for your analysis.
@Zaak:
Thanks for pointing out the missing allocation. Indeed I do not use 'realloc_lhs' with my original code, I simply forgot to copy the allocation statement into the example code (or to switch to standard semantics in the compile line). However, the described problem is not related to the allocation status. Even with allocated 'polymorphic_lhs', the runtime-error (invalid attempt to assign into a pointer that is not associated) appears.
To satisfy your curiosoty, I replaced the TYPE IS guard with a CLASS IS which triggers compiler error #8304: "In an intrinsic assignment statement, variable shall not be polymorphic". Makes sense but doesn't really answer your question about how and when the correct block of the SELECT TYPE is choosen in that situation, I guess. (However, I remember that with SELECT TYPE the F2003 standard outlines a short step-by-step algorithm where the general procedure is explained)
The second question is meant exactly as you understood it. Here is an example:
[fortran]
module m
implicit none
! abstract
type, abstract :: abstract_type
integer :: nonempty
end type
type, extends(abstract_type) :: extended_type
end type
! contains abstract allocatable
type :: container_type
integer :: nonempty
! fix: uncomment next line or use pointer instead
class(abstract_type), allocatable :: abstract_field
contains
procedure :: do_something
end type
contains
subroutine do_something(this)
class(container_type), intent(inout) :: this
type(container_type) :: some_local_result
! Type-bound passed dummy is always polymorphic
! so we have to type cast it before assignment
! (even if the code doesn't use polymorphism at all)
select type (this)
type is (container_type)
! Intrinsic assignment. In actual code,
! the rhs is a function call this = do_stuff(...)
this = some_local_result
end select
end subroutine
end module
program p
use m
implicit none
type(container_type) :: my_container
call my_container%do_something() ! runtime error
end program
[/fortran]
In the meantime I found a workaround, which consists in replacing the intrinsic assignment by a call to a (non-type bound) subprogram (copy-constructor) which does the assignment locally. This seems to do the job, but I am not entirely sure about how reliable it is.
Best regards
Ferdinand
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Intel) wrote:
ifort 14.0 does not support assignment to a polymorphic variable, which is a F2008 feature. But in the scope of the TYPE IS block, polymorphic_lhs is not polymorphic!
"Within the block following a TYPE IS type guard statement, the associating entity (16.5.5) is not polymorphic (4.3.1.3), has the type named in the type guard statement, and has the type parameter values of the selector." (F2008, page 185, paragraph 5)
As best as I can tell, -assume realloc_lhs would not be required here. My tests show that the assignment (with a type, not class) works without it.
Ah yes, I knew that about the type is type guard statement, after all that's the whole point of the construct! I guess I'm a bit of a derp today, sorry.
As to the point regarding -assume realloc_lhs, I can't see where polymorphic_lhs was previously allocated in the OP, my reading of the code as listed in the OP is that polymorphic_lhs is still an unallocated scalar inside the type is gaurd statement where it then appears in the lhs of an assignment. I did some testing with gfortran 4.8.2 and ifort 13.x.x and for a simple program listed below, even when turning on -assume realloc_lhs I get segfaults. If I then explicitly try to allocate polymorphic_lhs inside the type is block ifort says:
[plain]
error #8306: Associate name defined in ASSOCIATE or SELECT TYPE statements doesn't have ALLOCATABLE or POINTER attribute [LHS]
allocate(myt :: lhs)
---------------------^
[/plain]
even though lhs was declared as class(myt), allocatable. Gfortran gives a similar complaint:
[plain]
Error: Allocate-object at (1) is neither a data pointer nor an allocatable variable
[/plain]
This leads me to think that the selector of a select type construct cannot be (re)allocated within the construct, even if it is declared with the allocatable attribute.
Here is my test program:
[fortran]
program foo
implicit none
type :: myt
integer :: i
end type
type(myt) :: rhs
class(myt) ,allocatable :: lhs
rhs = myt(5)
print*, rhs%i
! allocate(myt :: lhs) ! Correct place to allocate polymorphic lhs
select type(lhs)
type is (myt)
allocate(myt :: lhs) ! Doesn't segfault, but gives error
lhs = rhs
end select
print*, rhs%i
!select type(lhs)
!type is (myt)
print*, lhs%i
!end select
end program
[/fortran]
compiled with ifort 13.x as: ifort -trace -assume realloc_lhs -warn foo.f90
@ Ferdinand
Can you make any guarantees about the allocation status of the PASSed dummy argument upon entry to the TBP subroutine? It is my understanding that you can only call a TBP if the object it is bound to is allocated, and, further, it seems that one cannot (re)allocate the selector of a select type construct from within it. Finally, the dummy argument does not have the allocatable attribute, so it MUST be allocated upon entry to the subroutine. I suspect that you are trying to do something with an unallocated polymorphic variable which at least the compiler doesn't like, if not the standard.
Edit: your revised code does not appear to suffer specifically from the issue I mentioned above, which is now crossed out, however your original code did. In the revised example, what is the declared and dynamic type of the rhs function result do_stuff(). If it is polymorphic perhaps that is the source of the issue, rather than the intrinsic assignment? FWIW your revised example program does not raise any compile time or runtime errors for me on ifort 13.0.2 on mac, so I think you've either removed the source of the problem or made a mistake in generating a smaller reproducer code.
Edit two: the strike through does not render on google chrome for OS X, I am referring to paragraph above the previous one. Also, as an aside, it is hard to enter code on chrome for os x on this form as extraneous line breaks are added.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ifort will do the reallocation on assignment, with or without -assume realloc_lhs. That is what the current standard says. The case where we won't do this by default is for allocatable arrays as they existed prior to F2003.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
First, @Zaak: thanks for your detailed investigations on that problem. In short:
- do_stuff is not polymorphic, e.g. of type(container_type)
- error is present in the program as stated in my second post, compiled with ifort 14.0.1 on unix (ubuntu 12.10)
Second, while trying to figure out some workarounds, I managed to reproduce some segfaults on the following lines:
[fortran]
! DERIVED TYPE (may or maynot be emtpy)
type t; end type
class(t), allocatable :: a
! EMPTY SELECT TYPE
select type (a)
type is (t)
end select
! OUTPUT: SIGSEGV, segmentation fault occurred
end
[/fortran]
Compiled with similar options (or no options at all) on the same machine.
Furthermore, I find Zaak's observations and Steves comment regarding the implicit reallocation in a type guard statement very interesting. What I understand so far:
The associate-name (e.g. 'polymorphic_lhs' within the select type statement) doesn't have the ALLOCATABLE
attribute, but the associated data object (e.g. the local variable 'polymorphic_lhs' outside the select type) has it. So you cannot use ALLOCATE. However, as Steve pointed out, you can change the allocation status through reallocation on assignment. As long you don't want to change the dynamic type, you can simply emulate ALLOCATE(x) via x = DERIVED_TYPE_CTOR(), and DEALLOCATE(x) or SOURCEd allocation via x = y, where y is either the source or an unallocated variable of similar dynamic type.
(Is that right? But why does the associate-name not have the ALLOCATABLE-attribute right from the beginning?)
Best regards
Ferdinand
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hmm - I admit I didn't consider the aspect that inside the TYPE IS the variable isn't allocatable. My test regarding the need for the switch or lack thereof didn't involve a TYPE IS. You're right - the selector is not allocatable so it needs to be allocated before the SELECT TYPE.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think it is implicit in the various posts above, but 16.5.1.6p2 in F2008 is worth a read. "If the selector is allocatable it shall be allocated; the associate name is associated with the data object and does not have the allocatable attribute."
The original post and some of the subsequent snippets (#7, #9) break this.
This has caught me out before in ASSOCIATE constructs that refer to CHARACTER(:), ALLOCATABLE components.
[fortran]TYPE some_type
CHARACTER(:), ALLOCATABLE :: name
END TYPE some_type
TYPE(some_type) :: array(10)
... ! name component not allocated here.
ASSOCIATE(name => array(i)%name)
name = 'This is bad Fortran.'
END ASSOCIATE[/fortran]
(I have vague recollections that when I got this wrong the name component was previously allocated to some length, and for the life of me I couldn't understand why the compiler was doing length padding or truncation or whatever.)
I've lost track of the specific details over the years and versions, but my experience is that assignment of derived types containing polymorphic components is broken. I wonder whether some examples (#6) trigger this. I am reasonably sure that there are outstanding bug reports around this. I think my current workaround is to "inline" the assignment to do it component by component, and use ALLOCATE(lhs%poly_comp, SOURCE=rhs%poly_comp) for any polymorphic components. Consumption of a mix of cabernet sauvignon and merlot while coding the workaround also seems to help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
IanH wrote:
I think it is implicit in the various posts above, but 16.5.1.6p2 in F2008 is worth a read. "If the selector is allocatable it shall be allocated; the associate name is associated with the data object and does not have the allocatable attribute."
[snip]
I've lost track of the specific details over the years and versions, but my experience is that assignment of derived types containing polymorphic components is broken. I wonder whether some examples (#6) trigger this. I am reasonably sure that there are outstanding bug reports around this. I think my current workaround is to "inline" the assignment to do it component by component, and use ALLOCATE(lhs%poly_comp, SOURCE=rhs%poly_comp) for any polymorphic components. Consumption of a mix of cabernet sauvignon and merlot while coding the workaround also seems to help.
Ian,
Thanks for citing the standard to back up my initial suspicion. (Albeit, my reasoning about WHY passing an unallocated variable as a selector to a select type construct was flawed, as Steve pointed out.)
Looking at this, I spot the immediate problem that a) polymorphic_lhs is unallocated upon entry to the select type construct, and therefore has no type
Ian, when you say that you "inline" the assignment, does that mean that you have public components in your objects and that you assign the subobjects one by one, or do you write defined assignments to achieve this?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the chapter 16 catch, Ian. I had looked up "dynamic type" but had not thought to also check construct association!
Therefore, the program is invalid. I would expect -check pointer to give a meaningful error here, but it doesn't. I've asked that it do so.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
While this discussion focusses on the allocation status of 'polymorphic_lhs', from which I actually learned a highly valuable lesson about the implications of the new fortran standard, I just want to clarify that the reported runtime-error is still an issue. As I admitted earlier (#6), I merely forgot to copy the [fortran]allocate(polymorphic_lhs)[/fortran] prior to SELECT TYPE (line 19) into my example code (sorry for that), but the error persists even with correct allocation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, now I understand and I can reproduce what you're seeing. Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Izaak Beekman wrote:
Ian, when you say that you "inline" the assignment, does that mean that you have public components in your objects and that you assign the subobjects one by one, or do you write defined assignments to achieve this?
I see I've used both. I've hit this issue typically dealing with container types (to allow "arrays" with elements of different dynamic type), so normally assignment is limited to one or two subroutines associated with changing the size of container array objects (and those subroutines are in the same module as the type definition). In other cases I've used defined assignment (where the defined assignment procedure emulates what should happen with intrinsic assignment, but using ALLOCATE(lhs%comp, SOURCE=rhs%comp) for polymorphic components (this also ties in a little with the discussion about ALLOCATE(...SOURCE=xxx) being "harmful").
The defined assignment approach seems more robust and easier to unwind once intrinsic assignment behaviour is reliable - not sure why I haven't always done it. One benefit of not using defined assignment in the context of changing the size of a container array is that you can use MOVE_ALLOC to move the component across - there's no point copying the object out of the original array as the original array is going to go away anyway.
Note that things have evolved over the years with different compiler versions - a workaround appropriate for 12.0 may not be relevant for 14.0. I'm also guessing here at the nature of the underlying problem, but rather tellingly, if I change Ferdinand's program in #6 to:
[fortran]
module m
implicit none
! abstract
type, abstract :: abstract_type
integer :: nonempty
end type
type, extends(abstract_type) :: extended_type
end type
! contains abstract allocatable
type :: container_type
integer :: nonempty
! fix: uncomment next line or use pointer instead
class(abstract_type), allocatable :: abstract_field
contains
procedure :: do_something
end type
contains
subroutine do_something(this)
class(container_type), intent(inout) :: this
type(container_type) :: some_local_result
! Define the local result, otherwise program is non-conforming.
some_local_result%nonempty = 0
! Either leave unallocated (object is still defined), or allocate
! to:
!ALLOCATE(extended_type:: some_local_result%abstract_field)
! Type-bound passed dummy is always polymorphic
! so we have to type cast it before assignment
! (even if the code doesn't use polymorphism at all)
select type (this)
type is (container_type)
! Unrolled imitation of intrinsic assignment.
this%nonempty = some_local_result%nonempty
IF (ALLOCATED(some_local_result%abstract_field)) &
ALLOCATE( this%abstract_field, &
SOURCE=some_local_result%abstract_field )
end select
end subroutine
end module
program p
use m
implicit none
type(container_type) :: my_container
call my_container%do_something() ! runtime error
IF (allocated(my_container%abstract_field)) THEN
SELECT TYPE (chicken => my_container%abstract_field)
TYPE IS (extended_type)
PRINT "('extended_type!')"
CLASS DEFAULT
PRINT "('rather confused!')"
end select
ELSE
PRINT "('not allocated!')"
END IF
end program[/fortran]
then everything appears to be working fine with 14.0.1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This has been fixed for a release later this year.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
To confirm, is it the run-time error alluded to in the original post and the compact reproducer in Quote #9 for a segmentation fault that gets fixed in an upcoming release later this year?
As I read through the above comments and take into account the corrections mentioned (e.g., Quote #14), the following appears to be a complete test case which causes a run-time error in the latest Intel Fortran compiler version. I assume this code will execute without errors following the fix? Fyi, the code below works as expected with gfortran GCC 5.0 development trunk.
program p implicit none integer :: istat ! abstract type, abstract :: abstract_type integer :: nonempty end type ! contains abstract allocatable type :: container_type integer :: nonempty ! fix: uncomment next line or use pointer instead class(abstract_type), allocatable :: abstract_field end type type, extends(abstract_type) :: extended_type end type type(container_type) :: rhs class(container_type), allocatable :: polymorphic_lhs !.. Ensure rhs is allocated and initialized allocate( extended_type :: rhs%abstract_field, stat=istat) if (istat /= 0) then print *, " error allocating rhs%abstract_field." stop end if rhs%nonempty = 2 select type (tmp => rhs%abstract_field) type is (extended_type) tmp%nonempty = 1 class default end select allocate(polymorphic_lhs, stat=istat) if (istat /= 0) then print *, " error allocating polymorphic_lhs." stop end if ! assign into polymorphic select type (polymorphic_lhs) type is (container_type) ! runtime error (ifort 14.0.1) ! problem with 'abstract_field' allocatable component ! (no matter it's allocation status in lhs and rhs) polymorphic_lhs = rhs class default end select ! expect output is T print *, " lhs%abstract_field allocated? ", allocated(polymorphic_lhs%abstract_field) stop end program p
Upon execution on Windows OS with Intel Fortran compiler 2015, Update 2:
forrtl: severe (122): invalid attempt to assign into a pointer that is not assoc iated Image PC Routine Line Source p64.exe 000000013FAB45A1 Unknown Unknown Unknown p64.exe 000000013FAB1562 MAIN__ 51 p.f90 p64.exe 000000013FAF79FE Unknown Unknown Unknown p64.exe 000000013FAF7CD4 Unknown Unknown Unknown kernel32.dll 00000000767759ED Unknown Unknown Unknown ntdll.dll 0000000076D8BA01 Unknown Unknown Unknown Press any key to continue . . .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, this test works in the new version. It won't work in the initial beta but should in any updates after that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, Steve. If it is of any help, the only relevant compiler option I used was standard-semantics; the rest were for warnings (-stand:f08) or run-time error checks (-trace -check:all) i.e., their equivalent for Windows OS.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page