问题描述
在这个最小的例子中,是否允许传递 y
的可选哑参数 test_wrapper
作为对应可选哑参数 {{1} present
个?
y
UndefinedBehavIoUrSanitizer 引发错误,表明它不是:https://godbolt.org/z/nKj1h6G9r
在 this Fortran standards document(第 311 页的第 15.5.2.12 节“参数存在和对不存在参数的限制”)中,它说:
- 不存在的可选虚拟参数受到以下限制。
- 除了上面列表中提到的之外,它可以作为与可选虚拟参数相对应的实际参数提供,然后也将其视为不存在。
我正在努力阅读该列表中的标准语,所以也许其中一项我不完全理解的项目禁止对假定形状数组进行此操作?但在我看来,任何限制都不适用于这种情况。
但有趣的是,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
可能与此相关。
为了完整起见,让我们来看看为什么这些限制(所有,而不仅仅是问题中引用的那些)不适用。我不会引用限制,所以好奇的人需要查找那些不在问题中的文本。
- 如果
y
不存在,则既不引用也不定义(作为实际参数出现,不引用或定义)。 -
y
都没有出现在指针赋值中(也不是指针)。 -
y
都不是过程或过程指针。 -
y
oftest_wrapper
不用作非可选虚拟参数的实际参数;y
oftest
不用作实际参数。 - 在
test_wrapper
中,实际参数是y
本身,而不是y
的子对象;y
中的test
不用作实际参数。 - 虽然是数组,但
y
都不是引用基本过程的实际参数。 -
y
都不是指针。 -
y
都不可分配。 -
y
都没有长度类型参数(尤其是没有被查询的)。 -
y
均不用作选择器。 - 过程指示符中均未使用
y
。 - 过程组件引用中均未使用
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