Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -92,10 +92,11 @@ 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 treat it as if it were preceded by whitespace. 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< + "invalid suffix on literal; C++11 requires a space between literal and " + "a macro">, 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/lib/Lex/Lexer.cpp =================================================================== --- clang/lib/Lex/Lexer.cpp +++ clang/lib/Lex/Lexer.cpp @@ -1986,6 +1986,7 @@ assert(LangOpts.CPlusPlus); // Maximally munch an identifier. + const char *TokStart = CurPtr; unsigned Size; char C = getCharAndSize(CurPtr, Size); bool Consumed = false; @@ -2012,10 +2013,43 @@ // 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. + bool IsUDSuffix = false; + if (!Consumed) { + if (C == '_') + IsUDSuffix = true; + else if (IsStringLiteral && LangOpts.CPlusPlus14) { + // In C++1y, we need to look ahead a few characters to see if this is a + // valid suffix for a string literal or a numeric literal (this could be + // the 'operator""if' defining a numeric literal operator). + const unsigned MaxStandardSuffixLength = 3; + char Buffer[MaxStandardSuffixLength] = {C}; + unsigned Consumed = Size; + unsigned Chars = 1; + while (true) { + unsigned NextSize; + char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize, LangOpts); + if (!isAsciiIdentifierContinue(Next)) { + // End of suffix. Check whether this is on the allowed list. + const StringRef CompleteSuffix(Buffer, Chars); + IsUDSuffix = + StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + break; + } + + if (Chars == MaxStandardSuffixLength) + // Too long: can't be a standard suffix. + break; + + Buffer[Chars++] = Next; + Consumed += NextSize; + } + } + } + if (!Consumed) CurPtr = ConsumeChar(CurPtr, Size, Result); - - Result.setFlag(Token::HasUDSuffix); + if (IsUDSuffix) + Result.setFlag(Token::HasUDSuffix); while (true) { C = getCharAndSize(CurPtr, Size); if (isAsciiIdentifierContinue(C)) { @@ -2026,6 +2060,24 @@ break; } + // As a conforming extension, we treat invalid suffixes as if they had + // whitespace before them if doing so results in macro expansions. + if (!isLexingRawMode() && !IsUDSuffix) { + unsigned TokLen = CurPtr - TokStart; + 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 @@ -489,7 +489,13 @@ #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}} + // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}} + const char* s0 = "FOO"BAR; + // expected-error@-1 {{no matching literal operator for call to 'operator""BAR' with arguments of types 'const char *' and 'unsigned long', and no matching literal operator template}} +#define BAR "BAZ" + const char* s1 = "FOO"BAR; + // expected-error@-1 {{invalid suffix on literal; C++11 requires a space between literal and a macro}} +#undef BAR #endif } Index: clang/test/CXX/drs/dr17xx.cpp =================================================================== --- clang/test/CXX/drs/dr17xx.cpp +++ clang/test/CXX/drs/dr17xx.cpp @@ -143,7 +143,7 @@ #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}} + // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}} #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() {