Studying note of GCC-3.4.6 source (130)

5.12.5.2.2.2.  Handling the body

Before going deeper into the function-body, which forms a new binding scope of block-scope, any pendding accessibility checkings should be performed to find out the illegal visit early.

 

cp_parser_function_definition_from_specifiers_and_declarator (continue)

 

14329   /* If there were names looked up in the decl-specifier-seq that we

14330     did not check, check them now. We must wait until we are in the

14331     scope of the function to perform the checks, since the function

14332     might be a friend.  */

14333   perform_deferred_access_checks ();

14334

14335   if (!success_p)

14336   {

14337     /* If begin_function_definition didn't like the definition, skip

14338       the entire function.  */

14339     error ("invalid function declaration");

14340     cp_parser_skip_to_end_of_block_or_statement (parser);

14341     fn = error_mark_node;

14342   }

14343   else

14344     fn = cp_parser_function_definition_after_declarator (parser,

14345                                                /*inline_p=*/ false);

14346

14347   return fn;

14348 }

 

We have seen cp_parser_function_definition_after_declarator in section 5.12.3.2.1.2.1.1.Parse function body . In it, cp_parser_ctor_initializer_opt_and_function_body parses the function-body and possible initializer for constructor. And in this function, begin_function_body prepares the root of sub-tree for the compound-statement, and the enclosing scope. After that, the relevant part of the intermediate tree now looks like below one.

(Click here for open )

And cp_parser_function_body handles the body which is a compound-statement.

 

11460 static void

11461 cp_parser_function_body (cp_parser *parser)                                            in parser.c

11462 {

11463   cp_parser_compound_statement (parser, false);

11464 }

 

5651   static tree

5652   cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)

5653   {

5654     tree compound_stmt;

5655  

5656     /* Consume the `{'.  */

5657     if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))

5658       return error_mark_node;

5659     /* Begin the compound-statement.  */

5660     compound_stmt = begin_compound_stmt (/*has_no_scope=*/ false);

5661     /* Parse an (optional) statement-seq.  */

5662     cp_parser_statement_seq_opt (parser, in_statement_expr_p);

5663     /* Finish the compound-statement.  */

5664     finish_compound_stmt (compound_stmt);

5665     /* Consume the `}'.  */

5666     cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");

5667  

5668     return compound_stmt;

5669   }

 

Another enclosing scope is created before handling the tokens following “{“, it is because former block-scope is built for the optional constructor initializer, and the one created here is really for the body.

(Click here for open )

 

5677   static void

5678   cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)       in parser.c

5679   {

5680     /* Scan statements until there aren't any more.  */

5681     while (true)

5682     {

5683       /* If we're looking at a `}', then we've run out of statements.  */

5684       if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)

5685          || cp_lexer_next_token_is (parser->lexer, CPP_EOF))

5686         break ;

5687  

5688        /* Parse the statement.  */

5689       cp_parser_statement (parser, in_statement_expr_p);

5690     }

5691   }

 

Deep into the callstack: cp_parser_statement à cp_parser_declaration_statement à cp_parser_block_declaration à cp_parser_simple_declaration , cp_parser_decl_specifier_seq parses the type-specifier for the first declaration by cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name à cp_parser_class_name to find out the template-id of “SmallObject<>”.

 

5425   static void

5426   cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)             in parser.c

5427   {

5428     tree statement;

5429     cp_token *token;

5430     int statement_line_number;

5431  

5432     /* There is no statement yet.  */

5433     statement = NULL_TREE;

5434     /* Peek at the next token.  */

5435     token = cp_lexer_peek_token (parser->lexer);

5436     /* Remember the line number of the first token in the statement.  */

5437     statement_line_number = token->location.line;

5438     /* If this is a keyword, then that will often determine what kind of

5439       statement we have.  */

5440     if (token->type == CPP_KEYWORD)

5441     {

         

5479     }

5480     else if (token->type == CPP_NAME)

5481     {

5482       /* If the next token is a `:', then we are looking at a

5483         labeled-statement.  */

5484       token = cp_lexer_peek_nth_token (parser->lexer, 2);

5485       if (token->type == CPP_COLON)

5486         statement = cp_parser_labeled_statement (parser, in_statement_expr_p);

5487     }

5488     /* Anything that starts with a `{' must be a compound-statement.  */

5489     else if (token->type == CPP_OPEN_BRACE)

5490       statement = cp_parser_compound_statement (parser, false);

5491  

5492     /* Everything else must be a declaration-statement or an

5493       expression-statement. Try for the declaration-statement

5494       first, unless we are looking at a `;', in which case we know that

5495       we have an expression-statement.  */

5496     if (!statement)

5497     {

5498       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))

