C++11: ill-formed calls are undefined behavior? - c++

§ 14.6.4.2 from N3485 states the following about dependent candidate function lookup:
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.
What exactly does it mean for a call to be "ill-formed", and how would an ill-formed call be selected by the lookup? Also, why does it matter that a better match would be found if all translation units were considered?

What exactly does it mean for a call to be "ill-formed"
Formally, ill-formed is defined by [defns.ill.formed] as not well-formed, and a well-formed program is defined by [defns.well.formed] as:
C++ program constructed according to the syntax rules, diagnosable semantic rules, and the One Definition Rule (3.2).
So an ill-formed call is one with invalid syntax or a diagnosable error such as passing the wrong number of arguments, or arguments which cannot be converted to the parameter types, or an overload ambiguity.
how would an ill-formed call be selected by the lookup?
I think it's saying "if (the call would be ill-formed || would find a better match) had the lookup within the associated namespaces considered all the function declarations with external linkage ...", which means you have undefined behaviour if considering other functions would have found equal or better matches. Equally good matches would make the call ambiguous, i.e. ill-formed, and better matches would have resulted in a different function being called.
So if in another context the call would have been ambiguous or caused another sort of error, but succeeds due to only considering a limited set of names in the instantiation and definition contexts, it's undefined. And if in another context the call would have chosen a better match, that's also undefined.
Also, why does it matter that a better match would be found if all translation units were considered?
I think the reason for the rule is to disallow situations where instantiating the same template specialization in two different contexts results in it calling two different functions, e.g. if in one translation unit the call finds one function, and in another translation unit it finds a different function, you'll get two different instantiations of the same template, which violates the ODR, and only one instantiation will be kept by the linker, so the instantiation that's not kept by the linker will get replaced by one which calls a function that wasn't even visible where the template was instantiated.
That's similar (if not already covered by) the last sentence of the previous paragraph:
A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required.
Page 426 of the C++ ARM (Ellis & Stroustrup) gives a bit of context for that text (and I believe for 14.6.4.2 as well) and explains it more concisely and clearly than I did above:
This would seem to imply that a global name used from within a template could be bound to different objects or functions in different compilation units or even at different points within a compilation unit. However, should that happen, the resulting template function or class is rendered illegal by the "one-definition" rule (§7.1.2).
There's another related formulation of the same rules in [basic.def.odr]/6

The problem is that namespaces can be defined piecemeal, so there is no one place that is guaranteed to define all of the members of a namespace. As a result, different translation units can see different sets of namespace members. What this section says is that if the part that isn't seen would affect lookup, the behavior is undefined. For example:
namespace mine {
void f(double);
}
mine::f(2); // seems okay...
namespace mine {
void f(char);
}
mine::f(2); // ambiguous, therefore ill-formed
The rule says that the first call to f(2) produces undefined behavior because it would have been ill-formed if all of the overloads in mine had been visible at that point.

Building on #tletnes' partial answer, I think I've come up with a simple program that triggers this particular undefined behavior. Of course it uses multiple translation units.
cat >alpha.cc <<EOF
#include <stdio.h>
void customization_point(int,int) { puts("(int,int)"); }
#include "beta.h"
extern void gamma();
int main() {
beta(42);
gamma();
}
EOF
cat >gamma.cc <<EOF
#include <stdio.h>
void customization_point(int,double) { puts("(int,double)"); }
#include "beta.h"
void gamma() { beta(42); }
EOF
cat >beta.h <<EOF
template<typename T>
void beta(T t) {
customization_point(t, 3.14);
}
EOF
Compiling this program with different optimization levels changes its behavior. This is all right, according to the Standard, because the call in "alpha.cc" invokes undefined behavior.
$ clang++ alpha.cc gamma.cc -O1 -w ; ./a.out
(int,int)
(int,int)
$ clang++ alpha.cc gamma.cc -O2 -w ; ./a.out
(int,int)
(int,double)

When I read this rule I imagine the code similar to the following is at least part of what was being considered:
int foo(int a; int b){ printf("A"); }
int main(){
foo(1, 1.0);
}
int foo(int a, double b){ printf("B"); }
or
int foo(int a);
int main(){
foo(1);
}
int foo(int a, double b){ printf("B"); }

Related

conflicting C++ classes in different modules get mixed up without link error [duplicate]

