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

5.12.5.2.2.2.  处理函数体

函数体构成了一个新的块绑定域,在更深入进入该函数体前,要执行之前挂起的访问检查,以尽早发现违例的访问。

 

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 }

 

5.12.3.2.1.2.1.2.解析函数体 一节看过 cp_parser_function_definition_after_declarator 。在这个函数中, cp_parser_ctor_initializer_opt_and_function_body 解析函数体,以及对于构造函数可能存在的初始化值。另外在这个函数中, begin_function_body 准备了复合语句的子树的根节点,以及其封闭作用域。之后,相关的中间树部分如下。

点此打开

cp_parser_function_body 处理作为一个复合语句的函数体。

 

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   }

 

在处理跟在“ { ”后面的符号前,构建了另一个封闭域,这是因为前一个块作用域是为可能的构造函数初始值构建的,而这里构建的才真正为了函数体。

点此打开

 

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   }

 

深入到调用栈: cp_parser_statement à cp_parser_declaration_statement à cp_parser_block_declaration à cp_parser_simple_declaration ,则 cp_parser_decl_specifier_seq 解析第一个声明的 type-specifier 部分,通过 cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name à cp_parser_class_name 找到对应“ SmallObject<> ”的 template-id

 

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   }

 

一个声明语句向一个作用域中引入了一个或多个新的标识符,它具有形式:

declaration-statement: block-declaration

如果被声明引入的一个标识符先前在一个外部的块中声明了,在当前块的余下部分,该外部的声明被屏蔽,之后它又恢复可见。

具有自动存储周期的变量,在其声明语句每次执行时都得到初始化。在从块中退出时,在该块中声明的具有自动存储周期的变量被摧毁。

有可能跳入一个块中,但不绕过具有初始化的声明。从一个具有自动存储周期的局部变量作用域外跳转到其作用域中的程序是错误的,除非该变量是 POD 类型并且没有初始值。例如:

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

}

在其他初始化执行前,执行所有具有静态存储周期的局部变量的零初始化( zero-initialization )。 POD 类型的,具有静态存储周期,并且通过常量表达式初始化的局部对象,在进入其包含块前被初始化。允许一个实现提前为其他具有静态存储周期的局部对象执行初始化;在相同条件下,允许一个实现为名字空间中的具有静态存储周期的对象执行静态初始化。否则对象在控制第一次经过其声明时得到初始化;在其初始化完成后,这样的对象被认为是初始化的。如果初始化通过抛出异常而退出,该初始化没有完成,因此在控制下一次进入其声明时,会再进行一次尝试。当对象正在被初始化时,如果控制再一次进入声明,其行为是尚未定义的。例如:

int foo(int i) {

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

return i+1;

}

具有静态存储周期的局部对象的析构函数仅当该变量被构造后才会得到执行。

 

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   }

 

对于“ SmallObject<> object_; ”,再一次根据 block-declaration 的语法进行解析。经过调用栈 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 ”。

5.12.5.2.2.2.1.          模板具现

5.12.5.2.2.2.1.1.    template-id

在此次 cp_parser_class_name 调用中,参数 typename_keyword_p template_keyword_p type_p , class_head_p is_declaration 都是 false ;而 check_dependency_p true 。详细的 template-id 的查找过程参考 5.12.4.2.2.2.Template-id 一节。

cp_parser_template_id 中,当发现该模板是一个类模板或模板模板参数时,将调用 finish_template_type 来完成该类型的处理。对于我们的例子,在 finish_template_type 中调用的 lookup_template_class 的参数 in_decl context 都是 NULL ,代表模板实参列表的 arglist 也是 NULL dl 则是对应的 TEMPLATE_DECL 节点,而 entering_scope 为非 0 值,表示进入 template-id 所代表的作用域。

 

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.            替换第一个缺省实参

因为 arglist NULL ,在 4348 行的 INNERMOST_TEMPLATE_ARGS 返回结果 NULL 。而 template 本身是最通用的形式,因此 INNERMOST_TEMPLATE_PARMS 返回了下图中的 TREE_VEC 作为其参数。

点此打开

 

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   }

 

在上面的 3839 行因为 args NULL add_outermost_template_args 不做任何事只是返回 new_inner_args 。在上图中,看到第一个参数的 TREE_PURPOSE 域(对应缺省实参)是“ SingleThreaded ”的 TMEPLATE_DECL 。那么接下来就是实参替换。

 

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   }

 

作为一个满足 DECL_P 条件的节点,对其处理由 tsubst_expr 完成。

 

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 返回非 0 值,如果节点的编码显示该节点代表一条语句( statement )(显然, TEMPLATE_DECL 不合格;参考 4.3.1.1. stmt_codes 一节)。

 

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   }

 

tsubst_copy_and_build 中, TEMPLATE_DECL 不要求特殊的处理(仅“拷贝”就足够)。

 

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   }

 

SingleThreaded ”没在模板参数列表中定义, DECL_TEMPLATE_TEMPLATE_PARM_P 则返回 0 ;它也不是成员模板;而且其上下文(封闭域)是名字空间“ Loki ”,明显不是类型依赖或值依赖的(因此 uses_template_parms 返回 false );所以在 7571 行返回了对应的 TEMPLATE_DECL 节点。

在回到 tsubst_template_arg 后, TEMPLATE_DECL 因为不是模板模板参数,导致在 5713 行的 uses_template_parms 返回 false ,并且跳过 5727 行的 IF 块,因为其 type 域不是 NULL 。接着的 fold 不做任何事,因为没有常量可折叠,只是返回这个 TEMPLATE_DECL 节点。

在返回缺省实参后,检查是否需要进行调整。在下图中的 TEMPLATE_DECL 节点被 parm 所指向,该节点来自模板参数的定义。

点此打开

在下图中, TEMPLATE_DECL 节点为 arg 所引用,该节点来自“ SingleThreaded ”的定义。

点此打开

 

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   }

 

明显地,在 3732 行, parmparm argparm 分别引用各自图中,对应 TREE_VEC 中的节点。在 coerce_template_template_parms 中不做任何事 并返回 1 。因此 arg convert_template_argument 返回,在 coerce_template_parms 中,它被设置为 new_inner_args 的第一个元素。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值