Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -94,10 +94,21 @@ Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Implemented `CWG1473 `_ which allows spaces after ``operator""``. - Clang used to err on the lack of space when the literal suffix identifier was invalid in - all the language modes, which contradicted the deprecation of the whitespaces. - Also turn on ``-Wdeprecated-literal-operator`` by default in all the language modes. +- Implemented `CWG1473 `_ allowing lack of space after ``operator""``. + Clang used to err on the lack of space when the literal suffix identifier was invalid, + contradicting ``-Wdeprecated-literal-operator`` which is now default on. + Instead, Clang now emits error only if the invalid suffix looks like a macro and the preceding + string literal is not empty, and then treat the suffix as if it were preceded by whitespace. + + .. code-block:: cpp + + #define E "!" + const char + *operator""E(const char*), + // ""E is a single token as it should be pedantically + *s = "not empty"E; + // treated as if whitespace preceds E hence a string concat: + // = "not empty!" C Language Changes ------------------ Index: clang/include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticLexKinds.td +++ clang/include/clang/Basic/DiagnosticLexKinds.td @@ -276,6 +276,12 @@ "identifier after literal will be treated as a reserved user-defined literal " "suffix in C++11">, InGroup, DefaultIgnore; +def ext_reserved_user_defined_literal : ExtWarn< + "invalid suffix on literal; C++11 requires a space between literal and " + "a macro">, InGroup, DefaultError; +def ext_ms_reserved_user_defined_literal : ExtWarn< + ext_reserved_user_defined_literal.Summary>, + InGroup; def err_unsupported_string_concat : Error< "unsupported non-standard concatenation of string literals">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9319,8 +9319,7 @@ "string literal operator templates are a GNU extension">, InGroup; def warn_user_literal_reserved : Warning< - "user-defined literal suffixes %select{|not starting with '_'|containing '__'}0 are reserved" - "%select{; no literal will invoke this operator|}1">, + "user-defined literal suffixes %select{not starting with '_'|containing '__'}0 are reserved">, InGroup; // C++ conversion functions Index: clang/include/clang/Basic/IdentifierTable.h =================================================================== --- clang/include/clang/Basic/IdentifierTable.h +++ clang/include/clang/Basic/IdentifierTable.h @@ -51,9 +51,9 @@ }; enum class ReservedLiteralSuffixIdStatus { - NotReserved = 0, - NotStartsWithUnderscore, + NotStartsWithUnderscore = 0, ContainsDoubleUnderscore, + NotReserved, }; /// Determine whether an identifier is reserved for use as a name at global Index: clang/lib/Lex/Lexer.cpp =================================================================== --- clang/lib/Lex/Lexer.cpp +++ clang/lib/Lex/Lexer.cpp @@ -1986,36 +1986,26 @@ assert(LangOpts.CPlusPlus); // Maximally munch an identifier. + const char *const TokStart = CurPtr; unsigned Size; char C = getCharAndSize(CurPtr, Size); - bool Consumed = false; - if (!isAsciiIdentifierStart(C)) { - if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) - Consumed = true; - else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) - Consumed = true; - else - return CurPtr; - } + if (isAsciiIdentifierStart(C)) { + CurPtr = ConsumeChar(CurPtr, Size, Result); + } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { + } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { + } else + return CurPtr; if (!LangOpts.CPlusPlus11) { if (!isLexingRawMode()) - Diag(CurPtr, + Diag(TokStart, C == '_' ? diag::warn_cxx11_compat_user_defined_literal : diag::warn_cxx11_compat_reserved_user_defined_literal) - << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); - return CurPtr; + << FixItHint::CreateInsertion(getSourceLocation(TokStart), " "); + return TokStart; } - // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix - // that does not start with an underscore is ill-formed. We assume a suffix - // beginning with a UCN or UTF-8 character is more likely to be a ud-suffix - // than a macro, however, and accept that. - if (!Consumed) - CurPtr = ConsumeChar(CurPtr, Size, Result); - - Result.setFlag(Token::HasUDSuffix); while (true) { C = getCharAndSize(CurPtr, Size); if (isAsciiIdentifierContinue(C)) { @@ -2026,6 +2016,31 @@ break; } + bool IsLiteralOperator = + StringRef(BufferPtr, 2).equals("\"\"") && BufferPtr + 2 == TokStart; + if (unsigned TokLen = CurPtr - TokStart; + StringLiteralParser::isValidUDSuffix(LangOpts, {TokStart, TokLen})) + Result.setFlag(Token::HasUDSuffix); + else if (!isLexingRawMode() && !IsLiteralOperator) { + // As a conforming extension, we treat invalid suffixes as if they had + // whitespace before them if doing so results in macro expansions. + // However, don't diagnose operator""E(...) even if E is a macro as it + // results in confusing error messages. Hence, ""E would not be treated as + // string concat; instead it's a single PP token (as it should be). + Result.setLength(TokLen); + Result.setLocation(getSourceLocation(TokStart, TokLen)); + Result.setKind(tok::raw_identifier); + Result.setRawIdentifierData(TokStart); + IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + if (II->hasMacroDefinition()) { + Diag(TokStart, LangOpts.MSVCCompat + ? diag::ext_ms_reserved_user_defined_literal + : diag::ext_reserved_user_defined_literal) + << FixItHint::CreateInsertion(getSourceLocation(TokStart), " "); + return TokStart; + } + } + return CurPtr; } Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -16571,8 +16571,7 @@ // contain a double underscore __ are reserved for use by C++ // implementations. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << static_cast(Status) - << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName()); + << static_cast(Status); } return false; Index: clang/test/CXX/drs/dr14xx.cpp =================================================================== --- clang/test/CXX/drs/dr14xx.cpp +++ clang/test/CXX/drs/dr14xx.cpp @@ -487,9 +487,14 @@ namespace dr1473 { // dr1473: 18 // NB: sup 1762, test reused there #if __cplusplus >= 201103L - float operator ""_E(const char *); - float operator ""E(const char *); // don't err on the lack of spaces even when the literal suffix identifier is invalid - // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}} +#define E "!" +const char + *operator""_E(const char*), + *operator""E(const char*), // don't err on the lack of spaces even when the literal suffix identifier is invalid + // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}} + *s = "not empty"E; + // expected-error@-1 {{invalid suffix on literal; C++11 requires a space between literal and a macro}} +#undef E #endif } Index: clang/test/CXX/drs/dr17xx.cpp =================================================================== --- clang/test/CXX/drs/dr17xx.cpp +++ clang/test/CXX/drs/dr17xx.cpp @@ -141,9 +141,14 @@ namespace dr1762 { // dr1762: 14 // NB: reusing 1473 test #if __cplusplus >= 201103L - float operator ""_E(const char *); - float operator ""E(const char *); - // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}} +#define E "!" +const char + *operator""_E(const char*), + *operator""E(const char*), // don't err on the lack of spaces even when the literal suffix identifier is invalid + // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}} + *s = "not empty"E; + // expected-error@-1 {{invalid suffix on literal; C++11 requires a space between literal and a macro}} +#undef E #endif } Index: clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp =================================================================== --- clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp +++ clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -std=c++11 -verify %s using size_t = decltype(sizeof(int)); -void operator ""wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}} -void operator ""wibble(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}} +void operator ""wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}} +void operator ""wibble(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}} template void f() { Index: clang/test/FixIt/fixit-c++11.cpp =================================================================== --- clang/test/FixIt/fixit-c++11.cpp +++ clang/test/FixIt/fixit-c++11.cpp @@ -68,9 +68,9 @@ } #define bar "bar" -const char *p = "foo" bar; +const char *p = "foo"bar; // expected-error {{requires a space between}} #define ord - '0' -int k = '4' ord; +int k = '4'ord; // expected-error {{requires a space between}} void operator"x" _y(char); // expected-error {{must be '""'}} void operator L"" _z(char); // expected-error {{encoding prefix}}