GCC-3.4.6源代码学习笔记(107)

5.12.3.2.1.2.  完成解析

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 (应用类型限定符至声明)实际上设置对应节点的相关标记。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值