5499       {

5500         cp_parser_parse_tentatively (parser);

5501         /* Try to parse the declaration-statement.  */

5502         cp_parser_declaration_statement (parser);

5503         /* If that worked, we're done.  */

5504         if (cp_parser_parse_definitely (parser))

5505           return ;

5506       }

5507       /* Look for an expression-statement instead.  */

5508       statement = cp_parser_expression_statement (parser, in_statement_expr_p);

5509     }

5510  

5511     /* Set the line number for the statement.  */

5512     if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))

5513       STMT_LINENO (statement) = statement_line_number;

5514   }

 

A declaration statement introduces one or more new identifiers into a block; it has the form

declaration-statement: block-declaration

If an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block, after which it resumes its force.

Variables with automatic storage duration are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block.

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type and is declared without an initializer. For example:

void f() {

// ...

goto lx; // ill-formed: jump into scope of a

// ...

ly:

X a = 1;

// ...

lx:

goto ly; // OK, jump implies destructor call for a followed by construction

// again immediately following label ly

}

The zero-initialization of all local objects with static storage duration is performed before any other initialization takes place. A local object of POD type with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope. Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined. For example:

int foo(int i) {

static int s = foo(2*i); // recursive call – undefined

return i+1;

}

The destructor for a local object with static storage duration will be executed if and only if the variable was constructed.

 

6144   static void

6145   cp_parser_declaration_statement (cp_parser* parser)                                         in parser.c

6146   {

6147     /* Parse the block-declaration.  */

6148     cp_parser_block_declaration (parser, /*statement_p=*/ true);

6149  

6150     /* Finish off the statement.  */

6151     finish_stmt ();

6152   }

 

For “SmallObject<> object_;”, it is parsed following rule of block-declaration again.With call stack: cp_parser_block_declaration à cp_parser_simple_declaration à cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name à cp_parser_class_name , template-id “SmallObject” is recognized.

5.12.5.2.2.2.1.          Template instantation

5.12.5.2.2.2.1.1.    The template-id

In this invocation of cp_parser_class_name , the arguments typename_keyword_p , template_keyword_p , type_p , class_head_p , and is_declaration are false; and check_dependency_p is true. The detail of template-id lookup, refers to section 5.412.4.2.2.2. Template-id .

In cp_parser_template_id , if the template is a class template or a template template parameter, it will call finish_template_type to finish the processing. For our example, in   finish_template_type , lookup_template_class has arguments in_decl and context of NULL, arglist of the template argument-list which is NULL too, dl of the node of TEMPLATE_DECL, and entering_scope of nonzero which means entering the scope of template-id indicated.

 

4133   tree

4134   lookup_template_class (tree d1,                                                                              in pt.c

4135                      tree arglist,

4136                      tree in_decl,

4137                       tree context,

4138                      int entering_scope,

4139                      tsubst_flags_t complain)

4140   {

4141     tree template = NULL_TREE, parmlist;

4142     tree t;

4143    

4144     timevar_push (TV_NAME_LOOKUP);

4145    

4146     if (TREE_CODE (d1) == IDENTIFIER_NODE)

4147     {

         

4162        }

4163     else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))

4164     {

         

4177     }

4178     else if (TREE_CODE (d1) == ENUMERAL_TYPE

4179           || (TYPE_P (d1) && IS_AGGR_TYPE (d1)))

4180     {

         

4183     }

4184     else if (TREE_CODE (d1) == TEMPLATE_DECL

4185           && TREE_CODE (DECL_TEMPLATE_RESULT (d1)) == TYPE_DECL)

