Fortran2003参数化派生类型分配报错:gfortran 8.3内部编译器错误
我之前在处理Fortran参数化派生类型时也踩过类似的坑,你遇到的情况是gfortran 8.3版本对参数化派生类型(PDT)中使用算术表达式定义数组长度的支持存在未修复的bug——Intel Fortran Compiler 18.0已经正确实现了这部分Fortran标准的支持,但旧版gfortran在处理这种场景时会直接触发内部编译器错误(ICE)。
问题复现代码
public type mytab(n) integer, len :: n integer :: tab1(n) integer :: tab2(n*2) ! 这里使用了依赖参数的算术表达式 end type mytab contains subroutine create(pt1, n) type(mytab(:)),allocatable, intent(out) :: pt1 integer, intent(in) :: n allocate (mytab(n)::pt1) ! 分配时触发ICE end subroutine
报错信息
internal compiler error: in gfc_conv_expr_op, at fortran/trans-expr.c:3498
0x5c5fa9 gfc_conv_expr_op ../../gcc/fortran/trans-expr.c:3498
0x5c5fa9 gfc_conv_expr(gfc_se*, gfc_expr*) ../../gcc/fortran/trans-expr.c:7999
0x704b17 gfc_conv_expr_val(gfc_se*, gfc_expr*) ../../gcc/fortran/trans-expr.c:8056
0x704c30 gfc_conv_expr_type(gfc_se*, gfc_expr*, tree_node*) ../../gcc/fortran/trans-expr.c:8070
0x6e3401 structure_alloc_comps ../../gcc/fortran/trans-array.c:9129
0x6e6260 gfc_allocate_pdt_comp(gfc_symbol*, tree_node*, int, gfc_actual_arglist*) ../../gcc/fortran/trans-array.c:9405
0x73e4cd gfc_trans_allocate(gfc_code*) ../../gcc/fortran/trans-stmt.c:6599
0x6cf5e7 trans_code ../../gcc/fortran/trans.c:2001
0x6f5dbb gfc_generate_function_code(gfc_namespace*) ../../gcc/fortran/trans-decl.c:6515
0x6d2fe9 gfc_generate_module_code(gfc_namespace*) ../../gcc/fortran/trans.c:2227
0x68612b translate_all_program_units ../../gcc/fortran/parse.c:6112
0x68612b gfc_parse_file() ../../gcc/fortran/parse.c:6328
0x6cca5f gfc_be_parse_file ../../gcc/fortran/f95-lang.c:204
Please submit a full bug report, with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
问题原因分析
内部编译器错误(ICE)本质是编译器自身的逻辑缺陷,这里gfortran 8.3在处理参数化派生类型中n*2这种依赖类型参数的算术表达式时,代码转换环节(gfc_conv_expr_op函数)出现了未处理的情况,导致崩溃。
解决方案
优先升级gfortran版本
这个bug在gfortran 9.x及以后的版本中已经被修复,建议你更新到较新的稳定版本(比如10.x、11.x或更高),新版本对Fortran 2003/2008标准中的参数化派生类型支持更加完善,能直接正确编译你的原始代码。临时规避方案(无法升级时)
如果暂时无法升级编译器,可以把数组长度的表达式提前定义为派生类型的额外参数,绕开直接在数组声明中使用算术表达式:public type mytab(n, n_double) integer, len :: n integer, len :: n_double = n*2 ! 将表达式结果作为类型参数 integer :: tab1(n) integer :: tab2(n_double) end type mytab contains subroutine create(pt1, n) type(mytab(:,:)),allocatable, intent(out) :: pt1 integer, intent(in) :: n allocate (mytab(n, n*2)::pt1) end subroutine
内容的提问来源于stack exchange,提问作者devFortran

