Why this example results in "substitution failure" not "hard error" - c++

Per [temp.deduct]/8:
[..]
Only invalid types and expressions
in the immediate context of the function type, its template parameter
types, and its explicit-specifier can result in a deduction failure.
[ Note: The substitution into types and expressions can result in
effects such as the instantiation of class template specializations
and/or function template specializations, the generation of
implicitly-defined functions, etc. Such effects are not in the
“immediate context” and can result in the program being ill-formed. —
end note ]
What I understand from the bold part is,
If the substitution process has side effects (such as instantiation of a template, etc), invalid types/expressions can result in a hard error.
If the substitution process does not have side effects, invalid types/expressions can result in a deduction failure.
If I right about what I saying above, why this program results in substitution failure and not hard error:
template <class T> struct S { using type = T; };
template <class> void f(...); // "fallback".
template <class T> struct A {};
template <class T> typename S<T>::type::type f(int);
int main(void){
f<A<int>>(0); // calls fallback. Why?
}
The above call substitutes A<int> with T. So the function type will be S<int>::type (int). Now it has to instantiate the template S<int> to check the existence of the member type. And here is the point of my question: The substitution process has side effects that result in an invalid type because S<int> specialization has no members called type. So I am expecting that the program is ill-formed instead of calling f(...).
I deliberately do not mention anything about the "immediate contexts" because I do not completely understand what this context involves/means even though there's a specific question asked here about it, but neither answer there mentions what exactly this context means. So, if possible, any side note about it will be appreciated.

So I am expecting that the program is ill-formed instead of calling f(...).
In the given example, both instantiations A<int> and S<A<int>> are well-formed by themselves. Now, even though the instantiation of A<int> and S<A<int>> is not in the immediate context of function template's substitution but S<A<int>>::type::type is.
Thus, we get a deduction failure corresponding to the expression S<A<int>>::type::type instead of getting a hard error corresponding to the instantiations A<int> and S<A<int>>.
If on the other hand, any of the instantiation were ill-formed then we would have gotten a hard error.

Related

Concept is satisfied by a type that would seemingly produce an invalid expression

