À propos de WG21, Varna 2023 (juin)

Je participe à cette rencontre à distance (elle se passe en Bulgarie et il n'était pas possible pour moi d'y aller).

Les principaux thèmes de la rencontre sont la progression des travaux pour C++ 26.

Tout ce qui suit est anonymisé et simplifié, dans le respect du code de conduite d'ISO en vigueur lors de nos rencontres.

Ce document est incomplet (j'ai manqué de temps). Je compléterai dès que possible.

Pour les « journaux de voyage » d'autres participants, voir :

Jour 0 12 juin 2023

J'arrive avec quelques minutes de retard (il est 2h du matin chez moi et je cherche le mot de passe pour me connecter; je ne suis pas pleinement réveillé encore car les infos sont très claires). Nos hôtes (Chaos, une boîte d'imagerie qui se spécialise dans le Ray Tracing – ils ont été impliqués dans les effets spéciaux de Game of Thrones – et VMWare) nous acccueillent et essaient de voir qui participera à certains événements périphériques (incluant une séance sur l'alphabet cyrillique en milieu de semaine, très chouette idée). Nous sommes 40 à participer à distance aujourd'hui.

John Spicer présente les consignes d'usage (qui peut voter, comment se comporter, etc.), puis les nouveaux membres se présentent. Ce qu'il y a de bien à se déplacer à divers endroits dans le monde, c'est qu'on donne une occasion à des gens qu'on ne voit pas souvent de se présenter. Herb Sutter prend les présence pour les National Bodies; il y en a 18 aujourd'hui.

Je me fais une cruche de café après la plénière (il y a une pause avant le début des travaux). Il est 3h du matin à la maison. Ce sera une étrange semaine pour le biorythme.

Chez Core, Jens Maurer s'affaire à organiser la logistique. C'est un héros, sérieusement. On examine l'organisation de la semaine (on perdra des joueurs à quelques moments clés, surtout pendant la rencontre de SG21 sur les contrats, alors il faut s'assurer que les personnes clés soient dans la salle pour les sujets qui les concernent).

p2828r1 – Copy elision for direct-initialization with a conversion function (Core issue 2327)

Cette proposition tente de faire en sorte que les conversions entre deux types soient possibles même lorsque les constructeurs de copie et de mouvement sont supprimés, dans la mesure où un opérateur de conversion approprié existe. Exemple :

struct Cat {
    Cat() = default;
  private:
    Cat(const Cat&) = delete;
    Cat(Cat&&) = delete;
};

struct Dog { operator Cat(); };

Dog d;
Cat c(d);  // OK; calls Dog::operator Cat

Avec le langage existant, on a des divergences d'implémentation dans de tels cas. Après avoir établi que le Core Language existant était l'enjeu (que ce n'étais pas un bogue d'implémentation), on examine le texte pour s'assurer qu'il mène bien là où son auteur souhaite nous amener. Entre autres, il faut s'assurer qu'il est clair dans le texte que le constructeur n'est pas appelé pour réaliser l'initialisation. J'ai une crainte que cela ne brise le Passkey Idiom, mais ce n'est pas le cas (il faut que, dans cet exemple, Dog puisse appeler un constructeur de Cat après tout).

On examine l'avenue d'ajouter une exception aux clauses expliquant l'impact de =delete mais cela entraîne un inconfort. Jens Maurer propose d'ajouter un terme pour nommer ce type d'initialisation par fonction de conversion et de définir des règles pour ce cas bien précis (on parlera de Conversion Initialization, manifestement). Mike Miller nous rappelle que la section sur Overload Resolution devra aussi être ajustée.

On reverra ceci cette semaine.

Core Issue 2102 – Constructor checking in new-expression

On a un problème avec du vieux texte :

« If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (11.4.11 [class.free]), and the constructor (11.4.5 [class.ctor]).  »

Le terme « ambiguity control » ne veut rien dire de formel, et les actes à poser ici ne peuvent être posés au moment indiqué dans le texte. La manière dont les tableaux sont décrits sont étranges aussi (on frappe des situations ... inconfortables avec new T[ ] sans valeur entre les crochets et le sens à y donner par exemple). On fait remarquer que [expr.delete] a des problèmes analogues.

C'est un dossier complexe qui recoupe plusieurs sections, mais certains sont d'avis qu'il n'y a pas d'enjeu. Shafik Yaghmour mentionne qu'il y a divergence d'implémentation dans ce cas.

