天天看點

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

5.9.2.2.    是否從友元通路

如果 protected_accessible_p 傳回非 0 值,目前類的派生樹包含了 decl ,而且 type 是目前類的一個基類( protected_accessible_p 的 837 行語句塊保證),那麼可以直接去檢查其通路屬性,而且 protected 以上即可。否則,如果目前類的派生樹不包含 decl ,或者 type 不是目前類的基類,那麼需要檢查目前作用域是否是可以通路 decl 的友元。函數 friend_accessible_p 的參數 scope (目前作用域)由下面的 current_scope 獲得。

550  tree

551  current_scope (void)                                                                                  in search.c

552  {

553    if (current_function_decl == NULL_TREE)

554      return current_class_type ;

555    if (current_class_type == NULL_TREE)

556      return current_function_decl ;

557    if ((DECL_FUNCTION_MEMBER_P (current_function_decl )

558         && same_type_p (DECL_CONTEXT (current_function_decl ),

559                           current_class_type ))

560        || (DECL_FRIEND_CONTEXT (current_function_decl )

561           && same_type_p (DECL_FRIEND_CONTEXT (current_function_decl ),

562                          current_class_type )))

563      return current_function_decl ;

564 

565    return current_class_type ;

566  }

current_class_type 和 current_function_decl 的設定情況如下表給出。

current_class_type current_function_decl
global NULL NULL
function-local NULL SET
class-local SET NULL
class->function * SET SET
function->class ** SET SET

* :包括類的函數友元。 ** : GNU 的擴充,函數内的局部類

這時需要考慮的情況就是:接受目前域(可以是類,或者函數)作為友元的類包含了 decl ,而且 type 是其的一個基類。在函數 friend_accessible_p 中,參數 binfo 來自 type 。

855  static int

856  friend_accessible_p (tree scope, tree decl, tree binfo)                                           in search.c

857  {

858    tree befriending_classes;

859    tree t;

860 

861    if (!scope)

862      return 0;

863 

864    if (TREE_CODE (scope) == FUNCTION_DECL

865       || DECL_FUNCTION_TEMPLATE_P (scope))

866      befriending_classes = DECL_BEFRIENDING_CLASSES (scope);

867    else if (TYPE_P (scope))

868      befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);

869    else

870      return 0;

871 

872    for (t = befriending_classes; t; t = TREE_CHAIN (t))

873      if (protected_accessible_p (decl, TREE_VALUE (t), binfo))

874        return 1;

875 

876   

878    if (TYPE_P (scope))

879      for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))

880        if (protected_accessible_p (decl, t, binfo))

881          return 1;

882 

883    if (TREE_CODE (scope) == FUNCTION_DECL

884      || DECL_FUNCTION_TEMPLATE_P (scope))

885    {

886     

888      if (DECL_CLASS_SCOPE_P (decl)

889         && friend_accessible_p (DECL_CONTEXT (scope), decl, binfo))

890        return 1;

891 

892     

893      if (DECL_TEMPLATE_INFO (scope))

894      {

895        int ret;

896       

898        ++processing_template_decl;

899        ret = friend_accessible_p (DECL_TI_TEMPLATE (scope), decl, binfo);

900        --processing_template_decl;

901        return ret;

902      }

903    }

904    else if (CLASSTYPE_TEMPLATE_INFO (scope))

905    {

906      int ret;

907     

909      ++processing_template_decl;

910      ret = friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope), decl, binfo);

911       --processing_template_decl;

912      return ret;

913    }

914 

915    return 0;

916  }

上面的 befriending_classes 就是目前函數或類作為友元的類的清單。如果對于這些類, protected_accessible_p 還是傳回 0 ,如果 scope 代表一個類,那麼這裡的做法是繼續逐級檢查包含 scope 的類;而如果 scope 代表一個類方法,則繼續考察其所在類作為友元的情形。 893 行表示該方法是一個模闆函數, DECL_TI_TEMPLATE 是代表其特化或具現的節點。而 904 行表示是一個模闆類, CLASSTYPE_TI_TEMPLATE 是代表其特化或具現的節點。這是考察模闆的特化類型是否是所期望的友元。

5.9.2.3.    确定通路屬性

從上面看到,如果 protected_accessible_p 或 friend_accessible_p 傳回非 0 值,表明 decl 和 type 都在同一棵派生樹裡。那麼接下來,在 accessible_p 的 1000 行,調用 access_in_type 來考察 type 對 decl 的通路屬性。如果結果在 protected 級别以上,毫無疑問, type 可以通路 decl 。但是對于友元來說, private 級别也不是問題。是以,如果結果是 private ,那麼還要看一下是否為友元。而且還有更複雜的情況,比如:

class B;

class A {

private :

int i;

friend void f(B*);

};

class B : public A { };

void f(B* p) {

p->i = 1; // OK: B* can be implicitly cast to A*, and f has access to i in A

}

這通過後序周遊 type 的派生樹時,執行 dfs_accessible_p 的方法來查找。 BINFO_ACCESS 在 1000 行的 access_in_type 執行時,就被設定好了。如果它是 ak_none ,就表明該類與 decl 無關。

778  static tree

779  dfs_accessible_p (tree binfo, void *data ATTRIBUTE_UNUSED)                   in search.c

780  {

781    access_kind access;

782 

783    BINFO_MARKED (binfo) = 1;

784    access = BINFO_ACCESS (binfo);

785    if (access != ak_none

786        && is_friend (BINFO_TYPE (binfo), current_scope ()))

787      return binfo;

788 

789    return NULL_TREE;

790  }

類似的, dfs_accessible_queue_p 傳回合适的 binfo 來遞歸地進入。它以中序周遊派生樹。

759  static tree

760  dfs_accessible_queue_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)

761  {

762    tree binfo = BINFO_BASETYPE (derived, ix);

763   

764    if (BINFO_MARKED (binfo))

765      return NULL_TREE;

766 

767   

769    if (BINFO_BASEACCESS (derived, ix) != access_public_node

770        && !is_friend (BINFO_TYPE (derived), current_scope ()))

771      return NULL_TREE;

772 

773    return binfo;

774  }

這一次,隻要找到一個合适的類,就傳回。

繼續閱讀