/* { dg-do compile } */ /* { dg-options "-O -fdiagnostics-show-caret" } */ /* This is a collection of unittests for ranges within string literals, using diagnostic_plugin_test_string_literals, which handles "__emit_string_literal_range" by generating a warning at the given subset of a string literal. The indices are 0-based. It's easiest to verify things using string literals that are runs of 0-based digits (to avoid having to count characters). LITERAL is a const void * to allow testing the various kinds of wide string literal, rather than just const char *. */ extern void __emit_string_literal_range (const void *literal, int caret_idx, int start_idx, int end_idx); void test_simple_string_literal (void) { __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */ 6, 6, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("0123456789", ^~ { dg-end-multiline-output "" } */ } void test_concatenated_string_literal (void) { __emit_string_literal_range ("01234" "56789", /* { dg-warning "range" } */ 4, 3, 6); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234" "56789", ~^~~~~~ { dg-end-multiline-output "" } */ } void test_multiline_string_literal (void) { __emit_string_literal_range ("01234" /* { dg-warning "range" } */ "56789", 4, 3, 6); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234" ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "56789", ~~~ { dg-end-multiline-output "" } */ /* FIXME: why does the above need three trailing spaces? */ } /* Tests of various unicode encodings. Digits 0 through 9 are unicode code points: U+0030 DIGIT ZERO ... U+0039 DIGIT NINE However, these are not always valid as UCN (see the comment in libcpp/charset.c:_cpp_valid_ucn). Hence we need to test UCN using an alternative unicode representation of numbers; let's use Roman numerals, (though these start at one, not zero): U+2170 SMALL ROMAN NUMERAL ONE ... U+2174 SMALL ROMAN NUMERAL FIVE ("v") U+2175 SMALL ROMAN NUMERAL SIX ("vi") ... U+2178 SMALL ROMAN NUMERAL NINE. */ void test_hex (void) { /* Digits 0-9, expressing digit 5 in ASCII as "\x35" and with a space in place of digit 6, to terminate the escaped hex code. */ __emit_string_literal_range ("01234\x35 789", /* { dg-warning "range" } */ 4, 3, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234\x35 789" ~^~~~~~~ { dg-end-multiline-output "" } */ } void test_oct (void) { /* Digits 0-9, expressing digit 5 in ASCII as "\065" and with a space in place of digit 6, to terminate the escaped octal code. */ __emit_string_literal_range ("01234\065 789", /* { dg-warning "range" } */ 4, 3, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234\065 789" ~^~~~~~~ { dg-end-multiline-output "" } */ } void test_multiple (void) { /* Digits 0-9, expressing digit 5 in ASCII as hex "\x35" digit 6 in ASCII as octal "\066", concatenating multiple strings. */ __emit_string_literal_range ("01234" "\x35" "\066" "789", /* { dg-warning "range" } */ 5, 3, 8); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234" "\x35" "\066" "789", ~~~~~~^~~~~~~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_ucn4 (void) { /* Digits 0-9, expressing digits 5 and 6 as Roman numerals expressed as UCN 4. The resulting string is encoded as UTF-8. Most of the digits are 1 byte each, but digits 5 and 6 are encoded with 3 bytes each. Hence to underline digits 4-7 we need to underling using bytes 4-11 in the UTF-8 encoding. */ __emit_string_literal_range ("01234\u2174\u2175789", /* { dg-warning "range" } */ 5, 4, 11); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234\u2174\u2175789", ~^~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_ucn8 (void) { /* Digits 0-9, expressing digits 5 and 6 as Roman numerals as UCN 8. The resulting string is the same as as in test_ucn4 above, and hence has the same UTF-8 encoding, and so we again need to underline bytes 4-11 in the UTF-8 encoding in order to underline digits 4-7. */ __emit_string_literal_range ("01234\U00002174\U00002175789", /* { dg-warning "range" } */ 5, 4, 11); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("01234\U00002174\U00002175789", ~^~~~~~~~~~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_u8 (void) { /* Digits 0-9. */ __emit_string_literal_range (u8"0123456789", /* { dg-warning "range" } */ 6, 4, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range (u8"0123456789", ~~^~ { dg-end-multiline-output "" } */ } void test_u (void) { /* Digits 0-9. */ __emit_string_literal_range (u"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */ 6, 4, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range (u"0123456789", ^~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_U (void) { /* Digits 0-9. */ __emit_string_literal_range (U"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */ 6, 4, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range (U"0123456789", ^~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_L (void) { /* Digits 0-9. */ __emit_string_literal_range (L"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */ 6, 4, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range (L"0123456789", ^~~~~~~~~~~~~ { dg-end-multiline-output "" } */ } void test_raw_string_one_liner (void) { /* Digits 0-9. */ __emit_string_literal_range (R"foo(0123456789)foo", /* { dg-warning "range" } */ 6, 4, 7); /* { dg-begin-multiline-output "" } __emit_string_literal_range (R"foo(0123456789)foo", ~~^~ { dg-end-multiline-output "" } */ } void test_raw_string_multiline (void) { __emit_string_literal_range (R"foo( hello world )foo", 6, 4, 7); /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-5 } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range (R"foo( ^~~~~~ hello ~~~~~ world ~~~~~ )foo", ~~~~~ { dg-end-multiline-output "" } */ } void test_macro (void) { #define START "01234" /* { dg-warning "range" } */ __emit_string_literal_range (START "56789", 4, 3, 6); /* { dg-begin-multiline-output "" } #define START "01234" ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ __emit_string_literal_range (START ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "56789", ~~~ { dg-end-multiline-output "" } */ } void test_multitoken_macro (void) { #define RANGE ("0123456789") /* { dg-error "unable to read substring location: macro expansion" } */ __emit_string_literal_range (RANGE, 4, 3, 6); /* { dg-begin-multiline-output "" } #define RANGE ("0123456789") ^~~~~~~~~~~~~~ { dg-end-multiline-output "" { target c } } */ /* { dg-begin-multiline-output "" } #define RANGE ("0123456789") ~^~~~~~~~~~~~~ { dg-end-multiline-output "" { target c++ } } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range (RANGE, 4, 3, 6); ^~~~~ { dg-end-multiline-output "" } */ #undef RANGE } /* Verify that the location of the closing quote is used for the location of the null terminating character. */ void test_terminator_location (void) { __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */ 10, 10, 10); /* { dg-begin-multiline-output "" } __emit_string_literal_range ("0123456789", ^ { dg-end-multiline-output "" } */ } /* Verify that we fail gracefully when a string literal token is split across multiple physical lines. */ void test_backslash_continued_logical_lines (void) { __emit_string_literal_range ("\ 01234\ 56789", 6, 6, 7); /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-3 } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range ("\ ^~ 01234\ ~~~~~~ 56789", 6, 6, 7); ~~~~~~ { dg-end-multiline-output "" } */ } /* Reproducer for PR 87652; this is whitespace-sensitive. */ #include "pr87562-a.h" #include "pr87562-b.h" void pr87652 (const char *stem, int counter) { char label[100]; ASM_GENERATE_INTERNAL_LABEL (label, stem, counter); /* This warning is actually in "pr87562-a.h". */ /* { dg-warning "39: range" "" { target *-*-* } 5 } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range ("*.%s%u", 2, 2, 3); \ ^~ { dg-end-multiline-output "" } */ } /* Reproducer for PR 87721. */ # define OFFSET __builtin_strlen (__FILE__) + __builtin_strlen(":%5d: ") # define DBG_ERROR(format, caret_idx, start_idx, end_idx) \ do { \ __emit_string_literal_range(__FILE__":%5d: " format, \ OFFSET + caret_idx, \ OFFSET + start_idx, \ OFFSET + end_idx); \ } while (0) /* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c } 329 } */ /* { dg-error "unable to read substring location: macro expansion" "" { target c++ } 329 } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range(__FILE__":%5d: " format, \ ^~~~~~~~ { dg-end-multiline-output "" { target c } } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range(__FILE__":%5d: " format, \ ^ { dg-end-multiline-output "" { target c++ } } */ void pr87721 (void) { DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25); /* { dg-message "in expansion of macro 'DBG_ERROR'" } */ /* { dg-begin-multiline-output "" } DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25); ^~~~~~~~~ { dg-end-multiline-output "" } */ }