Consider the following example:
// usedclass1.hpp
#include <iostream>
class UsedClass
{
public:
UsedClass() { }
void doit() { std::cout << "UsedClass 1 (" << this << ") doit hit" << std::endl; }
};
// usedclass2.hpp
#include <iostream>
class UsedClass
{
public:
UsedClass() { }
void doit() { std::cout << "UsedClass 2 (" << this << ") doit hit" << std::endl; }
};
// object.hpp
class Object
{
public:
Object();
};
// object.cpp
#include "object.hpp"
#include "usedclass2.hpp"
Object::Object()
{
UsedClass b;
b.doit();
}
// main.cpp
#include "usedclass1.hpp"
#include "object.hpp"
int main()
{
Object obj;
UsedClass a;
a.doit();
}
The code compiles without any compiler or linker errors. But the output is strange for me:
gcc (Red Hat 4.6.1-9) on Fedora x86_64 with no optimization [EG1]:
UsedClass 1 (0x7fff0be4a6ff) doit hit
UsedClass 1 (0x7fff0be4a72e) doit hit
same as [EG1] but with -O2 option enabled [EG2]:
UsedClass 2 (0x7fffcef79fcf) doit hit
UsedClass 1 (0x7fffcef79fff) doit hit
msvc2005 (14.00.50727.762) on Windows XP 32bit with no optimization [EG3]:
UsedClass 1 (0012FF5B) doit hit
UsedClass 1 (0012FF67) doit hit
same as [EG3] but with /O2 (or /Ox) enabled [EG4]:
UsedClass 1 (0012FF73) doit hit
UsedClass 1 (0012FF7F) doit hit
I would expect either a linker error (assuming ODR rule is violated) or the output as in [EG2] (code is inlined, nothing is exported from the translation unit, ODR rule is held). Thus my questions:
Why are outputs [EG1], [EG3], [EG4] possible?
Why do I get different results from different compilers or even from the same compiler? That makes me think that the standard somehow doesn't specify the behaviour in this case.
Thank you for any suggestions, comments and standard interpretations.
Update
I would like to understand the compiler's behaviour. More precisely, why there are no errors generated if the ODR is violated. A hypothesis is that since all functions in classes UsedClass1 and UsedClass2 are marked as inline (and therefore C++03 3.2 is not violated) the linker doesn't report errors, but in this case outputs [EG1], [EG3], [EG4] seem strange.
This is the rule that prohibits what you're doing (the C++11 wording), from section 3.2 of the Standard:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
each definition of D shall consist of the same sequence of tokens; and
in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D; and
in each definition of D, corresponding entities shall have the same language linkage; and
in each definition of D, the overloaded operators referred to, the implicit calls to conversion functions, constructors, operator new functions and operator delete functions, shall refer to the same function, or to a function defined within the definition of D; and
in each definition of D, a default argument used by an (implicit or explicit) function call is treated as if its token sequence were present in the definition of D; that is, the default argument is subject to the three requirements described above (and, if the default argument has sub-expressions with default arguments, this requirement applies recursively).
if D is a class with an implicitly-declared constructor (12.1), it is as if the constructor was implicitly defined in every translation unit where it is odr-used, and the implicit definition in every translation unit shall call the same constructor for a base class or a class member of D.
In your program, you're violating the ODR for class UsedClass because the tokens are different in different compilation units. You could fix that by moving the definition of UsedClass::doit() outside the class body, but the same rule applies to the body of inline functions.
Your program violates the One Definition Rule and invokes an Undefined Behavior.
The standard does not mandate an diagnostic message if you break the ODR but the behavior is Undefined.
C++03 3.2 One definition rule
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.
...
Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is used.
Further the standard defines specific requirements for existence of multiple definitions of an symbol, those are aptly defined in Para #5 of 3.2.
There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
— each definition of D shall consist of the same sequence of tokens; and
...
Why are outputs [EG1], [EG3], [EG4] possible?
The simple answer is that the behaviour is undefined, so anything is possible.
Most compilers handle an inline function by generating a copy in each translation unit in which it's defined; the linker then arbitrarily chooses one to include in the final program. This is why, with optimisations disabled, it calls the same function in both cases. With optimisations enabled, the function might be inlined by the compiler, in which case each inlined call will use the version defined in the current translation unit.
That makes me think that the standard somehow doesn't specify the behaviour in this case.
That's correct. Breaking the one definition rule gives undefined behaviour, and no diagnostic is required.

Moving the function templates definition to different translation unit resolves the ambiguity error

