Index: include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: include/clang/Lex/LiteralSupport.h =================================================================== --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { + Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions &LangOpts, + StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token &Tok, const char *TokBegin, Index: lib/Lex/Lexer.cpp =================================================================== --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; + StringLiteralParser::UDSuffixResult IsStringUDSuffix = + StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix(Buffer, Chars); + const LangOptions &LangOpts = getLangOpts(); + // First, check if the suffix is a numeric suffix (s,sv) + IsUDSuffix = + NumericLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + // If it is not, check for a string suffix + if (!IsUDSuffix) { + IsStringUDSuffix = + StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + IsUDSuffix = + IsStringUDSuffix == StringLiteralParser::UDSuffixResult::Valid; + } break; } @@ -1729,11 +1740,18 @@ } if (!IsUDSuffix) { - if (!isLexingRawMode()) - Diag(CurPtr, getLangOpts().MSVCCompat - ? diag::ext_ms_reserved_user_defined_literal - : diag::ext_reserved_user_defined_literal) - << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); + if (!isLexingRawMode()) { + if (IsStringUDSuffix == + StringLiteralParser::UDSuffixResult::SVIncompatible) { + Diag(CurPtr, diag::err_cxx1z_string_view_literal) + << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); + } else { + Diag(CurPtr, getLangOpts().MSVCCompat + ? diag::ext_ms_reserved_user_defined_literal + : diag::ext_reserved_user_defined_literal) + << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); + } + } return CurPtr; } Index: lib/Lex/LiteralSupport.cpp =================================================================== --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions &LangOpts, + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) + return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') + return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) + return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") + return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid + : UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: test/SemaCXX/cxx1z-user-defined-literals.cpp =================================================================== --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif