Clang vs. GCC:通过合格/不合格的名称为全球职能提供帮助

Ste*_*Lin 15 c++ gcc clang language-lawyer

我正在试图弄清楚是否要提交针对Clang,GCC或两者的错误报告(我已经针对Clang主干和GCC 4.7.2进行了测试:如果有人可以对GCC主干进行验证,这会有所帮助):

基本上,以下代码三行文件-fsyntax-only在默认和C++ 11模式下编译良好:

class A {
    friend void f();
};
Run Code Online (Sandbox Code Playgroud)

请注意,之前没有声明f(),但这显然是可以的.

但是,Clang(但不是GCC)拒绝接受以下内容:

class A {
    friend void ::f();
};
Run Code Online (Sandbox Code Playgroud)

Clang的错误是"在指定的范围内找不到类型'void()'的函数'f',但我在标准中找不到任何理由来处理这种情况与前一种不同,所以我认为这是一个错误; 我可能错了(我正在阅读N3242,但是,AFAIK是C++ 11之前的最后一次公开选秀).

然而,下一个例子被GCC而不是Clang拒绝:

void f() { }

void g()
{
    class A {
        friend void ::f();
    };
}
Run Code Online (Sandbox Code Playgroud)

来自GCC的错误是"没有事先声明的本地类中的朋友声明'void f()'",这似乎没有意义,因为void ::f()应该引用f()声明的全局命名空间.(没关系 - friend来自本地班级的全局功能是荒谬的,它似乎并非违法......)

最后,最后一个例子被Clang和GCC拒绝:

void g()
{
    class A {
        friend void ::f();
    };
}
Run Code Online (Sandbox Code Playgroud)

错误是本地类中的"friend declaration'void f()',而没有事先声明"和"分别在指定的范围"中没有找到名为'f'且类型为'void()'的函数.现在,从11.4p11开始,似乎有一些理由拒绝在本地类中拒绝朋友对先前未声明函数的声明,但该段实际上是:

如果友元声明出现在本地类(9.8)中并且指定的名称是非限定名称,则会查找先前声明,而不考虑最内部封闭非类作用域之外的作用域.对于朋友函数声明,如果没有事先声明,该程序是不正确的...

本声明的非法性显然是基于本段的第二句,但我不清楚该句是否适用于具有合格名称的情况,如本案所用.(可以说,无论是否使用"非限定名称",整个段落都适用于"本地类",并且"和指定的名称是非限定名称"条款仅适用于所描述的查找在第一句中,但它似乎是一个延伸...我想象这是一种可能性的唯一原因是因为两个编译器都拒绝它.)

无论如何,据我所知,所有这四个案件(无论他们是否合理)都应该是合法的; 即使不是,Clang和GCC中至少有一个在第二和第三种情况下是错误的.任何人都可以在我的逻辑中发现错误吗?

第三和第四个案件无疑是荒谬的; 但我可以看到第二个案例打破某人的有效和有用的代码,所以我有点惊讶它从未被捕获过,如果它确实是一个错误.

asc*_*ler 4

我认为 8.3/1 中的这句话是相关的:

declarator-id被限定时,声明应引用该限定符所引用的类或命名空间的先前声明的成员(或者,在命名空间的情况下,引用该命名空间的内联命名空间集的元素(7.3 .1)) 或其专业化;该成员不应仅仅由declarator-id嵌套名称说明符指定的类或命名空间范围内的using 声明引入。

该段落讨论的是任何类型声明中的一般声明符。所以我认为示例2和4是错误的,clang是正确的,而gcc是错误的。

(如果全局声明是模板函数,示例 3 可能会变得更加现实。将全局函数模板或本地类的专业化作为友元可能会很有用。如果允许的话,您编写的示例 3 也可能是合法的一致性。)