You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Clang][Sema] Explicit template arguments are not substituted into the exception specification of a function (#90760)
[temp.deduct.general] p6 states:
> At certain points in the template argument deduction process it is
necessary to take a function type that makes use of template parameters
and replace those template parameters with the corresponding template
arguments.
This is done at the beginning of template argument deduction when any
explicitly specified template arguments are substituted into the
function type, and again at the end of template argument deduction when
any template arguments that were deduced or obtained from default
arguments are substituted.
[temp.deduct.general] p7 goes on to say:
> The _deduction substitution loci_ are
> - the function type outside of the _noexcept-specifier_,
> - the explicit-specifier,
> - the template parameter declarations, and
> - the template argument list of a partial specialization
>
> The substitution occurs in all types and expressions that are used in
the deduction substitution loci. [...]
Consider the following:
```cpp
struct A
{
static constexpr bool x = true;
};
template<typename T, typename U>
void f(T, U) noexcept(T::x); // #1
template<typename T, typename U>
void f(T, U*) noexcept(T::y); // #2
template<>
void f<A>(A, int*) noexcept; // clang currently accepts, GCC and EDG reject
```
Currently, `Sema::SubstituteExplicitTemplateArguments` will substitute
into the _noexcept-specifier_ when deducing template arguments from a
function declaration or when deducing template arguments for taking the
address of a function template (and the substitution is treated as a
SFINAE context). In the above example, `#1` is selected as the primary
template because substitution of the explicit template arguments into
the _noexcept-specifier_ of `#2` failed, which resulted in the candidate
being ignored.
This behavior is incorrect ([temp.deduct.general] note 4 says as much), and
this patch corrects it by deferring all substitution into the
_noexcept-specifier_ until it is instantiated.
As part of the necessary changes to make this patch work, the
instantiation of the exception specification of a function template
specialization when taking the address of a function template is changed
to only occur for the function selected by overload resolution per
[except.spec] p13.1 (as opposed to being instantiated for every candidate).
// In C++17 onwards, substituting explicit template arguments into the
285
-
// function type substitutes into the exception specification (because it's
286
-
// part of the type). In earlier languages, we don't notice there's a problem
287
-
// until we've already started to instantiate.
288
284
template int f<short>(); // #cwg1330-f-short
289
-
// since-cxx17-error@-1 {{explicit instantiation of 'f' does not refer to a function template, variable template, member function, member class, or static data member}}
290
-
// since-cxx17-note@#cwg1330-f {{candidate template ignored: substitution failure [with T = short]: type 'short' cannot be used prior to '::' because it has no members}}
285
+
// since-cxx17-error@#cwg1330-f {{type 'short' cannot be used prior to '::' because it has no members}}
286
+
// since-cxx17-note@#cwg1330-f {{in instantiation of exception specification for 'f<short>' requested here}}
287
+
// since-cxx17-note@#cwg1330-f-short {{in instantiation of function template specialization 'cwg1330::f<short>' requested here}}
0 commit comments