1 // RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s \ 2 // RUN: -analyzer-config unroll-loops=true 3 4 // expected-no-diagnostics 5 6 template <bool, typename T, typename> using conditional_t = T; 7 class basic_format_arg; 8 template <typename> struct formatter; 9 10 template <typename Context> struct value { 11 template <typename T> value(T) { 12 using value_type = T; 13 (void)format_custom_arg<value_type, 14 typename Context::template formatter_type<value_type>>; 15 } 16 17 template <typename, typename Formatter> static void format_custom_arg() { 18 Context ctx; 19 auto f = Formatter(); 20 f.format(0, ctx); 21 } 22 }; 23 24 struct context { 25 template <typename T> using formatter_type = formatter<T>; 26 }; 27 28 enum { max_packed_args }; 29 30 template <typename Context, long> 31 using arg_t = conditional_t<max_packed_args, value<Context>, basic_format_arg>; 32 33 template <int NUM_ARGS> struct format_arg_store { 34 arg_t<context, NUM_ARGS> args; 35 }; 36 37 template <typename... T, long NUM_ARGS = sizeof...(T)> 38 auto make_format_args(T... args) -> format_arg_store<NUM_ARGS> { 39 return {args...}; 40 } 41 42 template <typename F> void write_padded(F write) { write(0); } 43 44 template <typename... T> void format(T... args) { make_format_args(args...); } 45 46 template <int> struct bitset { 47 bitset(long); 48 }; 49 50 template <long N> struct formatter<bitset<N>> { 51 struct writer { 52 bitset<N> bs; 53 54 template <typename OutputIt> void operator()(OutputIt) { 55 for (auto pos = N; pos > 0; --pos) // no-crash 56 ; 57 } 58 }; 59 60 template <typename FormatContext> void format(bitset<N> bs, FormatContext) { 61 write_padded(writer{bs}); 62 } 63 }; 64 65 bitset<6> TestBody_bs(2); 66 67 void TestBody() { format(TestBody_bs); } 68