下面的 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
5659
5660 if (ctype && (TYPE_ANONYMOUS_P (ctype)
5661 || decl_function_context (TYPE_MAIN_DECL (ctype))))
5662 publicp = 0;
5663
5664 if (publicp)
5665 {
5666
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 ;
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
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
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
10231 if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL)
10232 return 0;
10233
10234 cplus_decl_attributes (&decl1, attrs, 0);
10235
10236
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
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
10308 if (!DECL_INITIAL (decl1))
10309 DECL_INITIAL (decl1) = error_mark_node;
10310
10311
10313 TREE_STATIC (decl1) = 1;
…
10326
10327 current_function_decl = decl1;
10328
10329
10331 current_function_parms = DECL_ARGUMENTS (decl1);
10332
10333
10336 if (!processing_template_decl )
10337 check_function_type (decl1, current_function_parms);
10338
10339 check_default_args (decl1);
現在對應的 FUNCTION_DECL 節點及相應的引用更新如下圖。
對于我們的 “ main ” 函數 , check_function_type 隻是檢查參數類型及傳回類型是否是完整的類型 ( 而不僅是聲明 ) 。而 check_default_args 不做任何事情 , 因為我們沒有預設參數。
start_function(continue)
10341
10342 restype = TREE_TYPE (fntype);
10343
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
10359 bl = current_binding_level;
10360 allocate_struct_function (decl1);
10361 current_binding_level = bl;
10362
10363
10367 immediate_size_expand = 0;
10368 cfun ->x_dont_save_pending_sizes_p = 1;
10369
10370
10371 begin_stmt_tree (&DECL_SAVED_TREE (decl1));
10372
10373
10374 announce_function (decl1);
在 5.12.3.2.1.2.1.1.開始函數處理 一節中我們已經看過上面的函數,關于這些函數的細節參考該節内容。簡而言之,在繼續處理之前,我們得到以下子樹。注:在該圖中,“ (0) ”或“ (1) ”表示該域包含“ 0 ”或“ 1 ”,而“ [0] ”表示 tree_vec 的第 0 個成員,這個規則适用于所有的圖形。
( 點此打開 )
start_function(continue)
10376
10379 if (!processing_template_decl && !(flags & SF_PRE_PARSED))
10380 {
10381
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
10392 ;
10393 else
10394
10396 decl1 = olddecl;
10397 }
10398 else
10399 {
10400
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
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
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
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
10503 DECL_EXTERNAL (decl1) = 0;
10504
10505 if ((DECL_DECLARED_INLINE_P (decl1)
10506 || DECL_TEMPLATE_INSTANTIATION (decl1))
10507 && ! DECL_INTERFACE_KNOWN (decl1)
10508
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 , 傳回時,我們得到以下的節點。
( 點此打開 )