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

5.12.4.1.1.2.  缺省实参

跟在模板模板参数后的符号是“ = ::Loki::SingleThreaded ”,它是模板模板参数的缺省实参。“ ::Loki::SingleThreaded ”是 id-expression 形式。

 

cp_parser_type_parameter (continue)

 

7804         /* If the next token is an `=', then there is a

7805           default-argument.  */

7806         if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))

7807         {

7808           bool is_template;

7809  

7810           /* Consume the `='.  */

7811           cp_lexer_consume_token (parser->lexer);

7812           /* Parse the id-expression.  */

7813           default_argument

7814                = cp_parser_id_expression (parser,

7815                                       /*template_keyword_p=*/ false,

7816                                       /*check_dependency_p=*/ true,

7817                                       /*template_p=*/ &is_template,

7818                                       /*declarator_p=*/ false);

7819           if (TREE_CODE (default_argument) == TYPE_DECL)

7820             /* If the id-expression was a template-id that refers to

7821               a template-class, we already have the declaration here,

7822               so no further lookup is needed.  */

7823             ;

7824           else

7825             /* Look up the name.  */

7826             default_argument

7827                 = cp_parser_lookup_name (parser, default_argument,

7828                                        /*is_type=*/ false,

7829                                         /*is_template=*/ is_template,

7830                                        /*is_namespace=*/ false,

7831                                        /*check_dependency=*/ true);

7832           /* See if the default argument is valid.  */

7833           default_argument

7834               = check_template_template_default_arg (default_argument);

7835         }

7836         else

7837           default_argument = NULL_TREE;

7838  

7839         /* Create the combined representation of the parameter and the

7840           default argument.  */

7841         parameter = build_tree_list (default_argument, parameter);

7842       }

7843       break ;

7844  

7845       default :

7846         abort ();

7847         break ;

7848     }

7849    

7850     return parameter;

7851   }

 

为了方便起见,我们重新显示 cp_parser_id_expression 如下。该函数将返回对应的 IDENTIFIER_NODE 节点。对于这个例子,这个标识符是“ SingleThreaded ”。

 

2685   static tree

2686   cp_parser_id_expression (cp_parser *parser,                                               in parser.c

2687                        bool template_keyword_p,

2688                         bool check_dependency_p,

2689                        bool *template_p,

2690                        bool declarator_p)

2691   {

2692     bool global_scope_p;

2693     bool nested_name_specifier_p;

2694  

2695     /* Assume the `template' keyword was not used.  */

2696     if (template_p)

2697       *template_p = false;

2698  

2699     /* Look for the optional `::' operator.  */

2700     global_scope_p

2701       = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/ false)

2702          != NULL_TREE);

2703     /* Look for the optional nested-name-specifier.  */

2704     nested_name_specifier_p

2705       = (cp_parser_nested_name_specifier_opt (parser,

2706                                         /*typename_keyword_p=*/ false,

2707                                         check_dependency_p,

2708                                         /*type_p=*/ false,

2709                                         declarator_p)

2710          != NULL_TREE);

2711     /* If there is a nested-name-specifier, then we are looking at

2712       the first qualified-id production.  */

2713     if (nested_name_specifier_p)

2714     {

2715       tree saved_scope;

2716       tree saved_object_scope;

2717       tree saved_qualifying_scope;

2718       tree unqualified_id;

2719       bool is_template;

2720  

2721       /* See if the next token is the `template' keyword.  */

2722       if (!template_p)

2723         template_p = &is_template;

2724       *template_p = cp_parser_optional_template_keyword (parser);

2725        /* Name lookup we do during the processing of the

2726          unqualified-id might obliterate SCOPE.  */

2727        saved_scope = parser->scope;

2728        saved_object_scope = parser->object_scope;

2729        saved_qualifying_scope = parser->qualifying_scope;

2730        /* Process the final unqualified-id.  */

2731        unqualified_id = cp_parser_unqualified_id (parser, *template_p,

2732                                            check_dependency_p,

2733                                            declarator_p);

2734        /* Restore the SAVED_SCOPE for our caller.  */

2735        parser->scope = saved_scope;

2736        parser->object_scope = saved_object_scope;

2737        parser->qualifying_scope = saved_qualifying_scope;

2738  

2739        return unqualified_id;

2740     }

