cplusplus / cplusplus/draft

[temp.constr.normal] p1.4 The implementations have a divergence for substitution in the normalization of a concept-id

Open
#5,461 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TeX
Stars
221
Forks
813
Avg merge
16h 4m
Merged PRs (30d)
36

Description

[temp.constr.normal] p1.4 says

The normal form of a concept-id C<A1, A2, ..., An> is the normal form of the constraint-expression of C, after substituting A1, A2, ..., An for C's respective template parameters in the parameter mappings in each atomic constraint. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.

Consider this example:

template<typename T> concept A = T::value || true;
template<typename U> concept C = A<U*>;

template<class T>
requires C<T> void fun(T){}

int main(){
    int a = 0;
    fun<int&>(a);
}

In this case, the template parameter that appears in the atomic constraint is T, where the mapping is T↦ U*, and the template argument in concept-id C<int&> is int&, when undergoing the normalization of C<int&>, C's template parameter U that appears in the parameter mapping is substituted by int&, such substitution results in an invalid type int&*. By this logic, the program should be ill-formed. For this example, Clang rejects it but GCC accepts it and calls the specialization. Clang gave a kindly reminder:

<source>:2:37: note: because substituted constraint expression is ill-formed: 
'type name' declared as a pointer to a reference of type 'int &'


@jensmaurer

Another case based on the above concept-id for which they have a divergence is

   bool r = !C<int&>;
   std::cout<< r;

GCC prints 0 while Clang prints 1.

The divergence might raise from the confusion mentioned in https://github.com/cplusplus/draft/issues/5389.

In summary of these two issues, [temp.constr.normal] p1.4 might be changed to

The normal form of a concept-id C<A1, A2, ..., An> is the normal form of the constraint-expression of C, after substituting A1, A2, ..., An for C's respective template parameters that appear in concept-ids(if any) in C's constraint-expression and mapping C's respective template parameters that appear in C's constraint-expression to A1, A2, ..., An. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.

This modification conforms to the definition of parameter mapping

An atomic constraint is formed from an expression E and a mapping from the template parameters that appear within E to template arguments that are formed via substitution during constraint normalization in the declaration of a constrained entity (and, therefore, can involve the unsubstituted template parameters of the constrained entity), called the parameter mapping ([temp.constr.decl]).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with [temp.constr.normal] p1.4 and the parameter-mapping definition quoted in the issue. Compare the two linked compiler examples, including the C<int&> normalization and negation cases, against the proposed wording. Done means resolving the GCC/Clang divergence and agreeing on the corresponding draft text.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.