天天看點

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    

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 節點及相應的引用更新如下圖。

GCC-3.4.6源代碼學習筆記(129 續)

對于我們的 “ 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 , 傳回時,我們得到以下的節點。

( 點此打開 )

繼續閱讀