Test (extracted from a larger module) > cat test2.f90 module test integer,parameter,private :: int32 = 4 integer,private,parameter :: dik = kind(0) ! Default Integer Kind type MPI_Datatype integer :: mpi_val end type type(MPI_Datatype),parameter,private :: MPIx_I4 = MPI_Datatype(4) type(MPI_Datatype),parameter,private :: MPIx_I8 = MPI_Datatype(8) type(MPI_Datatype),parameter :: MPI_INTEGER = merge(MPIx_I4, MPIx_I8, dik==int32) end module test > ftn -c test2.f90 f951: internal compiler error: in gfc_conv_structure, at fortran/trans-expr.c:5360 Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions. Also fails with 4.8. Allowing MERGE here is a F2003 feature (elemental intrinsic with constant arguments). In any case, the compiler should not abort. Compiles OK with Cray compiler.
Plain integers in MERGE seem to be OK, so the problem appears to be with using constants of derived type as arguments to MERGE here.
I can confirm this error. It occurs with all gfortran versions I tried (starting from 4.3 up to the current trunk). Slightly compactified test case: module test type MPI_Datatype integer :: mpi_val end type type(MPI_Datatype) :: MPI_INTEGER = merge(MPI_Datatype(4), MPI_Datatype(8), .false.) end module Apparently the declaration needs to be in a module for the error to occur, and also derived types need to be involved. Using -std=f95, the test case is correctly rejected (without ICE): type(MPI_Datatype) :: MPI_INTEGER = merge(MPI_Datatype(4), MPI_Datatype(8), . 1 Error: Fortran 2003: Elemental function as initialization expression with non-integer/non-character arguments at (1)
The backtrace one gets on trunk is: 0x669272 gfc_conv_structure(gfc_se*, gfc_expr*, int) /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:5971 0x667dbb gfc_conv_initializer(gfc_expr*, gfc_typespec*, tree_node*, bool, bool, bool) /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:5550 0x648799 gfc_get_symbol_decl(gfc_symbol*) /home/jweil/gcc48/trunk/gcc/fortran/trans-decl.c:1480 That line (trans-expr.c:5971) is the following assert: gcc_assert (expr->expr_type == EXPR_STRUCTURE); which fails because we have an EXPR_FUNCTION.
For a case like this: module test integer :: MPI_INTEGER = merge(4, 8, .false.) end module we do not get an EXPR_FUNCTION in gfc_conv_initializer, but it is simplified to EXPR_CONSTANT before. It seems that this does not work for derived types.
The following patch fixes it: Index: gcc/fortran/simplify.c =================================================================== --- gcc/fortran/simplify.c (revision 193810) +++ gcc/fortran/simplify.c (working copy) @@ -3973,8 +3973,10 @@ gfc_simplify_maskl (gfc_expr *i, gfc_expr *kind_ar gfc_expr * gfc_simplify_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask) { - if (tsource->expr_type != EXPR_CONSTANT - || fsource->expr_type != EXPR_CONSTANT + if ((tsource->expr_type != EXPR_CONSTANT + && tsource->expr_type != EXPR_STRUCTURE) + || (fsource->expr_type != EXPR_CONSTANT + && fsource->expr_type != EXPR_STRUCTURE) || mask->expr_type != EXPR_CONSTANT) return NULL;
(In reply to comment #2) > type(MPI_Datatype) :: MPI_INTEGER = merge(MPI_Datatype(4), MPI_Datatype(8), > .false.) The problem is related to having array PARAMETERs. For normal parameters, simply their value is stored in the .mod file and always inserted when used. For array parameters, a static array in read-only memory is created, which can then be accessed at run time. That avoids replicating the information several times. In addition, the expression is also stored in the .mod file. Especially if constructors are involved, the current compile-time simplification doesn't work that well. Additionally, the question is also whether it always makes sense to expand constructors if one wants to simplify code. In any case, there is room for improvement. See also PR 44856 and PR 51260. * * * In gfc_simplify_merge, the compiler gives up when the type is not an EXPR_CONSTANT: 3976 if (tsource->expr_type != EXPR_CONSTANT 3977 || fsource->expr_type != EXPR_CONSTANT 3978 || mask->expr_type != EXPR_CONSTANT) 3979 return NULL; For the test case of this PR, one has an EXPR_STRUCTURE. Maybe replacing the check by calls to gfc_is_constant_expr() is sufficient.
I think the following variant makes even more sense: Index: gcc/fortran/simplify.c =================================================================== --- gcc/fortran/simplify.c (revision 193810) +++ gcc/fortran/simplify.c (working copy) @@ -3973,9 +3973,7 @@ gfc_simplify_maskl (gfc_expr *i, gfc_expr *kind_ar gfc_expr * gfc_simplify_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask) { - if (tsource->expr_type != EXPR_CONSTANT - || fsource->expr_type != EXPR_CONSTANT - || mask->expr_type != EXPR_CONSTANT) + if (mask->expr_type != EXPR_CONSTANT) return NULL; return gfc_copy_expr (mask->value.logical ? tsource : fsource); In order to simplify a MERGE expression, we don't need to rely on the TSOURCE and FSOURCE arguments being constant. It's sufficient that the MASK is.
(In reply to comment #5) > + && tsource->expr_type != EXPR_STRUCTURE) That's not okay: If you have integer, allocatable :: a(:), b(:) one has an EXPR_STRUCTURE for "[a,b]" but not a constant expression. One has to do a deep check. Well, gfc_is_constant_expr() is supposed to do this. (Or should gfc_check_init_expr be used? I always confuse the two. For F90/F95 it makes a difference, for F200x it doesn't, and gfortran's usage is a mess.)
(In reply to comment #7) > - if (tsource->expr_type != EXPR_CONSTANT > - || fsource->expr_type != EXPR_CONSTANT > - || mask->expr_type != EXPR_CONSTANT) > + if (mask->expr_type != EXPR_CONSTANT) > return NULL; That makes sense: If mask is a constant scalar, tsource or fsource can be used. That patch is pre-approved. However, at some point one has also to simplify: MERGE([1,2],[11,22], [.true.,.false.]) and for that case, all arguments have to be gfc_is_constant_expr(). At least Fortran 2008 requires that the processor can do such a simplification. (One could also handle the special case that mask is an array of only .true. or only .false.)
(In reply to comment #9) > (In reply to comment #7) > > - if (tsource->expr_type != EXPR_CONSTANT > > - || fsource->expr_type != EXPR_CONSTANT > > - || mask->expr_type != EXPR_CONSTANT) > > + if (mask->expr_type != EXPR_CONSTANT) > > return NULL; > > That makes sense: If mask is a constant scalar, tsource or fsource can be used. > That patch is pre-approved. Unfortunately, it triggers a couple of testsuite regressions: FAIL: gfortran.dg/bound_2.f90 -O0 execution test FAIL: gfortran.dg/bound_7.f90 -O0 execution test FAIL: gfortran.dg/char_cast_1.f90 -O scan-tree-dump-times original "6\\]\\[1\\]" 2 FAIL: gfortran.dg/merge_char_3.f90 -O0 execution test The last one is understandable: It is supposed to check for different char lengths beings passed to MERGE at runtime, but the call to MERGE is simplified away (which is good!). The third one is a tree-dump failure, where apparently the dump is different because MERGE is simplified away now. The first two are runtime checks, which are basically identical. Here is a reduced test case for these: implicit none integer :: i(-1:1) = 0 print *, lbound(merge(i,i,.true.)) print *, ubound(merge(i,i,.true.)) end Without the patch, this prints: 1 3 And with the patch: -1 1 The output with the patch does look more reasonable to me. Or is there any reason why the standard would demand the MERGE expression to have bounds of 1:3 instead of -1:1 ?
(In reply to comment #10) > The first two are runtime checks, which are basically identical. Here is a > reduced test case for these: > > implicit none > integer :: i(-1:1) = 0 > > print *, lbound(merge(i,i,.true.)) > print *, ubound(merge(i,i,.true.)) > > end > > Without the patch, this prints: > 1 > 3 > And with the patch: > -1 > 1 > > The output with the patch does look more reasonable to me. Or is there any > reason why the standard would demand the MERGE expression to have bounds of 1:3 > instead of -1:1 ? At least all of ifort, sunf95 and g95 agree with the first variant (1:3). [Btw, the bound_{2,7} test cases come from PR 29391.]
(In reply to comment #10) > integer :: i(-1:1) = 0 > print *, lbound(merge(i,i,.true.)) > Without the patch, this prints: > 1 > And with the patch: > -1 Makes perfectly sense: For "lbound(array,dim)": "If ARRAY is a whole array and either ARRAY is an assumed-size array of rank DIM or dimension DIM of ARRAY has nonzero extent, LBOUND (ARRAY, DIM) has a value equal to the lower bound for subscript DIM of ARRAY. Otherwise the result value is 1." With "whole array array component or array name without further qualication (6.5.2)" Thus "lbound(i)" is a whole-array, "lbound(i(:))" or "lbound(merge(i,i,.true))" is not. I think the simplest it to replace "lbound (merge(i,i,.true.)" by "lbound( (i) )" [e->expr_type = EXPR_OP && e->value.op.op == INTRINSIC_PARENTHESES]. Possibly only if expr_type == EXPR_VARIABLE as otherwise the INTRINSIC_PARENTHESES will hamper further optimization (unless -fno-protect-parens).
ICE from using MERGE in a constant specification expression, not in this program an initialization expression because it's an array bound, with gfortran 4.7.2. I have tried to install later versions but without success so far. cayley[~/Jfh] % cat testmerge3.f90 program testmerge3 implicit none integer,parameter::iarray(merge(2,3,.true.)) = 1, i = size(iarray) print "(A,99I2)",'i,iarray =',i,iarray end program testmerge3 cayley[~/Jfh] % gfortran -v testmerge3.f90 Driving: gfortran -v testmerge3.f90 -l gfortran -l m -shared-libgcc Using built-in specs. COLLECT_GCC=gfortran COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /build/src/gcc-4.7.2/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --enable-libstdcxx-time --enable-gnu-unique-object --enable-linker-build-id --with-ppl --enable-cloog-backend=isl --disable-ppl-version-check --disable-cloog-version-check --enable-lto --enable-gold --enable-ld=default --enable-plugin --with-plugin-ld=ld.gold --with-linker-hash-style=gnu --disable-multilib --disable-libssp --disable-build-with-cxx --disable-build-poststage1-with-cxx --enable-checking=release Thread model: posix gcc version 4.7.2 (GCC) COLLECT_GCC_OPTIONS='-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/f951 testmerge3.f90 -quiet -dumpbase testmerge3.f90 -mtune=generic -march=x86-64 -auxbase testmerge3 -version -fintrinsic-modules-path /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/finclude -o /tmp/ccPFQJLT.s GNU Fortran (GCC) version 4.7.2 (x86_64-unknown-linux-gnu) compiled by GNU C version 4.7.2, GMP version 5.1.0, MPFR version 3.1.1-p2, MPC version 1.0.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU Fortran (GCC) version 4.7.2 (x86_64-unknown-linux-gnu) compiled by GNU C version 4.7.2, GMP version 5.1.0, MPFR version 3.1.1-p2, MPC version 1.0.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 f951: internal compiler error: in is_illegal_recursion, at fortran/resolve.c:1420 Please submit a full bug report, with preprocessed source if appropriate. See <https://bugs.archlinux.org/> for instructions. cayley[~/Jfh] %
Just a note that I'm now using $ gf --version GNU Fortran (MacPorts gcc49 4.9-20130609_0) 4.9.0 20130609 (experimental) Copyright (C) 2013 Free Software Foundation, Inc. and the original test case works with this version.
(In reply to Bill Long from comment #14) > Just a note that I'm now using > GNU Fortran (MacPorts gcc49 4.9-20130609_0) 4.9.0 20130609 (experimental) > and the original test case works with this version. That issue was fixed for PR 56649 - which is the identical to the original test case. (In reply to john.harper from comment #13) > ICE from using MERGE in a constant specification expression, not in this > program an initialization expression because it's an array bound, with > gfortran 4.7.2. > > cayley[~/Jfh] % cat testmerge3.f90 > program testmerge3 > implicit none > integer,parameter::iarray(merge(2,3,.true.)) = 1, i = size(iarray) > print "(A,99I2)",'i,iarray =',i,iarray > end program testmerge3 That program still gives an ICE with GCC 4.9: f951: internal compiler error: in is_illegal_recursion, at fortran/resolve.c:1555 (Crossref: See also https://groups.google.com/forum/#!topic/comp.lang.fortran/sURf0GnYYfg )
Update, running test from comment 13 : $ gfortran-7 testmerge3.f90 testmerge3.f90:3:0: print "(a,99i2)",'i,iarray =',i,iarray internal compiler error: in gfc_conv_expr_descriptor, at fortran/trans-array.c:6737 It works with a separated extra parameter : $ cat z1.f90 program p integer, parameter :: n = merge(2,3,.true.) integer, parameter :: iarray(n) = 1, i = size(iarray) print "(a,99i2)",'i,iarray =',i,iarray end $ gfortran-6 -g -O0 -Wall -fcheck=all z1.f90 $ a.out i,iarray = 2 1 1
From comment 15 >That issue was fixed for PR 56649 - which is the identical to the original > test case. > ... > That program still gives an ICE with GCC 4.9: > f951: internal compiler error: in is_illegal_recursion, at fortran/resolve.c:1555 The ICE is now internal compiler error: in gfc_conv_expr_descriptor, at fortran/trans-array.c:6972 and I have opened pr82314 for this remaining issue. Closing this PR.