Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dcl.constexpr] p6 Relax the condition for a constexpr function that could be well-formed #5426

Open
xmh0511 opened this issue Apr 29, 2022 · 6 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Apr 29, 2022

[dcl.constexpr] p6 says

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object ([basic.start.static]), the program is ill-formed, no diagnostic required.

The condition here requires an argument to make the rule true. Consider this example:

constexpr int fun(){
    const int v = 0;
    if(v==1){
        static int v = 0;
    }
    return v;
}

struct A{
    constexpr int show(){
        if(a==1){
            static int v = 0;
        }
        return a;
    }
    int a = 0;
};

No argument here, however, the example is accepted by implementations. I think the argument is not necessary here to make the rule true. Maybe, we just need to say

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if there does not exist an invocation of the function or constructor such that the function call could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object ([basic.start.static]), the program is ill-formed, no diagnostic required.

In the above example, there exists such an invocation(e.g. v!=1, a!=1). As a contract example:

struct NoneLiteral{
   NoneLiteral(){}
  ~NoneLiteral(){}
};

struct B:NoneLiteral{
    int a;
   constexpr int fun(){
     return a;
  }
};

Since B is not a literal type and cannot be used to create a constexpr object or temporary object of the type within the context of a core constant expression, thus the lvalue-to-rvalue conversion that is applied to a can never satisfy the requirement of a core constant expression.

@jensmaurer
Copy link
Member

jensmaurer commented Apr 29, 2022

For clarity on what the "does not exist" refers to, I think we want to retain the reference to "argument values".

Maybe "A valid invocation is a set of argument values for which an invocation of a constexpr function or constructor ... If no valid invocation exists for a constexpr function or constexpr constructor that is neither defaulted nor a template, the program is ill-formed, no diagnostic required."

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 29, 2022

A valid invocation is a set of argument values for which an invocation of a constexpr function or constructor

As exposed in the first example(i.e. the non-member function), the function does not have a parameter and therefore the function call does not have arguments. It could be argued that the member function can have the implicit object argument, however, the non-member function definitely does not have arguments.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 29, 2022

Shall we phrase the wording as:

A potentially-constant-invocation is, for a given (possibly empty)set of (possible implied object)arguments, the function call to a constexpr function or constructor could be evaluated by a core constant expression. If no potentially-constant-invocation exists for a constexpr function or constexpr constructor that is neither defaulted nor a template, the program is ill-formed, no diagnostic required.

@jensmaurer
Copy link
Member

jensmaurer commented Apr 29, 2022

"set of argument values" does convey "possibly none", in my view. We can add "if any", if that helps.

I wouldn't want to define a global defined term for a concept that is only used in the next sentence and nowhere else.

Oh, and it's not really "potentially constant", since the set of argument values you found actually makes the invocation a core constant expression.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 29, 2022

@jensmaurer All right. Could we add "implied object argument" in that sentence, I think it also helps when we encounter member functions whose parameter-declaration-clause is empty. Because we define the concept in [dcl.fct]

If the parameter-declaration-clause is empty, the function takes no arguments.

The implied object argument is only mentioned in clause [over]. I think the second case strongly implies the argument should consider the implied object argument.

@languagelawyer
Copy link
Contributor

Hm. Isn't this issue a subject of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html#pnum_24?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants