ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
![]() |
Oracle Solaris Studio 12.3 リリースの新機能 Oracle Solaris Studio 12.3 Information Library (日本語) |
ここでは、このリリースでのコンパイラに関する既知の問題および回避策について説明します。
発行済みコンパイラドキュメントに含まれる誤りを、次に列挙します。
cc(1)、CC(1)、および f95(1) のマニュアルページに、3dnow などの AMD 命令セットを SSE3 命令セットに追加する —xarch=sse3a フラグを記載し忘れています。
C と C++ のドキュメントで、—xMF オプションと併用できるのは —xMD または —xMMD だけであり、—xM や —xM1 は併用できない点を指摘し忘れてします。これを指定すると、これらのオプションで使用されているデフォルトの .d ファイルの名前が上書きされます。
Solaris 10u10 以前、および初期リリースの Solaris 11 にインストールされた Apache stdcxx ライブラリでは、ヘッダー stdcxx4/loc/_moneypunct.h で構文エラーが発生します。このエラーは、以前のコンパイラでは見られなかったものですが、Oracle Solaris Studio 12.3 C++ コンパイラでは検出されます。このエラー検出を無効にする方法はありません。
このバグの修正は、Solaris 10 のパッチ、および最初の Solaris 11 SRU として入手できます。修正が使用可能になった時点で、その修正は Solaris 10u11 と Solaris 11u1 に含められます。
C++ では、あるときは宣言と解釈されたり、またあるときは式と解釈される可能性がある文があります。C++ のあいまい排除規則では、ある文を宣言文とみなすことができる場合は、その文は宣言文とすることになっています。
従来のバージョンのコンパイラでは、次のような事例を誤って解釈していました。
struct S { S(); }; struct T { T( const S& ); }; T v( S() ); // ???
このプログラマはおそらく、最後の行で S 型の一時的な値で初期化される変数 v を定義するつもりでした。従来のバージョンのコンパイラは、この文をそのように解釈していました。
しかし、宣言コンテキスト内のコンストラクト、"S()" は、"S 型の値を戻すパラメータのない関数" を意味する抽象宣言子 (識別子のない抽象宣言子) とみなすこともできます。この事例では、関数ポインタ、"S(*)()" に自動的に変換されています。この文はまた、戻り値が T 型で、パラメータが関数ポインタ型の関数 v の宣言としても有効です。
現在ではコンパイラが正しい解釈をするようになったので、このプログラマが意図したようにならない可能性があります。
あいまいにならないようにコードを修正するには、次の 2 通りの方法があります。
T v1( (S()) ); // v1 is an initialized object T v2( S(*)() ); // v2 is a function
1 行目の 1 対の余分な括弧は、v1 の構文が関数宣言としては不正であるので、"S 型の一時的な値で初期化される T 型のオブジェクト" という意味にしか解釈できません。
同様に、コンストラクト "S(*)()" は値とは考えられないので、関数宣言の意味にしか解釈できません。
1 行目は次のように記述することもできます。
T v1 = S();
意味は完全に明確になりますが、この初期設定の形式では、通常はそうでもないとはいえ、一時的な値として非常に大きな値が生成されることがあります。
次のようにコーディングするのはお勧めできません。その理由は、意味が不明確で、コンパイラが異なると結果が異なる可能性があるからです。
T v( S() ); // 推奨しない
テンプレートオプションの -instances=static (または -pto) を -xcrossfile や -xipo オプションと組み合わせると、機能しません。この組み合わせを使用したプログラムは、リンクに失敗することがよくあります。
-xcrossfile または -xipo オプションを使用する場合は、デフォルトのテンプレートコンパイルモデルの -instances=global を使用してください。
一般に、-instances=static (および -pto) は使わないでください。使うメリットはすでになく、依然として、『C++ ユーザーズガイド』で説明しているデメリットがあります。
次の場合に、リンク時に問題が発生することがあります。
const パラメータ付きで宣言されている関数が、別の場所で const パラメータなしで宣言されている。
例:
void foo1(const int); void foo1(int);
これらの宣言は等価ですが、コンパイラは異なる符号化名を付けます。この問題を回避するには、値のパラメータを const として宣言しないでください。たとえば、関数定義の本体などのあらゆる場所で void foo1(int); を使用します。
関数に同じ複合型のパラメータが 2 つあり、一方のパラメータだけ typedef で宣言されている。
例:
class T; typedef T x; // foo2 has composite (that is, pointer or array) // parameter types void foo2(T*, T*); void foo2(T*, x*); void foo2(x*, T*); void foo2(x*, x*);
すべての foo2 宣言は等価で、これらは同じものを符号化する必要があります。しかし、コンパイラは一部に異なった符号化を行なっています。この問題を回避するには、一貫して typedef を使用します。
typedef を一貫して使用できない場合は、回避策として、関数を定義しているファイルに weak シンボルを使用し、宣言とその定義を等価にします。例:
#pragma weak "__1_undefined_name" = "__1_defined_name"
ターゲットアーキテクチャーによって異なる符号化名があります。たとえば、size_t は SPARC V9 アーキテクチャー (m64) では unsigned long ですが、それ以外のアーキテクチャーでは unsigned int です。これは、2 つの異なったバージョンの符号化名がそれぞれ 1 つのモデルに存在するケースです。このような場合は、2 つのプラグマを用意し、適切な #if 指令で制御する必要があります。
プログラムでテンプレートと静的オブジェクトを使用していると、-instances=extern を指定してコンパイルした場合に未定義シンボルのリンク時エラーが発生します。これは、デフォルト設定の -instances=global では問題になりません。コンパイラは、大域的でない名前空間スコープのオブジェクトに対するテンプレートからの参照をサポートしません。次の例を考えてみましょう。
static int k; template<class T> class C { T foo(T t) { ... k ... } };
この例では、テンプレートクラスのメンバーは静的な名前空間スコープ変数を参照します。名前空間スコープはファイルスコープを含むことに注意してください。コンパイラは、静的な名前空間スコープ変数を参照するテンプレートクラスのメンバーをサポートしません。複数のコンパイル単位からテンプレートがインスタンス化されると、各インスタンスは異なる k を参照します。つまり、C++ 単一定義規則違反が発生し、コードは定義されていない動作を起こします。
k の使用方法やその効果に応じて、次の代替案が考えられます。2 番目のオプションは、クラスのメンバーの関数テンプレートにのみ使用できます。
変数に外部リンケージを持たせる
int k; // not static
すべてのインスタンスは、k の同じコピーを使用します。
変数をクラスの静的メンバーにする
template<class T> class C { static int k; T foo(T t) { ... k ... } };
静的なクラスメンバーは外部リンケージを持ちます。C<T>::foo のインスタンスが使用する k はそれぞれ異なります。C<T>::k のインスタンスは、ほかの関数で共有することができます。通常はこのオプションが使用されます。
名前空間内で #pragma align を使用する場合は、符号化名を使用する必要があります。たとえば、次のコードでは、#pragma align 文は何の働きもしません。この問題を解決するには、#pragma align 文の a、b、および c を符号化された名前に変更します。
namespace foo { #pragma align 8 (a, b, c) // has no effect //use mangled names: #pragma align 8 (__1cDfooBa_, __1cDfooBb_, __1cDfooBc_) static char a; static char b; static char c; }
このリリースの f95 コンパイラでは、次の問題に注意する必要があります。
前進なし印刷行の末尾の前にある空白が、出力の位置に影響を与えない (7087522)。
出力文の書式の末尾に X 編集記述子を指定しても、出力レコード内の次の文字の位置がその影響を受けません。これによって違いが生まれるのは、出力文に ADVANCE='NO' が含まれていて、かつ後続の出力文によって同じレコードに転送される文字がほかに存在している場合です。
多くの場合、これを回避するには、nX 編集記述子の代わりに空文字列編集記述子を使用します。これらは厳密には同じではありませんが、それは、空文字列編集記述子の場合は実際に空文字がレコード内に挿入されるのに対し、nX では次の n 個の文字がスキップされるだけであり、それによって通常は、それらのスキップされた位置がデフォルトで空になるからです。
2 つの継続アンパサンドから成る行が存在していると、有効なコードが拒否される。(7035243)。
単一のアンパサンドを含む空の継続行は、Fortran 規格で禁止されています。しかし、同じ行に 2 つのアンパサンドが含まれていると、規格の制限の対象から外れ、空の継続行を引き続き作成できます。コンパイラではそのような場合は処理されず、エラーが発生します。回避方法は、その行を削除することであり、それを行っても、プログラムの可読性に影響があるだけであり、意味が付加されることは一切ありません。
BOZ 定数が切り捨てられることがある (6944225)。
配列構成のように比較的複雑な一部のシナリオでは、BOZ 定数が、その代入先となると思われる対応する項目が 8 バイト整数エンティティーであっても、デフォルト整数サイズの 4 バイトに切り捨てられる可能性があります。回避方法は、BOZ 定数の代わりに正しい型と種別を持つ定数を、配列構成で使用することです。
以前のリリースの Fortran コンパイラで非互換性が導入されましたが、その非互換性はこのリリースのコンパイラにも引き継がれており、以前の Fortran コンパイラリリースからアップデートする際に注意する必要があります。互換性の問題とは次のとおりです。
ここでは、Oracle Solaris Studio 12.2 リリースで廃止対象の FORTRAN 77 ライブラリが削除されたことに注意してください。これは、レガシー Sun WorkShop f77 コンパイラでコンパイルされた、共有ライブラリ libF77、libM77、および libFposix に依存する古い実行可能ファイルが動作しないことを意味しています。
配列組み込み関数の ANY、ALL、COUNT、MAXVAL、MINVAL、SUM、PRODUCT、DOT_PRODUCT、MATMUL は、各 SPARC プラットフォームアーキテクチャー用に高度に調整されています。このため、これらの関数は大域レジスタの %g2、%g3、%g4 をスクラッチレジスタとして利用します。
上記の配列組み込み関数を呼び出す場合に、これらのレジスタが一時記憶領域として利用できることを前提にしたユーザーコードを作成しないでください。これらのレジスタ内のデータは、配列組み込み関数を呼び出したときに上書きされます。
デバッガ dbx では、コンパイルに使用されたすべてのオブジェクトファイルが実行可能ファイルの中に含まれている必要があります。通常、ユーザーが追加の作業を実行しなくても、プログラムはこの要件を満たしています。例外となるのは、モジュールを含むアーカイブを使用している場合です。プログラムがモジュールを使用するが、モジュール内の手順または変数をいずれも参照しない場合は、結果として生じるオブジェクトファイルには、モジュール内で定義されるシンボルへの参照は含まれません。オブジェクトファイル内で定義されているシンボルへの参照がある場合のみ、リンカーはアーカイブから取得したオブジェクトファイルをリンクします。このような参照が存在しない場合は、オブジェクトファイルは実行可能ファイルに含められません。使用されたモジュールに関連するデバッグ情報を dbx が検索しようとする場合に、dbx は警告を生成します。デバッグ情報が見つからないシンボルに関する情報は提供できません。
この問題を回避するためには、-u リンカーオプションを使用します。このオプションは、1 つのシンボルをそのオプション引数として取ります。そのシンボルを未定義のリンカーシンボルのセットに追加し、問題を解決します。モジュールと関連付けられているリンカーシンボルは通常、小文字の文字列に下線が後続するモジュール名です。
たとえば、モジュール MODULE_1 を含むオブジェクトファイルをアーカイブから取り出すには、リンカーオプション -u module_1_ を指定します。f95 コマンドを使用してリンクを実行する場合、コマンド行で -Qoption ld -umodule_1_ を使用してください。
システムの省電力が有効になっている場合、AMD プロセッサのクロックレートを正確に取得するための信頼できる方法はありません。結果として、Linux プラットフォーム上で gethrtime(3F) (Fortran コンパイラの、Solaris gethrtime(3C) 関数の Linux 版) に基づく時間関数を使用して実際の時間を高精度で取得する場合、精度の高い値が得られるのは、AMD システムの省電力が無効になっている場合だけです。省電力機能を無効にするには、システムをリブートしなければいけない可能性があります。