...

aC++ の標準準拠と互換性のための変更点

by user

on
Category: Documents
32

views

Report

Comments

Transcript

aC++ の標準準拠と互換性のための変更点
aC++ の標準準拠と互換性のための変更点
White paper
目次
概要................................................................................................................................................... 3
ISO C++ 標準への準拠 (ISO)................................................................................................................ 3
ISO-1
テンプレートと見なされないテンプレート フレンド (3301) ........................................................ 3
ISO-2
曖昧なオーバーロードの拒否 (2308).................................................................................. 4
ISO-3
関数配列には typedef が必要 (2088) ................................................................................ 4
ISO-4
キーワード template の不適切な使用 (3139-D).................................................................... 4
ISO-5
テンプレートによる非公開メンバへの不適切なアクセス (2265-D)............................................. 5
ISO-6
定数メンバには初期化が必要 (2366-D) .............................................................................. 5
ISO-7
共用体の複数のメンバの初期化は許容されない (2827) ........................................................ 5
ISO-8
ドットで連結されたメンバへのアクセスが定数式ではない (2028) ............................................. 5
ISO-9
演算子 << の不適切な使用によるエラー (2350) .................................................................. 6
ISO-10
不完全な型への動的な型キャストは許容されない (2695) ...................................................... 6
ISO-11
非公開基底クラスへのアクセスは許容されない (2265-D) ....................................................... 6
ISO-12
派生関数内での一致しない例外指定は許容されない (2766-D) ............................................... 7
ISO-13
void 型の例外指定は許容されない (2070) .......................................................................... 7
ISO-14
ポインタから関数型への互換性のない例外指定は許容されない (2835-D) ................................ 7
ISO-15
派生クラスのヌル ポインタへの、ポインタの暗黙的型キャストは許容されない (2308).................. 7
ISO-16
reinterpret_cast で定数はキャストされない (2694) ................................................................ 7
ISO-17
const char [] は const char *[] と同一視されない (2144)....................................................... 8
ISO-18
名前修飾の繰り返しは許容されない (2757)......................................................................... 8
ISO-19
ポインタや参照ではない const_cast は許容されない (2717) ................................................... 8
ISO-20
修飾されたメンバ テンプレートにはキーワード template が必要 (2894) .................................... 8
ISO-21
引き数に依存した名前検索に関する 2003 年策定のルール (2020)........................................ 8
ISO-22
テンプレート特殊化での記憶クラスは許容されない (2080) ..................................................... 9
ISO-23
テンプレート修飾にはテンプレート引き数が必要 (2441) ......................................................... 9
ISO-24
フレンドはグローバル スコープではなく名前空間に投入される (2070) .................................... 10
ISO-25
文字列のオーバーロードは char * に一致する (aCC6 に該当するエラーなし) ......................... 10
ISO-26
定数以外の参照には lvalue が必要 (2461) ....................................................................... 10
ISO-27
ユーザ代入演算子がコンパイラにより生成された演算子より優先される (aCC6 の診断なし) ...... 10
ISO-28
参照を初期化するためのテンポラリの使用はエラーにならない (aCC6 の診断なし)................... 11
ISO-29
型が一致しない関数の戻り値は許容されない (2159) .......................................................... 11
ISO-30
explicit による変換の許容 (2312) .................................................................................... 11
ISO-31
ISO-32
ISO-33
ISO-34
ISO-35
ISO-36
ISO-37
ISO-38
ISO-39
ISO-40
ISO-41
案内宣言は生成されない (unsat ld 診断) ........................................................................... 12
reinterpret_cast による 64 ビット ポインタから 32 ビット スカラへの変換は許容されない (2171) 12
__int8 など、定義済み型の再定義は不可 (2084) ............................................................... 12
大きすぎる整数定数値のエラー (2023) ............................................................................. 12
コピー初期化として扱われる型キャスト (2348) ................................................................... 12
定数オブジェクトによる非定数メンバ関数の呼び出し (3086、2315) ...................................... 13
キーワード export が名前として使用されるとエラーになる (2040).......................................... 13
何も宣言しない修飾型は許容されない (2064).................................................................... 13
aCC6 ではインスタンス化の競合が早めに検出される (2403)............................................... 13
aCC6 では抽象クラスを返すことは許容されない (2323)...................................................... 13
aCC6 では、抽象クラスを返す型指定のないテンプレート引き数の非整数演算は許容されない
(2873) ......................................................................................................................... 14
処理系で定義されている動作 (IDB) ....................................................................................................... 14
IDB-1
オブジェクトのスロー テンポラリの非生成........................................................................... 14
IDB-2
左から右方向への引き数の評価 ...................................................................................... 14
IDB-3
副作用完了点が存在しない場合のポスト インクリメントとその後のストア................................. 14
IDB-4
非準拠コードでのインライン動作の違い............................................................................. 14
IDB-5
静的テンプレートの初期化順序 ........................................................................................ 15
IDB-6
不完全な列挙型へのポインタ .......................................................................................... 15
オプションとプラグマ (OP) .................................................................................................................... 15
OP-1
名前付き戻り値の最適化はデフォルトで有効...................................................................... 15
OP-2
aCC6 には潜在的なエラーはない .................................................................................... 15
OP-3
エラー番号の改訂.......................................................................................................... 15
IPF ABI 仕様への準拠 (ABI) ................................................................................................................. 15
ABI-1
ポインタをクラス メンバにマングリングする際の正しい型の再利用 ......................................... 16
ABI-2
名前付き定数のテンプレート パラメータとしての正しいマングリング........................................ 16
ABI-3
単項符号演算子 + の正しいマングリング........................................................................... 16
ABI-4
型を持たないテンプレート パラメータのマングリングによる型キャストの無効化......................... 17
ABI-5
sizeof 演算子の正しいマングリング .................................................................................. 17
ABI-6
「_Z」で始まる名前のマングリング ..................................................................................... 17
ABI-7
extern “C” ブロックからの typedef を持つフレンド関数の正しいマングリング ........................... 17
ABI-8
配列引き数の正しいマングリング...................................................................................... 18
ABI-9
関数へのポインタ型パラメータを持つ extern “C” 名のマングリング........................................ 18
ABI-10
一部の共用体型が値ではなく参照で渡される ..................................................................... 18
ABI-11
__cxa_vec_cctor2 の unsat (unsat Id 診断) ...................................................................... 18
参考情報 .......................................................................................................................................... 19
概要
HP aC++ バージョン 6.0
HP aC++ コンパイラをバージョン 5.x からバージョン 6.0 にアップグレードするときには、これらのバージョン間の相違
点に留意する必要があります。この文書では、両バージョンの相違点を、次の 4 つの項に分けて説明します。
• ISO C++ 標準への準拠
• 処理系で定義されている動作
• オプションとプラグマ
• IPF ABI 仕様への準拠
以下の文中では、HP aC++ のバージョン 5.* を aCC5、バージョン 6.0 を aCC6 と、それぞれ略記しています。なお、
本書は最終版ではありません。今後、新しい情報が追加され、更新される可能性があります。今回の版は、2005 年 2
月に校了したものです。
ISO C++ 標準への準拠 (ISO)
aCC6 コンパイラは旧バージョンの aCC に比べ、最新の ISO C++ 標準に準拠する範囲が広がりました。ISO C++
標準はオンラインで公開されており、ANSI のWebサイト (英語) で利用できます。以下に、aCC6 より前の aC++ コン
パイラで許容されていた、標準に準拠せず、移植性がないコード、および構文エラーを含むコードの例を示します。
aCC5 で正常にコンパイルされていたコードも、aCC6 では次に示す検証結果になることがあります。次のリストには、
aCC6 の検証番号順に、対応する項番を併記しています。
2020 (21)
2080 (22)
2265 (5、11)
2350 (9)
2695 (10)
2873 (41)
unsat (31)
2023 (34)
2028
2084 (33)
2088
2308 (2、15)
2312
2366 (6)
2403
2717 (19)
2757
2894 (20)
3086
なし (25、27、28、30)
(8)
(3)
(30)
(39)
(18)
(37)
2040
2144
2315
2441
2766
3139
(37)
(17)
(36)
(23)
(12)
(4)
2064
2159
2323
2461
2827
3301
(38)
(29)
(40)
(26)
(7)
(1)
2070
2171
2348
2694
2835
(13、24)
(33)
(35)
(16)
(14)
ISO-1 テンプレートと見なされないテンプレート フレンド (3301)
aCC6 で外部テンプレート関数をフレンド関数として使用するには、クラス内でキーワード template を指定する必要が
あります。指定しないと、テンプレート関数とは見なされません。
template <class T> struct list;
template <class T>
inline int bar(list<T>* lp) {
lp->i = 7; // access error, as bar<T> is not a friend
return 9;
}
template <class T>
struct list {
int foo(int i) { return bar(this); }
// aCC6 does not treat this as a template function
friend int bar(list<T>*); // workaround:
// friend int bar<>(list<T>;*);
// another workaround:
// template <class T>
// friend int bar(lis<T>*);
private:
int i;
};
int main() {
list<int> l_i;
return l_i.foo(9);
}
"test.c", line 11: warning #3301-D: "int bar(list<T> *)" declares a
non-template function -- add <> to refer to a template instance
3
aCC6 の strict モードでの未結合フレンド関数の扱い
template <class T>
struct S {
template <class T1> friend void f(T1);
};
void foo() {
S<float> s;
f<int>(5);
}
この場合、aCC5 では対応する f がテンプレートの外部で宣言されますが、aCC6 の strict モード (+strict オプション)
では、そのような宣言は行われません。
ISO-2 曖昧なオーバーロードの拒否 (2308)
aCC6 では、曖昧なオーバーロードの解決は拒否されます。aCC5 では潜在的なエラーになり、オーバーロードのいず
れか 1 つが選択されます。
double pow(float, float);
double pow(float, int);
int main()
{
float f;
double d;
return pow(f, d); // aCC6 error: call of pow(float, double) is ambiguous
}
line 7: error #2308: more than one instance of overloaded
function "pow" matches the argument list:
function "pow(float, float)"
function "pow(float, int)"
argument types are: (float, double)
return pow(f, d); // aCC6 error: call of pow(float, double) is ambiguous
次に、整数型と符号なしで long long をオーバーロードしている一例を示します。
void f(long long ll) { }
void f(unsigned long long ll) {}
int bar ()
{
f(0);
// aCC6 error: call of f is ambiguous
}
省略記号 (…) を含む関数の呼び出しは、aCC5 では潜在的なエラーになるだけでしたが、aCC6 ではエラーになりま
す。
void f(int);
void f(int, …)
f(4);
// error 2308
ISO-3 関数配列には typedef が必要 (2088)
関数の配列は、typedef で明示的に定義する必要があります。g++ も同様です。なお、これは言語機能の拡張として
望ましいものではありません。他の配列型 (void * の配列など) にも typedef が必要になるためです。
void ((*fptr1)[2])(); // User meant typedef void (*P)(); P fptr1[2];
"test.c", line 1: error #2088: array of functions is not allowed
ISO-4 キーワード template の不適切な使用 (3139-D)
aCC5 には、テンプレート メンバ関数の呼び出しに問題があったため、キーワード template が必須でした。この手法
は、aCC6 では警告になります。
struct C {
int a;
template <typename T> T foo(T i) { return i; }
} *myC;
4
int main()
{
myC->template foo(3); // aCC6 warning, template not appropriate here
}
"test.c", line 8: warning #3139-D: the "template" keyword used for
syntactic disambiguation may only be used within a template
ISO-5 テンプレートによる非公開メンバへの不適切なアクセス (2265-D)
aCC5 では、既存クラスの非公開メンバへの公開アクセスを作成するテンプレート コンテキストが許容されることがあり
ました。これは ISO C++ 標準では不正です。
class Vap {
public:
Vap(const Vap&) {}
Vap( );
};
class Vob : private Vap {
private:
Vob(const Vob&) {}
public:
Vob( const Vap& a);
};
template <class T> class VPO : Vob {
public:
VPO( const Vap& a) : Vob(a) {}
// aCC6 error: Vap is private
};
template class VPO<int>;
"test.c", line 14: error #2265-D: type "Vap::Vap" is inaccessible
ISO-6 定数メンバには初期化が必要 (2366-D)
aCC5 では、定数メンバを初期化しないコンストラクタの作成が許容されていました。
struct S {
const int s;
S() {}
// aCC6 error, no initializer for const int s
};
S xs;
"test.c", line 3: error #2366-D: "S::S()" provides no initializer for:
const member "S::s"
ISO-7 共用体の複数のメンバの初期化は許容されない (2827)
aCC5 では、共用体の複数のメンバの初期化が許容されていました。
struct X {
union U {
int uint;
long ulong;
U() : uint(1), ulong(2) {} // aCC6 error, this is illegal
} u;
};
X x;
"test.c", line 5: error #2827: only one member of a union may be specified
in a constructor initializer list
ISO-8 ドットで連結されたメンバへのアクセスが定数式ではない (2028)
aCC5 では、クラス内の列挙番号を整数定数式として使用できましたが、これは ISO C++ 標準のセクション 5.19 に
準拠していません。ここで言う「整数定数式」では、列挙型のメンバへのアクセスだけが許容されるため、クラス メンバ
へのアクセス式 (5.2.5 参照) とは異なります (後者は列挙型の 1 つのメンバに変換されます)。このような構文が許容
されると、たとえば次のような評価上の問題が発生します。
int a [ foo().fish ]; // foo() returns an object of type X since
//one must evaluate (see 5.2.5) the "foo()" call has side effects and
// "integral constant-expression" must be side effect free. g++ is
// changing to conform to not allow this either.
template <class T> struct X {
enum { fish = 64 };
5
};
template <class T> struct Y {
struct X<T> xy;
int foo (T x) {
int a [ xy.fish ]; // aCC6 error, xy.fish is not a
// constant expression
return a[1];
}
};
int main () {
Y<int> yi;
return yi.foo(10);
}
"test.c", line 7: error #2028: expression must have a constant value
ISO-9 演算子 << の不適切な使用によるエラー (2350)
演算子 << の不適切な使用は、aCC5 では潜在的なエラー (229) となり、演算子 << が -AP モードで受け入れ可能な
型への暗黙的変換が実行されていました。この aCC5 の動作は、実行時の予期せぬ動作の原因になることがありま
す。
#include <iostream>;
int main()
{
long long ll;
cout << ll;
// error, no suitable cout for long long in +DD32
}
"test235.c", line 6: error #2350: more than one operator "<<" matches these
operands:
function "ostream::operator<<(char)"
function "ostream::operator<<(unsigned char)"
function "ostream::operator<<(int)"
function "ostream::operator<<(long)"
function "ostream::operator<<(double)"
function "ostream::operator<<(float)"
function "ostream::operator<<(unsigned int)"
function "ostream::operator<<(unsigned long)"
function "ostream::operator<<(bool)"
function "ostream::operator<<(short)"
function "ostream::operator<<(unsigned short)"
operand types are: ostream_withassign << long long
ISO-10 不完全な型への動的な型キャストは許容されない (2695)
aCC5 では、不完全な型への動的な型キャストは許容され、キャスト後の型がグローバルであれば、不正な型情報が
生成されていました。aCC6 と g++ では、これはエラーになります。
struct B * b;
struct A * a;
int main () {
dynamic_cast<B*> (a);
// aCC6 error, B is incomplete
}
"test.c", line 4: error #2695: the type in a dynamic_cast must be a pointer
or reference to a complete class type, or void *
ISO-11 非公開基底クラスへのアクセスは許容されない (2265-D)
非公開の基底クラスは、ANSI/ISO Technical Corrigendum (正誤表) issue 142 thread 8217 内の 11.2 P3 に準じ
たアクセス決定に使用されるべきですが、aCC5 では非公開基底クラスへの不正なアクセスが許容されていました。
class Messenger {
public:
Messenger();
};
class RastEventHandler : private Messenger {
public:
RastEventHandler(Messenger *); // see 10.2 -- this is allowed
};
class XRastEventHandler : public RastEventHandler {
public:
XRastEventHandler(Messenger *messenger); // error, inaccessible
6
// This would be acceptable as ::Messenger *
};
"test.c", line 11: error #2265-D: type "Messenger::Messenger" is
inaccessible
ISO-12 派生関数内での一致しない例外指定は許容されない (2766-D)
aCC5 では、派生クラスの仮想関数の例外指定が基底クラスと異なるか、または例外指定を有する仮想デストラクタを
持つ基底クラスと、例外指定なしの派生クラスを持つことが許容されていました。aCC6 と g++ では、これはエラーに
なります。15.4 P3 を参照してください。
struct B { virtual ~B () throw (); };
struct D : public B { ~D (); }; // aCC6 error, ~D not compatible with ~B
// "test.c", line 2: error #2766-D: exception specification for virtual
// function "D::~D" is incompatible with that of overridden function "B::~B"
ISO-13 void 型の例外指定は許容されない (2070)
aCC5 では、次に示す場合に、不正な型を含む例外指定が許容されていました。
int foo() throw(void,int); // aCC6 error: cannot throw "void"
"test.c", line 1: error #2070: incomplete type is not allowed
ISO-14 ポインタから関数型への互換性のない例外指定は許容されない (2835-D)
aCC5 では、ポインタから関数型への互換性のない例外指定が許容されていました。
int g() throw (float, int) { return 1; }
int (&r)() throw (float, int) = g;
void f( int (&)() throw (int)) {}
void h() { f(r); } // aCC6 error: r not compatible with parm for f
"test.c", line 4: error #2835-D: incompatible exception specifications
ISO-15 派生クラスのヌル ポインタへの、ポインタの暗黙的型キャストは許容されない (2308)
aCC5 では、オーバーロードの曖昧さを解決するため、派生クラスのヌル ポインタ引き数に、ポインタを暗黙的に型キ
ャストする機能が追加されました。そのような暗黙的型キャストは明らかに不正です。
extern "C" int printf(const char *, ...);
struct Y {
};
struct X : public Y {
void f(X *) { printf("in f(X)\n"); }
void f(Y *) { printf("in f(Y)\n"); }
};
X gx;
int main () {
X * x = &gx;
x->f(0); // aCC5 chooses f(X), aCC6, g++ error
x->;f((X*)0); // Fix
"test.c", line 11: error #2308: more than one instance of overloaded
function "X::f" matches the argument list
ISO-16 reinterpret_cast で定数はキャストされない (2694)
g++ と aCC6 では、reinterpret_cast による定数のキャストが検出されるとエラーになります。
struct X {
int i;
};
void foo() {
X *a;
const X *c = 0;
a = *reinterpret_cast<X* const*>(&c); // aCC6 error, const cast
}
"test.c", line 7: error #2694: reinterpret_cast cannot cast away const or
other type qualifiers
7
ISO-17 const char [] は const char *[] と同一視されない (2144)
次の構文はエラーになるべきですが、aCC 5 では許容されていました。
static const char AsciiPhases[2]={"P_RQ4", "P_RQ2"}; // should be "char *"
"test.c", line 1: error #2144: a value of type "const char [6]" cannot be
used to initialize an entity of type "const char [2]"
ISO-18 名前修飾の繰り返しは許容されない (2757)
この構文は aCC 5 では許容されましたが、aCC 6 ではエラーになります。これは明らかに不正です。
template <class T, class OUT>
class DataDesc {
public:
class CellDesc {
public:
CellDesc();
CellDesc( const CellDesc& c);
};
};
<class T,class OUT>
DataDesc<T,OUT>::CellDesc::CellDesc(
const typename DataDesc<T,OUT>::CellDesc::CellDesc::CellDesc& c){
// aCC6 error
}
"test.c", line 12: error #2757: overloaded function
"DataDesc::CellDesc::CellDesc" is not a type name
ISO-19 ポインタや参照ではない const_cast は許容されない (2717)
この不正なコードは、aCC5 では許容されていました。
unsigned f(unsigned int ref_secs) {
return const_cast<unsigned> (ref_secs); // aCC6 error, ref_secs is
// not a pointer
}
"test.c", line 2: error #2717: the type in a const_cast must be a pointer,
reference, or pointer to member to an object type
ISO-20 修飾されたメンバ テンプレートにはキーワード template が必要 (2894)
aCC5 ではメンバ テンプレートの宣言にキーワード template は不要でしたが、aCC6 では必須です (14.2 P4 参照)。
template <class T>
struct A {
template <class T2>
class B : public T2 {
public:
B() : T2() {}
};
};
template <class T>
struct C {
template <class T2>
class G : A<T>:: B<T2>; {}; // aCC6 error, not a class or struct name
// class G : A<T>:: template B<T2> {};
// Valid C++
};
"test.c", line 12: error #2894: nontype "A<t>::B [with T=T]" is not a
template
ISO-21 引き数に依存した名前検索に関する 2003 年策定のルール (2020)
aCC 5 では、引き数に依存した名前検索 (14.6.2 参照) が 1997 年策定の標準に準じて実行されますが、これは
2003 年策定の標準には準じていません (2002 ISO C++ Technical Corrigendum に、次の例の _C_coll_order は
this->; で修飾されているか、または明示的に修飾されていない限り、基底クラス内で検索されない旨が明記されていま
す)。これは aCC6 の strict モード (+strict オプション) でエラーになります。
template <class _CharT>
struct collate_base {
int _C_coll_order (_CharT __low1) const;
8
};
template <class _CharT>
struct collate : public collate_base<_CharT> {
int do_compare (const _CharT* __low1, const _CharT* __low2) const;
};
template <class _CharT>
int collate<_CharT>::
do_compare (const _CharT* __low1, const _CharT* __low2) const
{
int __comp = _C_coll_order (*__low1) - _C_coll_order (*__low2);
// aCC6 error: _C_coll_order is undefined
// This makes the dependency explicit and compiles:
// int __comp = this->;_C_coll_order (*__low1) - this->;_C_coll_order
// (*__low2);
return __comp;
}
int main () {
char *a = 0;
collate <char> mc1;
mc1.do_compare(a,a);
}
"test.c", line 13: error #2020: identifier "_C_coll_order" is undefined
ISO-22 テンプレート特殊化での記憶クラスは許容されない (2080)
aCC6 では、テンプレートの明示的な特殊化に記憶クラスが含まれているとエラーになります。C++ 標準の 14.7.3 で
inline は許容されていますが、7.1.1 P1 で static が禁じられています。
template static int mul(T a, T b, T *c) { return a+b; }
template <>;
inline static int mul(int a, int b, int *c) { return a+b; }
"test.c", line 3: error #2080: a storage class may not be specified here
ISO-23 テンプレート修飾にはテンプレート引き数が必要 (2441)
aCC5 では、特定のコンテキストでテンプレート引き数リストを省略するために、テンプレートへのクラス名投入が実行
されていました。そのような処理は、aCC6 のデフォルトでは実行されません。
namespace N {
template <typename T1> struct X {
template <typename T2> struct Y {
typedef T2 xt;
void foo ( typename N::X::Y<T2>::xt ); // OK in aCC5, g++
// void foo ( typename N::X<T1>::Y<T2>::xt ); // aCC6 prefers
};
};
}
using namespace N;
int main ()
{
X<int>::Y<int> y;
y.foo(10);
}
line 5: error #2441: argument list for class template “N::X” is missing
次にもう 1 つ、基底クラスに関連する例を示します。aCC5 では、クラス ベース リストに、それがあたかもクラスのスコ
ープを持つかのようにクラス名投入が実行されます。この処理は C++ 標準でも明示的に禁じられているわけではあり
ません。ただし、クラスのスコープは { から始まることが標準で示唆されているため、明らかに正しくない動作です。
template <class T> struct A { int x; int y; };
template <class T> struct B : A <B> { int a; int b; };
"test.c", line 6: error #2441: argument list for class template "B" is
missing
これは aCC6 では不正です。A<B> は、この時点で投入名 B が有効になっていないため、 A<B<T> > と記述
する必要があります。
9
ISO-24 フレンドはグローバル スコープではなく名前空間に投入される (2070)
class Y の末尾は aCC5 では ::Y ですが、aCC6 では N::Y です。この違いが問題になるのは、strict モード (+strict オ
プション) でコンパイルしていない場合です。
namespace N {
class X;
void f();
}
using N::X;
class X {
friend class Y;
};
class Y {};
void N::f() {
Y y; // aCC6 error, N::Y is incomplete
}
"test.c", line 11: error #2070: incomplete type is not allowed
ISO-25 文字列のオーバーロードは char * に一致する (aCC6 に該当するエラーなし)
aCC5 では、void * および char * のパラメータをオーバーロードする引き数として文字列が渡され、その文字列
(const char * 型) が、明示的ターゲットが存在する場合に char * に変換されると、4.2(2) の規定に従って潜在的なエ
ラーを生成します。aCC6 では strict モード (+strict オプション) で、文字列リテラルを const char * 型に変換するため
の診断が行われます。
void f(void *) { }
void f(char *) { }
int main () {
f("hi");
}
// aCC5 future error, no aCC6 diagnostic
ISO-26 定数以外の参照には lvalue が必要 (2461)
定数以外の参照には lvalue が必要です。aCC5 では、定数以外の参照に lvalue 以外の値を渡すことが許容されてお
り、潜在的なエラーになるだけでした。これは aCC6 でも許容されますが、strict モード (+strict オプション) ではエラ
ーになります。
void f(int & iref) {} // should be "const int reference" to avoid error
int main ()
{
f(10); // aCC6 error: int reference requires requires lvalue
// in strict mode
}
"test.c", line 4: error #2461: initial value of reference to non-const must
be an lvalue
ISO-27 ユーザ代入演算子がコンパイラにより生成された演算子より優先される (aCC6 の診断
なし)
aCC5 では、コンパイラで生成された代入演算子が、ユーザにより指定された演算子より優先されることがあります。
以下の例をご覧ください。12.8 P10 のルールは、基底の operator=(D&) には適用されません。operator=(const D&)
ではないためです。aCC5 はどちらか一方ではなく、両方の演算子を生成します。両方の演算子が必要になることもあ
りますが、きわめて限定された場合のみです (12.8 P10 を参照)。aCC6 と g++ では、基底の operator= が選択され
ます。これは隠蔽されておらず、オーバーロードされた関数セット内にあり、しかも修飾子の数が少ないからです。
aCC5 では、曖昧さにより潜在的なエラーが生成され、コンパイラで生成された不正な演算子が選択されます。
#include <stdio.h>
struct D; // fwd declaration
struct B {
D& operator=(D&);
};
struct D : B {
D() {}
D(int ii) { s = ii; }
using B::operator=;
int s;
10
};
int main() {
D od, od1(10);
od = od1; // implicit D::operator=(D&) called, not BASE::operator=(D&)
}
D& B::operator=(D& d) {
printf("B::operator called\n");
return d;
}
ISO-28 参照を初期化するためのテンポラリの使用はエラーにならない (aCC6 の診断なし)
aCC6 では、参照の値を保持するテンポラリが生成されます。aCC5 ではエラーになりますが、それは標準でサポート
されなくなった aCC5 の原則、「デストラクタ A が、B b の作成直後に呼び出される」に起因します。この動作は、a(5)
の存続時間と、その結合先である参照変数 const A& a の存続期間が同じになるべきであるため、不正です (後者は
コンストラクタ終了まで存続します)。
class A {
public:
int x;
A(int a) : x(a) {}
};
class B {
const A& a;
public:
B() : a(5) {}
};
// aCC5 error, no error with aCC6
ISO-29 型が一致しない関数の戻り値は許容されない (2159)
aCC5 では、ネストされたスコープ内で C の関数を再宣言し、関数の戻り値の型を互換性のない型に変換する処理が
許容されていました。この処理は ISO C++ 標準に準拠しておらず、aCC6 ではエラーになります。
long random();
int main () {
int random();
return random();
}
// aCC6 error, incompatible redeclartion
"test.c", line 3: error #2159: declaration is incompatible with previous
"random" (declared at line 1)
ISO-30 explicit による変換の許容 (2312)
aCC6 の explicit は、aCC5 の場合に比べ、より強い効力を持ちます。次の reverse_iterator クラスの定義を見てみま
しょう。
template <class RandomAccessIterator, class T, class Reference = T&,
class Pointer = T*, class Distance = ptrdiff_t>
class reverse_iterator : public random_access_iterator<T, Distance>
{
public:
reverse_iterator() {}
explicit reverse_iterator (RandomAccessIterator x) : current(x) {}
RandomAccessIterator base () { return current; }
// remaining members
};
さらに、次の例をご覧ください。
deque<int> dq;
deque<int>::reverse_iterator ri12345 =
dq.begin();
// Incorrect, should be changed to
// deque<int>::reverse_iterator
ri12345( dq.begin() );
ri12345 は、iterator 型 (dq.begin()) のコピーの初期化であるため、iterator から reverse_iterator に変換するために、
なんらかのユーザ定義関数が必要です。コンストラクタ reverse_iterator (RandomAccessIterator x) は explicit として
宣言されているため、変換関数とは見なされず、iterator から reverse_iterator への変換関数は不在になります。
11
ISO-31 案内宣言は生成されない (unsat ld 診断)
次のコードで、aCC5 はテンプレート関数 f の案内宣言 (guiding declaration) を生成しますが、aCC6 は生成しません。
int gx = 0;
template <class T>
void f (T ,T )
{
gx = 10;
}
void f(int, int);
template<>
void f(int, int)
{
gx = 20;
}
int main()
{
int a = 0,b;
char c,d = 0;
f(a, d);
// aCC5 chooses specialization for f(int, int).
// aCC6 chooses extern "f(int,int)"
}
ISO-32 reinterpret_cast による 64 ビット ポインタから 32 ビット スカラへの変換は許容されない
(2171)
次のコードは aCC5 (+DD64 でコンパイル) では許容されていましたが、aCC6 では不正です (5.2.10P4 を参照)。
struct X {};
int main () {
X *p = 0;
int a = reinterpret_cast<int>(p);
}
// error 2171 in aCC6
line 4: error #2171: invalid type conversion
ISO-33 __int8 など、定義済み型の再定義は不可 (2084)
typedef signed char __int8; // error #2084: invalid combination of
// type specifiers
ISO-34 大きすぎる整数定数値のエラー (2023)
大きすぎる整数定数値は aCC5 では警告だけですが、aCC6 ではエラーになります。
long long l = 0x10000000000000000000000000000000;
line 1: error #2023: integer constant is too large
ISO-35 コピー初期化として扱われる型キャスト (2348)
aCC5 では aCC6 とは異なり、静的な型キャストは直接初期化ではなく、コピー初期化として扱われます。
struct D {
D();
D(int);
D(const D &);
};
struct P {
P();
operator int() const;
operator D() const;
}
extern void g(D);
void f(const P& p) {
12
g((D)p);
// aCC5 copy init, aCC6 direct initialization of temporary
}
error #2348: more than one user-defined conversion function from
“const P” to “D” applies:
function “D::D(int)”
function “D::D(const D &)”
(D) の (static cast) へのキャストは、初期化がコピー初期化ではなく、直接初期化であることを示唆しています。
ISO-36 定数オブジェクトによる非定数メンバ関数の呼び出し (3086、2315)
定数オブジェクトによる非定数関数の呼び出しは、aCC5 では潜在的なエラーになるだけです。
struct S {
void nconst();
void con() const;
};
void S::con() const {
nconst();
// Error 3086 vs future error in aCC5
this->nconst(); // Error 2315 vs future error
}
int main() {
const S f;
f.nconst(); // Error 2315
}
ISO-37 キーワード export が名前として使用されるとエラーになる (2040)
キーワード export を変数名として使用しても、aCC5 では警告が生成されるだけでしたが、aCC6 ではエラーになりま
す。
ISO-38 何も宣言しない修飾型は許容されない (2064)
class B{};
class A {
private:
class ::B;
// error, decl does not declare anything (see 7.1.5.3(2))
};
line 4: error #2064: declaration does not declare anything
ISO-39 aCC6 ではインスタンス化の競合が早めに検出される (2403)
メンバ関数ごとにインスタンス化されるタイミングが異なるため、インスタンス化の競合通知も異なる可能性があります。
template <class T>
struct S {
void foo(T *i) {}
void foo(const T *i) {}
};
int main() {
int i = 5;
S<const int> s;
// uncommenting the line below makes aCC5 give a
// future error
// s.foo(&i);
return 0;
}
line 4: error #2403: function "S<T>::foo(T *) [with T=const int]"
has already been declared
void foo(const T *i) {}
^
detected during instantiation of class "S<T> [with T=const int]"
at line 9
ISO-40 aCC6 では抽象クラスを返すことは許容されない (2323)
class Base {
virtual void foo() = 0;
};
13
class Derived : public Base {
Derived bar(); // aCC6 reports that D is abstract as
// B::foo has not been overridden
// aCC5 compiles it fine
};
line 6: error #2323: function returning abstract class "Derived"
is not allowed:
pure virtual function "Base::foo" has no overrider
Derived bar(); // aCC6 reports that D is abstract as
ISO-41 aCC6 では、抽象クラスを返す型指定のないテンプレート引き数の非整数演算は許容さ
れない (2873)
typedef struct G {
unsigned short Data2;
} G;
extern "C" const G g;
template <const G *p>
struct foo {};
foo<(const G*)&g> ff;
line 9: error #2873: non-integral operation not allowed in
nontype template argument
foo<(const G*)&g> ff;
^
処理系で定義されている動作 (IDB)
C++ 標準には、セマンティックや構文上の意味合いをほとんど損なわずに、実装に違いを持たせることが可能な領域
があります。この違いが問題になることは少ないですが、プログラムによってはこの動作に影響を受ける場合がありま
す。
IDB-1 オブジェクトのスロー テンポラリの非生成
オブジェクトのスロー テンポラリは、そのテンポラリが省略可能な言語では、生成されません。aCC5 では、スローされ
たオブジェクトのテンポラリが生成され、そのテンポラリ内にオブジェクトを作成し、コピー コンストラクタを使用してスロ
ーされたオブジェクトに移動する場合があります。スローされたオブジェクトのクラスにテンポラリの生成が必要なけれ
ば、aCC6 はスローされたオブジェクト内に直接作成します (その結果、2 つのコンストラクタと 1 つのデストラクタの呼
び出しが省略されます)。
IDB-2 左から右方向への引き数の評価
関数の引き数は、aCC6 では左端の引き数から右方向へと評価されます。aCC5 の場合は、インライン関数を除いて、
右端の引き数から左方向です。
IDB-3 副作用完了点が存在しない場合のポスト インクリメントとその後のストア
次のコードは、aCC5 と aCC6 で実行結果が異なります。ポスト インクリメント演算子は副作用完了点 (sequence
point) より前に効果を持つ必要がありますが、文 a = a++; では「;」が副作用完了点になります。
int main()
{
int a = 11;
a = a++;
printf ("%d\n", a); // aCC5 == 12
// aCC6 == old C on IPF == aCC on PA == cc on PA == 11
}
IDB-4 非準拠コードでのインライン動作の違い
非準拠プログラムはコンパイラの種類により、定義を一度だけに限定する ODR(One Definition Rule) 規則に違反し、
異なる結果になることがあります。aCC5 で正常にコンパイルして実行できる非準拠コードも、aCC6 でコンパイルする
とリンク時に重複定義エラーが発生する可能性があります。
14
IDB-5 静的テンプレートの初期化順序
次に示すテストの結果は、静的テンプレート変数 Value<[0-6]>; の初期化方法に左右され、aCC5 では 0、aCC6 で
は 8 になります。これは ISO 標準グループの issue 362 に該当します。同標準により、静的テンプレート変数は静的
変数のように振る舞い、以降のテンプレートの初期化を妨げないように条件付けられています。
template<int n>
struct Fib { static int Value; };
template <>
int Fib<0>::Value = 0;
template <>
int Fib<1>::Value = 1;
template<int n>
int Fib<n>::Value = Fib<n-1>::Value + Fib<n-2>::Value;
int main ()
{
return Fib<6>::Value;
}
IDB-6 不完全な列挙型へのポインタ
ポインタを不完全な列挙型に間接参照する手法は、aCC5 では許容されますが、aCC6 ではエラーになります。
enum incomplete;
func () {
enum incomplete *e;
int i;
i = *e;
}
オプションとプラグマ (OP)
OP-1
名前付き戻り値の最適化はデフォルトで有効
aCC6 では、NRV (Named Return Value:名前付き戻り値) の最適化はデフォルトで実行されます。一方、aCC5 で最
適化を行うには、+nrv オプションで明示的に指定する必要があります。+nrv を指定すると一部のテンポラリ オブジェク
トの生成が省略されます。その結果、省略されたオブジェクトのコンストラクタとデストラクタは呼び出されません。
aCC6 コンパイラは、form f(S()) を使用する際のテンポラリの削除面でも優れています (S は何らかのクラス)。削除さ
れたテンポラリのデストラクタの呼び出しは省略されます。
OP-2
aCC6 には潜在的なエラーはない
aCC5 には、潜在的なエラー (future error) と呼ばれる警告クラスがありました。これらの警告は通常、aCC5 では警
告またはエラーになります。また、aCC5 の +p オプション (潜在的なエラーを致命的なエラーに変換) は無視されます。
OP-3
エラー番号の改訂
aCC5 のメッセージ セットは、aCC6 で完全に改訂され、更新されています。ドライバに由来しない、コンパイラが生成
するメッセージの番号はすべて変更されており、個々の診断の厳密度を指定する +W オプションの用法も更新が必要
です。
IPF ABI 仕様への準拠 (ABI)
aCC5 の動作は、IA64 ABI 仕様に正しく準拠していません。この仕様は、Itanium での C++ コンパイラの相互運用性
の確保を目的として、業界組織が連携して策定したものです。仕様の内容は、CodeSourcery Web サイト (英語) で閲
覧できます。以下に、aCC5 に存在し、aCC6 では解消された不具合に起因する、aCC5 と aCC6 のバイナリ互換性
の問題を列挙します。aCC6 で不具合が解消されたのは、それらの不具合により、リバース エンジニアリングも、既存
の c++filt による変換も不可能なマングリングが生成されていたためです。(さらに、2 つの署名で同じマングリングが合
成される可能性もありました。これが実際に起こるようであれば、正真正銘 aCC5 のバグであり、aCC6 に残すわけに
はいきません。) なお、ここに示す問題はいずれも稀に発生するに過ぎず、実用的な互換性を損なうものではありませ
ん。マングリングの問題は、シンボルの重複やリンク時のシンボル未定義エラーの原因になる可能性があります。
15
ABI-1 ポインタをクラス メンバにマングリングする際の正しい型の再利用
引き数リスト内で後に位置する型がクラス メンバへのポインタで、そのポインタが引き数リスト内で先に位置する型を再
利用する場合、aCC5 では型を再利用するためのマングリングが正しく実行されませんでした。
typedef void T();
struct S { } ;
void f (int S::*, T(S::*)) {}
// no type reuse between class member pointers
どちらのコンパイラも、f のリンカ識別子を次のようにマングリングします。
_Z1fM1SiMS_FvvE
ただし、f に渡される引き数の間に型の再利用が存在する場合には、f の識別子はマングリング後、互換性を失います。
typedef void T();
struct S { } ;
void f (T*, T(S::*)) {}
aCC5 と aCC6 のコンパイラによる、f のリンカ識別子のマングリング結果を次に示します。
_Z1fPFvvEM1SS_
// aCC5, incorrect per IA64 ABI
/opt/aCC/bin/c++filt = f(void (*)(),< (NOT IMPLEMENTED) > S::*)
_Z1fPFvvEM1SFvvE
// aCC6
/opt/aCC/bin/c++filt = f(void (*)(),void (S::*)())
Here is another similar case involving pointers to members.
// INDEX5 26 EXPECT _Z6mike_8M1AFivEPS0_ FCT
// INDEX6 26 EXPECT _Z6mike_8M1AFivEPFivE FCT
void mike_8 (int (A::*)(), int (*)());
ABI-2 名前付き定数のテンプレート パラメータとしての正しいマングリング
aCC5 では、テンプレート パラメータで使用される名前付き定数から、c++filt でデコードできないマングリングが生成さ
れます。
const int N = 3;
template <int I> struct S{};
template <int I> void f(S<n +="" i="">) {}
int main() {
f<7>(S<N + 7>());
}
_Z1fILi7EEv1SIXplL1NET_EE
// aCC5
/opt/aCC/bin/c++filt = void f<(int)7>(S<((N)-1+(%0=)(int)7)>)
_Z1fILi7EEv1SIXplLi3ET_EE
// aCC6
/opt/aCC/bin/c++filt = void f<(int)7>(S<((int)3+(%0=)(int)7)>)
ABI-3 単項符号演算子 + の正しいマングリング
aCC5 では、単項符号演算子 + は正しくマングリングされません。単項符号演算子 (+ および -) には、pl エンコードが
使用されます。
template <int T>
struct B{};
template <int T>
void f(B<+T> x) {}
int main() {
B<+1> b;
f<1>(b);
}
// Note unary plus here
aCC5 と aCC6 のコンパイラによる、f のリンカ識別子のマングリング結果を次に示します
_Z1fILi1EEv1BIXplT_EE
_Z1fILi1EEv1BIXpsT_EE
// aCC5, incorrect per IA64 ABI
// aCC6
16
ABI-4 型を持たないテンプレート パラメータのマングリングによる型キャストの無効化
aCC5 コンパイラは (unsigned char)-80 を –80 にマングリングします。一方、aCC6 コンパイラでは 176 になります。
template <int T>
struct B{};
template <int T>
void f(B<T> x) {}
int main() {
B<(unsigned char)-80> b;
f<(unsigned char)-80>(b);
}
この結果、f のリンカ識別子のマングリング結果は次のようになります。
_Z1fIXcvhLin80EEEv1BIXL1TEEE
/opt/aCC/bin/c++filt = _Z1fIXcvhLin80EEEv1BIXL1TEEE
_Z1fILi176EEv1BIXT_EE
/opt/aCC/bin/c++filt = void f<(int)176>(B<(%0=)(int)176>)
ABI-5 sizeof 演算子の正しいマングリング
sizeof 演算子は、型を持たないテンプレート引き数として使用されている場合、aCC5 コンパイラで正しくマングリングさ
れません。
template <int s> class A {};
template <class T1>
void foo(T1*, A<sizeof(T1)>) {}
template void foo( int*, A<sizeof( int* ) > );
aCC5 による foo のマングリング結果
_Z3fooIiEvPT_1AIXszT_EE
aCC6 (および g++) による foo のマングリング結果
Z3fooIiEvPT_1AIXstS0_EE
ABI-6 「_Z」で始まる名前のマングリング
「_Z」で始まる名前は、aCC5 コンパイラではマングリングされません (aCC6 コンパイラではマングリングされます)。ア
ンダースコア (_) で始まる名前はコンパイラとランタイム用に予約されており、「_Z」で始まる名前について言及している
のは、万一の互換性の問題に備えてのことです。
ABI-7 extern “C” ブロックからの typedef を持つフレンド関数の正しいマングリング
extern “C” ブロックの typedef と見なされていたクラスに含まれるフレンド関数は、aCC5 ではマングリングされません。
次に例を示します。
struct ostream;
extern "C" {
typedef struct ORDINAL FF;
}
struct ORDINAL {
friend ostream&
osfriend(ostream&, const ORDINAL&);
};
ostream& osfriend( ostream& os, const ORDINAL& ord) { return os; }
関数 osfriend は本来、マングリングされるべきですが、aCC5 コンパイラではマングリングされません。
17
ABI-8 配列引き数の正しいマングリング
aCC5 コンパイラでは、関数の配列型引き数が正しくマングリングされません。たとえば、関数 f0(char[2]) のマングリ
ング結果は、_Z2f0Pc ではなく _Z2f0A2_c になります。
ABI-9 関数へのポインタ型パラメータを持つ extern “C” 名のマングリング
関数へのポインタをパラメータとして持つ関数が、extern "C" ブロック内で宣言されているにも関わらず、extern "C" ブ
ロックなしで定義されている場合、aCC5 はそれらの関数を、定義にリンケージ C++ 関数へのポインタを含み、宣言に
リンケージ C へのポインタを含むものと見なしてマッチングします。その結果、定義はマングリングされません。
extern "C" {
char *(*change(int i,char *(*p)(char*,char*)))(char*,char*);
} // extern "C"
char *(*change(int i,char *(*p)(char*,char*)))(char*,char*) {
return p;
} // not extern C
名前 change は extern “C” ブロック内で宣言されていますが、aCC6 ではマングリングされます。aCC5 では、関数
change はマングリングされません。aCC6 で aCC5 と同じ動作を得るには、change を extern “C” ブロック内で定義
するか、–Aarm を使用します。
ABI-10 一部の共用体型が値ではなく参照で渡される
aCC5 では、コピー コンストラクタまたは削除演算子を含む共用体は、値渡しされます。これは IPF ABI に準拠しない
動作です。aCC6 コンパイラは、コピー コンストラクタとデストラクタを含む共用体を参照で渡します。aCC6 の将来のリ
リースでは、この処理で警告が生成されるようになり、値渡しでオーバーライドするオプションが追加される予定です。
union C {
C();
C(const C
&);
int i;
};
void foo(C i);
int main() {
C c;
foo(c); // c passed by value in aCC5 by reference in aCC6
}
ABI-11 __cxa_vec_cctor2 の unsat (unsat Id 診断)
aCC6 コンパイラは、配列のコピーを作成するランタイム ライブラリへの呼び出しを生成します。これは、IPF ABI 仕様
により忠実な動作です。新しいエントリとして使用される __cxa_vec_cctor2 は、標準の __cxa_vec_cctor とはわずか
に異なっており、aCC5 の動作に合わせるための追加引き数が 1 つ含まれています。アプリケーションのリンク時に
__cxa_vec_cctor2 が未定義エラーになる場合は、最新のランタイム ライブラリがインストールされていません。
18
参考情報
ANSI の Web サイト
http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS/ISO/IEC+14882-2003
CodeSourcery の Web サイト
http://www.codesourcery.com/cxx-abi/abi.html
お問い合わせはカスタマ インフォメーション センタへ
03-6416-6660
月~金9:00~19:00 土10:00~18:00 (日、祝祭日、年末年始および5/1を除く)
HP-UX 製品に関する情報は http://www.hp.com/jp/hpux
HP-UX に関する技術情報は http://www.hp.com/jp/developer
記載されている会社名および商品名は、各社の商標または登録商標です。
記載事項は2005年9月現在のものです。
本書に記載された内容は、予告なく変更されることがあります。
本書中の技術的あるいは校正上の誤り、省略に対して、
いかなる責任も負いかねますのでご了承ください。
本書は、『aC++ standard conformance and compatibility changes technical software』 (英語) をもとに加筆・修正し
て日本語で提供するものです。
© Copyright 2005 Hewlett-Packard Development Company,L.P.
日本ヒューレット・パッカード株式会社
〒140-8641 東京都品川区東品川2-2-24 天王洲セントラルタワー
PDFHS05030-01
Fly UP