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

5.12.4.2.              解析 class-head

跟在 template-parameter-list 后的符号是“ class ”,这标记着这是类模板的定义 / 声明。与前面的例子相同,沿着下面的调用栈: cp_parser_template_declaration_after_export à cp_parser_single_declaration à cp_parser_decl_specifier_seq à cp_parser_type_specifier , 关键字“ class ”把解析器导向函数 cp_parser_class_specifier

 

11855 static tree

11856 cp_parser_class_specifier (cp_parser* parser)                                                  in parser.c

11857 {

11858   cp_token *token;

11859   tree type;

11860   tree attributes;

11861   int has_trailing_semicolon;

11862   bool nested_name_specifier_p;

11863   unsigned saved_num_template_parameter_lists;

11864   bool pop_p = false;

11865   tree scope = NULL_TREE;

11866

11867   push_deferring_access_checks (dk_no_deferred);

11868

11869   /* Parse the class-head.  */

11870   type = cp_parser_class_head (parser,

11871                           &nested_name_specifier_p,

11872                           &attributes);

 

在解析 class-specifier 时,访问性检查通常应该执行而不作任何延迟,这反映在 11867 行所插入的 dk_no_deferred 节点。不过,后面我们可以看到在布局可能有不同的访问性检查。

 

12030 static tree

12031 cp_parser_class_head (cp_parser* parser,                                                        in parser.c

12032                   bool* nested_name_specifier_p,

12033                    tree *attributes_p)

12034 {

12035   cp_token *token;

12036   tree nested_name_specifier;

12037   enum tag_types class_key;

12038   tree id = NULL_TREE;

12039   tree type = NULL_TREE;

12040   tree attributes;

12041   bool template_id_p = false;

12042   bool qualified_p = false;

12043   bool invalid_nested_name_p = false;

12044   bool invalid_explicit_specialization_p = false;

12045   bool pop_p = false;

12046   unsigned num_templates;

12047

12048   /* Assume no nested-name-specifier will be present.  */

12049   *nested_name_specifier_p = false;

12050   /* Assume no template parameter lists will be used in defining the

12051     type.  */

12052   num_templates = 0;

12053

12054   /* Look for the class-key.  */

12055   class_key = cp_parser_class_key (parser);

12056   if (class_key == none_type)

12057     return error_mark_node;

12058

12059   /* Parse the attributes.  */

12060   attributes = cp_parser_attributes_opt (parser);

12061

12062   /* If the next token is `::', that is invalid -- but sometimes

12063     people do try to write:

12064

12065       struct ::S {}; 

12066

12067     Handle this gracefully by accepting the extra qualifier, and then

12068     issuing an error about it later if this really is a

12069     class-head. If it turns out just to be an elaborated type

12070     specifier, remain silent.  */

12071   if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/ false))

12072     qualified_p = true;

12073

12074   push_deferring_access_checks (dk_no_check);

12075

12076   /* Determine the name of the class. Begin by looking for an

12077     optional nested-name-specifier.  */

12078   nested_name_specifier

12079     = cp_parser_nested_name_specifier_opt (parser,

12080                                      /*typename_keyword_p=*/ false,

12081                                      /*check_dependency_p=*/ false,

12082                                      /*type_p=*/ false,

12083                                       /*is_declaration=*/ false);

12084   /* If there was a nested-name-specifier, then there *must* be an

12085     identifier.  */

12086   if (nested_name_specifier)

12087   {

          …

12143   }

12144   /* Otherwise, the identifier is optional.  */

12145   else

12146   {

12147      /* We don't know whether what comes next is a template-id,

12148       an identifier, or nothing at all.  */

12149     cp_parser_parse_tentatively (parser);

12150     /* Check for a template-id.  */

12151     id = cp_parser_template_id (parser,

12152                            /*template_keyword_p=*/ false,

12153                            /*check_dependency_p=*/ true,

12154                            /*is_declaration=*/ true);

12155     /* If that didn't work, it could still be an identifier.  */

12156     if (!cp_parser_parse_definitely (parser))

12157     {

12158       if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))

12159         id = cp_parser_identifier (parser);

12160       else

12161         id = NULL_TREE;

12162     }

12163     else

12164     {

12165       template_id_p = true;

12166       ++num_templates;

12167     }

12168   }

12169

12170   pop_deferring_access_checks ();

 

这里看到,在 12074 行加入了对访问性不作检查规则。这一规则将影响在 12149 行由 cp_parser_parse_tentatively 加入的访问性检查规则,使其也成为 dk_no_check 。在本例中,关键字“ class ”后的符号是“ SmallObject ”,这是一个标识符,由 12159 行的 cp_parser_identifier 识别。

注意 pop_deferring_access_checks 相应地弹出 dk_no_checks 节点。

 

