您的位置:首页 > 编程语言

GCC-3.4.6源代码学习笔记(154)

2011-01-29 15:17 351 查看
5.13.1.2.3.1.

案例学习:到指针的转换

5.13.1.2.3.1.1.

从类到指针

到指针的转换是很有趣的,值得一看。处理这个转换的函数是下面的
cp_convert_to_pointer

。类可以被转换到指针类型,仅当它定义了一个这样做的用户定义转换。

76

static
tree

77

cp_convert_to_pointer

(tree type, tree
expr, bool force)

in
cvt.c

78

{

79

tree intype = TREE_TYPE (expr);

80

enum
tree_code form;

81

tree rval;

82

if (intype == error_mark_node)

83

return
error_mark_node;

84

85

if (IS_AGGR_TYPE (intype))

86

{

87

intype = complete_type
(intype);

88

if (!COMPLETE_TYPE_P (intype))

89

{

90

error ("can't convert from incomplete
type `%T' to `%T'",

91

intype, type);

92

return
error_mark_node;

93

}

94

95

rval = build_type_conversion
(type, expr);

96

if (rval)

97

{

98

if
(rval == error_mark_node)

99

error ("conversion of `%E' from `%T'
to `%T' is ambiguous",

100

expr, intype, type);

101

return
rval;

102

}

103

}

函数
build_type_conversion


build_user_type_conversion

的定义如下。显然它查找这个用户定义的转换操作符,并产生执行转换的代码。

995

tree

996

build_type_conversion

(tree xtype, tree
expr)

in
cvt.c

997

{

998

/* C++: check to
see if we can convert this aggregate type

999

into the required
type.
*/

1000

return
build_user_type_conversion
(xtype, expr,
LOOKUP_NORMAL);

1001

}

2522

tree

2523

build_user_type_conversion

(tree totype, tree expr, int flags)

in call.c

2524

{

2525

struct
z_candidate *cand

2526

= build_user_type_conversion_1
(totype, expr, flags);

2527

2528

if (cand)

2529

{

2530

if (TREE_CODE (cand->second_conv) ==
AMBIG_CONV)

2531

return
error_mark_node;

2532

return
convert_from_reference
(convert_like
(cand->second_conv, expr));

2533

}

2534

return
NULL_TREE;

2535

}

5.13.1.2.3.1.2.


void*
或函数指针

那么在下面的
type

是转换的目标类型,
106
行的条件为“
void*
”或函数指针的
type

所满足。而
intype

是表达式
expr

的类型。

cp_convert_to_pointer (continue)

105

/* Handle
anachronistic conversions from (::*)() to cv void* or (*)().
*/

106

if (TREE_CODE (type) == POINTER_TYPE

107

&& (TREE_CODE (TREE_TYPE (type))
== FUNCTION_TYPE

108

|| VOID_TYPE_P (TREE_TYPE (type))))

109

{

110

/* Allow an
implicit this pointer for pointer to member

111

functions.

*/

112

if (TYPE_PTRMEMFUNC_P (intype))

113

{

114

if
(pedantic

|| warn_pmf2ptr

)

115

pedwarn ("converting from `%T' to
`%T'", intype, type);

116

if
(TREE_CODE (expr) == PTRMEM_CST)

117

expr = build_address
(PTRMEM_CST_MEMBER (expr));

118

else

119

{

120

tree decl = maybe_dummy_object
(TYPE_PTRMEM_CLASS_TYPE (intype),

121

0);

122

decl = build_address (decl);

123

expr = get_member_function_from_ptrfunc
(&decl, expr);

124

}

125

}

126

else if (TREE_CODE (TREE_TYPE (expr)) ==
METHOD_TYPE)

127

{

128

if
(pedantic

|| warn_pmf2ptr

)

129

pedwarn ("converting from `%T' to
`%T'", intype, type);

130

expr = build_addr_func
(expr);

131

}

132

if (TREE_CODE (TREE_TYPE (expr)) ==
POINTER_TYPE)

133

return
build_nop (type, expr);

134

intype = TREE_TYPE (expr);

135

}

如果
intype

是方法指针的类型,这个转换可能是危险的代码;因此给出警告。而如果
expr

是一个
PTRMEM_CST
——一个成员指针常量,只需要获取这个成员的地址。不过,对于
expr

是指向方法的指针的情况,要求在调用
get_member_function_from_ptrfunc

中有隐含的
this
指针实参来解析这个指针。因而需要调用
maybe_dummy_object

来构建该类型用于解析的假的实例。

1717

tree

1718

maybe_dummy_object

(tree type, tree* binfop)
in
cp/tree.c

1719

{

1720

tree decl, context;

1721

tree binfo;

1722

1723

if (current_class_type

1724

&& (binfo = lookup_base
(current_class_type

, type,

1725

ba_ignore | ba_quiet, NULL)))

1726

context = current_class_type

;

1727

else

1728

{

1729

/*
Reference from a nested class member function.

*/

1730

context = type;

1731

binfo = TYPE_BINFO (type);

1732

}

1733

1734

if (binfop)

1735

*binfop = binfo;

1736

1737

if (current_class_ref

&&
context == current_class_type

1738

/*
Kludge: Make sure that current_class_type is actually

1739

correct. It might not be if we're in
the middle of

1740

tsubst_default_argument.
*/

1741

&& same_type_p
(TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref

)),

1742

current_class_type

))

1743

decl = current_class_ref

;

1744

else

1745

decl = build_dummy_object
(context);

1746

1747

return
decl;

1748

}

首先,为这个假的对象设立相应的上下文;如果“
this
”指针是可用的,就把它用作这个假对象;否则,通过下面的函数构建该对象的一个
NULL
指针。

1706

tree

1707

build_dummy_object

(tree type)
in
cp/tree.c

1708

{

1709

tree decl = build1
(NOP_EXPR, build_pointer_type
(type),
void_zero_node);

1710

return
build_indirect_ref
(decl, NULL);

1711

}

5.13.1.2.3.1.3.

在类指针之间

如果源类型及目标类型都是指向类的指针,它们必须有继承关系;否则就是一个错误。而如果目标类型是指向方法的指针,把其他类型的指针转换到它是不允许的。那么对于标量指针之间,及标量指针与类指针之间的转换,只需为该转换构建
NOP_EXPR


这包括了【
3
】条文
5.2.10

Reinterpret_cast
”,条款
7
所定义的情况:

7.
指向一个对象的指针可用被显式地转换到一个不同类型的对象。除了转换类型为“
T1
指针类型”的一个右值到类型“
T2
指针类型”(其中
T1

T2
是对象类型,并且
T2
所要求的对齐不小于
T1
),然后回到其初始类型,产生初始的指针值之外;这样的一个指针转换的结果是未定义的。

cp_convert_to_pointer (continue)

137

if (expr == error_mark_node)

138

return
error_mark_node;

139

140

form = TREE_CODE (intype);

141

142

if (POINTER_TYPE_P (intype))

143

{

144

intype = TYPE_MAIN_VARIANT (intype);

145

146

if (TYPE_MAIN_VARIANT (type) != intype

147

&& TREE_CODE (type) == POINTER_TYPE

148

&& TREE_CODE (TREE_TYPE (type)) ==
RECORD_TYPE

149

&& IS_AGGR_TYPE (TREE_TYPE (type))

150

&& IS_AGGR_TYPE (TREE_TYPE (intype))

151

&& TREE_CODE (TREE_TYPE (intype)) ==
RECORD_TYPE)

152

{

153

enum
tree_code code = PLUS_EXPR;

154

tree binfo;

155

tree intype_class;

156

tree type_class;

157

bool same_p;

158

159

intype_class = TREE_TYPE (intype);

160

type_class = TREE_TYPE (type);

161

162

same_p = same_type_p (TYPE_MAIN_VARIANT
(intype_class),

163

TYPE_MAIN_VARIANT
(type_class));

164

binfo = NULL_TREE;

165

/* Try derived to base conversion.
*/

166

if
(!same_p)

167

binfo = lookup_base
(intype_class, type_class, ba_check, NULL);

168

if
(!same_p && !binfo)

169

{

170

/* Try base to derived conversion.
*/

171

binfo = lookup_base
(type_class, intype_class, ba_check, NULL);

172

code = MINUS_EXPR;

173

}

174

if
(binfo == error_mark_node)

175

return
error_mark_node;

176

if
(binfo || same_p)

177

{

178

if (binfo)

179

expr = build_base_path
(code, expr, binfo, 0);

180

/* Add any qualifier conversions.
*/

181

return
build_nop (type, expr);

182

}

183

}

184

185

if (TYPE_PTRMEMFUNC_P (type))

186

{

187

error ("cannot convert `%E' from type
`%T' to type `%T'",

188

expr, intype, type);

189

return
error_mark_node;

190

}

191

192

return
build_nop (type, expr);

193

}

5.13.1.2.3.1.4.

指向成员的指针之间

下面,
TYPE_PTRMEM_P
成立,如果这是一个指向数据成员的指针。

注意到当到达这里,该语句一定通过了解析过程中的语法检查;因此
TREE_TYPE (type)
必定匹配下面的
TREE_TYPE (intype)
。在上面的例子中,该转换可以被隐式地执行;除非该转换是自虚拟基类——这只能通过
reinterpret_cast

来完成,正如【
3
】条文
5.2.10

Reinterpret_cast
”,条款
3
定义的:“


reinterpret_cast

执行的映射是由实现定义的。

[

注意:它可能,或可能不,
产生一个不同于原始值的表达

]

”。
GCC
选择对于这种
自虚拟基类的
转换不做任何事。考虑下面的例子:

class
C {};

class
D {

public
:

C dc;

};

class
B: public
virtual
D {

public
:

C bc;

};

C* func (B* b) { return
&b->bc; }

int main () {

D d;

func (&d);

return
0;

}

编译器给出如下的消息(它违反了【
3
】条文
4.11
“成员指针的转换”,条款
2
):

test2.cpp: In function ‘int
main()’:

test2.cpp:17: error:
invalid conversion from ‘D*’ to ‘B*’

test2.cpp:17:
error:
initializing argument 1 of ‘C*
func(B*)’

test2.cpp:17: error:
cannot convert from base ‘D’ to derived type ‘B’ via virtual base ‘D’

前两个
error
是在
convert_like_real


3944

3946
行给出的;最后一个则是在这里。

如果
type


intype

没有继承关系,注意到下面在
204

207
行的
lookup_base

将返回
NULL
(如果基类是不可访问或具二义性,将返回
error_mark_node

),这也是仅为
reinterpret_cast

所允许的情形,如下面【
3
】的条文
5.2.10

Reinterpret_cast
”:

9.
一个“指向具有类型
T1

X
成员的指针”的右值,可以被显式地转换到一个“指向具有类型
T2

Y
成员的指针”的右值,如果
T1

T2
都是函数类型或两者都是对象类型。空成员指针值(
4.11
)可以被转换到目的类型的空成员指针值。这个转换的结果是不确定的,除了以下情形以外:


转换“成员函数指针”类型的一个右值到另外的成员函数指针类型,再转换回原始类型,产生原始的成员指针值。


转换

“指向具有类型
T1

X
成员的指针”类型的一个右值到“指向具有类型
T2

Y
成员的指针”的类型(其中
T2
的对齐要求不强于
T1

no stricter
than
)),再转换回原始类型,产生原始的成员指针值。

