10 votes

clang error : non-type template argument refers to function that does not have linkage -- bug ?

Je dispose d'un système très simple ( C++11 ) dont le dernier code clang ( version 3.4 trunk 187493 ) ne compile pas, mais GCC compile bien.

Le code (ci-dessous) instancie la fonction-template foo avec le type de fonction-local Bar et tente ensuite d'utiliser son adresse comme un paramètre de modèle non-type pour le modèle de classe Func :

template<void(*FUNC_PTR)(void)>
struct Func {};

template<typename T> extern inline
void foo() {
    using Foo = Func<foo<T>>;
}
int main() {
    struct Bar {}; // function-local type
    foo<Bar>();
    return 0;
}

clang émet l'erreur suivante :

erreur L'argument de modèle non-type fait référence à la fonction 'foo' qui n'a pas de lien

Cependant, si je déplace le type Bar à la portée globale (en le sortant de la fonction), alors clang le compile bien, ce qui prouve que le problème vient du fait que le type est fonction-locale .

Alors, est-ce que clang a raison d'émettre cette erreur, ou est-ce que le standard ne le supporte pas (dans ce cas, GCC est trop indulgent en le permettant) ?


EDIT #1 : Pour être clair, il s'agit pas un duplicata de cette question depuis le Impossible d'utiliser des types locaux comme paramètres de modèles a été supprimée dans C++11. Cependant Il n'est toujours pas clair s'il y a des implications de liaison impliquées dans l'utilisation d'un type local, et si clang est correct ou non en émettant cette erreur.


EDIT #2 : Il a été déterminé que clang avait raison d'émettre l'erreur pour le code ci-dessus (voir la réponse de @jxh), mais qu'il ne l'a pas fait. incorrectement émet également une erreur pour le code suivant (avec using la déclaration est passée de foo<Bar>() la portée de main() ) :

template<void(*FUNC_PTR)(void)>
struct Func {};

template<typename T> extern inline
void foo() {}

int main() {
    struct Bar {};
    using F = Func<foo<Bar>>;
    return 0;
}

3voto

jxh Points 32720

Par définition aucun lien dans C++.11 §3.5 Programme et liens ¶2, je croyais à l'origine foo<Bar> n'a pas de lien puisqu'il ne peut être référencé par son nom par aucune autre portée que celle qui a défini le type Bar (c'est-à-dire, main() ). Cependant, ceci n'est pas correct. En effet, la définition d'un nom avec lien externe est décrit comme suit :

Lorsqu'un nom a lien externe l'entité qu'il désigne peut être désignée par des noms provenant de champs d'application d'autres unités de traduction ou d'autres champs d'application de la même unité de traduction.

Et pour une fonction modèle, ce sera toujours le cas. En effet, il existe une autre portée à partir de laquelle le nom peut être référencé. En effet, la fonction modèle peut se référer à elle-même. Par conséquent, foo<Bar> a un lien avec l'extérieur. La réponse de zneak, EDIT 2 a une discussion par e-mail avec les développeurs de clang confirmant que foo<Bar> doit avoir un lien avec l'extérieur.

Ainsi, d'après C++.11 §14.3.2 Arguments non-types des modèles ¶1 :

A Argument de modèle pour un non-type, non-modèle Paramètres du modèle sera l'un de : ...

  • une expression constante (5.19) qui désigne l'adresse d'un objet avec une durée de stockage statique et un lien externe ou interne ou d'une fonction avec un lien externe ou interne, y compris les modèles de fonction et les fonctions. modèle-id mais en excluant les membres non statiques de la classe, exprimée (sans tenir compte des parenthèses) sous forme de & id-expression sauf que le & peut être omis si le nom se réfère à une fonction ou à un tableau et doit être omis si la fonction correspondante Paramètre du modèle est une référence ; ...

Le point le plus pertinent est le troisième point. Puisque foo<bar> a un lien externe, en le passant comme un non-type Paramètres du modèle devrait convenir.

3voto

zneak Points 45458

Je suis en retard sur la fête, mais la norme dit que les fonctions locales de type n'ont pas de lien (§3.5:8) :

Les noms non couverts par ces règles n'ont pas de lien. De plus, sauf indication contraire, un Le nom déclaré à la portée du bloc (3.3.3) n'a pas de lien avec le nom de l'utilisateur. .

La même section poursuit en disant :

Un type sans liaison ne doit pas être utilisé comme type d'une variable ou d'une fonction avec liaison externe, sauf si

  • l'entité a un lien avec le langage C (7.5), ou
  • l'entité est déclarée dans un espace de nom non nommé (7.3.1) ou
  • l'entité n'est pas odr-used (3.2) ou est définie dans la même unité de traduction.

Et, en fait, Clang le permet :

namespace
{
    template<void (*FUNC_PTR)(void)>
    struct Func {};

    template<typename T>
    void foo() {}
}

int main() {
    struct Bar {}; // function-local type
    Func<foo<Bar>> x;
}

Et le rejettera sans l'espace de nom anonyme.


EDIT 1 : Comme le note jxh, les noms sont également définis dans la même unité de traduction, donc je ne sais pas trop quoi penser de celle-ci.


EDIT 2 : Les gars de Clang confirment que c'est un bug.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X