Мы создаем предметно-ориентированный язык, который генерирует код C ++, который должен компилироваться в gcc, а также в компиляторах IBM xlc (версия 10.1 для AIX).
Один специфический фрагмент кода сгенерировал код 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
для другой переменной extern, созданной так же, как weco
ошибка исчезнет, даже если я заключу конструктор в круглые скобки, поэтому можно с уверенностью сказать, что для появления этой ошибки должны присутствовать оба условия.
Некоторые из вас могут спросить, почему бы нам тогда не убрать круглые скобки? может повреждать части кода, которые работают правильно, поэтому я склонен понимать, ожидается ли это поведение от компилятора C ++ или нет, или, по крайней мере, есть известный обходной путь для этого.
я думаю что
(someClass(otherClass(weco), otherClass(weco)))
неправильно анализируется как начало второго производства монолитно-выражение:
монолитно-выражение:
Унарное выражение
(
тип-идентификатор)
монолитно-выражение
Примечание § 8.2, параграф 2 (выделение добавлено):
Неоднозначность, возникающая из-за сходства между исполнением стиля функции и тип-идентификатор может происходить в разных контекстах. Неоднозначность проявляется в виде выбора между приведенным выражением в стиле функции и объявлением типа. Резолюция в том, что любая конструкция, которая может быть тип-идентификатор в его синтаксическом контексте считается тип-идентификатор.
Если вы считаете полный синтаксический контекст тип-идентификатор в монолитно-выражение, это невозможно для ...
в (..);
соответствовать type-id
, поскольку монолитно-выражение следуя )
не может быть пустым. Однако, если вы рассматриваете только контекст с одним токеном, где тип-идентификатор должно сопровождаться )
, вполне вероятно, что применимо 8.2 (2). Однако я не склонен полагать, что цель стандарта заключалась в том, чтобы рассмотреть только один прогноз.
РЕДАКТИРОВАТЬ
Отмечено как ошибка gcc 50637. Возможно, вы захотите отправить аналогичный отчет об ошибке в xlc.
Поскольку gcc 4.7.2, кажется, отмечает ту же ошибку, что и xlc. Я немного поигрался с gcc и убедил себя, что проблема в том, что gcc помечает ошибку в тип-идентификатор (то есть два параметра с одинаковым именем), прежде чем выяснить, что заключенное в скобки выражение не может быть тип-идентификатор.
Вот пример:
#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;
}
Видеть это на 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).
Других решений пока нет …