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

下面的 DECL_MAIN_P 返回非 0 值来表示遇到 main ”函数,对于该函数一些有趣的限制。看到 main 函数不能被声明为 inline ,而且永远是公有可访问的。

 

grokfndecl (continue)

 

5642     if (ctype == NULL_TREE && DECL_MAIN_P (decl))

5643     {

5644       if (processing_template_decl)

5645         error ("cannot declare `::main' to be a template");

5646       if (inlinep)

5647          error ("cannot declare `::main' to be inline");

5648       if (!publicp)

5649         error ("cannot declare `::main' to be static");

5650       if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),

5651                      integer_type_node))

5652         error ("`main' must return `int'");

5653       inlinep = 0;

5654       publicp = 1;

5655     }

5656  

5657     /* Members of anonymous types and local classes have no linkage; make

5658       them internal.  */

5659     /* FIXME what if it gets a name from typedef?  */

5660     if (ctype && (TYPE_ANONYMOUS_P (ctype)

5661        || decl_function_context (TYPE_MAIN_DECL (ctype))))

5662       publicp = 0;

5663  

5664     if (publicp)

5665     {

5666       /* [basic.link]: A name with no linkage (notably, the name of a class

5667         or enumeration declared in a local scope) shall not be used to

5668         declare an entity with linkage.

5669  

5670         Only check this for public decls for now. See core 319, 389.  */

5671       t = no_linkage_check (TREE_TYPE (decl));

5672       if (t)

5673       {

5674         if (TYPE_ANONYMOUS_P (t))

5675         {

5676           if (DECL_EXTERN_C_P (decl))

5677             /* Allow this; it's pretty common in C.  */;

5678           else

5679           {

5680             pedwarn ("non-local function `%#D' uses anonymous type",

5681                      decl);

5682             if (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))

5683               cp_pedwarn_at ("/

5684                           `%#D' does not refer to the unqualified type, so it is not used for linkage",

5685                           TYPE_NAME (t));

5686           }

5687         }

5688         else

5689           pedwarn ("non-local function `%#D' uses local type `%T'",

5690                   decl, t);

5691       }

5692     }

5693  

5694     TREE_PUBLIC (decl) = publicp;

        ...

5710     DECL_EXTERNAL (decl) = 1;

        ...

5870     if (ctype == NULL_TREE || check)

5871       return decl;

        ...

5877   }

 

3 】的 [basic.link] 一节给出了关于实体链接性的详细描述。

一个程序包含了一个或多个链接起来的编译单元。

Ÿ        一个名字被认为有链接性,当它可能代表,作为在另一个域中的声明所引入名字的,一个对象、引用、函数、类型、模板、名字空间或值:

当一个名字具有外部链接性时,其代表的实体可以被其他编译单元中的名字,或同一编译单元不同域中的名字所引用。

当一个名字具有内部链接性时,其代表的实体可以被同一编译单元不同域中的名字所引用。

当一个名字没有链接性时,其代表的实体不能被其他域中的名字所引用。

Ÿ        一个具有名字空间作用域( 3.3.5 )的名字具有内部链接性,如果它是如下的名字

一个显式声明为静态( static )的对象、引用、函数或函数模板,或者

一个显式声明为常量( const ),但没有声明为外部( extern ),或先前也没有声明为具有外部链接性的对象、引用;或者

匿名 union 的数据成员。

Ÿ        一个具有名字空间作用域的名字具有外部链接性,如果它是如下的名字

一个对象、引用,除非它具有内部链接性;或者

一个函数,除非它具有内部链接性;或者

一个具名类(条款 9 ),一个定义在 typedef 声明中的匿名类,在该声明中该类具有用于链接目的( 7.1.3 )的 typedef 名字;或者

一个具名枚举类型( 7.2 ),或者一个定义在 typedef 声明中的匿名枚举类型,在该声明中该枚举类型具有用于链接目的( 7.1.3 )的 typedef 名字;或者

一个从属域一个枚举类型的枚举值具有外部链接性;或者

一个模板,除非它是一个具有内部链接性(条款 14 )的函数模板;或者

一个名字空间( 7.3 ),除非它被声明在一个匿名名字空间中。

Ÿ        另外,类域中的成员函数、静态数据成员、类或枚举类型具有外部链接性,如果该类名具有外部链接性。

Ÿ        在一个块域中声明的函数名,及一个由块域中 extern 声明所声明的对象名,具有链接性。如果存在与一个具有链接性的实体的名字、类型相同的一个可见声明,忽略在最里层封闭名字空间作用域之外声明的实体,该块域中的声明声明了相同的实体,并且接受这个可见声明的链接性。如果存在多于一个匹配的实体,程序是错误的。否则,如果没有找到匹配的实体,块域中的实体接受外部链接性。【例如:

static void f();

static int i = 0; //1

void g() {

extern void f(); // internal linkage

int i; //2: i has no linkage

{

extern void f(); // internal linkage

extern int i; //3: external linkage

}

}

