5.12.3.2.1.2.1.2.2. 完成阶段
函数 cp_parser_function_body 只是调用 cp_parser_compound_statement 来解析复合语句。这里我们跳过解析复合语句的细节,不过记住每个语句都会构建节点并链入语句链(树)。注意到作为子语句链(树)根节点的对应的 COMPOUND_STMT 节点被保存在 cp_parser_ctor_initializer_opt_and_function_body 11476 行的 body 里。
10791 void
10792 finish_function_body (tree compstmt) in decl.c
10793 {
10794 /* Close the block. */
10795 finish_compound_stmt (compstmt);
10796
10797 if (processing_template_decl )
10798 /* Do nothing now. */ ;
10799 else if (DECL_CONSTRUCTOR_P (current_function_decl ))
10800 finish_constructor_body ();
10801 else if (DECL_DESTRUCTOR_P (current_function_decl ))
10802 finish_destructor_body ();
10803 }
函数体实际上是一个复合语句, finish_compound_stmt 被调用。注意到参数 compound_stmt 也是在 begin_compound_stmt 中构建的 body 。
1029 tree
1030 finish_compound_stmt (tree compound_stmt) in semantics.c
1031 {
1032 tree r;
1033 tree t;
1034
1035 if (COMPOUND_STMT_NO_SCOPE (compound_stmt))
1036 r = NULL_TREE;
1037 else
1038 r = do_poplevel ();
因为到达该复合语句的末尾时,需要进入上一级作用域。回忆我们已经看过从名字空间及类的作用域中退出;不过从函数作用域退出是不太相同的。
336 tree
337 do_poplevel (void) in semantics.c
338 {
339 tree block = NULL_TREE;
340
341 if (stmts_are_full_exprs_p ())
342 {
343 tree scope_stmts = NULL_TREE;
344
345 block = poplevel (kept_level_p (), 1, 0);
当从局部作用域退出时,对应的 cxx_scope 节点将被回收,而在该作用域中声明的名字,标签等等,不在随后的名字查找中可见。但是对于这些名字,标签的节点,如果没有另外的记录,也将消失。为了记住这些项,一个新的 BLOCK 节点将被构建作为缓存树的根节点。不过,对于空的局部作用域,这个节点是不必要的,下面的 kept_level_p 可以告知这个节点是否需要。
1492 bool
1493 kept_level_p (void) in name-lookup.c
1494 {
1495 return ( current_binding_level ->blocks != NULL_TREE
1496 || current_binding_level->keep
1497 || current_binding_level->kind == sk_cleanup
1498 || current_binding_level->names != NULL_TREE
1499 || current_binding_level->type_decls != NULL);
1500 }
因此,在下面如果参数 keep 是非 0 值,一个 BLOCK 节点将被构建来记录这些局部声明。而 functionbody 如果非 0 ,表示这一级是一个函数体。不过注意到当由 do_poplevel 来调用时, functionbody 是 0 —这是因为我们退出当前作用域后,即将进入 sk_function_parms 作用域——这才是语义意义上的“函数体”。事实上,在 finish_function 中从“函数体”退出时, poplevel 将被再一次调用。
423 tree
424 poplevel (int keep, int reverse, int functionbody) in decl.c
425 {
426 tree link;
427 /* The chain of decls was accumulated in reverse order.
428 Put it into forward order, just for cleanliness. */
429 tree decls;
430 int tmp = functionbody;
431 int real_functionbody;
432 tree subblocks;
433 tree block = NULL_TREE;
434 tree decl;
435 int leaving_for_scope;
436 scope_kind kind;
437
438 timevar_push (TV_NAME_LOOKUP);
439
440 my_friendly_assert ( current_binding_level ->kind != sk_class, 19990916);
441
442 real_functionbody = ( current_binding_level ->kind == sk_cleanup
443 ? ((functionbody = 0), tmp) : functionbody);
444 subblocks = functionbody >= 0 ? current_binding_level ->blocks : 0;
445
446 my_friendly_assert (! current_binding_level ->class_shadowed,
447 19990414);
448
449 /* We used to use KEEP == 2 to indicate that the new block should go
450 at the beginning of the list of blocks at this binding level,
451 rather than the end. This hack is no longer used. */
452 my_friendly_assert (keep == 0 || keep == 1, 0);
453
454 if ( current_binding_level ->keep)
455 keep = 1;
456
457 /* Any uses of undefined labels, and any defined labels, now operate
458 under constraints of next binding contour. */
459 if (cfun && !functionbody)
460 {
461 struct cp_binding_level *level_chain;
462 level_chain = current_binding_level->level_chain;
463 if (level_chain)
464 {
465 struct named_label_use_list *uses;
466 struct named_label_list *labels;
467 for (labels = named_labels; labels; labels = labels->next)
468 if (labels->binding_level == current_binding_level)
469 {
470 tree decl;
471 if (current_binding_level->kind == sk_try)
472 labels->in_try_scope = 1;
473 if (current_binding_level->kind == sk_catch)
474 labels->in_catch_scope = 1;
475 for (decl = labels->names_in_scope; decl;
476 decl = TREE_CHAIN (decl))
477 if (decl_jump_unsafe (decl))
478 labels->bad_decls = tree_cons (NULL_TREE, decl,
479 labels->bad_decls);
480 labels->binding_level = level_chain;
481 labels->names_in_scope = level_chain->names;
482 }
483
484 for (uses = named_label_uses; uses; uses = uses->next)
485 if (uses->binding_level == current_binding_level)
486 {
487 uses->binding_level = level_chain;
488 uses->names_in_scope = level_chain->names;
489 }
490 }
491 }
在 C++ 里,标签( label )只会出现在函数体内。在上面 467 行, named_labels 是 cfun 用来记录函数中定义的标签。 475 行 named_label_list 的 names_in_scope 域,是个巧妙的设计,例如,在复合语句:
{
D1; D2;
{
D31;
goto Label1; // inner 1
D32;
Label1:
D33;
…
goto Label1; // inner 2
goto Label2; // inner 3
}
D4;
Label2:
…
goto Label1;
}
在解析标签 Label1 时,其对应的 named_label_list 节点的 names_in_scope 域将被赋值为 current_binding_level 的 names 域的值(这时只包含 D32 , D31 。从这里可以看到把 current_binding_level 的 names 域用作栈的理由)。注意在到达里层复合语句的闭大括号时,一样要调用 poplevel (通过 do_poplevel ),因为这个函数服务于作用域的退出。那么在上面 475 行的 FOR 循环中,需要检查若跳转到 Label1 时,是否有潜在的危险,并记录导致危险的声明。比如如果 D31 或 D32 是带有初始化值的( initializer ),跳到标签 Label1 可能使得 D31 或 D32 得不到指定的初始化。 GCC 将禁止这样的行为。
2206 static int
2207 decl_jump_unsafe (tree decl) in decl.c
2208 {
2209 if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
2210 return 0;
2211
2212 if (DECL_INITIAL (decl) == NULL_TREE
2213 && pod_type_p (TREE_TYPE (decl)))
2214 return 0;
2215
2216 /* This is really only important if we're crossing an initialization.
2217 The POD stuff is just pedantry; why should it matter if the class
2218 contains a field of pointer to member type? */
2219 if (DECL_INITIAL (decl)
2220 || (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
2221 return 2;
2222 return 1;
2223 }
注意只有非静态变量才是考虑的对象。当变量声明中没有初始值( DECL_INITIAL 为空),或者其类型是 POD ( plain old data ),跳过它才是安全的。注意!上面里层的标记为“ inner 2 ”的 goto 语句不需要考虑 D31 及 D32 。
1763 int
1764 pod_type_p (tree t) in cp/tree.c
1765 {
1766 t = strip_array_types (t);
1767
1768 if (t == error_mark_node)
1769 return 1;
1770 if (INTEGRAL_TYPE_P (t))
1771 return 1; /* integral, character or enumeral type */
1772 if (FLOAT_TYPE_P (t))
1773 return 1;
1774 if (TYPE_PTR_P (t))
1775 return 1; /* pointer to non-member */
1776 if (TYPE_PTR_TO_MEMBER_P (t))
1777 return 1; /* pointer to member */
1778 if (TREE_CODE (t) == VECTOR_TYPE)
1779 return 1; /* vectors are (small) arrays of scalars */
1780
1781 if (! CLASS_TYPE_P (t))
1782 return 0; /* other non-class type (reference or function) */
1783 if (CLASSTYPE_NON_POD_P (t))
1784 return 0;
1785 return 1;
1786 }
可以看到引用类型 , 包含了 protected 或 private 或引用类型的数据成员的类 ( 对应的陈述 CLASSTYPE_NON_POD_P 为非 0 ) 不是 POD 类型。
回到上面的例子。当退出到外层的复合语句时, 480 及 481 行的代码把 Label1 的作用域改变为外层作用域,并把其 names_in_scope 域更新为包含 D1 及 D2 。因为此时跳转只能来自该层,比如外层的 goto 语句。注意!这条 goto 语句实际上只受 D31 及 D32 的影响,它只考虑里层中由 decl_jump_unsafe 检查出来的危险声明。
而在 484 行的 named_label_uses 记录的是对尚未定义的标签的使用,比如在解析上面例子中标记为“ inner 1 ”的 goto 语句时,这个 Label1 的引用将被放入 named_label_uses 。同时在这个节点( named_label_use_list 类型)中,其 names_in_scope 将是那时作用域中已有的声明(即 D31 )。在解析 Label1 时,这个悬而未决的引用将从 named_label_uses 中移除,同时使用 decl_jump_unsafe 检查这个 goto 语句到标签之间的声明(参见 check_previous_goto_1 )。
因此在这里 484 行的 FOR 循环中, named_label_uses 记录的是还没有看到定义的标签。毫无疑问,这些标签的定义只能出现在外层代码。比如上面例子中标记为“ inner 3 ”的 goto 语句,在它及 Label2 标签之间插有声明 D4 。在这个 FOR 循环中,把这个对标签的引用的 named_label_uses 更新为 D1 及 D2 ,亦把这个引用的作用域设置为外层作用域。这样它的处理和标记为“ inner 1 ”的 goto 语句没有什么不同。
poplevel (continue)
493 /* Get the decls in the order they were written.
494 Usually current_binding_level->names is in reverse order.
495 But parameter decls were previously put in forward order. */
496
497 if (reverse)
498 current_binding_level->names
499 = decls = nreverse (current_binding_level->names);
500 else
501 decls = current_binding_level ->names;
502
503 /* Output any nested inline functions within this block
504 if they weren't already output. */
505 for (decl = decls; decl; decl = TREE_CHAIN (decl))
506 if (TREE_CODE (decl) == FUNCTION_DECL
507 && ! TREE_ASM_WRITTEN (decl)
508 && DECL_INITIAL (decl) != NULL_TREE
509 && TREE_ADDRESSABLE (decl)
510 && decl_function_context (decl) == current_function_decl )
511 {
512 /* If this decl was copied from a file-scope decl
513 on account of a block-scope extern decl,
514 propagate TREE_ADDRESSABLE to the file-scope decl. */
515 if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
516 TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
517 else
518 {
519 push_function_context ();
520 output_inline_function (decl);
521 pop_function_context ();
522 }
523 }
524
525 /* When not in function-at-a-time mode, expand_end_bindings will
526 warn about unused variables. But, in function-at-a-time mode
527 expand_end_bindings is not passed the list of variables in the
528 current scope, and therefore no warning is emitted. So, we
529 explicitly warn here. */
530 if (!processing_template_decl )
531 warn_about_unused_variables (getdecls ());
532
533 /* If there were any declarations or structure tags in that level,
534 or if this level is a function body,
535 create a BLOCK to record them for the life of this function. */
536 block = NULL_TREE;
537 if (keep == 1 || functionbody)
538 block = make_node (BLOCK);
539 if (block != NULL_TREE)
540 {
541 BLOCK_VARS (block) = decls;
542 BLOCK_SUBBLOCKS (block) = subblocks;
543 }
544
545 /* In each subblock, record that this is its superior. */
546 if (keep >= 0)
547 for (link = subblocks; link; link = TREE_CHAIN (link))
548 BLOCK_SUPERCONTEXT (link) = block;
由 do_poplevel 来调用时, poplevel 的参数 reverse 为 1 ,其他情况下都是 0 。前面看到 current_binding_level 的 names 域总是记录了在该作用域中声明的名字,而且用作栈。现在是时候恢复其声明时的次序了。
GCC 支持嵌套函数,不过被嵌套的函数必须是内联的。 505 行的 FOR 循环对这些函数产生汇编代码(彼时其 TREE_ASM_WRITTEN 将被设为 1 )。
上面 542 行的 subblocks 来自 current_binding_level->blocks ,为当前作用域中所出现的语句块。注意 541 行的 decls ,它来自已恢复声明时次序的 current_binding_level->names 。上面构建了块与子块间的关系。
poplevel (continue)
550 /* We still support the old for-scope rules, whereby the variables
551 in a for-init statement were in scope after the for-statement
552 ended. We only use the new rules if flag_new_for_scope is
553 nonzero. */
554 leaving_for_scope
555 = current_binding_level->kind == sk_for && flag_new_for_scope == 1;
556
557 /* Remove declarations for all the DECLs in this level. */
558 for (link = decls; link; link = TREE_CHAIN (link))
559 {
560 if (leaving_for_scope && TREE_CODE (link) == VAR_DECL
561 && DECL_NAME (link))
562 {
563 cxx_binding *outer_binding
564 = IDENTIFIER_BINDING (DECL_NAME (link))->previous;
565 tree ns_binding;
566
567 if (!outer_binding)
568 ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link));
569 else
570 ns_binding = NULL_TREE;
571
572 if (outer_binding
573 && outer_binding->scope == current_binding_level->level_chain)
574 /* We have something like:
575
576 int i;
577 for (int i; ;);
578
579 and we are leaving the `for' scope. There's no reason to
580 keep the binding of the inner `i' in this case. */
581 pop_binding (DECL_NAME (link), link);
582 else if ((outer_binding
583 && (TREE_CODE (outer_binding->value) == TYPE_DECL))
584 || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL))
585 /* Here, we have something like:
586
587 typedef int I;
588
589 void f () {
590 for (int I; ;);
591 }
592
593 We must pop the for-scope binding so we know what's a
594 type and what isn't. */
595 pop_binding (DECL_NAME (link), link);
596 else
597 {
598 /* Mark this VAR_DECL as dead so that we can tell we left it
599 there only for backward compatibility. */
600 DECL_DEAD_FOR_LOCAL (link) = 1;
601
602 /* Keep track of what should have happened when we
603 popped the binding. */
604 if (outer_binding && outer_binding->value)
605 DECL_SHADOWED_FOR_VAR (link) = outer_binding->value;
606
607 /* Add it to the list of dead variables in the next
608 outermost binding to that we can remove these when we
609 leave that binding. */
610 current_binding_level->level_chain->dead_vars_from_for
611 = tree_cons (NULL_TREE, link,
612 current_binding_level->level_chain->
613 dead_vars_from_for);
614
615 /* Although we don't pop the cxx_binding, we do clear
616 its SCOPE since the scope is going away now. */
617 IDENTIFIER_BINDING (DECL_NAME (link))->scope = NULL;
618 }
619 }
620 else
621 {
622 /* Remove the binding. */
623 decl = link;
624 if (TREE_CODE (decl) == TREE_LIST)
625 decl = TREE_VALUE (decl);
626 if (DECL_P (decl))
627 pop_binding (DECL_NAME (decl), decl);
628 else if (TREE_CODE (decl) == OVERLOAD)
629 pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl);
630 else
631 abort ();
632 }
633 }
634
635 /* Remove declarations for any `for' variables from inner scopes
636 that we kept around. */
637 for (link = current_binding_level->dead_vars_from_for;
638 link; link = TREE_CHAIN (link))
639 pop_binding (DECL_NAME (TREE_VALUE (link)), TREE_VALUE (link));
在 C++ 里, FOR 循环与 WHILE , DO WHILE 循环的不同之处,在于它有 for-init-statement 部分。 GCC 在处理 FOR 循环时,首先为 FOR 循环构建一个 sk_for 的作用域,随后在看到“(”时,再加入一个 sk_block 作用域用于 FOR 循环体。那么 sk_for 作用域中 names 所记录的即是在 for-init-statement 部分中声明的变量。因此, 560 行的 IF 块,就是处理这样的变量声明。 572 行及 582 行条件所筛选的情形,其注释中已经显示得很清楚。而 596 行的 ELSE 块,对应的是, 1 )其名字不出现在外部作用域; 2 )其名字出现在外部作用域,但不是紧邻的这个。这里还将其保存 DECL_SHADOWED_FOR_VAR 中,是因为在 ISO 标准出来之前, for-init-statement 中声明的变量的作用域是 FOR 循环所在作用域,从声明点开始。考虑:
int i;
void g() {
for (int i = 0; i < 10; ++i) {}
extern void f(int j = i);
}
编译器将给出如下警告:
:4: warning: name lookup of `i' changed
:1: warning: matches this `i' under ISO standard rules
:3: warning: matches this `i' under old rules
DECL_SHADOWED_FOR_VAR 是编译器给出警告的根据。
另外,为了使得这些声明不为名字查找所见,关联的 cxx_binding 节点都被移除。
poplevel (continue)
641 /* Restore the IDENTIFIER_TYPE_VALUEs. */
642 for (link = current_binding_level ->type_shadowed;
643 link; link = TREE_CHAIN (link))
644 SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
645
646 /* Restore the IDENTIFIER_LABEL_VALUEs for local labels. */
647 for (link = current_binding_level->shadowed_labels;
648 link;
649 link = TREE_CHAIN (link))
650 pop_label (TREE_VALUE (link), TREE_PURPOSE (link));
651
652 /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
653 list if a `using' declaration put them there. The debugging
654 back-ends won't understand OVERLOAD, so we remove them here.
655 Because the BLOCK_VARS are (temporarily) shared with
656 CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have
657 popped all the bindings. */
658 if (block)
659 {
660 tree* d;
661
662 for (d = &BLOCK_VARS (block); *d; )
663 {
664 if (TREE_CODE (*d) == TREE_LIST)
665 *d = TREE_CHAIN (*d);
666 else
667 d = &TREE_CHAIN (*d);
668 }
669 }
670
671 /* If the level being exited is the top level of a function,
672 check over all the labels. */
673 if (functionbody)
674 {
675 /* Since this is the top level block of a function, the vars are
676 the function's parameters. Don't leave them in the BLOCK
677 because they are found in the FUNCTION_DECL instead. */
678 BLOCK_VARS (block) = 0;
679 pop_labels (block);
680 }
681
682 kind = current_binding_level ->kind;
683
684 leave_scope ();
685 if (functionbody)
686 DECL_INITIAL (current_function_decl ) = block;
687 else if (block)
688 current_binding_level ->blocks
689 = chainon ( current_binding_level ->blocks, block);
690
691 /* If we did not make a block for the level just exited,
692 any blocks made for inner levels
693 (since they cannot be recorded as subblocks in that level)
694 must be carried forward so they will later become subblocks
695 of something else. */
696 else if (subblocks)
697 current_binding_level ->blocks
698 = chainon ( current_binding_level ->blocks, subblocks);
699
700 /* Each and every BLOCK node created here in `poplevel' is important
701 (e.g. for proper debugging information) so if we created one
702 earlier, mark it as "used". */
703 if (block)
704 TREE_USED (block) = 1;
705
706 /* Take care of compiler's internal binding structures. */
707 if (kind == sk_cleanup)
708 {
709 tree scope_stmts;
710
711 scope_stmts
712 = add_scope_stmt (/*begin_p=*/ 0, /*partial_p=*/ 1);
713 if (block)
714 {
715 SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
716 SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
717 }
718
719 block = poplevel (keep, reverse, functionbody);
720 }
721
722 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, block);
723 }
注意 678 行,如果 functionbody 不为 0 ,我们退出的是 sk_function_parms 作用域,在这个作用域中只有函数参数,这些项不需要记录在 BLOCK 中,因为通过 FUNCTION_DECL 可以找到它们。在 684 行,执行 level_scope ,使得 current_binding_level 指向上一级作用域。那么看到在 686 行, FUNCTION_DECL 的 DECL_INITIAL 域,保存了在其中的块结构。最后这个块结构被返回,注意如果是空函数,这个块可能是 NULL 。
do_poplevel (continue)
346 if (!processing_template_decl )
347 {
348 /* This needs to come after the poplevel so that partial scopes
349 are properly nested. */
350 scope_stmts = add_scope_stmt (/*begin_p=*/ 0, /*partial_p=*/ 0);
351 if (block)
352 {
353 SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
354 SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
355 }
356 }
357 }
358
359 return block;
360 }
回到 do_poplevel ,注意 351 行的 block 即是 poplevel 返回在 722 行的 block 。在该函数的 350 行,封闭了 do_pushlevel 所引入的域。看到这个作用域的内容就是 block 。
finish_compound_stmt (continue)
1040 RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
1041
1042 /* When we call finish_stmt we will lose LAST_EXPR_TYPE. But, since
1043 the precise purpose of that variable is store the type of the
1044 last expression statement within the last compound statement, we
1045 preserve the value. */
1046 t = last_expr_type;
1047 finish_stmt ();
1048 last_expr_type = t;
1049
1050 return r;
1051 }
上面的宏 RECHAIN_STMTS 重新安排 COMPOUND_STMT 节点,把属于它的语句链表从 chain 域移到 operands[0] 域。
315 #define RECHAIN_STMTS (stmt, substmt) / in c-common.h
316 do { /
317 substmt = TREE_CHAIN (stmt); /
318 TREE_CHAIN (stmt) = NULL_TREE; /
319 last_tree = stmt; /
320 } while (0)
很奇怪 1046 到 1048 行的代码实际上不做任何事。
11252 void
11253 finish_stmt (void) in decl.c
11254 {
11255 /* Always assume this statement was not an expression statement. If
11256 it actually was an expression statement, its our callers
11257 responsibility to fix this up. */
11258 last_expr_type = NULL_TREE;
11259 }
此时,下列节点将为所解析的函数体所创建。此处忽略了函数体内语句对应的节点,它们在图形中由‘ … ’代表。不过,它们的形式与这个最外层的 COMPOUND_STMT 类似。以后我们会看到这些节点的细节。
( 点此打开 )
图 95 :为解析函数体构建的节点
类模板的方法与非类模板方法的区别是很大的。对于非类模板的方法,看到对于函数中的每一个作用域都会构建一对 SCOPE_STMT ,一个 tree_list 将持有它们来记录这个作用域的有效范围。另外, current_scope_stmt_stack 记录保存栈中的作用域。 finish_compound_stmt 的每次调用将对栈进行弹出查找,进入上一级作用域。