diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -121,7 +121,10 @@ // True if this is a mangled OpenMP variant name. unsigned IsMangledOpenMPVariantName : 1; - // 28 bits left in a 64-bit word. + // True if this identifier is a literal operator without whitespace. + unsigned IsLiteralOperatorWithoutWhitespace : 1; + + // 27 bits left in a 64-bit word. // Managed by the language front-end. void *FETokenInfo = nullptr; @@ -134,7 +137,8 @@ IsPoisoned(false), IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false), - IsModulesImport(false), IsMangledOpenMPVariantName(false) {} + IsModulesImport(false), IsMangledOpenMPVariantName(false), + IsLiteralOperatorWithoutWhitespace(false) {} public: IdentifierInfo(const IdentifierInfo &) = delete; @@ -378,6 +382,16 @@ /// Set whether this is the mangled name of an OpenMP variant. void setMangledOpenMPVariantName(bool I) { IsMangledOpenMPVariantName = I; } + /// Determine whether this is a literal operator without whitespace + bool isLiteralOperatorWithoutWhitespace() const { + return IsLiteralOperatorWithoutWhitespace; + } + + /// Set whether this is a literal operator without whitespace. + void setLiteralOperatorWithoutWhitespace(bool I) { + IsLiteralOperatorWithoutWhitespace = I; + } + /// Return true if this identifier is an editor placeholder. /// /// Editor placeholders are produced by the code-completion engine and are diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -285,6 +285,11 @@ if (Name.size() <= 1) return ReservedIdentifierStatus::NotReserved; + // [over.literal] p8 + llvm::errs() << Name << " isLiteralOperatorWithoutWhitespace: " << isLiteralOperatorWithoutWhitespace() << "\n"; + if(isLiteralOperatorWithoutWhitespace()) + return ReservedIdentifierStatus::NotReserved; + // [lex.name] p3 if (Name[0] == '_') { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2644,6 +2644,7 @@ Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], Literal.getUDSuffixOffset(), PP.getSourceManager(), getLangOpts()); + II->setLiteralOperatorWithoutWhitespace(true); } else if (Tok.is(tok::identifier)) { II = Tok.getIdentifierInfo(); SuffixLoc = ConsumeToken(); diff --git a/clang/test/Sema/reserved-identifier.cpp b/clang/test/Sema/reserved-identifier.cpp --- a/clang/test/Sema/reserved-identifier.cpp +++ b/clang/test/Sema/reserved-identifier.cpp @@ -81,6 +81,11 @@ return 0.; } +long double operator""_SacreBleue(long double) // no-warning +{ + return 0.; +} + struct _BarbeRouge { // expected-warning {{identifier '_BarbeRouge' is reserved because it starts with '_' followed by a capital letter}} } p; struct _BarbeNoire { // expected-warning {{identifier '_BarbeNoire' is reserved because it starts with '_' followed by a capital letter}}