原文
拉兹万
Razvan
从他最近在内联
中遇见的一个问题开始,他不知道如何解决.一般,当A模块
导入B模块
并从B调用函数
时,如果B的目标文件
没有传递给链接器
,则最终会出现链接器错误.
如,在命令行上使用A.d
编译并省略B.d
时.但是,当内联调用函数
时,则不会触发链接器错误
.他怀疑这是一个优化.
他发现该行为
,破坏了使用内联标志
的BetterC
构建.他解释说,内联
在语义3
后运行,但因为B
不是根模块,因此会完成一些额外语义工作
,然后最终会出现TypeInfo
错误.
他的第一反应
是,这是个侵改
,不应语义分析内联
.但是,如果更改
此设置,则可能会在其他地方
导致链接器错误
.
沃尔特说这是他第一次听说它.为什么不直接链接B模块
?或添加它为根文件
?为什么对BetterC
来说是一个特殊的问题?对前者,Razvan
说这是修复错误
的方法.
然后他问Walter
是否同意,不应语义分析内联
.沃尔特说他不知道,因为他没有调查
过.他不记得会语义分析内联
.
然后,Razvan
查询是否每个人都同意使用和不使用内联标志
编译应该产生相同结果.沃尔特说不一定.如果函数
是内联的,则无需链接
它.
要链接它,则必须按根模块
添加它.所以他不明白为什么这是一个问题,为什么这对BetterC
来说是一个特殊的问题.
Steve
说,必须语义分析内联代码
.因此,他问Razvan
是否在谈论一些其他语义分析,比如分析未使用代码
.
Razvan
解释说,他谈论的是,当导入
模块不是根模块
时,内联
必须分析
内联代码.
Martin
提到了一些LDC
链接器标志,这些标志需要对原本会在外部链接的事物额外的语义分析.他说,如果某个东西是根模块
,则都会对其分析,但是如果你只是编译模块A
,并且它决定内联另一个不需要语义分析的函数,则是的,他不确定自己是否明白这里的问题所在,但他可确认他们在几周前遇见了问题.他们遇见了与内联相关的链接器错误,但这与单独的编译无关.
他说这是以后的话题.
Walter
指出,如果B模块
中的内联函数
调用了B模块
中的其他函数
,则如果没有链接B
,你会看到链接器错误
.这就是问题吗,马丁说这不是他们说的问题.
它是一个包含所有代码
的单元测试
运行程序,因此不应有未定义
符号.
Walter
要求Razvan
澄清他看到了什么样的链接器错误
.Razvan
表示,这与BetterC
代码中的TypeInfo
生成有关.
最根本
问题是在不应该分析
语义时,分析了语义
,并生成TypeInfo
.如果用-betterC
编译,但不用-inline
,则不会看到错误,但如果同时使用两者
编译,则会看到错误.
Walter
说,好吧,这是一个TypeInfo
问题.为了弄清楚这一点,他必须跟踪代码,以了解此时为什么在B模块
中生成TypeInfo
.他想不出一个理由.
Razvan
建议另一个解决方法是,仅从根模块
中内联函数
.沃尔特说这不行.你无法拥有好头文件库.他说,正确解决方法是,确定为什么,在不应生成TypeInfo
时生成它.
Martin
表示,LDC
在TypeInfo
上没有这类问题,因为它对它们有不同的发射策略
.他建议DMD
采取同样的路线
.对类,总是在包含类声明的模块
中生成TypeInfo
.
据他所知,这与DMD
相同.只在结构不同
.添加到结构中的特殊TypeInfo
成员都发出到包含结构的目标文件中,但实际的TypeInfo
在访问时会延迟发出,但会从codegen
层发出.
因此,他们避免了CTFE
需要TypeInfo
的所有麻烦,因为它在每个需要它的模块
中都是懒生成的,它会在运行时执行实际代码
中访问它.
可在代码生成
层,而不在语义分析
阶段,推导实例化.
Steve
理解,如果带BetterC
且没有-inline
链接,调用需要TypeInfo
的函数,则表明因为需要TypeInfo
,被调
函数并不是真正的BetterC
.
Dennis
认为,想在库
中,调用仅CTFE
函数时,就会这样,如,调用仅在CTFE
中用GC
的Phobos
函数,并内联插入Phobos
代码到BetterC
代码中.
他说,本质上,BetterC
是一堆黑客,而前端内联
则有点黑客
,长远看,它们都应该消失.Steve
总结其为:当CTFE
函数使用运行时功能
时,BetterC
不能CTFE
,这是个长期存在
的问题.
Walter
问Razvan
是否存在Bugzilla
问题.沃尔特问公关
是否有效,拉兹万说没有.
更新:Bugzilla
问题和拉取请求都已关闭,因为该问题不再重现.
丹尼斯
Dennis
想知道DMD
中错误接口
的未来会怎样.他们一直在努力使用错误接收器
,这样就不仅是直接打印到控制台
,并且接口只是个printf
的薄包装器.
它出现了一些问题,且因为接口
太有限,试修复失败了.Walter
想要个简单
而不是复杂
的接口.
因此,丹尼斯想知道中间
可有位置:因为目标之一
是改进
错误消息.
沃尔特说他同意该目标.在他最近拉取请求
中,他一直不让错误消息
处理器提供多个接口
.并说明要简化诊断
错误消息打印机
.
他回忆说,他同意Iain
删除添加到错误接收器中的复杂性,但还没有开始.错误
接收器有两个目的:简化接口
,并使其可与DMD库
一起使用.
然后,库可提供自己的接口
来执行期望工作
.所以他想保持简单.DMD库
将很简单,因此可简单实现LSP
.
随后讨论了当前实现
问题,toChars
和toPrettyChars
的使用,关于截断和格式
等.一个重要观点
是,Walter
说,在消息
到达错误
接收器前,应该预先设置
好所有自定义格式
.
语法高亮
等,应该由错误
接收器调用
的事物来完成.但是,错误
接收器自身不应决定格式和高亮
.
结果是,Dennis
说会试新的toChars
方法,看看他能走多远.
亚当.
讨论微软
如何处理.NET
版本问题.他总结了下:
1,在11
月结束的,为期一年的发布周期
.
2,在2月份,开始第一次预览,三个月的准备阶段
.
3,共有七次
预览.
4,接着是两个
候选发布版本
.
路易斯
CTFE
整数溢出
路易斯首先提出了,Weka
在编译时遇见的一个问题:无法知道整数
是否会溢出.期望能对此发出警告
.他正在使用DMD库
和LDC
插件来开发linter
.
他想在linter
中对此
发出警告,但是无法勾挂
常目录.
Walter
说,检查整数溢出
的问题是,有时想要整数溢出
.路易斯同意并说,可以在真正
需要时忽略
它,但大多数
时候不想要这样.
他说,对编译器来说,或至少对编译时
,可像Clang
和GCC
那样清理
检查整数溢出
.运行时,可用GCC
和LLVM
支持的清理程序
.
他说他已就此开了个公关,丹尼斯告诉他这是已定义行为
.他同意这一点,但在某些用例
中,它并不受欢迎
.他明白沃尔特不喜欢警告
.
即使不会加进编译器
,他也想有个方法
查询是否毒化常量
,然后就可用linter
来处理.它与Razvan
在DMD库
上工作相吻合.
Walter
说,首先,有时确实需要整数溢出
.其次,在一堆不在源码
的位置上加
整数,如,在结构
成员偏移
上的加
.
并不清楚,是否应该检查
这些地方的整数溢出
.还没有解决
,很多整数溢出
问题.另一个
问题是它不适合DMD
的后端.
编译时
和运行时
的行为要一致.
路易斯说,如果DMD
可在编译时
完成,他们就可在运行时检查
它.最好,两者都可以.Martin
指出,Weka
已有了自己的编译器分支
.
沃尔特说,通过常数折叠
和运行时
会有不同行为.这不好,但如果Weka
对此感到满意,则可在他们的编译器分支中实现它.
他说Steven
已指出,可显式使用checkedint
.其中一些是在DMD
源中完成的.显式检查了容易溢出
的位置.
Timon
指出,CTFE
浮点行为与运行时
不同.沃尔特说,这是个难以解决
的已知问题.他做了个公关
来修复
它,但破坏
了很多东西,所以退缩了.
因此附带讨论了一些浮点差异
,如何明确指定实
按依赖实现,如果想要可移植性
,请使用双精
,Walter
说,可用自己的模拟器
替换所有浮点计算
,但它很慢.有时,只需要忍受
差异.
讨论又回到了易受影响的整数溢出
,这时应如何显式检查
,总是启用它的性能成本
等.路易斯指出LDC
有一个标志,可在运行时
启用溢出
检查.
Walter
建议应该也可在编译时
有个标志
来启用
它们,并认为这会是个好主意
.建议路易斯和马丁谈谈这件事.
推导属性漏洞
第二个
问题是,单独
编译时出现的推导属性
错误.有时候,它不正确.标准库
有问题时,他无法
解决它.
沃尔特说,这一般是由前向引用
问题引起
的.路易斯同意了,并说他试修复
它,但一直无法解决.沃尔特说丹尼斯
对此有一些想法.
他想交换默认值
.丹尼斯说他已试过了,但遇见了问题.查询
函数类型时,它要求知道
属性.
以后进一步讨论该问题.
AST
节点中的语义分析
接着,路易斯有个与DMD库
相关的主题.他说,他一直在为ldc
的lint
制定一些lint
规则.
他发现很多AST
方法在底层,都在搞语义
.如果有项目可把它们分开,那就太酷了.这是编译器大重构
的一部分.
Walter
说,他一直在慢慢努力,最小化AST
功能,提取不需要的非虚函数
.这很耗时,但也是前进方向
.
路易斯说,从LDClint
角度来看,主要问题是他们想查询AST
,但不想改变它.目前,某些查询(如在测试
是否存在@nogc
时),在未找到该属性
时,会跑语义
.
他不想在这些查询
函数中运行语义
.如果是前向引用
,只需告诉它.
他继续解释说,LDClint
使用的是LDC
的AST
,如果在语义和codegen
之间,如果改变了AST
,且有依赖未改变的东西,就会有未定义行为
.
阿蒂拉说,常
会对此有所帮助.路易斯同意了.但从重构
角度来看,语义
应该与查询
分开.如果在查询
,需要知道,它不变
.
阿蒂拉指出,这正是常
的目的.有人抱怨它太严格
了,但这就是它的重点.
Walter
说,分离功能
,以便在AST
中只有const
函数可用的想法非常好
.
史蒂文
Steve
首先指出,在D1
中,你可把int
数组字面转换为ubyte
来设置类型
,如cast(ubyte)[1,2,3,4]
.
他说Discord
中有人证明cast(ubyte)[10000,2,3,4]
同样,但10,000
最终变成了10,000
的ubyte
截断值.
他记得这只是个设置
类型的手段,而不是为了让你可丢弃
信息.他觉得这很奇怪,想知道是否应该解决它.
Walter
让他提交一个Bugzilla
问题,Steve
说应该有一个.
接着,他说他在编译时的关联数组
代码中,发现了一个重大缺陷,Dennis
已为他合并其到DMD
中.hashOf
函数的操作方式,与TypeInfo
上的toHash
不同.
会导致从它们中得到的哈希值
有时不同,导致运行时
的错误表示
.他说他有个解决方法.
最后,他提出了code-d
,这是由JanJurzitza(Webfreak)
维护的D的VSCode
扩展.史蒂夫说,工作
时很好,但是有很多奇怪
东西导致它坏了,这里.
除了code-d
之外,哪些是重要
的或关键
的D项目
这是需要解决
问题之一.
代码猫,小孩学习D编程
串插值
接着,他提出了串插值
,说已研究了很多年了.他说John
和Andrei
写了一个非常好的提案(YAIDIP)
这里,解决了他们在Symmetry
遇见的现实问题,可惜D语言
没变.
阿蒂拉说,问题是约翰和安德烈从未完成
过该提议.亚当说,实现
是有效的,在本可继续前进且富有成效,不应关心提案细节
.
阿蒂拉不知道有它的实现.他最后一次听说他们还在努力.Adam
说他已为从事的另一个DIP
编写了一个实现
,并撤回了它以支持YAIDIP
,但核心
是相同的.
阿蒂拉问实现
在哪.亚当说在某处DMD
公关中.
阿蒂拉
他发现有个导入std.file
的单行文件需要200
毫秒才能编译
,这太疯狂了.他要搞清楚
.
这只是导入
中的语义分析
.甚至没有生成
目标文件.同一台机器上,还试了仅使用#include<iostream>
的C++
编译,它耗时400
毫秒.
他说,比C++
快两倍是远远不够的.沃尔特同意了.
需要解决标准库
的循环导入
问题,但他并不是100%
相信这会大大缩短
这些构建时间.
史蒂夫想知道这是否与CTFE
不必要时的运行
有关.阿蒂拉说肯定
.就像有超过一百万
个静态foreach
.
需要一段时间,除了有个更好的CTFE
引擎外,你无能为力.但因为甚至没用导入文件
中的符号,不应花这么长时间.
Walter
指出,模板并不仅是通过导入
来分析语义
的.它们必须扩展.因此,std.file
中的某些内容正在扩展
模板.他怀疑与std.uni
等有关.
沃尔特
Walter
说,他一直在重构
前端来简化
它,使其更易理解和实现DMD即库
.
路易斯关于拥有const
的AST
函数想法是个好主意.
它在设法最小化
几个模块的依赖
.这样更易使用编译器
.他计划继续
这样做,路说,表达式
模块是DMD
中最大
文件之一.
沃尔特说,名单
上有它.他一直在考虑把它拆分
为两个文件
.
除此外,仍在不断修复
错误并稳定
语言.
会议结束时,Razvan
问是否还有补充的,Timon
说他最近参加了几次编程比赛
.注意到,他的D方法
一般是所有参赛者
中最简洁
的.
沃尔特
鼓励他在论坛
上写一两段关于它的文章
,并在其他地方
宣传它.