如果 constexpr 在 lambda 内部,在 pack expansion 中 - 编译器bug?

7
clang version 5.0.0 (trunk 305664)
Target: x86_64-unknown-linux-gnu

以下代码已经成功编译:
template <int... A>
void f() {
    ([](auto) {
        if constexpr (A == 0)
            return 42;
        else
            return 3.14;
    }(0), ...);
}

int main() {
    f<0, 1>();
}

……但是这个例子却没有:

template <int... A>
void f() {
    ([](auto...) {            // Variadic lambda
        if constexpr (A == 0)
            return 42;
        else
            return 3.14;
    }(), ...);                // No argument
}

int main() {
    f<0, 1>();
}

...产生:

<source>:7:13: error: 'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement
            return 3.14;
            ^
<source>:3:6: note: in instantiation of function template specialization 'f()::(anonymous class)::operator()<>' requested here
    ([](auto...) {            // Variadic lambda
     ^
<source>:12:5: note: in instantiation of function template specialization 'f<0, 1>' requested here
    f<0, 1>();
    ^

我不会期望一个空的参数包和一个虚拟(dummy)参数之间有不同的行为。

这种差异有原因吗?还是这是编译器的错误?


谁说 if constexpr 的条件必须是依赖的? - aschepler
为什么不展示完整的代码?我们无法看到错误信息所指的内容。 - Brian Bi
@Brian 已修复,我为了简洁起见删除了相同的 main 函数。 - Quentin
@aschepler 我的记忆好像有点混乱。我可能把它与涉及两阶段查找的其他内容混淆了。 - Quentin
1个回答

3
我认为这是clang的一个bug。
[dcl.spec.auto]中的规则如下,重点在于:
如果函数的声明返回类型包含占位符类型,则函数的返回类型将从函数体([stmt.if])中未被丢弃的任何return语句中推断出来。
如果具有包含占位符类型的声明返回类型的函数有多个未被丢弃的return语句,则对于每个此类return语句都会推导出返回类型。如果每次推导的类型不同,则程序不合法。 lambda表达式中的其中一个return语句被丢弃了(在if constexpr中未被采取的分支称为“已丢弃语句”),这样只剩下一个未被丢弃的return语句,因此lambda的返回类型应该仅从剩下的那个语句中推导出来。
此外,clang只需要这么做:
template <int A>
void f() {
    [](auto...) {
        if constexpr (A == 0)
            return 42;
        else
            return 3.14;
    }();
}

int main() {  
    f<0>();
    f<1>();
}

所以,这可能是与lambda在包表达式中的工作方式产生了一些不良交互。

好的。如果我想报告这个 bug,该怎么办?我只找到了关于后端崩溃 bug 的信息... - Quentin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接