首页 > 解决方案 > 是否允许为另一个过程的可选参数传递一个不存在的假定形状数组?

问题描述

在这个最小的例子中,是否允许传递 的可选虚拟参数可能不是对应的可选虚拟参数的y实际参数?test_wrapperpresentytest

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

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(:),即如果y是假设形状的数组。其他任何东西dimension(2),如dimension(n)添加大小参数nallocatablepointer什么都没有似乎不会触发 UBSan。

标签: fortranstandardsundefined-behavioroptional-parameterssanitizer

解决方案


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

如前所述,列出的限制均未提及“假定形状”。特别是,您引用的任何内容(如伊恩布什评论)都不适用于这种情况。这使得“除了上面列表中指出的情况外,它可能会被提供......”是允许的。

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

gfortran 7 没有抱怨。这个版本看不懂可能有关系-std=f2018

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

  1. 两者都不y存在时不被引用或定义(作为实际参数出现不是引用或定义)。
  2. 两者都没有y出现在指针赋值中(也不是指针)。
  3. 过程或过程指针都不y是。
  4. yoftest_wrapper不用作非可选虚拟参数的实际参数;yoftest不用作实际参数。
  5. test_wrapper实际参数中是y它本身,而不是 ; 的子对象yyintest不用作实际参数。
  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

推荐阅读