Dependent qualified name lookup in C++14 - c++

This is about dependent name lookup in a template function, for example:
template<class T>
void foo(T const &t)
{
::func(t);
}
In this code, func is a dependent name because it has a type-dependent expression as argument to a function call. In C++11 the lookup for func was covered by [temp.dep.candidate]/1:
For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:
For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
[Note: 3.4.1 is "ordinary" unqualified-id lookup, and 3.4.2 is unqualified-id lookup for function names, aka. ADL, and 3.4.3 is qualified-id lookup].
However in C++14 (N3936) the parts about qualified-id lookup were removed:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
Assuming that this change was done on purpose; which clauses now cover the finding of candidate functions for a function call where the postfix-expression is a dependent name and a qualified-id ?
(Background: I am looking for confirmation that qualified name lookup still only looks in the template definition context, not the instantiation context).

Defect report 1321 has been accepted into the latest C++14 draft (N4140). This defect report clarifies the equivalency of dependent names, and at the same time clarifies that a dependent name must be an unqualified-id. Formerly, in C++11, dependent names could be arbitrary id-expressions.
This means that qualified-id names are no longer dependent names, and are therefore looked up according to §14.6.3 [temp.nondep]. This doesn't actually affect program behaviour from C++11, since dependent names only affect whether ADL (§3.4.2) is performed with the template instantiation context, and only unqualified-ids are eligible for ADL anyway.

Related

where's the relevant rule for phase two name lookup of template instantiation in the current standard

template<typename T>
void fun(T t){
foo(t); //#1 foo is a dependent name
}
void foo(int){
}
int main(){
fun(0); // #2 ill-formed
}
Since the unqualified-id foo is a dependent name as per temp.dep#2, So, the lookup name rule for this name should obey the following rule, which is mentioned in the note of [temp.dep#2]
[ Note: Such names are unbound and are looked up at the point of the template instantiation ([temp.point]) in both the context of the template definition and the context of the point of instantiation ([temp.dep.candidate]). — end note ]
The lookup rule for a dependent name is clearly written in c++17 standard, that is:
temp.dep.res#1
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
And temp.dep.candidate#1
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup, only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either the template definition context or the template instantiation context are found.
In other words, these rules mean that only ADL is used to perform in phase two lookup.
However, I cannot find the relevant rule in the current standard(i.e, c++20). [temp.dep.res#1] has been removed from the current standard. [temp.dep.candidate#1] has been modified as:
temp.dep.candidate#1
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules from the template definition context ([basic.lookup.unqual], [basic.lookup.argdep]). [ Note: For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep]. — end note ] If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.
It's just to be a note in the current standard. It appears to me that the current standard does not clearly describe how the lookup rule performs for an unqualified dependent name in a function call. In the current standard, where's the relevant rule states that only ADL will perform in the second phase? It's unclear. If the usual unqualified look rule will be performed in the second phase, #2 would be well-formed due to void foo(int) can be found in the instantiation context by unqualified lookup. If I miss anything, where's the relevant rule?
In other words, these rules mean that only ADL is used to perform in phase two lookup.
This is the wrong conclusion to draw from the given specification quotes. You seem to be confusing two different concepts.
The first concept is what is commonly called "two-phase lookup": the fact that when a template gets parsed, names which are dependent on template parameters cannot be looked up at parse time. They can only be lookup up at instantiation time. There are two phases of lookup: one for non-dependent names, and one for dependent names.
The second concept is just name lookup, which has two scopes of names to search: regular unqualified lookup (defined in [basic.lookup.unqual]) and argument-dependent lookup (defined in [basic.lookup.argdep]). Unqualified lookup searches in the scope of the code itself, while ADL searches in the scope of the namespace of a function's arguments.
Both phases of template name lookup use both of these scopes. To be clear, dependent name lookup also does unqualified lookup. This is why one of the bullet points you quoted said "for the part of the lookup using unqualified name lookup... ". If dependent name lookup didn't use the rules for unqualified name lookup, it wouldn't have mentioned them.
Now, dependent name lookup does restrict what the candidate names are compared to the regular rules. But it doesn't restrict it to just ADL; it does both scopes of lookup.
These restrictions used to be specified in [temp.dep.candidate]/1, as you pointed out. But they got moved around a bit.
For the unqualified lookup part, the new [temp.dep.candidate]/1 covers that as you quoted it, because it says "usual lookup rules from the template definition context". This specifies the context of the unqualified lookup as being the template's definition only.
Note that the second bullet point also says to look in that scope, so it covers part of that.
The rest of the second bullet point is covered by [basic.lookup.argdep]/4.5:
If the lookup is for a dependent name ([temp.dep], [temp.dep.candidate]), any declaration D in N is visible if D would be visible to qualified name lookup ([namespace.qual]) at any point in the instantiation context ([module.context]) of the lookup, unless D is declared in another translation unit, attached to the global module, and is either discarded ([module.global.frag]) or has internal linkage.
This expands the lookup to include the "instantiation context", which largely matches the C++17 text (though with module-based modifications).