cp_parser_class_head (continue)

 

12259   /* Look up the type.  */

12260   if (template_id_p)

12261   {

12262     type = TREE_TYPE (id);

12263     maybe_process_partial_specialization (type);

12264   }

12265   else if (!nested_name_specifier)

12266   {

12267     /* If the class was unnamed, create a dummy name.  */

12268     if (!id)

12269       id = make_anon_name ();

12270     type = xref_tag (class_key, id, /*globalize=*/ false,

12271                   parser->num_template_parameter_lists);

12272   }

 

符号“ class SmallObject ”作为类标签( class tag )的处理与章节 加入类 SingleThreaded的标签 所描述的一样。因此我们跳过这部分的细节避免重复。

基类必须是已经定义的类型,从类名找到对应的类型节点,是一个复杂的过程,尤其是当这个类是一个模板类。下面首先看一下类名的查找过程。不过,在此之前,我们最好看看如何来确定给定名字的依赖性。

5.12.4.2.1.        评估类型的依赖性
5.12.4.2.1.1.  概述

在一个模板里,某些构造的语义可能在不同的具现中有所不同。这样的构造依赖于模板参数。特别的,类型及表达式可能依赖于模板参数的类型及值(即由模板实参确定),并且其也确定了查找这些名字的作用域。表达式可能是依赖类型的(模板参数的类型)或者是依赖于值的(模板非类型参数的值)。在一个具有以下形式的表达式中:

postfix-expression ( expression-list opt )

