我们正在创建一种特定于域的语言,该语言生成必须在gcc下编译的C ++代码以及IBM xlc(适用于AIX的10.1版)编译器。
一个特定的代码片段生成的C ++代码在gcc下运行得非常好,但在xlc下没有那么多。我已将代码修改为仍然触发编译错误的最小情况:
//bug183.h
class emptyList
{};
extern emptyList weco;
class otherClass
{
public:
otherClass();
otherClass(const int & p);
otherClass(const emptyList & e);
int geta() {return a;}
private:
int a;
};
class someClass
{
public:
someClass();
someClass(const someClass & other);
someClass(const otherClass & p1, const otherClass & p2);
void exportState();
private:
otherClass oc1;
otherClass oc2;
};
//bug183.cpp
#include "bug183.h"
#include <iostream>
emptyList weco = emptyList();
otherClass::otherClass() {a = 0;}
otherClass::otherClass(const int & p) {a = p;}
otherClass::otherClass(const emptyList & e) {a = 1000;}
someClass::someClass() {oc1 = otherClass(); oc2 = otherClass();}
someClass::someClass(const someClass & other) {oc1 = other.oc1; oc2 = other.oc2;}
someClass::someClass(const otherClass & p1, const otherClass & p2) {oc1 = p1; oc2 = p2;}
void someClass::exportState() {std::cout << oc1.geta() << " " << oc2.geta() << std::endl;}
int main()
{
someClass dudi;
dudi.exportState();
//this line triggers the error in xlc
someClass nuni = (someClass(otherClass(weco), otherClass(weco)));
nuni.exportState();
return 0;
}
编译它会导致引发以下错误: “bug183.cpp”,第21.66行:1540-0114(S)参数名称不能与此函数的另一个参数相同。
但是如果我删除构造函数调用中的括号括起来:
someClass nuni = someClass(otherClass(weco), otherClass(weco));
错误消失了。此外,如果我将weco
更改为另一个创建为weco
的外部变量,即使我将构造函数括在括号中,错误也会消失,因此可以肯定地说这两个条件都需要存在出现错误。
有些人可能会问为什么我们不删除括号,但这样做可能会损害部分正常工作的代码,所以我倾向于理解这种行为是否正确是否可以从C ++编译器开始,或者至少有一个已知的解决方法。
答案 0 :(得分:2)
我认为
(someClass(otherClass(weco), otherClass(weco)))
被错误地解析为 cast-expression 的第二次制作的开始:
铸表达:
一元表达式
(
type-id)
cast-expression
注意§8.2第2段(重点补充):
函数式转换和 type-id 之间的相似性引起的歧义可能发生在不同的上下文中。歧义似乎是函数式转换表达式和类型声明之间的选择。解决方案是在其语法上下文中可能是 type-id 的任何构造都应被视为 type-id 。
如果您考虑 cast-expression 中 type-id 的完整语法上下文,...
中的(..);
不可能匹配type-id
,因为)
后面的 cast-expression 不能为空。但是,如果您只考虑one-token-lookahead上下文,其中 type-id 必须跟)
,则8.2(2)适用可能是合理的。我并不是真的倾向于认为标准的意图只是考虑一个令牌前瞻。
修改强> 报告为gcc bug 50637。您可能希望向xlc提交类似的错误报告。
因为gcc 4.7.2似乎标记了与xlc相同的错误。我玩了一下gcc,并说服自己问题是gcc标记了 type-id 中的错误(即两个具有相同名称的参数),然后才发现括号表达式不能是 type-id 。
以下是一个例子:
#include <iostream>
#include <utility>
static const int zero = 0;
int main() {
// Consistent with 8.2[2]
// Example 1. Invalid cast.
// Here, 'int(int(zero))' is a type-id, so the compiler must take
// the expression to be a cast of '+3' to a function.
std::cout << (int(int(zero))) + 3 << std::endl;
// Example 2: No error.
// The parenthesized expression cannot be a type-id in this context
std::cout << (int(int(zero))) << std::endl;
// Example 3: Syntax error: zero redefined.
// Here the parenthesized expression could be a type-id, so it must
// be parsed as one, even though the type-id is invalid.
std::cout << (std::pair<int,int>(int(zero), int(zero))) + 3 << std::endl;
// Apparently not consistent with 8.2[2]
// Here the parenthesized expression can't be a type-id, as in example 2.
// However, the type-id triggers a syntax error, presumably before gcc
// figures out that it's not a cast-expression.
std::cout << (std::pair<int,int>(int(zero), int(zero))) << std::endl;
return 0;
}
见on lws。 (在gcc和clang之间切换以查看差异。)
基于上述分析,问题是过早触发类型错误,这是一个可能的解决方法:
1)为weco添加别名:
emptyList& weco_alias = weco;
2)使用其中一个:
someClass nuni = (someClass(otherClass(weco), otherClass(weco_alias)));
这适用于gcc 4.7.2和clang 3.2(lws)。