C++1y literal suffix support:
* Allow ns, us, ms, s, min, h as numeric ud-suffixes
* Allow s as string ud-suffix
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186933 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ed70736..21a5480 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5804,8 +5804,8 @@
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
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 9534c88..72c361d 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -569,8 +569,9 @@
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/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index b1430cc..2200e20 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -79,6 +79,8 @@
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/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 9505ccd..71db68a 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1586,7 +1586,8 @@
/// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 84882d0..7641bfa 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -413,10 +413,12 @@
/// 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 @@
/// 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 @@
/// 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 @@
// 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 @@
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 @@
}
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 @@
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
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b6f5fe9..0151330 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/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 @@
// 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/test/SemaCXX/cxx1y-user-defined-literals.cpp b/test/SemaCXX/cxx1y-user-defined-literals.cpp
new file mode 100644
index 0000000..85abfb4
--- /dev/null
+++ b/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