其中 postfix-expression 部分是一个标识符,该标识符表示一个依赖名,当且仅当 expression-list 部分中任一表达式是类型依赖的( 14.6.2 .2 )。如果一个操作符的一个操作数是一个类型依赖表达式,该操作数同样表示一个依赖名。这样的名字是未绑定的,并且在模板具现( 14.6.4.1 )这一点上,在模板定义的上下文及具现点的上下文中查找。 [ 例如:

template <class T> struct X : B<T> {

typename T::A* pa;

void f(B<T>* pb) {

static int i = B<T>::i;

pb->j++;

}

};

基类名 B<T> ,类型名 T::A ,名字 B<T>::i pb->j 显然依赖于模板参数。

在一个类模板或类模板的一个成员定义中,如果该类模板的一个基类依赖于一个模板参数,该基类的作用域,在类模板或其成员的定义这一点上的非限定名查找中,或者在该类模板或其成员的一个具现过程中,不作考察。 [ 例如:

typedef double A;

template <class T> class B {

typedef int A;

};

template <class T> struct X : B<T> {

A a; // a has type double

};

X<T> 定义中的类型名 A 绑定到在全局名字空间中定义的 typedef 名,而不是绑定到在基类 B<T> 中定义的 typedef 名。 [ 例如:

struct A {

struct B { /* ... */ };

int a;

int Y;

};

int a;

template <class T> struct Y : T {

struct B { /* ... */ };

B b; // The B defined in Y

void f(int i) { a = i; } // ::a

Y* p; // Y<T>

};

Y<A> ya;

模板实参 A 的成员 A::B A::a A::Y 不影响在 Y<A> 中的名字绑定。

5.12.4.2.1.2.  依赖于类型

函数 type_dependent_expression_p 返回 true 如果参数 expression 是依赖类型的。

 

11966 bool

11967 type_dependent_expression_p (tree expression)                                                 in pt.c

11968 {

11969    if (!processing_template_decl )

11970      return false;

11971

11972    if (expression == error_mark_node)

11973      return false;

11974

11975    /* An unresolved name is always dependent.  */

11976    if (TREE_CODE (expression) == IDENTIFIER_NODE)

11977      return true;

 

我们已经知道当解析器找到一个标识符时,它总是尝试查找这个名字以找出当前绑定的声明。该声明就是当前要用的那个对象,这通常是一个 *_DECL 节点。但是如果该标识符在当前作用域没有可见的绑定,解析器只能使用 IDENTIFIER_NODE 。例如上面例子中的:

template <class T> struct X : B<T> {

typename T::A* pa;

T::A 中的 A ”, 在此处只能是 IDENTIFIER_NODE

 

type_dependent_expression_p (continue)

 

11979     /* Some expression forms are never type-dependent.  */

11980    if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR

11981        || TREE_CODE (expression) == SIZEOF_EXPR

11982        || TREE_CODE (expression) == ALIGNOF_EXPR

11983        || TREE_CODE (expression) == TYPEID_EXPR

11984        || TREE_CODE (expression) == DELETE_EXPR

11985        || TREE_CODE (expression) == VEC_DELETE_EXPR

11986        || TREE_CODE (expression) == THROW_EXPR)

11987      return false;

11988

11989    /* The types of these expressions depends only on the type to which

11990      the cast occurs.  */

11991    if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR

11992        || TREE_CODE (expression) == STATIC_CAST_EXPR

11993        || TREE_CODE (expression) == CONST_CAST_EXPR

11994        || TREE_CODE (expression) == REINTERPRET_CAST_EXPR

11995        || TREE_CODE (expression) == CAST_EXPR)

11996      return dependent_type_p (TREE_TYPE (expression));

11997

11998    /* The types of these expressions depends only on the type created

11999      by the expression.  */

12000    if (TREE_CODE (expression) == NEW_EXPR

12001        || TREE_CODE (expression) == VEC_NEW_EXPR)

12002    {

12003      /* For NEW_EXPR tree nodes created inside a template, either

12004         the object type itself or a TREE_LIST may appear as the

12005         operand 1.  */

12006      tree type = TREE_OPERAND (expression, 1);

12007      if (TREE_CODE (type) == TREE_LIST)

12008        /* This is an array type. We need to check array dimensions

12009          as well.  */

12010        return dependent_type_p (TREE_VALUE (TREE_PURPOSE (type)))

12011                  || value_dependent_expression_p

12012                             (TREE_OPERAND (TREE_VALUE (type), 1));

12013      else

12014        return dependent_type_p (type);

12015    }

12016

12017    if (TREE_CODE (expression) == SCOPE_REF

12018        && dependent_scope_ref_p (expression,

12019                           type_dependent_expression_p))

12020      return true;

12021

12022    if (TREE_CODE (expression) == FUNCTION_DECL

12023        && DECL_LANG_SPECIFIC (expression)

12024        && DECL_TEMPLATE_INFO (expression)

12025        && (any_dependent_template_arguments_p

12026            (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))

12027      return true;

12028

12029    if (TREE_CODE (expression) == TEMPLATE_DECL

12030        && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression))

12031      return false;

 

根据【 3 】,下列形式是不可能类型依赖的。

literal

postfix-expression.pseduo-destructor-name

postfix-expression->pseduo-destructor-name

sizeof unary-expression

sizeof (type-id)

typeid (expression)

typeid (type-id)

::opt delete cast-expression

::opt delete[] cast-expression

throw assignment-expression opt

因为这些表达式的类型不会是依赖的。例如, sizeof 的类型总是 size_t GNU 的扩展操作符 alignof 也在这个类别中(它的类型也是 size_t )。

那么一个 id-expression 是类型依赖的,如果它包含:

一个以依赖类型声明的标识符 identifier

一个依赖的 template-id

一个指定一个依赖类型的 conversion-function-id

一个包含命名了一个依赖名的类名的 nested-name-specifier

以下形式的表达式,即使任一子表达式是类型依赖的,仅当由 type-id simple-type-specifier new-type-id 指定的类型是依赖的,才是是类型依赖的:

simple-type-specifier (expression-list opt )

::opt new new-placement opt new-type-id new-initializer opt

::opt new new-placement opt (type-id ) new-initializer opt

dynamic_cast <type-id > (expression)

static_cast <type-id > (expression)

const_cast <type-id > (expression)

reinterpret_cast <type-id > (expression)

(type-id ) cast-expression

上面规则的核心是检查表达式所包含的类型的类型依赖性。上面的 12000 行,注意对于 new-type-id ,其语法为:

new-type-id

type-specifier-seq new-declarator opt

new-declarator:

ptr-operator new-declarator opt

direct-new-declarator

direct-new-declarator:

[expression]

direct-new-declarator [constant-expression]

对于这个情形, NEW_EXPR/VEC_NEW_EXPR 节点中索引为 1 (从 0 开始)的操作数是 new-type-id ,它是应该 tree_list ,其 purpose 域保存了 type-specifier-seq 部分, value 域是 new-declarator 部分。如果 new-declarator 导出 direct-new-declarator ,它是 ARRAY_REF 节点,用作子维的 direct-new-declarator 是操作数 0 ,表示维度大小的表达式是操作数 1 。显然如果这个表达式是值依赖的, new-type-id 就视为类型依赖。

那么 dependent_type_p 验证传入的 type 是否依赖模板参数。

 

11786 bool

11787 dependent_type_p (tree type)                                                                           in pt.c

11788 {

11789    /* If there are no template parameters in scope, then there can't be

11790      any dependent types.  */

11791    if (!processing_template_decl )

11792      return false;

11793

11794    /* If the type is NULL, we have not computed a type for the entity

11795      in question; in that case, the type is dependent.  */

11796    if (!type)

11797      return true;

11798

11799     /* Erroneous types can be considered non-dependent.  */

11800    if (type == error_mark_node)

11801      return false;

11802

11803     /* If we have not already computed the appropriate value for TYPE,

11804      do so now.  */

11805    if (!TYPE_DEPENDENT_P_VALID (type))

11806    {

11807      TYPE_DEPENDENT_P (type) = dependent_type_p_r (type);

11808      TYPE_DEPENDENT_P_VALID (type) = 1;

11809    }

11810

11811    return TYPE_DEPENDENT_P (type);

11812 }

 

为了加速编译速度,某些类型如果已经经过评估,其树节点的 lang_flag_6 域已被设置( TYPE_DEPENDENT_P_VALID ),且 lang_flag_0 域保存了结果( TYPE_DEPENDENT_P )。

一个类型是依赖的如果它是:

1) 一个模板参数

2) 一个 qualified-id 。它具有一个 nested-name-specifier ,其包含了一个命名了一个依赖类型的类名;或其 unqualified-id 命名了一个依赖类型。

3) 一个 cv-qualified 类型,其 cv-unqualified 类型是依赖的。