4186     {

4187       template = d1;

4188       d1 = DECL_NAME (template);

4189       context = DECL_CONTEXT (template);

4190     }

       

4219     complain &= ~tf_user;

4220    

4221     if (DECL_TEMPLATE_TEMPLATE_PARM_P (template))

4222     {

         

4259     }

4260     else

4261     {

4262       tree template_type = TREE_TYPE (template);

4263       tree gen_tmpl;

4264       tree type_decl;

4265       tree found = NULL_TREE;

4266       tree *tp;

4267       int arg_depth;

4268       int parm_depth;

4269       int is_partial_instantiation;

4270  

4271       gen_tmpl = most_general_template (template);

4272       parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);

4273       parm_depth = TMPL_PARMS_DEPTH (parmlist);

4274       arg_depth = TMPL_ARGS_DEPTH (arglist);

4275  

4276       if (arg_depth == 1 && parm_depth > 1)

4277       {

           

4294       }

4295  

4296       /* Now we should have enough arguments.  */

4297       my_friendly_assert (parm_depth == arg_depth, 0);

4298        

4299       /* From here on, we're only interested in the most general

4300         template.  */

4301       template = gen_tmpl;

4302  

4303       /* Calculate the BOUND_ARGS. These will be the args that are

4304         actually tsubst'd into the definition to create the

4305         instantiation.  */

4306       if (parm_depth > 1)

4307       {

           

4344       }

4345       else

4346         arglist

4347             = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),

4348                                   INNERMOST_TEMPLATE_ARGS (arglist),

4349                                   template,

4350                                   complain, /*require_all_args=*/ 1);

4351  

4352       if (arglist == error_mark_node)

4353         /* We were unable to bind the arguments.  */

4354         POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

5.12.5.2.2.2.1.1.1.            Replace the first default arguments

As arglist is NULL, at line 4348 INNERMOST_TEMPLATE_ARGS returns NULL as result. And template itself is the most general form, so INNERMOST_TEMPLATE_PARMS returns the TREE_VEC in below figure for the parameters.

(Click here for open )

 

3805   static tree

3806   coerce_template_parms (tree parms,                                                                       in pt.c

3807                       tree args,

3808                        tree in_decl,

3809                       tsubst_flags_t complain,

3810                       int require_all_arguments)

3811   {

3812     int nparms, nargs, i, lost = 0;

3813     tree inner_args;

3814     tree new_args;

3815     tree new_inner_args;

3816  

3817     inner_args = INNERMOST_TEMPLATE_ARGS (args);

3818     nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;

3819     nparms = TREE_VEC_LENGTH (parms);

3820  

3821     if (nargs > nparms

3822       || (nargs < nparms

3823         && require_all_arguments

3824         && TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))

3825     {

3826       if (complain & tf_error)

3827       {

3828         error ("wrong number of template arguments (%d, should be %d)",

3829               nargs, nparms);

3830         

3831         if (in_decl)

3832           cp_error_at ("provided for `%D'", in_decl);

3833       }

3834  

3835       return error_mark_node;

3836     }

3837  

3838     new_inner_args = make_tree_vec (nparms);

3839     new_args = add_outermost_template_args (args, new_inner_args);

3840     for (i = 0; i < nparms; i++)

3841     {

3842       tree arg;

3843       tree parm;

3844  

3845       /* Get the Ith template parameter.  */

3846       parm = TREE_VEC_ELT (parms, i);

3847  

3848       /* Calculate the Ith argument.  */

3849       if (i < nargs)

3850         arg = TREE_VEC_ELT (inner_args, i);

3851       else if (require_all_arguments)

3852         /* There must be a default arg in this case.  */

3853         arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,

3854                                complain, in_decl);

3855       else

3856         break ;

3857        

3858       my_friendly_assert (arg, 20030727);

3859       if (arg == error_mark_node)

3860         error ("template argument %d is invalid", i + 1);

3861       else

3862         arg = convert_template_argument (TREE_VALUE (parm),

3863                                      arg, new_args, complain, i,

3864                                      i n_decl);

3865        

3866       if (arg == error_mark_node)

3867         lost++;

3868       TREE_VEC_ELT (new_inner_args, i) = arg;

3869     }

3870  

3871     if (lost)

