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

5.12.4.2.2.2.3.          完成 template-id

如果模板名是一个 IDENTIFER_NODE ,它可能是一个成员模板;而如果它是应该类模板的 TEMPLATE_DECL template-id 本身是一个类名;而如果是 FUNCTION_DECL OVERLOAD METHOD_DECL template-id 就是一个函数名。

因此如果模板名是一个类模板, template-id 可能代表一个新的类,对此我们需要通过 finish_template_type 来构建相应的类型。它是应该非常复杂的过程,在后面的章节中将给出一个例子来浏览这一过程。

 

cp_parser_template_id (continue)

 

7991   /* Build a representation of the specialization.  */

7992   if (TREE_CODE (template) == IDENTIFIER_NODE)

7993     template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);

7994   else if (DECL_CLASS_TEMPLATE_P (template)

7995         || DECL_TEMPLATE_TEMPLATE_PARM_P (template))

7996     template_id

7997       = finish_template_type (template, arguments,

7998                           cp_lexer_next_token_is (parser->lexer,

7999                                               CPP_SCOPE));

8000   else

8001   {

8002     /* If it's not a class-template or a template-template, it should be

8003       a function-template.  */

8004     my_friendly_assert ((DECL_FUNCTION_TEMPLATE_P (template)

8005                      || TREE_CODE (template) == OVERLOAD

8006                      || BASELINK_P (template)),

8007                      20010716);

8008      

8009     template_id = lookup_template_function (template, arguments);

8010   }

8011  

8012   /* Retrieve any deferred checks. Do not pop this access checks yet

8013     so the memory will not be reclaimed during token replacing below.  */

8014   access_check = get_deferred_access_checks ();

 

如果模板名是一个 IDNETIFIER_NODE ,所形成的 TEMPLATE_ID_EXPR build_min_nt 来构建。该函数构建的是一个 tree_exp 节点。

 

4069 tree

4070 build_min_nt (enum tree_code code, ...)                                                            in tree.c

4071 {

4072    tree t;

4073    int length;

4074    int i;

4075    va_list p;

4076

4077    va_start (p, code);

4078

4079    t = make_node (code);

4080    length = TREE_CODE_LENGTH (code);

4081    TREE_COMPLEXITY (t) = input_line;

4082

4083    for (i = 0; i < length; i++)

4084    {

4085      tree x = va_arg (p, tree);

4086      TREE_OPERAND (t, i) = x;

4087    }

4088

4089    va_end (p);

4090    return t;

4091 }

 

如果模板名是一个函数模板,所对应的 TEMPLATE_ID_EXPR 节点则是由 lookup_template_function 来构建。一个 BASEL INK 节点表示从基类对成员函数或成员函数集(因为重载)的引用。注意在这个情形下,在所产生的 TEMPLATE_ID_EXPR 节点中,其类型是 unknonw_type_node ,这将强制前端在后面调用 instantiate_type 来解析其类型。

 

4069 tree

4070 lookup_template_function (tree fns, tree arglist)                                                  in pt.c

4071 {

4072    tree type;

4073

4074    if (fns == error_mark_node || arglist == error_mark_node)

4075      return error_mark_node;

4076

4077    my_friendly_assert (!arglist || TREE_CODE (arglist) == TREE_VEC, 20030726);

4078    my_friendly_assert (fns && (is_overloaded_fn (fns)

4079                            || TREE_CODE (fns) == IDENTIFIER_NODE),

4080                    20050608);

4081

4082    if (BASELINK_P (fns))

4083    {

4084      BASELINK_FUNCTIONS (fns) = build (TEMPLATE_ID_EXPR,

4085                                        unknown_type_node,

4086                                        BASELINK_FUNCTIONS (fns),

4087                                        arglist);

4088      return fns;

4089    }

4090

4091    type = TREE_TYPE (fns);

4092    if (TREE_CODE (fns) == OVERLOAD || !type)

4093      type = unknown_type_node;

4094   

4095    return build (TEMPLATE_ID_EXPR, type, fns, arglist);

4096 }

 