4) 一个从任一依赖类型构建的复合类型。

5) 从任一依赖类型构建的数组,或者由常量表达式所表示的数组的大小是值依赖的。

6) 一个 template-id 。其模板名是一个模板参数; 或者其任一实参是依赖类型或类型依赖或值依赖的表达式。

下面, TEMPLATE_TYPE_PARM 是代表模板参数的节点,作为参数的模板的本身是 TEMPLATE_TEMPLATE_PARM 节点。

那么根据【 3 ISO-IE-14882-2003 14.6 名字解析( name resolution ):

Ÿ        一个在一个模板声明或模板定义中使用的依赖于模板参数的名字,其命名的假定不为类型,除非适用的名字查找找出一个类型名或者该名字为关键字 typename 所限定。

例如:

// no B declared here

class X;

template <class T> class Y {

        class Z;          // forward declaration of member class

        void f() {

               X* a1;     // declare pointer to X

               T* a2;     // declare pointer to T

               Y* a3;     // declare pointer to Y

               Z* a4;     // declare pointer to Z

               typedef typename T::A TA;

               TA* a5;          // declare pointer to T’s A

               typename T::A* a6; // declare pointer to T’s A

               T::A* a7;        // T::A is not a type name: mulitply T::A by a7;

                                    // ill-formed, no visible declaration of a7

               B* a8;     // multiply B by a8; ill-formed, no visible declaration of B and a8

        }

};

Ÿ        一个引用一个类型并且依赖于模板参数的限定名应该使用关键字 typename 作为前缀,来表示该限定名表示一个类型,构成一个 elaborated-type specifier

elaborated-type-specifier:

        typename ::opt nested-name-specifier identifier

        typename ::opt nested-name-specifier identifer <template-argument-list>

Ÿ        关键字 typename 只能用在模板声明及定义中,包括在函数模板或成员函数模板的返回类型中,类模板或其嵌套类的成员函数定义中返回类型里,及在类模板或其嵌套类的静态成员的 type-specifier 中。关键字 typename 只能用于限定名字,但这些名字不需要是依赖的。关键字 typename base-specifier mem-initializer 中是不被允许的;在这些上下文中一个依赖于模板参数的限定名被隐含地认为是一个类型名。

Ÿ        在一个类模板或类模板的成员的定义中,当引用一个先前已声明的成员,且该成员声明了一个类型时,不要求使用关键字 typename 。当使用限定名来引用成员时,即是该限定名就是该类模板名,要指明关键字 typename

例如:

template <class T> struct A {

        typedef int B;

        A::B b;                   // ill-formed: typename required before A::B

        void f(A<T>::B);    // ill-formed: typename required before A<T>::B

        typename A::B g();  // OK

};

不管使用的限定名是 A 还是 A<T> ,都要求使用关键字 typename ,因为在具有参数列表 <T> 的类模板中, A A<T> 是同义词。

根据上面的描述,如果一个模板被正确声明了,关键字 typename 总是表示一个依赖类型。因此在下面的 11704 行,如果我们看到 typename ,我们就可以安全地假定依赖于类型,反之亦然(如果模板被错误声明,比如缺少了 typename ,后面的解析将发出错误信息)。函数 dependent_type_p_r 执行检查。

 

11686 static bool

11687 dependent_type_p_r (tree type)                                                                        in pt.c

