[cfe-commits] r152302 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/LiteralSupport.cpp lib/Lex/PPExpressions.cpp lib/Sema/SemaExpr.cpp test/CodeGenCXX/cxx11-user-defined-literal.cpp test/Parser/cxx11-user-defined-literals.cpp test/SemaCXX/cxx11-user-defined-literals.cpp

Richard Smith richard-llvm at metafoo.co.uk
Thu Mar 8 00:45:33 PST 2012


Author: rsmith
Date: Thu Mar  8 02:45:32 2012
New Revision: 152302

URL: http://llvm.org/viewvc/llvm-project?rev=152302&view=rev
Log:
Add support for cooked forms of user-defined-integer-literal and
user-defined-floating-literal. Support for raw forms of these literals
to follow.

Added:
    cfe/trunk/test/SemaCXX/cxx11-user-defined-literals.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/LiteralSupport.h
    cfe/trunk/lib/Lex/LiteralSupport.cpp
    cfe/trunk/lib/Lex/PPExpressions.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/CodeGenCXX/cxx11-user-defined-literal.cpp
    cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Mar  8 02:45:32 2012
@@ -146,9 +146,9 @@
 def err_string_concat_mixed_suffix : Error<
   "differing user-defined suffixes ('%0' and '%1') in string literal "
   "concatenation">;
-def err_pp_invalid_char_udl : Error<
-  "character literal with user-defined suffix cannot be used in preprocessor "
-  "constant expression">;
+def err_pp_invalid_udl : Error<
+  "%select{character|integer}0 literal with user-defined suffix "
+  "cannot be used in preprocessor constant expression">;
 def err_bad_string_encoding : Error<
   "illegal character encoding in string literal">;
 def warn_bad_string_encoding : ExtWarn<

Modified: cfe/trunk/include/clang/Lex/LiteralSupport.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/LiteralSupport.h?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/LiteralSupport.h (original)
+++ cfe/trunk/include/clang/Lex/LiteralSupport.h Thu Mar  8 02:45:32 2012
@@ -45,7 +45,7 @@
 
   unsigned radix;
 
-  bool saw_exponent, saw_period;
+  bool saw_exponent, saw_period, saw_ud_suffix;
 
 public:
   NumericLiteralParser(const char *begin, const char *end,
@@ -64,8 +64,17 @@
   bool isFloatingLiteral() const {
     return saw_period || saw_exponent;
   }
-  bool hasSuffix() const {
-    return SuffixBegin != ThisTokEnd;
+
+  bool hasUDSuffix() const {
+    return saw_ud_suffix;
+  }
+  StringRef getUDSuffix() const {
+    assert(saw_ud_suffix);
+    return StringRef(SuffixBegin, ThisTokEnd - SuffixBegin);
+  }
+  unsigned getUDSuffixOffset() const {
+    assert(saw_ud_suffix);
+    return SuffixBegin - ThisTokBegin;
   }
 
   unsigned getRadix() const { return radix; }

Modified: cfe/trunk/lib/Lex/LiteralSupport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/LiteralSupport.cpp?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/LiteralSupport.cpp (original)
+++ cfe/trunk/lib/Lex/LiteralSupport.cpp Thu Mar  8 02:45:32 2012
@@ -333,6 +333,10 @@
 ///         decimal-constant integer-suffix
 ///         octal-constant integer-suffix
 ///         hexadecimal-constant integer-suffix
+///       user-defiend-integer-literal: [C++11 lex.ext]
+///         decimal-literal ud-suffix
+///         octal-literal ud-suffix
+///         hexadecimal-literal ud-suffix
 ///       decimal-constant:
 ///         nonzero-digit
 ///         decimal-constant digit
@@ -382,6 +386,7 @@
   s = DigitsBegin = begin;
   saw_exponent = false;
   saw_period = false;
+  saw_ud_suffix = false;
   isLong = false;
   isUnsigned = false;
   isLongLong = false;
@@ -519,13 +524,20 @@
       isImaginary = true;
       continue;  // Success.
     }
-    // If we reached here, there was an error.
+    // If we reached here, there was an error or a ud-suffix.
     break;
   }
 
