From 7f5f5f98c5c21e263884362a248e5891e98ac6bc Mon Sep 17 00:00:00 2001 From: Ollie Wild Date: Fri, 27 Apr 2012 14:29:32 +0000 Subject: [PATCH] Add new option, -Wliteral-suffix. This option, which is enabled by default, causes the preprocessor to warn when a string or character literal is followed by a ud-suffix which does not begin with an underscore. According to [lex.ext]p10, this is ill-formed. Also modifies the preprocessor to treat such ill-formed suffixes as separate preprocessing tokens. This is consistent with the Clang front end (see http://llvm.org/viewvc/llvm-project?view=rev&revision=152287), and enables backwards compatibility with code that uses formatting macros from , as in the following code block: int main() { int64_t i64 = 123; printf("My int64: %"PRId64"\n", i64); } Google ref b/6377711. 2012-04-27 Ollie Wild PR c++/52538 * gcc/c-family/c-common.c: Add CPP_W_LITERAL_SUFFIX mapping. * gcc/c-family/c-opts.c (c_common_handle_option): Handle OPT_Wliteral_suffix. * gcc/c-family/c.opt: Add Wliteral-suffix. * gcc/doc/invoke.texi (Wliteral-suffix): Document new option. * gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.c: New test. * libcpp/include/cpplib.h (struct cpp_options): Add new field, warn_literal_suffix. (CPP_W_LITERAL_SUFFIX): New enum. * libcpp/init.c (cpp_create_reader): Default initialization of warn_literal_suffix. * libcpp/lex.c (lex_raw_string): Treat user-defined literals which don't begin with '_' as separate tokens and produce a warning. (lex_string): Ditto. From-SVN: r186909 --- gcc/ChangeLog | 4 ++ gcc/c-family/ChangeLog | 6 +++ gcc/c-family/c-common.c | 1 + gcc/c-family/c-opts.c | 4 ++ gcc/c-family/c.opt | 4 ++ gcc/doc/invoke.texi | 28 ++++++++++++- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.C | 29 +++++++++++++ libcpp/ChangeLog | 11 +++++ libcpp/include/cpplib.h | 7 +++- libcpp/init.c | 1 + libcpp/lex.c | 44 +++++++++++++++++--- 12 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index aeda32c9791..7097f17befd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2012-04-27 Ollie Wild + + * doc/invoke.texi (Wliteral-suffix): Document new option. + 2012-04-27 Tom Tromey * dwarf2out.c (dwarf_stack_op_name): Use get_DW_OP_name. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fb895315d43..2082ff6c4af 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2012-04-27 Ollie Wild + + * c-common.c: Add CPP_W_LITERAL_SUFFIX mapping. + * c-opts.c (c_common_handle_option): Handle OPT_Wliteral_suffix. + * c.opt: Add Wliteral-suffix. + 2012-04-22 Manuel López-Ibáñez PR c/44774 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 4eacd198d77..bf5b034ee2d 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8820,6 +8820,7 @@ static const struct reason_option_codes_t option_codes[] = { {CPP_W_NORMALIZE, OPT_Wnormalized_}, {CPP_W_INVALID_PCH, OPT_Winvalid_pch}, {CPP_W_WARNING_DIRECTIVE, OPT_Wcpp}, + {CPP_W_LITERAL_SUFFIX, OPT_Wliteral_suffix}, {CPP_W_NONE, 0} }; diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 17e1958ad58..2510747c40e 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -476,6 +476,10 @@ c_common_handle_option (size_t scode, const char *arg, int value, cpp_opts->warn_invalid_pch = value; break; + case OPT_Wliteral_suffix: + cpp_opts->warn_literal_suffix = value; + break; + case OPT_Wlong_long: cpp_opts->cpp_warn_long_long = value; break; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index d8c944d7e13..db8ca812ca5 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -449,6 +449,10 @@ Wjump-misses-init C ObjC Var(warn_jump_misses_init) Init(-1) Warning Warn when a jump misses a variable initialization +Wliteral-suffix +C++ ObjC++ Warning +Warn when a string or character literal is followed by a ud-suffix which does not begin with an underscore. + Wlogical-op C ObjC C++ ObjC++ Var(warn_logical_op) Init(0) Warning Warn when a logical operator is suspiciously always evaluating to true or false diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c6bf20dd3d3..280fac3b04b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -198,8 +198,8 @@ in the following sections. -fno-default-inline -fvisibility-inlines-hidden @gol -fvisibility-ms-compat @gol -Wabi -Wconversion-null -Wctor-dtor-privacy @gol --Wdelete-non-virtual-dtor -Wnarrowing -Wnoexcept @gol --Wnon-virtual-dtor -Wreorder @gol +-Wdelete-non-virtual-dtor -Wliteral-suffix -Wnarrowing @gol +-Wnoexcept -Wnon-virtual-dtor -Wreorder @gol -Weffc++ -Wstrict-null-sentinel @gol -Wno-non-template-friend -Wold-style-cast @gol -Woverloaded-virtual -Wno-pmf-conversions @gol @@ -2425,6 +2425,30 @@ an instance of a derived class through a pointer to a base class if the base class does not have a virtual destructor. This warning is enabled by @option{-Wall}. +@item -Wliteral-suffix @r{(C++ and Objective-C++ only)} +@opindex Wliteral-suffix +@opindex Wno-literal-suffix +Warn when a string or character literal is followed by a ud-suffix which does +not begin with an underscore. As a conforming extension, GCC treats such +suffixes as separate preprocessing tokens in order to maintain backwards +compatibility with code that uses formatting macros from @code{}. +For example: + +@smallexample +#define __STDC_FORMAT_MACROS +#include +#include + +int main() @{ + int64_t i64 = 123; + printf("My int64: %"PRId64"\n", i64); +@} +@end smallexample + +In this case, @code{PRId64} is treated as a separate preprocessing token. + +This warning is enabled by default. + @item -Wnarrowing @r{(C++ and Objective-C++ only)} @opindex Wnarrowing @opindex Wno-narrowing diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 72f1f468456..54c616c441d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2012-04-27 Ollie Wild + + * g++.dg/cpp0x/Wliteral-suffix.c: New test. + 2012-04-27 Paolo Bonzini * gcc.c-torture/execute/20120427-2.c: New testcase. diff --git a/gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.C b/gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.C new file mode 100644 index 00000000000..39a8353561c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/Wliteral-suffix.C @@ -0,0 +1,29 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Make sure -Wliteral-suffix is enabled by default and +// triggers as expected. + +#define BAR "bar" +#define PLUS_ONE + 1 + +#include +#include + + +void +test() +{ + char c = '3'PLUS_ONE; // { dg-warning "invalid suffix on literal" } + char s[] = "foo"BAR; // { dg-warning "invalid suffix on literal" } + + assert(c == '4'); + assert(s[3] != '\0'); + assert(s[3] == 'b'); +} + +int +main() +{ + test(); +} diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 08878b27811..f7c330c5143 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,14 @@ +2012-04-27 Ollie Wild + + * include/cpplib.h (struct cpp_options): Add new field, + warn_literal_suffix. + (CPP_W_LITERAL_SUFFIX): New enum. + * init.c (cpp_create_reader): Default initialization of + warn_literal_suffix. + * lex.c (lex_raw_string): Treat user-defined literals which don't + begin with '_' as separate tokens and produce a warning. + (lex_string): Ditto. + 2012-04-26 Manuel López-Ibáñez * line-map.c (linemap_resolve_location): Synchronize comments with diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index bf59d016231..9dbc477b61e 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -427,6 +427,10 @@ struct cpp_options /* Nonzero for C++ 2011 Standard user-defnied literals. */ unsigned char user_literals; + /* Nonzero means warn when a string or character literal is followed by a + ud-suffix which does not beging with an underscore. */ + unsigned char warn_literal_suffix; + /* Holds the name of the target (execution) character set. */ const char *narrow_charset; @@ -906,7 +910,8 @@ enum { CPP_W_CXX_OPERATOR_NAMES, CPP_W_NORMALIZE, CPP_W_INVALID_PCH, - CPP_W_WARNING_DIRECTIVE + CPP_W_WARNING_DIRECTIVE, + CPP_W_LITERAL_SUFFIX }; /* Output a diagnostic of some kind. */ diff --git a/libcpp/init.c b/libcpp/init.c index 5fa82ca9c3e..3262184c9c5 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -175,6 +175,7 @@ cpp_create_reader (enum c_lang lang, hash_table *table, CPP_OPTION (pfile, warn_variadic_macros) = 1; CPP_OPTION (pfile, warn_builtin_macro_redefined) = 1; CPP_OPTION (pfile, warn_normalize) = normalized_C; + CPP_OPTION (pfile, warn_literal_suffix) = 1; /* Default CPP arithmetic to something sensible for the host for the benefit of dumb users like fix-header. */ diff --git a/libcpp/lex.c b/libcpp/lex.c index 9d23002d84b..7e2671ef026 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -1553,14 +1553,30 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base, if (CPP_OPTION (pfile, user_literals)) { + /* According to C++11 [lex.ext]p10, a ud-suffix not starting with an + underscore is ill-formed. Since this breaks programs using macros + from inttypes.h, we generate a warning and treat the ud-suffix as a + separate preprocessing token. This approach is under discussion by + the standards committee, and has been adopted as a conforming + extension by other front ends such as clang. */ + if (ISALPHA (*cur)) + { + // Raise a warning, but do not consume subsequent tokens. + if (CPP_OPTION (pfile, warn_literal_suffix)) + cpp_warning_with_line (pfile, CPP_W_LITERAL_SUFFIX, + token->src_loc, 0, + "invalid suffix on literal; C++11 requires " + "a space between literal and identifier"); + } /* Grab user defined literal suffix. */ - if (ISIDST (*cur)) + else if (*cur == '_') { type = cpp_userdef_string_add_type (type); ++cur; + + while (ISIDNUM (*cur)) + ++cur; } - while (ISIDNUM (*cur)) - ++cur; } pfile->buffer->cur = cur; @@ -1668,15 +1684,31 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base) if (CPP_OPTION (pfile, user_literals)) { + /* According to C++11 [lex.ext]p10, a ud-suffix not starting with an + underscore is ill-formed. Since this breaks programs using macros + from inttypes.h, we generate a warning and treat the ud-suffix as a + separate preprocessing token. This approach is under discussion by + the standards committee, and has been adopted as a conforming + extension by other front ends such as clang. */ + if (ISALPHA (*cur)) + { + // Raise a warning, but do not consume subsequent tokens. + if (CPP_OPTION (pfile, warn_literal_suffix)) + cpp_warning_with_line (pfile, CPP_W_LITERAL_SUFFIX, + token->src_loc, 0, + "invalid suffix on literal; C++11 requires " + "a space between literal and identifier"); + } /* Grab user defined literal suffix. */ - if (ISIDST (*cur)) + else if (*cur == '_') { type = cpp_userdef_char_add_type (type); type = cpp_userdef_string_add_type (type); ++cur; + + while (ISIDNUM (*cur)) + ++cur; } - while (ISIDNUM (*cur)) - ++cur; } pfile->buffer->cur = cur;