看到其结果是不确定的,这就是为什么
reinterpret_cast

是一个危险的操作符,它应该被小心使用。对于
type


intype

不具有继承关系的情形,
GCC

236
行为之构建了
NOP_EXPR
。并且注意到如果我们能来到这里,相应的转换表达式必定通过了语法检查。

cp_convert_to_pointer (continue)

194

else if (TYPE_PTRMEM_P (type) &&
TYPE_PTRMEM_P (intype))

195

{

196

tree b1;

197

tree b2;

198

tree binfo;

199

enum
tree_code code = PLUS_EXPR;

200

base_kind bk;

201

202

b1 = TYPE_PTRMEM_CLASS_TYPE (type);

203

b2 = TYPE_PTRMEM_CLASS_TYPE (intype);

204

binfo = lookup_base
(b1, b2, ba_check, &bk);

205

if (!binfo)

206

{

207

binfo = lookup_base
(b2, b1, ba_check, &bk);

208

code = MINUS_EXPR;

209

}

210

if (binfo == error_mark_node)

211

return
error_mark_node;

212

213

if (bk == bk_via_virtual)

214

{

215

if
(force)

216

warning ("pointer to member cast from
`%T' to `%T' is via virtual base",

217

intype, type);

218

else

219

{

220

error ("pointer to member cast from
`%T' to `%T' is via virtual base",

221

intype, type);

222

return
error_mark_node;

223

}

224

/* This is a reinterpret cast, whose result is unspecified.

225

We choose to do nothing.
*/

226

return
build1
(NOP_EXPR, type,
expr);

227

}

228

229

if (TREE_CODE (expr) == PTRMEM_CST)

230

expr = cplus_expand_constant (expr);

231

232

if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))