-  // Report an error if there are any.
   if (s != ThisTokEnd) {
-    PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+    if (PP.getLangOptions().CPlusPlus0x && s == SuffixBegin && *s == '_') {
+      // We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting
+      // with an '_' are ill-formed.
+      saw_ud_suffix = true;
+      return;
+    }
+
+    // Report an error if there are any.
+    PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin),
             isFPConstant ? diag::err_invalid_suffix_float_constant :
                            diag::err_invalid_suffix_integer_constant)
       << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);

Modified: cfe/trunk/lib/Lex/PPExpressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPExpressions.cpp?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPExpressions.cpp (original)
+++ cfe/trunk/lib/Lex/PPExpressions.cpp Thu Mar  8 02:45:32 2012
@@ -215,6 +215,10 @@
     }
     assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
 
+    // Complain about, and drop, any ud-suffix.
+    if (Literal.hasUDSuffix())
+      PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1;
+
     // long long is a C99 feature.
     if (!PP.getLangOptions().C99 && Literal.isLongLong)
       PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ?
@@ -253,7 +257,7 @@
   case tok::utf32_char_constant:    // U'x'
     // Complain about, and drop, any ud-suffix.
     if (PeekTok.hasUDSuffix())
-      PP.Diag(PeekTok, diag::err_pp_invalid_char_udl);
+      PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0;
 
     SmallString<32> CharBuffer;
     bool CharInvalid = false;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Mar  8 02:45:32 2012
@@ -2437,6 +2437,38 @@
                                       Context.IntTy, Loc));
 }
 
+static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
+                                  QualType Ty, SourceLocation Loc) {
+  const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty);
+
+  using llvm::APFloat;
+  APFloat Val(Format);
+
+  APFloat::opStatus result = Literal.GetFloatValue(Val);
+
+  // Overflow is always an error, but underflow is only an error if
+  // we underflowed to zero (APFloat reports denormals as underflow).
+  if ((result & APFloat::opOverflow) ||
+      ((result & APFloat::opUnderflow) && Val.isZero())) {
+    unsigned diagnostic;
+    SmallString<20> buffer;
+    if (result & APFloat::opOverflow) {
+      diagnostic = diag::warn_float_overflow;
+      APFloat::getLargest(Format).toString(buffer);
+    } else {
+      diagnostic = diag::warn_float_underflow;
+      APFloat::getSmallest(Format).toString(buffer);
+    }
+
+    S.Diag(Loc, diagnostic)
+      << Ty
+      << StringRef(buffer.data(), buffer.size());
+  }
+
+  bool isExact = (result == APFloat::opOK);
+  return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
+}
+
 ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
   // Fast path for a single digit (which is quite common).  A single digit
   // cannot have a trigraph, escaped newline, radix prefix, or type suffix.
@@ -2461,6 +2493,40 @@
   if (Literal.hadError)
     return ExprError();
 