What is the definition of "dependent name" in C++?

In C++, the concept of dependent names is important because:
Such names are unbound and are looked up at the point of the template instantiation ... in both the context of the template definition and the context of the point of instantiation
However, the only thing that the standard says is a dependent name is given in [temp.dep]/2, referring to unqualified function calls, basically in order to enable ADL to be fully effective for those function calls.
Are there any other dependent names besides those?
Consider some code like this, for example:
template <class T>
void foo(T t) {
t.bar();
};
If one were to refer to bar as a "dependent name", would that be a technically incorrect use of the term, according to the standard?
Thanks to Declarations and where to find them being accepted into C++23, there is now an explicit enumeration of categories of dependent names, which seems to cover the code in the question.
In N4919 [temp.dep.general]/2 it is stated that
[...] The component name of an unqualified-id (7.5.4.2) is dependent if
it is a conversion-function-id whose conversion-type-id is dependent, or
it is operator= and the current class is a templated entity, or
the unqualified-id is the postfix-expression in a dependent call.
And in [temp.dep.type]/5 the rules for when qualified names are dependent are given:
A qualified name (6.5.5) is dependent if
it is a conversion-function-id whose conversion-type-id is dependent, or
its lookup context is dependent and is not the current instantiation, or
its lookup context is the current instantiation and it is operator=, or
its lookup context is the current instantiation and has at least one dependent base class, and qualified name lookup for the name finds nothing (6.5.5).
Regarding the example of t.bar() given in the question, the name bar is described in the referenced section (6.5.5) ([basic.lookup.qual]) as a "member-qualified-name". Furthermore, [basic.lookup.qual]/2 explains that its "lookup context" is "the type of its associated object expression (considered dependent if the object expression is type-dependent)". Clearly t is type-dependent, and it is the lookup context for bar, so [temp.dep.type]/5.2 applies, and bar is indeed a dependent qualified name.

Should this function call be ambiguous?

