Studying note of GCC-3.4.6 source (154)

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

5.13.1.2.3.1. Casestudy: to pointer conversion

5.13.1.2.3.1.1.         From class to pointer

Conversion to pointers is interesting, it worthes a look. Thefunction handling this conversion is cp_convert_to_pointer below. Class can onlybe converted to pointer type if it defines a user-defined conversion to do so.

 

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      }

 

Function build_type_conversion, and build_user_type_conversionhave below definitions. Clearly, it searches the operator defined by user, andemits code to perform this conversion.

 

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.         To void* or function pointer

Then below type is the target of the conversion, conditionat line 106 is satisfied by type of void* or function pointer. And intypeis the type of expression (expr) below.

 

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      }

 

If intypeis of type of method pointer, this conversion may be dangerous code; so giveswarning about it. Then if expr is a PTRMEM_CST which is a pointer-to-memberconstants; it just takes the address of the method speicifed. However, for expr of pointer-to-member,it requires the implicit this argument in invoking get_member_function_from_ptrfuncto resolve the pointer. So it needs maybe_dummy_object to create the dummyinstance of the type for the resolution.

 

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 }

 

First of all, sets up the corresponding context for the dummyobject; if “this” pointer is available, just uses it as the dummy object;otherwise, builds a NULL pointer of the object by below function.

 

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.         Between pointers of class

If both source and target types are pointers to class, they musthave inheritance relation; otherwise it is an error. Then if the target type ispointer-to-method, converting other pointer type to it is not allowed. Then forcase of between pointer-to-scalar and pointer-to-scalar, and case of betweenpointer-to-scalar and pointer-to-class, just builds NOP_EXPR for theconversion.

It includescase as [3] clause 5.2.10“Reinterpret_cast”, terms 7 defines below:

7. A pointer to an object can be explicitly converted to a pointer to an object of different type. Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.

 

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          boolsame_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.         Between pointers-to-member

Below, TYPE_PTRMEM_P holds if it is a pointer to data-member of aclass.

Note that when arrivinghere, the statement must pass the semantic checking during parsing theassignment; so TREE_TYPE (type) must match TREE_TYPE (intype) below. In aboveexample, the conversion can be done implicitly except the conversion is fromvirtual base, which should only be executed by reinterpret_cast, as [3] clause 5.2.10“Reinterpret_cast”, terms 3 defines: “The mapping performed by reinterpret_cast is implementation-defined. [Note: it might, or might not, producea representation different from the original value.]”. GCC selectsto do nothing for this kind of conversion involves virtual base. Consider belowexample:

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;

}

The compilegives below messages (it a violation of [3], clause 4.11 “pointer to memberconversions”, terms 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’

The formertwo are issued at line 3944, 3946 inconvert_like_real,the last one is given here.

If type and intype haven’t inheritant relation,note that lookup_basebelow at line 204 and 207 should return NULL (it would return error_mark_nodewhen base is inaccessible or ambiguous), which is also only allowed by reinterpret_castas below [3] clause 5.2.10“Reinterpret_cast”:

9. An rvalue of type “pointer to member of X of type T1” can be explicitly converted to an rvalue of type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. The null member pointer value (4.11) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:

— converting an rvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.

— converting an rvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer to member value.

See the result is unspecified, that is why reinterpret_castis a dangerous operator and should be used with care. For the case of type andintypehaven’t inheritant relation,, GCC builds the NOP_EXPR at line 236. And notethat if we can come here, the corresponding conversion expression must pass thesemantics checking.

 

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);

 

And if those types have inheritant relation, the front-end needsadjust the class instances appropriately.

5.13.1.2.3.1.5.         From pointers-to-method toother pointer type

Then belowcode handles the following cases related to reinterpret_cast.

4. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined [Note: it is intended to be unsurprising to those who know the addressing structure of the underlying machine.]

5. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.

6. A pointer to a function can be explicitly converted to a pointer to a function of a different type. The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined. Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [Note: see also 4.10 for more details of pointer conversions.]

8. The null pointer value (4.10) is converted to the null pointer value of the destination type.

Below type is the target type, and formshould be slip of a pen of “from”. And note that pointer-to-member can’t beheld by any integer type as it in fact contains two parts – the object and themember.

 

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    }

 

Now back to procedure of ocp_convert. Note e below comes from expr, sodtypeat line 720 is the type of the expression; and code is the tree code of targettype. Then if the target type is class type as line 729 indicates, theconversion is possible if the source type has inheritance relation with thetarget, or the source type defines user-defined conversion to the target type.

 

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

754             TREE_TYPE (expr), type);

755      if (flags & LOOKUP_SPECULATIVELY)

756        returnNULL_TREE;

757      returnerror_mark_node;

758    }