是否允许为另一个过程的可选参数传递一个不存在的假定形状数组?

mja*_*bse 4 standards fortran optional-parameters sanitizer undefined-behavior

在该小例子,是它允许通过可选的伪参数ytest_wrapper可能不present作为用于相应的可选的伪参数实际参数ytest

program main
    implicit none
    real :: x = 5.0
    call test_wrapper(x)

contains
    subroutine test_wrapper(x, y)
        implicit none
        real, intent(in) :: x
        real, dimension(:), intent(out), optional :: y
        call test(x, y)
    end subroutine test_wrapper

    subroutine test(x, y)
        implicit none
        real, intent(in) :: x
        real, dimension(:), intent(out), optional :: y
        if (present(y)) then
            y = x
        end if
    end subroutine test
end program
Run Code Online (Sandbox Code Playgroud)

UndefinedBehaviourSanitizer 引发错误,表明它不是:https : //godbolt.org/z/nKj1h6G9r

这个 Fortran 标准文档(第 311 页的第 15.5.2.12 节,“参数存在和参数不存在的限制”)中,它说:

  1. 不存在的可选虚拟参数受以下限制。
    1. 如果它是一个数据对象,则不应引用或定义它。如果它是具有默认初始化的类型,则初始化无效。
    2. [...]
    3. [...]
    4. [...]
    5. 以它为基础对象并带有一个或多个子对象选择器的指示符不应作为实际参数提供。
    6. [...]
    7. 如果是指针,则不应分配、解除分配、无效化、指针分配或作为与可选的非指针虚拟参数相对应的实际参数提供。
    8. 如果它是可分配的,则不应分配、解除分配或作为与可选的不可分配虚拟参数相对应的实际参数提供。
    9. [...]
  2. 除了上面的列表中提到的,它可以作为一个实际参数提供,对应于一个可选的虚拟参数,然后也被认为不存在。

我正在努力阅读该列表中的标准,所以也许其中一项我不完全理解的项目禁止对假定形状的数组进行此操作?但在我看来,没有任何限制适用于这种情况。

但有趣的是,UBSan 似乎只在使用 时才会引发错误dimension(:),即 ify是一个假定形状的数组。还有什么样dimension(2)dimension(n)与添加的尺寸参数nallocatablepointer或什么似乎并不触发UBSan。

fra*_*lus 5

对于没有可选虚拟参数的假定形状的使用没有额外的限制。允许有一个不存在的假定形状数组参数作为另一个过程中可选虚拟参数的实际参数,除非另一个限制阻止它。(随后的虚拟参数将被视为不存在。)

如前所述,列出的限制都没有提到“假定形状”。特别是,你引用的那些(正如伊恩布什评论的)都不适用于这种情况。这使得“除非在上面的列表中注明,否则可能会提供......”是允许的。

如果你想进一步检查,y每个子程序的假定形状参数是一个普通的虚拟变量(并遵守 15.5.2.4 的规则)。

gfortran 7 没有抱怨。这个版本不理解可能是相关的-std=f2018

为了完整起见,让我们来看看为什么这些限制(所有,而不仅仅是问题中引用的那些)不适用。我不会引用限制,所以好奇的人需要查找那些不在问题中的文本。

  1. y当不存在时,两者都不会被引用或定义(作为实际参数出现而不是引用或定义)。
  2. 两者都没有y出现在指针赋值中(也不是指针)。
  3. 既不y是过程也不是过程指针。
  4. yoftest_wrapper不用作非可选虚拟参数的实际参数;yoftest不用作实际参数。
  5. test_wrapper实际参数中是y它本身,而不是y;的子对象。yintest不用作实际参数。
  6. 尽管是数组,但两者都不y是参考基本过程的实际参数。
  7. 也不y是指针。
  8. 两者都不可y分配。
  9. 两者都没有y长度类型参数(尤其是没有被查询的)。
  10. 两者都不y用作选择器。
  11. 两者都不y用于过程指示符。
  12. 两者都不y用于过程组件参考。

下面更简单的程序显示了相同的问题:

program main
    implicit none
    call test_wrapper

contains
    subroutine test_wrapper(y)
        real, dimension(1), intent(out), optional :: y
        call test(y)
    end subroutine test_wrapper

    subroutine test(y)
        real, dimension(:), intent(out), optional :: y
        if (present(y)) y=0  ! Used to silence unrelated warning
    end subroutine test
end program
Run Code Online (Sandbox Code Playgroud)