[PATCH] [libc++] reject <chrono> literals that can't be represented

Richard Smith richard at metafoo.co.uk
Tue Nov 11 12:05:21 PST 2014


[time.duration.literals]p3 says:

"If any of these suffixes are applied to an integer literal and the
resulting chrono::duration value cannot be represented in the result type
because of overflow, the program is ill-formed."

That's unimplementable in standard C++, but implementable with Clang using
the enable_if attribute. This patch also rejects

  (void) operator""ns(0x8000000000000000ull);

... and it's not entirely clear whether that's permissible, but this is the
best we can do at the moment (and I think it's a good thing to reject the
above code).

Thoughts?

(We could do the same thing for floating-point <chrono> literals, but the
standard doesn't allow us to do so.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141111/ea5da80e/attachment.html>
-------------- next part --------------
Index: include/__config
===================================================================
--- include/__config	(revision 221699)
+++ include/__config	(working copy)
@@ -206,6 +206,10 @@
 #define _LIBCPP_ALWAYS_INLINE  __attribute__ ((__visibility__("hidden"), __always_inline__))
 #endif
 
+#if !defined(_LIBCPP_ENABLE_IF) && __has_attribute(enable_if)
+#define _LIBCPP_ENABLE_IF(__cond, __msg) __attribute__((enable_if(__cond, __msg)))
+#endif
+
 #if defined(__clang__)
 
 #if defined(__APPLE__) && !defined(__i386__) && !defined(__x86_64__) &&        \
Index: include/chrono
===================================================================
--- include/chrono	(revision 221699)
+++ include/chrono	(working copy)
@@ -1018,6 +1018,30 @@
         return chrono::duration<long double, nano> (__ns);
     }
 
+    // If any of these suffixes are applied to an integer literal and the
+    // resulting value cannot be represented, the program is ill-formed.
+    // We cannot enforce this within standard C++, but we can do so with
+    // a Clang extension.
+#ifdef _LIBCPP_ENABLE_IF
+    void operator"" h(unsigned long long __h)
+      _LIBCPP_ENABLE_IF(__h > chrono::hours::max().count(), "")
+      = delete;
+    void operator"" min(unsigned long long __m)
+      _LIBCPP_ENABLE_IF(__m > chrono::minutes::max().count(), "")
+      = delete;
+    void operator"" s(unsigned long long __s)
+      _LIBCPP_ENABLE_IF(__s > chrono::seconds::max().count(), "")
+      = delete;
+    void operator"" ms(unsigned long long __ms)
+      _LIBCPP_ENABLE_IF(__ms > chrono::milliseconds::max().count(), "")
+      = delete;
+    void operator"" us(unsigned long long __us)
+      _LIBCPP_ENABLE_IF(__us > chrono::microseconds::max().count(), "")
+      = delete;
+    void operator"" ns(unsigned long long __ns)
+      _LIBCPP_ENABLE_IF(__ns > chrono::nanoseconds::max().count(), "")
+      = delete;
+#endif
 }}
 
 namespace chrono { // hoist the literals into namespace std::chrono
Index: test/testit
===================================================================
--- test/testit	(revision 221699)
+++ test/testit	(working copy)
@@ -159,6 +159,7 @@
 }
 
 afunc no
+wait
 
 echo "****************************************************"
 echo "Results for `pwd`:"
Index: test/utilities/time/time.duration/time.duration.literals/h_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/h_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/h_overflow.fail.cpp	(working copy)
@@ -0,0 +1,27 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000h; // should fail w/"out of range" error
+#elif _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LONG_MAX == 0x7FFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x80000000h; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/min_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/min_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/min_overflow.fail.cpp	(working copy)
@@ -0,0 +1,27 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000min; // should fail w/"out of range" error
+#elif _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LONG_MAX == 0x7FFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x80000000min; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/ms_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/ms_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/ms_overflow.fail.cpp	(working copy)
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LLONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000ms; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/ns_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/ns_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/ns_overflow.fail.cpp	(working copy)
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LLONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000ns; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/overflow.pass.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/overflow.pass.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/overflow.pass.cpp	(working copy)
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+#include <limits.h>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF)
+    using namespace std::literals::chrono_literals;
+
+#if LLONG_MAX == 0x7FFFFFFFFFFFFFFF
+    (void) 0x7FFFFFFFFFFFFFFFns;
+    (void) 0x7FFFFFFFFFFFFFFFus;
+    (void) 0x7FFFFFFFFFFFFFFFms;
+    (void) 0x7FFFFFFFFFFFFFFFs;
+#endif
+
+#if LONG_MAX == 0x7FFFFFFFFFFFFFFF
+    (void) 0x7FFFFFFFFFFFFFFFmin;
+    (void) 0x7FFFFFFFFFFFFFFFh;
+#elif LONG_MAX = 0x7FFFFFFF
+    (void) 0x7FFFFFFFmin;
+    (void) 0x7FFFFFFFh;
+#endif
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/s_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/s_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/s_overflow.fail.cpp	(working copy)
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LLONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000s; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+
Index: test/utilities/time/time.duration/time.duration.literals/us_overflow.fail.cpp
===================================================================
--- test/utilities/time/time.duration/time.duration.literals/us_overflow.fail.cpp	(revision 0)
+++ test/utilities/time/time.duration/time.duration.literals/us_overflow.fail.cpp	(working copy)
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <chrono>
+#include <cassert>
+
+int main()
+{
+#if _LIBCPP_STD_VER > 11 && defined(_LIBCPP_ENABLE_IF) && LLONG_MAX == 0x7FFFFFFFFFFFFFFF
+    using namespace std::literals::chrono_literals;
+
+    (void) 0x8000000000000000us; // should fail w/"out of range" error
+#else
+#error
+#endif
+}
+


More information about the cfe-commits mailing list