在这个程序中有 3 个对象被命名为 i 。具有内部链接性的对象被在全局作用域中的声明所引入(行 //1 ),具有自动存储周期且不具有链接性的对象由行 //2 的声明引入,而具有静态存储周期且具有外部链接性的对象由行 //3 的声明引入。】

Ÿ        当一个块域中一个具有链接性的实体没有发现引用其他声明,那么该实体是最里层封闭名字空间的一个成员。不过这样的声明不能在其名字空间作用域中引入成员名字。【例如:

namespace X {

void p() {

q(); //error: q not yet declared

extern void q(); // q is a member of namespace X

}

 

void middle() {

q(); //error: q not yet declared

}

void q() { /* ... */ } // definition of X::q

}

void q() { /* ... */ } // some other, unrelated q

Ÿ        不被这些规则所覆盖的名字不具有链接性。此外,除非另有说明,在一个局部域( 3.3.2 )中声明的名字不具有链接性。一个不具有链接性的名字(尤其是,在一个局部域中声明的一个类或枚举类型名)不应该用于声明一个具有链接性的实体。如果一个声明使用了一个 typedef 名,使用的链接性则来自 typedef 所引用的类型名【例如:

void f() {

struct A { int x; }; // no linkage

extern A a; // ill-formed

typedef A B;

extern B b; // ill-formed

}

这意味着不具有链接性的名字不能用作模板参数( 14.3 )。

Ÿ        两个相同的名字(条款 3 ),并且声明在不同的作用域中,应该代表相同的对象、引用、函数、类型、枚举类型、模板或名字空间,如果

两者具有外部链接性,或者两者具有内部链接性并声明在同一个编译单元中;而且

两者指向相同名字空间中的成员,或者同一个类的成员(不是通过继承);并且

当两者代表函数时,对于重载的目的,函数类型是相同的;并且

当两者代表函数模板,其签名( signatures 14.5.5.1 )是相同的。

Ÿ        在所有的类型调整之后(其中 typedef 7.1.3 )为其定义所替代),所有引用一个给定对象或函数的声明所指定的类型都应该相同,除了数组对象的声明可以指定有或没有主要数组边界( a major array bound 8.3.4 )的数组类型。对该规则的违反,不要求诊断。

5659 行的注释在 V4.3.0 中被移去,但没有改变代码。因为条款 8 (这个版本在这个规则被制定前完成)指出, typedef 名字应该遵循相同的规则;在前面关于处理 typedef 声明的章节中,我们可以看到有一个 TYPE_DECL 节点将为 typedef 声明所构建,并且将被置于同一个作用域中,代表被 typedef 的类型。随后当看到这个 typedef 名字时,我们使用这个 TYPE_DECL 节点,而且函数中的条件依然工作。在上面的 5661 行, decl_function_context 返回最里层的封闭函数作用域,如果没有这样的作用域返回 null

 

grokdeclarator (continue)

 

8550       my_friendly_assert (!RIDBIT_SETP (RID_MUTABLE, specbits), 19990927);

8551  

8552       /* Record `register' declaration for warnings on &

8553          and in case doing stupid register allocation.  */

8554  

8555       if (RIDBIT_SETP (RID_REGISTER, specbits))

8556         DECL_REGISTER (decl) = 1;

8557  

8558       if (RIDBIT_SETP (RID_EXTERN, specbits))

8559         DECL_THIS_EXTERN (decl) = 1;

8560  

8561       if (RIDBIT_SETP (RID_STATIC, specbits))

8562         DECL_THIS_STATIC (decl) = 1;

8563  

8564        /* Record constancy and volatility. There's no need to do this

8565          when processing a template; we'll do this for the instantiated

8566          declaration based on the type of DECL.  */

8567       if (!processing_template_decl)

8568         c_apply_type_quals_to_decl (type_quals, decl);

8569  

8570       return decl;

8571     }

8572   }

 

看到在下面 decl 被返回给 decl1 ,这是对应的 FUNCTION_DECL 。因此下面的 fntype 指向这个 FUNCTION_TYPE 节点,而 restype 指向 integer_type_node 节点。

 

start_function(continue)

 

10229     /* If the declarator is not suitable for a function definition,

10230       cause a syntax error.  */

10231     if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL)

10232       return 0;

10233

10234     cplus_decl_attributes (&decl1, attrs, 0);

10235

10236      /* If #pragma weak was used, mark the decl weak now.  */

10237     if (global_scope_p ( current_binding_level ))

10238       maybe_apply_pragma_weak (decl1);

10239

10240     fntype = TREE_TYPE (decl1);

10241

10242     restype = TREE_TYPE (fntype);

10243

10244     if (TREE_CODE (fntype) == METHOD_TYPE)

10245       ctype = TYPE_METHOD_BASETYPE (fntype);

10246     else if (DECL_MAIN_P (decl1))