+  if (Literal.hasUDSuffix()) {
+    // We're building a user-defined literal.
+    IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
+    SourceLocation UDSuffixLoc =
+      getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset());
+
+    // FIXME: Perform literal operator lookup now, and build a raw literal if
+    // there is no usable operator.
+
+    QualType Ty;
+    Expr *Lit;
+    if (Literal.isFloatingLiteral()) {
+      // C++11 [lex.ext]p4: If S contains a literal operator with parameter type
+      // long double, the literal is treated as a call of the form
+      //   operator "" X (f L)
+      Lit = BuildFloatingLiteral(*this, Literal, Context.LongDoubleTy,
+                                 Tok.getLocation());
+    } else {
+      // C++11 [lex.ext]p3: If S contains a literal operator with parameter type
+      // unsigned long long, the literal is treated as a call of the form
+      //   operator "" X (n ULL)
+      llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0);
+      if (Literal.GetIntegerValue(ResultVal))
+        Diag(Tok.getLocation(), diag::warn_integer_too_large);
+
+      QualType Ty = Context.UnsignedLongLongTy;
+      Lit = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation());
+    }
+
+    return BuildLiteralOperatorCall(UDSuffix, UDSuffixLoc,
+                                    llvm::makeArrayRef(&Lit, 1),
+                                    Tok.getLocation());
+  }
+
   Expr *Res;
 
   if (Literal.isFloatingLiteral()) {
@@ -2472,34 +2538,7 @@
     else
       Ty = Context.LongDoubleTy;
 
-    const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty);
-
-    using llvm::APFloat;
-    APFloat Val(Format);
-
-    APFloat::opStatus result = Literal.GetFloatValue(Val);
-
-    // Overflow is always an error, but underflow is only an error if
-    // we underflowed to zero (APFloat reports denormals as underflow).
-    if ((result & APFloat::opOverflow) ||
-        ((result & APFloat::opUnderflow) && Val.isZero())) {
-      unsigned diagnostic;
-      SmallString<20> buffer;
-      if (result & APFloat::opOverflow) {
-        diagnostic = diag::warn_float_overflow;
-        APFloat::getLargest(Format).toString(buffer);
-      } else {
-        diagnostic = diag::warn_float_underflow;
-        APFloat::getSmallest(Format).toString(buffer);
-      }
-
-      Diag(Tok.getLocation(), diagnostic)
-        << Ty
-        << StringRef(buffer.data(), buffer.size());
-    }
-
-    bool isExact = (result == APFloat::opOK);
-    Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation());
+    Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation());
 
     if (Ty == Context.DoubleTy) {
       if (getLangOptions().SinglePrecisionConstants) {

Modified: cfe/trunk/test/CodeGenCXX/cxx11-user-defined-literal.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-user-defined-literal.cpp?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-user-defined-literal.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx11-user-defined-literal.cpp Thu Mar  8 02:45:32 2012
@@ -4,15 +4,21 @@
 using size_t = decltype(sizeof(int));
 S operator"" _x(const char *, size_t);
 S operator"" _y(wchar_t);
+S operator"" _z(unsigned long long);
+S operator"" _f(long double);
 
 void f() {
   // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
   // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
   // CHECK: call void @_Zli2_yw({{.*}} 97)
+  // CHECK: call void @_Zli2_zy({{.*}} 42)
+  // CHECK: call void @_Zli2_fe({{.*}} x86_fp80 0xK3FFF8000000000000000)
   // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
   // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
   // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
-  "foo"_x, "bar"_x, L'a'_y;
+  // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
+  // CHECK: call void @_ZN1SD1Ev({{.*}}) nounwind
+  "foo"_x, "bar"_x, L'a'_y, 42_z, 1.0_f;
 }
 
 template<typename T> auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); }

Modified: cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp?rev=152302&r1=152301&r2=152302&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp (original)
+++ cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp Thu Mar  8 02:45:32 2012
@@ -31,6 +31,12 @@
 #error error
 #endif
 
+// A ud-suffix cannot be used on integer literals in preprocessor constant
+// expressions:
+#if 0_foo // expected-error {{integer literal with user-defined suffix cannot be used in preprocessor constant expression}}
+#error error
+#endif
+
 // But they can appear in expressions.
 constexpr char operator"" _id(char c) { return c; }
 constexpr wchar_t operator"" _id(wchar_t c) { return c; }
@@ -43,6 +49,9 @@
 constexpr const char16_t operator"" _id(const char16_t *p, size_t n) { return *p; }
 constexpr const char32_t operator"" _id(const char32_t *p, size_t n) { return *p; }
 
+constexpr unsigned long long operator"" _id(unsigned long long n) { return n; }
+constexpr long double operator"" _id(long double d) { return d; }
+
 template<int n> struct S {};
 S<"a"_id> sa;
 S<L"b"_id> sb;
@@ -55,30 +64,13 @@
 S<u'y'_id> sy;
 S<U'z'_id> sz;
 
+S<100_id> sn;
+S<(int)1.3_id> sf;
+
 void h() {
   (void)"test"_id "test" L"test";
 }
 