2792   }

 

首先,如果“ :: ”存在, cp_parser_global_scope_opt 将返回 global_namespace 作为全局名字空间作用域,并且同时相应的 NAMESPACE_DECL 节点被设置入 parser scope 域。符号“ Loki:: ”构成了 nested-name-specifier ,在 2705 行的 cp_parser_nested_name_specifier_opt 返回由该指定符( specifier )指定的类或名字空间作用域。对于这个例子,它是名字空间 “Loki” 的作用域。同样 parser scope 域被更新为相关的 NAMESPACE_DECL 节点。在 2731 行, cp_parser_unqualified_id 将返回绑定在该作用域中的 IDENTIFIER_NODE 节点。不过, IDNETIFIER_NODE 并不是我们期望的。这里我们需要 TEMPLATE_DECL 节点。因此这个名字由 cp_parser_lookup_name 来查找以返回期望的节点。

5.12.4.1.1.2.1.          名字查找的细节

函数 cp_parser_lookup_name 在中间树中查找指定的名字。不过对于依赖类型( dependent type ),不能应用普通的名字查找,因为类型仍然未知。

对于这个函数最后 4 个参数控制查找的过程:

如果 is_type true ,忽略不是引用类型的绑定。

如果 it_template true ,忽略不是引用模板的绑定。

如果 is_namespace true ,忽略不是引用名字空间的绑定。

如果 check_dependency true ,不在依赖类型内查找名字。

除了过滤掉不期望的结果,函数还需要检查重复对象。

 

13692 static tree

13693 cp_parser_lookup_name (cp_parser *parser, tree name,                               in parser.c

13694                       bool is_type, bool is_template, bool is_namespace,

13695                       bool check_dependency)

13696 {

13697    int flags = 0;

13698    tree decl;

13699    tree object_type = parser->context->object_type;

13700

13701    /* Now that we have looked up the name, the OBJECT_TYPE (if any) is

13702      no longer valid. Note that if we are parsing tentatively, and

13703      the parse fails, OBJECT_TYPE will be automatically restored.  */

13704    parser->context->object_type = NULL_TREE;

13705

13706    if (name == error_mark_node)

13707      return error_mark_node;

13708

13709    if (!cp_parser_parsing_tentatively (parser)

13710        || cp_parser_committed_to_tentative_parse (parser))

13711      flags |= LOOKUP_COMPLAIN;

13712

13713    /* A template-id has already been resolved; there is no lookup to

13714      do.  */

13715    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)

13716      return name;

13717    if (BASELINK_P (name))

13718    {

13719      my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name))

13720                          == TEMPLATE_ID_EXPR),

13721                       20020909);

13722      return name;

13723    }

13724

13725    /* A BIT_NOT_EXPR is used to represent a destructor. By this point,

13726      it should already have been checked to make sure that the name

13727      used matches the type being destroyed.  */

13728    if (TREE_CODE (name) == BIT_NOT_EXPR)

13729    {

13730      tree type;

13731

13732      /* Figure out to which type this destructor applies.  */

13733      if (parser->scope)

13734        type = parser->scope;

13735      else if (object_type)

13736        type = object_type;

13737      else

13738        type = current_class_type ;

13739      /* If that's not a class type, there is no destructor.  */

13740      if (!type || !CLASS_TYPE_P (type))

13741        return error_mark_node;

13742      if (!CLASSTYPE_DESTRUCTORS (type))

13743        return error_mark_node;

13744       /* If it was a class type, return the destructor.  */

13745      return CLASSTYPE_DESTRUCTORS (type);

13746    }

 

注意 13719 行的断言,如果找到了 BASELINK (这是对一个或一组基类的成员函数的引用。 BASELINK_FUNCTIONS 根据这些函数给出对应的 FUNCTION_DECL TEMPLATE_DECL OVERLOAD TEMPLATE_ID_EXPR 节点),它必须指向一个 template-id-expr 。为什么? 考虑:

struct A { void f(); };

struct B: public A {};
B b;

b.f();

BASELINK 节点将为“ b.f() ”而构建,因为“ b.f() ”实际上是“ a.f() ”,但这是名字查找的结果。这个 BASELINK 不会在查找过程中出现。

