在这个最小的示例中,是否允许将
y
的可选虚拟参数 test_wrapper
传递给 present
的相应可选虚拟参数 y
的实际参数,而该参数可能不是 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, 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 标准文档(第 15.5.2.12 节,第 311 页上的“参数存在和对不存在参数的限制”)中写道:
- 不存在的可选虚拟参数受到以下限制。
- 如果是数据对象,则不应对其进行引用或定义。如果是具有默认初始化的类型,则初始化无效。
- [...]
- [...]
- [...]
- 以它作为基础对象并带有一个或多个子对象选择器的指示符不应作为实际参数提供。
- [...]
- 如果它是一个指针,则不得对其进行分配、释放、无效、指针分配或作为与可选非指针虚拟参数相对应的实际参数提供。
- 如果它是可分配的,则不得对其进行分配、释放或作为与可选的不可分配虚拟参数相对应的实际参数提供。
- [...]
- 除了上面列表中指出的之外,它可以作为与可选虚拟参数相对应的实际参数提供,然后该虚拟参数也被认为不存在。
我正在努力阅读该列表中的标准术语,所以也许其中我不完全理解的一项禁止对假定形状数组执行此操作?但在我看来,任何限制都不适用于这种情况。
但有趣的是,UBSan 似乎仅在使用
dimension(:)
时才会引发错误,即如果 y
是假定形状数组。其他类似 dimension(2)
、dimension(n)
以及添加尺寸参数 n
、allocatable
、pointer
或其他任何内容似乎都不会触发 UBSan。
对于缺少可选虚拟参数的假设形状的使用没有额外的限制。允许将不存在的假设形状数组参数作为另一个过程中可选虚拟参数的实际参数,除非另一个限制阻止它。 (随后的虚拟参数将被视为不存在。)
如上所述,列出的限制均未提及“假定形状”。特别是,您引用的那些内容(正如伊恩·布什评论的那样)都不适用于这种情况。这使得“除了上面列表中指出的之外,可以提供......”是宽容的。
如果你想进一步检查,每个子程序的假定形状参数
y
是一个普通虚拟变量(并遵守F2018 15.5.2.4的规则)。
gfortran 7 不会抱怨。可能与此版本不理解有关
-std=f2018
。
在 GCC 错误跟踪器上报告该问题后,已确认这确实是 gfortran 中的一个错误,UBSan 所揭示的错误是正确的。修复该问题的补丁已在 GCC 14 的开发过程中提交,并向后移植到 GCC 13.3 版本。
为了完整起见,让我们来看看为什么这些限制(所有限制,而不仅仅是问题中引用的限制)不适用。我不会引用这些限制,因此好奇的人需要查找问题中未包含的内容的文本。
y
不存在时,不会被引用或定义(显示为实际参数并不是引用或定义)。
y
都不会出现在指针赋值中(也不是指针)。
y
都不是过程或过程指针。
y
的
test_wrapper
不用作非可选虚拟参数的实际参数;
y
的
test
不用作实际参数。
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(:), intent(out), optional :: y
if (present(y)) y=0 ! Used to silence unrelated warning
end subroutine test
end program