5.12.3.2.1.2.1. 延迟的内联函数解析
对类“ SingleThreaded ”余下方法的解析基本上与我们已见到的一样。因此我们跳过这些声明,并假设现在解析器看到了类结尾的“ } ”。除了与结构体“ Lock ”相似的处理外,类“ SingleThreaded ”,作为最顶层的类,将经受如下的处理。
cp_parser_class_specifier (continue)
11928 /* If this class is not itself within the scope of another class,
11929 then we need to parse the bodies of all of the queued function
11930 definitions. Note that the queued functions defined in a class
11931 are not always processed immediately following the
11932 class-specifier for that class. Consider:
11933
11934 struct A {
11935 struct B { void f() { sizeof (A); } };
11936 };
11937
11938 If `f' were processed before the processing of `A' were
11939 completed, there would be no way to compute the size of `A'.
11940 Note that the nesting we are interested in here is lexical --
11941 not the semantic nesting given by TYPE_CONTEXT. In particular,
11942 for:
11943
11944 struct A { struct B; };
11945 struct A::B { void f() { } };
11946
11947 there is no need to delay the parsing of `A::B::f'. */
11948 if (--parser->num_classes_being_defined == 0)
11949 {
11950 tree queue_entry;
11951 tree fn;
11952
11953 /* In a first pass, parse default arguments to the functions.
11954 Then, in a second pass, parse the bodies of the functions.
11955 This two-phased approach handles cases like:
11956
11957 struct S {
11958 void f() { g(); }
11959 void g(int i = 3);
11960 };
11961
11962 */
11963 for (TREE_PURPOSE (parser->unparsed_functions_queues)
11964 = nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
11965 (queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
11966 TREE_PURPOSE (parser->unparsed_functions_queues)
11967 = TREE_CHAIN (TREE_PURPOSE (parser->unparsed_functions_queues)))
11968 {
11969 fn = TREE_VALUE (queue_entry);
11970 /* Make sure that any template parameters are in scope. */
11971 maybe_begin_member_template_processing (fn);
11972 /* If there are default arguments that have not yet been processed,
11973 take care of them now. */
11974 cp_parser_late_parsing_default_args (parser, fn);
11975 /* Remove any template parameters from the symbol table. */
11976 maybe_end_member_template_processing ();
11977 }
11978 /* Now parse the body of the functions. */
11979 for (TREE_VALUE (parser->unparsed_functions_queues)
11980 = nreverse (TREE_VALUE (parser->unparsed_functions_queues));
11981 (queue_entry = TREE_VALUE (parser->unparsed_functions_queues));
11982 TREE_VALUE (parser->unparsed_functions_queues)
11983 = TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues)))
11984 {
11985 /* Figure out which function we need to process. */
11986 fn = TREE_VALUE (queue_entry);
11987
11988 /* A hack to prevent garbage collection. */
11989 function_depth ++;
11990
11991 /* Parse the function. */
11992 cp_parser_late_parsing_for_member (parser, fn);
11993 function_depth --;
11994 }
11995
11996 }
11997
11998 /* Put back any saved access checks. */
11999 pop_deferring_access_checks ();
12000
12001 /* Restore the count of active template-parameter-lists. */
12002 parser->num_template_parameter_lists
12003 = saved_num_template_parameter_lists;
12004
12005 return type;
12006 }
parser 的 unparsed_functions_queues 是一个 tree_list 节点,其 TREE_PURPOSE 域是记录函数默认参数的链表,而其 TREE_VALUE 域则记录了定义在类定义体中的内联函数。注意这 2 个链表是相互独立的。对于内联函数,记录它的 tree_list 节点的 TREE_VALUE 域是一个 METHOD_TYPE 节点(参见 cp_parser_save_member_function_body )。在我们退出最顶层类定义体这一刻,我们有足够的信息来处理这些对象。这里使用 2 个循环分别处理默认参数及内联函数。
14759 static void
14760 cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) in parser.c
14761 {
14762 cp_lexer *saved_lexer;
14763
14764 /* If this member is a template, get the underlying
14765 FUNCTION_DECL. */
14766 if (DECL_FUNCTION_TEMPLATE_P (member_function))
14767 member_function = DECL_TEMPLATE_RESULT (member_function);
14768
14769 /* There should not be any class definitions in progress at this
14770 point; the bodies of members are only parsed outside of all class
14771 definitions. */
14772 my_friendly_assert (parser->num_classes_being_defined == 0, 20010816);
14773 /* While we're parsing the member functions we might encounter more
14774 classes. We want to handle them right away, but we don't want
14775 them getting mixed up with functions that are currently in the
14776 queue. */
14777 parser->unparsed_functions_queues
14778 = tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
14779
14780 /* Make sure that any template parameters are in scope. */
14781 maybe_begin_member_template_processing (member_function);
14782
14783 /* If the body of the function has not yet been parsed, parse it
14784 now. */
14785 if (DECL_PENDING_INLINE_P (member_function))
14786 {
14787 tree function_scope;
14788 cp_token_cache *tokens;
14789
14790 /* The function is no longer pending; we are processing it. */
14791 tokens = DECL_PENDING_INLINE_INFO (member_function);
14792 DECL_PENDING_INLINE_INFO (member_function) = NULL;
14793 DECL_PENDING_INLINE_P (member_function) = 0;
14794
14795 /* If this is a local class, enter the scope of the containing
14796 function. */
14797 function_scope = current_function_decl ;
14798 if (function_scope)
14799 push_function_context_to (function_scope);
14800
14801 /* Save away the current lexer. */
14802 saved_lexer = parser->lexer;
14803 /* Make a new lexer to feed us the tokens saved for this function. */
14804 parser->lexer = cp_lexer_new_from_tokens (tokens);
14805 parser->lexer->next = saved_lexer;
14806
14807 /* Set the current source position to be the location of the first
14808 token in the saved inline body. */
14809 cp_lexer_peek_token (parser->lexer);
14810
14811 /* Let the front end know that we going to be defining this
14812 function. */
14813 start_function (NULL_TREE, member_function, NULL_TREE,
14814 SF_PRE_PARSED | SF_INCLASS_INLINE);
14815
14816 /* Now, parse the body of the function. */
14817 cp_parser_function_definition_after_declarator (parser,
14818 /*inline_p=*/ true);
14819
14820 /* Leave the scope of the containing function. */
14821 if (function_scope)
14822 pop_function_context_from (function_scope);
14823 /* Restore the lexer. */
14824 parser->lexer = saved_lexer;
14825 }
14826
14827 /* Remove any template parameters from the symbol table. */
14828 maybe_end_member_template_processing ();
14829
14830 /* Restore the queue. */
14831 parser->unparsed_functions_queues
14832 = TREE_CHAIN (parser->unparsed_functions_queues);
14833 }
未处理的内联函数设置了 DECL_PENDING_INLINE_P 。对于我们的例子程序, 至今尚未解析函数 , 因此 current_function_decl 现在是 null 。我们已经看到,词法分析器在源文件中推进的同时向解析器提供符号。 现在词法分析器停在类定义体的末尾,但是为了解析内联函数,解析器期望得到构成内联函数体的符号,这是当前词法分析器所不能提供的。最好使用一个临时词法分析器来为解析器提供缓存的符号,在完成时将之丢弃。在 14804 行,这个临时词法分析器在 GC 管理的内存中分配,在释放后它会被自动回收。
作为一个扩展, GCC 允许在函数作用域中定义局部类,因此类方法中亦可定义类,并且这个形式可以嵌套。例如,下面的代码在 GCC 中是有效的。
#include <stdio.h>
void func1 () {
struct A {
void funcA() {
struct B {
void funcB() { printf ("funcB/n"); }
};
B b;
b.funcB();
}
};
A a;
a.funcA();
}
main() {
func1();
return 0;
}
那么在处理 funcB 之前 , cfun 保存了 funcA 的数据 , 但在处理 funcB 的过程中 , 它必须更新为 funcB 的数据。然后在处理后 , 必须把 cfun 恢复为 funcA 的数据。出于这个目的,前端在 14799 行 push_function_context_to 的中,使用 outer_function_chain 来记录函数上下文。
324 void
325 push_function_context_to (tree context) in function.c
326 {
327 struct function *p;
328
329 if (context)
330 {
331 if (context == current_function_decl )
332 cfun ->contains_functions = 1;
333 else
334 {
335 struct function *containing = find_function_data (context);
336 containing->contains_functions = 1;
337 }
338 }
339
340 if (cfun == 0)
341 init_dummy_function_start ();
342 p = cfun ;
343
344 p->outer = outer_function_chain ;
345 outer_function_chain = p;
346 p->fixup_var_refs_queue = 0;
347
348 (*lang_hooks .function.enter_nested ) (p);
349
350 cfun = 0;
351 }
对于上面的例子, outer_function_chain 在处理 funcB 期间,将记录如下的函数上下文: funcB à funcA à func1 。而在 348 行,与语言相关的钩子为 C/C++ 执行如下指定任务,它拷贝 cfun 的 language_function 部分。
6289 void
6290 c_push_function_context (struct function *f) in c-decl.c
6291 {
6292 struct language_function *p;
6293 p = ggc_alloc (sizeof (struct language_function));
6294 f->language = p;
6295
6296 p->base.x_stmt_tree = c_stmt_tree ;
6297 p->base.x_scope_stmt_stack = c_scope_stmt_stack ;
6298 p->x_in_iteration_stmt = c_in_iteration_stmt ;
6299 p->x_in_case_stmt = c_in_case_stmt ;
6300 p->returns_value = current_function_returns_value ;
6301 p->returns_null = current_function_returns_null ;
6302 p->returns_abnormally = current_function_returns_abnormally ;
6303 p->warn_about_return_type = warn_about_return_type ;
6304 p->extern_inline = current_extern_inline ;
6305 }
显然在 14822 行的 pop 操作应该执行相反的过程。
5.12.3.2.1.2.1.1. 开始函数处理
创建了临时的词法分析器后, start_function 将准备并使得函数作用域成为有效作用域。看到参数 flags 表示该内联函数声明已经被解析了,而参数 declarator 指向对应的 METHOD_TYPE 节点。
10181 int
10182 start_function (tree declspecs, tree declarator, tree attrs, int flags) in decl.c
10183 {
10184 tree decl1;
10185 tree ctype = NULL_TREE;
10186 tree fntype;
10187 tree restype;
10188 int doing_friend = 0;
10189 struct cp_binding_level *bl;
10190 tree current_function_parms;
10191
10192 /* Sanity check. */
10193 my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
10194 my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
10195
10196 /* This should only be done once on the top most decl. */
10197 if (have_extern_spec )
10198 {
10199 declspecs = tree_cons (NULL_TREE, get_identifier ("extern"), declspecs);
10200 have_extern_spec = false;
10201 }
10202
10203 if (flags & SF_PRE_PARSED)
10204 {
10205 decl1 = declarator;
10206
10207 fntype = TREE_TYPE (decl1);
10208 if (TREE_CODE (fntype) == METHOD_TYPE)
10209 ctype = TYPE_METHOD_BASETYPE (fntype);
10210
10211 /* ISO C++ 11.4/5. A friend function defined in a class is in
10212 the (lexical) scope of the class in which it is defined. */
10213 if (!ctype && DECL_FRIEND_P (decl1))
10214 {
10215 ctype = DECL_FRIEND_CONTEXT (decl1);
10216
10217 /* CTYPE could be null here if we're dealing with a template;
10218 for example, `inline friend float foo()' inside a template
10219 will have no CTYPE set. */
10220 if (ctype && TREE_CODE (ctype) != RECORD_TYPE)
10221 ctype = NULL_TREE;
10222 else
10223 doing_friend = 1;
10224 }
10225 }
10226 else
10227 {
…
10257 }
10258
10259 if (DECL_DECLARED_INLINE_P (decl1)
10260 && lookup_attribute ("noinline", attrs))
10261 warning ("%Jinline function '%D' given attribute noinline", decl1, decl1);
10262
10263 if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1))
10264 /* This is a constructor, we must ensure that any default args
10265 introduced by this definition are propagated to the clones
10266 now. The clones are used directly in overload resolution. */
10267 adjust_clone_args (decl1);
10268
10269 /* Sometimes we don't notice that a function is a static member, and
10270 build a METHOD_TYPE for it. Fix that up now. */
10271 if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
10272 && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
10273 {
10274 revert_static_member_fn (decl1);
10275 ctype = NULL_TREE;
10276 }
10277
10278 /* Warn if function was previously implicitly declared
10279 (but not if we warned then). */
10280 if (! warn_implicit
10281 && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE)
10282 cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
10283
10284 /* Set up current_class_type, and enter the scope of the class, if
10285 appropriate. */
10286 if (ctype)
10287 push_nested_class (ctype);
10288 else if (DECL_STATIC_FUNCTION_P (decl1))
10289 push_nested_class (DECL_CONTEXT (decl1));
之前,在 cp_parser_class_specifier 的 11925 行, finish_struct 在 5257 行弹出类的作用域,现在当前作用域是包含其的类或名字空间。因此在处理内联函数之前,需要重新加入这个作用域。
5627 void
5628 push_nested_class (tree type) in class.c
5629 {
5630 tree context;
5631
5632 /* A namespace might be passed in error cases, like A::B:C. */
5633 if (type == NULL_TREE
5634 || type == error_mark_node
5635 || TREE_CODE (type) == NAMESPACE_DECL
5636 || ! IS_AGGR_TYPE (type)
5637 || TREE_CODE (type) == TEMPLATE_TYPE_PARM
5638 || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
5639 return ;
5640
5641 context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
5642
5643 if (context && CLASS_TYPE_P (context))
5644 push_nested_class (context);
5645 pushclass (type);
5646 }
如果这个类被包含在另一个类里,很可能我们已经退出其作用域,也需要先加会这个作用域。而对于我们的例子,需要恢复“ SingleThreaded ”,然后“ Lock ”的作用域。
start_function (continue)
10291 /* Now that we have entered the scope of the class, we must restore
10292 the bindings for any template parameters surrounding DECL1, if it
10293 is an inline member template. (Order is important; consider the
10294 case where a template parameter has the same name as a field of
10295 the class.) It is not until after this point that
10296 PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly. */
10297 if (flags & SF_INCLASS_INLINE)
10298 maybe_begin_member_template_processing (decl1);
10299
10300 /* Effective C++ rule 15. */
10301 if (warn_ecpp
10302 && DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
10303 && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
10304 warning ("`operator=' should return a reference to `*this'");
10305
10306 /* Make the init_value nonzero so pushdecl knows this is not tentative.
10307 error_mark_node is replaced below (in poplevel) with the BLOCK. */
10308 if (!DECL_INITIAL (decl1))
10309 DECL_INITIAL (decl1) = error_mark_node;
10310
10311 /* This function exists in static storage.
10312 (This does not mean `static' in the C sense!) */
10313 TREE_STATIC (decl1) = 1;
10314
10315 /* We must call push_template_decl after current_class_type is set
10316 up. (If we are processing inline definitions after exiting a
10317 class scope, current_class_type will be NULL_TREE until set above
10318 by push_nested_class.) */
10319 if (processing_template_decl )
10320 {
10321 tree newdecl1 = push_template_decl (decl1);
10322 if (newdecl1 != error_mark_node)
10323 decl1 = newdecl1;
10324 }
TEMPLATE_DECL 已经为该方法(非默认构造函数)所构建,因此在 10321 行的 push_template_decl 仅执行一些有效性检查。在函数 finish_struct 的 5254 行,标记 TYPE_BEING_DEFINED 已经被清除。
2770 tree
2771 push_template_decl_real (tree decl, int is_friend) in pt.c
2772 {
2773 tree tmpl;
2774 tree args;
2775 tree info;
2776 tree ctx;
2777 int primary;
2778 int is_partial;
2779 int new_template_p = 0;
2780
2781 /* See if this is a partial specialization. */
2782 is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
2783 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
2784 && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
2785
2786 is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
2787
2788 if (is_friend)
2789 /* For a friend, we want the context of the friend function, not
2790 the type of which it is a friend. */
2791 ctx = DECL_CONTEXT (decl);
2792 else if (CP_DECL_CONTEXT (decl)
2793 && TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL)
2794 /* In the case of a virtual function, we want the class in which
2795 it is defined. */
2796 ctx = CP_DECL_CONTEXT (decl);
2797 else
2798 /* Otherwise, if we're currently defining some class, the DECL
2799 is assumed to be a member of the class. */
2800 ctx = current_scope ();
2801
2802 if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)
2803 ctx = NULL_TREE;
2804
2805 if (!DECL_CONTEXT (decl))
2806 DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
2807
2808 /* See if this is a primary template. */
2809 primary = template_parm_scope_p ();
2810
2811 if (primary)
2812 {
...
2852 }
2853
2854 /* Check to see that the rules regarding the use of default
2855 arguments are not being violated. */
2856 check_default_tmpl_args (decl, current_template_parms,
2857 primary, is_partial);
2858
2859 if (is_partial)
2860 return process_partial_specialization (decl);
2861
2862 args = current_template_args ();
2863
2864 if (!ctx
2865 || TREE_CODE (ctx) == FUNCTION_DECL
2866 || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
2867 || (is_friend && !DECL_TEMPLATE_INFO (decl)))
2868 {
...
2904 }
2905 else
2906 {
2907 tree a, t, current, parms;
2908 int i;
2909
2910 if (TREE_CODE (decl) == TYPE_DECL)
2911 {
...
2922 }
2923 else if (!DECL_LANG_SPECIFIC (decl) || !DECL_TEMPLATE_INFO (decl))
2924 {
2925 error ("template definition of non-template `%#D'", decl);
2926 return decl;
2927 }
2928 else
2929 tmpl = DECL_TI_TEMPLATE (decl);
2930
2931 if (DECL_FUNCTION_TEMPLATE_P (tmpl)
2932 && DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl)
2933 && DECL_TEMPLATE_SPECIALIZATION (decl)
2934 && is_member_template (tmpl))
2935 {
...
2958 }
2959
2960 /* Make sure the template headers we got make sense. */
2961
2962 parms = DECL_TEMPLATE_PARMS (tmpl);
2963 i = TMPL_PARMS_DEPTH (parms);
2964 if (TMPL_ARGS_DEPTH (args) != i)
2965 {
2966 error ("expected %d levels of template parms for `%#D', got %d",
2967 i, decl, TMPL_ARGS_DEPTH (args));
2968 }
2969 else
2970 for (current = decl; i > 0; --i, parms = TREE_CHAIN (parms))
2971 {
2972 a = TMPL_ARGS_LEVEL (args, i);
2973 t = INNERMOST_TEMPLATE_PARMS (parms);
2974
2975 if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
2976 {
2977 if (current == decl)
2978 error ("got %d template parameters for `%#D'",
2979 TREE_VEC_LENGTH (a), decl);
2980 else
2981 error ("got %d template parameters for `%#T'",
2982 TREE_VEC_LENGTH (a), current);
2983 error (" but %d required", TREE_VEC_LENGTH (t));
2984 return error_mark_node;
2985 }
2986
2987 /* Perhaps we should also check that the parms are used in the
2988 appropriate qualifying scopes in the declarator? */
2989
2990 if (current == decl)
2991 current = ctx;
2992 else
2993 current = TYPE_CONTEXT (current);
2994 }
2995 }
2996
2997 DECL_TEMPLATE_RESULT (tmpl) = decl;
2998 TREE_TYPE (tmpl) = TREE_TYPE (decl);
2999
3000 /* Push template declarations for global functions and types. Note
3001 that we do not try to push a global template friend declared in a
3002 template class; such a thing may well depend on the template
3003 parameters of the class. */
3004 if (new_template_p && !ctx
3005 && !(is_friend && template_class_depth (current_class_type ) > 0))
3006 tmpl = pushdecl_namespace_level (tmpl);
3007
3008 if (primary)
3009 {
...
3022 }
3023
3024 /* The DECL_TI_ARGS of DECL contains full set of arguments refering
3025 back to its most general template. If TMPL is a specialization,
3026 ARGS may only have the innermost set of arguments. Add the missing
3027 argument levels if necessary. */
3028 if (DECL_TEMPLATE_INFO (tmpl))
3029 args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args);
3030
3031 info = tree_cons (tmpl, args, NULL_TREE);
3032
3033 if (DECL_IMPLICIT_TYPEDEF_P (decl))
3034 {
...
3041 }
3042 else if (DECL_LANG_SPECIFIC (decl))
3043 DECL_TEMPLATE_INFO (decl) = info;
3044
3045 return DECL_TEMPLATE_RESULT (tmpl);
3046 }
在 2929 行, tmpl 指向前面所构建的 TEMPLATE_DECL 节点。而对于这个 TEMPLATE_DECL , DECL_TEMPLATE_INFO 仍然是 null 。那么同样的 info 被同样创建。
start_function (continue)
10326 /* We are now in the scope of the function being defined. */
10327 current_function_decl = decl1;
10328
10329 /* Save the parm names or decls from this function's declarator
10330 where store_parm_decls will find them. */
10331 current_function_parms = DECL_ARGUMENTS (decl1);
10332
10333 /* Make sure the parameter and return types are reasonable. When
10334 you declare a function, these types can be incomplete, but they
10335 must be complete when you define the function. */
10336 if (!processing_template_decl )
10337 check_function_type (decl1, current_function_parms);
10338 /* Make sure no default arg is missing. */
10339 check_default_args (decl1);
10340
10341 /* Build the return declaration for the function. */
10342 restype = TREE_TYPE (fntype);
10343 /* Promote the value to int before returning it. */
10344 if (c_promoting_integer_type_p (restype))
10345 restype = type_promotes_to (restype);
10346 if (DECL_RESULT (decl1) == NULL_TREE)
10347 {
10348 DECL_RESULT (decl1)
10349 = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
10350 c_apply_type_quals_to_decl (cp_type_quals (restype),
10351 DECL_RESULT (decl1));
10352 }
10353
10354 /* Initialize RTL machinery. We cannot do this until
10355 CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this
10356 even when processing a template; this is how we get
10357 CFUN set up, and our per-function variables initialized.
10358 FIXME factor out the non-RTL stuff. */
10359 bl = current_binding_level ;
10360 allocate_struct_function (decl1);
10361 current_binding_level = bl;
10362
10363 /* Even though we're inside a function body, we still don't want to
10364 call expand_expr to calculate the size of a variable-sized array.
10365 We haven't necessarily assigned RTL to all variables yet, so it's
10366 not safe to try to expand expressions involving them. */
10367 immediate_size_expand = 0;
10368 cfun ->x_dont_save_pending_sizes_p = 1;
10369
10370 /* Start the statement-tree, start the tree now. */
10371 begin_stmt_tree (&DECL_SAVED_TREE (decl1));
在前端中, METHOD_TYPE 的 TREE_TYPE 描述了返回类型。令人惊奇的是,如果返回类型是整形而且其大小小于 int ,它将被提升至 int 类型。
3560 bool
3561 c_promoting_integer_type_p (tree t) in c-common.c
3562 {
3563 switch (TREE_CODE (t))
3564 {
3565 case INTEGER_TYPE:
3566 return (TYPE_MAIN_VARIANT (t) == char_type_node
3567 || TYPE_MAIN_VARIANT (t) == signed_char_type_node
3568 || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node
3569 || TYPE_MAIN_VARIANT (t) == short_integer_type_node
3570 || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node
3571 || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node));
3572
3573 case ENUMERAL_TYPE:
3574 /* ??? Technically all enumerations not larger than an int
3575 promote to an int. But this is used along code paths
3576 that only want to notice a size change. */
3577 return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node);
3578
3579 case BOOLEAN_TYPE:
3580 return 1;
3580
3581 default :
3582 return 0;
3583 }
3584 }
提升至 int ,只是意味着找出具有期望大小的内建整数类型。在设立运行时环境的过程中,我们已经见到了这样类型的内部表达形式的创建细节,并且在中间树中查找它们的方法。
1115 tree
1116 type_promotes_to (tree type) in cvt.c
1117 {
1118 if (type == error_mark_node)
1119 return error_mark_node;
1120
1121 type = TYPE_MAIN_VARIANT (type);
1122
1123 /* bool always promotes to int (not unsigned), even if it's the same
1124 size. */
1125 if (type == boolean_type_node)
1126 type = integer_type_node;
1127
1128 /* Normally convert enums to int, but convert wide enums to something
1129 wider. */
1130 else if (TREE_CODE (type) == ENUMERAL_TYPE
1131 || type == wchar_type_node)
1132 {
1133 int precision = MAX (TYPE_PRECISION (type),
1134 TYPE_PRECISION (integer_type_node));
1135 tree totype = c_common_type_for_size (precision, 0);
1136 if (TREE_UNSIGNED (type)
1137 && ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
1138 type = c_common_type_for_size (precision, 1);
1139 else
1140 type = totype;
1141 }
1142 else if (c_promoting_integer_type_p (type))
1143 {
1144 /* Retain unsignedness if really not getting bigger. */
1145 if (TREE_UNSIGNED (type)
1146 && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
1147 type = unsigned_type_node;
1148 else
1149 type = integer_type_node;
1150 }
1151 else if (type == float_type_node)
1152 type = double_type_node;
1153
1154 return type;
1155 }
上面从 10346 到 10352 行,这个返回类型,根据 C++ 语言规范,在返回地址的情况下,必须是一个已经被定义或前向声明的类型。那么如果应用了任意的 cv-qualifier ,本质上它与应用在其他地方没有什么不同。但是,前端需要知道该函数的返回类型来进行某些优化,因此为返回类型构建 RESULT_DECL 节点,并链接入对应 FUNCTION_DECL 节点的 DECL_RESULT 域。最后, cv-qualifier 通过 c_apply_type_quals_to_decl 应用到 RESULT_DECL 节点中。
2805 void
2806 c_apply_type_quals_to_decl (int type_quals, tree decl) in c-common.c
2807 {
2808 tree type = TREE_TYPE (decl);
2809
2810 if (type == error_mark_node)
2811 return ;
2812
2813 if (((type_quals & TYPE_QUAL_CONST)
2814 || (type && TREE_CODE (type) == REFERENCE_TYPE))
2815 /* An object declared 'const' is only readonly after it is
2816 initialized. We don't have any way of expressing this currently,
2817 so we need to be conservative and unset TREE_READONLY for types
2818 with constructors. Otherwise aliasing code will ignore stores in
2819 an inline constructor. */
2820 && !(type && TYPE_NEEDS_CONSTRUCTING (type)))
2821 TREE_READONLY (decl) = 1;
2822 if (type_quals & TYPE_QUAL_VOLATILE)
2823 {
2824 TREE_SIDE_EFFECTS (decl) = 1;
2825 TREE_THIS_VOLATILE (decl) = 1;
2826 }
2827 if (type_quals & TYPE_QUAL_RESTRICT)
2828 {
2829 while (type && TREE_CODE (type) == ARRAY_TYPE)
2830 /* Allow 'restrict' on arrays of pointers.
2831 FIXME currently we just ignore it. */
2832 type = TREE_TYPE (type);
2833 if (!type
2834 || !POINTER_TYPE_P (type)
2835 || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
2836 error ("invalid use of `restrict'");
2837 else if (flag_strict_aliasing && type == TREE_TYPE (decl))
2838 /* Indicate we need to make a unique alias set for this pointer.
2839 We can't do it here because it might be pointing to an
2840 incomplete type. */
2841 DECL_POINTER_ALIAS_SET (decl) = -2;
2842 }
2843 }
这个所谓的 apply-type-quals-to-decl (应用类型限定符至声明)实际上设置对应节点的相关标记。