而对于析构函数,如果在类外部,它必须或者是 nested-name-specifier ,或者是声明符(即,“ a.~A() ”或“ A::~A() ”)。在解析“ a. ”或“ A:: ”部分之后(通常由前一次 cp_parser_lookup_name 来完成),将填充 parser scope (对于“ A:: ”)或 object_type (对于“ a. ”)域。否则,它应该在当前类中,该由 current_class_type 所指向。在 13745 行, CLASSTYPE_DESTRUCTORS 返回这个析构函数。

5.12.4.1.1.2.1.1.    在指定域中查找

parser scope 域表示进行名字查找的区域。如果是 NULL_TREE ,那么我们要在源程序中当前打开的作用域内查找名字。如果不是 NULL ,它是一个代表所要查找的作用域的 *_TYPE 或者 NAMESPACE_DECL 节点。

 

cp_parser_lookup_name (continue)

 

13754    /* Perform the lookup.  */

13755    if (parser->scope)

13756    {

13757      bool dependent_p;

13758

13759      if (parser->scope == error_mark_node)

13760       return error_mark_node;

13761

13762      /* If the SCOPE is dependent, the lookup must be deferred until

13763        the template is instantiated -- unless we are explicitly

13764        looking up names in uninstantiated templates. Even then, we

13765        cannot look up the name if the scope is not a class type; it

13766         might, for example, be a template type parameter.  */

13767      dependent_p = (TYPE_P (parser->scope)

13768                   && !(parser->in_declarator_p

13769                        && currently_open_class (parser->scope))

13770                   && dependent_type_p (parser->scope));

13771      if ((check_dependency || !CLASS_TYPE_P (parser->scope))

13772         && dependent_p)

13773     {

13774        if (is_type)

13775          /* The resolution to Core Issue 180 says that `struct A::B'

13776            should be considered a type-name, even if `A' is

13777            dependent.  */

13778          decl = TYPE_NAME (make_typename_type (parser->scope,

13779                           name,

13780                            /*complain=*/ 1));

13781        else if (is_template)

13782          decl = make_unbound_class_template (parser->scope,

13783                                         name,

13784                                          /*complain=*/ 1);

13785        else

13786          decl = build_nt (SCOPE_REF, parser->scope, name);

13787     }

 

如果 parser scope 域是依赖的,查找的结果依赖于传入函数的查找控制标志,不过注意在 is_type is_template is_namespace 标志中,在调用时,最多设置一个标志。

如果我们正在查找类型,这里有所谓的 Core Iusse 180 问题。其具体描述在 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#180

180. typename 及阐述类型( elaborated types

Section: 14.7  [temp.res]     Status: CD1     Submitter: Mike Miller     Date: 21 Dec 1999

[Moved to DR at 4/02 meeting.]

Mike Miller : 在对 issue 68 的讨论中,提及了一个关于 typename 的问题。在一定程度上,它与在一个能明确知道要求一个类型的上下文中忽略 typename 的这个想法相关。考虑:

        template <class T>

        class X {

            friend class T::nested;

        };

这里要求 typename 吗?如果是这样,它应该出现在哪里呢?(语法看起来不允许它出现在一个具有 class-key elaborated-type-specifier 里)。

Bill Gibbons : class 应用到限定名中的最后一个标识符,因为所有之前的名字必须是 类或者名字空间。因为这个名字被限定为作为一个类,它不需要 typename [ 不过, ] 看起来 14.7 [temp.res] 的段落 3 要求 typename 并且后面的段落没有豁免这个情况。这是我们所不同意的。

Proposed resolution (04/01):

14.7 [temp.res] 段落 5 ,修改

关键字 typename 在一个 base-specifier mem-initializer 中是不被允许的,在这些上下文中一个依赖于一个 template-parameter 14.7.2 [temp.dep] )的限定名( qualified-name )隐含地假定为是一个类型的名字。

一个在 mem-initializer-id base-specifier ,或 elaborated-type-specifier (以 class-key enum 形式)中用作名字的限定名隐含地假定为命名一个类型,而不需要关键字 typename [ 注意:关键字 typename 不为这些结构的句法( syntax )所不允许 ]

issue 254 的期望的解决方案将从 elaborated-type-specifier 的语法中移去那个 typename 的形式。如果这个解决方案被采纳,在先前措辞中的括号短语“ ( class-key enum 形式 ) ”将被移去,因为那将是仅有的 elaborated-type-specifier 形式)。

