Topic: qualified name lookup discussion / Core WG


Author: Alexander Krotov <ank@nixu.fi>
Date: Mon, 7 May 2001 09:35:19 GMT
Raw View
Following up the discussion about qualified name lookup
during core WG session. As far as i understand there
was no consensus about lookup rules and ambiguities
resolution in the case of using using-declaration.

I had been doing some digging into this topic
for my phd thesis and compiler implementation.
How i did this: lookup algorithm consists of
several steps:

1. Looking up for given name in class scopes using
inheritance graph. This part is just a simple
recursive graph traversal algorithm. Once the name is
found in certain class it does not traverse any
base classes (but the base classes might be visited
from another derived class). Elaborated specifiers
and name position in nested-name specifier are taken
into account at this stage (elaborated specifiers are
taken into account for the last name in qualified-id,
for all the other names we are looking for [nested]
class names). During this step, names introduced by
using-declarations are considered as first-class names,
if the set of entities using-decl refers to contains entity
matching searching criteria (matches elaborated name
specifier). using-decl might refer to a name defined in
base class.
As the result of this step we have set D of pairs:
(class, named entity or using-decl).

2. Clean up the set D removing all the "dominated"
names. "Dominate" relationship is defined as in
10.2P2 "hides" but defined on classes. The reasons
why this step is separated from the step 1 are:
a. simplicity of both steps
b. we do not construct subobject graphs for classes
   (because subobjects graphs are class-specific,
   when inheritance graph is shared). It is rather
   easy to emulate subobjects graph traversal using
   inheritance graph.
c. domination relationship is defined in terms
   of classes and subobjects, and it does not
   depend on names or members. This gives a way
   to efficient implementation.
As the result of this step we have a subset D'
of D.

3. For each entity in D' we follow using-decls
chains to find what this name refers to. It maps
each element of D' to set of named entities
(at this point we are taking into account
elaborated specifiers again). According to the rules
specified in 10.2 all the sets must contain members
of the same class type.
Then we take union off all the sets, as the result
we have set C.
Lookup is unambiguous iff C contains only one
element, or it contains only functions, set of
functions (taking into account special rules for
hidden parameter and using-decls) is processed by
best-matching algorithm.
Subobjects ambiguity for non-static members is
checked separately.

As far as I see the questions which rase up during
the discussion were:
1. Should D' be single-element set for
unambiguous lookkup ? According to examples
given in 10.2P3 it is not required.
2. If not, how should we unite sets for each element
of D' ? as far as i see there are several options:
a. union of all the sets (we have implemented this)
b. find maximum of all the sets (was mentioned during
   the discussion).
c. find minimum of all the sets
d. intersection of all the sets
e. according to the rules in 10.2P2 there is no question
   because all the entities should be defined in the same
   class. As far as i can see after running some tests
   EDG follows this rule.

This way does not implement rules from 10.2P2 exactly
because suobject ambiguity (in the case of presence
of nonstatic member) is checked after best-matching
selection, but according to the rules in that paragraph
it must be checked before.
The second example attached shows the difference, EDG
compiles it according to the standard.

Is there any rationale why all the entities found must
be defined in the same class type ? This rule restricts
freedom of functions overloading.

Following example 1 illustrates g++ 2.95.2/2.96.2.97
lookups related bug. EDG compiles it correctly.
----- ex1.c -----
struct A {
 static void f(char);
};

struct B: A {
 // static void f(int);
 using A::f;
};

struct B1: B {
 using B::f;
};

struct C: A {
 // static void f(short);
 using A::f;
};

struct C1: C {
 using C::f;
};

struct D: B1, C1 {
};

void f ()
{
 D *p;
 p->f('a');
}
----- ex2.c -----
struct A {
 void f(int);
 static void f(char);
};

struct B: A {};
struct C: A {};
struct D: B,C {};

void f ()
{
 D *p;
 p->f('c');
}
-----

--
Alexander Krotov gsm: +358 40-725 7216
Product Developer fax: +358  9-478 1030
NIXU Ltd.  http://www.nixu.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]