diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ed70736cef08..21a548018b81 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5804,8 +5804,8 @@ def err_literal_operator_params : Error< def err_literal_operator_extern_c : Error< "literal operator must have C++ linkage">; def warn_user_literal_reserved : Warning< - "user-defined literal suffixes not starting with '_' are reserved; " - "no literal will invoke this operator">, + "user-defined literal suffixes not starting with '_' are reserved" + "%select{; no literal will invoke this operator|}0">, InGroup; // C++ conversion functions diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index 9534c88355e1..72c361dba875 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -569,8 +569,9 @@ private: void SkipBytes(unsigned Bytes, bool StartOfLine); - const char *LexUDSuffix(Token &Result, const char *CurPtr); - + const char *LexUDSuffix(Token &Result, const char *CurPtr, + bool IsStringLiteral); + // Helper functions to lex the remainder of a token of the specific type. void LexIdentifier (Token &Result, const char *CurPtr); void LexNumericConstant (Token &Result, const char *CurPtr); diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index b1430cc80519..2200e202695e 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -79,6 +79,8 @@ public: return SuffixBegin - ThisTokBegin; } + static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix); + unsigned getRadix() const { return radix; } /// GetIntegerValue - Convert this numeric literal value to an APInt that diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 9505ccd97223..71db68a58c02 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -1586,7 +1586,8 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { /// LexUDSuffix - Lex the ud-suffix production for user-defined literal suffixes /// in C++11, or warn on a ud-suffix in C++98. -const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) { +const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, + bool IsStringLiteral) { assert(getLangOpts().CPlusPlus); // Maximally munch an identifier. FIXME: UCNs. @@ -1606,9 +1607,20 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) { // that does not start with an underscore is ill-formed. As a conforming // extension, we treat all such suffixes as if they had whitespace before // them. - if (C != '_') { + bool IsUDSuffix = false; + if (C == '_') + IsUDSuffix = true; + else if (IsStringLiteral && C == 's' && getLangOpts().CPlusPlus1y) { + // In C++1y, "s" is a valid ud-suffix for a string literal. + unsigned NextSize; + if (!isIdentifierBody(getCharAndSizeNoWarn(CurPtr + Size, NextSize, + getLangOpts()))) + IsUDSuffix = true; + } + + if (!IsUDSuffix) { if (!isLexingRawMode()) - Diag(CurPtr, getLangOpts().MicrosoftMode ? + Diag(CurPtr, getLangOpts().MicrosoftMode ? diag::ext_ms_reserved_user_defined_literal : diag::ext_reserved_user_defined_literal) << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); @@ -1667,7 +1679,7 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) - CurPtr = LexUDSuffix(Result, CurPtr); + CurPtr = LexUDSuffix(Result, CurPtr, true); // If a nul character existed in the string, warn about it. if (NulCharacter && !isLexingRawMode()) @@ -1750,7 +1762,7 @@ void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) - CurPtr = LexUDSuffix(Result, CurPtr); + CurPtr = LexUDSuffix(Result, CurPtr, true); // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; @@ -1840,7 +1852,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr, // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) - CurPtr = LexUDSuffix(Result, CurPtr); + CurPtr = LexUDSuffix(Result, CurPtr, false); // If a nul character existed in the character, warn about it. if (NulCharacter && !isLexingRawMode()) diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index 84882d02165c..7641bfaa8b2c 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -413,10 +413,12 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, /// decimal-constant integer-suffix /// octal-constant integer-suffix /// hexadecimal-constant integer-suffix +/// binary-literal integer-suffix [GNU, C++1y] /// user-defined-integer-literal: [C++11 lex.ext] /// decimal-literal ud-suffix /// octal-literal ud-suffix /// hexadecimal-literal ud-suffix +/// binary-literal ud-suffix [GNU, C++1y] /// decimal-constant: /// nonzero-digit /// decimal-constant digit @@ -428,6 +430,10 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, /// hexadecimal-constant hexadecimal-digit /// hexadecimal-prefix: one of /// 0x 0X +/// binary-literal: +/// 0b binary-digit +/// 0B binary-digit +/// binary-literal binary-digit /// integer-suffix: /// unsigned-suffix [long-suffix] /// unsigned-suffix [long-long-suffix] @@ -441,6 +447,9 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, /// 0 1 2 3 4 5 6 7 8 9 /// a b c d e f /// A B C D E F +/// binary-digit: +/// 0 +/// 1 /// unsigned-suffix: one of /// u U /// long-suffix: one of @@ -515,6 +524,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, // Parse the suffix. At this point we can classify whether we have an FP or // integer constant. bool isFPConstant = isFloatingLiteral(); + const char *ImaginarySuffixLoc = 0; // Loop over all of the characters of the suffix. If we see something bad, // we break out of the loop. @@ -598,9 +608,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, case 'j': case 'J': if (isImaginary) break; // Cannot be repeated. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), - diag::ext_imaginary_constant); isImaginary = true; + ImaginarySuffixLoc = s; continue; // Success. } // If we reached here, there was an error or a ud-suffix. @@ -608,9 +617,17 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, } if (s != ThisTokEnd) { - if (PP.getLangOpts().CPlusPlus11 && s == SuffixBegin && *s == '_') { - // We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting - // with an '_' are ill-formed. + if (isValidUDSuffix(PP.getLangOpts(), + StringRef(SuffixBegin, ThisTokEnd - SuffixBegin))) { + // Any suffix pieces we might have parsed are actually part of the + // ud-suffix. + isLong = false; + isUnsigned = false; + isLongLong = false; + isFloat = false; + isImaginary = false; + isMicrosoftInteger = false; + saw_ud_suffix = true; return; } @@ -623,6 +640,35 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, hadError = true; return; } + + if (isImaginary) { + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, + ImaginarySuffixLoc - ThisTokBegin), + diag::ext_imaginary_constant); + } +} + +/// 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. +bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts, + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) + return false; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') + return true; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus1y) + return false; + + // In C++1y, "s", "h", "min", "ms", "us", and "ns" are used in the library. + return llvm::StringSwitch(Suffix) + .Cases("h", "min", "s", true) + .Cases("ms", "us", "ns", true) + .Default(false); } /// ParseNumberStartingWithZero - This method is called when the first character diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b6f5fe9eb4f7..015133041f96 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -27,6 +27,7 @@ #include "clang/AST/TypeOrdering.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" @@ -10650,7 +10651,8 @@ FinishedParams: // C++11 [usrlit.suffix]p1: // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. - Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved); + Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) + << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; diff --git a/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp b/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp new file mode 100644 index 000000000000..85abfb4fbf93 --- /dev/null +++ b/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++1y %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct duration {}; + duration operator"" ns(unsigned long long); + duration operator"" us(unsigned long long); + duration operator"" ms(unsigned long long); + duration operator"" s(unsigned long long); + duration operator"" min(unsigned long long); + duration operator"" h(unsigned long long); + + struct string {}; + string operator"" s(const char*, size_t); +} + +#else + +using namespace std; +duration a = 1ns, b = 1us, c = 1ms, d = 1s, e = 1min, f = 1h; +string s = "foo"s; +char error = 'x's; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +int _1z = 1z; // expected-error {{invalid suffix}} +int _1b = 1b; // expected-error {{invalid digit}} + +#endif