5.12.5.2.2.2.1.4.
完成具现
现在继续我们模板具现例子的处理,在
前端部分的初始化
一节,我们已经看到当使用命令行选项
-frepo
时,
init_repo
会产生一个
.rpo
文件,或读入一个已经存在的
.rpo
文件。下面的
repo_template_used
将在对应的
.rpo
文件中记录该模板具现的使用,这个信息将被编译器及
collect2
(
GCC
自带的链接器)在以后使用。
instantiate_class_template (continue)
5473
/* Clear this now
so repo_template_used is happy.
*/
5474
TYPE_BEING_DEFINED (type) = 0;
5475
repo_template_used (type);
5476
5477
/* Now that the
class is complete, instantiate default arguments for
5478
any member functions. We don't
do this earlier because the
5479
default arguments may
reference members of the class.
*/
5480
if (!PRIMARY_TEMPLATE_P (template))
5481
for
(t = TYPE_METHODS (type); t; t = TREE_CHAIN (t))
5482
if (TREE_CODE (t) == FUNCTION_DECL
5483
/*
Implicitly generated member functions will not have template
5484
information; they are
not instantiations, but instead are
5485
created
"fresh" for each instantiation.
*/
5486
&& DECL_TEMPLATE_INFO (t))
5487
tsubst_default_arguments (t);
5488
5489
popclass
();
5490
pop_from_top_level
();
5491
pop_deferring_access_checks
();
5492
pop_tinst_level ();
5493
5494
if (TYPE_CONTAINS_VPTR_P (type))
5495
keyed_classes = tree_cons (NULL_TREE, type,
keyed_classes);
5496
5497
return
type;
5498
}
然后记得通过
popclass
退出类的作用域;接着通过
pop_from_top_level
恢复原有的作用域。还有递减
tinst_depth
并通过
pop_tinst_level
更新
current_tinst_level
,它是
EXPR_WITH_FILE_LOCATION
类型的节点。因为类
C
包含
vtable
,它被视为锁定类(
keyed class
)。
从
instantiate_class_template
退出,我们回到
complete_type
,然后
layout_var_decl
。这个模板是在函数
main
中具现,因此
current_function_decl
指向该函数的作用域,那么在
layout_var_decl
的
4100
行,
push_local_name
把这个变量加入函数的作用域。
948
static
void
949
push_local_name
(tree decl)
in decl.c
950
{
951
size_t i, nelts;
952
tree t, name;
953
954
timevar_push (TV_NAME_LOOKUP);
955
if (!local_names)
956
VARRAY_TREE_INIT (local_names, 8,
"local_names");
957
958
name = DECL_NAME (decl);
959
960
nelts = VARRAY_ACTIVE_SIZE (local_names);
961
for
(i = 0; i < nelts; i++)
962
{
963
t = VARRAY_TREE (local_names, i);
964
if (DECL_NAME (t) == name)
965
{
966
if
(!DECL_LANG_SPECIFIC (decl))
967
retrofit_lang_decl (decl);
968
DECL_LANG_SPECIFIC
(decl)->decl_flags.u2sel = 1;
969
if
(DECL_LANG_SPECIFIC (t))
970
DECL_DISCRIMINATOR (decl) =
DECL_DISCRIMINATOR (t) + 1;
971
else
972
DECL_DISCRIMINATOR (decl) = 1;
973
974
VARRAY_TREE (local_names, i) = decl;
975
timevar_pop (TV_NAME_LOOKUP);
976
return
;
977
}
978
}
979
980
VARRAY_PUSH_TREE (local_names, decl);
981
timevar_pop (TV_NAME_LOOKUP);
982
}
上面的
local_names
是一个访问
cfun
的
language
部分
x_local_names
域的宏,这个域是一个可变的数组,保存了在由
cfun
所表示的函数中声明的布局名字。
5.12.5.2.2.2.1.5.
完成
VAR_DECL
现在我们回到了
cp_finish_decl
,曙光就在前面!
cp_finish_decl (continue)
4962
/* Output the
assembler code and/or RTL code for variables and functions,
4963
unless the type is an
undefined structure or union.
4964
If not, it will get done when
the type is completed.
*/
4965
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE
(decl) == FUNCTION_DECL)
4966
{
4967
if (TREE_CODE (decl) == VAR_DECL)
4968
maybe_commonize_var (decl);
4969
4970
make_rtl_for_nonlocal_decl (decl, init,
asmspec);
4971
4972
if (TREE_CODE (type) == FUNCTION_TYPE
4973
|| TREE_CODE (type) == METHOD_TYPE)
4974
abstract_virtuals_error
(decl,
4975
strip_array_types
(TREE_TYPE (type)));
4976
else if (POINTER_TYPE_P (type) || TREE_CODE
(type) == ARRAY_TYPE)
4977
{
…
4986
}
4987
else
4988
abstract_virtuals_error
(decl, type);
4989
4990
if (TREE_CODE (decl) == FUNCTION_DECL
4991
|| TREE_TYPE (decl) == error_mark_node)
4992
/* No
initialization required.
*/
4993
;
4994
else if (DECL_EXTERNAL (decl)
4995
&& ! (DECL_LANG_SPECIFIC
(decl)
4996
&&
DECL_NOT_REALLY_EXTERN (decl)))
4997
{
4998
if (init)
4999
DECL_INITIAL (decl) = init;
5000
}
5001
else
5002
{
5003
/* A variable
definition.
*/
5004
if
(DECL_FUNCTION_SCOPE_P (decl))
5005
{
5006
/* This is a
local declaration.
*/
5007
maybe_inject_for_scope_var (decl);
5008
/* Initialize
the local variable.
*/
5009
if (processing_template_decl)
5010
{
5011
if (init || DECL_INITIAL (decl) ==
error_mark_node)
5012
DECL_INITIAL (decl) = init;
5013
}
5014
else if (!TREE_STATIC (decl))
5015
initialize_local_var
(decl, init);
5016
}
5017
5018
/* If a
variable is defined, and then a subsequent
5019
definintion with external
linkage is encountered, we will
5020
get here twice for the
same variable. We want to avoid
5021
calling expand_static_init
more than once. For variables
5022
that are not static data
members, we can call
5023
expand_static_init only
when we actually process the
5024
initializer. It is not
legal to redeclare a static data
5025
member, so this issue does
not arise in that case.
*/
5026
if (var_definition_p &&
TREE_STATIC (decl))
5027
expand_static_init (decl, init);
5028
}
5029
finish_end0:
5030
5031
/* Undo call to
`pushclass' that was done in `start_decl'
5032
due to initialization of qualified member
variable.
5033
i.e., Foo::x = 10;
*/
5034
{
5035
tree context = CP_DECL_CONTEXT (decl);
5036
if (context
5037
&& TYPE_P (context)
5038
&& (TREE_CODE (decl) ==
VAR_DECL
5039
/* We
also have a pushclass done that we need to undo here
5040
if we're at top level and declare a
method.
*/
5041
|| TREE_CODE (decl) ==
FUNCTION_DECL)
5042
/* If size
hasn't been set, we're still defining it,
5043
and therefore inside the class body;
don't pop
5044
the binding level..
*/
5045
&& COMPLETE_TYPE_P (context)
5046
&& context == current_class_type
)
5047
pop_nested_class ();
5048
}
5049
}
5050
5051
/* If a
CLEANUP_STMT was created to destroy a temporary bound to a
5052
reference, insert it in the
statement-tree now.
*/
5053
if (cleanup)
5054
add_stmt (cleanup);
5055
5056
finish_end:
5057
5058
if (was_readonly)
5059
TREE_READONLY (decl) = 1;
5060
5061
/* If this was
marked 'used', be sure it will be output.
*/
5062
if (lookup_attribute ("used",
DECL_ATTRIBUTES (decl)))
5063
mark_referenced (DECL_ASSEMBLER_NAME
(decl));
5064
}
在函数剩余的代码里,为了把模板的具现
obj_
按照局部变量来处理,在
5015
行调用了
initialize_local_var
。
698
static
void
4699
initialize_local_var
(tree decl, tree
init)
in decl.c
4700
{
4701
tree type = TREE_TYPE (decl);
4702
tree cleanup;
4703
4704
my_friendly_assert (TREE_CODE (decl) ==
VAR_DECL
4705
|| TREE_CODE (decl) ==
RESULT_DECL,
4706
20021010);
4707
my_friendly_assert (!TREE_STATIC (decl),
20021010);
4708
4709
if (DECL_SIZE (decl) == NULL_TREE)
4710
{
4711
/* If we used it
already as memory, it must stay in memory.
*/
4712
DECL_INITIAL (decl) = NULL_TREE;
4713
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
4714
}
4715
4716
if (DECL_SIZE (decl) && type !=
error_mark_node)
4717
{
4718
int already_used;
4719
4720
/* Compute and store the initial value.
*/
4721
already_used = TREE_USED (decl) ||
TREE_USED (type);
4722
4723
/* Perform the
initialization.
*/
4724
if (init)
4725
{
4726
int saved_stmts_are_full_exprs_p;
4727
4728
my_friendly_assert (building_stmt_tree
(), 20000906);
4729
saved_stmts_are_full_exprs_p =
stmts_are_full_exprs_p ();
4730
current_stmt_tree
()->stmts_are_full_exprs_p = 1;
4731
finish_expr_stmt (init);
4732
current_stmt_tree
()->stmts_are_full_exprs_p =
4733
saved_stmts_are_full_exprs_p;
4734
}
4735
4736
/* Set this to 0
so we can tell whether an aggregate which was
4737
initialized was ever used.
Don't do this if it has a
4738
destructor, so we don't
complain about the 'resource
4739
allocation is
initialization' idiom. Now set
4740
attribute((unused)) on types
so decls of that type will be
4741
marked used. (see TREE_USED,
above.)
*/
4742
if (TYPE_NEEDS_CONSTRUCTING (type)
4743
&& ! already_used
4744
&& TYPE_HAS_TRIVIAL_DESTRUCTOR
(type)
4745
&& DECL_NAME (decl))
4746
TREE_USED (decl) = 0;
4747
else if (already_used)
4748
TREE_USED (decl) = 1;
4749
}
4750
4751
/* Generate a
cleanup, if necessary.
*/
4752
cleanup = cxx_maybe_build_cleanup
(decl);
4753
if (DECL_SIZE (decl) && cleanup)
4754
finish_decl_cleanup
(decl, cleanup);
4755
}
这里参数
init
来自声明符中跟在“
=
”后面的部分,它是由程序员指定的初始值,而不是在前面我们看到的由编译器指定的。显然,对于我们的例子,
init
是
NULL
。
接着看
4752
行的
cxx_maybe_build_cleanup
。编译器可能会插入代码来清除局部变量,在它退出其作用域时。
11215
tree
11216
cxx_maybe_build_cleanup
(tree decl)
in decl.c
11217
{
11218
tree type = TREE_TYPE (decl);
11219
11220
if (type != error_mark_node &&
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
11221
{
11222
int flags =
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
11223
tree rval;
11224
11225
if (TREE_CODE (type) == ARRAY_TYPE)
11226
rval = decl;
11227
else
11228
{
11229
cxx_mark_addressable (decl);
11230
rval = build_unary_op (ADDR_EXPR, decl,
0);
11231
}
11232
11233
/* Optimize for
space over speed here.
*/
11234
if (! TYPE_USES_VIRTUAL_BASECLASSES (type)
11235
|| flag_expensive_optimizations
)
11236
flags |= LOOKUP_NONVIRTUAL;
11237
11238
rval = build_delete
(TREE_TYPE (rval), rval,
11239
sfk_complete_destructor,
flags, 0);
11240
11241
if (TYPE_USES_VIRTUAL_BASECLASSES (type)
11242
&& ! TYPE_HAS_DESTRUCTOR
(type))
11243
rval = build_compound_expr (rval, build_vbase_delete
(type, decl));
11244
11245
return
rval;
11246
}
11247
return
NULL_TREE;
11248
}
断言
TYPE_HAS_NONTRIVIAL_DESTRUCTOR
是
true
,如果该类型的析构函数不是平凡的(对于某个类,如果我们没有定义析构函数,并且对于所有的基类及非静态数据成员,
TYPE_HAS_NONTRIVIAL_DESTRUCTOR
是
false
,那么对于这个类,
TYPE_HAS_NONTRIVIAL_DESTRUCTOR
返回
false
)。
这就是为什么如果析构函数不做任何事就不要定义它。虽然编译器会为你添加一个隐含的析构函数,但只要它的基类及非静态数据成员都具有平凡析构函数,它就会被标记为平凡。结果,在这里不会产生用于清除的代码。
如果期望清除操作,首先从局部变量
decl
构建出一个
ADDR_EXPR
,因为
delete
操作符总是作用于指针。在程序员使用
register
强制把变量放入寄存器的情形下,
cxx_mark_addressable
将修改所产生的代码以表示把这个局部变量放入栈中。
2866
tree
2867
build_delete
(tree type, tree addr,
special_function_kind auto_delete,
in init.c
2868
int flags, int use_global_delete)
2869
{
2870
tree expr;
2871
2872
if (addr == error_mark_node)
2873
return
error_mark_node;
2874
2875
/* Can happen when
CURRENT_EXCEPTION_OBJECT gets its type
2876
set to `error_mark_node'
before it gets properly cleaned up.
*/
2877
if (type == error_mark_node)
2878
return
error_mark_node;
2879
2880