---
title: "Core Language Working Group \"ready\" Issues for the June, 2026 meeting"
document: P4271R0
date: 2026-06-12
audience: CWG Core
reply-to:
  - "Jens Maurer <jens.maurer@gmx.net>"
---


## Core Language Working Group "ready" Issues for the June, 2026 meeting

References in this document reflect the section and paragraph numbering of document [WG21 N5046](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/n5046.pdf).

---

#### Ambiguity resolution for cast to function type

Section: 

9.3.3  [

dcl.ambig.res

]

Status: 

ready

Submitter: 

Richard Smith

Date: 

2016-02-02

Consider:

```
  int x = (int()) + 5; 
```

This is ill-formed, because 9.3.3 [[dcl.ambig.res](https://wg21.link/dcl.ambig.res#2)] paragraph 2 specifies:

> An ambiguity can arise from the similarity between a function-style
> cast and a
> 
> type-id
> 
> . The resolution is that any construct that
> could possibly be a
> 
> type-id
> 
> in its syntactic context shall be
> considered a
> 
> type-id
> 
> .

and thus int() is interpreted as a *type-id* instead of as a function-style cast, so this is an ill-formed cast to a function type.

This seems to be the wrong disambiguation for all cases where there is a choice between a C-style cast and a parenthesized expression: in all those cases, the C-style cast interpretation results in a cast to a function type, which is always ill-formed.

Further, there is implementation divergence in the handling of this example:

```
  struct T { int operator++(int); T operator[](int); };
  int a = (T()[3])++; // not a cast
```

**EWG 2022-11-11**

This is tracked in github issue [cplusplus/papers#1376](https://github.com/cplusplus/papers/issues/1376).

**Additional notes (May, 2025)**

Also consider this example:

```
  (S())[]->A<int>;              // OK, constructor call
  (S())[]->A<int> {return {};}; // error: C-style cast of lambda
```

Without the suggested simple rule that (T()) is never a conversion to a function type (which is always semantically ill-formed), syntactic disambiguation would require analysis whether the thing after the arrow is a type (i.e. a trailing return type) or an expression (for operator->).

**Proposed resolution (approved by CWG 2026-06-10):**

1. Change in 7.6.2 [[expr.unary](https://wg21.link/expr.unary#1)] paragraph 1 as follows: *unary-expression : postfix-expression unary-operator cast-expression ++ cast-expression -- cast-expression await-expression sizeof unary-expression sizeof ( <ins>nofun-</ins>type-id ) sizeof ... ( identifier ) alignof ( <ins>nofun-</ins>type-id ) noexcept-expression new-expression delete-expression*
2. Change in 7.6.2.5 [[expr.sizeof](https://wg21.link/expr.sizeof#1)] paragraph 1 as follows: The operand is either an expression, which is an unevaluated operand (7.2.3 [[expr.context](https://wg21.link/expr.context)]), or a parenthesized *<ins>nofun-</ins>type-id*.
3. Change in 7.6.2.6 [[expr.alignof](https://wg21.link/expr.alignof#1)] paragraph 1 as follows: The operand shall be a *<ins>nofun-</ins>type-id* representing a complete object type, or an array thereof, or a reference to one of those types.
4. Replace *type-id* with *nofun-type-id* throughout 7.6.2.8 [[expr.new](https://wg21.link/expr.new)], for example in paragraph 1: *new-expression : ::<sub>opt</sub> new new-placement<sub>opt</sub> new-type-id new-initializer<sub>opt</sub> ::<sub>opt</sub> new new-placement<sub>opt</sub> ( <ins>nofun-</ins>type-id ) new-initializer<sub>opt</sub>*
5. Change in 7.6.3 [[expr.cast](https://wg21.link/expr.cast#2)] paragraph 2 as follows: *cast-expression : unary-expression ( <ins>nofun-</ins>type-id ) cast-expression*
6. Change in 9.2.9.7.1 [[dcl.spec.auto.general](https://wg21.link/dcl.spec.auto.general#6)] paragraph 6 as follows: A placeholder type can also be used in the *type-specifier-seq* of the *new-type-id* or in the *<ins>nofun-</ins>type-id* of a *new-expression* (7.6.2.8 [[expr.new](https://wg21.link/expr.new)]). In such a *<ins>nofun-</ins>type-id*, the placeholder type shall appear as one of the *type-specifier*s in the *type-specifier-seq* or as one of the *type-specifier*s in a *trailing-return-type* that specifies the type that replaces such a *type-specifier* .
7. Change in 9.2.9.7.2 [[dcl.type.auto.deduct](https://wg21.link/dcl.type.auto.deduct#2)] paragraph 2 as follows: A placeholder for a deduced class type can also be used in the *type-specifier-seq* in the *new-type-id* or *<ins>nofun-</ins>type-id* of a *new-expression* (7.6.2.8 [[expr.new](https://wg21.link/expr.new)]), as the *simple-type-specifier* in an explicit type conversion (functional notation) (7.6.1.4 [[expr.type.conv](https://wg21.link/expr.type.conv)]), or as the *type-specifier* in the *parameter-declaration* of a *template-parameter* (13.2 [[temp.param](https://wg21.link/temp.param)]). A placeholder for a deduced class type shall not appear in any other context.
8. Change in 9.3.1 [[dcl.decl.general](https://wg21.link/dcl.decl.general#6)] paragraph 6 as follows, to fix auto (*p)() -> int(X()); (now a function pointer initialized by X()): *trailing-return-type : -> <ins>nofun-</ins>type-id*
9. Change in 9.3.2 [[dcl.name](https://wg21.link/dcl.name#1)] paragraph 1 as follows: <del>To specify type conversions explicitly, and as an argument of sizeof, alignof, new, or typeid, the name of a type shall be specified. This can be done</del> <ins>A type can be named</ins> with a *type-id*<ins>, *nofun-type-id*,</ins> or *new-type-id* (7.6.2.8 [[expr.new](https://wg21.link/expr.new)]), <ins>each of</ins> which is syntactically a declaration for a variable or <ins>(only for a *type-id*)</ins> function of that type that omits the name of the entity. *nofun-type-id: type-specifier-seq nofun-declarator<sub>opt</sub> nofun-declarator: ptr-nofun-declarator noptr-nofun-declarator parameters-and-qualifiers trailing-return-type ptr-nofun-declarator: noptr-nofun-declarator ptr-operator ptr-nofun-declarator<sub>opt</sub> noptr-nofun-declarator: noptr-nofun-declarator parameters-and-qualifiers noptr-nofun-declarator<sub>opt</sub> [ constant-expression<sub>opt</sub> ] attribute-specifier-seq<sub>opt</sub> ( ptr-nofun-declarator )* It is possible to identify uniquely the location in the *abstract-declarator* <ins>or *nofun-declarator*</ins> where the identifier would appear if the construction were a declarator in a declaration. The named type is then the same as the type of the hypothetical identifier.
10. Change in 9.3.3 [[dcl.ambig.res](https://wg21.link/dcl.ambig.res#2)] paragraph 2 as follows: An ambiguity can arise from the similarity between a function-style cast and a *type-id*. The resolution is that any construct that could possibly be a *type-id* in its syntactic context shall be considered a *type-id*. <ins>[ Note: No such ambiguity can arise between an expression and a *nofun-type-id*. -- end note ]</ins> However, a construct that can syntactically be a *type-id* whose outermost *abstract-declarator* would match the grammar of an *abstract-declarator* with a *trailing-return-type* is considered a *type-id* only if it starts with auto. [Example 2 : template <class T> struct X {}; template <int N> struct Y {}; X<int()> a; // type-id X<int(1)> b; // expression (ill-formed) Y<int()> c; // type-id (ill-formed) Y<int(1)> d; // expression void foo(signed char a) { sizeof(int()); // <del>type-id (ill-formed)</del> <ins>expression</ins> sizeof(int(a)); // expression sizeof(int(unsigned(a))); // <del>type-id (ill-formed)</del> <ins>expression</ins> (int())+1; // <del>type-id (ill-formed)</del> <ins>expression</ins> (int(a))+1; // expression (int(unsigned(a)))+1; // <del>type-id (ill-formed)</del> <ins>expression</ins> } typedef struct BB { int C[2]; } *B, C; void g() { sizeof(B()->C[1]); // OK, sizeof(expression) sizeof(auto()->C[1]); // error: <del>sizeof of a function returning an array</del> <ins>ill-formed expression</ins> } -- end example ]
11. Change in 9.13.1 [[dcl.attr.grammar](https://wg21.link/dcl.attr.grammar#1)] paragraph 1 as follows: *alignment-specifier : alignas ( <ins>nofun-</ins>type-id ...<sub>opt</sub> ) alignas ( constant-expression ...<sub>opt</sub> )*
12. Change in 9.13.2 [[dcl.align](https://wg21.link/dcl.align#3)] paragraph 3 as follows: An *alignment-specifier* of the form alignas( *<ins>nofun-</ins>type-id* ) has the same effect as alignas(alignof( *<ins>nofun-</ins>type-id* )) (7.6.2.6 [[expr.alignof](https://wg21.link/expr.alignof)]).
13. Do not change 13.8.1 [[temp.res.general](https://wg21.link/temp.res.general#4)] paragraph 4.
14. Change in 13.8.3.3 [[temp.dep.expr](https://wg21.link/temp.dep.expr#3)] paragraph 3 as follows: Expressions of the following forms are type-dependent only if the type specified by the *type-id*, <ins>*nofun-type-id*,</ins> *simple-type-specifier*, *typename-specifier*, or *new-type-id* is dependent, even if any subexpression is type-dependent: *simple-type-specifier ( expression-list<sub>opt</sub> ) simple-type-specifier braced-init-list typename-specifier ( expression-list<sub>opt</sub> ) typename-specifier braced-init-list ::opt new new-placement<sub>opt</sub> new-type-id new-initializeropt ::opt new new-placement<sub>opt</sub> ( <ins>nofun-</ins>type-id ) new-initializer<sub>opt</sub> dynamic_cast < type-id > ( expression ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( <ins>nofun-</ins>type-id ) cast-expression*
15. Change in 13.8.3.3 [[temp.dep.expr](https://wg21.link/temp.dep.expr#4)] paragraph 4 as follows: *literal sizeof unary-expression sizeof ( <ins>nofun-</ins>type-id ) sizeof ... ( identifier ) alignof ( <ins>nofun-</ins>type-id ) typeid ( expression ) typeid ( type-id ) ::opt delete cast-expression ::opt delete [ ] cast-expression throw assignment-expressionopt noexcept ( expression ) requires-expression*
16. Change in 13.8.3.4 [[temp.dep.constexpr](https://wg21.link/temp.dep.constexpr#2)] paragraph 2 as follows: Expressions of the following form are value-dependent if the *unary-expression* or expression is type-dependent or the *type-id* <ins>or *nofun-type-id*</ins> is dependent: *sizeof unary-expression sizeof ( <ins>nofun-</ins>type-id ) typeid ( expression ) typeid ( type-id ) alignof ( <ins>nofun-</ins>type-id )*
17. Change in 13.8.3.4 [[temp.dep.constexpr](https://wg21.link/temp.dep.constexpr#3)] paragraph 3 as follows: Expressions of the following form are value-dependent if either the *type-id*, <ins>*nofun-type-id*,</ins> *simple-type-specifier*, or *typename-specifier* is dependent or the *expression* or *cast-expression* is value-dependent or any expression in the *expression-list* is value-dependent or any *assignment-expression* in the *braced-init-list* is value-dependent: *simple-type-specifier ( expression-list<sub>opt</sub> ) typename-specifier ( expression-list<sub>opt</sub> ) simple-type-specifier braced-init-list typename-specifier braced-init-list static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) dynamic_cast < type-id > ( expression ) ( <ins>nofun-</ins>type-id ) cast-expression*

**EWG 2025-06-16**

EWG agrees with the direction represented by the wording for the May, 2025 notes, above.

---

#### thread_local dynamic initialization

Section: 

6.10.3.3  [

basic.start.dynamic

]

Status: 

ready

Submitter: 

Jason Merrill

Date: 

2023-01-06

Subclause 6.10.3.3 [[basic.start.dynamic](https://wg21.link/basic.start.dynamic#7)] paragraph 7 specifies:

> It is implementation-defined whether the dynamic initialization of a
> non-block non-inline variable with thread storage duration is
> sequenced before the first statement of the initial function of a
> thread or is deferred. If it is deferred, the initialization
> associated with the entity for thread t is sequenced before the first
> non-initialization odr-use by t of any non-inline variable with thread
> storage duration defined in the same translation unit as the variable
> to be initialized. ...

How does the rule quoted above affect variables declared constinit? For example:

```
  extern thread_local constinit int x;
```

Clang and gcc do not emit suitable wrapper code to allow for x to trigger deferred initialization of other thread-local variables, which is non-conforming.

**Proposed resolution (approved by CWG 2026-05-29):**

Change in 6.10.3.3 [[basic.start.dynamic](https://wg21.link/basic.start.dynamic#7)] paragraph 7 as follows:

> It is implementation-defined whether the dynamic initialization of a
> non-block non-inline variable with thread storage duration is
> sequenced before the first statement of the initial function of a
> thread or is deferred. If it is deferred, the initialization
> associated with the entity for thread t is sequenced before the first
> non-initialization odr-use by t of any non-inline variable with thread
> storage duration
> 
> and dynamic initialization
> 
> defined in the
> same translation unit as the variable to be initialized. ...

---

#### Completion of initialization by delegating constructor

Section: 

11.9  [

class.init

]

Status: 

ready

Submitter: 

Brian Bi

Date: 

2023-06-20

Subclause 6.8.4 [[basic.life](https://wg21.link/basic.life#1)] paragraph 1 specifies:

> ... The lifetime of an object of type T begins when:
> 
> - storage with the proper alignment and size for type T is obtained, and
> - its initialization (if any) is complete (including vacuous initialization) (9.5 [[dcl.init](https://wg21.link/dcl.init)]),
> 
> except that ...

It is unclear whether initialization is considered complete when the (ultimate) target constructor completes, or when the outermost delegating constructor completes. Subclause 14.3 [[except.ctor](https://wg21.link/except.ctor#4)] paragraph 4 suggests it is the former:

> If the
> 
> compound-statement
> 
> of the
> 
> function-body
> 
> of a
> delegating constructor for an object exits via an exception, the
> object's destructor is invoked. ...

**Proposed resolution (approved by CWG 2023-07-14) [SUPERSEDED]:**

1. Split and change 11.9.3 [[class.base.init](https://wg21.link/class.base.init#9)] paragraph 9 as follows: [Note 3: An abstract class ... -- end note ] <del>An attempt to initialize more than one non-static data member of a union renders the program ill-formed.</del> [Note 4: After the call to a constructor for class X ... -- end note ] [Example 6: ... -- end example ] An attempt to initialize more than one non-static data member of a union renders the program ill-formed. An object's initialization is considered complete when a non-delegating constructor for that object returns. [Note: Therefore, an object's lifetime can begin (6.8.4 [[basic.life](https://wg21.link/basic.life)]) before all delegating constructors have completed. -- end note]
2. Change in 6.8.4 [[basic.life](https://wg21.link/basic.life#1.2)] bullet 1.2 as follows: ... The lifetime of an object of type T begins when: storage with the proper alignment and size for type T is obtained, and its initialization (if any) is complete (including vacuous initialization) (9.5 [[dcl.init](https://wg21.link/dcl.init)]<ins>, 11.9.3 [[class.base.init](https://wg21.link/class.base.init)]</ins>), except that ...

**CWG 2023-10-20**

Utterances about "during construction or destruction" in 11.9.5 [[class.cdtor](https://wg21.link/class.cdtor)] need to be adjusted.

**Proposed resolution (approved by CWG 2026-05-19):**

1. Split and change 11.9.3 [[class.base.init](https://wg21.link/class.base.init#9)] paragraph 9 as follows: [Note 3: An abstract class ... -- end note ] <del>An attempt to initialize more than one non-static data member of a union renders the program ill-formed.</del> [Note 4: After the call to a constructor for class X ... -- end note ] [Example 6: ... -- end example ] An attempt to initialize more than one non-static data member of a union renders the program ill-formed. An object's initialization is considered complete when a non-delegating constructor for that object returns. [Note: Therefore, an object's lifetime can begin (6.8.4 [[basic.life](https://wg21.link/basic.life)]) before all delegating constructors have completed. -- end note]
2. Change in 6.8.4 [[basic.life](https://wg21.link/basic.life#1.2)] bullet 1.2 as follows: ... The lifetime of an object of type T begins when: storage with the proper alignment and size for type T is obtained, and its initialization (if any) is complete (including vacuous initialization) (9.5 [[dcl.init](https://wg21.link/dcl.init)]<ins>, 11.9.3 [[class.base.init](https://wg21.link/class.base.init)]</ins>), except that ...
3. Change in 11.9.5 [[class.cdtor](https://wg21.link/class.cdtor#2)] paragraph 2 as follows: During the <del>construction</del> <ins>initialization</ins> of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor's this pointer, the value of the object or subobject thus obtained is unspecified.

**CWG 2026-05-19**

For e.g. a virtual base class VB that inherits constructors, the vtable will not be in its final state while executing inheriting constructors of VB, therefore 11.9.5 [[class.cdtor](https://wg21.link/class.cdtor#4)] paragraph 4 through 6 are correct as written.

---

#### Non-deduced context for qualified-id naming a template

Section: 

13.10.3.6  [

temp.deduct.type

]

Status: 

ready

Submitter: 

Hubert Tong

Date: 

2024-12-27

(From submission [#660](https://github.com/cplusplus/CWG/issues/660).)

Subclause 13.10.3.6 [[temp.deduct.type](https://wg21.link/temp.deduct.type#5.1)] bullet 5.1 specifies as a non-deduced context:

> - The *nested-name-specifier* of a type that was specified using a *qualified-id*.
> - ...

This does not cover templates named using a *qualified-id*:

```
  template <template <typename> class>
  struct B;

  struct C {
    template <typename>
    struct Nested;
  };

  template <typename T>
  void f(T *, B<T::template Nested> *);

  void g(C *cp) {
    f(cp, 0);           // should be OK
  }
```

**Proposed resolution (approved by CWG 2026-05-29):**

Change in 13.10.3.6 [[temp.deduct.type](https://wg21.link/temp.deduct.type#5.1)] bullet 5.1 as follows:

> - The *nested-name-specifier* of a type <ins>or template</ins> that was specified using a *qualified-id*.
> - ...

---

#### Default arguments in list-initialization

Section: 

9.5.5  [

dcl.init.list

]

Status: 

ready

Submitter: 

Brian Bi

Date: 

2025-04-24

Consider:

```
  #include <iostream>
  struct I {
    I(int x) { std::cout << x; }
  };
  struct S {
    S(I, I = 2) {}
  };
  int main() {
    S(1, 2); std::cout << '\n';  // unspecified order; prints 12 or 21
    S{1, 2}; std::cout << '\n';  // prints 12 (9.5.5 [dcl.init.list] paragraph 4)
    S{1};                        // ???
  }
```

Since no *initializer-clause* is present for the second argument, 9.5.5 [[dcl.init.list](https://wg21.link/dcl.init.list#4)] paragraph 4 does not, but should, prescribe lexical ordering of the argument evaluations.

**Proposed resolution (approved by CWG 2026-06-10):**

Change in 9.5.5 [[dcl.init.list](https://wg21.link/dcl.init.list#4)] paragraph 4 as follows:

> Within the *initializer-list* of a *braced-init-list*, the *initializer-clause*s, including any that result from pack expansions (13.7.4 [[temp.variadic](https://wg21.link/temp.variadic)]), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given *initializer-clause* is sequenced before every value computation and side effect associated with any *initializer-clause* that follows it in the comma-separated list of the *initializer-list*. <ins>If the *initializer-clause*s of the *initializer-list* are interpreted as arguments of a constructor call (12.2.2.8 [[over.match.list](https://wg21.link/over.match.list)]), any default arguments used are evaluated in the order as if an *initializer-clause* were present for the corresponding parameter.</ins>
> 
> [*Note 4:* This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the *initializer-list* are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. <ins>[ Example:</ins>
> 
> ```
>   #include <iostream>
>   struct I {
>     I(int x) { std::cout << x; }
>   };
>   struct S {
>     S(I, I = 2) {}
>   };
>   int main() {
>     S(1, 2); std::cout << '\n';  // unspecified order; prints 12 or 21
>     S{1, 2}; std::cout << '\n';  // prints 12
>     S{1};                        // prints 12
>   }
> ```
> 
> <ins>-- end example ]</ins> —*end note*]

---

#### Equivalence of pack-index-specifiers

Section: 

13.6  [

temp.type

]

Status: 

ready

Submitter: 

Corentin Jabot

Date: 

2025-04-14

(From submission [#700](https://github.com/cplusplus/CWG/issues/700).)

Subclause 13.6 [[temp.type](https://wg21.link/temp.type#5)] paragraph 5 and paragraph 6 specify:

> For a type template parameter pack T, T...[constant-expression] denotes a unique dependent type.
> 
> If the *constant-expression* of a *pack-index-specifier* is value-dependent, two such *pack-index-specifier*s refer to the same type only if their *constant-expression*s are equivalent (13.7.7.2 [[temp.over.link](https://wg21.link/temp.over.link)]). Otherwise, two such *pack-index-specifier* s refer to the same type only if their indexes have the same value.

That seems to imply that *pack-index-specifier*s referring to different template parameter packs could be equivalent.

**Proposed resolution (approved by CWG 2026-05-19):**

Change and merge in 13.6 [[temp.type](https://wg21.link/temp.type#5)] paragraph 5 and paragraph 6 as follows:

> For a type template parameter
> pack
> 
> T
> 
> ,
> 
> T
> 
> ...[
> 
> constant-expression
> 
> ] denotes a
> unique dependent type.
> 
> If the *constant-expression* of
> a *pack-index-specifier* is value-dependent, two
> 
> Two
> 
> such
> 
> pack-index-specifier
> 
> s
> (9.2.9.4 [
> 
> dcl.type.pack.index
> 
> ]) refer to the same type only if
> 
> - their *typedef-name*s refer to the same template parameter pack and
> - <ins>if neither of their *constant-expression*s is value-dependent, then they have the same value, otherwise</ins> their *constant-expression*s are equivalent (13.7.7.2 [[temp.over.link](https://wg21.link/temp.over.link)])<ins>.</ins>
> 
> Otherwise, two such *pack-index-specifier* s refer to the
> same type only if their indexes have the same value.

---

#### Enumerations as part of the common initial sequence

Section: 

9.8.1  [

dcl.enum

]

Status: 

ready

Submitter: 

Benjamin Sch.

Date: 

2025-07-28

(From submission [#732](https://github.com/cplusplus/CWG/issues/732).)

Consider:

```
  #include <iostream>
  #include <type_traits>

  enum E { E0 } e;
  enum F { F0, F1, F2, F3 };
  static_assert(std::is_same_v<std::underlying_type_t<E>, std::underlying_type_t<F>>);  // assume this passes

  struct A { E e; };
  struct B { F f; };
  union U {
    A a;
    B b;
  } u;

  bool test() {
    return u.a.e == 2;
  }

  auto ptest = test;

  int main() {
    u.b.f = F2;
    std::cout << ptest();
  }
```

Both u.a and u.b are part of the common initial sequence, allowing u.a.e to read the value of u.a.f, even though E cannot represent all values of F.

**Proposed resolution (approved by CWG 2026-05-29):**

Change in 9.8.1 [[dcl.enum](https://wg21.link/dcl.enum#10)] paragraph 10 as follows:

> Two enumeration types are
> 
> layout-compatible enumerations
> 
> if they have
> the same underlying type
> 
> and the same values
> 
> .

---

#### Usual arithmetic conversions for enumerations are different in C

Section: 

C.7.4  [

diff.expr

]

Status: 

ready

Submitter: 

Hubert Tong

Date: 

2025-12-09

(From submission [#829](https://github.com/cplusplus/CWG/issues/829).)

C23 converts values of an enumeration type to the underlying type of the enumeration type (which might be different from int), but enumerators always have type int. In contrast, in C++ enumerators have the type of their enumeration and integral promotions are performed, which are independent of the implementation's choice of underlying type.

**Proposed resolution (approved by CWG 2026-06-10):**

Add a new entry in C.7.4 [[diff.expr](https://wg21.link/diff.expr)] as follows:

> Affected subclause
> 
> : 7.4 [
> 
> expr.arith.conv
> 
> ]
> 
> Change
> 
> : The usual arithmetic conversions differ, between C and C++, in
> the treatment of enumeration types with no fixed underlying type. In
> C++, values of such types are not specified as converting to the
> underlying type of the enumeration as part of the usual arithmetic
> conversions. Instead, integral promotions (7.3.7 [
> 
> conv.prom
> 
> ])
> based on the values of the enumeration (9.8.1 [
> 
> dcl.enum
> 
> ])
> are applied.
> 
> Rationale
> 
> : Avoids the difference that can arise in C when replacing an
> enumeration constant in an expression with a cast of the same
> enumeration constant to the enumeration type. Allows C++ to treat an
> enumerator with behavior like that of
> 
> int
> 
> even while giving
> the enumerator the type of its enumeration.
> 
> Effect on original feature
> 
> : Changes to semantics of well-defined
> feature. Some C expressions that have a dependence upon the
> implementation-defined underlying type of affected enumeration types
> will yield different results (as they would if a different underlying
> type is chosen by the C implementation).
> 
> [Example:
> 
> ```
>   typedef enum { E0 } E;         // the underlying type of E can be unsigned int
>   static_assert(((E)E0 - 1 < 0) == (E0 - 1 < 0), "Must pass for C++");
> ```
> 
> The
> 
> static_assert
> 
> may fail in C. -- end example]
> 
> Difficulty of converting
> 
> : Programs must add explicit casts to the underlying type.
> 
> How widely used
> 
> : Rare.

---

#### Instantiation of variables with incomplete array types

Section: 

13.9.2  [

temp.inst

]

Status: 

ready

Submitter: 

Richard Smith

Date: 

2025-04-01

(From submission [#843](https://github.com/cplusplus/CWG/issues/843).)

When a variable has an incomplete array type and a braceed initializer, the complete array type can be determined by instantiating a definition of the variable; see 13.9.2 [[temp.inst](https://wg21.link/temp.inst#4)] paragraph 4 and 13.9.2 [[temp.inst](https://wg21.link/temp.inst#7)] paragraph 7. The level of tracking differs between implementations.

```
  // Case 1: Clang rejects because the type of `*p` changes
  // between redeclarations; Clang seems to be incorrect:
  // The array bound affects the semantics of the program.
  template<typename T> struct X {
    static inline int arr[] = {1, 2, 3};
  };

  // Clang does not instantiate a definition here.
  extern decltype(X<int>::arr) *p;
  // Clang does instantiate a definition here.
  int n = sizeof(X<int>::arr);
  decltype(X<int>::arr) *p;

  // Case 2: GCC, EDG, MSVC reject because they instantiate a definition
  // of `X<int>::arr` even though it's not odr-used and doesn't appear to
  // affect the semantics of the program.
  template<typename T> struct X {
    static inline int arr[] = {1, 2, T::error};
  };

  // The array bound here doesn't matter; array-to-pointer decay doesn't
  // care about it.
  decltype(+X<int>::arr) r;

  // Case 3: GCC and clang accept; MSVC rejects because it instantiates a definition
  // of X<int>::arr even though it's not odr-used and its type is complete.
  // EDG rejects because it instantiates the definition of arr while instantiating X<int>.
  template<typename T> struct X {
    static inline int arr[3] = {1, 2, T::error};
  };

  // No definition needed, thus the initializer is not instantiated.
  decltype(+X<int>::arr) r;
```

**Proposed resolution (approved by CWG 2026-05-08):**

Add a new paragraph after 13.9.2 [[temp.inst](https://wg21.link/temp.inst#8)] paragraph 8 as follows:

> 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
> (7.7 [
> 
> expr.const
> 
> ]), even if constant evaluation of the
> expression is not required or if constant expression evaluation does
> not use the definition. [ Example: ... ]
> 
> Similarly, the existence of a definition of a variable or function is considered to affect the semantics of the program if the instantiation is necessary to determine the type of an expression in the program, even if the variable or function is not odr-used (6.3 [[basic.def.odr](https://wg21.link/basic.def.odr)]). [ Example:
> 
> ```
>   template<typename T> struct X {
>     static inline int arr[] = {1, 2, T::error};
>   };
>   decltype(+X<int>::arr) r;  // error: definition of X<int>::arr is instantiated to complete its type
> 
>   template<typename T> struct X2 {
>     static inline int arr[3] = {1, 2, T::error};
>   };
>   decltype(+X2<int>::arr) r2;  // OK, type of arr is complete and arr is not odr-used
> ```
> 
> -- end example ]

---

#### Location of specification of __STDCPP_FLOAT16_T__ macro

Section: 

15.12  [

cpp.predefined

]

Status: 

ready

Submitter: 

Jay Ghiron

Date: 

2026-02-15

(From submission [#851](https://github.com/cplusplus/CWG/issues/851).)

The macros for the extended floating-point types are presented in a paragraph where unconditionally-defined macros are specified. However, those macros are conditionally defined and their presentation should be moved to the appropriate paragraph.

**Proposed resolution (approved by CWG 2026-04-28):**

1. Move the following macro definitions from 15.12 [[cpp.predefined](https://wg21.link/cpp.predefined#1)] paragraph 1 as follows: The following macro names shall be defined by the implementation: __STDCPP_FLOAT16_T__ Defined as the integer literal 1 if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary16 as an extended floating-point type (6.9.3 [[basic.extended.fp](https://wg21.link/basic.extended.fp)]). __STDCPP_FLOAT32_T__ Defined as the integer literal 1 if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary32 as an extended floating-point type. __STDCPP_FLOAT64_T__ Defined as the integer literal 1 if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary64 as an extended floating-point type. __STDCPP_FLOAT128_T__ Defined as the integer literal 1 if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary128 as an extended floating-point type. __STDCPP_BFLOAT16_T__ Defined as the integer literal 1 if and only if the implementation supports an extended floating-point type with the properties of the typedef-name std::bfloat16_t as described in 6.9.3 [[basic.extended.fp](https://wg21.link/basic.extended.fp)].
2. Add the macro definitions to 15.12 [[cpp.predefined](https://wg21.link/cpp.predefined#2)] paragraph 2 with the indicated changes as follows: The following macro names are conditionally defined by the implementation: __STDCPP_FLOAT16_T__ Defined<ins>, and has the value</ins> integer literal 1<ins>,</ins> if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary16 as an extended floating-point type (6.9.3 [[basic.extended.fp](https://wg21.link/basic.extended.fp)]). __STDCPP_FLOAT32_T__ Defined<ins>, and has the value</ins> integer literal 1<ins>,</ins> if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary32 as an extended floating-point type. __STDCPP_FLOAT64_T__ Defined <ins>, and has the value</ins> integer literal 1<ins>,</ins> if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary64 as an extended floating-point type. __STDCPP_FLOAT128_T__ Defined<ins>, and has the value</ins> integer literal 1<ins>,</ins> if and only if the implementation supports the ISO/IEC 60559 floating-point interchange format binary128 as an extended floating-point type. __STDCPP_BFLOAT16_T__ Defined<ins>, and has the value</ins> integer literal 1<ins>,</ins> if and only if the implementation supports an extended floating-point type with the properties of the typedef-name std::bfloat16_t as described in 6.9.3 [[basic.extended.fp](https://wg21.link/basic.extended.fp)].

---

#### Protected access rule for a pointer-to-member from a reflect-expression

Section: 

7.6.2.10  [

expr.reflect

]

Status: 

ready

Submitter: 

Brian Bi

Date: 

2026-02-17

(From submission [#852](https://github.com/cplusplus/CWG/issues/852).)

Consider:

```
  class A {
  protected:
    void f();
  };

  struct B : A {
    static constexpr auto r = ^^A::f;
  };
```

Do the restrictions in 11.8.5 [[class.protected](https://wg21.link/class.protected)] on the use of expression &A::f apply to the *reflect-expression*?

Suggested resolution [SUPERSEDED]:

Change in 7.6.2.10 [[expr.reflect](https://wg21.link/expr.reflect#7.2)] bullet 7.2 as follows:

> A
> 
> reflect-expression
> 
> R of the form
> 
> ^^
> 
> id-expression
> 
> represents an entity determined as
> follows:
> 
> - ...
> - Otherwise, if the *id-expression* denotes an overload set S, <del>overload resolution for the expression &S with no target shall select a unique function (12.3 [[over.over](https://wg21.link/over.over)])</del> <ins>the expression &*id-expression* shall be well-formed when considered as an unevaluated operand</ins>; R represents <del>that</del> <ins>the</ins> function <ins>selected by overload resolution (12.3 [[over.over](https://wg21.link/over.over)])</ins>.

**CWG 2026-05-08**

Reflection supports deleted functions, but the phrasing above does not.

**Proposed resolution (approved by CWG 2026-05-19):**

Change in 7.6.2.10 [[expr.reflect](https://wg21.link/expr.reflect#7.2)] bullet 7.2 as follows:

> A
> 
> reflect-expression
> 
> R of the form
> 
> ^^
> 
> id-expression
> 
> represents an entity determined as
> follows:
> 
> - ...
> - Otherwise, if the *id-expression* denotes an overload set S, <del>overload resolution for the expression &S with no target shall select a unique function (12.3 [[over.over](https://wg21.link/over.over)])</del> <ins>the expression &*id-expression* shall be well-formed when considered as an unevaluated operand, except that the function *F* selected as described in 12.3 [[over.over](https://wg21.link/over.over)] may be deleted (9.6.3 [[dcl.fct.def.delete](https://wg21.link/dcl.fct.def.delete)])</ins>; R represents <del>that function</del> <ins>*F*</ins> .

---

#### Initializing typedefs

Section: 

9.5  [

dcl.init

]

Status: 

ready

Submitter: 

Bee

Date: 

2026-02-27

(From submission [#856](https://github.com/cplusplus/CWG/issues/856).)

Consider:

```
  typedef int x = 0;
```

There is no prohibition against this.

**Proposed resolution (approved by CWG 2026-05-08):**

1. Add before 9.3.1 [[dcl.decl.general](https://wg21.link/dcl.decl.general#4)] paragraph 4 and change paragraphs 4 and 5 as follows: The *initializer* of an *init-declarator* shall not be present unless the declarator declares a variable and the host scope (6.4.1 [[basic.scope.scope](https://wg21.link/basic.scope.scope)]) of the declaration is the same as its target scope. The optional *requires-clause* <del>in</del> <ins>of</ins> an *init-declarator* or *member-declarator* shall <ins>not</ins> be present <del>only if</del> <ins>unless</ins> the declarator declares a templated function (13.1 [[temp.pre](https://wg21.link/temp.pre)]). ... The optional *function-contract-specifier-seq* (9.4.1 [[dcl.contract.func](https://wg21.link/dcl.contract.func)]) <del>in</del> <ins>of</ins> an *init-declarator* shall <ins>not</ins> be present <del>only if</del> <ins>unless</ins> the declarator declares a function.
2. Remove 9.5.1 [[dcl.init.general](https://wg21.link/dcl.init.general#5)] paragraph 5 as follows: A declaration D of a variable with linkage shall not have an initializer if D inhabits a block scope.

---

#### Issues with integer conversion ranks

Section: 

6.9.6  [

conv.rank

]

Status: 

ready

Submitter: 

Jay Ghiron

Date: 

2026-03-01

(From submission [#856](https://github.com/cplusplus/CWG/issues/856).)

First, the rule about the conversion rank of signed integer types wrongly implies that char, if it is signed, would be a signed integer type.

Second, the rule about the conversion rank of bool allows it have a greater rank than extended integer types.

See also [WG14 paper N3747](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3747.pdf).

**Proposed resolution (approved by CWG 2026-05-08):**

Change in 6.9.6 [[conv.rank](https://wg21.link/conv.rank#1)] paragraph 1 as follows:

> Every integer type has an integer conversion rank defined as follows:
> 
> - No two signed integer types <del>other than char and signed char (if char is signed)</del> have the same rank, even if they have the same representation.
> - ...
> - The rank of char equals the rank of signed char and unsigned char.
> - The rank of bool is less than the rank of all <del>standard</del> <ins>other</ins> integer types.
> - The ranks of <del>char8_t, char16_t, char32_t, and wchar_t</del> <ins>the character types</ins> equal the ranks of their <ins>corresponding</ins> underlying types (6.9.2 [[basic.fundamental](https://wg21.link/basic.fundamental)]).
> - ...

---

#### Sequencing default arguments during constant evaluation

Section: 

6.10.1  [

intro.execution

]

Status: 

ready

Submitter: 

Lénárd Szolnoki

Date: 

2026-03-09

(From submission [#859](https://github.com/cplusplus/CWG/issues/859).)

According to 6.10.1 [[intro.execution](https://wg21.link/intro.execution#16)] paragraph 16, lexical order is used for sequencing during constant evalution. It is unclear how that applies to default arguments used in a function call.

**Proposed resolution (approved by CWG 2026-06-10):**

Change in 6.10.1 [[intro.execution](https://wg21.link/intro.execution#16)] paragraph 16 as follows:

> During the evaluation of an expression as a core constant expression
> (7.7 [
> 
> expr.const
> 
> ]), evaluations of operands of individual
> operators and of subexpressions of individual expressions that are
> otherwise either unsequenced or indeterminately sequenced are
> evaluated in lexical order.
> 
> For a function call
> (7.6.1.3 [[expr.call](https://wg21.link/expr.call)]), any default arguments used are evaluated in
> the order as if an argument were present for the corresponding
> parameter.

---

#### Formation of a header-name preprocessing token

Section: 

5.5  [

lex.pptoken

]

Status: 

ready

Submitter: 

Richard Smith

Date: 

2026-04-08

(From submission [#881](https://github.com/cplusplus/CWG/issues/881).)

The rules inn 5.5 [[lex.pptoken](https://wg21.link/lex.pptoken#5.4.2.1)] bullet 5.4.2.1 and 15.1 [[cpp.pre](https://wg21.link/cpp.pre#2.2)] bullet 2.2 form a circular definition when specifying the formation of a *header-name* preprocessing token.

**Proposed resolution (approved by CWG 2026-04-17):**

Change in 5.5 [[lex.pptoken](https://wg21.link/lex.pptoken#5.4)] bullet 5.4 as follows:

> - ...
> - Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail, except that
>   - a *string-literal* token is never formed when a *header-name* token can be formed, and
>   - a *header-name* (5.6 [[lex.header](https://wg21.link/lex.header)]) is only formed <ins>A preprocessing token is considered to be *immediately after* another preprocessing token if the preprocessing tokens are on the same logical source line and there are no intervening preprocessing tokens.</ins>
>     - immediately after the include<del>,</del> <ins>or</ins> embed<del>, or import</del> preprocessing token in a #include (15.3 [[cpp.include](https://wg21.link/cpp.include)])<del>,</del> <ins>or</ins> #embed (15.4 [[cpp.embed](https://wg21.link/cpp.embed)])<del>, or import (15.6 [[cpp.import](https://wg21.link/cpp.import)])</del> directive, respectively, or
>     - immediately after an import preprocessing token that is at the start of a logical source line, or
>     - immediately after a preprocessing token sequence of __has_include or __has_embed immediately followed by ( in a #if, #elif, or #embed directive (15.2 [[cpp.cond](https://wg21.link/cpp.cond)], 15.4 [[cpp.embed](https://wg21.link/cpp.embed)]).

---

#### More edge cases for a void function parameter

Section: 

9.3.4.6  [

dcl.fct

]

Status: 

ready

Submitter: 

Matheus Izvekov

Date: 

2026-04-21

(From submission [#889](https://github.com/cplusplus/CWG/issues/889).)

Consider:

```
  template<class T>
  struct S {
    using U = decltype((void)(T*)0);
    void f(U);   // #1
  };
  template<class T>
  void S<T>::f() {}  // redeclaration of #1?
```

Also consider:

```
  template<class T>
  struct S {
    void f(std::void_t<T*>);  // #1
  };
  S<int> x;  // #1 is a zero-parameter function or has an ill-formed parameter of type void
```

The current phrasing in 9.3.4.6 [[dcl.fct](https://wg21.link/dcl.fct#2)] paragraph 2 is the result of core issues 577 and 2915. The current rule, enabling typedefs for void, is primarily motivated by C compatibility.

Possible resolution (2026-04-22) [SUPERSEDED]:

Change in 9.3.4.6 [[dcl.fct](https://wg21.link/dcl.fct#3)] paragraph 3 as follows and split into two paragraphs:

> The *parameter-declaration-clause* determines the arguments that can be specified, and their processing, when the function is called. [*Note 1:* The *parameter-declaration-clause* is used to convert the arguments specified on the function call; see 7.6.1.3 [[expr.call](https://wg21.link/expr.call)]. —*end note*] If the *parameter-declaration-clause* is empty, the function takes no arguments. A <ins>parameter list (void) and, for a non-templated function, a</ins> parameter list consisting of a single unnamed non-object parameter of <del>non-dependent</del> type void <del>is</del> <ins>are</ins> equivalent to an empty parameter list. Except for <del>this</del> <ins>these</ins> special <del>case</del> <ins>cases</ins>, a parameter shall not have type cv void. A parameter with volatile-qualified type is deprecated; see D.4 [[depr.volatile.type](https://wg21.link/depr.volatile.type)].
> 
> If the *parameter-declaration-clause* terminates with an ellipsis or a function parameter pack (13.7.4 [[temp.variadic](https://wg21.link/temp.variadic)]), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs. Where syntactically correct and where “...” is not part of an *abstract-declarator* , “...” is synonymous with “, ...”. A *parameter-declaration-clause* of the form *parameter-declaration-list* ... is deprecated (D.5 [[depr.ellipsis.comma](https://wg21.link/depr.ellipsis.comma)]). ...

**CWG 2026-04-28**

Despite the fact that "equivalent type" is not well-defined (see issue 2584), the most appropriate approach is to use "equivalent type". Both examples above are ill-formed.

**Proposed resolution (approved by CWG 2026-06-10):**

Change in 9.3.4.6 [[dcl.fct](https://wg21.link/dcl.fct#3)] paragraph 3 as follows and split into two paragraphs:

> The *parameter-declaration-clause* determines the arguments that can be specified, and their processing, when the function is called. [*Note 1:* The *parameter-declaration-clause* is used to convert the arguments specified on the function call; see 7.6.1.3 [[expr.call](https://wg21.link/expr.call)]. —*end note*] If the *parameter-declaration-clause* is empty, the function takes no arguments. A parameter list consisting of a single unnamed non-object parameter <del>of non-dependent</del> <ins>whose</ins> type <ins>is the same as (13.7.7.2 [[temp.over.link](https://wg21.link/temp.over.link)])</ins> void is <del>equivalent to</del> <ins>interpreted as</ins> an empty parameter list. Except for this special case, a parameter shall not have type cv void. A parameter with volatile-qualified type is deprecated; see D.4 [[depr.volatile.type](https://wg21.link/depr.volatile.type)].
> 
> [ Example:
> 
> ```
>   template<class T>
>   struct S {
>     void f(std::void_t<T*>);  // #1
>   };
>   S<int> x;  // error: #1 has a parameter of type void
> 
>   template<class T>
>   struct S2 {
>     void f(std::void_t<int*>);  // #2
>   };
>   S2<int> y;  // OK, #2 is a zero-parameter function
> ```
> 
> -- end example ]
> 
> If the *parameter-declaration-clause* terminates with an ellipsis or a function parameter pack (13.7.4 [[temp.variadic](https://wg21.link/temp.variadic)]), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs. Where syntactically correct and where “...” is not part of an *abstract-declarator* , “...” is synonymous with “, ...”. A *parameter-declaration-clause* of the form *parameter-declaration-list* ... is deprecated (D.5 [[depr.ellipsis.comma](https://wg21.link/depr.ellipsis.comma)]). ...

---

#### Notional template parameters introduced for an array parameter

Section: 

13.10.3.2  [

temp.deduct.call

]

Status: 

ready

Submitter: 

Brian Bi

Date: 

2026-04-09

(From submission [#883](https://github.com/cplusplus/CWG/issues/883).)

Subclause 13.10.3.2 [[temp.deduct.call](https://wg21.link/temp.deduct.call#1)] paragraph 1 states:

> ... If removing references and cv-qualifiers from P gives
> std::initializer_list<P'> or P'[N] for some P' and N and the
> argument is a non-empty initializer list (9.5.5 [
> 
> dcl.init.list
> 
> ]),
> then deduction is performed instead for each element of the
> initializer list independently, taking P' as separate function
> template parameter types P'i and the ith initializer element as the
> corresponding argument. ...

There is no requirement that the deduction results for all such independent deductions agree, or be non-deduced contexts.

**Proposed resolution (approved by CWG 2026-05-19):**

Change in 13.10.3.2 [[temp.deduct.call](https://wg21.link/temp.deduct.call#1)] paragraph 1 as follows:

> ... If removing references and cv-qualifiers from P gives
> std::initializer_list<P'> or P'[N] for some P' and N and the
> argument is a non-empty initializer list (9.5.5 [
> 
> dcl.init.list
> 
> ]),
> then deduction is
> 
> instead
> 
> performed
> 
> instead for each
> element of the initializer list independently, taking P' as separate
> function template parameter types P'i and the ith initializer element
> as the corresponding argument
> 
> as if each element of the
> initializer list were the argument for a separate parameter having
> type P'
> 
> . ...

---

#### No expressions in an expression-list

Section: 

7.6.1.3  [

expr.call

]

Status: 

ready

Submitter: 

Vlad Serebrennikov

Date: 

2026-04-13

(From submission [#886](https://github.com/cplusplus/CWG/issues/886).)

Consider 7.6.1.3 [[expr.call](https://wg21.link/expr.call#7)] paragraph 7:

> The
> 
> postfix-expression
> 
> is sequenced before
> each
> 
> expression
> 
> in the
> 
> expression-list
> 
> and any default
> argument. ...

However, an *expression-list* is an *initializer-list* and consists of *initializer-clause*.

**Proposed resolution (approved by CWG 2026-04-28):**

Change in 7.6.1.3 [[expr.call](https://wg21.link/expr.call#7)] paragraph 7 as follows:

> The
> 
> postfix-expression
> 
> is sequenced before
> each
> 
> *expression*
> 
> *initializer-clause*
> 
> in the
> 
> expression-list
> 
> and any default argument. ...

---

#### Pointer arithmetic with similar types

Section: 

7.6.6  [

expr.add

]

Status: 

ready

Submitter: 

Jay Ghiron

Date: 

2026-04-26

(From submission [#892](https://github.com/cplusplus/CWG/issues/892).)

Consider:

```
char**p;
int diff = p - (const char * const *)p;
```

This is ill-formed per 7.6.6 [[expr.add](https://wg21.link/expr.add#2)] paragraph 2, but ought to be allowed, in harmony with 7.6.9 [[expr.rel](https://wg21.link/expr.rel#3)] paragraph 3, 7.6.10 [[expr.eq](https://wg21.link/expr.eq#3)] paragraph 3, and 7.6.16 [[expr.cond](https://wg21.link/expr.cond#4)] paragraph 4.

**Proposed resolution (approved by CWG 2026-06-10):**

Change in 7.6.6 [[expr.add](https://wg21.link/expr.add#2)] paragraph 2 as follows:

> For subtraction, one of the following shall hold:
> 
> - both operands have arithmetic type; or
> - both operands are pointers to <del>cv-qualified or cv-unqualified versions of the same</del> <ins>similar (7.3.6 [[conv.qual](https://wg21.link/conv.qual)])</ins> <del>completely-defined</del> <ins>complete</ins> object <del>type</del> <ins>types</ins>; or
> - the left operand is a pointer to a completely-defined object type and the right operand has integral type.

---

#### Argument-dependent lookup is for a name

Section: 

6.5.4  [

basic.lookup.argdep

]

Status: 

ready

Submitter: 

CWG

Date: 

2026-04-25

(From submission [#891](https://github.com/cplusplus/CWG/issues/891).)

Consider:

```
  namespace N {
    struct C {
      friend void f(C);
      friend void g(C);
    };
  }

  void h() {
    f(N::C{});
  }
```

According to 6.5.4 [[basic.lookup.argdep](https://wg21.link/basic.lookup.argdep#4)] paragraph 4, argument-dependent lookup finds functions without considering their names (such as g in the example above). This is misguided.

**Proposed resolution (approved by CWG 2026-05-19):**

Change in 6.5.4 [[basic.lookup.argdep](https://wg21.link/basic.lookup.argdep#4)] paragraph 4 as follows:

> The associated namespaces for a call are the innermost enclosing
> non-inline namespaces for its associated entities as well as every
> element of the inline namespace set (9.9.2 [
> 
> namespace.def
> 
> ]) of
> those namespaces. Argument-dependent lookup
> 
> for a
> name *N*
> 
> finds all declarations of functions and function
> templates
> 
> named *N*
> 
> that
> 
> - are found by a search <del>of</del> <ins>for *N* in</ins> any associated namespace, or
> - are declared as a friend (11.8.4 [[class.friend](https://wg21.link/class.friend)]) of any class with a reachable definition in the set of associated entities, or
> - are exported, are attached to a named module M (10.2 [[module.interface](https://wg21.link/module.interface)]), do not appear in the translation unit containing the point of the lookup, and have the same innermost enclosing non-inline namespace scope as a declaration of an associated entity attached to M (6.7 [[basic.link](https://wg21.link/basic.link)]).
> 
> If
> 
> the lookup is for a
> 
> *N* is a
> 
> dependent name (13.8.3 [
> 
> temp.dep
> 
> ],
> 13.8.4.2 [
> 
> temp.dep.candidate
> 
> ]), the above lookup is also performed
> from each point in the instantiation context
> (10.6 [
> 
> module.context
> 
> ]) of the lookup, additionally ignoring any
> declaration that appears in another translation unit, is attached to
> the global module, and is either discarded (10.4 [
> 
> module.global.frag
> 
> ])
> or has internal linkage.

---

#### Behavior change for class template argument deduction

Section: 

C.2  [

diff.cpp20

]

Status: 

ready

Submitter: 

Christof Meerwald

Date: 

2026-04-30

Consider:

```
   template<typename T>
   struct B {
     B(T);
   };

   template<typename T>
   struct D : B<T *> {
     D(T);
     using B<T *>::B;
     T m = "a";   // #1
   };

   D d("");       // #1 is OK with C++20 (T deduced as const char*), but ill-formed with C++23 (T deduced as const char)
```

**Proposed resolution (approved by CWG 2026-06-10):**

Add a new subclause in C.2 [[diff.cpp20](https://wg21.link/diff.cpp20)] as follows:

> **C.2.5+ Clause 12: overloading [diff.cpp20.over]**
> 
> Affected subclause:
> 
> 12.2.2.9 [
> 
> over.match.class.deduct
> 
> ]
> 
> Change:
> 
> Deducing class template arguments from inherited constructors.
> 
> Rationale:
> 
> Making class template argument deduction consistent with construction.
> 
> Effect on original feature:
> 
> Valid ISO C++ 2020 code may become
> ill-formed or change meaning.
> 
> [Example 1 :
> 
> ```
>    template<typename T>
>    struct B {
>      B(T);
>    };
> 
>    template<typename T>
>    struct D : B<T *> {
>      D(T);
>      using B<T *>::B;
>      T m = "a";   // #1
>    };
> 
>    D d("");       // ill-formed at #1 (T deduced as const char); previously well-formed (T deduced as const char*)
> ```
> 
> -- end example]

---

#### Ambiguous lookup for type aliases in reflection

Section: 

7.6.2.10  [

expr.reflect

]

Status: 

ready

Submitter: 

Richard Smith

Date: 

2026-05-06

Consider:

```
  namespace A {
    using T = int;
  }
  namespace B {
    using T = int;
  }
  using namespace A;
  using namespace B;
  T t;                // #1, OK
  auto r = ^^T;       // #2, ???
```

While 6.1 [[basic.pre](https://wg21.link/basic.pre#8)] paragraph 8 clarifies that #1 is well-formed by considering the underlying type, the treatment of #2 is unclear.

Possible resolution (option 2) [SUPERSEDED]:

Change in 7.6.2.10 [[expr.reflect](https://wg21.link/expr.reflect#5)] paragraph 5 as follows:

> - ...
> - Otherwise, if lookup finds a namespace alias (9.9.3 [[namespace.alias](https://wg21.link/namespace.alias)]), R represents <del>that</del> <ins>an unspecified</ins> namespace alias <ins>among the lookup results</ins>.
> - ...
> - Otherwise, if lookup finds a type alias A, R represents the underlying entity of A if A was introduced by the declaration of a template parameter; otherwise, R represents <del>A</del> <ins>an unspecified type alias among the lookup results</ins>. [ Example: namespace A { using T = int; } namespace B { using T = int; } using namespace A; using namespace B; auto r = ^^T; // OK, represents either A::T or B::T -- end example ]
> - ...

**Proposed resolution (approved by CWG 2026-06-10):**

Change in 7.6.2.10 [[expr.reflect](https://wg21.link/expr.reflect#5)] paragraph 5 as follows:

> - ...
> - Otherwise, if lookup finds a namespace alias (9.9.3 [[namespace.alias](https://wg21.link/namespace.alias)]), <ins>all declarations found by name lookup shall have the same target scope, and</ins> R represents <del>that</del> <ins>the</ins> namespace alias.
> - ...
> - Otherwise, if lookup finds a type alias <del>A,</del><ins>:</ins> [ Example: namespace A { using T = int; } namespace B { using T = int; } using namespace A; using namespace B; auto r = ^^T; // error: lookup finds type aliases with different target scopes -- end example ]
>   - <ins>If any declaration found by name lookup is of a template parameter T,</ins> R represents the underlying entity of <ins>T.</ins> <del>A if A was introduced by the declaration of a template parameter; otherwise,</del>
>   - <ins>Otherwise, all declarations found by name lookup shall have the same target scope, and</ins> R represents <del>A</del> <ins>the type alias</ins>.
> - ...

**CWG 2026-05-19**

Seeking EWG's approval via [paper issue #2795](https://github.com/cplusplus/papers/issues/2795).

**EWG 2026-06-08**

EWG approved the proposed resolution.