11688 {

11689    tree scope;

11690

11691    /* [temp.dep.type]

11692

11693     A type is dependent if it is:

11694

11695     -- a template parameter. Template template parameters are

11696     types for us (since TYPE_P holds true for them) so we

11697     handle them here.  */

11698    if (TREE_CODE (type) == TEMPLATE_TYPE_PARM

11699        || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)

11700      return true;

11701    /* -- a qualified-id with a nested-name-specifier which contains a

11702      class-name that names a dependent type or whose unqualified-id

11703      names a dependent type.  */

11704    if (TREE_CODE (type) == TYPENAME_TYPE)

11705      return true;

11706    /* -- a cv-qualified type where the cv-unqualified type is

11707      dependent.  */

11708    type = TYPE_MAIN_VARIANT (type);

11709    /* -- a compound type constructed from any dependent type.  */

11710    if (TYPE_PTR_TO_MEMBER_P (type))

11711      return (dependent_type_p (TYPE_PTRMEM_CLASS_TYPE (type))

11712           || dependent_type_p (TYPE_PTRMEM_POINTED_TO_TYPE

11713                            (type)));

11714    else if (TREE_CODE (type) == POINTER_TYPE

11715          || TREE_CODE (type) == REFERENCE_TYPE)

11716      return dependent_type_p (TREE_TYPE (type));

11717    else if (TREE_CODE (type) == FUNCTION_TYPE

11718          || TREE_CODE (type) == METHOD_TYPE)

11719    {

11720      tree arg_type;

11721

11722      if (dependent_type_p (TREE_TYPE (type)))

11723        return true;

11724      for (arg_type = TYPE_ARG_TYPES (type);

11725          arg_type;

11726          arg_type = TREE_CHAIN (arg_type))

11727        if (dependent_type_p (TREE_VALUE (arg_type)))

11728          return true;

11729      return false;

11730    }

 

11710 行,如果 type 是指向类数据成员或方法的指针, TYPE_PTR_TO_MEMBER_P 不为 0 ,而对于类型 T X::* TYPE_PTRMEM_CLASS_TYPE 返回 X TYPE_PTRMEM_CLASS_TYPE 返回 T

FUNCTION_DECL(function) METHOD_DECL(method of class) TREE_TYPE 返回其返回类型,而 TREE_ARG_TYPE 返回实参列表。

 

dependent_type_p_r (continue)

 

11731    /* -- an array type constructed from any dependent type or whose

11732      size is specified by a constant expression that is

11733      value-dependent.  */

11734    if (TREE_CODE (type) == ARRAY_TYPE)

11735    {

11736      if (TYPE_DOMAIN (type)

11737          && ((value_dependent_expression_p

11738              (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))

11739          || (type_dependent_expression_p

11740            (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))))

11741        return true;

11742      return dependent_type_p (TREE_TYPE (type));

11743    }

 

一个数组的边界的类型由 TYPE_DOMAIN 访问,而其上下边界可分别由 TYPE_MAX_VALUE TYPE_MIN_VALUE 得到。

在上面的类型依赖性条件,由条款 5 ,一个数组是类型依赖的,如果其大小由一个值依赖的常量表达式指定。那么怎么算值依赖呢?

5.12.4.2.1.3.  依赖于值

值依赖的表达式应该是:

Ÿ        除以下描述的之外,一个常量表达式是值依赖的,如果任一子表达式是值依赖的。

Ÿ        一个标识符是值依赖的,如果它是:

以依赖类型声明的名字。

模板非类型参数的名字。

一个整型或枚举类型的常量,由一个值依赖的表达式初始化。

Ÿ        以下形式的表达式是值依赖的,如果 unary-expression 部分依赖类型或 type-id 部分是依赖性的(即使 sizeof unary-expression sizeof (type-id) 不是类型依赖的): sizeof unary-expression, sizeof (type-id)

Ÿ        以下形式的表达式是值依赖的,如果 type-id simple-type-specifier 部分是依赖的,或者 expression cast-expression 部分是值依赖的:

simple-type-specifier (expression-list opt )

static_cast <type-id> (expression)

const_cast <type-id> (expression)

reinterpret_cast <type-id> (expression)

(type-id) cast-expression

 

11851 bool

11852 value_dependent_expression_p (tree expression)                                                in pt.c

11853 {

11854    if (!processing_template_decl )

11855      return false;

11856

11857    /* A name declared with a dependent type.  */

11858    if (TREE_CODE (expression) == IDENTIFIER_NODE

11859        || (DECL_P (expression)

11860           && type_dependent_expression_p (expression)))

11861      return true;

11862    /* A non-type template parameter.  */

11863    if ((TREE_CODE (expression) == CONST_DECL

11864         && DECL_TEMPLATE_PARM_P (expression))

11865       || TREE_CODE (expression) == TEMPLATE_PARM_INDEX)

11866      return true;

11867    /* A constant with integral or enumeration type and is initialized

11868      with an expression that is value-dependent.  */

11869    if (TREE_CODE (expression) == VAR_DECL

11870        && DECL_INITIAL (expression)

11871        && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (expression))

11872        && value_dependent_expression_p (DECL_INITIAL (expression)))

11873      return true;

11874    /* These expressions are value-dependent if the type to which the

11875      cast occurs is dependent or the expression being casted is

11876      value-dependent.  */

11877    if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR

11878        || TREE_CODE (expression) == STATIC_CAST_EXPR

11879        || TREE_CODE (expression) == CONST_CAST_EXPR

11880        || TREE_CODE (expression) == REINTERPRET_CAST_EXPR

11881        || TREE_CODE (expression) == CAST_EXPR)

