GCC中constexpr上下文用__builtin_expect检查临时指针空值致异常
核心矛盾:非标准扩展干扰constexpr合法性检查
你的代码出现异常的根源在于__builtin_expect这个GCC非标准内置扩展,以及C++标准对constexpr上下文的严格限制:
临时对象指针的constexpr比较限制
标准C++明确规定:在constexpr求值过程中,临时对象的地址不能与nullptr或其他临时对象的地址做比较(除非是同一个对象的地址)。你的指针版Add函数中,x && y本质是检查两个指针均非空,也就是分别和nullptr进行比较,这属于constexpr上下文里的非法操作。__builtin_expect绕过了编译检查
__builtin_expect是GCC用于分支预测的扩展,不属于C++标准的constexpr允许操作。GCC处理constexpr函数时会忽略它的分支预测语义,但它的存在会干扰编译器对内部表达式的合法性检查——本该因临时对象指针比较报错的代码,被编译器违规放过了。未定义行为导致错误的返回值
编译器跳过检查后,编译期对x && y的求值出现错误(被错误判定为false),触发assert。在constexpr上下文里,assert失败本该导致常量表达式求值失败、编译报错,但受__builtin_expect干扰,编译器没有正确处理这个错误,进而产生未定义行为,最终让result被错误初始化为0。移除__builtin_expect后的报错才是符合标准的
去掉这个扩展后,GCC严格按照C++标准检查constexpr代码,发现临时对象指针比较的非法操作,因此给出正确的编译错误,这是符合标准要求的行为。
内容的提问来源于stack exchange,提问作者Lukas Vozenilek