I was using function templates when I noticed that moving the definition of one of the function template to a different translation unit resolves the ambiguous error. Below are the two examples that I tried. The first example produces ambiguous error as expected but when I move the definition of one of the function template into another translation unit then the error is gone.
Example 1
#include <iostream>
template<typename X, typename Y>
void func(X, Y)
{
std::cout<<"X-Y in order version called"<<std::endl;
}
template<typename X, typename Y>
//--------v--v----->order changed
void func(Y, X)
{
std::cout<<"Y-X in order version called"<<std::endl;
}
int main()
{
func(2,2); //this is ambiguous as expected
}
Demo showing that we get ambiguous error as expected.
My question is about the second example given below:
Example 2
main.cpp
#include <iostream>
template<typename X, typename Y>
void func(X, Y)
{
std::cout<<"X-Y in order version called"<<std::endl;
}
extern void init();
int main()
{
func(2,2); //WORKS BUT HOW? How does the compiler resolves the ambiguity here
init();
}
source2.cpp
#include <iostream>
//moved to source2.cpp
template<typename X, typename Y>
//--------v--v----->order changed
void func(Y, X)
{
std::cout<<"Y-X in order version called"<<std::endl;
}
void init()
{
func(2,2);
}
The second version given above successfully compiles and produces the output:
X-Y in order version called
Y-X in order version called
My questions are:
How is the ambiguity resolved when i moved the definition of the second overload to a different translation unit? I mean we still have two intantiations(one from the overload in the main.cpp and other from the overload in source2.cpp) as before but now we're not getting the ambiguity error. So how does the C++ standard resolves this ambiguity.
How does the C++ standard allows the first overload to be selected/preferred instead of the second. I mean is there a reference in the standard that says that the instantiation from the overload in the same translation unit should be selected.
Summary
Note that my second question is about why the first version is preferred over the one in the other translation unit. While my first question is about how is the ambiguity removed when moving the definition to another translation unit.
How is the ambiguity resolved when i moved the definition of the second overload to a different translation unit?
You moved not only the definition, but also the only declaration of the second overload into the second translation unit. Each translation unit is now aware of only one of the overloads.
Overload resolution considers only the declarations which can be found by name lookup from the context of the function call as candidates. So in the first translation unit only the first overload will be found as candidate and in the second translation unit only the second overload can be found.
The overload resolution will therefore have only ever one viable candidate to choose from. There is no possibility for ambiguity.
It is not a problem that overload resolution depends on which declarations have been introduced. This would be an issue only if it violated ODR, e.g. because definitions for the same inline function make a call that results in different overload resolution results in two translation units.
I mean we still have two intantiations(one from the overload in the main.cpp and other from the overload in source2.cpp) as before but now we're not getting the ambiguity error.
There are two instantiations, but these are instantiations of different function templates and therefore different functions. There is no reason for this to be an issue. Which of the template specializations is called for which function call has already been decided by overload resolution. There is no chance of confusing them.
In the second example, it's not ambiguous because the compiler doesn't see the second translation unit and therefore just compiles a call to void func<int,int>(int,int) after implicitly instantiating the function. As, in the second translation unit you're also instantiating void func<int,int>(int,int) but with a different definition, it's IFNDR (Ill-Formed No Diagnostic Required). The linker might choose any definition and therefore your program will have undefined behavior.
how does the C++ standard resolves this ambiguity.
From temp.over.link#1:
1. It is possible to overload function templates so that two different function template specializations have the same type.
2. Such specializations are distinct functions and do not violate the one-definition rule.
(emphasis mine)
Now, in the given example both the specializations resulting from the two overloads will have the same type void (int, int) and as quoted in the points above, this usage is allowed.
How does the C++ standard allows the first overload to be selected/preferred instead of the second.
To answer the second question, during overload resolution the call func(2,2) inside function init in source2.cpp was already bound to the instantiated version from the second overload. Similarly, for the call expression func(2,2) inside main.cpp, it is bound to the instantiated version from the first overload.
Thus, when init is called from inside main.cpp, the second version is called. If we changed the order of the calls inside main.cpp, then the output will be reversed because the call was already bound to their respective version during overload resolution.

Possible ODR-violations when using a constexpr variable in the definition of an inline function (in C++14)

