1 /**
2    Integration tests that stem from failues in real-life C projects
3  */
4 module it.c.compile.projects;
5 
6 import it;
7 
8 @("multicharacter_literal")
9 @safe unittest {
10     shouldCompile(
11         C(
12             `
13                 #define test 'ABCD'
14             `
15         ),
16 
17         D(
18             q{
19                 static assert(test == 1094861636); // determined by printf("%d\n", 'ABCD'); in C
20             }
21         )
22     );
23 }
24 
25 @("nn_get_statistic")
26 @safe unittest {
27     shouldCompile(
28         C(
29             // the original uses regular uint64_t, let's beat any special cases
30             // defining our own
31             q{
32                 typedef unsigned long int __my_uint64_t;
33                 typedef __my_uint64_t my_uint64_t;
34                 my_uint64_t nn_get_statistic (int s, int stat);
35             }
36         ),
37 
38         D(
39             q{
40                 int s;
41                 int stat;
42                 my_uint64_t ret = nn_get_statistic(s, stat);
43             }
44         )
45     );
46 }
47 
48 @("Lstring literals (seen in Windows)")
49 @safe unittest {
50     shouldCompile(
51         C(
52             `
53                 #define test L"testing"
54             `
55         ),
56 
57         D(
58             q{
59                 wstring s = test;
60             }
61         )
62     );
63 }
64 
65 @("lowercase integer suffices")
66 @safe unittest {
67     shouldCompile(
68         C(
69             `
70                 #define test 100l
71                 #define test2 100ll
72             `
73         ),
74 
75         D(
76             q{
77                 auto t = test;
78                 auto t2 = test2;
79             }
80         )
81     );
82 }
83 
84 @("__io_read_fn")
85 @safe unittest {
86     shouldCompile(
87         C(
88             q{
89                 typedef long long __ssize_t;
90                 typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, long __nbytes);
91             }
92         ),
93 
94         D(
95             q{
96                 void* cookie;
97                 char[1024] buf;
98                 __ssize_t ret = __io_read_fn.init(cookie, buf.ptr, buf.length);
99             }
100         ),
101     );
102 }
103 
104 @("timer_t")
105 @safe unittest {
106     shouldCompile(
107         C(
108             // the original uses regular uint64_t, let's beat any special cases
109             // defining our own
110             `
111                 #define __TIMER_T_TYPE void *
112                 typedef __TIMER_T_TYPE __timer_t;
113             `
114         ),
115 
116         D(
117             q{
118                 __timer_t timer = null;
119             }
120         ),
121     );
122 }
123 
124 
125 @("curl_multi_wait")
126 @safe unittest {
127     shouldCompile(
128         C(
129             q{
130                 typedef enum { CURLM_OK } CURLMcode;
131                 typedef int curl_socket_t;
132 
133                 struct curl_waitfd {
134                     curl_socket_t fd;
135                     short events;
136                     short revents; /* not supported yet */
137                 };
138 
139                 typedef struct { int dummy; } CURLM;
140                 CURLMcode curl_multi_wait(CURLM *multi_handle,
141                                           struct curl_waitfd extra_fds[],
142                                           unsigned int extra_nfds,
143                                           int timeout_ms,
144                                           int *ret);
145             }
146         ),
147 
148         D(
149             q{
150                 CURLM handle;
151                 curl_waitfd[] extra_fds;
152                 int ret;
153                 CURLMcode code = curl_multi_wait(&handle, extra_fds.ptr, 42u, 33, &ret);
154             }
155          ),
156     );
157 }
158 
159 @("__sigset_t")
160 @safe unittest {
161     shouldCompile(
162         // the original uses regular uint64_t, let's beat any special cases
163         // defining our own
164         C(
165              `
166                  #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
167                  typedef struct
168                  {
169                      unsigned long int __val[_SIGSET_NWORDS];
170                  } __sigset_t;
171              `
172         ),
173         D(
174             q{
175                 auto s = __sigset_t();
176                 ++s.__val[7];
177             }
178         ),
179     );
180 }
181 
182 
183 @("_IO_flockfile")
184 @safe unittest {
185     shouldCompile(
186         C(
187             `
188                 struct _IO_FILE { int dummy; };
189                 extern void _IO_flockfile (struct _IO_FILE *);
190                 #define _IO_flockfile(_fp)
191             `
192         ),
193         D(
194             q{
195                 _IO_FILE file;
196                 _IO_flockfile(&file);
197             }
198         ),
199     );
200 }
201 
202 
203 @("struct with union")
204 @safe unittest {
205     shouldCompile(
206         C(
207             q{
208                 struct Struct {
209                     union {
210                         void *ptr;
211                         int i;
212                     } data;
213                 };
214                 typedef struct Struct Struct;
215             }
216         ),
217 
218         D(
219             q{
220                 Struct s;
221                 s.data.ptr = null;
222                 s.data.i = 42;
223             }
224         ),
225     );
226 }
227 
228 @("const char* const")
229 @safe unittest {
230     shouldCompile(
231         C(
232             q{
233                 struct Struct {
234                     const char * const *protocols;
235                 };
236                 typedef struct Struct Struct;
237             }
238         ),
239 
240         D(
241             q{
242                 Struct s;
243                 static assert(is(typeof(s.protocols) == const(char*)*),
244                               "Expected const(char*)*, not " ~
245                               typeof(s.protocols).stringof);
246             }
247         ),
248      );
249 }
250 
251 @("forward declaration")
252 @safe unittest {
253     shouldCompile(
254         C(
255             q{
256                 struct Struct;
257                 void fun(struct Struct* s);
258                 struct Struct* make_struct(void);
259             }
260         ),
261 
262         D(
263             q{
264                 Struct* s = make_struct();
265                 fun(s);
266             }
267         ),
268     );
269 }
270 
271 
272 @("restrict")
273 @safe unittest {
274     shouldCompile(
275         C(
276             q{
277                 struct FILE { int dummy; };
278                 extern struct FILE *fopen(const char *restrict filename,
279                                           const char *restrict modes);
280             }
281         ),
282 
283         D(
284             q{
285                 import std.string;
286                 fopen("foo.txt".toStringz, "w".toStringz);
287             }
288         ),
289     );
290 }
291 
292 
293 @("return type typedefd enum")
294 @safe unittest {
295     shouldCompile(
296         C(
297             q{
298                 typedef struct { int dummy; } CURL;
299 
300                 typedef enum {
301                     CURLIOE_OK,            /* I/O operation successful */
302                 } curlioerr;
303 
304                 typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
305                                                          int cmd,
306                                                          void *clientp);
307             }
308         ),
309         D(
310             q{
311                 CURL handle;
312                 auto func = curl_ioctl_callback.init;
313                 curlioerr err = func(&handle, 42, null);
314             }
315         ),
316     );
317 }
318 
319 
320 @("curl_slist")
321 @safe unittest {
322     shouldCompile(
323         C(
324             q{
325                    struct curl_httppost {
326                        struct curl_slist *contentheader;
327                    };
328                    struct curl_slist {
329                        char *data;
330                        struct curl_slist *next;
331                    };
332                }
333         ),
334         D(
335             q{
336                 curl_httppost p;
337                 p.contentheader.data = null;
338                 p.contentheader.next = null;
339                 curl_slist l;
340                 l.data = null;
341                 l.next = null;
342             }
343         ),
344     );
345 }
346 
347 @("struct var collision with var before")
348 @safe unittest {
349     shouldCompile(
350         C(
351             q{
352                 extern int foo;
353                 struct foo { int dummy; };
354             }
355         ),
356         D(
357             q{
358                 auto u = foo(44);
359                 foo_ = 42;
360             }
361         ),
362     );
363 }
364 
365 @("struct function collision with function before")
366 @safe unittest {
367     shouldCompile(
368         C(
369             q{
370                 void foo(void);
371                 struct foo { int dummy; };
372             }
373         ),
374         D(
375             q{
376                 auto u = foo(44);
377                 foo_();
378             }
379         ),
380     );
381 }
382 
383 
384 @("union var collision")
385 @safe unittest {
386     shouldCompile(
387         C(
388             q{
389                 union foo { int dummy; };
390                 extern int foo;
391             }
392         ),
393         D(
394             q{
395                 auto u = foo(44);
396                 foo_ = 42;
397             }
398         ),
399     );
400 }
401 
402 @("enum var collision")
403 @safe unittest {
404     shouldCompile(
405         C(
406             q{
407                 enum foo { one, two, three };
408                 extern int foo;
409             }
410         ),
411         D(
412             q{
413                 auto e = foo.three;
414                 foo_ = 42;
415             }
416         ),
417     );
418 }
419 
420 @("use int for enum parameter")
421 @safe unittest {
422     shouldCompile(
423         C(
424             q{
425                 typedef enum {
426                     foo,
427                     bar,
428                 } Enum;
429                 void func(Enum e);
430             }
431         ),
432         D(
433             q{
434                 func(Enum.bar);
435             }
436         ),
437     );
438 }
439 
440 @("pthread struct")
441 @safe unittest {
442     with(immutable IncludeSandbox()) {
443         writeFile("hdr.h",
444                q{
445                    typedef struct {
446                        void (*routine)(void*);
447                    } Struct;
448                }
449         );
450         writeFile("app.dpp",
451                   `
452                       #include "hdr.h"
453                       extern(C) void foo(void*) {}
454 
455                       void main() {
456                           Struct s;
457                           s.routine = &foo;
458                       }
459                   `
460         );
461 
462         runPreprocessOnly("app.dpp");
463         shouldCompile("app.d");
464     }
465 }
466 
467 
468 @("multiple headers with the same typedef")
469 @safe unittest {
470     with(const IncludeSandbox()) {
471         writeFile("hdr1.h",
472                   q{
473                       typedef long time_t;
474                       typedef long time_t;
475             }
476         ),
477 
478         writeFile("hdr2.h",
479                   q{
480                       typedef long time_t;
481                       typedef long time_t;
482             }
483         ),
484 
485         writeFile("app.dpp",
486                   `
487                       #include "hdr1.h"
488                       #include "hdr2.h"
489                       void main() {
490                           time_t var = 42;
491                       }
492                   `);
493 
494         runPreprocessOnly("app.dpp");
495         shouldCompile("app.d");
496     }
497 }
498 
499 @("jmp_buf")
500 @safe unittest {
501     shouldCompile(
502         C(
503             q{
504                 typedef long int __jmp_buf[8];
505             }
506         ),
507 
508         D(
509             q{
510                 __jmp_buf buf;
511                 static assert(buf.length == 8);
512             }
513         ),
514     );
515 }
516 
517 @("__pthread_unwind_buf_t")
518 @safe unittest {
519     shouldCompile(
520         C(
521             q{
522                 typedef long int __jmp_buf[8];
523                 typedef struct {
524                     struct {
525                         __jmp_buf __cancel_jmp_buf;
526                         int __mask_was_saved;
527                     } __cancel_jmp_buf[1];
528                     void *__pad[4];
529                 } __pthread_unwind_buf_t __attribute__ ((__aligned__));
530             }
531         ),
532 
533         D(
534             q{
535                 __pthread_unwind_buf_t buf;
536             }
537         ),
538     );
539 }
540 
541 
542 @("struct pointer to unknown struct that is defined by a later header")
543 @safe unittest {
544     with(immutable IncludeSandbox()) {
545         writeFile("hdr1.h",
546                   q{
547                       typedef struct Foo {
548                           struct Bar* bar;
549                       } Foo;
550                   });
551         writeFile("hdr2.h",
552                   q{
553                       struct Bar;
554                   });
555         writeFile("app.dpp",
556                   `
557                       #include "hdr1.h"
558                       #include "hdr2.h"
559                       void main() {
560                           Foo f;
561                           f.bar = null;
562                       }
563                   `);
564         runPreprocessOnly("app.dpp");
565         shouldCompile("app.d");
566     }
567 }
568 
569 @("typedef struct pointer with no declaration")
570 @safe unittest {
571     shouldCompile(
572         C(
573             q{
574                 typedef struct _Foo Foo;
575                 typedef Foo *FooPtr;
576             }
577         ),
578         D(
579             q{
580                 void fun(FooPtr ptr) { }
581                 FooPtr ptr;
582                 fun(ptr);
583             }
584         ),
585     );
586 }
587 
588 @("extern global variable with undefined macro")
589 @safe unittest {
590     with(immutable IncludeSandbox()) {
591         writeFile("hdr.h",
592                   q{
593                       // EXPORT_VAR not defined anywhere
594                       typedef struct _Foo Foo;
595                       typedef Foo *FooPtr;
596                       EXPORT_VAR FooPtr theFoo;
597                   });
598         writeFile("app.dpp",
599                   `
600                       #include "hdr.h"
601                   `);
602         try {
603             runPreprocessOnly("app.dpp");
604             assert(0, "Should not get here");
605         } catch(Exception e) {
606             "unknown type name 'EXPORT_VAR'".shouldBeIn(e.msg);
607         }
608     }
609 }
610 
611 @("angle brackets headers with more angle brackets")
612 @safe unittest {
613 
614     with(immutable IncludeSandbox()) {
615 
616         writeFile("includes/libfoo/libfoo.h",
617                   `
618                       #include <libfoo/libfoo-common.h>
619                       #include <libfoo/libfoo-host.h>
620                   `);
621 
622         writeFile("includes/libfoo/libfoo-common.h",
623                   `
624                       #define EXPORT_VAR extern
625                   `);
626 
627         writeFile("includes/libfoo/libfoo-host.h",
628                   q{
629                       typedef struct _Foo Foo;
630                       typedef Foo *FooPtr;
631                   });
632 
633         writeFile("app.dpp",
634                   `
635                       #include <libfoo/libfoo.h>
636                       void func(FooPtr foo) {
637                           assert(foo is null);
638                       }
639                   `);
640 
641         runPreprocessOnly(
642             "--include-path",
643             inSandboxPath("includes"),
644             "app.dpp");
645 
646         shouldCompile("app.d");
647     }
648 }
649 
650 
651 @("double enum typedef")
652 @safe unittest {
653 
654     with(immutable IncludeSandbox()) {
655 
656         writeFile("enum.h",
657                   `
658                   #ifndef _ENUM_H
659                   #define _ENUM_H
660                       typedef enum {
661                           only_value,
662                       } Enum;
663                   #endif
664                   `);
665 
666         writeFile("hdr1.h",
667                   `
668                       #include "enum.h"
669                   `);
670 
671         writeFile("hdr2.h",
672                   `
673                       #include "enum.h"
674                   `);
675 
676         writeFile("app.dpp",
677                   `
678                       #include "hdr1.h"
679                       #include "hdr2.h"
680                   `);
681 
682         runPreprocessOnly("app.dpp");
683         shouldCompile("app.d");
684     }
685 
686 }
687 
688 @("gregset_t")
689 @safe unittest {
690     shouldCompile(
691         C(
692             `
693                 typedef long long int greg_t;
694                 #define __NGREG 23
695                 typedef greg_t gregset_t[__NGREG];
696             `
697         ),
698         D(
699             q{
700                 static assert(greg_t.sizeof == 8);
701                 static assert(gregset_t.sizeof == 23 * 8);
702             }
703         ),
704     );
705 }
706 
707 
708 @("nv_alloc_ops")
709 @safe unittest {
710     shouldCompile(
711         C(
712             q{
713                 typedef struct Inner_ Inner;
714 
715                 typedef struct Outer {
716                     const Inner *nva_ops;
717                 } Outer;
718 
719                 struct Inner_ {
720                     int dummy;
721                 };
722             }
723         ),
724         D(
725             q{
726             }
727         ),
728     );
729 }
730 
731 @("va_list")
732 @safe unittest {
733     shouldCompile(
734         C(
735             `
736                 #include <stdarg.h>
737                 typedef struct Struct {
738                     int (*func)(int, va_list);
739                 };
740             `
741         ),
742         D(
743             q{
744             }
745         ),
746     );
747 }
748 
749 
750 @("ASN1_ITEM")
751 @safe unittest {
752     shouldCompile(
753         C(
754             q{
755                 struct Foo_st;
756                 typedef struct Foo_st Foo;
757                 extern const Foo gVar;
758             }
759         ),
760         D(
761             q{
762 
763             }
764         ),
765     );
766 }
767 
768 
769 @("X509_get0_extensions")
770 @safe unittest {
771     shouldCompile(
772         C(
773             q{
774                 typedef struct { int dummy; } Param;
775                 struct Ret;
776                 const struct Ret *func(const Param *x);
777             }
778         ),
779         D(
780             q{
781 
782             }
783         ),
784     );
785 }
786 
787 
788 @("double semicolon after function declaration")
789 @safe unittest {
790     shouldCompile(
791         C(
792             q{
793                 void foo(void);;
794             }
795         ),
796         D(
797             q{
798 
799             }
800         ),
801     );
802 }
803 
804 
805 @("_Bool")
806 @safe unittest {
807     shouldCompile(
808         C(
809             `
810                 #include <stdbool.h>
811                 typedef bool handler_t(int, double);
812             `
813         ),
814         D(
815             q{
816                 handler_t handler;
817                 bool b = handler(42, 33.3);
818             }
819         ),
820     );
821 }
822 
823 @("(unsigned) long long C suffixes")
824 @safe unittest {
825     shouldCompile(
826         C(
827             `
828                 #define A 1LL
829                 #define B 2ll
830                 #define C 3LLU
831                 #define D 4LLu
832                 #define E 5llU
833                 #define F 6llu
834                 #define G 7ULL
835                 #define H 8Ull
836                 #define I 9uLL
837                 #define J 10ull
838             `
839         ),
840         D(
841             q{
842                 auto a = A;
843                 auto b = B;
844                 auto c = C;
845                 auto d = D;
846                 auto e = E;
847                 auto f = F;
848                 auto g = G;
849                 auto h = H;
850                 auto i = I;
851                 auto j = J;
852             }
853         ),
854     );
855 }
856 
857 @("Casting when type has attribute")
858 @safe unittest {
859     shouldCompile(
860          C(
861             `
862                 typedef unsigned int gfp_t;
863 
864                 #define DUMMY ((__force gfp_t) 7)
865                 #define __force
866             `
867         ),
868         D(
869             q{
870                 auto a = DUMMY;
871             }
872         ),
873     );
874 }
875 
876 @("Accessing nested aggregates")
877 @safe unittest {
878     shouldCompile(
879         C(
880             q{
881                 struct A {
882                     struct B {
883                         int a;
884                         struct C {
885                             int b;
886                             enum E {Mon, Tue};
887                         } c_obj1;
888                     } b_obj;
889 
890                     union U {
891                         int v1;
892                         char v2;
893                     };
894 
895                     struct C c_obj2;
896                 };
897 
898                 void f(struct C *);
899                 void g(struct B *);
900                 void h(union U *);
901                 void i(enum E);
902             }
903         ),
904         D(
905             q{
906                 A a_obj;
907                 a_obj.b_obj.c_obj1.b = 3;
908 
909                 A.B.C.E day = A.B.C.E.Mon;
910             }
911         ),
912     );
913 }
914 
915 @("C preprocessor warnings should not be written to file")
916 @safe unittest {
917 
918     with(immutable IncludeSandbox()) {
919 
920         writeFile("hdr.h",
921                   `
922                   #define A B(__VA_ARGS__)
923                   `);
924 
925         writeFile("app.dpp",
926                   `
927                       #include "hdr.h"
928                   `);
929 
930         runPreprocessOnly("app.dpp");
931         shouldCompile("app.d");
932     }
933 }
934 
935 
936 @("Extern void variable")
937 @safe unittest {
938     shouldCompile(
939         C(
940             q{
941                 extern void v;
942                 extern const void cv;
943             }
944         ),
945         D(
946             q{
947                 static assert(is(typeof(v) == void*),
948                               "Expected void*, not " ~
949                               typeof(v).stringof);
950 
951                 static assert(is(typeof(cv) == const(void*)),
952                               "Expected const(void*), not " ~
953                               typeof(cv).stringof);
954             }
955         ),
956     );
957 }