2017-07-17 1 views
1

Considérez ce qui suit test.c:Pourquoi les directives #line ne sont pas traitées dans false #if in clang?

int main(void) 
{ 
    int a; 
#if 1==0 
#line 1 "test.c" 
#endif 
    a = 1; 
    return 0; 
} 

Notez que #if condition est fausse ici.

que je dois faire ainsi, qu'après avoir effectué les commandes suivantes la sortie ne sera pas vide:

clang -g test.c 
objdump -D a.out >dis 
sed -i 's/line 1/line 2/' test.c 
clang -g test.c 
objdump -D a.out | diff dis - 

Pour faire la différence claire: si nous changeons 1==0 à 1==1 dans l'exemple et exécutez le ci-dessus commandes, nous obtenons la sortie suivante:

749c749 
< 33: 05 05 0a c8 05   add $0x5c80a05,%eax 
--- 
> 33: 05 05 0a c9 05   add $0x5c90a05,%eax 

En d'autres termes, je dois faire honneur clang toujours #line directives à l'intérieur #if, même si c'est faux.

Ceci est nécessaire pour compiler correctement la sortie de ctangle. Dans le cas contraire, les avertissements et les numéros de ligne de débogage sont incorrects.

Cela ne devrait pas être difficile à faire, car les lignes à l'intérieur de # if- # endif sont numérisées de toute façon.

Et les directives #line en dehors de # if- # endif (et à l'intérieur - si elle est vraie) sont traitées si nécessaire.

Donc, j'ai juste besoin de combiner ces deux comportements - effectuer le traitement nécessaire pour les directives #line dans # if- # endif. Est-ce que quelqu'un peut me diriger vers la bonne direction comment changer la source clang? (Toute version clang fera)

+1

Le compilateur est sous des instructions strictes par les gens qui ont écrit la norme d'ignorer le contenu des sections de code sautée en raison des directives de préprocesseur insatisfaits (sauf dans la mesure nécessaire pour déterminer l'imbrication de "# if", etc.). Puisque le '# line' est ignoré, il doit être ignoré. Si vous voulez le traiter, il ne doit pas être ignoré. –

+1

ISO/CEI 9899: 2011 §6.10.1 Inclusion conditionnelle ¶6 _La condition de chaque directive est vérifiée dans l'ordre. Si elle est évaluée à false (zéro), le groupe qu'elle contrôle est ignoré: les directives ne sont traitées que par le nom qui détermine la directive afin de garder une trace du niveau des conditions imbriquées; le reste des jetons de prétraitement des directives est ignoré, tout comme les autres jetons de prétraitement du groupe . Seul le premier groupe dont la condition de contrôle est évaluée à vrai (non nul) est traité ._ [... suite ...] –

+1

[... suite ...] _Si aucune des conditions n'est vraie, et qu'il y a une directive '# else', le groupe contrôlé par le' # else' est traité; manquant une directive '# else', tous les groupes jusqu'à ce que' # endif' soit sauté._ Le terme 'group' est utilisé pour décrire les lignes contrôlées par' # if' ('# ifdef',' # ifndef', les directives '# elif',' # endif'). –

Répondre

0

Les correctifs suivants ce (applicable aux clang-4.0 et au-dessus):

clang/lib/Lex/PPDirectives.cpp: 

@@ -358,7 +358,7 @@ 

    char FirstChar = RI[0]; 
    if (FirstChar >= 'a' && FirstChar <= 'z' && 
-  FirstChar != 'i' && FirstChar != 'e') { 
+  FirstChar != 'i' && FirstChar != 'e' && FirstChar != 'l') { 
     CurPPLexer->ParsingPreprocessorDirective = false; 
     // Restore comment saving mode. 
     if (CurLexer) CurLexer->resetExtendedTokenMode(); 
@@ -479,6 +479,11 @@ 
     } 
     } 
    } 
+ else if (Directive[0] == 'l') { 
+  CurPPLexer->LexingRawMode = false; 
+  HandleLineDirective(); 
+  CurPPLexer->LexingRawMode = true; 
+ } 

    CurPPLexer->ParsingPreprocessorDirective = false; 
    // Restore comment saving mode. 

Maintenant, nous pouvons utiliser des sections dans préprocesseur conditionals (y compris conditionals comme #ifdef, qui sont connus seulement à la compilation). Et nous pouvons utiliser des fichiers de changement qui changent les conditions du préprocesseur.

Voir aussi https://bugs.llvm.org/show_bug.cgi?id=33806

Un patch pour gcc est la bienvenue ...