前面我们已经为需要构造函数及析构函数的全局或静态对象准备、注册好了初始化函数及退出函数。这一次的迭代检查是否还有没有处理的全局对象,并处理之。函数 walk_namespaces 从上至下以前序访问名字空间树。
848 int
849 walk_namespaces (walk_namespaces_fn f, void* data) in decl.c
850 {
851 return walk_namespaces_r (global_namespace , f, data);
852 }
域 namespaces 保存了在 namespace 中声明的名字空间列表。
831 static int
832 walk_namespaces_r (tree namespace, walk_namespaces_fn f, void* data) in decl.c
833 {
834 int result = 0;
835 tree current = NAMESPACE_LEVEL (namespace)->namespaces;
836
837 result |= (*f) (namespace, data);
838
839 for (; current; current = TREE_CHAIN (current))
840 result |= walk_namespaces_r (current, f, data);
841
842 return result;
843 }
下面的函数是遍历过程中,在每个名字空间节点上执行的实参 f 。实参 data 由调用者传入,表示是否是该函数的最后一次调用。在这里是 0 ,而在 finish_file 的 2856 行,为 1 。
905 int
906 wrapup_globals_for_namespace (tree namespace, void* data) in decl.c
907 {
908 struct cp_binding_level *level = NAMESPACE_LEVEL (namespace);
909 varray_type statics = level->static_decls;
910 tree *vec = &VARRAY_TREE (statics, 0);
911 int len = VARRAY_ACTIVE_SIZE (statics);
912 int last_time = (data != 0);
913
914 if (last_time)
915 {
916 check_global_declarations (vec, len);
917 return 0;
918 }
919
920 /* Write out any globals that need to be output. */
921 return wrapup_global_declarations (vec, len);
922 }
如果这不是最后的调用,那么调用下面的函数来处理名字空间中的全局或静态声明。下面 1572 行的钩子 finish_incomplete_decl ,对于 C++ 前端,指向 lhd_do_nothing_t ,它是一个空函数。
1554 int
1555 wrapup_global_declarations (tree *vec, int len) in toplev.c
1556 {
1557 tree decl;
1558 int i;
1559 int reconsider;
1560 int output_something = 0;
1561
1562 for (i = 0; i < len; i++)
1563 {
1564 decl = vec[i];
1565
1566 /* We're not deferring this any longer. Assignment is
1567 conditional to avoid needlessly dirtying PCH pages. */
1568 if (DECL_DEFER_OUTPUT (decl) != 0)
1569 DECL_DEFER_OUTPUT (decl) = 0;
1570
1571 if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0)
1572 (*lang_hooks .finish_incomplete_decl) (decl);
1573 }
1574
1575 /* Now emit any global variables or functions that we have been
1576 putting off. We need to loop in case one of the things emitted
1577 here references another one which comes earlier in the list. */
1578 do
1579 {
1580 reconsider = 0;
1581 for (i = 0; i < len; i++)
1582 {
1583 decl = vec[i];
1584
1585 if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl))
1586 continue ;
1587
1588 /* Don't write out static consts, unless we still need them.
1589
1590 We also keep static consts if not optimizing (for debugging),
1591 unless the user specified -fno-keep-static-consts.
1592 ??? They might be better written into the debug information.
1593 This is possible when using DWARF.
1594
1595 A language processor that wants static constants to be always
1596 written out (even if it is not used) is responsible for
1597 calling rest_of_decl_compilation itself. E.g. the C front-end
1598 calls rest_of_decl_compilation from finish_decl.
1599 One motivation for this is that is conventional in some
1600 environments to write things like:
1601 static const char rcsid[] = "... version string ...";
1602 intending to force the string to be in the executable.
1603
1604 A language processor that would prefer to have unneeded
1605 static constants "optimized away" would just defer writing
1606 them out until here. E.g. C++ does this, because static
1607 constants are often defined in header files.
1608
1609 ??? A tempting alternative (for both C and C++) would be
1610 to force a constant to be written if and only if it is
1611 defined in a main file, as opposed to an include file. */
1612
1613 if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
1614 {
1615 bool needed = 1;
1616
1617 if (flag_unit_at_a_time
1618 && cgraph_varpool_node (decl)->finalized)
1619 needed = 0;
1620 else if ((flag_unit_at_a_time && !cgraph_global_info_ready )
1621 && (TREE_USED (decl)
1622 || TREE_USED (DECL_ASSEMBLER_NAME (decl))))
1623 /* needed */ ;
1624 else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
1625 /* needed */ ;
1626 else if (DECL_COMDAT (decl))
1627 needed = 0;
1628 else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl)
1629 && (optimize || !flag_keep_static_consts
1630 || DECL_ARTIFICIAL (decl)))
1631 needed = 0;
1632
1633 if (needed)
1634 {
1635 reconsider = 1;
1636 rest_of_decl_compilation (decl, NULL, 1, 1);
1637 }
1638 }
1639
1640 if (TREE_CODE (decl) == FUNCTION_DECL
1641 && DECL_INITIAL (decl) != 0
1642 && DECL_SAVED_INSNS (decl) != 0
1643 && DECL_SAVED_INSNS (decl)->saved_for_inline
1644 && (flag_keep_inline_functions
1645 || (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
1646 || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
1647 {
1648 reconsider = 1;
1649 output_inline_function (decl);
1650 }
1651 }
1652
1653 if (reconsider)
1654 output_something = 1;
1655 }
1656 while (reconsider);
1657
1658 return output_something;
1659 }
注意在此时, 1620 行的 cgraph_global_info_ready 仍然是 false 。看到如果变量真正被使用,在 1636 行,调用 rest_of_decl_compilation ,在其中,对于非外部变量,调用 cgraph_varpool_finalize_decl 来确保生成相关的 cgrap_varpool_node ,并把这个节点标记为已完成( finialized )(对于 FUNCTION_DECL , assemble_variable 不做任何事,仅清除 last_assemble_variable_decl )。
另外对于已经被使用,或者在外部可见的内联函数,或者使用编译选项 –fkeep-inline-functions 来发布所有内联函数;其对应的调用表达式应该为函数体所替代,这由下面的函数来完成。
下面的 write_symbols 表示所产生的调试信息的类型。看到真正的工作由 2995 行的 rest_of_compilation 完成,它包含了非常复杂的操作,因此我们暂时不看它。
2965 void
2966 output_inline_function (tree fndecl) in integrate.c
2967 {
2968 enum debug_info_type old_write_symbols = write_symbols ;
2969 const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks ;
2970 struct function *f = DECL_SAVED_INSNS (fndecl);
2971
2972 old_cfun = cfun ;
2973 cfun = f;
2974 current_function_decl = fndecl;
2975
2976 set_new_last_label_num (f->inl_max_label_num);
2977
2978 /* We're not deferring this any longer. */
2979 DECL_DEFER_OUTPUT (fndecl) = 0;
2980
2981 /* If requested, suppress debugging information. */
2982 if (f->no_debugging_symbols)
2983 {
2984 write_symbols = NO_DEBUG;
2985 debug_hooks = &do_nothing_debug_hooks ;
2986 }
2987
2988 /* Make sure warnings emitted by the optimizers (e.g. control reaches
2989 end of non-void function) is not wildly incorrect. */
2990 input_location = DECL_SOURCE_LOCATION (fndecl);
2991
2992 /* Compile this function all the way down to assembly code. As a
2993 side effect this destroys the saved RTL representation, but
2994 that's okay, because we don't need to inline this anymore. */
2995 rest_of_compilation (fndecl);
2996 DECL_INLINE (fndecl) = 0;
2997
2998 cfun = old_cfun;
2999 current_function_decl = old_cfun ? old_cfun->decl : 0;
3000 write_symbols = old_write_symbols;
3001 debug_hooks = old_debug_hooks;
3002 }
接下来, pending_statics 保存了一个静态类变量列表。这是需要的,因为一个静态类变量可以被声明在该类中,并且不带初始值,然后在该类的外部静态地初始化这个变量。注意到 pending_statics 可能与 static_aggregates 重叠,不过那些变量已经在前面的章节中处理过了,不会在这里再处理。
首先,需要调用 import_export_decl 来确定变量的可见性及链接属性;然后就是 wrapup_global_declarations 。注意没有初始值,不需要为这些对象构建初始化函数,就像章节 迭代 – 发布全局聚集类的构造函数 /析构函数 中所做的那样。
然后在 DO…WHILE 循环的末尾的 2797 行,如果设置了 flag_unit_at_a_time , cgraph_assemble_pending_functions 不做任何事。