File: final-support.F90

package info (click to toggle)
fckit 0.14.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,528 kB
  • sloc: f90: 7,650; python: 5,805; cpp: 2,202; pascal: 805; sh: 656; makefile: 66
file content (465 lines) | stat: -rw-r--r-- 11,876 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
! (C) Copyright 2013 ECMWF.
!
! This software is licensed under the terms of the Apache Licence Version 2.0
! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
! In applying this licence, ECMWF does not waive the privileges and immunities
! granted to it by virtue of its status as an intergovernmental organisation nor
! does it submit to any jurisdiction.



! This file is used in conjunction with final-support.cmake to detect compiler behaviour
! for the finalisation of derived types

#ifdef FINAL_FUNCTION_RESULT
#define TEST 1
#endif

#ifdef FINAL_UNINITIALIZED_LOCAL
#define TEST 1
#endif

#ifdef FINAL_UNINITIALIZED_INTENT_OUT
#define TEST 2
#endif

#ifdef FINAL_UNINITIALIZED_INTENT_INOUT
#define TEST 3
#endif

#ifdef FINAL_NOT_PROPAGATING
#define TEST 6
#endif

#ifdef FINAL_NOT_INHERITING
#define TEST 7
#endif

#ifdef FINAL_BROKEN_FOR_ALLOCATABLE_ARRAY
#define TEST 8
#endif

#ifdef FINAL_BROKEN_FOR_AUTOMATIC_ARRAY
#define TEST 9
#endif

#ifndef TEST
#define OUTPUT
#endif

module final_support_module
implicit none
public
integer, parameter :: output_unit = 6

type :: Object
  logical, public :: return = .false.
  logical, public :: initialized = .false.
  logical, public :: finalized = .false.
contains
  procedure, public :: copy => copy_f
  generic, public :: assignment(=) => copy
  final :: destructor
endtype

interface Object
  module procedure construct_Object
end interface

type, extends(Object) :: ObjectDerivedWithFinal
contains
  final :: destructor_ObjectDerivedWithFinal
endtype

interface ObjectDerivedWithFinal
  module procedure construct_ObjectDerivedWithFinal
end interface

type, extends(Object) :: ObjectDerivedWithoutFinal
contains
endtype

interface ObjectDerivedWithoutFinal
  module procedure construct_ObjectDerivedWithoutFinal
end interface


integer :: final_uninitialized = 0
integer :: final_return        = 0
integer :: final_initialized   = 0
integer :: final_base         = 0
integer :: final_derived       = 0
integer :: indent=0

contains

subroutine reset()
  final_uninitialized = 0
  final_return        = 0
  final_initialized   = 0
  final_base          = 0
  final_derived       = 0
end subroutine

subroutine write_indented( string )
  character(len=*) :: string
  integer :: i
#ifdef OUTPUT
  do i=1,indent
    write(0,'(A)',advance='no') '  '
  enddo
  write(0,'(A)') string
#endif
end subroutine
subroutine write_counters()
#ifdef OUTPUT
  write(0,*) ''
  write(0,*) 'final_uninitialized: ',final_uninitialized
  write(0,*) 'final_initialized:   ',final_initialized
  write(0,*) 'final_return:        ',final_return
  write(0,*) 'final_base:          ',final_base
  write(0,*) 'final_derived:       ',final_derived
#endif
end subroutine

function construct_Object() result(this)
  type(Object) :: this
  this%initialized = .true.
  this%return = .true.
end function

function construct_ObjectDerivedWithFinal() result(this)
  type(ObjectDerivedWithFinal) :: this
  this%initialized = .true.
  this%return = .true.
end function

function construct_ObjectDerivedWithoutFinal() result(this)
  type(ObjectDerivedWithoutFinal) :: this
  this%initialized = .true.
  this%return = .true.
end function

subroutine destructor_ObjectDerivedWithFinal(this)
  type(ObjectDerivedWithFinal) :: this
  call write_indented( 'final( derived )' )
  final_derived = final_derived + 1
  associate( unused => this )
  end associate
end subroutine

subroutine copy_f(this,obj_in)
  class(Object), intent(inout) :: this
  class(Object), target, intent(in) :: obj_in
#if 1
  if( obj_in%return ) then
     if( .not. this%initialized ) then
        call write_indented( 'copy uninitialized from rvalue' )
     else
        call write_indented( 'copy initialized from rvalue' )
     endif
  else if ( obj_in%initialized ) then
     if( .not. this%initialized ) then
        call write_indented( 'copy uninitialized from already existing initialized' )
     else
        call write_indented( 'copy initialized from already existing initialized' )
     endif
  endif
