1  /* { dg-do compile } */
       2  /* { dg-options "-O -fdiagnostics-show-caret" } */
       3  
       4  /* This is a collection of unittests for ranges within string literals,
       5     using diagnostic_plugin_test_string_literals, which handles
       6     "__emit_string_literal_range" by generating a warning at the given
       7     subset of a string literal.
       8  
       9     The indices are 0-based.  It's easiest to verify things using string
      10     literals that are runs of 0-based digits (to avoid having to count
      11     characters).
      12  
      13     LITERAL is a const void * to allow testing the various kinds of wide
      14     string literal, rather than just const char *.  */
      15  
      16  extern void __emit_string_literal_range (const void *literal, int caret_idx,
      17  					 int start_idx, int end_idx);
      18  
      19  void
      20  test_simple_string_literal (void)
      21  {
      22    __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */
      23  			       6, 6, 7);
      24  /* { dg-begin-multiline-output "" }
      25     __emit_string_literal_range ("0123456789",
      26                                         ^~
      27     { dg-end-multiline-output "" } */
      28  }
      29  
      30  void
      31  test_concatenated_string_literal (void)
      32  {
      33    __emit_string_literal_range ("01234" "56789", /* { dg-warning "range" } */
      34  			       4, 3, 6);
      35  /* { dg-begin-multiline-output "" }
      36     __emit_string_literal_range ("01234" "56789",
      37                                      ~^~~~~~
      38     { dg-end-multiline-output "" } */
      39  }
      40  
      41  void
      42  test_multiline_string_literal (void)
      43  {
      44    __emit_string_literal_range ("01234" /* { dg-warning "range" } */
      45                                 "56789",
      46                                 4, 3, 6);
      47  /* { dg-begin-multiline-output "" }
      48     __emit_string_literal_range ("01234"
      49                                      ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      50                                  "56789",
      51                                  ~~~   
      52     { dg-end-multiline-output "" } */
      53    /* FIXME: why does the above need three trailing spaces?  */
      54  }
      55  
      56  /* Tests of various unicode encodings.
      57  
      58     Digits 0 through 9 are unicode code points:
      59        U+0030 DIGIT ZERO
      60        ...
      61        U+0039 DIGIT NINE
      62     However, these are not always valid as UCN (see the comment in
      63     libcpp/charset.c:_cpp_valid_ucn).
      64  
      65     Hence we need to test UCN using an alternative unicode
      66     representation of numbers; let's use Roman numerals,
      67     (though these start at one, not zero):
      68        U+2170 SMALL ROMAN NUMERAL ONE
      69        ...
      70        U+2174 SMALL ROMAN NUMERAL FIVE  ("v")
      71        U+2175 SMALL ROMAN NUMERAL SIX   ("vi")
      72        ...
      73        U+2178 SMALL ROMAN NUMERAL NINE.  */
      74  
      75  void
      76  test_hex (void)
      77  {
      78    /* Digits 0-9, expressing digit 5 in ASCII as "\x35"
      79       and with a space in place of digit 6, to terminate the escaped
      80       hex code.  */
      81    __emit_string_literal_range ("01234\x35 789", /* { dg-warning "range" } */
      82  			       4, 3, 7);
      83  /* { dg-begin-multiline-output "" }
      84     __emit_string_literal_range ("01234\x35 789"
      85                                      ~^~~~~~~
      86     { dg-end-multiline-output "" } */
      87  }
      88  
      89  void
      90  test_oct (void)
      91  {
      92    /* Digits 0-9, expressing digit 5 in ASCII as "\065"
      93       and with a space in place of digit 6, to terminate the escaped
      94       octal code.  */
      95    __emit_string_literal_range ("01234\065 789", /* { dg-warning "range" } */
      96  			       4, 3, 7);
      97  /* { dg-begin-multiline-output "" }
      98     __emit_string_literal_range ("01234\065 789"
      99                                      ~^~~~~~~
     100     { dg-end-multiline-output "" } */
     101  }
     102  
     103  void
     104  test_multiple (void)
     105  {
     106    /* Digits 0-9, expressing digit 5 in ASCII as hex "\x35"
     107       digit 6 in ASCII as octal "\066", concatenating multiple strings.  */
     108    __emit_string_literal_range ("01234"  "\x35"  "\066"  "789", /* { dg-warning "range" } */
     109  			       5, 3, 8);
     110  /* { dg-begin-multiline-output "" }
     111     __emit_string_literal_range ("01234"  "\x35"  "\066"  "789",
     112                                      ~~~~~~^~~~~~~~~~~~~~~~~~
     113     { dg-end-multiline-output "" } */
     114  }
     115  
     116  void
     117  test_ucn4 (void)
     118  {
     119    /* Digits 0-9, expressing digits 5 and 6 as Roman numerals expressed
     120       as UCN 4.
     121       The resulting string is encoded as UTF-8.  Most of the digits are 1 byte
     122       each, but digits 5 and 6 are encoded with 3 bytes each.
     123       Hence to underline digits 4-7 we need to underling using bytes 4-11 in
     124       the UTF-8 encoding.  */
     125    __emit_string_literal_range ("01234\u2174\u2175789", /* { dg-warning "range" } */
     126  			       5, 4, 11);
     127  /* { dg-begin-multiline-output "" }
     128     __emit_string_literal_range ("01234\u2174\u2175789",
     129                                       ~^~~~~~~~~~~~~
     130     { dg-end-multiline-output "" } */
     131  }
     132  
     133  void
     134  test_ucn8 (void)
     135  {
     136    /* Digits 0-9, expressing digits 5 and 6 as Roman numerals as UCN 8.
     137       The resulting string is the same as as in test_ucn4 above, and hence
     138       has the same UTF-8 encoding, and so we again need to underline bytes
     139       4-11 in the UTF-8 encoding in order to underline digits 4-7.  */
     140    __emit_string_literal_range ("01234\U00002174\U00002175789", /* { dg-warning "range" } */
     141  			       5, 4, 11);
     142  /* { dg-begin-multiline-output "" }
     143     __emit_string_literal_range ("01234\U00002174\U00002175789",
     144                                       ~^~~~~~~~~~~~~~~~~~~~~
     145     { dg-end-multiline-output "" } */
     146  }
     147  
     148  void
     149  test_u8 (void)
     150  {
     151    /* Digits 0-9.  */
     152    __emit_string_literal_range (u8"0123456789", /* { dg-warning "range" } */
     153  			       6, 4, 7);
     154  /* { dg-begin-multiline-output "" }
     155     __emit_string_literal_range (u8"0123456789",
     156                                         ~~^~
     157     { dg-end-multiline-output "" } */
     158  }
     159  
     160  void
     161  test_u (void)
     162  {
     163    /* Digits 0-9.  */
     164    __emit_string_literal_range (u"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
     165  			       6, 4, 7);
     166  /* { dg-begin-multiline-output "" }
     167     __emit_string_literal_range (u"0123456789",
     168                                  ^~~~~~~~~~~~~
     169     { dg-end-multiline-output "" } */
     170  }
     171  
     172  void
     173  test_U (void)
     174  {
     175    /* Digits 0-9.  */
     176    __emit_string_literal_range (U"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
     177  			       6, 4, 7);
     178  /* { dg-begin-multiline-output "" }
     179     __emit_string_literal_range (U"0123456789",
     180                                  ^~~~~~~~~~~~~
     181     { dg-end-multiline-output "" } */
     182  }
     183  
     184  void
     185  test_L (void)
     186  {
     187    /* Digits 0-9.  */
     188    __emit_string_literal_range (L"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
     189  			       6, 4, 7);
     190  /* { dg-begin-multiline-output "" }
     191     __emit_string_literal_range (L"0123456789",
     192                                  ^~~~~~~~~~~~~
     193     { dg-end-multiline-output "" } */
     194  }
     195  
     196  void
     197  test_raw_string_one_liner (void)
     198  {
     199    /* Digits 0-9.  */
     200    __emit_string_literal_range (R"foo(0123456789)foo", /* { dg-warning "range" } */
     201  			       6, 4, 7);
     202  /* { dg-begin-multiline-output "" }
     203     __emit_string_literal_range (R"foo(0123456789)foo",
     204                                            ~~^~
     205     { dg-end-multiline-output "" } */
     206  }
     207  
     208  void
     209  test_raw_string_multiline (void)
     210  {
     211    __emit_string_literal_range (R"foo(
     212  hello
     213  world
     214  )foo",
     215  			       6, 4, 7);
     216    /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-5 } */
     217    /* { dg-begin-multiline-output "" }
     218     __emit_string_literal_range (R"foo(
     219                                  ^~~~~~
     220   hello
     221   ~~~~~                           
     222   world
     223   ~~~~~                           
     224   )foo",
     225   ~~~~~                           
     226     { dg-end-multiline-output "" } */
     227  }
     228  
     229  void
     230  test_macro (void)
     231  {
     232  #define START "01234"  /* { dg-warning "range" } */
     233    __emit_string_literal_range (START
     234                                 "56789",
     235                                 4, 3, 6);
     236  /* { dg-begin-multiline-output "" }
     237   #define START "01234"
     238                     ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     239     __emit_string_literal_range (START
     240     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     241                                  "56789",
     242                                  ~~~
     243     { dg-end-multiline-output "" } */
     244  }
     245  
     246  void
     247  test_multitoken_macro (void)
     248  {
     249  #define RANGE ("0123456789")  /* { dg-error "unable to read substring location: macro expansion" } */
     250    __emit_string_literal_range (RANGE, 4, 3, 6);
     251  /* { dg-begin-multiline-output "" }
     252   #define RANGE ("0123456789")
     253                 ^~~~~~~~~~~~~~
     254     { dg-end-multiline-output "" { target c } } */
     255  /* { dg-begin-multiline-output "" }
     256   #define RANGE ("0123456789")
     257                 ~^~~~~~~~~~~~~
     258     { dg-end-multiline-output "" { target c++ } } */
     259  /* { dg-begin-multiline-output "" }
     260     __emit_string_literal_range (RANGE, 4, 3, 6);
     261                                  ^~~~~
     262     { dg-end-multiline-output "" } */
     263  #undef RANGE
     264  }
     265  
     266  /* Verify that the location of the closing quote is used
     267     for the location of the null terminating character.  */
     268  
     269  void
     270  test_terminator_location (void)
     271  {
     272    __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */
     273  			       10, 10, 10);
     274  /* { dg-begin-multiline-output "" }
     275     __emit_string_literal_range ("0123456789",
     276                                             ^
     277     { dg-end-multiline-output "" } */
     278  }
     279  
     280  /* Verify that we fail gracefully when a string literal token is split
     281     across multiple physical lines.  */
     282  
     283  void
     284  test_backslash_continued_logical_lines (void)
     285  {
     286    __emit_string_literal_range ("\
     287  01234\
     288  56789", 6, 6, 7);
     289    /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-3 } */
     290    /* { dg-begin-multiline-output "" }
     291     __emit_string_literal_range ("\
     292                                  ^~
     293   01234\
     294   ~~~~~~                          
     295   56789", 6, 6, 7);
     296   ~~~~~~                          
     297     { dg-end-multiline-output "" } */
     298  }
     299  
     300  /* Reproducer for PR 87652; this is whitespace-sensitive.  */
     301  
     302  #include "pr87562-a.h"
     303  
     304  
     305  
     306  
     307  #include "pr87562-b.h"
     308  
     309  void
     310  pr87652 (const char *stem, int counter)
     311  {
     312    char label[100];
     313    ASM_GENERATE_INTERNAL_LABEL (label, stem, counter);
     314  
     315    /* This warning is actually in "pr87562-a.h".  */
     316    /* { dg-warning "39: range" "" { target *-*-* } 5 } */
     317    /* { dg-begin-multiline-output "" }
     318         __emit_string_literal_range ("*.%s%u", 2, 2, 3); \
     319                                         ^~
     320       { dg-end-multiline-output "" } */
     321  }
     322  
     323  /* Reproducer for PR 87721.  */
     324  
     325  # define OFFSET __builtin_strlen (__FILE__) + __builtin_strlen(":%5d: ")
     326  
     327  # define DBG_ERROR(format, caret_idx, start_idx, end_idx)	\
     328    do {								\
     329      __emit_string_literal_range(__FILE__":%5d: " format,	\
     330  				OFFSET + caret_idx,		\
     331  				OFFSET + start_idx,		\
     332  				OFFSET + end_idx);		\
     333    } while (0)
     334  
     335  /* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c } 329 } */
     336  /* { dg-error "unable to read substring location: macro expansion" "" { target c++ } 329 } */
     337  /* { dg-begin-multiline-output "" }
     338       __emit_string_literal_range(__FILE__":%5d: " format,        \
     339                                   ^~~~~~~~
     340       { dg-end-multiline-output "" { target c } } */
     341  /* { dg-begin-multiline-output "" }
     342       __emit_string_literal_range(__FILE__":%5d: " format,        \
     343                                   ^
     344       { dg-end-multiline-output "" { target c++ } } */
     345  
     346  void pr87721 (void) {
     347    DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25); /* { dg-message "in expansion of macro 'DBG_ERROR'" } */
     348    /* { dg-begin-multiline-output "" }
     349     DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25);
     350     ^~~~~~~~~
     351       { dg-end-multiline-output "" } */
     352  }