rZhBoYao created this revision.
rZhBoYao added reviewers: clang-language-wg, aaron.ballman, jyknight.
Herald added a project: All.
rZhBoYao requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
As a language extension, if an invalid a UDL's suffix can result in macro
expansion, it is treated as if whitespace preceded it. This allows legacy
code to co-exist with new code via -Wno-reserved-user-defined-literal.
The following code results in string concat not calling literal operator.
const char* s = "FOO"BAR;
Address comments in D153156 <https://reviews.llvm.org/D153156>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D158372
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticLexKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Lex/Lexer.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr17xx.cpp
clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
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<typename T>
void f() {
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/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/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<int>(Status)
- << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName());
+ << static_cast<int>(Status);
}
return false;
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/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<GNUStringLiteralOperatorTemplate>;
def warn_user_literal_reserved : Warning<
- "user-defined literal suffixes %select{<ERROR>|not starting with '_'|containing '__'}0 are reserved"
- "%select{; no literal will invoke this operator|}1">,
+ "user-defined literal suffixes %select{<ERROR>|not starting with '_'|containing '__'}0 are reserved">,
InGroup<UserDefinedLiterals>;
// C++ conversion functions
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<CXX11CompatReservedUserDefinedLiteral>, DefaultIgnore;
+def ext_reserved_user_defined_literal : ExtWarn<
+ "invalid suffix on literal; C++11 requires a space between literal and "
+ "a macro">, InGroup<ReservedUserDefinedLiteral>, DefaultError;
+def ext_ms_reserved_user_defined_literal : ExtWarn<
+ "invalid suffix on literal; C++11 requires a space between literal and "
+ "a macro">, InGroup<ReservedUserDefinedLiteral>;
def err_unsupported_string_concat : Error<
"unsupported non-standard concatenation of string literals">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -92,10 +92,11 @@
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Implemented `CWG1473 <https://wg21.link/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 <https://wg21.link/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
------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits