Studying note of GCC-3.4.6 source (163)

5.13.4.7.1.2.  Do appropriate conversion for arguments

In this section, we go a little deeper to see in detail how to match the argument with the parameter, and do necessary conversion appropriately.

In C++ front-end, function parameters are recorded by TYPE_ARG_TYPES field in the FUNCTION_TYPE, which is a chain of tree_list, and in which TREE_VALUE of each node in this list is the type of the corresponding parameter; the TREE_PURPOSE is an expression for the default argument value, if any. If the last node in the list is void_list_node (a TREE_LIST node whose TREE_VALUE is the void_type_node ), then functions of this type do not take variable arguments. Otherwise, they do take a variable number of arguments. And arguments of the function would be constructed into a chain of tree_list, in which TREE_VALUE of each node is a representation of an assignment-expression.

In below function, arguments typelist is the tree_list for parameters and values is the tree_list for arguments for the function. So in case of no variable number parameters (typelist is ended by void_list_node ), typelist has the same length as values (at this point, any default argument used has been added into values ). Condition at line 2573 filters out the error case as we are pushing typelist and values with the same speed.

The detail of determining the conversion sequence and executing the real conversion is given in section Preliminaries - detail of conversion .

 

2538 tree

2539 convert_arguments (tree typelist, tree values, tree fndecl, int flags)                in typeck.c

2540 {

2541    tree typetail, valtail;

2542    tree result = NULL_TREE;

2543    const char *called_thing = 0;

2544    int i = 0;

2545

2546     /* Argument passing is always copy-initialization.  */

2547    flags |= LOOKUP_ONLYCONVERTING;

2548

2549    if (fndecl)

2550    {

2551      if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)

2552      {

2553        if (DECL_NAME (fndecl) == NULL_TREE

2554           || IDENTIFIER_HAS_TYPE_VALUE (DECL_NAME (fndecl)))

2555          called_thing = "constructor";

2556        else

2557          called_thing = "member function";

2558      }

2559      else

2560        called_thing = "function";

2561    }

2562

2563    for (valtail = values, typetail = typelist;

2564        valtail;

2565         valtail = TREE_CHAIN (valtail), i++)

2566    {

2567      tree type = typetail ? TREE_VALUE (typetail) : 0;

2568      tree val = TREE_VALUE (valtail);

2569

2570      if (val == error_mark_node)

2571        return error_mark_node;

2572

2573      if (type == void_type_node)

2574      {

2575        if (fndecl)

2576        {

2577          cp_error_at ("too many arguments to %s `%+#D'", called_thing,

2578                     fndecl);

2579          error ("at this point in file");

2580        }

2581        else

2582           error ("too many arguments to function");

2583        /* In case anybody wants to know if this argument

2584          list is valid.  */

2585        if (result)

2586          TREE_TYPE (tree_last (result)) = error_mark_node;

2587        break ;

2588      }

2589

2590      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.

2591        Strip such NOP_EXPRs, since VAL is used in non-lvalue context.  */

2592      if (TREE_CODE (val) == NOP_EXPR

2593         && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))

2594         && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))

2595        val = TREE_OPERAND (val, 0);

2596

2597      if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)

2598      {

2599        if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE

2600            || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE

2601           || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)

2602          val = decay_conversion (val);

2603      }

2604

2605      if (val == error_mark_node)

2606         return error_mark_node;

2607

2608      if (type != 0)

2609      {

2610        /* Formal parm type is specified by a function prototype.  */

2611        tree parmval;

2612

2613        if (!COMPLETE_TYPE_P (complete_type (type)))

2614        {

2615          if (fndecl)

2616            error ("parameter %P of `%D' has incomplete type `%T'",

2617                  i, fndecl, type);

2618          else

2619            error ("parameter %P has incomplete type `%T'", i, type);

2620          parmval = error_mark_node;

2621        }

2622        else

2623        {

2624          parmval = convert_for_initialization

2625                                    (NULL_TREE, type, val, flags,

2626                                      "argument passing", fndecl, i);

2627          parmval = convert_for_arg_passing (type, parmval);

2628        }

2629

2630        if (parmval == error_mark_node)

2631          return error_mark_node;

2632

2633        result = tree_cons (NULL_TREE, parmval, result);

2634      }