In the following code, the can_foo concept tests whether or not a foo() member function can be called on an instance of a type. I will use it to test instances of two templates: base conditionally enables the foo member function, and derived overrides foo to call into its base's implementation:
template <typename T>
concept can_foo = requires(T v) {
v.foo();
};
template <bool enable_foo>
struct base {
void foo()
requires enable_foo
{}
};
template <typename T>
struct derived : T {
void foo()
{
static_cast<T&>(*this).foo();
}
};
If I test whether instances of the base template satisfy the concept, it does what I would expect:
static_assert(can_foo<base<true>>); //okay
static_assert(not can_foo<base<false>>); //okay
When I wrap those types in derived, I see:
static_assert(can_foo<derived<base<true>>>); //okay
static_assert(not can_foo<derived<base<false>>>); //error: static assertion failed
This is surprising! I expected that derived<base<false>> would not satisfy can_foo - its definition of foo uses an expression that isn't valid given T = base<false>, and using the same expression tested by the concept in an evaluated context results in an error that says as much:
int main()
{
derived<base<false>> v{};
v.foo(); //error
}
The error message isn't at the call site, which is probably relevant; it references the body of derived<>::foo. From clang:
<source>:18:32: error: invalid reference to function 'foo': constraints not satisfied
static_cast<T&>(*this).foo();
^
<source>:31:7: note: in instantiation of member function 'derived<base<false>>::foo' requested here
v.foo(); //"invalid reference to function 'foo'"
^
<source>:10:18: note: because 'false' evaluated to false
requires enable_foo
^
clang: https://godbolt.org/z/vh58TTPxo
gcc: https://godbolt.org/z/qMPrzznar
Both compilers produce the same results, so I assume the problem is that there's a subtlety in the standard that I'm missing. Adding a can_foo<T> constraint to derived<T> or derived<T>::foo "fixes" this (that is, derived<base<false>> will no longer satisfy can_foo), and in a code review I would argue that this constraint should be present - but this is surprising behaviour nonetheless and I'd like to understand what's going on.
So: why does derived<false> satisfy can_foo?
A requires-expression can only detect invalid constructs in the "immediate context" of the expression that is tested. In particular
requires(T v) {
v.foo();
};
will not check whether it is actually well-formed to have the call v.foo(). If v.foo() would be ill-formed due to an ill-formed construct inside the body of the foo function, this will not be detected by the requires-expression because the body is not in the immediate context.
The question is, what should happen next? Should the requires-expression go and instantiate the body of foo and give a hard error, or should it return true and give you a hard error later when you attempt to call v.foo()? The answer is the second one: instantiation is not performed because it is not required. See [temp.inst]/5
Unless a function template specialization is a declared specialization, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. [...]
[temp.inst]/11 additionally implies that the implementation is not permitted to instantiate the definition unless it is required.
In an unevaluated context, calling v.foo() does not require the definition of foo to exist, because it is not odr-used unless it is potentially evaluated and it is normally the ODR that requires a definition to exist. (However, there are two situations where referencing a function requires its definition to exist even in an unevaluated context: when the function has a deduced return type or is needed for constant evaluation ([temp.inst]/8)). Since the definition is not required to exist, the definition is not instantiated.
You might want to modify derived::foo so that it propagates the constraint from T::foo, and thus the ill-formedness can be detected by can_foo<derived<T>>:
void foo() requires can_foo<T> {
static_cast<T&>(*this).foo();
}
derived has a foo for every template parameter T, it just cannot always be instantiated. When trying to instantiate derived<base<false>>::foo where you try to to call it in main, you get the error message that the instantiation is not valid since foo cannot be called for the type base<false>.
Rules regarding when instantiation is optional and/or required in the standard would be [temp.inst].
I'm however not able to point to a conclusive passage that says that
checking whether derived<base<false>>::foo exists in the context of the static_assert does not require instantiation. Is it the same as overload resolution checking? "If the function selected by overload resolution can be determined without instantiating a class template definition, it is unspecified whether that instantiation actually takes place."
If you want derived::foo to only be available if it can be instantiated, you could require can_foo on its T.
template <typename T>
struct derived : T {
void foo() requires can_foo<T>
{
static_cast<T&>(*this).foo();
}
};
https://godbolt.org/z/EqrMq4Moq

Partial specialization of single type template parameter class template using non-type template parameter through a dependent type

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
Consider the following snippet:
#include <type_traits>
template <int N> struct num {};
template <typename> struct A;
// (1)
template <int N> struct A<num<N>> { using type = bool; };
// (2)
template <long N> struct A<num<N>> { using type = char; };
static_assert(!std::is_same_v<long, int>, "");
// (A)
static_assert(std::is_same_v<A<num<1>>::type, bool>, "");
int main() {}
The static_assert at (A) is successful for GCC, but fails for Clang:
error: static_assert failed due to
requirement 'std::is_same_v<char, bool>' ""
Essentially, GCC picks the perfectly matching specialization (1), whereas Clang picks the specialization (2).
Similarly, if we remove the assertions as well as specialization (1):
template <int N> struct num {};
template <typename> struct A;
// (2)
template <long N> struct A<num<N>> { using type = char; };
int main() {
A<num<1>> a{};
(void)a;
}
Then GCC fails to compile the program whereas Clang accepts it.
GCC:
error: variable '`A<num<1> > a`' has initializer but incomplete type
This behaviour holds over various GCC and Clang versions, as well as various C++ language levels over these version (C++11, C++14, C++17, C++2a).
Question
Is the first snippet above in fact ill-formed (no diagnostic required?), or is either GCC or Clang wrong?
My guess is that this is ill-formed, but haven't been able to apply a relevant part of [temp.class.spec] to reject it. Perhaps [temp.class.spec]/8.1?
[temp.class.spec]/8.1 The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example: [...] — end example ]
As far as I can tell, the first snippet is ill-formed (and a diagnostic is required); compilers should reject the program because of the partial specialization (2).
[temp.deduct.type]/18 applies here:
If P has a form that contains <i>, and if the type of i differs
from the type of the corresponding template parameter of the template
named by the enclosing simple-template-id, deduction fails. [...]
The associated example in the Standard uses a function template, but is otherwise very similar.
So the template argument of the partial specialization (2) can never be deduced, and [temp.class.spec.match]/3 applies:
If the template arguments of a partial specialization cannot be
deduced because of the structure of its template-parameter-list and
the template-id, the program is ill-formed.
Interestingly, I couldn't find a compiler that diagnoses this issue, not even EDG in strict mode. We could speculate that most compiler writers consider the benefits of having a diagnostic here not to be worth the effort of implementing the checks. This could mean that we might see the requirement in the paragraph above change in the future from ill-formed to ill-formed, no diagnostic required. However, this is pure speculation. In any case, I don't see it ever changing to well-formed; I can't think of a valid use for a partial specialization that never matches.
The wording of [temp.deduct.type]/18 was clarified by the resolution of CWG2091.
The standard is not nearly precise enough about the template argument deduction for a partial specialization ([temp.class.spec.match]/2) to definitively determine the meaning of your example. In particular, all deduction is ultimately defined in terms of types ([temp.deduct.type]), but there are no types involved for a non-type template argument.
The deduction for partial ordering among partial specializations handles this case in terms of an invented class template ([temp.class.order]/1.2), which brings to bear the rule that deduction fails for any mismatch between the type of a non-type template argument and its parameter ([temp.deduct.type]/18). That makes any use of A<num<…>> in your example ambiguous if both partial specializations match (avoiding the need to determine whether a narrowing conversion was involved in using the “unique value” synthesized for partial ordering ([temp.func.order]/3) as a template argument). However, if we apply the same rule to the matching itself, we find (as does GCC) that (2) never matches. In turn, that arguably should provoke a diagnostic for the specialization itself ([temp.class.spec.match]/3, as bogdan’s answer mentioned), although it’s not entirely obvious what “structure” there is meant to include if the error is to be diagnosable and no compiler rejects it.
Meanwhile, [temp.class.spec]/8.1 is certainly irrelevant: there are no specialized non-type arguments involved.

