Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4128,7 +4128,8 @@ bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); - bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); + bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id, + bool isUDSuffix); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1088,6 +1088,10 @@ if (!II) return ReservedIdentifierStatus::NotReserved; + // already checked at lexing time + if (getDeclName().getCXXLiteralIdentifier()) + return ReservedIdentifierStatus::NotReserved; + ReservedIdentifierStatus Status = II->isReserved(LangOpts); if (Status == ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope) { // Check if we're at TU level or not. Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -9,7 +9,6 @@ // This file implements the Expression parsing implementation for C++. // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" @@ -17,6 +16,7 @@ #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -2636,9 +2636,10 @@ // Grab the literal operator's suffix, which will be either the next token // or a ud-suffix from the string literal. + const bool isUDSuffix = !Literal.getUDSuffix().empty(); IdentifierInfo *II = nullptr; SourceLocation SuffixLoc; - if (!Literal.getUDSuffix().empty()) { + if (isUDSuffix) { II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); SuffixLoc = Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], @@ -2675,7 +2676,7 @@ Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); - return Actions.checkLiteralOperatorId(SS, Result); + return Actions.checkLiteralOperatorId(SS, Result, isUDSuffix); } // Parse a conversion-function-id. Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -484,8 +484,19 @@ } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, - const UnqualifiedId &Name) { + const UnqualifiedId &Name, bool isUDSuffix) { assert(Name.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId); + if (!isUDSuffix) { + // [over.literal] p8 + IdentifierInfo *II = Name.Identifier; + auto Status = II->isReserved(PP.getLangOpts()); + auto Loc = Name.getBeginLoc(); + if (Status != ReservedIdentifierStatus::NotReserved && + !PP.getSourceManager().isInSystemHeader(Loc)) { + Diag(Loc, diag::warn_reserved_extern_symbol) + << II << static_cast(Status); + } + } if (!SS.isValid()) return false; Index: clang/test/Sema/reserved-identifier.cpp =================================================================== --- clang/test/Sema/reserved-identifier.cpp +++ clang/test/Sema/reserved-identifier.cpp @@ -76,7 +76,12 @@ int _barbatruc; // no-warning } -long double operator"" _BarbeBleue(long double) // expected-warning {{identifier 'operator""_BarbeBleue' is reserved because it starts with '_' followed by a capital letter}} +long double operator"" _BarbeBleue(long double) // expected-warning {{identifier '_BarbeBleue' is reserved because it starts with '_' followed by a capital letter}} +{ + return 0.; +} + +long double operator""_SacreBleue(long double) // no-warning { return 0.; }