233

expr =
size_binop

(code,

234

build_nop (sizetype, expr),

235

BINFO_OFFSET (binfo));

236

return
build_nop (type, expr);

237

}

238

else if (TYPE_PTRMEMFUNC_P (type) &&
TYPE_PTRMEMFUNC_P (intype))

239

return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);

而如果这些类型具有继承关系,前端会相应地调整类实例。

5.13.1.2.3.1.5.

从成员函数指针到其它指针类型

那么下面的代码处理以下与
reinterpret_cast

相关的情形:

4.
一个指针可用被显式地转换到任意足够大保存它的整数类型。其映射函数是实现定义的
[
注意:对于那些知道底层机器寻址结构的人来说,这不足为奇
]


5.
一个整数类型或枚举类型的值可以被显式地转换到一个指针。一个指针转换到足够大小的一个整数(如果在实现中有这样对象的存在),然后转换回同样的指针类型,将得到其原始值;指针与整数映射的其他方面则是由实现确定的。

6.
指向一个函数的指针可用被显式地转换到指向另一个函数类型的指针。通过一个指向别的函数类型的指针(
8.3.5
)来调用这个函数,其行为是未定义的。除了把类型“
T1
指针”的一个右值转换到“
T2
指针”类型(其中
T1

T2
都是函数类型),然后转换回其原始类型,产生原始的指针值之外,这样的一个指针转换的结果是不确定的。
[
注意:参考
4.10
,关于更多指针转换的细节
]