11882    {

11883      tree type = TREE_TYPE (expression);

11884      if (dependent_type_p (type))

11885        return true;

11886       /* A functional cast has a list of operands.  */

11887      expression = TREE_OPERAND (expression, 0);

11888      if (!expression)

11889      {

11890        /* If there are no operands, it must be an expression such

11891          as "int()". This should not happen for aggregate types

11892          because it would form non-constant expressions.  */

11893        my_friendly_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type),

11894                        20040318);

11895

11896        return false;

11897      }

11898      if (TREE_CODE (expression) == TREE_LIST)

11899      {

11900        do

11901        {

11902          if (value_dependent_expression_p (TREE_VALUE (expression)))

11903            return true;

11904          expression = TREE_CHAIN (expression);

11905        }

11906        while (expression);

11907        return false;

11908      }

11909      else

11910        return value_dependent_expression_p (expression);

11911    }

11912    /* A `sizeof' expression is value-dependent if the operand is

11913      type-dependent.  */

11914    if (TREE_CODE (expression) == SIZEOF_EXPR

11915        || TREE_CODE (expression) == ALIGNOF_EXPR)

11916     {

11917      expression = TREE_OPERAND (expression, 0);

11918      if (TYPE_P (expression))

11919        return dependent_type_p (expression);

11920      return type_dependent_expression_p (expression);

11921    }

11922    if (TREE_CODE (expression) == SCOPE_REF)

11923      return dependent_scope_ref_p (expression, value_dependent_expression_p );

11924    if (TREE_CODE (expression) == COMPONENT_REF)

11925      return (value_dependent_expression_p (TREE_OPERAND (expression, 0))

11926           || value_dependent_expression_p (TREE_OPERAND (expression, 1)));

11927    /* A constant expression is value-dependent if any subexpression is

11928      value-dependent.  */

11929    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))

11930    {

11931      switch (TREE_CODE_CLASS (TREE_CODE (expression)))

11932      {

11933        case '1':

11934         return (value_dependent_expression_p

11935               (TREE_OPERAND (expression, 0)));

11936         case '<':

11937        case '2':

11938          return ((value_dependent_expression_p

11939                  (TREE_OPERAND (expression, 0)))

11940               || (value_dependent_expression_p

11941                  (TREE_OPERAND (expression, 1))));

11942        case 'e':

11943        {

11944          int i;

11945          for (i = 0; i < first_rtl_op (TREE_CODE (expression)); ++i)

11946             /* In some cases, some of the operands may be missing.

11947              (For example, in the case of PREDECREMENT_EXPR, the

11948              amount to increment by may be missing.) That doesn't

11949              make the expression dependent.  */

11950            if (TREE_OPERAND (expression, i)

11951                && (value_dependent_expression_p

11952                    (TREE_OPERAND (expression, i))))

11953              return true;

11954          return false;

11955         }

11956      }

11957    }

11958

11959    /* The expression is not value-dependent.  */

11960    return false;

11961 }

 

从上面规则中导出的 2 个情形值得进一步的考察。在 11922 行, SCOPE_REF 节点的第 0 个操作数是类节点,第 1 个操作数是代表域的节点。例如:它用于保存下面的 A::i (看到这个表达式是值依赖的)。

template <typename T> struct A {

        static const int i = sizeof (T);

};

A::i;

COMPONENT_REF 的第 0 个操作数是代表对象的节点,第 1 个操作数是代表域的节点。例如:它用于保存下面的 a.i a.i 也是值依赖的,因为它以依赖类型来声明的)。

template <typename T> struct A {

        T i;

};

 

template <typename V> void f (A<V>& a, V value) {

   a.i = value;

}

对于 SCOPE_REF 节点, dependent_scope_ref_p 验证它是否为依赖。注意到参数 criterion 指向函数 value_dependent_expression_p

 

11816 static bool

11817 dependent_scope_ref_p (tree expression, bool criterion (tree))                                   in pt.c

11818 {

11819    tree scope;

11820    tree name;

11821

11822    my_friendly_assert (TREE_CODE (expression) == SCOPE_REF, 20030714);

11823

11824    if (!TYPE_P (TREE_OPERAND (expression, 0)))

11825      return true;

11826

11827    scope = TREE_OPERAND (expression, 0);

11828    name = TREE_OPERAND (expression, 1);

11829

11830     /* [temp.dep.expr]

11831

11832      An id-expression is type-dependent if it contains a

11833      nested-name-specifier that contains a class-name that names a

11834      dependent type.  */

11835    /* The suggested resolution to Core Issue 2 implies that if the

11836      qualifying type is the current class, then we must peek

11837      inside it.  */

11838    if (DECL_P (name)

11839        && currently_open_class (scope)

11840        && !criterion (name))

11841      return false;

11842    if (dependent_type_p (scope))

11843      return true;

11844

11845    return false;

11846 }

 