(Note! This question particularly covers the state of C++14, before the introduction of inline variables in C++17)
TLDR; Question
What constitutes odr-use of a constexpr variable used in the definition of an inline function, such that multiple definitions of the function violates [basic.def.odr]/6?
(... likely [basic.def.odr]/3; but could this silently introduce UB in a program as soon as, say, the address of such a constexpr variable is taken in the context of the inline function's definition?)
TLDR example: does a program where doMath() defined as follows:
// some_math.h
#pragma once
// Forced by some guideline abhorring literals.
constexpr int kTwo{2};
inline int doMath(int arg) { return std::max(arg, kTwo); }
// std::max(const int&, const int&)
have undefined behaviour as soon as doMath() is defined in two different translation units (say by inclusion of some_math.h and subsequent use of doMath())?
Background
Consider the following example:
// constants.h
#pragma once
constexpr int kFoo{42};
// foo.h
#pragma once
#include "constants.h"
inline int foo(int arg) { return arg * kFoo; } // #1: kFoo not odr-used
// a.cpp
#include "foo.h"
int a() { return foo(1); } // foo odr-used
// b.cpp
#include "foo.h"
int b() { return foo(2); } // foo odr-used
compiled for C++14, particularly before inline variables and thus before constexpr variables were implicitly inline.
The inline function foo (which has external linkage) is odr-used in both translation units (TU) associated with a.cpp and b.cpp, say TU_a and TU_b, and shall thus be defined in both of these TU's ([basic.def.odr]/4).
[basic.def.odr]/6 covers the requirements for when such multiple definitions (different TU's) may appear, and particularly /6.1 and /6.2 is relevant in this context [emphasis mine]:
There can be more than one definition of a [...] inline function with external linkage [...] in a program
provided that each definition appears in a different translation unit,
and provided the definitions satisfy the following requirements. Given
such an entity named D defined in more than one translation unit, then
/6.1 each definition of D shall consist of the same sequence of tokens; and
/6.2 in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within
the definition of D, or shall refer to the same entity, after overload
resolution ([over.match]) and after matching of partial template
specialization ([temp.over]), except that a name can refer to a
non-volatile const object with internal or no linkage if the object
has the same literal type in all definitions of D, and the object is
initialized with a constant expression ([expr.const]), and the object
is not odr-used, and the object has the same value in all definitions
of D; and
...
If the definitions of D do not satisfy these requirements, then the behavior is undefined.
/6.1 is fulfilled.
/6.2 if fulfilled if kFoo in foo:
[OK] is const with internal linkage
[OK] is initialized with a constant expressions
[OK] is of same literal type over all definitions of foo
[OK] has the same value in all definitions of foo
[??] is not odr-used.
I interpret 5 as particularly "not odr-used in the definition of foo"; this could arguably have been clearer in the wording. However if kFoo is odr-used (at least in the definition of foo) I interpret it as opening up for odr-violations and subsequent undefined behavior, due to violation of [basic.def.odr]/6.
Afaict [basic.def.odr]/3 governs whether kFoo is odr-used or not,
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion ([conv.lval]) to x yields a constant expression ([expr.const]) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion ([conv.lval]) is applied to e, or e is a discarded-value expression (Clause [expr]). [...]
but I'm having a hard time to understand whether kFoo is considered as odr-used e.g. if its address is taken within the definition of foo, or e.g. whether if its address is taken outside of the definition of foo or not affects whether [basic.def.odr]/6.2 is fulfilled or not.
Further details
Particularly, consider if foo is defined as:
// #2
inline int foo(int arg) {
std::cout << "&kFoo in foo() = " << &kFoo << "\n";
return arg * kFoo;
}
and a() and b() are defined as:
int a() {
std::cout << "TU_a, &kFoo = " << &kFoo << "\n";
return foo(1);
}
int b() {
std::cout << "TU_b, &kFoo = " << &kFoo << "\n";
return foo(2);
}
then running a program which calls a() and b() in sequence produces:
TU_a, &kFoo = 0x401db8
&kFoo in foo() = 0x401db8 // <-- foo() in TU_a:
// &kFoo from TU_a
TU_b, &kFoo = 0x401dbc
&kFoo in foo() = 0x401db8 // <-- foo() in TU_b:
// !!! &kFoo from TU_a
namely the address of the TU-local kFoo when accessed from the different a() and b() functions, but pointing to the same kFoo address when accessed from foo().
DEMO.
Does this program (with foo and a/b defined as per this section) have undefined behaviour?
A real life example would be where these constexpr variables represent mathematical constants, and where they are used, from within the definition of an inline function, as arguments to utility math functions such as std::max(), which takes its arguments by reference.
In the OP's example with std::max, an ODR violation does indeed occur, and the program is ill-formed NDR. To avoid this issue, you might consider one of the following fixes:
give the doMath function internal linkage, or
move the declaration of kTwo inside doMath
A variable that is used by an expression is considered to be odr-used unless there is a certain kind of simple proof that the reference to the variable can be replaced by the compile-time constant value of the variable without changing the result of the expression. If such a simple proof exists, then the standard requires the compiler perform such a replacement; consequently the variable is not odr-used (in particular, it does not require a definition, and the issue described by the OP would be avoided because none of the translation units in which doMath is defined would actually reference a definition of kTwo). If the expression is too complicated, however, then all bets are off. The compiler might still replace the variable with its value, in which case the program may work as you expect; or the program may exhibit bugs or crash. That's the reality with IFNDR programs.
The case where the variable is immediately passed by reference to a function, with the reference binding directly, is one common case where the variable is used in a way that is too complicated and the compiler is not required to determine whether or not it may be replaced by its compile-time constant value. This is because doing so would necessarily require inspecting the definition of the function (such as std::max<int> in this example).
You can "help" the compiler by writing int(kTwo) and using that as the argument to std::max as opposed to kTwo itself; this prevents an odr-use since the lvalue-to-rvalue conversion is now immediately applied prior to calling the function. I don't think this is a great solution (I recommend one of the two solutions that I previously mentioned) but it has its uses (GoogleTest uses this in order to avoid introducing odr-uses in statements like EXPECT_EQ(2, kTwo)).
If you want to know more about how to understand the precise definition of odr-use, involving "potential results of an expression e...", that would be best addressed with a separate question.
Does a program where doMath() defined as follows: [...] have undefined behaviour as soon as doMath() is defined in two different translation units (say by inclusion of some_math.h and subsequent use of doMath())?
Yes; this particular issue was highlighted in LWG2888 and LWG2889 which were both resolved for C++17 by P0607R0 (Inline Variables for the Standard Library) [emphasis mine]:
2888. Variables of library tag types need to be inline variables
[...]
The variables of library tag types need to be inline variables.
Otherwise, using them in inline functions in multiple translation
units is an ODR violation.
Proposed change: Make piecewise_construct, allocator_arg, nullopt,
(the in_place_tags after they are made regular tags), defer_lock,
try_to_lock and adopt_lock inline.
[...]
[2017-03-12, post-Kona] Resolved by p0607r0.
2889. Mark constexpr global variables as inline
The C++ standard library provides many constexpr global variables.
These all create the risk of ODR violations for innocent user code.
This is especially bad for the new ExecutionPolicy algorithms, since
their constants are always passed by reference, so any use of those
algorithms from an inline function results in an ODR violation.
This can be avoided by marking the globals as inline.
Proposed change: Add inline specifier to: bind placeholders _1, _2,
..., nullopt, piecewise_construct, allocator_arg, ignore, seq, par,
par_unseq in
[...]
[2017-03-12, post-Kona] Resolved by p0607r0.
Thus, in C++14, prior to inline variables, this risk is present both for your own global variables as well as library ones.

Point of template instantiation, dependent names and ADL

It's my understanding from post that argument dependent lookup is used when template dependent names are bound at the point of instantiation. I understand the first simple form below, however am unsure how exactly ADL and binding works on the second. I have a specific question regarding overriding sort().
Appreciate if anyone can guide me on how ADL and binding is occurring in the second code post. Also, if there is a way to redefine sort() to not bind to the std::sort and to bind to some other implementation.
template<typename T> T f(T a) {
// Can find ::ns::g(Q) only via ADL on T for
// an instantiation of f with T == ::ns::Q.
return g(a);
}
namespace ns {
class Q {};
Q g(Q e) { return e; }
} // namespace ns
int main() {
(void) f(::ns::Q{});
return 0;
}
Form that I need help with:
#include <iostream>
#include <vector>
template<typename T>
void print_sorted(std::vector<T>& v)
{
//typename std::vector<T>::iterator it;
sort(v.begin(),v.end()); // ADL looks at return type of begin()?
for (const auto& x : v)
std::cout << x << '\n';
}
int main(int argc, char *argv[])
{
std::vector<std::string> v = {"b", "a"};
print_sorted(v); // sort using std::sort, then print using std::cout
return 0;
}
#include <algorithm> // adl of sort() would allow std::sort to be defined here
Compilation:
clang++ -pedantic -Wall -std=c++11 test187.cc && ./a.out
a
b
I tried the OP's code on Godbolt. Just as OP claimed, it compiles under Clang (and, it seems, on GCC as well). If #include <algorithm> is commented out, both compilers claim that the name sort is unknown to them.
I believe that the reason for this behaviour is that these compilers defer the instantiation of the print_sorted function until the end of the translation unit. The license to do so is given by C++17 [temp.point]/8:
A specialization for a function template, a member function template, or of a member function or static
data member of a class template may have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any such specialization that has a point
of instantiation within the translation unit, the end of the translation unit is also considered a point of
instantiation. A specialization for a class template has at most one point of instantiation within a translation
unit. A specialization for any template may have points of instantiation in multiple translation units.
If two different points of instantiation give a template specialization different meanings according to the
one-definition rule (6.2), the program is ill-formed, no diagnostic required.
In other words, regardless of where the function template specialization is instantiated, it is also considered to be instantiated at the end of the translation unit, and all such instantiations must have the same meaning, otherwise the program is ill-formed NDR.
Thus, the compiler writers may defer function template instantiations, as much as possible, until the end of the translation unit, possibly for efficiency reasons, without being concerned that this would change the meaning of the program. If it does change the meaning of the program, it means that the programmer messed up and the compiler is not required to catch this mistake. (See also CWG 993)
The wording of [temp.point]/8 is unclear as to whether it applies to the OP's program (since here, at one point of instantiation, the specialization is actually ill-formed due to using an undeclared name, as opposed to simply having a different meaning than it does at another point of instantiation). I think this is just a defect in the wording, and GCC and Clang are following the "spirit" of the rule.

Name resolution in templates

I was reading about the template name resolution here. Just to get the feel of the things I replicated the code like this:
void f (char c)
{
std::cout<<"f(char)\n";
}
template <class T>
void g(T t)
{
f(1);
f(T(1));
f(t);
d++;
}
double d;
void f(int n)
{
std::cout<<"f(int)\n";
}
void test()
{
std::cout<<"First call\n";
g(1);
std::cout<<"Second call\n";
g('a');
}
int main()
{
test();
return 0;
}
According to the article linked I should have a compiler error for the d++ statement. Also for the first call of g(1), I should have one call of f(char) followed by two calls of f(int) and for the second call I should get three calls of f(char). However, when I compiled this using Vs2008, it compiled fine without any errors. Also, the output was:
First call
f(int)
f(int)
f(int)
Second call
f(int)
f(char)
f(char)
I am now wondering which one is correct? The article I am linking to or the VS2008 output? Any clue which is correct?
Also for the first call of g(1), I should have one call of f(char) followed by two calls of f(int) and for the second call I should get three calls of f(char).
This is not the expected result with a Standard compliant compiler. Since both time you call it with a fundamental type, you will not get name lookup at the instantiation context for the function call.
Name lookup at instantiation context only happens for argument dependent lookup (called lookup using associated namespaces). Both of int and char do not have argument dependent lookup, an thus all the function calls you do will call f(char) after you removed the d++ line.
Since i understand you won't possibly just believe me, here is the Standard quote, out of 14.6.4.2:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, 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 with external linkage from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.
Note that the article uses a defective example of the Standard (at 14.6/9) (and note that examples are non-normative: They can't change or state rules. Their purpose entirely is illustrative). The defect has been fixed and is incorporated into the upcoming Standard. See this defect report.
As you see, you will have to change from int / char to some user defined type (enums or classes) too see the effect of lookup in instantiation context. Read this answer Order affects visibility for more information.
Even though VS2008 was considered the most standard-compliant C++ compiler of it's time, here we have one instance where it's accepting invalid code. G++ doesn't compile this (d++: error: 'd' was not declared in this scope). That said, any program that relies this much on the intricacies of the C++ language is broken anyway :)
The article is correct about whether d++ should compile.
Visual C++ does not do two-phase template instantiation - it does pretty much all its parsing at instatiation time.
Gcc and Comeau will give the correct error and will call the correct f.
VS should have complained about d++ as d should be looked up at point of definition.
The article is incorrect, the calls should be resolved to f(char) as point of instantiation lookup should not be done for fundamental types (see tlib answer).
g++ behaviour depends on the version:
before 3.4, it does always point of instantiation lookup, which is a bug.
starting with 3.4, it does point of definition lookup for d; but it does point of
instantiation lookup for fundamental types when they are a template parameter, which
is a bug.
starting with 4.1, it doesn't do point of instantiation lookup for basic types anymore.