Studying note of GCC-3.4.6 source (154)

5.13.1.2.3.1.  Case study: to pointer conversion

5.13.1.2.3.1.1.          From class to pointer

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

 

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      }

 

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

 

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

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

 

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      }

 

If intype is of type of method pointer, this conversion may be dangerous code; so gives warning about it. Then if expr is a PTRMEM_CST which is a pointer-to-member constants; 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_ptrfunc to resolve the pointer. So it needs maybe_dummy_object to create the dummy instance of the type for the resolution.

 

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 }

 

First of all, sets up the corresponding context for the dummy object; 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)                                                                  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.          Between pointers of class

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

It includes case 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        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.          Between pointers-to-member

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

Note that when arriving here, the statement must pass the semantic checking during parsing the assignment; so TREE_TYPE (type) must match TREE_TYPE (intype) below. In above example, the conversion can be done implicitly except the conversion is from virtual 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, produce a representation different from the original value.] ”. GCC selects to do nothing for this kind of conversion involves virtual base. Consider below example:

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 compile gives below messages (it a violation of [3], clause 4.11 “pointer to member conversions”, terms 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’

The former two are issued at line 3944, 3946 in convert_like_real , the last one is given here.

If type and intype haven’t inheritant relation, note that lookup_base below at line 204 and 207 should return NULL (it would return error_mark_node when base is inaccessible or ambiguous), which is also only allowed by reinterpret_cast as 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_cast is a dangerous operator and should be used with care. For the case of type and intype haven’t inheritant relation,, GCC builds the NOP_EXPR at line 236. And note that if we can come here, the corresponding conversion expression must pass the semantics 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        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);

 

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

5.13.1.2.3.1.5.          From pointers-to-method to other pointer type

Then below code 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 form should be slip of a pen of “from”. And note that pointer-to-member can’t be held by any integer type as it in fact contains two parts – the object and the member.

 

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    }

 

Now back to procedure of ocp_convert . Note e below comes from expr , so dtype at line 720 is the type of the expression; and code is the tree code of target type. Then if the target type is class type as line 729 indicates, the conversion is possible if the source type has inheritance relation with the target, 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            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    }

 

你可能感兴趣的:(Studying note of GCC-3.4.6 source (154))