static_assert typeof log message entries

Please wait to commit this review until all of the code that
causes static_assert failures is committed.

Resolves openbmc/openbmc#2905

Tested: static_assert only

phosphor-logging now static_asserts that each item to be converted
by the printf-like function has integral, enum, floating_point, or
pointer type and each format argument has a type that decays to
a char * type.

Specifically, std::string fails the assertion because
its address would be logged and not the string buffer.  You
probably want your strings to use s.c_str().

Note that we considered automatically applying c_str() to string
objects, but the underlying entry function is constexpr which
makes that impossible.

Change-Id: I88f6c626d58254eaad9b1a44e6a9c693d2fc6cd9
Signed-off-by: Joseph Reynolds <jrey@us.ibm.com>
diff --git a/phosphor-logging/log.hpp b/phosphor-logging/log.hpp
index a5ba738..a933591 100644
--- a/phosphor-logging/log.hpp
+++ b/phosphor-logging/log.hpp
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <tuple>
+#include <type_traits>
 #include <systemd/sd-journal.h>
 #include <sdbusplus/server/transaction.hpp>
 
@@ -135,11 +136,43 @@
     details::log(log_tuple);
 }
 
+template<class T>
+struct is_printf_argtype
+    : std::integral_constant<
+        bool,
+        (std::is_integral<typename std::remove_reference<T>::type>::value ||
+         std::is_enum<typename std::remove_reference<T>::type>::value ||
+         std::is_floating_point<typename
+                                    std::remove_reference<T>::type>::value ||
+         std::is_pointer<typename std::decay<T>::type>::value)>
+{};
+
+template<class T>
+struct is_char_ptr_argtype
+    : std::integral_constant<
+        bool,
+        (std::is_pointer<typename std::decay<T>::type>::value &&
+         std::is_same<typename std::remove_cv<typename
+                                   std::remove_pointer<typename
+                                       std::decay<T>::type>::type>::type,
+                      char>::value)>
+{};
+
+template<bool...>
+struct bool_pack;
+
+template<bool... bs>
+using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
+
 template <typename Arg, typename ...Args>
 constexpr auto entry(Arg&& arg, Args&&... args)
 {
+    static_assert(is_char_ptr_argtype<Arg>::value,
+                  "bad argument type: use char*");
+    static_assert(all_true<is_printf_argtype<Args>::value...>::value,
+                  "bad argument type: use string.c_str() if needed");
     const auto entry_tuple = std::make_tuple(std::forward<Arg>(arg),
-                                       std::forward<Args>(args)...);
+                                             std::forward<Args>(args)...);
     return entry_tuple;
 }