GCC-3.4.6源代码学习笔记(129 续)
来源:互联网 发布:传动轴加工工艺与编程 编辑:程序博客网 时间:2024/06/04 19:55
下面的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' tobe a template");
5646 if (inlinep)
5647 error ("cannot declare `::main' to beinline");
5648 if (!publicp)
5649 error ("cannot declare `::main' tobe 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 ofanonymous types and local classes have no linkage; make
5658 them internal. */
5659 /* FIXME what if it gets a namefrom 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 alocal scope) shall not be used to
5668 declare an entity withlinkage.
5669
5670 Only check this for publicdecls 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 /* Allowthis; 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 returndecl;
...
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 stupidregister 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 noneed to do this
8565 when processing a template;we'll do this for the instantiated
8566 declaration based on thetype of DECL. */
8567 if (!processing_template_decl)
8568 c_apply_type_quals_to_decl (type_quals, decl);
8569
8570 returndecl;
8571 }
8572 }
看到在下面decl被返回给decl1,这是对应的FUNCTION_DECL。因此下面的fntype指向这个FUNCTION_TYPE节点,而restype指向integer_type_node节点。
start_function(continue)
10229 /* If thedeclarator is not suitable for a function definition,
10230 cause a syntax error. */
10231 if (decl1 == NULL_TREE ||TREE_CODE (decl1) != FUNCTION_DECL)
10232 return0;
10233
10234 cplus_decl_attributes(&decl1, attrs, 0);
10235
10236 /* If #pragma weak was used, mark the declweak 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 ("returntype 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 (Thisdoes 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 /* Savethe parm names or decls from this function's declarator
10330 wherestore_parm_decls will find them. */
10331 current_function_parms = DECL_ARGUMENTS (decl1);
10332
10333 /* Make sure theparameter and return types are reasonable. When
10334 youdeclare a function, these types can be incomplete, but they
10335 mustbe complete when you define the function. */
10336 if (!processing_template_decl)
10337 check_function_type (decl1,current_function_parms);
10338 /* Make sure nodefault arg is missing. */
10339 check_default_args (decl1);
现在对应的FUNCTION_DECL节点及相应的引用更新如下图。
对于我们的“main”函数,check_function_type只是检查参数类型及返回类型是否是完整的类型(而不仅是声明)。而check_default_args不做任何事情,因为我们没有缺省参数。
start_function(continue)
10341 /* Build the returndeclaration for the function. */
10342 restype = TREE_TYPE (fntype);
10343 /* Promote thevalue 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 RTLmachinery. We cannot do this until
10355 CURRENT_FUNCTION_DECL and DECL_RESULT areset up. We do this
10356 even when processing a template; this ishow we get
10357 CFUN set up, and our per-function variablesinitialized.
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 thoughwe're inside a function body, we still don't want to
10364 call expand_expr to calculate the size of avariable-sized array.
10365 We haven't necessarily assigned RTL to allvariables yet, so it's
10366 not safe to try to expand expressionsinvolving them. */
10367 immediate_size_expand = 0;
10368 cfun->x_dont_save_pending_sizes_p = 1;
10369
10370 /* Start thestatement-tree, start the tree now. */
10371 begin_stmt_tree(&DECL_SAVED_TREE (decl1));
10372
10373 /* Let the userknow 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 declso 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 /* Aspecialization 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 /* Ifsomething went wrong when registering the declaration,
10390 use DECL1; we have to have aFUNCTION_DECL to use when
10391 parsing the body of thefunction. */
10392 ;
10393 else
10394 /* Otherwise,OLDDECL is either a previous declaration of
10395 the same function or DECL1itself. */
10396 decl1 = olddecl;
10397 }
10398 else
10399 {
10400 /* We need toset 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 incase 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 knewbefore. */
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 functionbelongs 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 templateinstantiations. */
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 adefinition, 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 tryto 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,返回时,我们得到以下的节点。
(点此打开)
- GCC-3.4.6源代码学习笔记(129 续)
- GCC-3.4.6源代码学习笔记(129)
- GCC-3.4.6源代码学习笔记(10续1)
- GCC-3.4.6源代码学习笔记(10续2)
- GCC-3.4.6源代码学习笔记(10续3)
- GCC-3.4.6源代码学习笔记(10续4)
- GCC-3.4.6源代码学习笔记(19续)
- GCC-3.4.6源代码学习笔记(24续)
- GCC-3.4.6源代码学习笔记(25续1)
- GCC-3.4.6源代码学习笔记(25续2)
- GCC-3.4.6源代码学习笔记(26续1)
- GCC-3.4.6源代码学习笔记(26续2)
- GCC-3.4.6源代码学习笔记(48续)
- GCC-3.4.6源代码学习笔记(48续2)
- GCC-3.4.6源代码学习笔记(139-续1)
- GCC-3.4.6源代码学习笔记(139-续2)
- GCC-3.4.6源代码学习笔记(140 - 续)
- GCC-3.4.6源代码学习笔记(141-续1)
- Flex array数组到java Object[] 的转换方法
- 效率最高的Excel数据导入续---SSIS Package包制作图解全过程
- beta技术沙龙:大型网站的Lucene应用
- 0.0
- LC.exe已退出,代码为-1
- GCC-3.4.6源代码学习笔记(129 续)
- NSOperation与performSelectorOnMainThread
- H.263:视频编码和解码(Video Coding and Decoding - CODEC rk)
- linux jdk环境变量设置
- H.261:视频编码和解码(Video Coding and Decoding - CODEC)
- G.7xx:视频/音频压缩协议(Audio/Voice Compression Protocols)
- Ubuntu10.0.4JDK安装
- VOIP Media/CODEC 协议组
- 用下载电缆实现AT89S5X的ISP编程