然后对应的符号被捆绑成 CPP_TEMPLATE_ID ;类似的符号组还有 NESTED_NAME_SPECFIER

 

cp_parser_template_id (continue)

 

8016    /* If parsing tentatively, replace the sequence of tokens that makes

8017      up the template-id with a CPP_TEMPLATE_ID token. That way,

8018      should we re-parse the token stream, we will not have to repeat

8019      the effort required to do the parse, nor will we issue duplicate

8020      error messages about problems during instantiation of the

8021      template.  */

8022    if (start_of_id >= 0)

8023    {

8024      cp_token *token;

8025

8026      /* Find the token that corresponds to the start of the

8027        template-id.  */

8028      token = cp_lexer_advance_token (parser->lexer,

8029                                  parser->lexer->first_token,

8030                                   start_of_id);

8031

8032      /* Reset the contents of the START_OF_ID token.  */

8033      token->type = CPP_TEMPLATE_ID;

8034      token->value = build_tree_list (access_check, template_id);

8035      token->keyword = RID_MAX;

8036      /* Purge all subsequent tokens.  */

8037      cp_lexer_purge_tokens_after (parser->lexer, token);

8038

8039      /* ??? Can we actually assume that, if template_id ==

8040        error_mark_node, we will have issued a diagnostic to the

8041        user, as opposed to simply marking the tentative parse as

8042        failed?  */

8043      if (cp_parser_error_occurred (parser) && template_id != error_mark_node)

8044        error ("parse error in template argument list");

8045     }

8046

8047    pop_deferring_access_checks ();

8048    return template_id;

8049 }

5.12.4.2.2.3.  完成类名查找

当为 identifier 获得 decl 时,根据语法,它必须是一个标识符或 template-id 。如果参数 typename_p true ,这表示已经看到关键字 typename 。因此调用 make_typename_type 来解析“ typename CONTEXT::NAME ”,并返回合适的类型。

 

cp_parser_class_name (continue)

 

11812    decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);

11813

11814     /* If this is a typename, create a TYPENAME_TYPE.  */

11815    if (typename_p && decl != error_mark_node)

11816    {

11817      decl = make_typename_type (scope, decl, /*complain=* /1);

11818      if (decl != error_mark_node)

11819        decl = TYPE_NAME (decl);

11820    }

11821

11822    /* Check to see that it is really the name of a class.  */

11823    if (TREE_CODE (decl) == TEMPLATE_ID_EXPR

11824        && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE

11825        && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))

11826        /* Situations like this:

11827

11828           template <typename T> struct A {

11829               typename T::template X<int>::I i;

11830           };

11831

11832           are problematic. Is `T::template X<int>' a class-name? The

11833           standard does not seem to be definitive, but there is no other

11834            valid interpretation of the following `::'. Therefore, those

11835           names are considered class-names.  */

11836      decl = TYPE_NAME (make_typename_type (scope, decl, tf_error));

11837    else if (decl == error_mark_node

11838          || TREE_CODE (decl) != TYPE_DECL

11839          || !IS_AGGR_TYPE (TREE_TYPE (decl)))

11840    {

11841      cp_parser_error (parser, "expected class-name");

11842      return error_mark_node;

11843    }

11844

11845    return decl;

11846 }

 

参考在 cp_parser_template_id 中调用的 maybe_get_template_decl_from_type_decl 来帮助更好地理解 cp_parser_maybe_treat_template_as_class 。参数 tag_name_p true 时, decl 表示的类正在 class-head 中定义,或声明在一个 elaborated-type-specifier 中。

 

13901 static tree

13902 cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p)              in parser.c