8.
空指针值(
4.10
)被转换到目的类型的空指针值。

下面的
type

是目的类型,而
form

应该是“
from
”的笔误。注意到成员指针不能保存在任一整数类型中,因为事实上,它包含了两个部分——对象及成员。

cp_convert_to_pointer (continue)

240

else if (TYPE_PTRMEMFUNC_P (intype))

241

{

242

if (!warn_pmf2ptr

)

243

{

244

if
(TREE_CODE (expr) == PTRMEM_CST)

245

return
cp_convert_to_pointer
(type,

246

PTRMEM_CST_MEMBER (expr),

247

force);

248

else if (TREE_CODE (expr) == OFFSET_REF)

249

{

250

tree object = TREE_OPERAND (expr, 0);

251

return
get_member_function_from_ptrfunc
(&object,

252

TREE_OPERAND (expr, 1));

253

}

254

}

255

error ("cannot convert `%E' from type
`%T' to type `%T'",

256

expr, intype, type);

257

return
error_mark_node;

258

}

259

260

if (integer_zerop
(expr))

261

{

262

if (TYPE_PTRMEMFUNC_P (type))

263

return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);

264

265

if (TYPE_PTRMEM_P (type))

266

/* A NULL
pointer-to-member is represented by -1, not by

267

zero.

*/

268

expr = build_int_2
(-1, -1);

269

else

270

expr = build_int_2
(0, 0);

271

TREE_TYPE (expr) = type;

272

/* Fix up the
representation of -1 if appropriate.
*/

273

force_fit_type
(expr, 0);

274

return
expr;

275

}

276

