c++ - 为什么未诊断出在 constexpr 上下文中使用保留的标识符名称?

标签 c++ language-lawyer undefined-behavior

基于以下两条规则:

  • 使用以“_”+大写字母开头或包含双下划线的标识符是未定义的行为。
  • constexpr 表达式中不允许出现未定义的行为 -> 编译器不应编译。

那为什么编译器不提示这个呢?

constexpr int _UB() {return 1;}
int main() {
    constexpr int a = _UB();
    return a;
}

Demo

另外,我看到很多专业的、符合 MISRA 标准的代码似乎违反了这个命名规则,例如参见here :

#ifndef __STM32F732xx_H
#define __STM32F732xx_H

所有这些库是否也调用 UB?

最佳答案

Undefined behavior is not allowed in constexpr expressions -> compiler should not compile

比这更窄一点;根据 [expr.const]/5 , /5.7特别是:

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

  • [...]
  • /5.7 an operation that would have undefined behavior as specified in [intro] through [cpp];

现在,[intro] 通过 [cpp] 包括:

1 Scope[intro.scope]
2 Normative references[intro.refs]
3 Terms and definitions[intro.defs]
4 General principles[intro]
5 Lexical conventions[lex]
6 Basics[basic]
7 Expressions[expr]
8 Statements[stmt.stmt]
9 Declarations[dcl.dcl]
10 Modules[module]
11 Classes[class]
12 Overloading[over]
13 Templates[temp]
14 Exception handling[except]
15 Preprocessing directives[cpp]

然而,关于全局名称下划线的规则来自 [library],特别是 [reserved.names]/2[global.names]/1在 [library] 中,它不在“[intro] through [cpp]” 中。

[reserved.names]/2 If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.

[global.names]/1 Certain sets of names and function signatures are always reserved to the implementation:

  • (1.1) Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter ([lex.key]) is reserved to the implementation for any use.
  • (1.2) Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

现在,[lex.name]/3还包括相同的标识符保留规则

In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.

  • (3.1) Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
  • (3.2) Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

违反 [lex.name]/3 是格式错误的,不需要诊断(IFNDR),这与未定义的行为不同;根据上面的 [expr.const]/5.7,一些 UB 应该实际上被诊断出来(constexpr 上下文)。

根据 [intro] 到 [cpp] [expr.const]/5.7 对 UB 的限制可以说是有意限制规则以避免构造对于典型的 C++ 实现者来说是 UB 而不是 STL 库实现者,例如[库]中的规则。这也可能是一个措辞缺陷,特别是当 [lex.name]/3 的规则仅在 [library] 中 [reserved.names]/2 的“事实之后”从 IFNDR 变为 UB 时。

因此,这种“种类”的未定义行为 (UB) 可以说不属于使表达式无法成为核心常量表达式的 UB。

关于c++ - 为什么未诊断出在 constexpr 上下文中使用保留的标识符名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70244992/

相关文章:

c - 如果未初始化变量的值不应该影响表达式的值,它仍然是 UB 吗?

c++ - QThread 中的槽和信号

c++ - 我们可以使用数组的最后一个元素吗?

c++ - 标准的意图是任何形式的 `nested-type-specifier followed by an identifier` 都可以称为合格 ID

c++ - 为什么忽略返回类型 'cv'?

c++ - 在 C 和 C++ 中,使用逗号运算符(如 "a = b,++a;")的表达式是否未定义?

c++ - 使用 C++ 将 HTML 转换为 XML

c++ - 输出以空格开头

c++ - 如何指定指向参数数量未知的 C 函数的 C++ 指针?

c - 在无法到达的路径上具有未定义行为的程序的行为是否已定义?