Is a function definition required to be instantiated when there is no need to check for narrowing?
Asked Answered
L

1

8

Consider the following program:

template<typename T>
constexpr int f() 
{
    T{}.i; // error if instantiated with [T = double]
    return 42;
}

constexpr void g(char);

using U = decltype( g( {f<double>()} ) );

To my understanding, the last line is an error because the call to f<double>() is within a brace initializer, and even though f<T> returns an int, the value of the returned int is needed to decide if it can be narrowed to a char as expected by g. This requires the definition of f to be instantiated with double, which causes an error. Both gcc and clang reject this code.


However, if the definition of g is changed to accept an int parameter:

constexpr void g(int);

then it seems that there is no need to instantiate the definition of f, since the narrowing conversion must succeed. Indeed, gcc accepts this, but clang still instantiates f with double and rejects the code. Additionally, if f is only declared, but not defined, clang accepts the code, which implies that the definition is not needed, and shouldn't be instantiated.

Is my reasoning correct, and this is a clang bug, or is instantiation required, and this is actually a gcc bug?

Littell answered 24/8, 2020 at 2:13 Comment(2)
this might helpIndoaryan
@Indoaryan It's related, but the code there is definitely valid (and is accepted by both compilers). In this case, there is an additional brace initializer which changes the rules I think.Littell
R
2

This is CWG #1581 I think, resolved by P0859.

temp.inst/5 says:

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.

Does the existence affect the semantics of the program?

temp.inst/8 says:

The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function is needed for constant evaluation by an expression ([expr.const]), even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition.

Is it needed for constant evaluation by an expression?

expr.const/15.6-7 says:

A function or variable is needed for constant evaluation if it is:

  • a constexpr function that is named by an expression that is potentially constant evaluated, or
  • a variable whose name appears as a potentially constant evaluated expression that is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type.

Is it named by an expression that is potentially constant evaluated?

expr.const/15.1-15.5 says:

An expression or conversion is potentially constant evaluated if it is:

  • a manifestly constant-evaluated expression,
  • a potentially-evaluated expression,
  • an immediate subexpression of a braced-init-list,
  • an expression of the form & cast-expression that occurs within a templated entity, or
  • a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.

It is an immediate subexpression of a braced-init-list.

Rockandroll answered 24/8, 2020 at 5:42 Comment(5)
So you're saying the code is invalid, and it's a gcc bug?Littell
Yes. Instantiation is required. The paper p0859 references the potential need for narrowing as the reason for including that clause. The code is invalid and it is a gcc bug. And p0859 I think was adopted somewhere around ~2017 from what I could find.Rockandroll
To share a couple other things I learned: gcc's DR status page lists cwg1851 as open: gcc.gnu.org/projects/cxx-dr-status.html and I could not find a relevant gcc bug. However, the adoption of p0859 is referenced in the constexpr invoke paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1065r2.htmlRockandroll
This is helpful information, thanks. I think I agree that this is invalid. So the fact that clang accepts this is a bug, right? Since the definition is needed and doesn't exist?Littell
Yes, it would seem to be a bug.Rockandroll

© 2022 - 2024 — McMap. All rights reserved.