2635      else

2636      {

2637        if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)

2638          val = convert_from_reference (val);

2639

2640        if (fndecl && DECL_BUILT_IN (fndecl)

2641           && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)

2642          /* Don't do ellipsis conversion for __built_in_constant_p

2643            as this will result in spurious warnings for non-POD

2644            types.  */

2645          val = require_complete_type (val);

2646        else

2647          val = convert_arg_to_ellipsis (val);

2648

2649        result = tree_cons (NULL_TREE, val, result);

2650      }

2651

2652      if (typetail)

2653        typetail = TREE_CHAIN (typetail);

2654    }

 

If type is the type specified in the function prototype, as line 2608 indicates, it needs ensure that the argument can be converted to the type of the parameter and then does the conversion (see that handling argument passed mostly like placing it at right hand of assignment expression). After that convert_for_arg_passing provides special conversion for argument passing based on the target platform the code generated for. Here is the detail of convert_for_initialization .

 

5809 tree

5810 convert_for_initialization (tree exp, tree type, tree rhs, int flags,                     in typeck.c

5811                        const char *errtype, tree fndecl, int parmnum)

5812 {

5813    enum tree_code codel = TREE_CODE (type);

5814    tree rhstype;

5815    enum tree_code coder;

5816

5817    /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.

5818      Strip such NOP_EXPRs, since RHS is used in non-lvalue context.  */

5819    if (TREE_CODE (rhs) == NOP_EXPR

5820        && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0))

5821        && codel != REFERENCE_TYPE)

5822      rhs = TREE_OPERAND (rhs, 0);

5823

5824    if (rhs == error_mark_node

5825       || (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))

5826      return error_mark_node;

5827

5828    if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)

5829      rhs = convert_from_reference (rhs);

5830

5831    if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE

5832        && TREE_CODE (type) != ARRAY_TYPE

5833        && (TREE_CODE (type) != REFERENCE_TYPE

5834             || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))

5835        || (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE

5836           && (TREE_CODE (type) != REFERENCE_TYPE

5837               || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE))

5838        || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)

5839      rhs = decay_conversion (rhs);

5840

5841    rhstype = TREE_TYPE (rhs);

5842    coder = TREE_CODE (rhstype);

5843

5844    if (coder == ERROR_MARK)

5845      return error_mark_node;

5846

5847     /* We accept references to incomplete types, so we can

5848      return here before checking if RHS is of complete type.  */

5849      

5850    if (codel == REFERENCE_TYPE)

5851    {

5852      /* This should eventually happen in convert_arguments.  */

5853      int savew = 0, savee = 0;

5854

5855      if (fndecl)

5856        savew = warningcount , savee = errorcount ;

5857      rhs = initialize_reference (type, rhs, /*decl=*/ NULL_TREE,

5858                           /*cleanup=*/ NULL);

5859      if (fndecl)

5860      {

5861        if (warningcount > savew)

5862          cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl);

5863        else if (errorcount > savee)

5864          cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);

5865      }

5866      return rhs;

5867    }     

5868

5869    if (exp != 0)

5870      exp = require_complete_type (exp);

5871    if (exp == error_mark_node)

5872      return error_mark_node;

5873

5874    rhstype = non_reference (rhstype);

5875

5876    type = complete_type (type);

5877

5878    if (IS_AGGR_TYPE (type))

5879      return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);

5880

5881    return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);

5882 }

 

First, argument passed having (rhs ) reference type (but the parameter isn’t) should have its value copied as this reference should be ignored, so it needs build an INDIRECT_REF expression for the purpose. Condition at line 5831, says if 1) we pass an array to the parameter that is neither of type array, nor of the reference type of the array; or 2) pass a function (in fact, its address), but the parameter is neither of function type, nor of the reference type of the function; or 3) pass a method (in fact, its address, and note that method can’t be referenced because it requires implicit argument of ‘this’ pointer); it decays rhs according to lvalue-to-rvalue conversion.