(la pause du dîner arrive; je dois m'occuper du démarrage de la journée scolaire des enfants et j'ai des obligations familiales pour « l'après-midi » qui s'annonce – il est 5 h 30 du matin pour moi – alors je risque de manquer l'essentiel de ces travaux qui ont porté sur CWG2600 Type dependency of placeholder types, CWG1038 Overload resolution of &x.static_func, D1061R6 Structured Bindings can introduce a Pack, D2828R2 Copy elision for direct-initialization with a conversion function, CWG2729 Meaning of new-type-id)

Jour 1 7 février 2023

J'arrive à 1 h 30 du matin (8 h 30 heure de Varna) alors que les travaux commencent. Richard Corden qui est un régulier du passé et revient travailler avec nous se présente.

Core Issue 2725 – Overload resolution for non-call of class member access

Jens Maurer dit avoir découvert que cet exemple duplique... Core Issue 61, qui a 25 ans et était considéré NAD à l'époque. Le problème est que ceci :

struct A {
   static void f();
   static void f(int);
} x;
void (*p)() = x.f;   // error

... et cela :

struct B {
   static void f();
} y;
void (*q)() = y.f;   // error

... ne compilent pas (ça n'a jamais fonctionné pour les fonctions membres non-static, et il fallait clarifier que ça ne fonctionnait pas pour les fonctions membres static). Nous avons désormais une proposition sur la table qui réglerait les deux. Mike Miller craint que les ajustements proposés ne soient pas suffisamment clairs en ce qui consiste un Member Function par rapport à un Member Function Call. Mike Miller et Jens Maurer discutent et on en vient à proposer de clarifier le propos par une référence croisée.

On officialisera cette position à Kona cet automne. Je ne suis pas certain de celle-là (j'aimerais bien que le 2e cas compile, mais faut ajouter & pour le moment).

Remplacer classifications par categories dans [basic.lval]

On examine un changement terminologique mineur dans cette clause. Mike Miller demande une précision, Jason Merrill pense que c'est superflu. On approuve tout de même (c'est une légère amélioration).

p2828r2 – Copy elision for direct-initialization with a conversion function (Core issue 2327)

RS a regardé ce à quoi CWG est arrivé hier à ce sujet et pense que nous faisons fausse route. Son exemple est :

struct A {
  // A has no copy or move constructor.
  A(const A&) requires false;
};
A f();
struct B { operator A(); } b;

A a = f(); // ok, [dcl.init.general]/16.6.1
A a = b; // ok, [dcl.init.general]/16.6.3, via [over.match.copy]
A a(f()); // ok, [dcl.init.general]/16.6.1
A a(b); // error!

Il propose une approche alternative : réaliser l'Overload Resolution normalement et ajouter un Surrogate Constructor de signature C(C) silencieusement pour tenir compte de l'opérateur de conversion; ce constructeur ne serait valide que dans le cas où un opérateur de conversion en C serait disponible. Jason Merrill pense que cette nouvelle approche est plus compliquée encore que ce qui est sur la table. Brian Bi n'est pas certain que les deux approches donnent toujours les mêmes résultats. L'idée du Surrogate Constructor est qu'il n'apparaît que dans le tout dernier cas, quand les options de construction ont été explorées et qu'il ne reste que l'opérateur de conversion.

Les craintes de Mike Miller et Jason Merrill tiennent au fait qu'on veut vraiment éviter de toucher aux règles du Overload Resolution (apparemment, quand on touche à ça, on brise Windows). Après pas mal de discussions, on demeure partagés alors Jens Maurer décide de retirer P2828 des propositions pour vote et de recommander qu'on expérimente avant de procéder.

Core Issue 233 -- References vs pointers in UDC overload resolution

Le problème sur la table est :

struct Z { Z(){} };

struct A {
   Z x;

   operator Z *() { return &x; }
   operator const Z *() { return &x; }
};

struct B {
   Z x;

   operator Z &() { return x; }
   operator const Z &() { return x; }
};

int main() {
   A a;
   Z *a1=a;
   const Z *a2=a; // not ambiguous

   B b;
   Z &b1=b;
   const Z &b2=b; // ambiguous
}

Un autre cas est :

struct A {int a;};
struct B: public A { B() {}; int b;};

struct X {
   B x;
   operator A &() { return x; }
   operator B &() { return x; }
};

int main() {
   X x;
   A &g=x; // ambiguous
}

En gros, les références n'ont pas le traitement des pointeurs dans certains cas.

Brian Bi pense qu'on peut résoudre ceci, mais se demande si on veut le faire.

Shafik Yaghmour dit que le deuxième cas est accepté aujourd'hui par plusieurs compilateurs (le Core Issue est vieux de plus de vingt ans, alors le langage a changé depuis), alors l'enjeu qui reste est le cas const ou non-const. Jason Merrill fait remarquer que dans les conversions entre références sur un parent et sur un enfant, on ne semble pas parler de const ce qui est étrange (ommission involontaire?), car le cas cv-qualified pour deux références de même type, lui, est couvert.

Roger Orr penche pour laisser le cas ambigu, estimant que c'est probablement un bogue dans bien des cas, mais la salle penche plus vers un langage dont les règles sont plus uniformes. Brian Bi va retravailler le texte et ajouter un exemple.

Core Issue 2492 – Comparing user-defined conversion sequences in list-initialization

On a ceci :

#include <initializer_list>
struct A{
   operator short(){
      return 0;
   }
};
struct B{
   operator bool(){
      return 0;
   }
};
void fun(std::initializer_list<int>){}
void fun(std::initializer_list<bool>){}
int main(){
   fun({A{},B{}});
}

... ce qui est ambigu selon le standard, mais il y a divergence d'implémentations. On penche vers une clarification du fait que cet exemple devrait être ambigu. Les discussions portent sur les nuances entre les conversions standards (qui sont en nombre fini) et celles résultant du code client. Mike Miller va travailler le texte.

Roger Orr soulève que selon le texte, le moment où la conversion sequence est définie peut être inapproprié. Il faut comprendre que dans certains cas, le standard est un algorithme de relativement haut niveau, un peu comme du pseudocode, ce qui permet d'assurer une forme d'homogénéité comporementale entre les implémentations, ce qui peut avoir pour conséquence de briser les compilateurs si on fait certaines étapes dans le désordre (au passage, on attrape une note non-normative qui est incorrecte et devra être corrigée). Roger Orr propose une autre approche, qui semble prometteuse, mais le terme different conversion functions semble demander à être précisé.

(brève pause à 10 h 35 heure de Varna, 3 h 35 heure de Montréal)

Core Issue 2492 – Comparing user-defined conversion sequences in list-initialization

Au retour, John Spicer nous informe être préoccupé par 4192, craignant que l'avenue explorée ne brise du code existant. On examine le problème sous différentes facettes. Le concept de Worst Conversion tel qu'actuellement défini semble... un peu mou. Intéressante nuance : la conversion d'un int en bool et la conversion d'un short en bool ne passent pas par les mêmes chemins dans le standard (joies de la compatibilité avec C, je présume), la nuance étant que l'une fait partie des règles de promotion arithmétique et l'autre fait partie des règles de conversion. Ça peut bel et bien changer le comportement du code dans certains cas, après examen, alors on va fignoler le texte et l'envoyer à EWG pour avoir leur avis. L'avenue qui se décide semble après tout être l'invention d'un nouveau type de conversion.

Core Issue 1223 – . Syntactic disambiguation and trailing-return-types

Le problème soulevé remonte à 2010 :

struct A {
  A(int *);
  A *operator()(void);
  int B;
};

int *p;
typedef struct Brian Bi
 { int C[2]; } *B, C;

void foo() {
// The following line becomes invalid under C++0x:
  A (p)()->B;  // ill-formed function declaration

// In the following,
// - B()->C is either type-id or class member access expression
// - B()->C[1] is either type-id or subscripting expression
// N3126 subclause 8.2 [dcl.ambig.res] does not mention an ambiguity
// with these forms of expression
  A a(B ()->C);  // function declaration or object declaration
  sizeof(B ()->C[1]);  // sizeof(type-id) or sizeof on an expression
}

La résolution proposée irait dans la direction suivante et exigerait auto :

struct M;
struct S {
  S* operator()();
  int N;
  int M;
  void mem(S s) {
    auto(s)()->M; // S::M hides ::M, this is an expression
  }
};
void f(S s) {
  {
    auto(s)()->N; // expression
    auto(s)()->M; // function declaration
  }
  {
    S(s)()->N; // expression
    S(s)()->M; // expression
  }
}

On a un exemple préoccupant mais correct, soit :

typedef struct Brian Bi
 { int C[2]; } *B, C;
void f() {
  sizeof(B ()-> C[1]); // sizeof(expression)
  sizeof(auto () -> C[1]); // ill-formed - sizeof of a function returning an array
}

... où B() instancie un pointeur nul de type B* (ça nous prend tous du temps avant de le voir). C'est un Function-Style Cast... Ouf.

Core Issue 2732 – Can importable headers react to preprocessor state from point of import?

La question est de clarifier si le contenu d'un header unit est influencé par les macros définies au point d'un import ou d'un #include.

Hubert Tong mentionne que les macros prédéfinies ne semblent pas couvertes par le texte proposé.

On travaille un peu le texte pour faire en sorte que les macros dans un header unit soient indépendantes de celles du code qui l'inclut. Ça passera au vote samedi.

Core Issue 1223 – . Syntactic disambiguation and trailing-return-types

On y revient pour voir les retouches qui ont été faites. PR valide que S c(auto(B{})->C); et S c(auto(B())->C); sont tous deux bien couverts par le texte et ça semble être le consensus dans la salle. On travaille une bonne trentaine de minutes à examiner l'enjeu sous divers angles. Ça passera au vote samedi sous la forme d'une proposition formelle plutôt que sous celle d'une Core Issue.

Le C++ Ecosystem IS

Jens Maurer aborde la question des travaux de SG15 à ce sujet, car il faudra éventuellement passer le texte au peigne fin si on souhaite que la mention « qualité WG21 » puisse y être estampillée. Le texte sur la table est p2656.

(pause pour le dîner à 12 h 30 heure de Varna, 5 h 30 heure de Montréal; j'en profite pour prendre une douche, sortir les chiens, nourrir les animaux, faire un peu de vaisselle...)

P2752 – Static storage for braced initializers

L'intention ici est d'éviter de réallouer les valeurs d'une initializer_list à chaque utilisation (le texte actuel donne la permission en théorie, mais en pratique ça ne fonctionne pas car on peut prendre l'adresse d'un tel objet alors la différence entre mémoire statique et automatique est observable du code client). L'impact est particulièrement grand si le contenu de cette initializer_list est vaste, p. ex. : provenant d'un fichier de données à travers #embed.

Le texte introduit l'idée de backing array, qui est as-if matérialisé par le compilateur à titre de substrat pour l'objet. Si le constructeur ou le destructeur du type d'objet logé dans un initializer_list a des effets de bord, le compilateur n'a pas l'autorisation d'appliquer cette optimisation.

Jason Merrill dit l'avoir appliqué pour les types littéraux et ça fonctionne bien.

Hubert Tong demande si le texte discute du cas d'objets avec membres mutables. L'auteur dit Oh dear... Le plaisir de présenter devant CWG. C'est un enjeu car les tableaux const, visés par la proposition, peuvent muter dû à mutable. On fait des tests et pour le moment, gcc semble le permettre et promouvoir le tableau sous-jacent en mémoire statique (ouille!). https://godbolt.org/z/eeE5z86ce pour des détails (Jason Merrill corrige le bogue pendant qu'on discute!)

Le terme value intervient par la suite : quel et le sens de same value dans le cas, par exemple, d'une string avec optimisation SSO? Est-ce que le compilateur doit avoir la liberté de partager les substrats de deux const string?

Hubert Tong ajoute un cas de test : https://godbolt.org/z/eeE5z86ce

On discute ensuite de l'ajout à l'annexe C, là où sont placés les breaking changes, puis quelques ennuis nous tombent dessus : SG21 tient une rencontre lourde sur le plan politique en même temps que nous, et a des ennuis de microphone, alors Jens Maurer leur apporte les nôtre (nous sommes un beaucoup plus petit groupe), puis nous devons nous organiser avec les moyens du bord (Jens Maurer est remarquablement efficace). En plus, je perds Internet quelques minutes dû à une courte panne de courant. Hé la la...

On passe ensuite à la lecture des Ready Papers et des Ready Issues car SG21 draîne beaucoup de gens.

P2621R2 – UB? In My Lexer?

Cette proposition change un cas de UB pour un Ill-Formed.

P1854R4 – Making non-encodable string literals ill-formed

Ceci restreint ce qui peut être fait avec des littéraux multi-caractères pour éviter des absurdités

P2361R6 – Unevaluated strings

On parle de ces chaînes qui ne sont pas conservées dans le binaire, par exemple le texte dans un [[nodiscard]] ou dans un static_assert ou dans un bloc asm.

P2558 – Add @, $, and ` to the basic character set

Comme le titre le dit

P2738R1 – constexpr cast from void*: towards constexpr type-erasure

Oh, une bonne nouvelle!

On regarde par la suite plusieurs Ready Core Issues (on va vite et je n'ai pas le temps de noter les détails). Quelques trucs intéressants ou étranges, par exemple le recours à des digraphs  dans des annotations par exemple.

(courte pause; je fais à déjeuner à mon plus jeune Ludo et Jens Maurer trouve un micro de remplacement)

On poursuit avec les Ready Core Issues (on va vite et je n'ai pas le temps de noter les détails, bis.). Parmi les trucs notables, on trouve le traitement de littéraux entiers avec le suffixe z qui doivent être représentables par un std::size_t, la gestion des cv-qualifiers lors d'une levée d'exception à l'aide d'un tableau ou d'un pointeur, l'initialisation des tableaux avec des parenthèses (tout le monde l'acceptait mais c'était interdit), une clarification des boucles dans une fonction constexpr (elles sont exprimées sur la base de goto dans le texte... mais goto est proscrit dans un contexte constexpr), la permission d'utiliser des Designated Initializers dans une initializer_list (chouette!), le support d'une expansion de Pack dans une expresion alignas (l'enjeu ici est que les paramètres doivent être séparés par des espaces, or args... sépare par des virgules!), le support du débordement sur des nombres à virgule flottante IEEE754, etc.

Ça vaut la peine car on attrape quelques menus bogues au passage! Ne pouvant pas participer aux téléconférences de CWG entre les rencontres de WG21 (il y en a régulièrement, mais je suis toujours en classe quand elles se tiennent) je prends connaissance de ces nombreux objets d'étude et de discussion des derniers mois.

On bouge ensuite vers les Tentatively Ready Issues...

Core Issue 170 – Pointer-to-member conversions

Ceci semble être un cas où les règles de deux sections du standard ne sont pas pleinement cohérentes lors de conversions parent-enfant. Le correctif proposé semble bien.

Core Issue 1353 – Array and variant members and deleted special member functions

On parle ici d'harmoniser les tableaux et les union et les fonctions =delete. Le texte donne la latitude au compilateur de ne pas inspecter les autres membres d'un union ou d'un tableau une fois qu'un des membres a été déterminé comme non-viable. Ça semble prêt, et ça devrait être un DR.

Core Issue 1973 – Which parameter-declaration-clause in a lambda-expression?

Celui-ci est amusant et clarifie ce que sont les paramètres dans une expression comme []{ return 3; } où les paramètres sont implicites.

Core Issue 2476 – placeholder-type-specifiers and function declarators

Le but est d'atteindre l'objectif suivant :

int f();
auto (*fp1)() = f;       // OK
auto (*fp2)()->int = f;  // OK
auto (*fp3)()->auto = f; // OK

template<typename T> struct C { };
C<auto(*)()> c1;         // Not OK
C<auto(*)()->int> c2;    // OK
C<auto(*)()->auto> c3;   // Not OK

C'est subtil alors on le traitera quand il y aura plus de participant(e)s dans la salle.

Core Issue 2485 – Bit-fields in integral promotions

L'intention est de clarifier ce qui se produit dans de tels cas. On en a beaucoup parlé dans le passé et ça semble prêt.

Core Issue 2519 – Object representation of a bit-field

Celle-ci couvre un trou dans la définition de cet étrange type d'entité. Ça semble prêt

Core Issue 2663 – Example for member redeclarations with using-declarations

On parle d'ajouter des exemples pour l'exposition de membres de parents à travers un enfant à partir de using et pour montrer les différences avec l'écriture semblable pour exposer des membres d'un namespace.

Core Issue 2492 (suite)

Mike Miller a préparé un petit quelque chose dans le dossier du Worst Conversion examiné plus tôt, dans le but d'éliminer la possibilité de générer des conversion sequences ambiguës. On construit un exemple pour appuyer l'explication, et pour explorer les limites de ce qui devrait être permis. Jason Merrill propose une approche, soit de créer deux ensembles de conversions possibles (celles vers le type A et celles vers le type B), puis de statuer que si l'une des conversions est meilleure que toutes celles de l'autre ensemble alors cette dernière gagne. Mike Miller fait remarquer que cela peut mener à plus de cas ambigus que ce qu'on aurait avec le texte proposé, mais c'est peut-être souhaitable.

Roger Orr souligne qu'on devrait peut-être demander l'opinion de EWG car nous ne sommes pas tous pleinement d'accord sur le chemin à suivre, ce qui ressemble à une forme de design. À réfléchir, car la journée se termine.

(je ne ferai pas les séances de soirée cette semaine; j'ai besoin de dormir et j'ai du travail hors-WG21 à faire aussi)

Jour 2 8 février 2023

J'arrive à 1 h 35 du matin, le temps de remplir les thermos de café.

D2641R4 – Checking if a union alternative is active

Barry Revzin explique l'intérêt de cette proposition sur la base de l'exemple de std::optional<bool> qui a trois états possibles (vrai, faux et disengaged) mais ne peut être implémenté aussi efficacement que souhaité (entre autres de manière constexpr) sans pouvoir tester lequel des membres de l'union sous-jacent sans un outil permettant de savoir lequel si un membre en particulier est actif.

La fonction appelée se nomme std::is_within_lifetime(membre) et est consteval, donc ne peut être utilisée que dans un contexte constexpr (ce n'est pas un outil runtime). Elle ne permet de détecter qu'un membre qui est devenu actif pendant une évaluation donnée.

Roger Orr détecte un problème entre le texte et l'un des exemples (le texte laisse entendre que la validité du mécanisme est local à une expression, mais l'exemple montre un constexpr std::optional<bool> d'un côté et un static_assert sur son état ailleurs, les deux au niveau global). On ajuste le texte en conséquence.

On discute un peu de l'intérêt d'un static_assert particulier qui n'apporte rien sur le plan de Core, mais Jens Maurer nous rappelle que ce test est présenté dans la section Library du standard et ne devrait pas nous concerner. Reste que Core a des exigences différentes. On ajuste légèrement pour faire ressortir l'intention de l'exemple plus clairement.

Hubert Tong demande si la fonction est supposée retourner true ou false, ou si elle est supposée être Ill-Formed quand elle est appliquée sur une variable non-initialisée. Barry Revzin dit que Ill-Formed est l'intention. Hubert Tong a en tête un cas où on aurait terminé la vie du pointé par des moyens détournés...

Hubert Tong demande quel est le comportement attendu de cette fonction pendant la construction ou la destruction d'un objet (je pense que oui). Roger Orr demande ce qui se passe si l'expression évaluée est void. J'aime CWG!

Hubert Tong demande si cette proposition entre en conflit avec la résolution attendue pour Core Issue 2677 – Replacing union subobjects qui vise à permettre la réalisation d'un placement new dans un sous-objet d'un union (avec std::construct_at() par exemple). Bien vu. John Spicer suggère que les propriétés exigées par std::is_within_lifetime() doivent tenir dans un contexte constexpr. On essaiera d'examiner les interactions avec Core Issue 2677 en présence (virtuelle) de RS plus tard cette semaine.

À moins d'une surprise, on votera ça à la fin de la semaine.

D1061R1 – Structured bindings can introduce a pack

On profite de la présence de Barry Revzin pour discuter de Structured Bindings dans le contexte de la confection de packs. John Spicer pense qu'il faut clarifier le modèle à partir duquel on réfléchit cet enjeu.

Hubert Tong demande si on peut restreindre ce mécanisme à un contexte générique. Jens Maurer pense que les gens vont simplement enrober les appels dans un template inutile si on fait cela. Barry Revzin pense que ces mécanismes sont utiles hors des templates (ils permettent entre autres d'utiliser des Fold Expressions). Jason Merrill trace une distinction entre se trouver dans un template et dépendre d'un paramètre d'un template (être dépendant); John Spicer dit que c'est précisément ce qu'il faudrait préciser dans la proposition. Jens Maurer mentionne que le « changement de contexte » qui nous fait passer du code non-générique au traitement réservé au code générique est coûteux pour certaines implémentations.

John Spicer et Barry Revzin vont travailler là-dessus.

Core Issue 6173 – Clarify confusing wording in [expr.rel]

On a un petit enjeu de clarification de texte à valider (ça valait la peine, il y avait un peu de travail à faire). C'est pas tout à fait prêt.

D2552R3 – On the ignorability of standard attributes

Timur Doumler explique la philosophie derrière la proposition. L'enjeu qui est sur la table est l'interaction avec __has_cpp_attribute qui ne distingue pas entre « le mot est traité dans un programme conforme » et « le compilateur fait avec ce mot ce qui est demandé ».

Jonathan Caves demande comment cette idée interagit avec un truc comme [[likely]].

Hubert Tong demande comment on traite l'évolution de la valeur de __has_cpp_attribute(annotation) car cette valeur peut changer avec le temps. Quel sens doit-on y donner? Mike Miller mentionne [[carries_dependency]] et la salle rit un peu.

Pour les cas non-triviaux comme [[likely]], Timur Doumler propose une section Recommended Practice.

Roger Orr demande des exemples, des cas d'utilisation. Timur Doumler en montre un qui fait une cascade de tests à la précompilation pour choisir un mécanisme standard ou un truc moins portable.

Timur Doumler explique qu'il voit ce mécanisme comme un moyen de demander au compilateur « as-tu fait le meilleur effort possible dans les circonstances? ».

On revient sur la question de Hubert Tong à propos des changements de sémantique sur une annotation (p. ex. : le passage de [[nodiscard]] à [[nodiscard(raison)]]). Hubert Tong voit un intérêt à __has_cpp_attribute sur le strict plan syntaxique et s'inquiète du glissement vers un test sémantique amené par cette proposition. On discute fort

(pause café à 3 h 30 du matin, 10 h 30 heure de Varna, puis on continue)

Jens Maurer rappelle que la proposition sur la table a été vue par EWG et que nous devons tenir compte de leur évaluation des conséquences du glissement sémantique qu'elle induit. Timur Doumler ajoute que __has_c_attribute aura un comportement analogue. Timur Doumler confirme que l'impact d'un changement de syntaxe (on parle de [[nodiscard]] avec et sans raison par exemple) n'a pas été discuté par EWG et se dit d'accord de ramener la proposition dans ce forum pour obtenir un avis. John Spicer pense que tester pour la version du langage supportée par un compilateur peut suffire pour distinguer les deux cas.

Hubert Tong demande si on doit ajouter des mots pour indiquer que pour prétendre supporter un standard donné, un compilateur doit implémenter les plus récentes sémantiques pour toutes ses annotations. Jens Maurer confirme que c'est un enjeu avec les Feature Test Macros en général (c'est là ou c'est pas là); Timur Doumler ajoute que la nature plus « optionnelle » des annotations joue un peu ici.

On fait un peu de chirurgie sur le texte proposé. Pour [[fallthrough]] et [[maybe_unused]], Hubert Tong demande ce qu'une implémentation devrait faire si elle ne produit pas d'avertissements dans ces cas de toute manière. On convient que le seul enjeu pour un 0 dans ce cas devrait toucher au support de l'annotation elle-même. Le texte ne dit pas vraiment cela alors on l'ajuste un peu. On remarque aussi que [[likely]] et [[unlikely]] sont formulés un peu différemment des autres annotations, et on essaie d'harmoniser le tout au passage; Hubert Tong se dit d'avis que [[likely]], [[unlikely]] et [[assume]] sont d'une autre nature que les autres annotations et qu'il est raisonnable de les exprimer différemment.

Timur Doumler explique que [[noreturn]] est intéressant. Il se limite à traiter de la partie où le compilateur devrait offrir un avertissement si la demande n'est pas respectée pour ne pas encourager le code client à tricher.

La définition du comportenent associé à [[no_unique_address]] parle d'objets de taille zéro, alors on discute pas mal et on ajuste (Timur Doumler explique le choix du Zero Size, ça se tient dans le contexte mais on le contextualise).

Timur Doumler retourne à EWG et nous reviendra plus tard. Il nous explique que son intention est de faire de ceci un DR.

On examine ensuite rapidement les autres sujets de discussion prévus pour être soumis pour vote cette semaine, dans l'optique de cibler lesquelles devraient être des DR aussi. On convient que P2621 et P1854 devraient être des DR.

On passe aux Core Issues.

Core Issue 2476 – placeholder-type-specifiers and function declarators

À titre de rappel, le texte existant rend ce qui suit illégal, ce qu'on aimerait corriger :

int f();
auto (*fp)()=f;

Le texte proposé permettrait quant à lui d'écrire :

auto f() -> int;                // OK, f returns int
auto (*fp)() -> auto = f;       // OK

Les productions grammaticales ont été ajustées en conséquence. On passe le tete en revue (beaucoup de changements). Christof Meerwald demande :

void f1(auto (*)()); // OK
void f2(auto (*)() -> auto); // ?

On attrape des irritants à quelques endroits (parfois, c'est le texte préexistant qui pose problème, et les ajustements le brisent mais ne le briseraient pas s'il était approprié au préalable).

Jens Maurer essaiera de régler les problèmes trouvés dans le courant de la semaine.

(pause à 5 h 30 du matin, 12 h 30 heure de Varna; temps de prendre ma douche, m'occuper des animaux et faire le lunch de Ludo)

D2552R3 – On the ignorability of standard attributes

Timur Doumler est de retour après un voyage aller-retour chez EWG. Ils sont d'accord avec nous pour dire que dans des cas comme [[likely]], où l'optimisation peut être faite post-compilation, le fait de passer l'information du compilateur vers l'optimiseur comme comme un effort louable.

On envoie ça pour vote cette semaine.

P2741 – User-generated static_assert messages

Une proposition que les gens de SG14 attendent depuis longtemps, moi inclus. Jens Maurer insiste pour dire que l'on ne parle pas d'un appel à std::format() pour le moment, mais bien de quelque chose de plus limité.

Il y a un exemple intéressant là-dedans (exécution expérimentale : https://godbolt.org/z/PdvKsjTxq) :

template <auto N>
consteval std::string_view oups() {
   static_assert(N, "this always fires");
   return "oups!";
}
void f() {
   static_assert(true, oups<false>());
}

La grammaire ajustée permet d'insérer une constant-expression arbitraire à titre de message (le recours à du texte en fin de parcours est une contrainte sémantique, pas syntaaxique), ce que nous transformons en manifestly-constant-expression en cours de route car il y a des contraintes particulières au recours à constant-expression qui ne sont pas rencontrées ici. Ce texte est représenté par l'équivalent d'un triplet begin(), end(), size(). On travaille un peu sur la définition du type requis pour la taille. Jonathan Caves remarque que c'est la seule occurrence du terme valid range dans tout le Core Wording alors on ajoute une référence croisée vers la définition de ce terme.

Une préoccupation est la nature du message : quels sont les requis? Le compilateur doit-il valider size() même si la condition évalue à true? Comment réagir si l'expression qui génère le message échoue? Le type utilisé peut être un type usager alors il faut être prudents.

P2169 – A nice placeholder with no name

L'idée est de réserver '_' en ce sens, mais sans briser le code existant. Si une seule occurrence de cette variable existe dans une portée donnée, c'est une variable normale; s'il en existe plusieurs, c'est un « je m'en fous » et c'est implicitement considéré [[maybe_unused]]. On ne peut pas utiliser deux fois ce nom dans certains contextes comme dans la portée d'un namespace. Le terme grammatical introduit est name-independent. Brian Bi fait remarquer qu'on ne peut pas, en ce moment, annoter une seule variable d'un Structured Binding (on peut l'annoter en bloc seulement) ce qui fait de ceci quelque chose d'un peu novateur.

Hubert Tong soulève la question du name mangling, mais ça semble bien couvert par le texte (les endroits problématiques ne permettent pas ce mécanisme).

(brève pause vers 15 h 30 heure de Varna, 8 h 30 ici)

D2752R3 – Static storage for braced initializers

Le texte a été légèrement retravaillé pour tenir compte des remarques soulevées lors de la discussion précédente.

Hubert Tong signale un problème au sens du langage dans des appels récursifs, où la fin de la vie d'un initializer_list peut être provoquée par la construction conceptuelle d'une nouvelle initializer_list identique au même endroit. AOD indique que le texte permettant une exception pour les string literals a été utilisé ici. On discute longtemps car la durée de vie de cette nouvelle créature est une nouveauté. Avec les tableaux constexpr, l'impossibilité de prendre leur adresse ouvre techniquement la possibilité de ne pas leur donner d'adresse unique de par as-if.

Un des exemples recoupe une zone où il y a divergence d'implémentation. On discute longtemps pour essayer de cerner l'interprétation qui devrait prévaloir, pour décider de changer l'exemple tout simplement.

On votera là-dessus cette semaine. Jason Merrill pense qu'il s'agit d'un DR.

Core Issue 2733 – Applying [[maybe_unused]] to a label

Il semble que ce ne soit pas permis, mais que ça pourrait être pertinent. La grammaire le permet apparemment, mais le texte ne le permet pas, une incohérence. On hésite entre corriger et passer par EWG dans les circonstances. On corrige, Tentatively Ready.

P2169 – A nice placeholder with no name

On revient sur cet enjeu avec une proposition incluant la plupart des correctifs demandés. On retravaille avec l'auteur jusqu'à la fin de la journée.

Jour 3 9 février 2023

(note : j'ai manqué le début de la rencontre; il est 3 h 10 du matin quand j'ai réalisé que je ne suis pas parvenu à me lever à temps. Dure semaine sur le corps... À mon arrivée, on travaille sur D2169R4)

L'exemple sur lequel on travaille est :

int _;
void f() {
   int _; // B
   _ = 0;
   using ::_; // error, using declaration does not precede B
}

... pour voir s'il porte correctement le message attendu à propos des règles sur using et les symboles name-independent. Je n'ai pas compris les subtilités de l'argumentaire, étant arrivé sur le tard, mais il semble y avoir interaction entre ce que cet exemple essaie d'exprimer et les règles qui permettent de laisser un paramètre de fonction sans nom.

(à la pause, je demande aux collègues quel était l'enjeu; on m'explique que les règles qui permettent d'omettre un nom d'un argument de fonction, un nom d'un paramètre de template et de faire en sorte qu'un _ soit un « peu importe » sont très semblables et qu'on essaie de les harmoniser)

Un exemple qui semble avoir été discuté en mon absence est :

template <class T>
   concept C = requires(T *_, T _) { typename T; };

... qui montre la possibilité d'utiliser _ à titre de nom de paramètre ignorable (un paramètre est une variable locale après tout).

Core Issue 2546 – Defaulted secondary comparison operators defined as deleted

L'intention est que ce qui suit soit valide :

struct HasNoLessThan { };
struct C {
    friend HasNoLessThan operator<=>(const C&, const C&);
    bool operator<(const C&) const = default;  // OK, function is deleted
};

... mais le texte du standard ne mène pas à ce point (le type de retour rend le tout Ill-Formed). La proposition est d'ajouter deux étapes au processus permettant de déterminer quoi faire ici.

Core Issue 2547 – Defaulted comparison operator function for non-classes

Permet-on de définir les opérateurs de comparaison =default pour des enum? On le permet pour des classes. On pense que pour le moment, il est préférable de ne pas le permettre (on réévaluera si un cas d'utilisation pertinent nous est livré).

Core Issue 2548 – Array prvalues and additive operators

L'exemple est :

int main() {
   using IA = int[];
   IA{ 1, 2, 3 } + 0;
}

... qui semble Ill-Formed, étant équivalent à prendre l'adresse d'une prvalue, mais ne semble pas formellement interdit par le texte existant. On pense que c'est peut-être couvert par la résolution de Core Issue 1642, mais ça ne semble pas être le cas finalement.

Core Issue 2549 – Implicitly moving the operand of a throw-expression in unevaluated contexts

L'enjeu est :

void f() {
   X x;
   // Is x an lvalue or an xvalue here?
   void g(int n = (decltype((throw x, 0))()));  // status quo: x is move-eligible here
}

void f() {
   X x;
   struct A {
      void g() {
         try {
            struct Y {
               // Is x an lvalue or an xvalue here?
               void h(int n = (decltype((throw x, 0))()));
            };
         } catch (...) { }
      }
   };
}

On nous demande donc de préciser ce qu'est une movable-entity dans un contexte non-évalué. Selon le Core Issue : « Thus, in the first example above, x is treated as an xvalue, but it is treated as an lvalue in the second example. This outcome is surprising ».

La résultion proposée est difficile à digérer en lien avec le texte existant. On travaille fort.

Library Issue 3436 – std::construct_at should support arrays

Library nous demande de regarder cette Library Issue. Tel qu'exprimé en ce moment, std::construct_at() ne peut pas supporter les tableaux (il y a un enjeu de type), mais ils sont d'avis que cette restriction est inutile. Ils suggèrent qu'on ajoute un std::launder() dans le cas où std::is_array_v<T> s'avère. Jason Merrill pense qu'un simple (T*) suffirait, sans passer par std::launder(), mais Hubert Tong n'est pas convaincu (on perdrait le constexpr dans ce cas).

Après examen, on pense que la stratégie envisagée par LWG ne fonctionnerait pas (std::launder() a des restrictions que leurs intentions ne permettent pas de rencontrer), et Hubert Tong propose une approche alternative. Hubert Tong explique que le problème survient dans le cas où un tableau est le premier membre d'un agrégat, dans quel cas si on traite le tableau comme pointer-interconvertible avec autre chose on laisse fuir l'objet entier pour les fins de l'analyse (bobo). L'alternative serait de remplacer new T par new T[1] pour que launder() soit applicable de tableau à tableau (les gens de LWG sont extrêmement divertis par cela).

Il y a des gens qui sont juste brillants :)

Core Issue 2550 – Type "reference to cv void" outside of a declarator

Formellement, le texte n'interdit pas cette horreur :

void f(void &x);

Le changement est très petit. On le passera au vote cette semaine.

Core Issue 2551 – "Refers to allocated storage" has no meaning

On a un terme ici qui est utilisé à quelques endroits mais n'a pas de définition formelle dans le standard. On compte réécrire les passages (probablement hérités de C et de std::malloc()) pour éliminer le terme. Mike Miller pense que ça résout aussi Core Issue 1583 (bonne nouvelle!)

Core Issue 2552 – Constant evaluation of non-defining variable declarations

La proposition P2242 qui permet certains goto dans une fonction constexpr ouvre la porte à certaines déclarations, en particulier les block-scope extern ce qui semble.. abusif dans le contexte. Faut resserrer le texte un peu et remplacer quelques « declarations » par des « definitions ». On travaille un peu plus car Brian Bi constate que ça ne suffit pas tout à fait à porter l'idée. Après travail, ça semble prêt alors on votera dessus cette semaine.

Core Issue 2553 – Restrictions on explicit object member functions

On en a échappé quelques-unes avec Deducing this qui permettent pour le moment d'avoir un paramètre this dans une fonction membre static par exemple, et qui permet d'avoir un paramètre this dans une fonction virtuelle (que ce soit parce que déclarée comme telle our parce qu'elle spécialise une telle fonction).

Roger Orr fait remarquer qu'il faudrait ajouter des restrictions semblables à operator new et operator delete comme fonctions membres.

Christof Meerwald fait remarquer que nous avons des règles ailleurs pour couvrir les cas virtual et static.

On travaille un peu, et ça semble prêt pour vote cette semaine.

Core Issue 2554 – Overriding virtual functions, also with explicit object parameters

Il y a un petit irritant dans le texte de l'algorithme qui parle de paramètres dans des fonctions virtuelles en situation de surcharge. On exige techniquement que les paramètres soient de même type, or dans ceci :

struct B {
   virtual void f();   // #1
};
struct D : B {
   void f();           // #2
};

... le paramètre this de B::f est un B* alors que le paramètre this de D::f est un D* et les fonctions ne correspondent pas. C'est... amusant :) Faut évidemment corriger le texte, mais dans ce cas c'est pas une petite chirurgie.

L'approche proposée est d'ignorer le paramètre this pour les fins de cet algorithme. On travaille sur le texte de corresponds-to dans le contexte de voir si deux fonctions virtuelles correspondent l'une à l'autre.

(pause dîner; il est 5 h 30 du matin chez moi alors temps pour une douche, préparer le lunch de Ludo, nourrir les animaux...)

P2662 – Pack Indexing

Oh, un sujet qui en rendra plusieurs très, très heureux! L'idée èst de permettre des trucs comme :

template <typename... T>
constexpr auto first_plus_last(T... values) -> T...[0] {
   return T...[0](values...[0] + values...[sizeof...(values)-1]);
}
int main() {
   //first_plus_last(); // ill formed
   static_assert(first_plus_last(1, 2, 10) == 11);
}

... ce qui est vraiment déplaisant à faire « à bras ». Jens Maurer demande si on a prévu l'interaction avec les Structured Bindings et ça semble être le cas.

Hubert Tong demande si on peut avoir un pack sans lui donner un nom. Il semble que ce genre de code plutôt rare (hors des suites de tests des compilateurs) soit supporté seulement par Clang en ce moment.

On fait le tour de la grammaire. Le type de l'index entre [ ] n'est pas spécifié mais ce sera clairement un std::size_t (il est tentant de faire comme les tableaux, mais un tableau peut être indicé par un entier signé et ici, un négatif ne ferait aucun sens).

Jason Merrill soulève la question de la généralisation du procédé (je pense qu'on l'a toutes et tous en tête), mais on convient qu'il s'agit d'un sujet pour EWG.

En creusant, on constate que la transformation proposée à la grammaire ne fonctionne pas (ça provoque une ambiguïté) alors on accompagne Corentin Jabot dans les ajustements requis. C'est extrêmement subtil car on voit poindre à l'horizon une généralisation du concept (surtout avec la réflexivité qui approche) et on ne veut pas une grammaire qui ne permettrait pas d'exprimer des idées plus générales.

Sur le plan des types, ce qui est proposé semble trop général pour le moment (on pourrait indexer dans un template template...). On passe plus de deux heures sur la grammaire, qui a plein de ramifications et a besoin de soins (c'est normal pour un truc aussi complexe). Ce qui n'aide pas est qu'il y a des trucs dans ces zones du langage qui n'ont pas été examinées en détail depuis une décennie, alors il y a de l'entropie...

L'équivalence et l'équivalence fonctionnelle des indices demande un peu d'attention (p. ex. : s'assurer que T...[i] et T...[i+0] représentent fonctionnellement la même chose)

Jens Maurer fait remarquer qu'on veut que ceci :

template <class ... T>
   int f(T...[0], std::tuple<T...>);
// ...
int n = f(5u, std::tuple(5, 1));

...fonctionne malgré la différence de signe. C'est probablement évolutionnaire, cela dit

(pause vers 8 h 30 ici, 15 h 30 à Varna; c'était franchement intéressant)

D2795R2 – Erroneous behaviour for uninitialized reads

Proposition de Thomas Köppe pour intégrer au langage une nouvelle catégorie de comportement incorrect, né des (intenses) discussions sur le volet Safety du langage. Thomas Köppe explique pourquoi il est d'avis que ceci améliore le langage et comble un trou conceptuel : des comportements à la fois légaux et erronés.

Le cas clé de sa présentation est la lecture d'une variable non-initialisée : en introduisant cette nouvelle catégorie, il souhaite faciliter la production de diagnostics par les compilateurs. Il y a de la résistance dans la salle (certains estiment que ça ressemble à obliger l'injection d'un Runtime Sanitizer dans les compilateurs). On discute des conséquences sur l'initialisation de mémoire allouée dynamiquement.

Jens Maurer rappelle l'importance de la règle as-if.

On lit la proposition. Le erroneous behavior serait une forme de well-defined behavior, ce qui surprend certains. Les implémentations seraient encouragées (pas obligées) de le diagnostiquer. Roger Orr demande si l'un des comportements permis est de refuser de compiler; Thomas Köppe dit que non car le programme doit pouvoir s'exécuter tel que défini.

Thomas Köppe mentionne que certains compilateurs (Clang, par exemple) font un peu ce qu'il suggère à partir de fanions de compilation, p. ex. : -ftrivial-auto-var-init=zero mais le résultat n'est pas le type de diagnostic qu'il souhaiterait encourager.

Jens Maurer se questionne sur le recours à conditionnally-supported, qui lui semble syntaxique plutôt que sémantique, et cherche une formulation alternative. Hubert Tong pense que l'encouragement au diagnostic dans sa forme actuelle encourage la production de faux-positifs.

On examine les frontières entre erroneous behavior et undefined behavior. Les règles sur les diagnostics sont dans [intro.compliance.general].

(Hubert Tong nous informe que std::construct_at() va nous revenir, car LWG a trouvé un problème avec notre suggestion; il pense que std::launder() va fonctionner, mais faut éviter de descendre à reinterpret_cast)

Jens Maurer parle d'une nouveau terme, vague-value, pour ces valeurs déterminées par l'implémentation mais qui provoquent un comportement erroné.

Core Issue 2689 – Are cv-qualified std::nullptr_t fundamental types?

Enjeu de clarification : est-ce que const std::nullptr_t est un type distinct de std::nullptr_t par exemple? Le texte n'est pas clair à ce sujet.

Core Issue 2738 – "denotes a destructor" is missing specification

Ce terme est utilisé sans être défini dans le texte.

(on termine à 10 h 30 heure de Montréal, 17 h 30 heure de Varna; les gens sur place ont un souper protocolaire ce soir)

Jour 4 9 février 2023

Jens Maurer explique où nous en sommes en lien avec ce qui devait être fait cette semaine.

D2169R4 – A nice placeholder with no name

Cette proposition nous revient avec les plus récents ajustements faits (principalement à notre demande) au texte. L'auteur n'est pas un anglophone, alors il faut parfois retravailler le volet « langue anglaise correcte » du texte. Une Feature Test Macro a été ajoutée. On travaille à ce stade sur la forme, la clarté du texte.

Un des derniers irritants est la permission d'utiliser _ à titre de nom (répété) de paramètre de fonction alors qu'on peut obtenir le même effet en ne les nommant tout simplement pas. L'argument derrière cette décision est la cohérence, mais c'est une proposition qui introduit une incohérence, fondamentalement (en particulier, a ce passage : « it is a parameter-declaration that is not a template-parameter » qui introduit explicitement un traitement différencié). Jonathan Caves pense qu'il vaut la peine de consulter EWG une dernière fois à ce sujet.

D2741R4 – user-generated static_assert messages

La principale question restante est de savoir si le message sera formé que la condition s'avère ou pas. On travaille la définition formelle de l'expression constante qui produit le message (chaque caractère doit être lui-même une expression constante). Certains ajustements sont particulièrement nécessaires (le texte exigeait que .data() appliqué au texte soit une constant-expression or cette fonction a le droit d'allouer dynamiquement, et cette exigence pourrait provoquer des fuites).

Hubert Tong fait remarquer qu'on ne peut pas parler de static_cast dans le texte décrivant les règles de formation du message car cet opérateur peut invoquer des opérateurs de conversion implicites (on veut entre autres éviter d'injecter des Proxy Objects dans le portrait)

(ma carte réseau cesse subitement de fonctionner et je dois redémarrer mon ordinateur alors je manque une dizaine de minutes de discussions)

En gros, il ne faut pas que la fonction qui forme le message d'un static_assert puisse échouer ou fuire!

D2795R2 – Erroneous behaviour for uninitialized reads

Thomas Köppe explique les changements apportés depuis hier. Entre autres, il propose de retirer le mot « erroneous » du texte expliquant... le comportement indéfini, pour réduire les risques de confusion. On penche pour « incorrect » (Mike Miller parle de « does not conform to expectations »), mais selon les cas il y a plusieurs synonymes qui s'appliquent (ça fait du bien de resserrer le texte), incluant des trucs qui sont détectables à la compilation et pour lesquels Ill-Formed est préférable... et dans certains cas « erroneous » dans ce nouveau sens formel fonctionne bien.

(brève pause vers 3 h 30 heure de Montréal, 10 h 30 heure de Varna; la proposition sur le erroneous-behavior va améliorer le langage selon moi, j'en suis bien content! Pendant la pause, un membre de SG1 consulte informellement les gens dans la salle pour savoir si on pourrait remplacer la prose du standard par des mathématiques, pour réduire les risques d'ambiguïté... C'est une proposition osée!)

On poursuit sur la même proposition, et on passe de erroneous behavior à erroneous values. Jens Maurer parle du cas où une variable aurait une valeur erronée, et où on ferait un Placement New d'un objet trivialement constructible au même endroit.

Mike Miller demande quelle est la position du groupe quant à l'initialisation à l'exécution des valeurs. Il faut que l'implémentation soit claire quant aux valeurs des objets ayant une valeur erronnée.

La question du Placement New revient. Jens Maurer souligne avec justesse que l'implémentation ne sait pas si on place l'objet sur la pile ou sur le tas. PR souligne que l'initialisation des tampons peut influer sur la programmation avec des objets pour lesquels les bits de Padding ont une importance, p. ex. : les atomiques ou ce qui interface avec le GPU. Jens Maurer pense que std::bit_cast fait exactement ce que l'initialisation à bas niveau demandée fait ici. Ces enjeux ont des conséquences sur la copie d'un objet contenant du Padding : une lecture bit à bit lirait des valeurs erronnées, mais une lecture membre à membre ne le ferait pas.

Hubert Tong fait remarquer que dans sa forme actuelle, la proposition brise tous les programmes ayant des union, alors on ne peut pas l'accepter avant d'avoir réglé ce problème. Une avenue serait ne ne copier « magiquement » que les valeurs pertinentes... Hubert Tong dit qu'on veut le faire depuis longtemps, alors ce sera une occasion de se faire plaisir. Il y a aussi le cas de std::memcpy()... On veut pouvoir lire les bits, erronnés ou pas, mais on ne veut pas de diagnostic dans ce cas.

Jens Maurer fait remarquer que pour la lecture des valeurs indéterminées, il y a une liste d'exceptions pour lesquelles l'action ne cause pas de comportement indéfini dans [basic.indet]. Il demande si on souhaite une liste d'exceptions semblable pour les valeurs erronnées. En gros, ce qui passe est tout ce qui se limite à copier des bits; dès qu'on essaie de faire des trucs comme de l'arithmétique avec les représentations, le comportement indéfini embarque. On parvient à alléger un peu la proposition en récupérant ce qui existe déjà dans le standard.

John Spicer fait remarquer que si on veut garantir la valeur des bytes de Padding, il faudra essentiellement faire un std::memset() avant construction... Ce sera coûteux.

Il reste du travail à faire ici, manifestement, mais on joue en eaux troubles.

Core Issue 2749 – Treatment of "pointer to void" for relational comparisons

Une note indique que les comparaisons d'inégalité d'adresses à travers des void* est illégal, mais il semble raisonnable de les permettre si les void* pointent vers des objets. John Spicer fait remarquer qu'on change le sens d'un texte normatif par une note interprétative, mais bon.

(pause « dîner », temps pour la douche et le démarrage de la journée chez moi)

Library Issue 3436 – std::construct_at should support arrays

 LWG nous informe que la suggestion d'allouer un T[1] plutôt qu'un T suivi d'un std::launder() dans le cas des tableaux pose problème à certains égards. Hubert Tong pense que std::launder() fait la bonne chose finalement, mais qu'il faut retoucher légèrement le texte. Une clause clé ici est [expr.const].

Il y a un enjeu dans le texte avec std::construct_at() pour des types trivialement constructibles. On crée le Core Issue 2750 – construct_at without constructor call... et on le votera demain.

P2865R1 – Remove Deprecated Array Comparisons from C++26

AM fait le ménage dans le standard encore une fois. Son objectif est de rendre illégal l'application d'opérateurs relationnels d'inégalité sur des tableaux (qui fonctionne actuellement sur la base du Pointer Decay, en C comme en C++).

Hubert Tong demande quelle est l'intention dans le cas où on compare un tableau avec un std::nullptr_t. AM dit qu'il n'a rien changé dans ce cas. Brian Bi pense que c'est déjà Ill-Formed. Hubert Tong pense qu'il faut au moins considérer operator== entre un tableau et un pointeur nul.

On travaille un peu sur le texte, mais principalement pour la forme. On s'assure que SG22 en sera informé car cela impacte la compatibilité entre les langages.

(on planifie les prochaines dates de téléconférence en attendant le prochain proposeur; si je n'étais pas toujours en classe, je participerais bien)

D2169R4 – A nice placeholder with no name

Corentin Jabot a un retour d'EWG. Les corrections sont faites. On vote là-dessus demain.

P2620R2 – Improve the wording for Universal Character Names in identifiers

Hubert Tong explique que ceci était présenté comme une simple mise à jour terminologique, mais c'est inexact et la proposition a d'importants impacts à certains niveaux. Cela dit, il convient que le travail à faire est du travail qu'il est pertinent de faire. Un des enjeux est de permettre (un jour) des trucs comme l'introduction d'opérateurs mathématiques usuels pour rendre le langage plus accessible aux mathématiciennes et aux mathématiciens.

Ce qu'on a permettra d'utiliser des accents de manière portable dans le code source. C'est difficile, le texte...

D2795R2 – Erroneous behaviour for uninitialized reads

Thomas Köppe a procédé à des mises à jour, qui intègrent les clauses qui parlent de indeterminate et de erroneous.

(brève pause à 8 h 30 heure de Montréal, 15 h 30 heure de Varna)

On poursuit l'examen un à un des endroits où le mot erroneous apparaît désormais pour assurer la cohérence du standard en lien avec ce terme (et avec les autres types d'erreurs).

Jens Maurer nous informe que EWG aimerait savoir si CWG a une opinion consensuelle sur la proposition dans son état actuel. Notre consensus officiel est qu'on n'est pas à l'aise de le laisser passer dans sa forme actuelle. On n'est pas pressés (C++ 26 est deux ans devant)

D2662R2 – Pack Indexing

On revient sur cette importante proposition, mais qui demande beaucoup de travail à cause de sa place dans la grammaire du langage. On a un joli exemple :

[](auto... pack) {
   decltype(pack...[0]) x5; // type is int
   decltype((pack...[0])) x6; // type is int&
}(0);

On travaille plus d'une heure sur les termes de grammaires choisis pour être certains d'avoir les productions souhaitées et de ne pas fermer la porte à l'évolution du langage dans ce créneau (on voit venir les coups!).

En examinant les trucs que ceci brise, j'apprends que la syntaxe T...[N] avait déjà un sens (c'est un pack d'arguments de fonctions qui sont tous des tableaux de N éléments de type T, sans les nommer). Eh ben...

P2865R2 – Remove Deprecated Array Comparisons from C++26

AM n'est pas retourné à EWG encore, mais a continué à travailler le texte de sa proposition.

Core Issue 2726 – Alternative tokens tokens appearing as attribute-tokens

On parle ici du traitement de symboles alternatifs, incluant ceux déjà supportés (p. ex. : or au lieu de ||) comme des mots clés à part entière pour utilisation dans des annotations. On demandera l'avis de EWG.

Core Issue 2102 – Constructor checking in new-expression

On essaie de voir comment raisonner sur ces expressions même dans un contexte non-évalué (en particulier, pour un tableau ou un initializer_list, quels constructeurs doivent être ODR-used?).

(on ferme vers 10 h 30 heure de Montréal, 17 h 30 heure de Varna)

Le Canada tient une rencontre pour faire le point sur les dossiers chauds de la semaine et déterminer s'il y a lieu d'avoir une position nationale sur certains dossiers, ce soir à 0 h 30 heure de Montréal (7 h 30 heure de Varna). La plénière débutera à 8 h 30 heure de Varna. Le principal dossier chaud, d'une perspective canadienne, semble provenir de LWG (std::atomic_max et std::atomic_min, P0493). La proposition 25 de LWG semble sensible aussi, du moins pour certains.

Jour 5 – 11 février 2023

La rencontre canadienne débute à 0 h 30 heure de Montréal (7 h 30 heure de Varna). C'est assez bref (une vingtaine de minutes).

La plénière débute à 1 h 30 heure de Montréal (8 h 30 heure de Varna). Je suis fatigué...

On fait le tour des rapports des divers SG et des WG.

CWG Polls

Les votes vont comme suit.

1. Accept as Defect Reports and apply the proposed resolutions of all issues in P2922R0 (Core Language Working Group "ready" Issues for the June, 2023 meeting) to the C++ Working Paper

(unanime)

2. Accept as a Defect Report and apply the changes in P2621R2 (UB? In my Lexer?) to the C++26 Working Paper

(unanime)

3. Accept as a Defect Report and apply the changes in P1854R4 (Making non-encodable string literals ill-formed) to the C++26 Working Paper

(unanime)

4. Apply the changes in P2361R6 (Unevaluated strings) to the C++26 Working Paper

(unanime)

5. Apply the changes in P2558R2 (Add @, $, and ` to the basic character set) to the C++26 Working Paper

(unanime)

6. Apply the changes in P2738R1 (constexpr cast from void*: towards constexpr type-erasure) to the C++26 Working Paper

(unanime)

7. Accept as a Defect Report and apply the changes in P2915R0 (Proposed resolution for CWG1223) to the C++26 Working Paper

(unanime)

8. Accept as a Defect Report and apply the changes in P2552R3 (On the ignorability of standard attributes) to the C++26 Working Paper

(unanime)

9. Accept as a Defect Report and apply the changes in P2752R3 (Static storage for braced initializers) to the C++26 Working Paper

(unanime)

10. Apply the changes in P2741R3 (User-generated static_assert messages) to the C++26 Working Paper

(unanime)

11. Apply the changes in P2169R4 (A nice placeholder with no name) to the C++26 Working Paper

(unanime)

LWG polls

Les votes vont comme suit.

1. Apply the changes for all Tentatively Ready issues in P2910R0 (C++ Standard Library Issues to be moved in Varna, Jun. 2023) to the C++ working paper

(unanime)

2. Apply the changes in P2497R0 (Testing for success or failure of  functions) to the C++ working paper

(unanime)

3. Apply the changes in P2592R3 (Hashing support for std::chrono value classes) to the C++ working paper

(unanime)

4. Apply the changes in P2587R3 (to_string or not to_string) to the C++ working paper

(unanime)

5. Apply the changes in P2562R1 (constexpr Stable Sorting) to the C++ working paper

(unanime)

6. Apply the changes in P2545R4 (Read-Copy Update (RCU)) to the C++ working paper

(unanime)

7. Apply the changes in P2530R3 (Hazard Pointers for C++26) to the C++ working paper

(unanime)

8. Apply the changes in P2538R1 (ADL-proof std::projected) to the C++ working paper

(unanime)

9. Apply the changes in P2495R3 (Interfacing stringstreams with string_view) to the C++ working paper

(unanime)

10. Apply the changes in P2510R3 (Formatting pointers) to the C++ working paper

(unanime)

11. Apply the changes in P2198R7 (Freestanding Feature-Test Macros and Implementation-Defined Extensions) to the C++ working paper

(unanime)

12. Apply the changes in P2338R4 (Freestanding Library: Character primitives and the C library) to the C++ working paper

(unanime)

13. Apply the changes in P2013R5 (Freestanding Language: Optional ::operator new) to the C++ working paper

(unanime)

14. Apply the changes in P0493R4 (Atomic maximum/minimum) to the C++ working paper

Certains aspects en lien avec les nombres à virgule flottante, en particulier les NaN, demandent discussion. On retire cette proposition pour aujourd'hui.

15. Apply the changes in P2363R5 (Extending associative containers with the remaining heterogeneous overloads) to the C++ working paper

(unanime)

16. Apply the changes in P1901R2 (Enabling the Use of weak_ptr as Keys in Unordered Associative Containers) to the C++ working paper

(unanime)

17. Apply the changes in P1885R12 (Naming Text Encodings to Demystify Them) to the C++ working paper

(unanime)

18. Apply the changes in P0792R14 (function_ref: a type-erased callable reference) to the C++ working paper

(vote, consensus)

19 Apply the changes in P2874R2 (Mandating Annex D) to the C++ working paper

(unanime)

20 Apply the changes in P2757R3 (Type checking format args) to the C++ working paper

(unanime)

21 Apply the changes in P2637R3 (Member visit) to the C++ working paper

(unanime)

22 Apply the changes in P2641R4 (Checking if a union alternative is active) to the C++ working paper

(unanime)

23 Apply the changes in P1759R6 (Native handles and file streams) to the C++ working paper

(unanime)

24 Apply the changes in P2697R1 (Interfacing bitset with string_view) to the C++ working paper

(unanime)

25 Apply the changes in P1383R2 (More constexpr for cmath and complex) to the C++ working paper

(vote, consensus)

26 Apply the changes in P2734R0 (Adding the new 2022 SI prefixes) to the C++ working paper

(unanime)

27 Apply the changes in P2548R6 (copyable_function) to the C++ working paper

(vote, consensus)

28 Apply the changes in P2714R1 (Bind front and back to NTTP callables) to the C++ working paper

(vote, consensus)

29 Apply the changes in P2630R4 (submdspan) to the C++ working paper

(unanime)

WG21 Polls

Les votes vont comme suit.

Approve P1000R5 as the schedule for C++26

(unanime)

Le reste est de la routine; on prépare les prochaines rencontres, pour l'essentiel, et on ferme vers 3 h 15 heure de Montréal (10 h 15 heure de Varna)


Valid XHTML 1.0 Transitional

CSS Valide !