else if (TYPE_PTR_TO_MEMBER_P (type)
&& INTEGRAL_CODE_P (form))

277

{

278

error ("invalid conversion from '%T'
to '%T'", intype, type);

279

return
error_mark_node;

280

}

281

282

if (INTEGRAL_CODE_P (form))

283

{

284

if (TYPE_PRECISION (intype) == POINTER_SIZE)

285

return
build1
(CONVERT_EXPR, type, expr);

286

expr = cp_convert (c_common_type_for_size
(POINTER_SIZE, 0), expr);

287

/* Modes may be
different but sizes should be the same.

*/

288

if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE
(expr)))

289

!= GET_MODE_SIZE (TYPE_MODE (type)))

290

/* There is
supposed to be some integral type

291

that is the same width as a pointer.
*/

292

abort ();

293

return
convert_to_pointer (type, expr);

294

}

295

296

if (type_unknown_p (expr))

297

return
instantiate_type
(type, expr, tf_error |
tf_warning);

298

299

error ("cannot convert `%E' from type
`%T' to type `%T'",

300

expr, intype, type);

301

return
error_mark_node;

302

}

现在回到
ocp_convert

中的过程。注意下面的
e

来自
expr

,因此
720
行的
dtype

是表达式的类型;而
code

是目的类型的节点编码。那么如果目的类型是类类型,如
729
行所示,如果源类型与目的类型具有继承关系,或者源类型定义了到目的类型的转换操作符,这个转换是可能的。

ocp_convert
(continue)

705

(code == VECTOR_TYPE)

706

return
fold
(convert_to_vector (type, e));

707

if (code == REAL_TYPE || code ==
COMPLEX_TYPE)

708

{

709

if (IS_AGGR_TYPE (TREE_TYPE (e)))

710

{

711

tree rval;

712

rval = build_type_conversion (type, e);

713

if (rval)

714

return
rval;

715

else

716

if (flags & LOOKUP_COMPLAIN)

717

error ("`%#T' used where a
floating point value was expected",

718

TREE_TYPE (e));

719

}

720

if (code == REAL_TYPE)

710

return
fold (convert_to_real (type, e));

711

else if (code == COMPLEX_TYPE)

712

return
fold (convert_to_complex (type, e));

713

}

714

715

/* New C++
semantics: since assignment is now based on

716

memberwise
copying, if the rhs type is derived from the

717

lhs type, then we
may still do a conversion.
*/

718

if (IS_AGGR_TYPE_CODE (code))

719

{

720

tree dtype = TREE_TYPE (e);

721

tree ctor = NULL_TREE;

722

723

dtype = TYPE_MAIN_VARIANT (dtype);

724

725

/* Conversion
between aggregate types. New C++ semantics allow

726

objects of
derived type to be cast to objects of base type.

727

Old semantics only allowed this between
pointers.

728

729

There may be some ambiguity between using a
constructor

730

vs. using a type conversion operator when both
apply.
*/

731

732

ctor = e;

733

734

if (abstract_virtuals_error
(NULL_TREE, type))

735

return
error_mark_node;

736

737

if ((flags & LOOKUP_ONLYCONVERTING)

738

&& ! (IS_AGGR_TYPE (dtype)
&& DERIVED_FROM_P
(type, dtype)))

739

/* For
copy-initialization, first we create a temp of the proper type

740

with a user-defined conversion sequence,
then we direct-initialize

741

the
target with the temp (see [dcl.init]).

*/

742

ctor = build_user_type_conversion
(type, ctor,
flags);

743

else

744

ctor = build_special_member_call
(NULL_TREE,

745

complete_ctor_identifier

,

746

build_tree_list (NULL_TREE, ctor),

747

TYPE_BINFO
(type), flags);

748

if (ctor)

749

return
build_cplus_new
(type, ctor);

750

}

751

752

if (flags & LOOKUP_COMPLAIN)

753

error ("conversion from `%T' to
non-scalar type `%T' requested",

754

TREE_TYPE (expr), type);

755

if (flags & LOOKUP_SPECULATIVELY)

756

return
NULL_TREE;

757

return
error_mark_node;

758

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: