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

来源:互联网 发布:白金数据结局神乐和龙 编辑:程序博客网 时间:2024/06/05 03:47

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 theclass-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   enumtag_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 nonested-name-specifier will be present.  */

12049   *nested_name_specifier_p = false;

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

12051     type. */

12052   num_templates = 0;

12053

12054  /* Look for theclass-key.  */

12055   class_key = cp_parser_class_key (parser);

12056   if (class_key == none_type)

12057     returnerror_mark_node;

12058

12059  /* Parse theattributes.  */

12060  attributes = cp_parser_attributes_opt (parser);

12061

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

12063     people do try to write:

12064

12065       struct ::S {}; 

12066

12067     Handle this gracefully by accepting theextra qualifier, and then

12068     issuing an error about it later if thisreally 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 thename 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 anested-name-specifier, then there *must* be an

12085    identifier.  */

12086   if (nested_name_specifier)

12087   {

         

12143   }

12144   /* Otherwise, theidentifier is optional.  */

12145   else

12146   {

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

12148       an identifier, or nothing at all.  */

12149     cp_parser_parse_tentatively(parser);

12150     /* Check for atemplate-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'twork, 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 thetype.  */

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 classwas 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;

voidf(B<T>* pb) {

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

pb->j++;

}

};

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

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

typedef double A;

template<classT> 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<classT> 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::BA::aA::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     returnfalse;

11971

11972   if (expression ==error_mark_node)

11973     returnfalse;

11974

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

11976   if (TREE_CODE (expression)== IDENTIFIER_NODE)

11977     returntrue;

 

我们已经知道当解析器找到一个标识符时,它总是尝试查找这个名字以找出当前绑定的声明。该声明就是当前要用的那个对象,这通常是一个*_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 nevertype-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     returnfalse;

11988

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

11990     thecast 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     returndependent_type_p (TREE_TYPE (expression));

11997

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

11999     by theexpression.  */

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 mayappear 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         aswell.  */

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     returntrue;

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     returntrue;

12028

12029   if (TREE_CODE (expression)== TEMPLATE_DECL

12030       && !DECL_TEMPLATE_TEMPLATE_PARM_P(expression))

12031     returnfalse;

 

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

literal

postfix-expression.pseduo-destructor-name

postfix-expression->pseduo-destructor-name

sizeofunary-expression

sizeof(type-id)

typeid(expression)

typeid (type-id)

::optdelete cast-expression

::optdelete[] cast-expression

throwassignment-expression opt

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

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

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

一个依赖的template-id

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

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

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

simple-type-specifier(expression-list opt)

::optnew new-placement opt new-type-idnew-initializer opt

::optnew 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)                                                                           inpt.c

11788 {

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

11790     anydependent types.  */

11791   if (!processing_template_decl)

11792     returnfalse;

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     returntrue;

11798

11799   /* Erroneous types can be considerednon-dependent.  */

11800   if (type == error_mark_node)

11801     returnfalse;

11802

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

11804     do sonow.  */

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   returnTYPE_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节点。

那么根据【3ISO-IE-14882-200314.6名字解析(nameresolution):

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

例如:

// no B declared here

class X;

template<classT> class Y {

        class Z;          // forwarddeclaration 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

               typedeftypename T::A TA;

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

               typenameT::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, novisible declaration of B and a8

        }

};

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

elaborated-type-specifier:

        typename::opt nested-name-specifier identifier

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

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

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

例如:

template<classT> struct A {

        typedefint B;

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

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

        typenameA::B g();  // OK

};

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

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

 

11686 static bool

11687 dependent_type_p_r (tree type)                                                                        inpt.c

11688 {

11689   tree scope;

11690

11691   /*[temp.dep.type]

11692

11693    A type is dependent if it is:

11694

11695    -- atemplate parameter. Template template parameters are

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

11697    handlethem here.  */

11698   if (TREE_CODE (type) ==TEMPLATE_TYPE_PARM

11699       || TREE_CODE (type) ==TEMPLATE_TEMPLATE_PARM)

11700     returntrue;

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

11702     class-name that names a dependent type orwhose unqualified-id

11703     namesa dependent type.  */

11704   if (TREE_CODE (type) ==TYPENAME_TYPE)

11705     returntrue;

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     returndependent_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       returntrue;

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     returnfalse;

11730   }

 