3872       return error_mark_node;

3873  

3874     return new_inner_args;

3875   }

 

Above at line 3839, as args is NULL, add_outermost_template_args does nothing but returns new_inner_args . In above figure, we see that TREE_PURPOSE field (the default argument) of first parameter is the TMEPLATE_DECL of “SingleThreaded”. Then next is the arguments replacement.

 

5700   static tree

5701   tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)         in pt.c

5702   {

5703     tree r;

5704    

5705     if (!t)

5706       r = t;

5707     else if (TYPE_P (t))

5708       r = tsubst (t, args, complain, in_decl);

5709     else

5710     {

5711       r = tsubst_expr (t, args, complain, in_decl);

5712  

5713       if (!uses_template_parms (r))

5714       {

5715         /* Sometimes, one of the args was an expression involving a

5716           template constant parameter, like N - 1. Now that we've

5717            tsubst'd, we might have something like 2 - 1. This will

5718           confuse lookup_template_class, so we do constant folding

5719           here. We have to unset processing_template_decl, to fool

5720           tsubst_copy_and_build() into building an actual tree.  */

5721  

5722         /* If the TREE_TYPE of ARG is not NULL_TREE, ARG is already

5723           as simple as it's going to get, and trying to reprocess

5724           the trees will break. Once tsubst_expr et al DTRT for

5725           non-dependent exprs, this code can go away, as the type

5726           will always be set.  */

5727         if (!TREE_TYPE (r))

5728         {

5729           int saved_processing_template_decl = processing_template_decl;

5730           processing_template_decl = 0;

5731            r = tsubst_copy_and_build (r, /*args=*/ NULL_TREE,

5732                                 tf_error, /*in_decl=*/ NULL_TREE,

5733                                 /*function_p=*/ false);

5734           processing_template_decl = saved_processing_template_decl;

5735         }

5736         r = fold (r);   

5737       }

5738     }

5739     return r;

5740   }

 

Being a node satisfying DECL_P, tsubst_expr takes the job.

 

7822   static tree

7823   tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)                            in pt.c

7824   {

7825     tree stmt, tmp;

7826     tsubst_flags_t stmt_expr

7827       = complain & (tf_stmt_expr_cmpd | tf_stmt_expr_body);

7828  

7829     complain ^= stmt_expr;

7830     if (t == NULL_TREE || t == error_mark_node)

7831       return t;

7832  

7833     if (!STATEMENT_CODE_P (TREE_CODE (t)))

7834       return tsubst_copy_and_build (t, args, complain, in_decl,

7835                                 /*function_p=*/ false);

       

8156   }

 

STATEMENT_CODE_P above returns nonzero if the code of the node indicates that the node is one of the statements (of course, TEMPLATE_DECL is not qualified; see section 4.3.1.1. stmt_codes for reference).

 

8180   tree

8181   tsubst_copy_and_build (tree t,                                                                         in pt.c

8182                        tree args,

8183                       tsubst_flags_t complain,

8184                       tree in_decl,

8185                       bool function_p)

8186   {

8187   #define RECUR(NODE) /

8188     tsubst_copy_and_build (NODE, args, complain, in_decl, /*function_p=*/ false)

8189  

8190     tree op1;

8191  

8192     if (t == NULL_TREE || t == error_mark_node)

8193       return t;

8194  

8195     switch (TREE_CODE (t))

8196     {

         

8693       default :

8694         return tsubst_copy (t, args, complain, in_decl);

8695     }

8696  

8697   #undef RECUR

8698   }

 

TEMPLATE_DECL doesn’t require special treatment in tsubst_copy_and_build (just “copy” is enough).

 

7449   static tree

7450   tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)                    in pt.c

7451   {

7452     enum tree_code code;

7453     tree r;

7454  

7455     if (t == NULL_TREE || t == error_mark_node)

7456       return t;

7457  

7458     code = TREE_CODE (t);

7459  

7460     switch (code)

7461     {

        

7542       case TEMPLATE_DECL:

7543         if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))

7544           return tsubst (TREE_TYPE (DECL_TEMPLATE_RESULT (t)),

7545                      args, complain, in_decl);

7546         else if (is_member_template (t))