简而言之, A::B 如果 A 是依赖性的, B 将被认为是 typename 。而如果 is_template true ,它就是由【 3 】,条款 14.2 “模板特化的名字( Names of template specializations )”,条件 4

当一个成员模板特化的名字,在一个 postfix-expression 中出现在“ . ”或“ -> ”之后,或在一个 qualified-id 中出现在 nested-name-specifier 之后,并且该 postfix-expression qualified-id 明确地依赖于一个模板参数,该成员模板的名字必须以关键字 template 为前缀。否则该名字被假定为一个非模板。例如:

 

class X {

public :

template <size_t> X* alloc();

template <size_t> static X* adjust();

};

template <class T> void f(T* p)

{

T* p1 = p->alloc<200>();

// ill-formed: < means less than

T* p2 = p->template alloc<200>();

// OK: < starts template argument list

T::adjust<100>();

// ill-formed: < means less than

T::template adjust<100>();

// OK: < starts template argument list

}

在这个例子中,形如:“ T::template adjust<100>(); ”的表达式,是这里由 make_unbound_class_template 处理的目标。

 

2724 tree

2725 make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)   in decl.c

2726 {

2727    tree t;

2728    tree d;

2729

2730    if (TYPE_P (name))

2731      name = TYPE_IDENTIFIER (name);

2732    else if (DECL_P (name))

2733      name = DECL_NAME (name);

2734    if (TREE_CODE (name) != IDENTIFIER_NODE)

2735      abort ();

2736

2737    if (!dependent_type_p (context)

2738        || currently_open_class (context))

2739    {

2740      tree tmpl = NULL_TREE;

2741

2742      if (IS_AGGR_TYPE (context))

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

2744

2745      if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))

2746      {

2747        if (complain & tf_error)

2748          error ("no class template named `%#T' in `%#T'", name, context);

2749        return error_mark_node;

2750      }

2751       

2752      if (complain & tf_error)

2753        perform_or_defer_access_check (TYPE_BINFO (context), tmpl);

2754

2755      return tmpl;

2756    }

2757

2758     /* Build the UNBOUND_CLASS_TEMPLATE.  */

2759    t = make_aggr_type (UNBOUND_CLASS_TEMPLATE);

2760    TYPE_CONTEXT (t) = FROB_CONTEXT (context);

2761    TREE_TYPE (t) = NULL_TREE;

2762

2763     /* Build the corresponding TEMPLATE_DECL.  */

2764    d = build_decl (TEMPLATE_DECL, name, t);

2765    TYPE_NAME (TREE_TYPE (d)) = d;

2766     TYPE_STUB_DECL (TREE_TYPE (d)) = d;

2767    DECL_CONTEXT (d) = FROB_CONTEXT (context);

2768    DECL_ARTIFICIAL (d) = 1;

2769

2770    return t;

2771 }

 

2743 行, lookup_field 在里面调用 lookup_member ,它返回 NULL 如果找到的是函数( function )而不是方法( member )。看到在上面的表达式中,如果“ T ”不是依赖的,或者它是当前打开的类,这个表达式就是错误的,除非“ adjust ”是一个类模板。

否则,如果 T 是依赖性的并且不是当前打开的, UNBOUND_CLASS_TEMPLATE 为之构建。它被命名为 UNBOUND ,因为类似“ T ”的上下文仍然是未知的。

而在 cp_parser_lookup_name 13785 行,如果不期待类型或者模板,那么将它作为普通的 SCOPE_REF 来处理。

 

cp_parser_lookup_name (continue)

 

13788      else

13789     {

13790        bool pop_p = false;

13791     

13792        /* If PARSER->SCOPE is a dependent type, then it must be a

13793          class type, and we must not be checking dependencies;

13794          otherwise, we would have processed this lookup above. So

13795          that PARSER->SCOPE is not considered a dependent base by

13796          lookup_member, we must enter the scope here.  */

13797        if (dependent_p)

13798          pop_p = push_scope (parser->scope);

13799        /* If the PARSER->SCOPE is a a template specialization, it

13800          may be instantiated during name lookup. In that case,

13801          errors may be issued. Even if we rollback the current

13802           tentative parse, those errors are valid.  */

13803        decl = lookup_qualified_name (parser->scope, name, is_type,

13804                                 /*complain=*/ true);

13805        if (pop_p)

13806          pop_scope (parser->scope);

13807     }