13903 {

13904   /* If the TEMPLATE_DECL is being declared as part of a class-head,

13905     the translation from TEMPLATE_DECL to TYPE_DECL occurs:

13906

13907        struct A {

13908          template <typename T> struct B;

13909        };

13910

13911        template <typename T> struct A::B {};

13912   

13913     Similarly, in a elaborated-type-specifier:

13914

13915        namespace N { struct X{}; }

13916

13917        struct A {

13918          template <typename T> friend struct N::X;

13919        };

13920

13921     However, if the DECL refers to a class type, and we are in

13922     the scope of the class, then the name lookup automatically

13923     finds the TYPE_DECL created by build_self_reference rather

13924     than a TEMPLATE_DECL. For example, in:

13925

13926        template <class T> struct S {

13927          S s;

13928        };

13929

13930     there is no need to handle such case.  */

13931

13932   if (DECL_CLASS_TEMPLATE_P (decl) && tag_name_p)

13933     return DECL_TEMPLATE_RESULT (decl);

13934

13935   return decl;

13936 }

 

函数的作用是,如果 decl 是一个可以在当前上下文中按 TYPE_DECL 处理的 TEMPLATE_DECL ,返回其对应的 TYPE_DECL

下面如果 name 是一个类模板(由 CLASSTYPE_IS_TEMPLATE )或者一个模板的具现或特化( CLASSTYPE_USE_TEMPLATE ),一个 TMEPLATE_ID_EXPR 被构建。其处理涉及函数 lookup_template_class ,我们在后面再结合例子来看这个复杂的函数。

 

2608 tree

2609 make_typename_type (tree context, tree name, tsubst_flags_t complain)               in decl.c

2610 {

2611    tree fullname;

2612

2613    if (name == error_mark_node

2614        || context == NULL_TREE

2615        || context == error_mark_node)

2616      return error_mark_node;

2617

2618    if (TYPE_P (name))

2619    {

2620      if (!(TYPE_LANG_SPECIFIC (name)

2621          && (CLASSTYPE_IS_TEMPLATE (name)

2622              || CLASSTYPE_USE_TEMPLATE (name))))

2623         name = TYPE_IDENTIFIER (name);

2624      else

2625         /* Create a TEMPLATE_ID_EXPR for the type.  */

2626         name = build_nt (TEMPLATE_ID_EXPR,

2627                       CLASSTYPE_TI_TEMPLATE (name),

2628                       CLASSTYPE_TI_ARGS (name));

2629    }

2630    else if (TREE_CODE (name) == TYPE_DECL)

2631      name = DECL_NAME (name);

2632

2633    fullname = name;

2634

2635    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)

2636    {

2637      name = TREE_OPERAND (name, 0);

2638      if (TREE_CODE (name) == TEMPLATE_DECL)

2639         name = TREE_OPERAND (fullname, 0) = DECL_NAME (name);

2640    }

2641    if (TREE_CODE (name) == TEMPLATE_DECL)

2642    {

2643      error ("`%D' used without template parameters", name);

2644      return error_mark_node;

2645    }

2646    my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030802);

2647    my_friendly_assert (TYPE_P (context), 20050905);

2648

2649    if (!dependent_type_p (context)

2650        || currently_open_class (context))

2651    {

2652      if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR)

2653      {

2654          tree tmpl = NULL_TREE;

2655        if (IS_AGGR_TYPE (context))

2656            tmpl = lookup_field (context, name, 0, false);

2657        if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))

2658        {

2659          if (complain & tf_error)

2660             error ("no class template named `%#T' in `%#T'",

2661                  name, context);

2662          return error_mark_node;

2663        }

2664

2665        if (complain & tf_error)

2666            perform_or_defer_access_check (TYPE_BINFO (context), tmpl);

2667

2668        return lookup_template_class (tmpl,

2669                                  TREE_OPERAND (fullname, 1),

2670                                  NULL_TREE, context,

2671                                  /*entering_scope=*/ 0,

2672                                  tf_error | tf_warning | tf_user);

2673      }

2674      else