Next if the parameter is of reference type, argument passed in would be referred instead of copying the value. It is handled differently than value-copy done by initialize_reference . Section Case of conversion for reference type shows the procedure of determining the conversion sequence from argument to the reference type of parameter by reference_binding , which returns NULL if no such conversion sequence exists or “ICS_BAD_FLAG (conv)” holds if the conversion is not allowed.

 

6120 tree

6121 initialize_reference (tree type, tree expr, tree decl, tree *cleanup)                           in call.c

6122 {

6123    tree conv;

6124

6125    if (type == error_mark_node || error_operand_p (expr))

6126      return error_mark_node;

6127

6128    conv = reference_binding (type, TREE_TYPE (expr), expr, LOOKUP_NORMAL);

6129    if (!conv || ICS_BAD_FLAG (conv))

6130    {

6131      if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)

6132          && !real_lvalue_p (expr))

6133        error ("invalid initialization of non-const reference of "

6134             "type '%T' from a temporary of type '%T'",

6135             type, TREE_TYPE (expr));

6136      else

6137        error ("invalid initialization of reference of type "

6138             "'%T' from expression of type '%T'", type,

6139             TREE_TYPE (expr));

6140        return error_mark_node;

6141    }

        // …

6177    my_friendly_assert (TREE_CODE (conv) == REF_BIND, 20030302);

6178    if (decl)

6179    {

         

6268      return build_nop (type, expr);

6269    }

6270

6271    /* Perform the conversion.  */

6272    return convert_like (conv, expr);

6273 }

 

Above if argument decl is non-NULL, it is the VAR_DECL being initialized with the expr . In our scenario here, decl is NULL as we are handling call arguments, it needs compiler to create the temparory artificially. And convert_like at line 6272 is just a simple wrapper of convert_like_real ; it can simply call the function doing the conversion as we don’t need worry about the lifetime of the argument for the parameter by reference.

While if the parameter is not of reference type, the argument should be copied. As precondition, the type definition must be already completed for both argument and parameter. Further note that rhstype gives the type of argument, if we use a reference as argument, the reference semantics should be abandoned from the type (see above we have built INDIRECT_REF for using value of the argument), here non_reference helps us to fetch the underling type be referred.

Next if the parameter is a class type, it needs invoke appropriate constructor to build the instance from the argument, which is the duty of ocp_convert above. Note that argument flags in it is LOOKUP_NORMAL (bitset LOOKUP_PROTECT | LOOKUP_COMPLAIN), which forces the function to look for matching constructor but skip conversion operations; and argument convtype is bitset CONV_IMPLICIT|CONV_FORCE_TEMP, which indicates to look for implicit conversion and needs a temporary to hold the result.

For function parameter of other non-reference types, it follows the same rule as assignment, that is the function argument can be regarded as the part of right hand side of an expression.

 

5712 static tree

5713 convert_for_assignment (tree type, tree rhs,                                                in typeck.c

5714                       const char *errtype, tree fndecl, int parmnum)

5715 {

5716    tree rhstype;

5717    enum tree_code coder;

5718

5719     /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */

5720    if (TREE_CODE (rhs) == NON_LVALUE_EXPR)

5721      rhs = TREE_OPERAND (rhs, 0);

5722

5723    rhstype = TREE_TYPE (rhs);

5724    coder = TREE_CODE (rhstype);

5725

5726    if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE

5727       && ((*targetm .vector_opaque_p) (type)

5728            || (*targetm .vector_opaque_p) (rhstype)))

5729      return convert (type, rhs);

5730

5731    if (rhs == error_mark_node || rhstype == error_mark_node)

5732      return error_mark_node;

5733    if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)

5734      return error_mark_node;

5735

5736    /* The RHS of an assignment cannot have void type.  */

5737    if (coder == VOID_TYPE)

5738    {

5739      error ("void value not ignored as it ought to be");

5740      return error_mark_node;

5741    }

5742

5743    /* Simplify the RHS if possible.  */

5744    if (TREE_CODE (rhs) == CONST_DECL)

5745      rhs = DECL_INITIAL (rhs);

5746   