13808      parser->qualifying_scope = parser->scope;

13809      parser->object_scope = NULL_TREE;

13810    }

 

如果 scope 不是依赖的,它构成了限定名。函数 lookup_qualified_name 执行名字解析。

 

3775 tree

3776 lookup_qualified_name (tree scope, tree name, bool is_type_p, bool complain)       in name-lookup.c

3777 {

3778    int flags = 0;

3779

3780    if (TREE_CODE (scope) == NAMESPACE_DECL)

3781    {

3782      cxx_binding binding;

3783

3784      cxx_binding_clear (&binding);

3785      flags |= LOOKUP_COMPLAIN;

3786      if (is_type_p)

3787         flags |= LOOKUP_PREFER_TYPES;

3788      if (qualified_lookup_using_namespace (name, scope, &binding, flags))

3789         return select_decl (&binding, flags);

3790    }

3791    else if (is_aggr_type (scope, complain))

3792    {

3793      tree t;

3794      t = lookup_member (scope, name, 0, is_type_p);

3795      if (t)

3796         return t;

3797    }

3798

3799    return error_mark_node;

3800 }

 

根据指定的作用域的性质不同,查找分为以下 2 种。

5.12.4.1.1.2.1.1.1.            在指定名字空间中的查找

如果指定的作用域是名字空间,那么查找工作由下面的函数接手。

 

3835   static bool

3836   qualified_lookup_using_namespace (tree name, tree scope,                    in name-lookup.c

3837                                 cxx_binding *result, int flags)

3838   {

3839     /* Maintain a list of namespaces visited...  */

3840     tree seen = NULL_TREE;

3841     /* ... and a list of namespace yet to see.  */

3842     tree todo = NULL_TREE;

3843     tree todo_maybe = NULL_TREE;

3844     tree usings;

3845     timevar_push (TV_NAME_LOOKUP);

3846     /* Look through namespace aliases.  */

3847     scope = ORIGINAL_NAMESPACE (scope);

3848     while (scope && result->value != error_mark_node)

3849     {

3850       cxx_binding *binding =

3851         cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name);

3852       seen = tree_cons (scope, NULL_TREE, seen);

3853       if (binding)

3854         result = ambiguous_decl (name, result, binding, flags);

3855  

3856       /* Consider strong using directives always, and non-strong ones

3857         if we haven't found a binding yet. ??? Shouldn't we consider

3858         non-strong ones if the initial RESULT is non-NULL, but the

3859         binding in the given namespace is?  */

3860       for (usings = DECL_NAMESPACE_USING (scope); usings;

3861           usings = TREE_CHAIN (usings))

3862         /* If this was a real directive, and we have not seen it.  */

3863         if (!TREE_INDIRECT_USING (usings))

3864         {

3865           /* Try to avoid queuing the same namespace more than once,

3866             the exception being when a namespace was already

3867             enqueued for todo_maybe and then a strong using is

3868             found for it. We could try to remove it from

3869             todo_maybe, but it's probably not worth the effort.  */

3870           if (is_associated_namespace (scope, TREE_PURPOSE (usings))

3871             && !purpose_member (TREE_PURPOSE (usings), seen)

3872             && !purpose_member (TREE_PURPOSE (usings), todo))

3873            todo = tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);

3874           else if ((!result->value && !result->type)

3875                  && !purpose_member (TREE_PURPOSE (usings), seen)

3876                  && !purpose_member (TREE_PURPOSE (usings), todo)

3877                  && !purpose_member (TREE_PURPOSE (usings), todo_maybe))

3878             todo_maybe = tree_cons (TREE_PURPOSE (usings), NULL_TREE,

3879                                  todo_maybe);

3880         }

3881       if (todo)

3882       {

3883         scope = TREE_PURPOSE (todo);

3884         todo = TREE_CHAIN (todo);

3885       }

3886       else if (todo_maybe

3887             && (!result->value && !result->type))