2675      {

2676        tree t;

2677

2678         if (!IS_AGGR_TYPE (context))

2679         {

2680           if (complain & tf_error)

2681            error ("no type named `%#T' in `%#T'", name, context);

2682           return error_mark_node;

2683         }

2684

2685         t = lookup_field (context, name, 0, true);

2686         if (t)

2687         {

2688           if (TREE_CODE (t) != TYPE_DECL)

2689          {

2690              if (complain & tf_error)

2691               error ("no type named `%#T' in `%#T'", name, context);

2692             return error_mark_node;

2693          }

2694

2695           if (complain & tf_error)

2696            perform_or_defer_access_check (TYPE_BINFO (context), t);

2697

2698           if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))

2699            t = TREE_TYPE (t);

2700      

2701          return t;

2702         }

2703      }

2704    }

2705

2706    /* If the CONTEXT is not a template type, then either the field is

2707      there now or its never going to be.  */

2708    if (!dependent_type_p (context))

2709    {

2710      if (complain & tf_error)

2711        error ("no type named `%#T' in `%#T'", name, context);

2712      return error_mark_node;

2713    }

2714

2715    return build_typename_type (context, name, fullname);

2716 }

 

而对于表达式“ typename CONTEXT::NAME ”,如果 CONTEXT 不具有依赖性,或者它是当前打开的类, NAME 首先通过 lookup_field 在该类中查找。

 

1372 tree

1373 lookup_field (tree xbasetype, tree name, int protect, bool want_type)             in search.c

1374 {

1375    tree rval = lookup_member (xbasetype, name, protect, want_type);

1376   

1377    /* Ignore functions.  */

1378    if (rval && BASELINK_P (rval))

1379      return NULL_TREE;

1380

1381    return rval;

1382 }

 

看到参数 want_type 2656 行的调用中,对于 template-id false ;而在 2685 行的调用中对普通类型是 true 。而 want_type true ,表示我们只接受 TYPE_DECL

如果找不到该名字,而且该上下文具有依赖性,就必须为这个类型构建一个占位符。这就是 TYPENAME_TYPE 节点。

 

2566 static tree

2567 build_typename_type (tree context, tree name, tree fullname)                        in decl.c

2568 {

2569    tree t;

2570    tree d;

2571    void **e;

2572

2573    if (typename_htab == NULL)

2574    {

2575      typename_htab = htab_create_ggc (61, &typename_hash,

2576                                   &typename_compare, NULL);

2577    }

2578

2579    /* Build the TYPENAME_TYPE.  */

2580    t = make_aggr_type (TYPENAME_TYPE);

2581    TYPE_CONTEXT (t) = FROB_CONTEXT (context);

2582    TYPENAME_TYPE_FULLNAME (t) = fullname;

2583

2584    /* Build the corresponding TYPE_DECL.  */

2585    d = build_decl (TYPE_DECL, name, t);

2586    TYPE_NAME (TREE_TYPE (d)) = d;

2587    TYPE_STUB_DECL (TREE_TYPE (d)) = d;

2588    DECL_CONTEXT (d) = FROB_CONTEXT (context);

2589    DECL_ARTIFICIAL (d) = 1;

2590

2591    /* See if we already have this type.  */

2592    e = htab_find_slot (typename_htab , t, INSERT);

2593    if (*e)

2594      t = (tree) *e;

2595    else

2596      *e = t;

2597

2598    return t;

2599 }

 

TYPENAME_TYPE 节点表示 typename T::t ”这样的结构。在这个节点中,其 TYPE_CONTEXT 是‘ T ’, TYPE_NAME 是代表‘ t ’的一个 IDENTIFIER_NODE 。如果该类型来自 template-id TYPENAME_TYPE_FULLNAME 将保存这个 TEMPLATE_ID_EXPR

注意这里对“ typename T::t ”的处理,‘ T ’在前一步中已经被解析,它可能是一个模板或模板参数,其子树已经构建。因此事实上,在不同的上下文‘ T ’中,“ typename T::t ”代表不同的结构。为了确保在编译单元中,代表这些结构的节点的唯一性,这些节点都被保存在哈希表 typename_htab 中。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值