提问人:Jan Schultke 提问时间:9/22/2023 最后编辑:Jan Schultke 更新时间:9/23/2023 访问量:117
编译器是否需要诊断模板中的语言语法冲突?
Is the compiler required to diagnose violations of language syntax in templates?
问:
[temp.res.general] 中有一个让我感到困惑的例子:
template<class T> class X { // ... void g(T t) { +; // may be diagnosed even if X::g is not instantiated } };
“可能”一词表示允许编译器进行诊断,但是,它不是必需的。据我所知,是无效的C++语法。+;
+;
如果需要,证明它的措辞在哪里?如果不是,你能走多远?
void g(T t) {
+(()=/)(/)§(/)(/)/=)$§/%)=§(/&%=)§/(%)=§/%§; // diagnostic required?
}}}}}}}}}}}}}}}}}}}}; // diagnostic required?
}
似乎编译器必须匹配大括号才能知道语法错误是发生在模板内部还是外部。这就引出了另外两个问题:
- 语法错误是否只是一般的 IFNDR,而不仅仅是模板中的语法错误?
- 是否有任何措辞说必须进行大括号匹配?
澄清
通过“违反语言语法”组合标记,以违反语言语法规则的方式组合标记,因为标记序列无法形成 C++ 翻译单元。
+;
与 C++ 语法中的任何规则都不匹配,即使它直接或间接位于模板中,也可能需要对其进行诊断......是吗?
答:
2赞
Jan Schultke
9/22/2023
#1
是的,编译器需要诊断任何地方的语言语法冲突,而标准中的示例具有误导性。
+;
不是有效的陈述;因此{ +; }
不是有效的复合语句,也不是有效的函数体;因此void g() { +; }
不是有效的函数定义,也不是有效的成员声明;因此- 的定义不是有效的模板声明,也不是 TU 声明序列的元素;因此
X
- 整个翻译单元无效
正如你所看到的,违反语言语法不可避免地会在语法中“冒泡”,这也意味着任何包含的模板首先都不是模板。 如果没有包含模板,甚至没有有效的翻译单元,则需要进行诊断,因为语法冲突属于可诊断规则的范畴。
除非明确说明“无需诊断”,否则以下情况适用:
[...]如果程序包含违反任何可诊断规则的内容,或者当实现不支持该构造时出现本文档中描述为“有条件支持”的构造,则符合要求的实现应发出至少一条诊断消息。
- [intro.compliance.general] 第 2.3 页
总之,这个例子具有误导性。
改进它的一种可能方法是使用“必须诊断”而不是“可能诊断”。+;
注意:我已经提交了一个编辑拉取请求,修复了这个措辞。
评论
1赞
Language Lawyer
9/22/2023
嗯。在 中,语法上 是 什么?我认为它应该是 id-expression,但“标识符只是一个 id-expression,如果它已被适当声明”,我们还不知道这一点。template<typename T> void f(T x) { g(x); }
g
0赞
Jan Schultke
9/22/2023
@LanguageLawyer 是 id-expression,周围的函数调用是一个后缀表达式,左侧有另一个 id-expression。id-expression 可以是 unqualified-id,因此可以是标识符。如果是在程序中的某个位置声明的函数,则假定标识符已适当声明。适当声明可能适用于当前 TU 中的某个地方。x
g
1赞
Language Lawyer
9/22/2023
但是,如果不声明,则为语法错误,应进行诊断?
0赞
Jan Schultke
9/22/2023
这个规则有点奇怪,因为它是对声明函数的调用,要么是对仅通过 ADL 找到的函数的调用。后一种情况意味着需要分析整个程序,包括其他 TU,以确定这是一个后缀表达式。这似乎是一个缺陷。g(x)
g
g(x)
0赞
Jan Schultke
9/22/2023
或者坚持,如果是一个类型,它可以是一个函数样式的强制转换,如果是一个表达式,它可以是一个函数调用。无论哪种方式,语法都是有效的。我想这意味着在模板实例化之前,编译器不需要诊断哪些情况适用。我怀疑标准中有一条规则明确指出,为了解决歧义,某些解析会延迟。g(x)
g
g
评论