10247     {

10248       /* If this doesn't return integer_type, or a typedef to

10249         integer_type, complain.  */

10250       if (!same_type_p (TREE_TYPE (TREE_TYPE (decl1)), integer_type_node))

10251       {

10252         if (pedantic || warn_return_type )

10253           pedwarn ("return type for `main' changed to `int'");

10254         TREE_TYPE (decl1) = fntype = default_function_type;

10255       }

10256     }

10257   }

       

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;

        …

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);

 

现在对应的 FUNCTION_DECL 节点及相应的引用更新如下图。

汤

对于我们的 main 函数 check_function_type 只是检查参数类型及返回类型是否是完整的类型 而不仅是声明 。而 check_default_args 不做任何事情 因为我们没有缺省参数。

 

start_function(continue)

 

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));

10372

10373   /* Let the user know we're compiling this function.  */

10374   announce_function (decl1);

 

5.12.3.2.1.2.1.1.开始函数处理 一节中我们已经看过上面的函数,关于这些函数的细节参考该节内容。简而言之,在继续处理之前,我们得到以下子树。注:在该图中,“ (0) ”或“ (1) ”表示该域包含“ 0 ”或“ 1 ”,而“ [0] ”表示 tree_vec 的第 0 个成员,这个规则适用于所有的图形。

点此打开

 

start_function(continue)

 

10376   /* Record the decl so that the function name is defined.

10377     If we already have a decl for this name, and it is a FUNCTION_DECL,

10378     use the old decl.  */

10379   if (!processing_template_decl && !(flags & SF_PRE_PARSED))

10380   {

10381     /* A specialization is not used to guide overload resolution.  */

10382     if (!DECL_FUNCTION_MEMBER_P (decl1)

10383        && !(DECL_USE_TEMPLATE (decl1) &&

10384             PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl1))))

10385     {

10386       tree olddecl = pushdecl (decl1);

10387

10388       if (olddecl == error_mark_node)

10389         /* If something went wrong when registering the declaration,

10390           use DECL1; we have to have a FUNCTION_DECL to use when

10391           parsing the body of the function.  */

10392         ;

10393       else

10394         /* Otherwise, OLDDECL is either a previous declaration of

10395           the same function or DECL1 itself.  */

10396         decl1 = olddecl;

10397     }

10398     else

10399     {

10400       /* We need to set the DECL_CONTEXT.  */

10401       if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1))

10402         DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1));

10403     }

10404     fntype = TREE_TYPE (decl1);

10405   }

10406

10407   /* Reset these in case the call to pushdecl changed them.  */

10408   current_function_decl = decl1;

10409   cfun ->decl = decl1;

 

因为在 10327 行, current_function_decl 指向 decl1 ,而 main 函数在全局名字空间中是新定义, pushdecl 把对应的 FUNCTION_DECL 链接入全局名字空间的 cxx_scope 节点的 name 域。在 10386 行, olddecl decl1 相同。

 

start_function(continue)

 

10411   /* If we are (erroneously) defining a function that we have already

10412      defined before, wipe out what we knew before.  */

10413   if (!DECL_PENDING_INLINE_P (decl1))

10414     DECL_SAVED_FUNCTION_DATA (decl1) = NULL;

10415

10416   if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))

10417   {

          ...

10447   }

10448

10449   if (DECL_INTERFACE_KNOWN (decl1))

10450   {

          ...

10461   }

10462   /* If this function belongs to an interface, it is public.

10463      If it belongs to someone else's interface, it is also external.

10464      This only affects inlines and template instantiations.  */

10465   else if (interface_unknown == 0

10466         && ! DECL_TEMPLATE_INSTANTIATION (decl1))

10467   {

          ...

10485   }

10486   else if (interface_unknown && interface_only

10487         && ! DECL_TEMPLATE_INSTANTIATION (decl1))

10488   {

          ...

10498   }

10499   else

10500   {

10501     /* This is a definition, not a reference.

10502       So clear DECL_EXTERNAL.  */

10503     DECL_EXTERNAL (decl1) = 0;

10504

10505     if ((DECL_DECLARED_INLINE_P (decl1)

10506          || DECL_TEMPLATE_INSTANTIATION (decl1))

10507        && ! DECL_INTERFACE_KNOWN (decl1)

10508        /* Don't try to defer nested functions for now.  */

10509        && ! decl_function_context (decl1))

10510       DECL_DEFER_OUTPUT (decl1) = 1;

10511     else

10512       DECL_INTERFACE_KNOWN (decl1) = 1;

10513   }

10514

10515   begin_scope (sk_function_parms, decl1);

10516

10517   ++function_depth ;

10518

10519   if (DECL_DESTRUCTOR_P (decl1))

10520   {

10521     dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);

10522     DECL_CONTEXT (dtor_label) = current_function_decl ;

10523   }

10524

10525   start_fname_decls ();

10526  

10527   store_parm_decls (current_function_parms);

10528

10529   return 1;

10530 }

 

当我们从 start_function , 返回时,我们得到以下的节点。

点此打开

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值