使用std::swap交换double变量触发g++ 11.2.0内部编译器错误排查求助
首先明确一点:你遇到的是g++的内部编译器错误(ICE),这不是你的代码语法错误,而是编译器自身在处理C20模块代码时出现的实现缺陷。g 11.x系列对C++20模块的支持还处于早期阶段,存在不少已知的兼容性问题,下面是一些可以尝试的排查和解决方向:
你的场景细节
相关代码片段
export module BoundingBox; import Vector3d; // ... (自定义文件) import <list>; import <string>; import <cassert>; import <numbers>; import <algorithm>; import <cstddef>; using std::swap; using std::iterator; using std::list; using std::string; using std::numbers::pi; export class BoundingBox { void test() { double a=1, b=2; std::swap(a,b); } };
编译错误信息
In file included from /usr/include/c++/11.2.0/bits/stl_pair.h:59,
from /usr/include/c++/11.2.0/bits/stl_algobase.h:64,
from /usr/include/c++/11.2.0/bits/char_traits.h:39,
from /usr/include/c++/11.2.0/string:40,
of module /usr/include/c++/11.2.0/string, imported at raytracer/BoundingBox.cpp:8:
/usr/include/c++/11.2.0/bits/move.h: In instantiation of ‘constexpr std::_Require<std::_not<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> > std::swap(_Tp&, _Tp&) [with _Tp = double; std::_Require<std::_not<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> > = void]’:
raytracer/BoundingBox.cpp:1503239:18: required from here
/usr/include/c++/11.2.0/bits/move.h:204:19: internal compiler error: in tsubst_copy, at cp/pt.c:16621
204 | _Tp __tmp = _GLIBCXX_MOVE(__a);
| ^~~~~~~~~~~~~
0xe4c988 internal_error(char const*, ...) ???:0
0xe42d02 fancy_abort(char const*, int, char const*) ???:0
0x1140ae0 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*, bool, bool) ???:0
...(后续栈跟踪省略)
使用的编译命令
# 预编译系统头文件为模块 g++ -c -fmodules-ts -x c++-system-header -std=c++20 iostream algorithm numbers string vector cmath list cassert fstream cstddef # 编译自定义模块 g++ -fmodules-ts -std=c++20 -lGL -lglut -c \ raytracer/Vector3d.cpp \ ... raytracer/BoundingBox.cpp
具体排查和解决步骤
先尝试绕过std::swap的调用
既然是std::swap(double, double)的实例化触发了编译器崩溃,你可以手动实现swap逻辑来临时绕过这个问题:void test() { double a=1, b=2; double tmp = std::move(a); a = std::move(b); b = std::move(tmp); }如果这样能编译通过,就可以确认是std::swap的模块实例化路径触发了编译器bug。
调整模块导入和using声明的方式
模块环境下的名字查找规则和传统头文件有差异,你可以尝试:- 注释掉
using std::swap;这一行,只保留std::swap(a,b)的显式调用,避免名字查找的冲突 - 调整系统模块的导入顺序,把
<algorithm>(std::swap的定义所在模块)移到其他系统模块的最前面,比如:import <algorithm>; import <list>; import <string>; import <cassert>; import <numbers>; import <cstddef>;
- 注释掉
升级编译器版本
g++ 11.2.0的C20模块支持非常不完善,后续的g 12、13版本修复了大量模块相关的bug。建议你升级到g++ 13或者最新的稳定版,这大概率能解决这个问题——毕竟ICE本身就是编译器的实现问题,新版本通常会修复这类问题。逐步简化代码定位触发点
虽然你没法生成最小复现示例,但可以在现有代码库中逐步排查:- 先注释掉BoundingBox模块中除了swap调用之外的所有代码,看错误是否还存在
- 逐步恢复其他代码(比如自定义类型、其他模块的导入),找到和swap调用交互触发错误的部分
- 检查代码库中是否有其他地方对
std::swap进行了特化或者重载,模块环境下这类操作可能导致名字查找的异常
内容的提问来源于stack exchange,提问作者Konrad Höffner

