Skip to content

CWG2777 [temp.param.note] p3 lacks the formal wording to define the type of the id-expression denoting the template parameter object #374

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

Closed
xmh0511 opened this issue Jul 26, 2023 · 7 comments · Fixed by cplusplus/draft#6906

Comments

@xmh0511
Copy link

xmh0511 commented Jul 26, 2023

Full name of submitter (unless configured in github; will be published with the issue): Jim X

[temp.param.note] p3 says:

[Note 3: If an id-expression names a non-type non-reference template-parameter, then it is a prvalue if it has non-class type.
Otherwise, if it is of class type T, it is an lvalue and has type const T ([expr.prim.id.unqual]). — end note]

Then, in [expr.prim.id.unqual], there is still only a note that says the type of the id-expression, [expr.prim.id.unqual.note] p4

[Note 4: If the entity is a template parameter object for a template parameter of type T ([temp.param]), the type of the expression is const T. — end note]

If there is no extra formal rule, then [temp.param] p8 just trumps any note, which says:

An id-expression naming a non-type template-parameter of class type T denotes a static storage duration object of

T is the declared type of the id-expression.

Suggested Resolution

When an id-expression that denotes the template parameter object appears in a context other than decltype(id-expression) , we should define its type with a formal rule.

In this decltype(id-expression), GCC and Clang have divergence, GCC says the type is const T while Clang says it is T.

struct A{};
template<auto const a>
void show(){
   decltype(a) b;
   A& rf = b;
}
int main(){
    show<A{}>();
}

https://godbolt.org/z/9jqhYn3vd

@frederick-vs-ja
Copy link

It seems that const T are normatively specified by [temp.param] p8 and [expr.prim.id.unqual] p3.

[temp.param] p8 states (emphasis mine):

An id-expression naming a non-type template-parameter of class type T denotes a static storage duration object of type const T, known as a template parameter object, [...]

So the id-expression denotes the template parameter object. Per [expr.prim.id.unqual] p3, the result of the id-expression is that template parameter object, and the type of the id-expression is that of the template parameter object, i.e., const T.
(The id-expression is also specified to be an lvalue in [expr.prim.id.unqual] p3.)

Perhaps the current wording is a bit ambiguous. In [temp.param] p8, "of class type T" should be associated to "a non-type template-parameter", not "an id-expression".


In this decltype(id-expression), GCC and Clang have divergence, GCC says the type is const T while Clang says it is T.

struct A{};
template<auto const a>
void show(){
   decltype(a) b;
   A& rf = b;
}
int main(){
    show<A{}>();
}

The template parameter is of type A in this example. The top-level const is dropped ([temp.param] p6). So gcc is buggy here, which is known (GCC Bug 99631).

@xmh0511
Copy link
Author

xmh0511 commented Jul 26, 2023

"denote" in [expr.prim.id.unqual] p3 merely means it denotes the entity that is introduced by the declaration that declares the name(i.e. id-expression) for which name lookup finds the declaration, which is statically determined. Since the id-expression is introduced by the parameter-declaration(i.e. A a), its declared type should be A.

Moreover, "denote an object" does not mean the lvalue is required to be that type of object, for example:

int a;
const int& ref = a;

According to [expr.type] p1

The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

The object denoted by the reference is a non-const object, by your logic, the id-expression ref thereof has type int? Furthermore, consider this example:

int a = 0;
using Type = int const;
new (&a) Type{1};

Now, the name can arguably say it denotes a const object, so the type of the id-expression is const it? Presumably, it is not the intent. The type of a name and the type of object it denotes does not have a close connection.

So, [expr.prim.id.unqual] p3 merely mean the type of an id-expression is the declared type of the declaration introducing the name.

@frederick-vs-ja
Copy link

frederick-vs-ja commented Jul 26, 2023

"denote" in [expr.prim.id.unqual] p3 merely means it denotes the entity that is introduced by the declaration that declares the name(i.e. id-expression) for which name lookup finds the declaration, which is statically determined.

But a template parameter is arguably not itself an entity (although the term "value" in [basic.pre] p3 is not very clear), while a template parameter object is definitely an entity.

Moreover, "denote an object" does not mean the lvalue is required to be that type of object, for example:

int a;
const int& ref = a;

Hmm... it is far less than ideal to use the ambiguous verb "denote", which you should have noticed for many times (cplusplus/draft#5346).

While "denote" is ambiguous, I think we can say a template parameter is not a thing that can be denoted by an id-expression (in the meaning of denoting an entity), so [temp.param] p8 should be considered unambiguously meaning that the id-expression only denotes the template parameter object, and thus have the same type as that object.

I think we should have an omnibus issue that clarifies "denoting", "naming", "designating", and "referring to".

@xmh0511
Copy link
Author

xmh0511 commented Jul 27, 2023

But a template parameter is arguably not itself an entity (although the term "value" in [basic.pre] p3 is not very clear), while a template parameter object is definitely an entity.

The template parameter introduces an object that is an entity, whose declaration is a parameter-declaration, and if there is any other specification, the type of the parameter-declaration is specified by [dcl.meaning], regardless of what actual object it denotes. The declaration just declares the name should denote a certain object, rather than specify which object it denotes.

So, you shouldn't determine the type of the expression according to the type of the object it denotes, instead, there is no special specification, the type of the name/expression should be determined by its declaration.

@frederick-vs-ja
Copy link

The template parameter introduces an object that is an entity

Not obviously true to me. I think it's still unclear whether a template parameter object is introduced by a template parameter. Perhaps we can say a template parameter object is introduced and created in some way other than declaration (there're some other objects created in unclear ways, see CWG2334).

IMO a template parameter object is very similar to a variable, but the current wording seemingly intends to distinguish between a template parameter object and a variable. (Perhaps we should continue the discussion in #148.)

@xmh0511
Copy link
Author

xmh0511 commented Jul 27, 2023

A declaration that introduces an object does not necessarily mean the declaration creates the object. Consider this example:

extern A a; // introduces an object but not create it. 

IMO a template parameter object is very similar to a variable

The variable is a unified name for either a reference or an object, even though the definition is unclear for what can be called a declaration of an object, however, this is another recorded issue.


As you mentioned above, we first should clear the definition of these verbs: denote, designate, which was discussed in #44 (comment)

When we say a name/expression denotes an entity, it should mean after performing a name lookup, which finds a declaration, that introduces the name, introduces such an entity, i.e. it is a declaration introducing such a kind of entity.

When we say a name/expression designates an object, we intend to mean, it is identified as a specific object, after evaluating it.

@jensmaurer
Copy link
Member

CWG2777

Note that decltype is handled specially for non-type template parameters.

@jensmaurer jensmaurer changed the title [temp.param.note] p3 lacks the formal wording to define the type of the id-expression denoting the template parameter object CWG2777 [temp.param.note] p3 lacks the formal wording to define the type of the id-expression denoting the template parameter object Jul 29, 2023
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

Successfully merging a pull request may close this issue.

3 participants