考虑 11838 行的条件,以下例为例:

template <typename T> struct A {

    int j;

};

当解析类 A 中的成员 j 时,在作用域内 j 不应该被视为类型 / 值依赖,但是从类域外来看却是依赖的。

另外,考虑以下例子:

template <typename T> struct A{

        typedef T innerType;

innerType j;

};

A<int>::innerType intType;

A<T>::innerType aType

intType A<int>::innerType )不是值依赖的,但 aType A<T>::innerType )是。

 

dependent_type_p_r (continue)

 

11745    /* -- a template-id in which either the template name is a template

11746      parameter ...  */

11747    if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)

11748      return true;

11749    /* ... or any of the template arguments is a dependent type or

11750      an expression that is type-dependent or value-dependent.  */

11751    else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type)

11752          && (any_dependent_template_arguments_p

11753               (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))

11754      return true;

11755   

11756    /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof'

11757      expression is not type-dependent, then it should already been

11758      have resolved.  */

11759    if (TREE_CODE (type) == TYPEOF_TYPE)

11760      return true;

11761   

11762    /* The standard does not specifically mention types that are local

11763      to template functions or local classes, but they should be

11764      considered dependent too. For example:

11765

11766         template <int I> void f() {

11767          enum E { a = I };

11768          S<sizeof (E)> s;

11769         }

11770

11771      The size of `E' cannot be known until the value of `I' has been

11772      determined. Therefore, `E' must be considered dependent.  */

11773    scope = TYPE_CONTEXT (type);

11774    if (scope && TYPE_P (scope))

11775      return dependent_type_p (scope);

11776    else if (scope && TREE_CODE (scope) == FUNCTION_DECL)

11777      return type_dependent_expression_p (scope);

11778

11779    /* Other types are non-dependent.  */

11780    return false;

11781 }

 

对于条件“在一个 template-id 中,或者其模板名是一个模板参数,或者其任一实参是一个依赖类型或一个类型依赖或值依赖的表达式 ”,考虑以下例子:

例子 1

template <class T> struct Temp {

    int t;

};

 

template <template <class U> class T, typename X, typename V = T<X> > struct A {

    V func;

};

 

int main() {

    A<Temp, int> a;

    a.func.t = 0;

    return 1;

}

类型 Temp 用作缺省实参,它依赖于模板参数 X (这是模板名是模板参数的情形)。

例子 2

template <class T> struct Temp {

    T t;

};

 

template<typename T> struct A {

    Temp<T> func;

};

 

int main() {

    A<int> a;

    a.func.t = 0;

    return 1;

}

模板 Temp 作为 A 的成员,接受依赖类型 T 。在这个情形下, Temp 的定义包含了一个层级的模板参数( T )。对于模板相关的树节点,参考图形: 访问模板定义的宏 。它只是检测最里层的模板实参,因为【 3 ISO-IE-14882-2003 规定了:

