5.12.3.2.1.2.1. Late parse inline methods
The parsing of rest members of the class “SingleThreaded” is almost the same as those we have seen. So we just skip these declarations, and assumes that now parser seeing the closing “}” of the class. Besides the similar handling of struct “Lock”, class “SingleThreaded”, being the top one, will undergo following processing.
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 }
Field unparsed_functions_queues of parser is a tree_list, whose TREE_PURPOSE field holds the chain recording default arguments of methods, and TREE_VALUE field is a chain recording inline methods defining in the class body. Note that these 2 chains are independent upon each other. For inline method, its recording tree_list has the node of METHOD_TYPE in its TREE_VALUE field (refers to cp_parser_save_member_function_body ). At time exitting the top-most class, we have enough information to handle these objects. So here it uses 2 loops to process default arguments and inline methods respectively.
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 }
Unprocessed inline method has DECL_PENDING_INLINE_P set. For our exmaple program, no function is parsed so far, so current_function_decl is null now. As we have seen, lexer feeds parser with tokens when advances ahead in the source. Now lexer stops at the end of the class body, but for parsing the body of inline method, the parser expects tokens forming the body which current lexer can’t provide. It is better to use a temperary lexer to feed parser with those cached tokens, and abandon it when finish. At line 14804, the temperary lexer is allocated in GC controls memory, and will be collected automatically after its release.
As an extension, GCC allows local class defined within function scope, and as result class methods can have class defined within too, and this fashion can be nested. For example, following code is valid in 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;
}
Then before processing funcB, cfun holds data of funcA; but during the processing of funcB, it must be updated with data of funcB. And after this handling, it must restore cfun with data of funcA. For the purpose, the front-end uses outer_function_chain records the function contexts in push_function_context_to at line 14799
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 }
For above example, outer_function_chain will record the function contexts as: funcB à funcA à func1 during processing funcB. And at line 348, the language dependent hook does specified task for C/C++ as below, it just copy the part of language_function in cfun .
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 }
Obviously pop operation at line 14822, should do reversely.
5.12.3.2.1.2.1.1. Start function handling
After creating temperary lexer, start_function will prepare and make the function scope into effective. See that argument flags indicates the inline method declaraction has been parsed; and argument declarator refers to the nodes of 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));
Previous, at line 11925 in cp_parser_class_specifier , routine finish_struct pops the scope of the class at line 5257, and current scope now is that of the containing class/namespace. It needs push back this scope again before going ahead to handling the inline method.
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 }
If the class is contained by another class, it is very possible we have exited from its scope, and it should be pushed into before. And for our example, it needs push back scope of “SingleThreaded”, then “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 has been created for the method (the non-default constructor), so at line 10321 push_template_decl just does some sainty check. Already at line 5254 in finish_struct , TYPE_BEING_DEFINED has been cleared.
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 }
At line 2929, tmpl refers to the TEMPLATE_DECL created in previous section. But for this TEMPLATE_DECL, DECL_TEMPLATE_INFO is still null. Then the same info is created again.
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));
In front-end, TREE_TYPE of METHOD_TYPE describes the returned type. Surprising, if the returned type is integer type having size less that int, it should be promoted to int type.
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 }
Promoting to int, is just to find out builtin integer type of desired size. In the procedure of setting up run-time environment, we can see details about creating internal presentation of such types and the way to find them out in the intermediate tree.
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 }
Above from line 10346 to 10352, the returned type, according to the specification of C++ language must be one defined or forward declared for case of address returned. Then if any cv-qualifier applied, in natural it has nothing different than type appears other place. However, the front-end needs to know the returned type of the function to do some optimization, so returned type has RESULT_DECL created for, and linked into DECL_RESULT field of the FUNCTION_DECL node. As result, the cv-qualifier applied is enforced upon the RESULT_DECL node instead by c_apply_type_quals_to_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 }
The so-called apply-type-quals-to-decl in fact sets relevant flags in the node.