From 661a99690bc133bbaa029da925481d4a860dec90 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 15 Oct 2011 01:18:56 +0000 Subject: -Wc++98-compat warnings for the lexer. This also adds a -Wc++98-compat-pedantic for warning on constructs which would be diagnosed by -std=c++98 -pedantic (that is, it warns even on C++11 features which we enable by default, with no warning, in C++98 mode). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142034 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticCommonKinds.td | 3 +++ include/clang/Basic/DiagnosticGroups.td | 2 ++ include/clang/Basic/DiagnosticLexKinds.td | 20 ++++++++++++++++++++ lib/Lex/Lexer.cpp | 15 +++++++++++++++ lib/Lex/PPDirectives.cpp | 8 ++++++-- lib/Lex/PPExpressions.cpp | 7 +++---- lib/Lex/PPMacroExpansion.cpp | 6 ++++-- test/SemaCXX/cxx98-compat-pedantic.cpp | 11 +++++++++++ test/SemaCXX/cxx98-compat.cpp | 17 +++++++++++++++++ 9 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 test/SemaCXX/cxx98-compat-pedantic.cpp diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index dabaeadc85..f9a910a1c2 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -74,6 +74,9 @@ def note_pragma_entered_here : Note<"#pragma entered here">; def ext_longlong : Extension< "'long long' is an extension when C99 mode is not enabled">, InGroup; +def warn_cxx98_compat_longlong : Warning< + "'long long' is incompatible with C++98">, + InGroup, DefaultIgnore; def warn_integer_too_large : Warning< "integer constant is too large for its type">; def warn_integer_too_large_for_signed : Warning< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index c499b08b4b..49603eb69e 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -55,6 +55,8 @@ def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; def CXX98Compat : DiagGroup<"c++98-compat">; +// Warnings for C++11 features which are Extensions in C++98 mode. +def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 04409c7de9..9b3a178cac 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -24,6 +24,11 @@ def escaped_newline_block_comment_end : Warning< def backslash_newline_space : Warning< "backslash and newline separated by space">; +// Digraphs. +def warn_cxx98_compat_less_colon_colon : Warning< + "'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">, + InGroup, DefaultIgnore; + // Trigraphs. def trigraph_ignored : Warning<"trigraph ignored">, InGroup; def trigraph_ignored_block_comment : Warning< @@ -67,6 +72,9 @@ def err_invalid_char_raw_delim : Error< "; use PREFIX( )PREFIX to delimit raw string">; def err_unterminated_raw_string : Error< "raw string missing terminating delimiter )%0\"">; +def warn_cxx98_compat_raw_string_literal : Warning< + "raw string literals are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_multichar_character_literal : ExtWarn< "multi-character character constant">, InGroup; @@ -112,6 +120,9 @@ def warn_ucn_escape_too_large : ExtWarn< "character unicode escape sequence too long for its type">; def warn_ucn_not_valid_in_c89 : ExtWarn< "unicode escape sequences are only valid in C99 or C++">; +def warn_cxx98_compat_unicode_literal : Warning< + "unicode literals are incompatible with C++98">, + InGroup, DefaultIgnore; def err_unsupported_string_concat : Error< "unsupported non-standard concatenation of string literals">; @@ -179,6 +190,9 @@ def ext_pp_bad_vaargs_use : Extension< def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">; def ext_variadic_macro : Extension<"variadic macros were introduced in C99">, InGroup; +def warn_cxx98_compat_variadic_macro : Warning< + "variadic macros are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_named_variadic_macro : Extension< "named variadic macros are a GNU extension">, InGroup; def ext_embedded_directive : Extension< @@ -187,6 +201,9 @@ def ext_missing_varargs_arg : Extension< "varargs argument missing, but tolerated as an extension">; def ext_empty_fnmacro_arg : Extension< "empty macro arguments were standardized in C99">; +def warn_cxx98_compat_empty_fnmacro_arg : Warning< + "empty macro argument list is incompatible with C++98">, + InGroup, DefaultIgnore; def err_pp_invalid_directive : Error<"invalid preprocessing directive">; def err_pp_hash_error : Error<"#error%0">; @@ -334,6 +351,9 @@ def err_pp_linemarker_invalid_pop : Error< "invalid line marker flag '2': cannot pop empty include stack">; def ext_pp_line_too_big : Extension< "C requires #line number to be less than %0, allowed as extension">; +def warn_cxx98_compat_pp_line_too_big : Warning< + "#line number greater than 32767 is incompatible with C++98">, + InGroup, DefaultIgnore; def err_pp_export_non_macro : Error<"no macro named %0 to export">; diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 802024f79b..a98d889dbc 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1373,6 +1373,12 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, tok::TokenKind Kind) { const char *NulCharacter = 0; // Does this string contain the \0 character? + if (!isLexingRawMode() && + (Kind == tok::utf8_string_literal || + Kind == tok::utf16_string_literal || + Kind == tok::utf32_string_literal)) + Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal); + char C = getAndAdvanceChar(CurPtr, Result); while (C != '"') { // Skip escaped characters. Escaped newlines will already be processed by @@ -1419,6 +1425,9 @@ void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, // any transformations performed in phases 1 and 2 (trigraphs, // universal-character-names, and line splicing) are reverted. + if (!isLexingRawMode()) + Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal); + unsigned PrefixLen = 0; while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) @@ -1523,6 +1532,10 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr, tok::TokenKind Kind) { const char *NulCharacter = 0; // Does this character contain the \0 character? + if (!isLexingRawMode() && + (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant)) + Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal); + char C = getAndAdvanceChar(CurPtr, Result); if (C == '\'') { if (!isLexingRawMode() && !Features.AsmPreprocessor) @@ -2799,6 +2812,8 @@ LexNextToken: char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); if (After != ':' && After != '>') { Kind = tok::less; + if (!isLexingRawMode()) + Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon); break; } } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 482dd77e7e..de50c750e4 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -777,6 +777,8 @@ void Preprocessor::HandleLineDirective(Token &Tok) { LineLimit = 2147483648U; if (LineNo >= LineLimit) Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit; + else if (Features.CPlusPlus0x && LineNo >= 32768U) + Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big); int FilenameID = -1; Token StrTok; @@ -1367,8 +1369,10 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { Diag(Tok, diag::err_pp_expected_ident_in_arg_list); return true; case tok::ellipsis: // #define X(... -> C99 varargs - if (!Features.C99 && !Features.CPlusPlus0x) - Diag(Tok, diag::ext_variadic_macro); + if (!Features.C99) + Diag(Tok, Features.CPlusPlus0x ? + diag::warn_cxx98_compat_variadic_macro : + diag::ext_variadic_macro); // Lex the token after the identifier. LexUnexpandedToken(Tok); diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 84156d59b9..20f624a0bb 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -216,9 +216,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); // long long is a C99 feature. - if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x - && Literal.isLongLong) - PP.Diag(PeekTok, diag::ext_longlong); + if (!PP.getLangOptions().C99 && Literal.isLongLong) + PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_longlong); // Parse the integer literal into Result. if (Literal.GetIntegerValue(Result.Val)) { @@ -778,4 +778,3 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } - diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 9b20605124..e10c95c75f 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -421,8 +421,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // Empty arguments are standard in C99 and C++0x, and are supported as an extension in // other modes. - if (ArgTokens.size() == ArgTokenStart && !Features.C99 && !Features.CPlusPlus0x) - Diag(Tok, diag::ext_empty_fnmacro_arg); + if (ArgTokens.size() == ArgTokenStart && !Features.C99) + Diag(Tok, Features.CPlusPlus0x ? + diag::warn_cxx98_compat_empty_fnmacro_arg : + diag::ext_empty_fnmacro_arg); // Add a marker EOF token to the end of the token list for this argument. Token EOFTok; diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp new file mode 100644 index 0000000000..2ca0ae4d1e --- /dev/null +++ b/test/SemaCXX/cxx98-compat-pedantic.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s + +// -Wc++98-compat-pedantic warns on C++11 features which we accept without a +// warning in C++98 mode. + +#line 32767 // ok +#line 32768 // expected-warning {{#line number greater than 32767 is incompatible with C++98}} + +#define VA_MACRO(x, ...) x // expected-warning {{variadic macros are incompatible with C++98}} +VA_MACRO(,x) // expected-warning {{empty macro argument list is incompatible with C++98}} diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index f3f323f5d4..6a3881cf42 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -11,3 +11,20 @@ class Variadic3 {}; int alignas(8) with_alignas; // expected-warning {{'alignas' is incompatible with C++98}} int with_attribute [[ ]]; // expected-warning {{attributes are incompatible with C++98}} + +void Literals() { + (void)u8"str"; // expected-warning {{unicode literals are incompatible with C++98}} + (void)u"str"; // expected-warning {{unicode literals are incompatible with C++98}} + (void)U"str"; // expected-warning {{unicode literals are incompatible with C++98}} + (void)u'x'; // expected-warning {{unicode literals are incompatible with C++98}} + (void)U'x'; // expected-warning {{unicode literals are incompatible with C++98}} + + (void)u8R"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}} + (void)uR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}} + (void)UR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}} + (void)R"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}} + (void)LR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}} +} + +template struct S {}; +S<::S > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}} -- cgit v1.2.3