#endif
  this%initialized = obj_in%initialized
  this%return = .false.
end subroutine

impure elemental subroutine destructor(this)
  type(Object), intent(inout) :: this
  final_base = final_base + 1

  if( .not. this%initialized ) then
    call write_indented( 'final( uninitialized )' )
    final_uninitialized = final_uninitialized+1
  else
    if( this%return ) then
      call write_indented( 'final( returned )' )
      final_return = final_return+1
    else
      call write_indented( 'final( initialized )' )
      final_initialized = final_initialized+1
    endif
  endif
end subroutine


subroutine create_obj_out(obj)
  implicit none
  type(Object), intent(out) :: obj
  call write_indented( 'obj = Object()' )
  indent = indent+1
  obj = Object()
  indent = indent-1
end subroutine

subroutine create_obj_inout(obj)
  implicit none
  type(Object), intent(inout) :: obj
  call write_indented( 'obj = Object()' )
  indent = indent+1
  obj = Object()
  indent = indent-1
end subroutine

subroutine test1
  implicit none
  type(Object) :: obj
  call write_indented( 'obj = Object()' )
  indent = indent+1
  obj = Object()
  indent = indent-1
end subroutine

subroutine test2
  implicit none
  type(Object) :: obj
  call write_indented( 'subroutine create_obj_out(obj)' )
  indent = indent+1
  call create_obj_out(obj)
  indent = indent-1
  call write_indented( 'end subroutine create_obj_out(obj)' )
end subroutine

subroutine test3
  implicit none
  type(Object) :: obj
  call write_indented( 'subroutine create_obj_inout(obj)' )
  indent = indent+1
  call create_obj_inout(obj)
  indent = indent-1
  call write_indented( 'end subroutine create_obj_inout(obj)' )
end subroutine

subroutine test4
  implicit none
  type(Object) :: obj1, obj2
  call write_indented( 'subroutine create_obj_inout(obj1)' )
  indent = indent+1
  call create_obj_inout(obj1)
  indent = indent-1
  call write_indented( 'end subroutine create_obj_inout(obj)' )
  call write_indented( 'obj2 = obj1' )
  indent = indent+1
  obj2 = obj1
  indent = indent-1
end subroutine

subroutine test5
  implicit none
  type(Object) :: obj1, obj2
  call write_indented( 'subroutine create_obj_inout(obj1)' )
  indent = indent+1
  call create_obj_inout(obj1)
  indent = indent-1
  call write_indented( 'end subroutine create_obj_inout(obj)' )
  call write_indented( 'obj2 = obj1' )
  indent = indent+1
  obj2 = obj1
  indent = indent-1
  call write_indented( 'obj2 = obj1' )
  indent = indent+1
  obj1 = obj2
  indent = indent-1
end subroutine

subroutine test6
  implicit none
  type(ObjectDerivedWithFinal) :: obj
  indent = indent+1
  obj = ObjectDerivedWithFinal()
  indent = indent-1
  call write_indented('--- scope end ---')
end subroutine

subroutine test7
  implicit none
  type(ObjectDerivedWithoutFinal) :: obj
  indent = indent+1
  obj = ObjectDerivedWithoutFinal()
  indent = indent-1
  call write_indented('--- scope end ---')
end subroutine

subroutine test8
  implicit none
  type(Object), allocatable :: list(:)
  allocate( list(2) )
  call write_indented('list(1) = Object()')
  indent=indent+1
  list(1) = Object()
  indent=indent-1
  call write_indented('list(2) = Object()')
  indent=indent+1
  list(2) = Object()
  indent=indent-1
  call write_indented('--- deallocate ---')
  deallocate( list )
  call write_indented('--- scope end ---')
end subroutine

subroutine test9
  implicit none
  type(Object) :: list(2)
  call write_indented('list(1) = Object()')
  indent=indent+1
  list(1) = Object()
  indent=indent-1
  call write_indented('list(2) = Object()')
  indent=indent+1
  list(2) = Object()
  indent=indent-1
  call write_indented('--- scope end ---')
end subroutine

subroutine run_test(i)
  integer, intent(in) :: i
  character(len=1) :: test_number
  write(test_number,'(I0)') i
#ifndef TEST
#define COMPARE_TEST(x) (x == i)
#else
#define COMPARE_TEST(x) (x == TEST)
#endif
#ifdef OUTPUT
  write(0,'(A)') '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