3888       {

3889         scope = TREE_PURPOSE (todo_maybe);

3890         todo = TREE_CHAIN (todo_maybe);

3891         todo_maybe = NULL_TREE;

3892       }

3893       else

3894         scope = NULL_TREE; /* If there never was a todo list.  */

3895     }

3896     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result->value != error_mark_node);

3897   }

 

如果在该名字空间查不出这个名字,在 3860 行的 FOR 循环处理在该名字空间中的“ using namespace xxx ”语句。看到在 3883 3889 行,“ using namespace xxx ”中的名字空间“ xxx ”被设置入 scope ,进入回到 3848 WHILE 循环开头,通过 cxx_scope_find_binding_for_name 来查找名字。

在一个作用域域中,如果可以同时看到同名的多个声明,则需要检查是否发生了错误。

 

3474 static cxx_binding *

3475 ambiguous_decl (tree name, cxx_binding *old, cxx_binding *new, int flags)   in name-lookup.c

3476 {

3477    tree val, type;

3478    my_friendly_assert (old != NULL, 393);

3479    /* Copy the value.  */

3480    val = new->value;

3481    if (val)

3482      switch (TREE_CODE (val))

3483      {

3484        case TEMPLATE_DECL:

3485          /* If we expect types or namespaces, and not templates,

3486            or this is not a template class.  */

3487          if (LOOKUP_QUALIFIERS_ONLY (flags)

3488              && !DECL_CLASS_TEMPLATE_P (val))

3489            val = NULL_TREE;

3490          break ;

3491        case TYPE_DECL:

3492          if (LOOKUP_NAMESPACES_ONLY (flags))

3493            val = NULL_TREE;

3494          break ;

3495        case NAMESPACE_DECL:

3496          if (LOOKUP_TYPES_ONLY (flags))

3497            val = NULL_TREE;

3498          break ;

3499        case FUNCTION_DECL:

3500          /* Ignore built-in functions that are still anticipated.  */

3501          if (LOOKUP_QUALIFIERS_ONLY (flags) || DECL_ANTICIPATED (val))

3502             val = NULL_TREE;

3503          break ;

3504        default :

3505          if (LOOKUP_QUALIFIERS_ONLY (flags))

3506            val = NULL_TREE;

3507      }

 

在指定的名字空间中,所谓的二义性发生在出现一个以上同名的同一类的声明时。比如,变量和函数可以同名,而不会导致二义性。因为在引用点,编译器能识别出是函数还是变量。因此函数 ambiguous_decl 首先滤掉不期望的结果。上面用到的宏的定义如下。

 

3366 #define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES)

3369 #define LOOKUP_NAMESPACES_ONLY(F)  /                                        in cp-tree.h

3370    (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))

3371 #define LOOKUP_TYPES_ONLY(F)  /

3372    (!((F) & LOOKUP_PREFER_NAMESPACES) && ((F) & LOOKUP_PREFER_TYPES))

3373 #define LOOKUP_QUALIFIERS_ONLY(F)     ((F) & LOOKUP_PREFER_BOTH)

 

ambiguous_decl (continue)

 

3509    if (!old->value)

3510      old->value = val;

3511    else if (val && val != old->value)

3512    {

3513      if (is_overloaded_fn (old->value) && is_overloaded_fn (val))

3514        old->value = merge_functions (old->value, val);

3515      else

3516      {

3517        /* Some declarations are functions, some are not.  */

3518        if (flags & LOOKUP_COMPLAIN)

3519        {

3520          /* If we've already given this error for this lookup,

3521             old->value is error_mark_node, so let's not

3522             repeat ourselves.  */

3523          if (old->value != error_mark_node)

3524          {

3525            error ("use of `%D' is ambiguous", name);

3526            cp_error_at ("  first declared as `%#D' here",

3527                      old->value);

3528          }

3529          cp_error_at ("  also declared as `%#D' here", val);

3530        }

3531        old->value = error_mark_node;

3532      }

3533    }

3534     /* ... and copy the type.  */

3535    type = new->type;

3536    if (LOOKUP_NAMESPACES_ONLY (flags))

3537      type = NULL_TREE;

3538    if (!old->type)

3539      old->type = type;

3540    else if (type && old->type != type)