5747    /* We do not use decl_constant_value here because of this case:

5748

5749       const char* const s = "s";

5750 

5751      The conversion rules for a string literal are more lax than for a

5752      variable; in particular, a string literal can be converted to a

5753      "char *" but the variable "s" cannot be converted in the same

5754      way. If the conversion is allowed, the optimization should be

5755      performed while creating the converted expression.  */

5756

5757    /* [expr.ass]

5758

5759      The expression is implicitly converted (clause _conv_) to the

5760      cv-unqualified type of the left operand.

5761

5762      We allow bad conversions here because by the time we get to this point

5763      we are committed to doing the conversion. If we end up doing a bad

5764      conversion, convert_like will complain.  */

5765    if (!can_convert_arg_bad (type, rhstype, rhs))

5766    {

5767      /* When -Wno-pmf-conversions is use, we just silently allow

5768        conversions from pointers-to-members to plain pointers. If

5769        the conversion doesn't work, cp_convert will complain.  */

5770      if (!warn_pmf2ptr

5771         && TYPE_PTR_P (type)

5772         && TYPE_PTRMEMFUNC_P (rhstype))

5773        rhs = cp_convert (strip_top_quals (type), rhs);

5774      else

5775      {

5776        /* If the right-hand side has unknown type, then it is an

5777          overloaded function. Call instantiate_type to get error

5778          messages.  */

5779        if (rhstype == unknown_type_node)

5780          instantiate_type (type, rhs, tf_error | tf_warning);

5781        else if (fndecl)

5782          error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",

5783               rhstype, type, parmnum, fndecl);

5784        else

5785          error ("cannot convert `%T' to `%T' in %s", rhstype, type,

5786                errtype);

5787        return error_mark_node;

5788      }

5789    }

5790    return perform_implicit_conversion (strip_top_quals (type), rhs);

5791 }

 

Comments above explain the special treatment in conversion in assignment. The conversion of argument to parameter type is also subject to implicit conversion. Below function like can_convert_arg to look for the conversion sequence but but allows dubious conversions as well.

 

6005 bool

6006 can_convert_arg_bad (tree to, tree from, tree arg)                                              in call.c

6007 {

6008    return implicit_conversion (to, from, arg, LOOKUP_NORMAL) != 0;

6009 }

 

Here the parameter is not of reference type, then the converted argument would get its value copied before later use, so it just needs convert the argument to the type without top cv-qualifier of the parameter. The rest is the same as other ways of conversion.

Back convert_arguments , for the ellipse arguments at line 2635, for argument of reference but parameter of non-reference here, the argument’s value is what we interest. At line 2641, code BUILT_IN_CONSTANT_P goes with builtin function “constant_p”, which accepts variable arguments and tells if its argument(s) is(are) constant or not. And see that convert_arg_to_ellipsis at line 2647, it gives out warning when the argument is of non-POD type which can be passed to constant_p which only evaluates the constantness and cares nothing else. So it needesn’t take trouble to invoke convert_arg_to_ellipsis .

Then following code processes the case of default argument, it is the same as that we have seen in procedure of finding user-defined conversion in implicit conversion.

 

convert_arguments (continue)

 

2656    if (typetail != 0 && typetail != void_list_node)

2657    {

2658       /* See if there are default arguments that can be used.  */

2659      if (TREE_PURPOSE (typetail)

2660         && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)

2661      {

2662        for (; typetail != void_list_node; ++i)

2663        {

2664          tree parmval

2665                = convert_default_arg (TREE_VALUE (typetail),

2666                                    TREE_PURPOSE (typetail),

2667                                   fndecl, i);

2668

2669          if (parmval == error_mark_node)

2670            return error_mark_node;

2671

2672          result = tree_cons (0, parmval, result);

2673          typetail = TREE_CHAIN (typetail);

2674           /* ends with `...'.  */

2675          if (typetail == NULL_TREE)

2676            break ;

2677        }

2678      }

2679      else

2680      {

2681        if (fndecl)

2682        {

2683          cp_error_at ("too few arguments to %s `%+#D'",

2684                     called_thing, fndecl);

2685          error ("at this point in file");

2686        }

2687        else

2688          error ("too few arguments to function");

2689        return error_mark_list ;

2690      }

2691    }

2692

2693    return nreverse (result);

2694 }

 

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