-enum class LitKind { Char, WideChar, Char16, Char32, CharStr, WideStr, Char16Str, Char32Str };
-constexpr LitKind operator"" _kind(char p) { return LitKind::Char; }
-constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; }
-constexpr LitKind operator"" _kind(char16_t p) { return LitKind::Char16; }
-constexpr LitKind operator"" _kind(char32_t p) { return LitKind::Char32; }
-constexpr LitKind operator"" _kind(const char *p, size_t n) { return LitKind::CharStr; }
-constexpr LitKind operator"" _kind(const wchar_t *p, size_t n) { return LitKind::WideStr; }
-constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind::Char16Str; }
-constexpr LitKind operator"" _kind(const char32_t *p, size_t n) { return LitKind::Char32Str; }
-
-static_assert('x'_kind == LitKind::Char, "");
-static_assert(L'x'_kind == LitKind::WideChar, "");
-static_assert(u'x'_kind == LitKind::Char16, "");
-static_assert(U'x'_kind == LitKind::Char32, "");
-static_assert("foo"_kind == LitKind::CharStr, "");
-static_assert(u8"foo"_kind == LitKind::CharStr, "");
-static_assert(L"foo"_kind == LitKind::WideStr, "");
-static_assert(u"foo"_kind == LitKind::Char16Str, "");
-static_assert(U"foo"_kind == LitKind::Char32Str, "");
-
 // Test source location for suffix is known
 const char *p =
   "foo\nbar" R"x(
@@ -89,7 +81,14 @@
 "and a bit more"
 "and another suffix"_no_such_suffix;
 
-// And for character literals
 char c =
   '\x14'\
 _no_such_suffix; // expected-error {{'_no_such_suffix'}}
+
+int &r =
+1234567\
+_no_such_suffix; // expected-error {{'_no_such_suffix'}}
+
+int k =
+1234567.89\
+_no_such_suffix; // expected-error {{'_no_such_suffix'}}

Added: cfe/trunk/test/SemaCXX/cxx11-user-defined-literals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx11-user-defined-literals.cpp?rev=152302&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx11-user-defined-literals.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx11-user-defined-literals.cpp Thu Mar  8 02:45:32 2012
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -fms-extensions -triple x86_64-apple-darwin9.0.0
+
+using size_t = decltype(sizeof(int));
+enum class LitKind {
+  Char, WideChar, Char16, Char32,
+  CharStr, WideStr, Char16Str, Char32Str,
+  Integer, Floating
+};
+constexpr LitKind operator"" _kind(char p) { return LitKind::Char; }
+constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; }
+constexpr LitKind operator"" _kind(char16_t p) { return LitKind::Char16; }
+constexpr LitKind operator"" _kind(char32_t p) { return LitKind::Char32; }
+constexpr LitKind operator"" _kind(const char *p, size_t n) { return LitKind::CharStr; }
+constexpr LitKind operator"" _kind(const wchar_t *p, size_t n) { return LitKind::WideStr; }
+constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind::Char16Str; }
+constexpr LitKind operator"" _kind(const char32_t *p, size_t n) { return LitKind::Char32Str; }
+constexpr LitKind operator"" _kind(unsigned long long n) { return LitKind::Integer; }
+constexpr LitKind operator"" _kind(long double n) { return LitKind::Floating; }
+
+static_assert('x'_kind == LitKind::Char, "");
+static_assert(L'x'_kind == LitKind::WideChar, "");
+static_assert(u'x'_kind == LitKind::Char16, "");
+static_assert(U'x'_kind == LitKind::Char32, "");
+static_assert("foo"_kind == LitKind::CharStr, "");
+static_assert(u8"foo"_kind == LitKind::CharStr, "");
+static_assert(L"foo"_kind == LitKind::WideStr, "");
+static_assert(u"foo"_kind == LitKind::Char16Str, "");
+static_assert(U"foo"_kind == LitKind::Char32Str, "");
+static_assert(194_kind == LitKind::Integer, "");
+static_assert(0377_kind == LitKind::Integer, "");
+static_assert(0x5ffc_kind == LitKind::Integer, "");
+static_assert(.5954_kind == LitKind::Floating, "");
+static_assert(1._kind == LitKind::Floating, "");
+static_assert(1.e-2_kind == LitKind::Floating, "");
+static_assert(4e6_kind == LitKind::Floating, "");





More information about the cfe-commits mailing list