5

ソース(質問の最後)は、Solaris Studio(他のコンパイラではなく)でのマングリングエラーであると私が信じているものを引き起こします。

わかりやすくするために、エラー メッセージは新しい行で再フォーマットされました。

"overload.cpp", line 44: Error:
runGenEntries<std::vector<int>>(const GenEntryRuleDriven<int>&, const std::vector<int>&)
and
runGenEntries<std::vector<int>>(const GenEntryRulesDriven<int>&, const std::vector<int>&)
have same extern name
"__1cNrunGenEntries4nDstdGvector4Cin0AJallocator4Ci_____6FrkTArk1_v_".
1 Error(s) detected.

2 つの関数 runGenEntries の最初のパラメーターが 1 文字 (Rule の末尾の「s」) だけ異なることに注意してください。

これは、最初のパラメーターのタイプが次の場合に発生するようです。

const typename GenEntryRulesDrivenType<typename InputsType::value_type>::type

また、最初のパラメーターがタイプの代わりにある場合は発生しません:

const typename GenEntryRulesDriven<typename InputsType::value_type>

最終的に同じタイプに解決されます。

これは、Solaris だけに実装されているあいまいな C++ ルールの結果ですか? それとも、シンボルをマングルするときの Solaris Studio のバグですか?

完全なソース

次のソースは、どのコンパイラでもそのままコンパイルできます。

定義は、エラーを引き起こすコードをアクティブにするか、同じ結果を生成するはずのコードをアクティブにします (ただし、今回はバグなし):

#include <iostream>
#include <vector>

template<typename T>
struct GenEntryRulesDriven
{
   void foo() const
   {
   }
};

template<typename T>
struct GenEntryRuleDriven
{
   void bar() const
   {
   }
   std::string toto; // to have a different size than GenEntryRulesDriven
};


template <typename T>
struct GenEntryRulesDrivenType
{
   typedef GenEntryRulesDriven<T> type;
};

template <typename T>
struct GenEntryRuleDrivenType
{
   typedef GenEntryRuleDriven<T> type;
};

#if 1 // Gives an error

template <typename InputsType>
void runGenEntries(const typename GenEntryRulesDrivenType<
                          typename InputsType::value_type>::type &genEntry,
                          const InputsType& inputs)
{
   genEntry.foo();
}

template <typename InputsType>
void runGenEntries(const typename GenEntryRuleDrivenType<
                          typename InputsType::value_type>::type &genEntry,
                          const InputsType& inputs)
{
   genEntry.bar();
}

#else // No error but same types as above!

template <typename InputsType>
void runGenEntries(const typename GenEntryRulesDriven<
                          typename InputsType::value_type> &genEntry,
                          const InputsType& inputs)
{
   genEntry.foo();
}

template <typename InputsType>
void runGenEntries(const typename GenEntryRuleDriven<
                          typename InputsType::value_type> &genEntry,
                          const InputsType& inputs)
{
   genEntry.bar();
}

#endif

int
main()
{
   std::vector<int> v;
   GenEntryRulesDriven<int> rulesDriven;
   runGenEntries(rulesDriven, v);

   GenEntryRuleDriven<int> ruleDriven;
   runGenEntries(ruleDriven, v);

   return 0;
}

このコードは、次のプラットフォームでコンパイルされました。

bash$ uname -a
SunOS pegasus 5.10 Generic_118855-33 i86pc i386 i86pc
bash$ CC -V
CC: Sun C++ 5.10 SunOS_i386 128229-07 2010/03/24
4

1 に答える 1

3

簡潔な答え

簡単な回答: これは「修正不可能な」バグ 6532605 のようです (多数の Google 検索で参照されていますが、https://support.oracle.com/rs?type=bug&id=6532605でバグ自体を開くことはできません)。

Qt 開発者が行う回避策は、メソッド定義を別のコンパイル ユニット (.cpp ファイル) に入れることです。

バックグラウンド

CC が文句を言っているシンボル名をデマングルすると、最初の引数として const __type_0& 引数をコンパイルしていることがわかります。

$ echo __1cNrunGenEntries4nDstdGvector4Cin0AJallocator4Ci_____6FrkTArk1_v_ | c++filt
void runGenEntries<std::vector<int> >(const __type_0&,const __type_0&)
$

まったく同じ Solaris 10 ボックスで g++ 3.4.6 を使用すると、ブロック 1 のシンボルは次のように分解されます。

runGenEntries<std, vector<int, std::allocator,<int>void> >(const GenEntryRuleDrivenType<int::value_type>::type(const GenEntryRuleDrivenType<int::value_type>&)&)
runGenEntries<std, vector<int, std::allocator,<int>void> >(const GenEntryRulesDrivenType<int::value_type>::type(const GenEntryRulesDrivenType<int::value_type>&)&)

オラクルが同じことを達成できない理由は、私にはわかりません。

Qt の回避策

このバグ/回避策が参照されている Qt コードはこちらです。

同様の名前で宣言された 2 つの関数があることがわかります。

Expression::Ptr DocFN::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType);
Expression::Ptr IdFN::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType);

そして、バグを回避するために、それぞれが独自のソース (ここここ) でコンパイルされます。

サポートされていない解決策: ccfe のマングリング オプションを変更してください

ここから、 でコンパイルすることもできます-Qoption ccfe -abiopt=mangle6。これらのフラグを使用すると、コードは正常にコンパイルされ、シンボル (デマングル) は次のようになります。

void runGenEntries<std::vector<int> >(const GenEntryRuleDrivenType<__type_0::value_type>::type&,const __type_0&)
void runGenEntries<std::vector<int> >(const GenEntryRulesDrivenType<__type_0::value_type>::type&,const __type_0&)

問題は、Steve Clamage が書いたように、このコンパイル オプションがサポートされていないことです。

最後に、コンパイラには、すべての既知のマングリング バグを無条件に修正する隠しオプションがあります。このオプションは公開していません。

  • 不安定です。さらにバグが見つかった場合、将来のパッチまたはリリースでマングリングが変更される可能性があります。
  • このオプションを使用して、サードパーティ ライブラリを含むすべての C++ コードを再コンパイルする必要がある場合があります。
  • このオプションを使用してライブラリを作成すると、オプションを使用せずにコンパイルされたコードと互換性がなくなる可能性があります。
  • すべての非表示オプションと同様に、予告なしに変更または削除される場合があります。
  • 私たちはこのオプションを「自己責任で使用する」と考えています。

これらすべての警告の後、オプションを試してみたい場合は、次のとおりです。

-Qoption ccfe -abiopt=mangle6

必ずすべての CC コマンドに追加して、すべてを再コンパイルしてください。

幸いなことに、Solaris または Studio に同梱されている C++ システム ライブラリは、このバグや隠しオプションの影響を受けないため、これらのライブラリのバージョンが異なることを心配する必要はありません。

于 2014-06-19T14:12:20.647 に答える