C++1y literal suffix support:

* Allow ns, us, ms, s, min, h as numeric ud-suffixes
 * Allow s as string ud-suffix

llvm-svn: 186933
This commit is contained in:
Richard Smith 2013-07-23 08:14:48 +00:00
parent 6030a65039
commit f4198b7598
7 changed files with 111 additions and 16 deletions

View File

@ -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<UserDefinedLiterals>;
// C++ conversion functions

View File

@ -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);

View File

@ -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

View File

@ -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())

View File

@ -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<bool>(Suffix)
.Cases("h", "min", "s", true)
.Cases("ms", "us", "ns", true)
.Default(false);
}
/// ParseNumberStartingWithZero - This method is called when the first character

View File

@ -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;

View File

@ -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