3541    {

3542      if (flags & LOOKUP_COMPLAIN)

3543      {

3544        error ("`%D' denotes an ambiguous type",name);

3545        error ("%J  first type here", TYPE_MAIN_DECL (old->type));

3546        error ("%J  other type here", TYPE_MAIN_DECL (type));

3547      }

3548    }

3549    return old;

3550 }

 

在指定名字空间中一个以上同类同名的声明意味着二义性,即编译器无从选择。除非有其他信息能帮助编译器进行抉择。典型的例子有函数重载,及模板的具现,引用时的函数实参列表及模板实参列表,使得编译器可以从一组候选者中挑出最合适的一个(如果没有最合适者,但有候选者,即引发二义性错误)。对于可以重载的声明,必须把所有的这些声明记录起来。

 

852  int

853  is_overloaded_fn (tree x)                                                                                   in tree.c

854  {

855    /* A baselink is also considered an overloaded function.  */

856    if (TREE_CODE (x) == OFFSET_REF)

857      x = TREE_OPERAND (x, 1);

858    if (BASELINK_P (x))

859      x = BASELINK_FUNCTIONS (x);

860    return (TREE_CODE (x) == FUNCTION_DECL

861           || TREE_CODE (x) == TEMPLATE_ID_EXPR

862           || DECL_FUNCTION_TEMPLATE_P (x)

863           || TREE_CODE (x) == OVERLOAD);

864  }

 

那么函数 merge_functions 检查声明是否重复,并把非重复的声明加入重载记录。

 

3437 static tree

3438 merge_functions (tree s1, tree s2)                                                  in name-lookup.c

3439 {

3440    for (; s2; s2 = OVL_NEXT (s2))

3441    {

3442      tree fn2 = OVL_CURRENT (s2);

3443      tree fns1;

3444

3445      for (fns1 = s1; fns1; fns1 = OVL_NEXT (fns1))

3446      {

3447        tree fn1 = OVL_CURRENT (fns1);

3448

3449        /* If the function from S2 is already in S1, there is no

3450          need to add it again. For `extern "C"' functions, we

3451          might have two FUNCTION_DECLs for the same function, in

3452          different namespaces; again, we only need one of them.  */

3453        if (fn1 == fn2

3454           || (DECL_EXTERN_C_P (fn1) && DECL_EXTERN_C_P (fn2)

3455             && DECL_NAME (fn1) == DECL_NAME (fn2)))

3456          break ;

3457      }

3458       

3459      /* If we exhausted all of the functions in S1, FN2 is new.  */

3460      if (!fns1)

3461        s1 = build_overload (fn2, s1);

3462    }

3463    return s1;

3464 }

 

上面,注意对于普通的函数( FUNCTION_DECL 节点), OVL_CURRENT 返回节点本身,而 OVL_NEXT 返回 NULL 。因此看到如果 s2 FUNCTION_DECL 并且尚未记录在 s1 中,那么在 3461 行, fn2 s2

 

916  tree

917  build_overload (tree decl, tree chain)                                                                  in tree.c

918  {

919    if (! chain && TREE_CODE (decl) != TEMPLATE_DECL)

920       return decl;

921    if (chain && TREE_CODE (chain) != OVERLOAD)

922      chain = ovl_cons (chain, NULL_TREE);

923    return ovl_cons (decl, chain);

924  }

 

在上面的函数中,看到如果 chain NULL 而且 decl TEMPLATE_DECL ,将执行 923 行的代码,为一个新链表构建头节点。重载对象将被 tree_overload 类型的链表所记录。

 

306  struct tree_overload GTY(())                                                                in cp-tree.h

307  {

308    struct tree_common common;

309    tree function;

310  };

 

而函数 ovl_cons 构建这些节点并依序串接它们。

 

902  tree

903  ovl_cons (tree decl, tree chain)                                                                           in tree.c

904  {

905    tree result = make_node (OVERLOAD);

906    TREE_TYPE (result) = unknown_type_node;

907    OVL_FUNCTION (result) = decl;

908    TREE_CHAIN (result) = chain;

909   

910    return result;

911  }

 

qualified_lookup_using_namespace 中,注意在“ using namespace xxx ”语句所指定的名字空间中的声明不在二义性检查之列,除非是“ using namespace xxx __attribute ((strong)) ”所引入的名字空间关联( namespace association )。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值