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

来源:互联网 发布:sql substr 编辑:程序博客网 时间:2024/06/10 03:49

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, treeexpr, bool force)                                     incvt.c

78      {

79        tree intype = TREE_TYPE (expr);

80        enumtree_code form;

81        tree rval;

82        if (intype == error_mark_node)

83          returnerror_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 incompletetype `%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_conversionbuild_user_type_conversion的定义如下。显然它查找这个用户定义的转换操作符,并产生执行转换的代码。

 

995    tree

996    build_type_conversion (tree xtype, treeexpr)                                                    incvt.c

997    {

998      /* C++: check tosee if we can convert this aggregate type

999        into the requiredtype.  */

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     structz_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     returnNULL_TREE;

2535   }

5.13.1.2.3.1.2.         void*或函数指针

那么在下面的type是转换的目标类型,106行的条件为“void*”或函数指针的type所满足。而intype是表达式expr的类型。

 

cp_convert_to_pointer (continue)

 

105      /* Handleanachronistic 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 animplicit 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)                                            incp/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 inthe 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   returndecl;

1748 }

 

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

 

1706 tree

1707 build_dummy_object(tree type)                                                                  incp/tree.c

1708 {

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

1710   returnbuild_indirect_ref (decl, NULL);

1711 }

5.13.1.2.3.1.3.         在类指针之间

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

这包括了【3】条文5.2.10Reinterpret_cast”,条款7所定义的情况:

7. 指向一个对象的指针可用被显式地转换到一个不同类型的对象。除了转换类型为“T1指针类型”的一个右值到类型“T2指针类型”(其中T1T2是对象类型,并且T2所要求的对齐不小于T1),然后回到其初始类型,产生初始的指针值之外;这样的一个指针转换的结果是未定义的。

 

cp_convert_to_pointer (continue)

 

137      if (expr == error_mark_node)

138        returnerror_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          enumtree_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        returnbuild_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.10Reinterpret_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 ‘intmain()’:

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_real39443946行给出的;最后一个则是在这里。

如果typeintype没有继承关系,注意到下面在204207行的lookup_base将返回NULL(如果基类是不可访问或具二义性,将返回error_mark_node),这也是仅为reinterpret_cast所允许的情形,如下面【3】的条文5.2.10Reinterpret_cast”:

9. 一个“指向具有类型T1X成员的指针”的右值,可以被显式地转换到一个“指向具有类型T2Y成员的指针”的右值,如果T1T2都是函数类型或两者都是对象类型。空成员指针值(4.11)可以被转换到目的类型的空成员指针值。这个转换的结果是不确定的,除了以下情形以外:

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

转换 “指向具有类型T1X成员的指针”类型的一个右值到“指向具有类型T2Y成员的指针”的类型(其中T2的对齐要求不强于T1no stricter than)),再转换回原始类型,产生原始的成员指针值。

看到其结果是不确定的,这就是为什么reinterpret_cast是一个危险的操作符,它应该被小心使用。对于typeintype不具有继承关系的情形,GCC236行为之构建了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        returnbuild_nop (type, expr);

237      }

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

239        returnbuild_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指针”类型(其中T1T2都是函数类型),然后转换回其原始类型,产生原始的指针值之外,这样的一个指针转换的结果是不确定的。[注意:参考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        returnerror_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 NULLpointer-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 therepresentation of -1 if appropriate.  */

273        force_fit_type(expr, 0);

274        returnexpr;

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        returnerror_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 bedifferent 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 issupposed to be some integral type

291            that is the same width as a pointer.  */

292          abort ();

293        returnconvert_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      returnerror_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            returnrval;

715          else

716            if (flags & LOOKUP_COMPLAIN)

717              error ("`%#T' used where afloating point value was expected",

718                   TREE_TYPE (e));

719        }

720        if (code == REAL_TYPE)

710          returnfold (convert_to_real (type, e));

711         else if (code == COMPLEX_TYPE)

712          returnfold (convert_to_complex (type, e));

713      }

714   

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

716        memberwisecopying, if the rhs type is derived from the

717        lhs type, then wemay 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        /* Conversionbetween aggregate types. New C++ semantics allow

726          objects ofderived type to be cast to objects of base type.

727          Old semantics only allowed this betweenpointers.

728   

729          There may be some ambiguity between using aconstructor

730          vs. using a type conversion operator when bothapply.  */

731   

732        ctor = e;

733   

734        if (abstract_virtuals_error(NULL_TREE, type))

735          returnerror_mark_node;

736   

737        if ((flags & LOOKUP_ONLYCONVERTING)

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

739          /* Forcopy-initialization, first we create a temp of the proper type

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

741            thetarget 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' tonon-scalar type `%T' requested",

754             TREE_TYPE (expr), type);

755      if (flags & LOOKUP_SPECULATIVELY)

756        returnNULL_TREE;

757      returnerror_mark_node;

758    }

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机打字键盘上没有语音功能怎么办 网贷催收发语音侮辱人怎么办 康力无机房电梯到楼层不关门怎么办 档案工龄少算了工资领开了怎么办 别人骚扰我打电话报警人走了怎么办 因外借医保卡被香港保险拒保怎么办 医保和社保断了一个月怎么办 苹果8呼叫受限请勿越权使用怎么办 药物储存2~8度没冰箱怎么办 利仁分体电饼铛做饼熟的慢怎么办 闲鱼买的东西自提有问题怎么办 老板油烟机的表层的膜掉了怎么办 给老板打工老板跑路了怎么办 公司要业务员承担客户的欠款怎么办 从自己公司出去抢自己客户怎么办? 在苏宁买东西买贵了怎么办 苏宁购物小票不见了未提货怎么办 结痂的地方扣掉了颜色不一样怎么办 实体店买手机不给发票怎么办 小孩学英语字母怎么都记不住怎么办 聊客老是提示网络连接失败怎么办? 天猫购物漏发客服不理怎么办 京东二维码被骗怎么办联系客服号码 京东客服打电话来让自己退款怎么办 淘宝上买到的衣服是坏的怎么办 淘宝上买到的产品是坏的怎么办? 在淘宝买到东西是坏的怎么办 冰箱冷冻室门生锈变形关不严怎么办 诲信电冰箱电脑板坏了怎么办 冰箱里放了热水后就不制冷了怎么办 双温冰柜冷藏矿泉水不冰怎么办 美的电饭煲e一传感器也没坏怎么办 美的电饭煲不工作显示C3怎么办 美的电饭煲啪一声响不工作了怎么办 误给宝宝吃了坏的饭怎么办 鼠标没反应键盘指示灯不亮怎么办 新买变频冰箱风机声音大怎么办 三星手机玩王者荣耀一直闪退怎么办 刚申请的阿里大宝卡不想要了怎么办 国美刚买不到一个月电视坏了怎么办 交保险后保险公司不给开收据怎么办