
GCC est une collection de compilateurs du projet GNU qui prend en charge différents langages de programmation, architectures matérielles et systèmes d'exploitation. La Free Software Foundation (FSF) distribue GCC en tant que logiciel libre sous la licence publique générale GNU (GNU GPL). GCC est un composant clé de la chaîne d'outils GNU, utilisée pour la plupart des projets liés à GNU et au noyau Linux. Avec environ 15 millions de lignes de code en 2019, GCC est l'un des plus grands programmes libres existants. Il a joué un rôle important dans la croissance du logiciel libre, à la fois comme outil et comme exemple.
La nouvelle version GCC 15.1 propose une interface pour le langage COBOL, diverses améliorations de la convivialité, de nombreuses améliorations du langage de programmation Rust pour gccrs, le passage de la version par défaut du langage C à C23, des améliorations de la cible AMD Zen 5 « znver5 » parmi d'autres nouvelles optimisations de la cible AMD Zen, le ciblage des Intel Xeon 7 Diamond Rapids, la prise en charge de l'Intel AVX10. 2 pour la nouvelle révision de 512 bits seulement, plus d'activations Intel Advanced Performance Extensions « APX », la suppression du support Xeon Phi, des améliorations OpenMP offloading, et beaucoup d'autres changements du support matériel aux caractéristiques du langage.
Le back-end AMDGPU pour les processeurs graphiques AMD prend désormais en charge la bibliothèque C++ standard (libstdc++), la prise en charge expérimentale des périphériques génériques et le retrait de la prise en charge du GPU Fiji. De même, le back-end NVIDIA NVPTX avec GCC15 prend également en charge libstdc++.
Les interfaces des langages D et Modula-2 de GCC, dont on parle moins, ont également fait l'objet d'un travail considérable, tout comme l'interface Fortran.
Fonctionnalités de C++26
Les fonctionnalités C++26 de GCC 15 comprennent l'indexation des paquets, les attributs pour les liaisons structurées, la prise en charge améliorée des fonctions dont la définition consiste en =delete, et plus encore.
Indexation des paquets
C++11 a introduit les modèles variadiques qui permettent au programmeur d'écrire des modèles qui acceptent n'importe quel nombre d'arguments de modèle. Un paquet peut représenter une série de types ou de valeurs. Par exemple, pour imprimer des arguments arbitraires, on peut écrire :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | template<typename T, typename... Types> void print (T t, Types... args) { std::cout << t << '\n'; if constexpr (sizeof...(args) > 0) print (args...); } int main () { print ('a', "foo", 42); } |
Cependant, il n'était pas possible d'indexer un élément d'un pack, à moins que le programmeur n'ait recours à diverses astuces récursives qui sont généralement lentes à compiler. Avec cette fonctionnalité du C++26, pour indexer un paquet, on peut écrire pack...[N] (où N doit être une expression constante). L'index d'un paquet se comporte alors exactement comme si l'expression résultante était utilisée. Un paquet vide ne peut pas être indexé. Le programme suivant imprimera a :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | template<typename... Types> void print (Types... args) { std::cout << args...[0] << '\n'; } int main () { print ('a', "foo", 42); } |
Attributs pour les liaisons structurées
Cette proposition permet d'ajouter un attribut à chacune des liaisons structurées introduites, comme dans l'exemple suivant :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | struct S { int a, b; }; void g (S& s) { auto [ a, b [[gnu::deprecated]] ] = s; } |
=delete avec une raison
Le C++11 prend en charge les fonctions supprimées, c'est-à-dire les fonctions dont la définition consiste en =delete. Les fonctions supprimées participent à la résolution des surcharges, mais leur appel constitue une erreur. Cela remplace l'ancien mécanisme qui consistait à déclarer les fonctions membres spéciales comme private.
En C++26, il est possible de fournir un message expliquant pourquoi la fonction est marquée comme supprimée : =delete(« reason »). Le programme suivant :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | void oldfn(char *) = delete("unsafe, use newfn"); void newfn(char *); void g () { oldfn ("bagel"); } |
provoquera l'émission par le compilateur du message suivant :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | q.C: In function ‘void g()’: q.C:7:9: error: use of deleted function ‘void oldfn(char*)’: unsafe, use newfn 7 | oldfn ("bagel"); | ~~~~~~^~~~~~~~~ q.C:1:6: note: declared here 1 | void oldfn(char *) = delete("unsafe, use newfn"); | ^~~~~ |
Amis variadiques
La fonctionnalité suivante permet d'utiliser une déclaration friend avec un paquet de paramètres :
Code : | Sélectionner tout |
1 2 3 4 | template<class... Ts> class Foo { friend Ts...; }; |
Un exemple où cette fonctionnalité peut être utilisée en pratique est l'idiome Passkey :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | template<typename... Ts> class Passkey { friend Ts...; Passkey() {} }; class A; class B; struct Widget { // Only callable from A and B. void secret (Passkey<A, B>); }; class A { void doit (Widget& w) { w.secret ({}); // OK } }; class B { void doit (Widget& w) { w.secret ({}); // OK } }; class D { void doit (Widget& w) { w.secret ({}); // won't compile! } }; |
Placement constexpr new
Le C++20 a ajouté la possibilité d'utiliser new dans un contexte constexpr :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | constexpr void use (int *) { } constexpr int foo () { auto *p = new int[]{1, 2, 3}; use (p); delete[] p; return 1; } int main () { constexpr auto r = foo (); } |
GCC a mis en œuvre la proposition dans GCC 10. Cependant, constexpr placement new n'était pas encore possible. Le C++26 rectifie cette situation et permet au programmeur d'écrire du code comme :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <memory> constexpr int foo () { std::allocator<int> alloc; auto p = alloc.allocate (16); new (p) int(42); alloc.deallocate (p, 16); return 1; } int main () { constexpr int r = foo (); } |
Déclaration de liaison structurée en tant que condition
La fonctionnalité des liaisons structurées a été ajoutée en C++17, et GCC la supporte depuis longtemps. GCC 15 implémente P0963R3, qui permet la déclaration de liaisons structurées dans les conditions if/while/for/switch ; auparavant, ce n'était pas possible.
Si une liaison structurée est utilisée dans un contexte de condition, sa variable de décision est la variable artificielle sous-jacente créée par le compilateur. Cette variable doit être convertible en bool (sauf lorsqu'elle est utilisée dans une instruction switch). En voici un exemple :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | struct S { int a, b; explicit operator bool () const noexcept { return a != b; } }; void use (int, int); void g (S s) { if (auto [ a, b ] = s) use (a, b); } |
Dans l'exemple précédent, use sera appelé lorsque a et b, décomposés à partir de s, ne sont pas égaux. La variable artificielle utilisée comme variable de décision a un nom unique et son type est ici S.
Suppression d'un pointeur sur un type incomplet
Le C++26 a clairement indiqué que les fonctions delete et delete[] sur un pointeur vers un type de classe incomplet ne sont pas valides. Auparavant, cela invoquait un comportement indéfini à moins que la classe n'ait un destructeur trivial et pas de désallocateur personnalisé. Par conséquent, GCC 15 émettra une erreur en mode C++26, ou un avertissement dans les modes plus anciens pour cet exemple :
Code : | Sélectionner tout |
1 2 3 4 5 6 | struct S; void foo (S *p) { delete p; } |
Virgule variadique d'Oxford
L'utilisation d'une ellipse variadique sans virgule précédente en C++26 est dépréciée dans cet article. Cela signifie que GCC 15, lorsqu'il compilera le cas de test suivant de la proposition, émettra trois avertissements en mode C++26 :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | void d_depr(auto......); // deprecated void d_okay(auto..., ...); // OK void g_depr(int...); // deprecated void g_okay(int, ...); // OK void h_depr(int x...); // deprecated void h_okay(int x, ...); // OK |
Les utilisateurs peuvent activer l'avertissement dans les modes plus anciens en spécifiant ...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.