当传递 -fsanitize=undefined 时,来自 gcc-trunk 的 -Wconversion 诊断
-Wconversion diagnostic from gcc-trunk when -fsanitize=undefined is passed
这是关于 short int
s 在“常规算术转换”期间得到提升时的正确诊断。在操作期间 /
可以合理地发出诊断,但在 /=
期间应该发出 none。
gcc-trunk 和 clang-trunk 的行为似乎没问题(下面的第一种或第二种情况都没有发出诊断)...直到...
我们添加完全不相关的 -fsanitize=undefined
... 之后,完全奇怪:
gcc-trunk 为这两种情况发出诊断。 至少第二种情况确实不应该。
这是 gcc 中的错误吗?
Godbolt link with -O3 - same result
int main() {
short sum = 50;
short count = 10;
// sum and count get promoted to int for the "usual arithmetic conversions"
// then the assignment could result in a reasonable -Wconversion diagnostic for reduction back
// to short
// However clang-trunk and gcc-trunk choose NOT TO issue a diagnostic with -Wconversion enabled
short avg1 = sum / count;
// we should be able to prevent promotion to int by using /= assignment operator.
// Both clang-trunk and gcc-trunk, correctly, DON'T issue a diagnostic with -Wconversion enabled
auto tmp = sum;
tmp /= count;
short avg2 = tmp;
// HOWEVER if we add -fsanitize=undefined for both compilers
// then, bizarrly, gcc-trunk issues a diagnostic for both cases above and clang-trunk still for
// neither
// none of these ever issue a diagnostic (nor should they)
tmp += count; // all
tmp -= count; // are
tmp *= count; // silent
return (avg1 + avg2) & 0xff; // prevent "unused" diagnostics
}
编辑
这是我为 GCC 提交的错误:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104616
对于 built-in 复合赋值运算符 $=
,表达式 A $= B
的行为与表达式 A = A $ B
相同,只是 A
仅计算一次。所有提升和其他常见的算术转换以及转换回原始类型仍然会发生。
因此,不应期望 short avg1 = sum / count;
和 tmp /= count;
之间的警告不同。
在每种情况下都会发生从 int
到 short
的转换。因此,无论哪种情况,转换警告都是合适的。
但是,the documentation of GCC warning flags 特别指出,从 -Wconversion
标志中排除了对提升的小型类型的算术转换。尽管如此,GCC 还是提供了 -Warith-conversion
标志来包含此类情况。使用它 all 算术在你的例子中产生一个警告。
另请注意,-Wconversion
的这个例外仅在 GCC 10 中引入。有关它的更多上下文,引入它的错误报告是 here。
似乎Clang在这些情况下一直比GCC宽容。例如参见 [=26=].
对于 GCC 中的 /
-fsanitize=undefined
似乎打破了 -Wconversion
应该有的异常。在我看来,这与未定义的行为消毒剂有关,它专门为除法添加了 null-value 检查。也许,在这个转换之后,警告标志逻辑不再将其识别为较小类型的直接算术。
如果我对警告标志的预期行为的理解是正确的,我会说这看起来不是预期的,因此是一个错误。
用户17732522回答下讨论的补充信息。
下面的代码似乎说明了使用 +=
(仅使用单个小整数 RHS!)与 +=
使用 2 项二进制小整数运算 RHS 与简单 =
的情况有帮助吗?
gcc 为第一种和第三种情况发出 -Wconversion 诊断。 Clang 发出 none.
这是为什么?这是 gcc 发出这些诊断的方式中的“另一个不一致”吗?还是由于 this bug 仅涵盖使用单个小整数 RHS 的复合赋值的狭义情况而实施的更改?
注意:这都是没有-fsanitizer
int main() {
short a = 10;
short b = 20;
short sum1 = 30;
sum1 += b - a;
short sum2 = 30;
sum2 += b;
sum2 -= a;
short sum3 = 30 + b - a;
return (sum1 + sum2 + sum3) & 0xff; // prevent "unused" diagnostics
}
这是关于 short int
s 在“常规算术转换”期间得到提升时的正确诊断。在操作期间 /
可以合理地发出诊断,但在 /=
期间应该发出 none。
gcc-trunk 和 clang-trunk 的行为似乎没问题(下面的第一种或第二种情况都没有发出诊断)...直到...
我们添加完全不相关的 -fsanitize=undefined
... 之后,完全奇怪:
gcc-trunk 为这两种情况发出诊断。 至少第二种情况确实不应该。
这是 gcc 中的错误吗?
Godbolt link with -O3 - same result
int main() {
short sum = 50;
short count = 10;
// sum and count get promoted to int for the "usual arithmetic conversions"
// then the assignment could result in a reasonable -Wconversion diagnostic for reduction back
// to short
// However clang-trunk and gcc-trunk choose NOT TO issue a diagnostic with -Wconversion enabled
short avg1 = sum / count;
// we should be able to prevent promotion to int by using /= assignment operator.
// Both clang-trunk and gcc-trunk, correctly, DON'T issue a diagnostic with -Wconversion enabled
auto tmp = sum;
tmp /= count;
short avg2 = tmp;
// HOWEVER if we add -fsanitize=undefined for both compilers
// then, bizarrly, gcc-trunk issues a diagnostic for both cases above and clang-trunk still for
// neither
// none of these ever issue a diagnostic (nor should they)
tmp += count; // all
tmp -= count; // are
tmp *= count; // silent
return (avg1 + avg2) & 0xff; // prevent "unused" diagnostics
}
编辑
这是我为 GCC 提交的错误: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104616
对于 built-in 复合赋值运算符 $=
,表达式 A $= B
的行为与表达式 A = A $ B
相同,只是 A
仅计算一次。所有提升和其他常见的算术转换以及转换回原始类型仍然会发生。
因此,不应期望 short avg1 = sum / count;
和 tmp /= count;
之间的警告不同。
在每种情况下都会发生从 int
到 short
的转换。因此,无论哪种情况,转换警告都是合适的。
但是,the documentation of GCC warning flags 特别指出,从 -Wconversion
标志中排除了对提升的小型类型的算术转换。尽管如此,GCC 还是提供了 -Warith-conversion
标志来包含此类情况。使用它 all 算术在你的例子中产生一个警告。
另请注意,-Wconversion
的这个例外仅在 GCC 10 中引入。有关它的更多上下文,引入它的错误报告是 here。
似乎Clang在这些情况下一直比GCC宽容。例如参见 [=26=].
对于 GCC 中的 /
-fsanitize=undefined
似乎打破了 -Wconversion
应该有的异常。在我看来,这与未定义的行为消毒剂有关,它专门为除法添加了 null-value 检查。也许,在这个转换之后,警告标志逻辑不再将其识别为较小类型的直接算术。
如果我对警告标志的预期行为的理解是正确的,我会说这看起来不是预期的,因此是一个错误。
用户17732522回答下讨论的补充信息。
下面的代码似乎说明了使用 +=
(仅使用单个小整数 RHS!)与 +=
使用 2 项二进制小整数运算 RHS 与简单 =
的情况有帮助吗?
gcc 为第一种和第三种情况发出 -Wconversion 诊断。 Clang 发出 none.
这是为什么?这是 gcc 发出这些诊断的方式中的“另一个不一致”吗?还是由于 this bug 仅涵盖使用单个小整数 RHS 的复合赋值的狭义情况而实施的更改?
注意:这都是没有-fsanitizer
int main() {
short a = 10;
short b = 20;
short sum1 = 30;
sum1 += b - a;
short sum2 = 30;
sum2 += b;
sum2 -= a;
short sum3 = 30 + b - a;
return (sum1 + sum2 + sum3) & 0xff; // prevent "unused" diagnostics
}