11710行,如果type是指向类数据成员或方法的指针,TYPE_PTR_TO_MEMBER_P不为0,而对于类型T X::*TYPE_PTRMEM_CLASS_TYPE返回XTYPE_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     sizeis 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       returntrue;

11742     returndependent_type_p (TREE_TYPE (type));

11743   }

 

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

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

5.12.4.2.1.3. 依赖于值

值依赖的表达式应该是:

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

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

以依赖类型声明的名字。

模板非类型参数的名字。

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

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

Ÿ       以下形式的表达式是值依赖的,如果type-idsimple-type-specifier部分是依赖的,或者expressioncast-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)                                                inpt.c

11853 {

11854   if (!processing_template_decl)

11855     returnfalse;

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     returntrue;

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     returntrue;

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

11868     withan 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     returntrue;

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

11875     castoccurs 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 ofoperands.  */

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-constantexpressions.  */

11893       my_friendly_assert(INTEGRAL_OR_ENUMERATION_TYPE_P (type),

11894                       20040318);

11895

11896       returnfalse;

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       returnfalse;

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     returntype_dependent_expression_p(expression);

11921   }

11922   if (TREE_CODE (expression)== SCOPE_REF)

11923     returndependent_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 ofPREDECREMENT_EXPR, the

11948             amount to increment by may bemissing.) 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             returntrue;

11954         return false;

11955       }

11956     }

11957   }

11958

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

11960   returnfalse;

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.ia.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))                                   inpt.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     returntrue;

11826

11827   scope = TREE_OPERAND(expression, 0);

11828   name = TREE_OPERAND(expression, 1);

11829

11830   /* [temp.dep.expr]

11831

11832     Anid-expression is type-dependent if it contains a

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

11834     dependent type.  */

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

11836     qualifying type is the current class, thenwe must peek

11837     insideit.  */

11838   if (DECL_P (name)

11839       && currently_open_class(scope)

11840       && !criterion(name))

11841     returnfalse;

11842   if (dependent_type_p (scope))

11843     returntrue;

11844

11845   returnfalse;

11846 }

 

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

template<typenameT> struct A {

    int j;

};

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

另外,考虑以下例子:

template <typename T> struct A{

        typedefT innerType;

innerType j;

};

A<int>::innerTypeintType;

A<T>::innerTypeaType

intTypeA<int>::innerType)不是值依赖的,但aTypeA<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     returntrue;

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

11750     anexpression 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     returntrue;

11755   

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

11757     expression is not type-dependent, then itshould already been

11758     haveresolved.  */

11759   if (TREE_CODE (type) ==TYPEOF_TYPE)

11760     returntrue;

11761   

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

11763     totemplate 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     Thesize of `E' cannot be known until the value of `I' has been

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

11773   scope = TYPE_CONTEXT (type);

11774   if (scope && TYPE_P(scope))

11775     returndependent_type_p (scope);

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

11777     returntype_dependent_expression_p (scope);

11778

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

11780   returnfalse;

11781 }

 

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

例子1

template<class T> structTemp {

    int t;

};

 

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

    V func;

};

 

int main() {

    A<Temp, int> a;

    a.func.t = 0;

    return1;

}

类型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;

    return1;

}

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

12134 }

 

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

 

12097 static bool

12098 dependent_template_arg_p (tree arg)                                                                 inpt.c

12099 {

12100   if (!processing_template_decl)

12101     returnfalse;

12102

12103   if (TREE_CODE (arg) ==TEMPLATE_DECL

12104       || TREE_CODE (arg) ==TEMPLATE_TEMPLATE_PARM)

12105     returndependent_template_p (arg);

12106   else if (TYPE_P (arg))

12107     returndependent_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)                                                                     inpt.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     returnfalse;

12150   }

12151

12152   /*Template template parameters are dependent. */

12153   if(DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)

12154       || TREE_CODE (tmpl) ==TEMPLATE_TEMPLATE_PARM)

12155     returntrue;

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

12157   if (TREE_CODE (tmpl) ==SCOPE_REF

12158       || TREE_CODE (tmpl) ==IDENTIFIER_NODE)

12159     returntrue;

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

12161   if (TYPE_P (CP_DECL_CONTEXT(tmpl)))

12162     returndependent_type_p (DECL_CONTEXT (tmpl));

12163   returnfalse;

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       returnfalse;

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

 

原创粉丝点击