对于一个类模板的成员或一个模板成员,在其一个出现在名字空间作用域的显式特化声明中,该模板成员和其某些封闭类模板可能保持未特化; 除了如果其封闭类模板不被显式特化,该声明不应该显式特化这个类模板成员。在这样的显式特化声明中,在该成员的显式特化声明之前,要提供后跟着模板参数列表的关键字 template ,而不是 template<> 。在模板参数列表中的模板参数的类型,应该与主模板定义中指出的类型一致。 [ 例子:

template <class T1> class A {

template <class T2> class B {

template <class T3> void mf1(T3);

void mf2();

};

};

 

template <> template <class X> class A<int>::B { };

template <> template <> template <class T> void A<int>::B<double>::mf1(T t) { }

template <class Y> template <>

void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized but

// its enclosing class template A is not

函数 any_dependent_tempalte_arguments_p 可以评估模板参数向量,虽然这里该向量只包含了最里层的实参。

 

12116 bool

12117 any_dependent_template_arguments_p (tree args)                                              in pt.c

12118 {

12119    int i;

12120    int j;

12121

12122    if (!args)

12123      return false;

12124

12125    for (i = 0; i < TMPL_ARGS_DEPTH (args); ++i)

12126    {

12127      tree level = TMPL_ARGS_LEVEL (args, i + 1);

12128      for (j = 0; j < TREE_VEC_LENGTH (level); ++j)

12129        if (dependent_template_arg_p (TREE_VEC_ELT (level, j)))

12130          return true;

12131    }

12132

12133    return false;

12134 }

 

检查实参是否有依赖性,与类型声明的检查颇为相似。

 

12097 static bool

12098 dependent_template_arg_p (tree arg)                                                                 in pt.c

12099 {

12100    if (!processing_template_decl )

12101      return false;

12102

12103    if (TREE_CODE (arg) == TEMPLATE_DECL

12104        || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)

12105      return dependent_template_p (arg);

12106    else if (TYPE_P (arg))

12107      return dependent_type_p (arg);

12108    else

12109      return (type_dependent_expression_p (arg)

12110            || value_dependent_expression_p (arg));

12111 }

 

这里注意到,只有 TEMPLATE_TEMPLATE_PARM 节点或 TEMPLATE_DECL 节点被 dependent_template_p 处理。看到如果 TEMPLATE_DECL 不是被用作模板参数(即 12153 行的条件不满足)并且它不是在依赖性的作用域中,该 TEMPLATE_DECL 不被认为是依赖性的( ISO-IE-14882-2003 [temp.dep.type] ,在一个 template-id 中,或者其模板名是一个模板参数,或者其任一实参是一个依赖类型或一个类型依赖或值依赖的表达式)。

 

12138 bool

12139 dependent_template_p (tree tmpl)                                                                     in pt.c

12140 {

12141    if (TREE_CODE (tmpl) == OVERLOAD)

12142    {

12143      while (tmpl)

12144      {

12145        if (dependent_template_p (OVL_FUNCTION (tmpl)))

12146          return true;

12147        tmpl = OVL_CHAIN (tmpl);

12148      }

12149      return false;

12150    }

12151

12152    /* Template template parameters are dependent.  */

12153    if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)

12154        || TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)

12155      return true;

12156    /* So are names that have not been looked up.  */

12157    if (TREE_CODE (tmpl) == SCOPE_REF

12158        || TREE_CODE (tmpl) == IDENTIFIER_NODE)

12159      return true;

12160    /* So are member templates of dependent classes.  */

12161    if (TYPE_P (CP_DECL_CONTEXT (tmpl)))

12162      return dependent_type_p (DECL_CONTEXT (tmpl));

12163    return false;

12164 }

 

看到如果找到的函数模板是重载函数,它是 OVERLOAD 节点,通过 OVL_FUNCTION 封装了 TEMPLATE_DECL ,因此在 12145 行的 dependent_template_p 将找出这个函数模板。

下面特殊节点 unknown_type_node 用作重载函数 / 方法的类型。

 

type_dependent_expression_p (continue)

 

12033    if (TREE_TYPE (expression) == unknown_type_node)

12034    {

12035       if (TREE_CODE (expression) == ADDR_EXPR)

12035         return type_dependent_expression_p (TREE_OPERAND (expression, 0));

12037      if (TREE_CODE (expression) == COMPONENT_REF

12038         || TREE_CODE (expression) == OFFSET_REF)

12039      {

12040        if (type_dependent_expression_p (TREE_OPERAND (expression, 0)))

12041          return true;

12042        expression = TREE_OPERAND (expression, 1);

12043        if (TREE_CODE (expression) == IDENTIFIER_NODE)

12044          return false;

12045      }

12046      /* SCOPE_REF with non-null TREE_TYPE is always non-dependent.  */

12047      if (TREE_CODE (expression) == SCOPE_REF)

12048        return false;

12049       

12050      if (TREE_CODE (expression) == BASELINK)

12051        expression = BASELINK_FUNCTIONS (expression);

12052      if (TREE_CODE (expression) == TEMPLATE_ID_EXPR)

12053      {

12054        if (any_dependent_template_arguments_p

12055               (TREE_OPERAND (expression, 1)))

12056          return true;

12057        expression = TREE_OPERAND (expression, 0);

12058      }

12059      if (TREE_CODE (expression) == OVERLOAD

12060         || TREE_CODE (expression) == FUNCTION_DECL)

12061      {

12062        while (expression)

12063        {

12064          if (type_dependent_expression_p (OVL_CURRENT (expression)))

12065            return true;

12066          expression = OVL_NEXT (expression);

12067        }

12068        return false;

12069      }

12070      abort ();

12071    }

12072   

12073    my_friendly_assert (TREE_CODE (expression) != TYPE_DECL, 20051116);

12074  

12075    return (dependent_type_p (TREE_TYPE (expression)));

12076 }

 

上面这段代码继续检查类型的依赖性。注意 12043 行,如果在一个非依赖的作用域中,有未解析的名字,即认为它是非依赖的(除了错误的情况,我想不出合法的情形)。否则,继续 12047 行以下的代码,继续检查这个操作数 1

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值