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

问题描述

在这个最小的例子中,是否允许传递 y 的可选哑参数 test_wrapper 作为对应可选哑参数 {{1} present 个?

y

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

this Fortran standards document(第 311 页的第 15.5.2.12 节“参数存在和对不存在参数的限制”)中,它说:

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

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

但有趣的是,ubsan 似乎只在使用 test 时才会引发错误,即如果 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,optional :: y if (present(y)) then y = x end if end subroutine test end program 是假定形状的数组。其他任何像 dimension(:)y 加上大小参数 dimension(2)dimension(n)n 或什么都不会触发 ubsan

解决方法

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

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

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

gfortran 7 没有抱怨。此版本不理解 -std=f2018 可能与此相关。

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

  1. 如果 y 不存在,则既不引用也不定义(作为实际参数出现,不引用或定义)。
  2. y 都没有出现在指针赋值中(也不是指针)。
  3. y 都不是过程或过程指针。
  4. y of test_wrapper 不用作非可选虚拟参数的实际参数; y of test 不用作实际参数。
  5. test_wrapper中,实际参数是y本身,而不是y的子对象; y 中的 test 不用作实际参数。
  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(:),optional :: y
        if (present(y)) y=0  ! Used to silence unrelated warning
    end subroutine test
end program