#endif
  call write_indented( 'subroutine test'//test_number )
  indent = indent+1
  call reset
  if( COMPARE_TEST(1) ) call test1
  if( COMPARE_TEST(2) ) call test2
  if( COMPARE_TEST(3) ) call test3
  if( COMPARE_TEST(4) ) call test4
  if( COMPARE_TEST(5) ) call test5
  if( COMPARE_TEST(6) ) call test6
  if( COMPARE_TEST(7) ) call test7
  if( COMPARE_TEST(8) ) call test8
  if( COMPARE_TEST(9) ) call test9
  indent = indent-1
  call write_indented( 'end subroutine test'//test_number )
  call write_counters()
end subroutine


end module


program final_support
  use final_support_module
  implicit none

  call run_test(1)
  call write_indented( 'test1 summary:' )
  if( final_return > 0 ) then
    call write_indented( 'rvalue Object() was finalised' )
  endif
  if( final_uninitialized > 0 ) then
    call write_indented( 'Locally scoped object is finalised before assignment' )
  endif
  if( final_return == 0 .and. final_uninitialized == 0 ) then
    call write_indented( 'Behaviour of GNU 6.3.0' )
  endif
  if( final_return == 0 .and. final_uninitialized == 1 ) then
    call write_indented( 'Behaviour of PGI 17.10' )
  endif
  if( final_return == 1 .and. final_uninitialized == 0 ) then
    call write_indented( 'Behaviour of Cray 8.6.2' )
    call write_indented( 'Behaviour of Intel 17-18' )
  endif
#ifdef FINAL_FUNCTION_RESULT
  write(output_unit,'(I0)',advance='no') final_return
#endif
#ifdef FINAL_UNINITIALIZED_LOCAL
  write(output_unit,'(I0)',advance='no') final_uninitialized
#endif

  call run_test(2)
  call write_indented( 'test2 summary:' )
  if( final_uninitialized > 0 ) then
    call write_indented( 'object with intent OUT is finalised before assignment' )
  endif
  if( final_uninitialized == 1 ) then
    call write_indented( 'Behaviour of GNU 6.3.0' )
    call write_indented( 'Behaviour of Intel 17-18' )
  endif
  if( final_uninitialized == 0 ) then
    call write_indented( 'Behaviour of Cray 8.6.2' )
    call write_indented( 'Behaviour of PGI 17.10' )
  endif
#ifdef FINAL_UNINITIALIZED_INTENT_OUT
  write(output_unit,'(I0)',advance='no') final_uninitialized
#endif


  call run_test(3)
  call write_indented( 'test3 summary:' )
  if( final_uninitialized > 0 ) then
    call write_indented('object with intent INOUT is finalised before assignment')
  endif
  if( final_uninitialized == 0 ) then
    call write_indented( 'Behaviour of GNU 6.3.0' )
    call write_indented( 'Behaviour of Cray 8.6.2' )
    call write_indented( 'Behaviour of Intel 17-18' )
    call write_indented( 'Behaviour of PGI 17.1' )
  endif
#ifdef FINAL_UNINITIALIZED_INTENT_INOUT
  write(output_unit,'(I0)',advance='no') final_uninitialized
#endif

  call run_test(4)

  call write_indented( 'test4 summary:' )
  if( final_uninitialized == 0 .and. final_initialized == 2 ) then
    call write_indented( 'Behaviour of GNU 6.3.0' )
  endif

  call run_test(5)

  call write_indented( 'test5 summary:' )
  if( final_uninitialized == 0 .and. final_initialized == 2 ) then
    call write_indented( 'Behaviour of GNU 6.3.0' )
  endif

  call run_test(6)
#ifdef FINAL_NOT_PROPAGATING
  if( final_derived > 0 .and. final_initialized == 0 ) then
    write(output_unit,'(I0)',advance='no') 1
  else
    write(output_unit,'(I0)',advance='no') 0
  endif
#endif

  call run_test(7)
#ifdef FINAL_NOT_INHERITING
  if( final_initialized == 0 ) then
    write(output_unit,'(I0)',advance='no') 1
  else
    write(output_unit,'(I0)',advance='no') 0
  endif
#endif

  call run_test(8)
#ifdef FINAL_BROKEN_FOR_ALLOCATABLE_ARRAY
  if( final_initialized == 0 ) then
    write(output_unit,'(I0)',advance='no') 1
  else
    write(output_unit,'(I0)',advance='no') 0
  endif
#endif

  call run_test(9)
#ifdef FINAL_BROKEN_FOR_AUTOMATIC_ARRAY
  if( final_initialized == 0 ) then
    write(output_unit,'(I0)',advance='no') 1
  else
    write(output_unit,'(I0)',advance='no') 0
  endif
#endif

end program