7547           return tsubst (t, args, complain, in_decl);

7548         else if (DECL_CLASS_SCOPE_P (t)

7549               && uses_template_parms (DECL_CONTEXT (t)))

7550         {

7551           /* Template template argument like the following example need

7552              special treatment:

7553  

7554             template <template <class> class TT> struct C {};

7555             template <class T> struct D {

7556                template <class U> struct E {};

7557                C<E> c;                            // #1

7558             };

7559             D<int> d;                      // #2

7560  

7561             We are processing the template argument `E' in #1 for

7562             the template instantiation #2. Originally, `E' is a

7563             TEMPLATE_DECL with `D<T>' as its DECL_CONTEXT. Now we

7564             have to substitute this with one having context `D<int>'.  */

7565  

7566           tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);

7567           return lookup_field (context, DECL_NAME(t), 0, false);

7568         }

7569         else

7570           /* Ordinary template template argument.  */

7571           return t;

           

7816     }

7817   }

 

Not defined in template parameter-list, DECL_TEMPLATE_TEMPLATE_PARM_P returns zero for “SingleThreaded”; nor is it a member template; and the context (enclosing scope) of “SingleThreaded” is the namespace of “Loki” which of course is not type-dependent or value-dependent (so uses_template_parms returns false); so the node of TEMPLATE_DECL is just returned at line 7571.

After returning back tsubst_template_arg , TEMPLATE_DECL which isn’t template template parameter causes uses_template_parms at line 5713 returns false, and it skips IF block at line 5727 as type field is not NULL. Further fold following does nothing as no constant can be folded but just returns the TEMPLATE_DECL.

After returning the default argument, it checks if adjustment is needed and possible. Node of TEMPLATE_DECL in below figure is pointed by parm , which comes from template parameter definition.

(Click here for open )

In below figure, node of TEMPLATE_DECL is referred by arg , which comes from the definition of “SingleThreaded”.

(Click here for open )

 

3636   static tree

3637   convert_template_argument (tree parm,                                                            in pt.c

3638                           tree arg,

3639                           tree args,

3640                           tsubst_flags_t complain,

3641                           int i,

3642                           tree in_decl)

3643   {

3644     tree val;

3645     tree inner_args;

3646     int is_type, requires_type, is_tmpl_type, requires_tmpl_type;

3647    

3648     inner_args = INNERMOST_TEMPLATE_ARGS (args);

3649      

3650     requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;

3651     requires_type = (TREE_CODE (parm) == TYPE_DECL

3652                   || requires_tmpl_type);

3653  

3654     is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL

3655                     && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)

3656                   || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM

3657                   || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);

3658    

3659     if (is_tmpl_type

3660        && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM

3661             || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))

3662       arg = TYPE_STUB_DECL (arg);

3663  

3664     is_type = TYPE_P (arg) || is_tmpl_type;

       

3722     if (is_type)

3723     {

3724       if (requires_tmpl_type)

3725       {

3726         if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)

3727           /* The number of argument required is not known yet.

3728             Just accept it for now.  */

3729           val = TREE_TYPE (arg);

3730         else

3731          {

3732           tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);

3733           tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);

3734  

3735           if (coerce_template_template_parms (parmparm, argparm,

3736                                          complain, in_decl,

3737                                          inner_args))

3738           {

3739             val = arg;

3740                

3741             /* TEMPLATE_TEMPLATE_PARM node is preferred over

3742               TEMPLATE_DECL.  */

3743             if (val != error_mark_node

3744                && DECL_TEMPLATE_TEMPLATE_PARM_P (val))

3745               val = TREE_TYPE (val);

3746           }

3747           else

3748           {

               

3757           }

3758         }

3759       }

3760       else

3761         val = groktypename (arg);

3762     }

3763     else

3764     {

         

3790     }

3791  

3792     return val;

3793   }

 

 

Clearly, at line 3732, parmparm and argparm refer to the nodes of TREE_VEC respectively in figure they belong to. Nothing is done in coerce_template_template_parms , and 1 is returned. So arg is returned by convert_template_argument . Then it is set in first element of new_inner_args in coerce_template_parms .

 

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