Referring to specific template specialization from a non-instantiated context: instantiation or not?

Consider the following example
template <typename A> struct S
{
A a;
void foo() {}
};
template <typename T> void bar()
{
S<void> *p = 0;
}
template <typename T> void baz()
{
S<void>{}.foo();
}
template <typename T> void qux()
{
S<void> s{};
}
int main()
{
}
Function templates bar, baz and qux are deliberately left non-instantiated.
The definition of baz fails to compile in GCC and Clang for "obvious" reason - S<void> is an invalid specialization of S. However, which language rule is working in this case?
On the one hand, S<void> does not depend on template parameters of baz, member access requires it to be complete, which triggers instantiation of S<void>, which fails. Diagnostic is required.
On the other hand we have the blanket rule of "if no valid specialization can be generated for a non-instantiated template, the code is ill-formed". This makes the definition of baz ill-formed. However, no diagnostic is required.
More specifically, am I correct in my assumption (as expressed in #1) that the above reference to S<void> from non-instantiated baz requires instantiation of S<void>? The assumption is supported by the fact that both compilers happily accept the definition of bar, which does not instantiate S<void>.
However, the aforementioned compilers differ in their treatment of qux - Clang complains, while GCC accepts it without any complaints. Is this a bug in one of the compilers? Is diagnostic required in this case? Or am I wrong in my assumption that #1 is at work here? If #2 is the basis for the diagnostic, then the difference between the compilers is acceptable.
For both baz and qux, the validity of the expression including S<void> can only be done through instantiation of S. Nevertheless, compilers are not mandated to perform this validation before any instantiation [temp.res]/8
The validity of a template may be checked prior to any instantiation.
[...
 ] The program is ill-formed, no diagnostic required, if:
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter,
Both S<void>{} and S<void> s{} are used in a context that requires the instantiation of S<void>, such an instantiation is ill-formed due to the member having incomplete type void.
The relevant quotes are [temp.inst]/1:
Unless a class template specialization has been explicitly instantiated or explicitly specialized, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [...]
and [temp.arg]/6:
If the use of a template-argument gives rise to an ill-formed construct in the instantiation of a template specialization, the program is ill-formed.
On the other hand both baz and quz are ill-formed NDR
[temp.res]/8:
Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if:
(8.1) no valid specialization can be generated for a template, [...]

Type deduction for non-viable function templates

In his answer to this question and the comment section, Johannes Schaub says there's a "match error" when trying to do template type deduction for a function template that requires more arguments than have been passed:
template<class T>
void foo(T, int);
foo(42); // the template specialization foo<int>(int, int) is not viable
In the context of the other question, what's relevant is whether or not type deduction for the function template succeeds (and substitution takes place):
template<class T>
struct has_no_nested_type {};
// I think you need some specialization for which the following class template
// `non_immediate_context` can be instantiated, otherwise the program is
// ill-formed, NDR
template<>
struct has_no_nested_type<double>
{ using type = double; };
// make the error appear NOT in the immediate context
template<class T>
struct non_immediate_context
{
using type = typename has_no_nested_type<T>::type;
};
template<class T>
typename non_immediate_context<T>::type
foo(T, int) { return {}; }
template<class T>
bool foo(T) { return {}; }
int main()
{
foo(42); // well-formed? clang++3.5 and g++4.8.2 accept it
foo<int>(42); // well-formed? clang++3.5 accepts it, but not g++4.8.2
}
When instantiating the first function template foo for T == int, the substitution produces an invalid type not in the immediate context of foo. This leads to a hard error (this is what the related question is about.)
However, when letting foo deduce its template-argument, g++ and clang++ agree that no instantiation takes place. As Johannes Schaub explains, this is because there is a "match error".
Question: What is a "match error", and where and how is it specified in the Standard?
Altenative question: Why is there a difference between foo(42) and foo<int>(42) for g++?
What I've found / tried so far:
[over.match.funcs]/7 and [temp.over] seem to describe the overload resolution specifics for function templates. The latter seem to mandate the substitution of template parameters for foo.
Interestingly, [over.match.funcs]/7 triggers the process described in [temp.over] before checking for viability of the function template (specialization).
Similarly, type deduction does not to take into account, say, default function arguments (other than making them a non-deduced context). It seems not to be concerned with viability, as far as I can tell.
Another possibly important aspect is how type deduction is specified. It acts on single function parameters, but I don't see where the distinction is made between parameter types that contain / are dependent on template parameters (like T const&) and those which aren't (like int).
Yet, g++ makes a difference between explicitly specifying the template parameter (hard error) and letting them be deduced (deduction failure / SFINAE). Why?
What I've summarized is the process described at 14.8.2.1p1
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
In our case, we have for P (T, int) and for A, we have (int). For the first pair of P/A, which is T against int, we can match T to int (by the process described in 14.8.2.5). But for the second "pair", we have int but have no counterpart. Thus deduction cannot be made for this "pair".
Thereby, by 14.8.2.5p2, "If type deduction cannot be done for any P/A pair, ..., template
argument deduction fails.".
You then won't ever come to the point where you substitute template arguments into the function template.
This can all probably described more precisely in the Standard (IMO), but I believe this is how one could implement things to match the actual behavior of Clang and GCC and it seems a reasonable interpretation of the Standardese.

Is this program ill-formed despite SFINAE?

template <typename T> void f() {
return 0; // returning value from function returning `void`
}
int main()
{
// Not instantiating or calling any f<T>()
}
In comments to this answer, David asserts that a function template that contains a semantic error and is not instantiated causes a program to be ill-formed:
Whether the template is used or not does not matter, the program is ill-formed even with no instantiation but the compiler is not required to diagnose it.
Conversely, I am quite sure that SFINAE, as well as preventing type deduction and therefore instantiation of the function template per [C++11: 14.8.2/8], allows the program to remain well-formed. however I cannot find any text in this standard paragraph that explicitly says so.
Who is correct?
Wikipedia, which I shall not consider authoritative for this question, says about a slightly different case:
[..] SFINAE was introduced to avoid creating ill-formed programs when unrelated template declarations were visible [..]
(emphasis mine)
The program is ill-formed as per 14.6/8:
If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required.
That is whether you instantiate the template or not, the template definition is ill-formed as there is no possible instantiation that will succeed.
Note that this is completely unrelated to SFINAE: Substitution Failure is not an Error is part of the substitution process, and never takes into account the contents of the template.
Reading more closely, that standard passage says:
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [..]
return 0 is not an expression, so SFINAE does not apply.
The passage goes on:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
return 0 has nothing to do with the function type or its template parameter types, so SFINAE still does not apply.