3

gcc および IBM xlc (AIX 用バージョン 10.1) コンパイラーでコンパイルする必要がある C++ コードを生成するドメイン固有言語を作成しています。

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", line 21.66: 1540-0114 (S) パラメータ名は、この関数の別のパラメータと同じであってはなりません。

しかし、次のようにコンストラクター呼び出しで囲み括弧を削除すると:

someClass nuni = someClass(otherClass(weco), otherClass(weco));

エラーはなくなります。また、コンストラクターを括弧で囲んでもエラーが消えるときにweco作成された別の extern 変数に変更するwecoと、このエラーが表示されるには両方の条件が存在する必要があると言っても過言ではありません。

なぜ括弧を削除しないのかと尋ねる人もいるかもしれませんが、削除すると正しく動作しているコードの一部が損なわれる可能性があるため、この動作が C++ コンパイラで想定されているかどうかを理解したいと思っています。少なくとも、既知の回避策があります。

4

1 に答える 1

2

と思います

(someClass(otherClass(weco), otherClass(weco)))

キャスト式の 2 番目の生成の開始として誤って解析されています:

キャスト式:
 単項式
 
(type-id)キャスト式

注 § 8.2 パラグラフ 2 (強調を追加):

関数スタイルのキャストと型 IDの類似性から生じるあいまいさは、さまざまなコンテキストで発生する可能性があります。あいまいさは、関数スタイルのキャスト式と型の宣言の間の選択として現れます。解決策は、構文コンテキストでtype-idになる可能性のある構成は、 type- idと見なされることです。

cast-expressionのtype-idの完全な構文コンテキストを考慮すると、inがmatch に一致することはありません。これは、に続くcast-expressionを空にすることはできないためです。ただし、type-idの後に が続く必要がある 1 トークン先読みコンテキストのみを考慮する場合、8.2(2) が適用される可能性があります。ただし、標準の意図が 1 トークンの先読みのみを考慮することであったとは、あまり信じたくありません。...(..);type-id))

編集 gcc バグ50637として報告されました。同様のバグ レポートを xlc に送信することもできます。

gcc 4.7.2 は xlc と同じエラーにフラグを立てているようです。私は gcc を少しいじり、括弧で囲まれた式が type-id ではないことを認識する前に、gcc が type-id のエラー (つまり、同じ名前の 2 つのパラメーター) にフラグ立てることが問題であると確信しました。

次に例を示します。

#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 つを次に示します。

1) weco のエイリアスを追加します。

emptyList& weco_alias = weco;

2) それぞれの 1 つを使用します。

someClass nuni = (someClass(otherClass(weco), otherClass(weco_alias)));

これは gcc 4.7.2 と clang 3.2 ( lws ) の両方で動作します。

于 2013-01-18T18:04:51.933 に答える