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>::i及pb->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::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 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_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)
::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节点。
那么根据【3】ISO-IE-14882-2003,14.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只能用于限定名字,但这些名字不需要是依赖的。关键字typename在base-specifier或mem-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>的类模板中,A及A<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返回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 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_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) 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.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)) 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
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 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)。对于模板相关的树节点,参考图形:访问模板定义的宏。它只是检测最里层的模板实参,因为【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) 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。
- GCC-3.4.6源代码学习笔记(121)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 小酌独饮对月吟
- 摸索
- GCC-3.4.6源代码学习笔记(120)
- Studying note of GCC-3.4.6 source (120)
- 窗口刷新时的问题
- GCC-3.4.6源代码学习笔记(121)
- 喜欢羽球
- Studying note of GCC-3.4.6 source (121)
- 最后一个人可以挽救360和QQ的——马云
- VirtualBox安装Fedora后的相关设置1——全屏显示
- visibility 属性
- Ext JavaScript 运行机制
- oracle数据库使用odbc导出到access失败
- c#俄罗斯方块程序