Skip to content

reference

NAGAMINE Hideaki edited this page Feb 15, 2017 · 13 revisions

「参照の要素」の案

参照型

参照型はpointerTypeによって表現する。pointerTypeに非必須属性として is_lvalue_reference, is_rvalue_reference 属性を追加する。これらはそれぞれ右辺値参照であるか、左辺値参照であるかを表現する。文面の案を次に示す。

3.5 pointerType要素

pointerType要素はポインター型またはリファレンス型を表現する。

 <pointerType/>
  • 属性(必須): type, ref
  • 属性(optional): is_lvalue_reference, is_rvalue_reference, データ型定義要素属性

以下の属性をもつ。

  • type - この型に与えられたデータ型識別名
  • ref - このポインターまたはリファレンスが参照する静的型のデータ型識別名
  • is_lvalue_reference - この型がlvalueリファレンス型であるかどうか
  • is_rvalue_reference - この型がrvalueリファレンス型であるかどうか

is_lvalue_reference, is_rvalue_referenceの属性値には、真を意味する1とtrue, 偽を意味する0とfalseが許される。属性が省略されたとき、偽を意味する(3.3)。

Rationale

ポインターを表現するXcodeML要素を用いて参照を(一貫して)表現すると、Cに対応するXcodeML処理系は変更なしに参照を使ったプログラムを処理することができる。

参照型の変数

プログラム中に現れる参照型変数の使用は、is_lvalue_reference属性またはis_rvalue_refernce型が真であるようなpointerRef要素で表現する。すなわち、

int & lri = i;
lri = 100; // (*1)

において、(*1)はXcodeMLにおいて

<assignExpr>
	<pointerRef is_lvalue_reference="1">
		<Var type="ref_to_int">lri</Var>
	</pointerRef>
	<intConstant type="int">100</intConstant>
</assignExpr>

のように表現する。文面案を次に示す。

7.3 pointerRef要素

ポインターまたはリファレンスによる間接参照を表現する。

 <pointerRef>
   式の参照
 </pointerRef>
  • 属性(必須): type
  • 属性(optional): is_reference

Rationale

参照型をpointerType要素で表すので、ポインター型の変数との一貫性をとった。ポインター型変数を使って上記のプログラム片に対応するものを書くと、

int *pi = &i;
*pi = 100; // (*2)

となる。(*2)はXcodeMLにおいて

<assignExpr>
	<pointerRef is_lvalue_reference="1">
		<Var type="ptr_to_int">pi</Var>
	</pointerRef>
	<intConstant type="int">100</intConstant>
</assignExpr>

と表現される。上の提案はこれとの一貫性を重視したものである。

参照を使ったプログラムの例

void func(const double & lrcd) {
	int i = 10;
	int & lri = i;
	lri = 100;
}
<XcodeProgram>
	<typeTable>
		<basicType type="const_double" is_const="1" name=double"/>
		<pointerType is_lvalue_reference="1" type="ref_to_const_double" ref="const_double" />
		<pointerType is_lvalue_reference="1" type="ref_to_int" ref="int" />
		<functionType type="fun_from_ref_to_const_double_to_void" return_type="void">
			<params>
				<name type="ref_to_const_double">lrcd</name>
			</params>
		</functionType>
	</typeTable>
	<globalSymbols>
		<id type="fun_from_ref_to_const_double_to_void" sclass="extern_def">
			<name>func</name>
		</id>
	</globalSymbols>
	<globalDeclarations>
		<functionDefinition>
			<name>func</name>
			<symbols>
				<id type="ref_to_const_double sclass="param">
					<name>lrcd</name>
				</id>
			</symbols>
			<params>
				<name type="ref_to_const_double">lrcd</name>
			</params>
			<body>
				<compoundStatement>
					<symbols>
						<id type="int" sclass="auto">
							<name>i</name>
						</id>
						<id type="ref_to_int" sclass="auto">
							<name>lri</name>
						</id>
					</symbols>
					<declarations>
						<varDecl>
							<name>i</name>
							<value>
								<intConstant type="int">0</intConstant>
							</value>
						</varDecl>
							<name>lri</name>
							<value>
								<Var type="int">i</Var>
							</value>
						</varDecl>
						<exprStatement>
							<assignExpr>
								<pointerRef is_reference="1">
									<Var type="ref_to_int">lri</Vaar>
								</pointerRef>
								<intConstant type="int">100</intConstant>
							</assignExpr>
						</exprStatement>
					</declarations>
				</compoundStatement>
			</body>
		</functionDefinition>
	</globalDeclarations>
</XcodeProgram>

課題

reference collapsing

参照への参照は規格上存在しないが、typedefされた型やテンプレートパラメータ型などに参照修飾子を付けることで見かけ上参照への参照が発生したとき、コンパイラーはこれを適切な型に置き換えることになっている(reference collapsing)。

typedef int & LRI;
extern LRI& lrlri;

これをtypeTable上でどう扱うか。仕様書にはこのことを明記せず、C++->XcodeML翻訳器がとりあえず正しい型を吐けばそれでよいとするか、または仕様書の「pointerType要素」セクションでrefが参照型であったときのルールをちゃんと定めるか? 既に似たような例はあるか(型の解決に関する特別なルールがXcodeML/Cに存在するか)?

参照型変数の初期化を表すXcodeML要素で右辺をどう表すか

上記の例では、参照型変数の初期化はポインター型のそれとは一貫していない。上のXcodeMLには

<!-- int& lri = i -->
</varDecl>
	<name>lri</name>
	<value>
		<Var type="int">i</Var>
	</value>
</varDecl>

とあるが、ポインター型変数の初期化は

<!-- int* pi = &i -->
</varDecl>
	<name>pi</name>
	<value>
		<varAddr type="ptr_to_int" scope="...">i</Var>
	</value>
</varDecl>

である。右辺はどう表すのが良いか?

変数以外の参照について

ここまでに書かれた方針は、そのまま「返り値が参照となる関数の呼び出し」のような式が出現したときも適用できる。例えば

int &f();

のような関数 f の返り値の型は <pointerType is_lvalue_refence="1"/> の形で表現し、

f() = 1;

という式は

<assignExpr>
  <pointerRef is_lvalue_reference="1">
    <functionCall …略/>
  </pointerRef>
  <intConstant type="int">1</intConstant>
</assignExpr>

という形で表現する、といった具合である。