I stumbled on this the other day and can't figure out which answer is correct, or whether both are acceptable.
Specifically, I'm referring to the call to bar(T{}) in OtherFunction. From what I've been able to test on compiler explorer, the decision seems split. msvc and icc agree that it is ambiguous while gcc and clang compile the code without issue.
The function bar inside the namespace hidden becomes visible through argument-dependent lookup. Additionally, msvc/icc consider the declaration of bar in the global namespace as a candidate while gcc/clang do not. It seems that the declaration in the global namespace should not be considered since it is declared after the call to bar(T{}) but I'm not sure whether I'm reading the rules for unqualified name lookup correctly or if the standard is ambiguous in this regard.
https://godbolt.org/z/HAS-Cv
EDIT:
Looks like msvc has fixed this as long as /permissive- option is used
(https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/)
template <typename T>
inline void OtherFunction () {
bar(T{});
}
namespace hidden {
struct Foo {};
inline void bar (Foo foo) {}
}
inline void bar (hidden::Foo foo) {}
void Function () {
OtherFunction<hidden::Foo>();
}
Gcc and Clang are correct. The global bar defined after the definition of OtherFunction can't be found by name lookup; while hidden::bar could be found by ADL.
(emphasis mine)
For a dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11) that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).
The code is valid, so msvc and icc are incorrect.
Since an argument of bar is type-dependent, the name bar is a dependent name, and is looked up only when the template OtherFunction is instantiated, not when the template is defined.
C++17 [temp.dep.candidate]/1:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup ([basic.lookup.unqual]), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations from either the template definition context or the template instantiation context are found.
So jumping to [basic.lookup.argdep]/3:
Let X be the lookup set produced by unqualified lookup ([basic.lookup.unqual]) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
a declaration of a class member, or
a block-scope function declaration that is not a using-declaration, or
a declaration that is neither a function nor a function template
then Y is empty. Otherwise Y is the set of declarations found in the namespaces associated with the argument types as described below. The set of declarations found by the lookup of the name is the union of X and Y.
[The current C++20 draft has rearranged wordings in these sections. In particular, the rule about including the instantiation context for lookup of a dependent name in associated namespaces is now listed in [basic.lookup.argdep]/4.5, and is just a Note in [temp.dep.candidate]. I'm not sure if the reason for this is just for clarity, or might have something to do with effects of modules.]
X is the result of unqualified lookup for the name bar considering only declarations visible from the template definition context. But since the template definition context is the very beginning of your translation unit, obviously X is empty.
Since X doesn't contain anything at all, it doesn't contain the listed items which would force Y to be empty. So to determine Y, we look in the namespaces associated with the argument types. The argument type in this instantiation is hidden::Foo, so the only associated namespace is hidden, and the single result of name lookup is function hidden::bar.
::bar is not visible in this name lookup, so the bar(T{}) expression cannot be ambiguous.

C++ lookup for dependent names

In the current C++ standard (march 2019), there are these two paragraphs (emphasis mine):
[temp.res] p.2:
A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename. [...]
[temp.res] p.9:
When looking for the declaration of a name used in a template definition, the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known ([temp.dep]). [...]
The first paragraph implies that a name that is dependent on a template parameter will be looked up by "the applicable name lookup".
However, the second paragraph states that lookup for names dependent on template parameters is postponed until the template argument is known.
The example that is part of the first paragraph includes a situation similar to the following one:
template <typename T>
class A
{
void f()
{
T* p;
}
};
In method f, I believe T is a "name dependent on template parameters", therefore its lookup should be postponed until T is known, therefore there is no "applicable name lookup", the name should be assumed not to name a type.
What does the first quoted paragraph mean by "unless the applicable name lookup finds a type name", if the second quoted paragraph seems to state that there is no lookup performed? Am I missing something?
Thank you.
The lookup that is postponed is for dependent names: for example, foo in contexts like T::foo or Bar<T>::foo, or operator# in contexts like T() # 0. Obviously T and Bar must themselves be looked up just to know a template parameter is involved (template parameters can be hidden) and to parse the template argument list. Since a (type) template parameter is a typedef-name and any specialization of Bar is a type, that “name lookup finds a type name”.

Overload resolution of a qualified name

Consider this function call:
foo::bar();
11.3.1.1.1, paragraph 3 [over.call.func] (N4778) covers this case:
In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls...
Here, foo::bar is an unqualified name, in the sense that it's not qualified by -> or .. So this paragraph applies. Now, the meaning of the phrase "looked up in the context of" is explained in 6.4, paragraph 2 [basic.lookup]:
A name “looked up in the context of an expression” is looked up as an unqualified name in the scope where the expression is found.
However, foo::bar is a qualified name in the realm of name lookup. In other words, this combination of paragraphs basically say that, the qualified name foo::bar is looked up by the rule of unqualified name lookup. However, I don't think that unqualified name lookup is capable of recursively entering into a narrower scope, i.e., foo to bar. Is this a defect?
No, I don't think this is a defect. It says
The name is looked up in the context of the function call following the normal rules for name lookup in function calls [...]
As you can see from the part that I highlighted, the standard specifies how the name is supposed to be looked up: By name lookup.
Name lookup involves unqualified, qualified and argument-dependent lookup, so your name is indeed resolved by the qualified name lookup rules.
The "looked up in the context of expr" rule doesn't apply here, as it is specified what rule is used. That paragraph only comes into play when it's not. For example, in [class.qual]p1:
the names in a template-argument of a template-id are looked up in the context in which the entire postfix-expression occurs.