5.13.4.5. 疊代 – 處理名字空間中的全局對象
前面我們已經為需要構造函數及析構函數的全局或靜态對象準備、注冊好了初始化函數及退出函數。這一次的疊代檢查是否還有沒有處理的全局對象,并處理之。函數 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
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
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
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
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 ;
1624 else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
1625 ;
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
2979 DECL_DEFER_OUTPUT (fndecl) = 0;
2980
2981
2982 if (f->no_debugging_symbols)
2983 {
2984 write_symbols = NO_DEBUG;
2985 debug_hooks = &do_nothing_debug_hooks ;
2986 }
2987
2988
2990 input_location = DECL_SOURCE_LOCATION (fndecl);
2991
2992
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 }
5.13.4.6. 疊代 – 在類中沒有初始值的靜态成員
接下來, pending_statics 儲存了一個靜态類變量清單。這是需要的,因為一個靜态類變量可以被聲明在該類中,并且不帶初始值,然後在該類的外部靜态地初始化這個變量。注意到 pending_statics 可能與 static_aggregates 重疊,不過那些變量已經在前面的章節中處理過了,不會在這裡再處理。
首先,需要調用 import_export_decl 來确定變量的可見性及連結屬性;然後就是 wrapup_global_declarations 。注意沒有初始值,不需要為這些對象建構初始化函數,就像章節 疊代 – 釋出全局聚集類的構造函數 /析構函數 中所做的那樣。
然後在 DO…WHILE 循環的末尾的 2797 行,如果設定了 flag_unit_at_a_time , cgraph_assemble_pending_functions 不做任何事。