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

The grammar template-name component has a narrow definition #5345

Open
xmh0511 opened this issue Mar 16, 2022 · 5 comments
Open

The grammar template-name component has a narrow definition #5345

xmh0511 opened this issue Mar 16, 2022 · 5 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Mar 16, 2022

template-name:

  • identifier
template<class T>
struct X{};  // #1

X<int> v;  // #2

X is a class-name introduced by the declaration at #1. However, a simple-template-id is defined as:

template-name < template-argument-list opt >

template-name cannot be a class-name. Unlike other grammar definitions, they include as many as possible grammar components that can be used to form that grammar. Specifically, such as the qualified-id:

  • nested-name-specifier templateopt unqualified-id

where the grammar nested-name-specifier is defined as:

  • [...]
  • type-name
  • namespace-name
  • [...]

where the grammar type-name can be broken up into that:

  • class-name
  • [...]

That means, the grammar in the following example all can be covered

struct X{
   static int value;
};
namespace A{
  int a = 0;
}
int main(){
   sizeof(X::value) + A::a;
}

X:: and A:: are nested-name-specifiers where the first is class-name and the second is namespace-name, even though they ultimately are identifiers. Conversely, the template-name in a simple-template-id just includes an identifier. That is, it greatly limits what the components are. Although, [temp.names.note] p1 implies that a name that is an identifier can be reinterpreted as a template-name if possible. However, it is not a formal rule. The quo status is, a component can only be a template-name when we have explicitly specified it is a template-name. Such as [temp.alias] p1

The name of the alias template is a template-name.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 16, 2022

As discussed in the mentioned issue. If we prepare to restrict certain language constructs by using grammar, identifier is too flexible. Since lookup only concerns name and the entity introduced by the declaration. Even if we augment the definition of template-name, it is still not sufficient. Because of the identifier, we still need to draft the wording as that: if..., the name shall be introduced by a template declaration.

In order to make the restriction that is in terms of the grammar to work, we might have a formal rule that means as the following:

once an identifier(name) is determined which entity E it denotes after lookup, the identifier will be promoted to the corresponding component(e.g. class-name, namespace-name, or declarator-id) of the declaration of E. For some language constructs, their grammar requires the component to be class-name, namespace-name, which is the restriction to the name.

T::X * i; // #1

Whether the language construct at #1 is a declaration or expression is determined by what the identifier X denotes after lookup. If the identifier X denotes a class, it is promoted to be a class-name and only type-specifier can be a well-formed construct. Conversely, if X is determined to be an object, the identifier is promoted to unqualified-id( assume its declaration is int X = 1;), then only qualified-id can be a well-formed construct.

@jensmaurer
Copy link
Member

jensmaurer commented Mar 16, 2022

We need something like [class.pre] for templates.
Other than that, [gram.key] comes pretty close for the fact that we reinterpret an identifier as an X-name, except that it's a non-normative Annex.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 17, 2022

[gram.key] comes pretty close for the fact that we reinterpret an identifier as an X-name

In translation phase 7, all preprocessing identifier tokens are just converted to an identifier token as specified in [lex.token]. I think we should also need a rule to explicitly state that the identifier will be reinterpreted to a high-level grammar(after lookup?), which can be convenient to limit the context where the identifier can be used. I think it is exactly the meaning of defining high-level grammar. We can say an unqualified-id can be an identifier but it is not the other way around, unqualified-id, therefore, is more special than an identifier. When an identifier is identified to be an unqualified-id, the latter can narrow the context where the identifier can be used.

struct X{};
int main(){
   X * i;
}

In translation phase 7, X is converted to an identifier, an identifier can be validly used in both multiplicative-expression and type-specifier(i.e. their grammars accept identifiers). There is no more restriction on an identifier. However, once we have a rule that specifies that the identifier X is reinterpreted to a class-name since lookup associates the use of the name with the class-specifier. This will result that the identifier X can only be used as a type-specifier. In other words, multiplicative-expression does not accept a class-name.

The quo status is, we just cannot clearly interpret why the identifier X cannot be used as an expression(i.e. unqualified-id) that is an identifier.

@jensmaurer
Copy link
Member

The quo status is, we just cannot clearly interpret why the identifier X cannot be used as an expression(i.e. unqualified-id) that is an identifier.

I think we've this part covered okay-ish: [expr.prim.id.unqual] p1 "An identifier is only an id-expression if it has been suitably declared (Clause 9) or if it appears as part of a declarator-id (9.3). An identifier that names a coroutine parameter refers to the copy of the parameter (9.5.4)."

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 17, 2022

suitably declared

I would say this is a bit unclear. What does the "suitably declared" exactly mean? We seem to have not given the concrete specification.
id-expression is a high-level grammar identity for these identifiers that are eligible to be that. Presumably, "suitably declared" means the identifiers should be introduced by the declarations that introduce these entities: object, reference, structured binding, function...

From certain perspectives, that means what declaration is found by lookup for that name, and therefore resulting in how the identifier will be reinterpreted or could say what high-level grammar identity the underlying identifier will be promoted to. That results will ultimately determine the context in which the use of the identifier is valid.

If possible, we should explicitly specify what the name will become when a declaration introduces it. Similar to [class.pre] have done.

A class is a type. Its name(i.e. identifier) becomes(i.e. promoted to) is reinterpreted as a class-name ([class.name]) within its scope.

And we might make a rule and add it to [basic.lookup], the rule might mean

the name that is an identifier is reinterpreted by the found declaration for further syntactical and semantic analysis.

Then we will clearly know the reason why we categorize the identifiers into various high-level grammar stuff.

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

2 participants