blob: 0939caeccf9f439298f2a1a65309de8e14174da9 [file] [log] [blame]
Brian Silverman4e662aa2022-05-11 23:10:19 -07001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::{
10 builder_modifiers::{
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011 make_clang_arg_adder, make_clang_optional_arg_adder, make_cpp17_adder, EnableAutodiscover,
12 SetSuppressSystemHeaders,
Brian Silverman4e662aa2022-05-11 23:10:19 -070013 },
14 code_checkers::{
15 make_error_finder, make_rust_code_finder, make_string_finder, CppMatcher,
16 NoSystemHeadersChecker,
17 },
18};
19use autocxx_integration_tests::{
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070020 directives_from_lists, do_run_test, do_run_test_manual, run_generate_all_test, run_test,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070021 run_test_ex, run_test_expect_fail, run_test_expect_fail_ex, BuilderModifier, TestError,
Brian Silverman4e662aa2022-05-11 23:10:19 -070022};
23use indoc::indoc;
24use itertools::Itertools;
25use proc_macro2::{Span, TokenStream};
26use quote::quote;
27use syn::{parse_quote, Token};
28use test_log::test;
29
30#[test]
31fn test_return_void() {
32 let cxx = indoc! {"
33 void do_nothing() {
34 }
35 "};
36 let hdr = indoc! {"
37 void do_nothing();
38 "};
39 let rs = quote! {
40 ffi::do_nothing();
41 };
42 run_test(cxx, hdr, rs, &["do_nothing"], &[]);
43}
44
45#[test]
46fn test_two_funcs() {
47 let cxx = indoc! {"
48 void do_nothing1() {
49 }
50 void do_nothing2() {
51 }
52 "};
53 let hdr = indoc! {"
54 void do_nothing1();
55 void do_nothing2();
56 "};
57 let rs = quote! {
58 ffi::do_nothing1();
59 ffi::do_nothing2();
60 };
61 run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
62}
63
64#[test]
65fn test_two_funcs_with_definition() {
66 // Test to ensure C++ header isn't included twice
67 let cxx = indoc! {"
68 void do_nothing1() {
69 }
70 void do_nothing2() {
71 }
72 "};
73 let hdr = indoc! {"
74 struct Bob {
75 int a;
76 };
77 void do_nothing1();
78 void do_nothing2();
79 "};
80 let rs = quote! {
81 ffi::do_nothing1();
82 ffi::do_nothing2();
83 };
84 run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
85}
86
87#[test]
88fn test_return_i32() {
89 let cxx = indoc! {"
90 uint32_t give_int() {
91 return 5;
92 }
93 "};
94 let hdr = indoc! {"
95 #include <cstdint>
96 uint32_t give_int();
97 "};
98 let rs = quote! {
99 assert_eq!(ffi::give_int(), 5);
100 };
101 run_test(cxx, hdr, rs, &["give_int"], &[]);
102}
103
104#[test]
105fn test_take_i32() {
106 let cxx = indoc! {"
107 uint32_t take_int(uint32_t a) {
108 return a + 3;
109 }
110 "};
111 let hdr = indoc! {"
112 #include <cstdint>
113 uint32_t take_int(uint32_t a);
114 "};
115 let rs = quote! {
116 assert_eq!(ffi::take_int(3), 6);
117 };
118 run_test(cxx, hdr, rs, &["take_int"], &[]);
119}
120
121#[test]
122fn test_nested_module() {
123 let cxx = indoc! {"
124 void do_nothing() {
125 }
126 "};
127 let hdr = indoc! {"
128 void do_nothing();
129 "};
130 let hexathorpe = Token![#](Span::call_site());
131 let unexpanded_rust = quote! {
132 mod a {
133 use autocxx::prelude::*;
134
135 include_cpp!(
136 #hexathorpe include "input.h"
137 generate!("do_nothing")
138 safety!(unsafe)
139 );
140
141 pub use ffi::*;
142 }
143
144 fn main() {
145 a::do_nothing();
146 }
147 };
148
149 do_run_test_manual(cxx, hdr, unexpanded_rust, None, None).unwrap();
150}
151
152#[test]
153#[ignore] // https://github.com/google/autocxx/issues/681
154#[cfg(target_pointer_width = "64")]
155fn test_return_big_ints() {
156 let cxx = indoc! {"
157 "};
158 let hdr = indoc! {"
159 #include <cstdint>
160 inline uint32_t give_u32() {
161 return 5;
162 }
163 inline uint64_t give_u64() {
164 return 5;
165 }
166 inline int32_t give_i32() {
167 return 5;
168 }
169 inline int64_t give_i64() {
170 return 5;
171 }
172 inline __int128 give_i128() {
173 return 5;
174 }
175 "};
176 let rs = quote! {
177 assert_eq!(ffi::give_u32(), 5);
178 assert_eq!(ffi::give_u64(), 5);
179 assert_eq!(ffi::give_i32(), 5);
180 assert_eq!(ffi::give_i64(), 5);
181 assert_eq!(ffi::give_i128(), 5);
182 };
183 run_test(
184 cxx,
185 hdr,
186 rs,
187 &["give_u32", "give_u64", "give_i32", "give_i64", "give_i128"],
188 &[],
189 );
190}
191
192#[test]
193#[ignore] // because cxx doesn't support unique_ptrs to primitives.
194fn test_give_up_int() {
195 let cxx = indoc! {"
196 std::unique_ptr<uint32_t> give_up() {
197 return std::make_unique<uint32_t>(12);
198 }
199 "};
200 let hdr = indoc! {"
201 #include <cstdint>
202 #include <memory>
203 std::unique_ptr<uint32_t> give_up();
204 "};
205 let rs = quote! {
206 assert_eq!(ffi::give_up().as_ref().unwrap(), 12);
207 };
208 run_test(cxx, hdr, rs, &["give_up"], &[]);
209}
210
211#[test]
212#[ignore] // because we don't yet implement UniquePtr etc. for autocxx::c_int and friends
213fn test_give_up_ctype() {
214 let cxx = indoc! {"
215 std::unique_ptr<int> give_up() {
216 return std::make_unique<int>(12);
217 }
218 "};
219 let hdr = indoc! {"
220 #include <memory>
221 std::unique_ptr<int> give_up();
222 "};
223 let rs = quote! {
224 assert_eq!(ffi::give_up().as_ref().unwrap(), autocxx::c_int(12));
225 };
226 run_test(cxx, hdr, rs, &["give_up"], &[]);
227}
228
229#[test]
230fn test_give_string_up() {
231 let cxx = indoc! {"
232 std::unique_ptr<std::string> give_str_up() {
233 return std::make_unique<std::string>(\"Bob\");
234 }
235 "};
236 let hdr = indoc! {"
237 #include <memory>
238 #include <string>
239 std::unique_ptr<std::string> give_str_up();
240 "};
241 let rs = quote! {
242 assert_eq!(ffi::give_str_up().as_ref().unwrap().to_str().unwrap(), "Bob");
243 };
244 run_test(cxx, hdr, rs, &["give_str_up"], &[]);
245}
246
247#[test]
248fn test_give_string_plain() {
249 let cxx = indoc! {"
250 std::string give_str() {
251 return std::string(\"Bob\");
252 }
253 "};
254 let hdr = indoc! {"
255 #include <string>
256 std::string give_str();
257 "};
258 let rs = quote! {
259 assert_eq!(ffi::give_str().as_ref().unwrap(), "Bob");
260 };
261 run_test(cxx, hdr, rs, &["give_str"], &[]);
262}
263
264#[test]
265fn test_cycle_string_up() {
266 let cxx = indoc! {"
267 std::unique_ptr<std::string> give_str_up() {
268 return std::make_unique<std::string>(\"Bob\");
269 }
270 uint32_t take_str_up(std::unique_ptr<std::string> a) {
271 return a->length();
272 }
273 "};
274 let hdr = indoc! {"
275 #include <memory>
276 #include <string>
277 #include <cstdint>
278 std::unique_ptr<std::string> give_str_up();
279 uint32_t take_str_up(std::unique_ptr<std::string> a);
280 "};
281 let rs = quote! {
282 let s = ffi::give_str_up();
283 assert_eq!(ffi::take_str_up(s), 3);
284 };
285 run_test(cxx, hdr, rs, &["give_str_up", "take_str_up"], &[]);
286}
287
288#[test]
289fn test_cycle_string() {
290 let cxx = indoc! {"
291 std::string give_str() {
292 return std::string(\"Bob\");
293 }
294 uint32_t take_str(std::string a) {
295 return a.length();
296 }
297 "};
298 let hdr = indoc! {"
299 #include <string>
300 #include <cstdint>
301 std::string give_str();
302 uint32_t take_str(std::string a);
303 "};
304 let rs = quote! {
305 let s = ffi::give_str();
306 assert_eq!(ffi::take_str(s), 3);
307 };
308 let generate = &["give_str", "take_str"];
309 run_test(cxx, hdr, rs, generate, &[]);
310}
311
312#[test]
313fn test_cycle_string_by_ref() {
314 let cxx = indoc! {"
315 std::unique_ptr<std::string> give_str() {
316 return std::make_unique<std::string>(\"Bob\");
317 }
318 uint32_t take_str(const std::string& a) {
319 return a.length();
320 }
321 "};
322 let hdr = indoc! {"
323 #include <string>
324 #include <memory>
325 #include <cstdint>
326 std::unique_ptr<std::string> give_str();
327 uint32_t take_str(const std::string& a);
328 "};
329 let rs = quote! {
330 let s = ffi::give_str();
331 assert_eq!(ffi::take_str(s.as_ref().unwrap()), 3);
332 };
333 let generate = &["give_str", "take_str"];
334 run_test(cxx, hdr, rs, generate, &[]);
335}
336
337#[test]
338fn test_cycle_string_by_mut_ref() {
339 let cxx = indoc! {"
340 std::unique_ptr<std::string> give_str() {
341 return std::make_unique<std::string>(\"Bob\");
342 }
343 uint32_t take_str(std::string& a) {
344 return a.length();
345 }
346 "};
347 let hdr = indoc! {"
348 #include <string>
349 #include <memory>
350 #include <cstdint>
351 std::unique_ptr<std::string> give_str();
352 uint32_t take_str(std::string& a);
353 "};
354 let rs = quote! {
355 let mut s = ffi::give_str();
356 assert_eq!(ffi::take_str(s.as_mut().unwrap()), 3);
357 };
358 let generate = &["give_str", "take_str"];
359 run_test(cxx, hdr, rs, generate, &[]);
360}
361
362#[test]
363fn test_give_pod_by_value() {
364 let cxx = indoc! {"
365 Bob give_bob() {
366 Bob a;
367 a.a = 3;
368 a.b = 4;
369 return a;
370 }
371 "};
372 let hdr = indoc! {"
373 #include <cstdint>
374 struct Bob {
375 uint32_t a;
376 uint32_t b;
377 };
378 Bob give_bob();
379 "};
380 let rs = quote! {
381 assert_eq!(ffi::give_bob().b, 4);
382 };
383 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
384}
385
386#[test]
387fn test_give_pod_class_by_value() {
388 let cxx = indoc! {"
389 Bob give_bob() {
390 Bob a;
391 a.a = 3;
392 a.b = 4;
393 return a;
394 }
395 "};
396 let hdr = indoc! {"
397 #include <cstdint>
398 class Bob {
399 public:
400 uint32_t a;
401 uint32_t b;
402 };
403 Bob give_bob();
404 "};
405 let rs = quote! {
406 assert_eq!(ffi::give_bob().b, 4);
407 };
408 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
409}
410
411#[test]
412fn test_give_pod_by_up() {
413 let cxx = indoc! {"
414 std::unique_ptr<Bob> give_bob() {
415 auto a = std::make_unique<Bob>();
416 a->a = 3;
417 a->b = 4;
418 return a;
419 }
420 "};
421 let hdr = indoc! {"
422 #include <cstdint>
423 #include <memory>
424 struct Bob {
425 uint32_t a;
426 uint32_t b;
427 };
428 std::unique_ptr<Bob> give_bob();
429 "};
430 let rs = quote! {
431 assert_eq!(ffi::give_bob().as_ref().unwrap().b, 4);
432 };
433 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
434}
435
436#[test]
437fn test_take_pod_by_value() {
438 let cxx = indoc! {"
439 uint32_t take_bob(Bob a) {
440 return a.a;
441 }
442 "};
443 let hdr = indoc! {"
444 #include <cstdint>
445 struct Bob {
446 uint32_t a;
447 uint32_t b;
448 };
449 uint32_t take_bob(Bob a);
450 "};
451 let rs = quote! {
452 let a = ffi::Bob { a: 12, b: 13 };
453 assert_eq!(ffi::take_bob(a), 12);
454 };
455 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
456}
457
458#[test]
459fn test_negative_take_as_pod_with_destructor() {
460 let cxx = indoc! {"
461 uint32_t take_bob(Bob a) {
462 return a.a;
463 }
464 "};
465 let hdr = indoc! {"
466 #include <cstdint>
467 struct Bob {
468 uint32_t a;
469 uint32_t b;
470 inline ~Bob() {}
471 };
472 uint32_t take_bob(Bob a);
473 "};
474 let rs = quote! {
475 let a = ffi::Bob { a: 12, b: 13 };
476 assert_eq!(ffi::take_bob(a), 12);
477 };
478 run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]);
479}
480
481#[test]
482fn test_negative_take_as_pod_with_move_constructor() {
483 let cxx = indoc! {"
484 uint32_t take_bob(Bob a) {
485 return a.a;
486 }
487 "};
488 let hdr = indoc! {"
489 #include <cstdint>
490 #include <type_traits>
491 struct Bob {
492 uint32_t a;
493 uint32_t b;
494 inline Bob(Bob&& other_bob) {}
495 };
496 uint32_t take_bob(Bob a);
497 "};
498 let rs = quote! {
499 let a = ffi::Bob { a: 12, b: 13 };
500 assert_eq!(ffi::take_bob(a), 12);
501 };
502 run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]);
503}
504
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700505#[ignore] // https://github.com/google/autocxx/issues/1252
Brian Silverman4e662aa2022-05-11 23:10:19 -0700506#[test]
507fn test_take_as_pod_with_is_relocatable() {
508 let cxx = indoc! {"
509 uint32_t take_bob(Bob a) {
510 return a.a;
511 }
512 "};
513 let hdr = indoc! {"
514 #include <cstdint>
515 #include <type_traits>
516 struct Bob {
517 uint32_t a;
518 uint32_t b;
519 inline Bob() {}
520 inline ~Bob() {}
521 inline Bob(Bob&& other_bob) { a = other_bob.a; b = other_bob.b; }
522 using IsRelocatable = std::true_type;
523 };
524 uint32_t take_bob(Bob a);
525 "};
526 let rs = quote! {
527 let a = ffi::Bob { a: 12, b: 13 };
528 assert_eq!(ffi::take_bob(a), 12);
529 };
530 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
531}
532
533#[test]
534fn test_take_pod_by_ref() {
535 let cxx = indoc! {"
536 uint32_t take_bob(const Bob& a) {
537 return a.a;
538 }
539 "};
540 let hdr = indoc! {"
541 #include <cstdint>
542 struct Bob {
543 uint32_t a;
544 uint32_t b;
545 };
546 uint32_t take_bob(const Bob& a);
547 "};
548 let rs = quote! {
549 let a = ffi::Bob { a: 12, b: 13 };
550 assert_eq!(ffi::take_bob(&a), 12);
551 };
552 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
553}
554
555#[test]
556fn test_take_pod_by_ref_and_ptr() {
557 let cxx = indoc! {"
558 uint32_t take_bob_ref(const Bob& a) {
559 return a.a;
560 }
561 uint32_t take_bob_ptr(const Bob* a) {
562 return a->a;
563 }
564 "};
565 let hdr = indoc! {"
566 #include <cstdint>
567 struct Bob {
568 uint32_t a;
569 uint32_t b;
570 };
571 uint32_t take_bob_ref(const Bob& a);
572 uint32_t take_bob_ptr(const Bob* a);
573 "};
574 let rs = quote! {
575 let a = ffi::Bob { a: 12, b: 13 };
576 assert_eq!(ffi::take_bob_ref(&a), 12);
577 };
578 run_test(cxx, hdr, rs, &["take_bob_ref", "take_bob_ptr"], &["Bob"]);
579}
580
581#[test]
582fn test_return_pod_by_ref_and_ptr() {
583 let hdr = indoc! {"
584 #include <cstdint>
585 struct B {
586 uint32_t a;
587 };
588 struct A {
589 B b;
590 };
591 inline const B& return_b_ref(const A& a) {
592 return a.b;
593 }
594 inline const B* return_b_ptr(const A& a) {
595 return &a.b;
596 }
597 "};
598 let rs = quote! {
599 let a = ffi::A { b: ffi::B { a: 3 } };
600 assert_eq!(ffi::return_b_ref(&a).a, 3);
601 let b_ptr = ffi::return_b_ptr(&a);
602 assert_eq!(unsafe { b_ptr.as_ref() }.unwrap().a, 3);
603 };
604 run_test("", hdr, rs, &["return_b_ref", "return_b_ptr"], &["A", "B"]);
605}
606
607#[test]
608fn test_take_pod_by_mut_ref() {
609 let cxx = indoc! {"
610 uint32_t take_bob(Bob& a) {
611 a.b = 14;
612 return a.a;
613 }
614 "};
615 let hdr = indoc! {"
616 #include <cstdint>
617 struct Bob {
618 uint32_t a;
619 uint32_t b;
620 };
621 uint32_t take_bob(Bob& a);
622 "};
623 let rs = quote! {
624 let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
625 assert_eq!(ffi::take_bob(a.as_mut()), 12);
626 assert_eq!(a.b, 14);
627 };
628 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
629}
630
631#[test]
632fn test_take_nested_pod_by_value() {
633 let cxx = indoc! {"
634 uint32_t take_bob(Bob a) {
635 return a.a;
636 }
637 "};
638 let hdr = indoc! {"
639 #include <cstdint>
640 struct Phil {
641 uint32_t d;
642 };
643 struct Bob {
644 uint32_t a;
645 uint32_t b;
646 Phil c;
647 };
648 uint32_t take_bob(Bob a);
649 "};
650 let rs = quote! {
651 let a = ffi::Bob { a: 12, b: 13, c: ffi::Phil { d: 4 } };
652 assert_eq!(ffi::take_bob(a), 12);
653 };
654 // Should be no need to allowlist Phil below
655 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
656}
657
658#[test]
659fn test_take_nonpod_by_value() {
660 let cxx = indoc! {"
661 Bob::Bob(uint32_t a0, uint32_t b0)
662 : a(a0), b(b0) {}
663 uint32_t take_bob(Bob a) {
664 return a.a;
665 }
666 "};
667 let hdr = indoc! {"
668 #include <cstdint>
669 #include <string>
670 struct Bob {
671 Bob(uint32_t a, uint32_t b);
672 uint32_t a;
673 uint32_t b;
674 std::string reason_why_this_is_nonpod;
675 };
676 uint32_t take_bob(Bob a);
677 "};
678 let rs = quote! {
679 let a = ffi::Bob::new(12, 13).within_unique_ptr();
680 assert_eq!(ffi::take_bob(a), 12);
681 };
682 run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
683}
684
685#[test]
686fn test_take_nonpod_by_ref() {
687 let cxx = indoc! {"
688 uint32_t take_bob(const Bob& a) {
689 return a.a;
690 }
691 std::unique_ptr<Bob> make_bob(uint32_t a) {
692 auto b = std::make_unique<Bob>();
693 b->a = a;
694 return b;
695 }
696 "};
697 let hdr = indoc! {"
698 #include <cstdint>
699 #include <memory>
700 struct Bob {
701 uint32_t a;
702 };
703 std::unique_ptr<Bob> make_bob(uint32_t a);
704 uint32_t take_bob(const Bob& a);
705 "};
706 let rs = quote! {
707 let a = ffi::make_bob(12);
708 assert_eq!(ffi::take_bob(&a), 12);
709 };
710 run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
711}
712
713#[test]
714fn test_take_nonpod_by_up() {
715 let cxx = indoc! {"
716 uint32_t take_bob(std::unique_ptr<Bob> a) {
717 return a->a;
718 }
719 std::unique_ptr<Bob> make_bob(uint32_t a) {
720 auto b = std::make_unique<Bob>();
721 b->a = a;
722 return b;
723 }
724 "};
725 let hdr = indoc! {"
726 #include <cstdint>
727 #include <memory>
728 struct Bob {
729 uint32_t a;
730 };
731
732 struct NOP { inline void take_bob(); };
733 std::unique_ptr<Bob> make_bob(uint32_t a);
734 uint32_t take_bob(std::unique_ptr<Bob> a);
735 "};
736 let rs = quote! {
737 let a = ffi::make_bob(12);
738 assert_eq!(ffi::take_bob(a), 12);
739 };
740 run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob", "NOP"], &[]);
741}
742
743#[test]
744fn test_take_nonpod_by_ptr_simple() {
745 let cxx = indoc! {"
746 uint32_t take_bob(const Bob* a) {
747 return a->a;
748 }
749 std::unique_ptr<Bob> make_bob(uint32_t a) {
750 auto b = std::make_unique<Bob>();
751 b->a = a;
752 return b;
753 }
754 "};
755 let hdr = indoc! {"
756 #include <cstdint>
757 #include <memory>
758 struct Bob {
759 uint32_t a;
760 };
761 std::unique_ptr<Bob> make_bob(uint32_t a);
762 uint32_t take_bob(const Bob* a);
763 "};
764 let rs = quote! {
765 let a = ffi::make_bob(12);
766 let a_ptr = a.into_raw();
767 assert_eq!(unsafe { ffi::take_bob(a_ptr) }, 12);
768 unsafe { cxx::UniquePtr::from_raw(a_ptr) }; // so we drop
769 };
770 run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
771}
772
773#[test]
774fn test_take_nonpod_by_ptr_in_method() {
775 let hdr = indoc! {"
776 #include <cstdint>
777 #include <memory>
778 struct Bob {
779 uint32_t a;
780 };
781 #include <cstdint>
782 class A {
783 public:
784 A() {};
785 uint32_t take_bob(const Bob* a) const {
786 return a->a;
787 }
788 std::unique_ptr<Bob> make_bob(uint32_t a) const {
789 auto b = std::make_unique<Bob>();
790 b->a = a;
791 return b;
792 }
793 uint16_t a;
794 };
795
796 "};
797 let rs = quote! {
798 let a = ffi::A::new().within_unique_ptr();
799 let b = a.as_ref().unwrap().make_bob(12);
800 let b_ptr = b.into_raw();
801 assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr) }, 12);
802 unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop
803 };
804 run_test("", hdr, rs, &["A", "Bob"], &[]);
805}
806
807#[test]
808fn test_take_nonpod_by_ptr_in_wrapped_method() {
809 let hdr = indoc! {"
810 #include <cstdint>
811 #include <memory>
812 struct C {
813 C() {}
814 uint32_t a;
815 };
816 struct Bob {
817 uint32_t a;
818 };
819 class A {
820 public:
821 A() {};
822 uint32_t take_bob(const Bob* a, C) const {
823 return a->a;
824 }
825 std::unique_ptr<Bob> make_bob(uint32_t a) const {
826 auto b = std::make_unique<Bob>();
827 b->a = a;
828 return b;
829 }
830 uint16_t a;
831 };
832
833 "};
834 let rs = quote! {
835 let a = ffi::A::new().within_unique_ptr();
836 let c = ffi::C::new().within_unique_ptr();
837 let b = a.as_ref().unwrap().make_bob(12);
838 let b_ptr = b.into_raw();
839 assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr, c) }, 12);
840 unsafe { cxx::UniquePtr::from_raw(b_ptr) }; // so we drop
841 };
842 run_test("", hdr, rs, &["A", "Bob", "C"], &[]);
843}
844
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700845fn run_char_test(builder_modifier: Option<BuilderModifier>) {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700846 let hdr = indoc! {"
847 #include <cstdint>
848 #include <memory>
849 struct C {
850 C() { test = \"hi\"; }
851 uint32_t a;
852 const char* test;
853 };
854 class A {
855 public:
856 A() {};
857 uint32_t take_char(const char* a, C) const {
858 return a[0];
859 }
860 const char* make_char(C extra) const {
861 return extra.test;
862 }
863 uint16_t a;
864 };
865
866 "};
867 let rs = quote! {
868 let a = ffi::A::new().within_unique_ptr();
869 let c1 = ffi::C::new().within_unique_ptr();
870 let c2 = ffi::C::new().within_unique_ptr();
871 let ch = a.as_ref().unwrap().make_char(c1);
872 assert_eq!(unsafe { ch.as_ref()}.unwrap(), &104i8);
873 assert_eq!(unsafe { a.as_ref().unwrap().take_char(ch, c2) }, 104);
874 };
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700875 run_test_ex(
876 "",
877 hdr,
878 rs,
879 directives_from_lists(&["A", "C"], &[], None),
880 builder_modifier,
881 None,
882 None,
883 );
884}
885
886#[test]
887fn test_take_char_by_ptr_in_wrapped_method() {
888 run_char_test(None)
889}
890
891#[test]
892fn test_take_char_by_ptr_in_wrapped_method_with_unsigned_chars() {
893 run_char_test(make_clang_arg_adder(&["-funsigned-char"]))
Brian Silverman4e662aa2022-05-11 23:10:19 -0700894}
895
896#[test]
897fn test_take_nonpod_by_mut_ref() {
898 let cxx = indoc! {"
899 uint32_t take_bob(Bob& a) {
900 return a.a;
901 }
902 std::unique_ptr<Bob> make_bob(uint32_t a) {
903 auto b = std::make_unique<Bob>();
904 b->a = a;
905 return b;
906 }
907 "};
908 let hdr = indoc! {"
909 #include <cstdint>
910 #include <memory>
911 struct Bob {
912 uint32_t a;
913 };
914 std::unique_ptr<Bob> make_bob(uint32_t a);
915 uint32_t take_bob(Bob& a);
916 "};
917 let rs = quote! {
918 let mut a = ffi::make_bob(12);
919 assert_eq!(ffi::take_bob(a.pin_mut()), 12);
920 };
921 // TODO confirm that the object really was mutated by C++ in this
922 // and similar tests.
923 run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
924}
925
926#[test]
927fn test_return_nonpod_by_value() {
928 let cxx = indoc! {"
929 Bob::Bob(uint32_t a0, uint32_t b0)
930 : a(a0), b(b0) {}
931 Bob give_bob(uint32_t a) {
932 Bob c(a, 44);
933 return c;
934 }
935 uint32_t take_bob(std::unique_ptr<Bob> a) {
936 return a->a;
937 }
938 "};
939 let hdr = indoc! {"
940 #include <cstdint>
941 #include <memory>
942 struct Bob {
943 Bob(uint32_t a, uint32_t b);
944 uint32_t a;
945 uint32_t b;
946 };
947 Bob give_bob(uint32_t a);
948 uint32_t take_bob(std::unique_ptr<Bob> a);
949 "};
950 let rs = quote! {
951 let a = ffi::give_bob(13).within_unique_ptr();
952 assert_eq!(ffi::take_bob(a), 13);
953 };
954 run_test(cxx, hdr, rs, &["take_bob", "give_bob", "Bob"], &[]);
955}
956
957#[test]
958fn test_get_str_by_up() {
959 let cxx = indoc! {"
960 std::unique_ptr<std::string> get_str() {
961 return std::make_unique<std::string>(\"hello\");
962 }
963 "};
964 let hdr = indoc! {"
965 #include <string>
966 #include <memory>
967 std::unique_ptr<std::string> get_str();
968 "};
969 let rs = quote! {
970 assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
971 };
972 run_test(cxx, hdr, rs, &["get_str"], &[]);
973}
974
975#[test]
976fn test_get_str_by_value() {
977 let cxx = indoc! {"
978 std::string get_str() {
979 return \"hello\";
980 }
981 "};
982 let hdr = indoc! {"
983 #include <string>
984 std::string get_str();
985 "};
986 let rs = quote! {
987 assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
988 };
989 run_test(cxx, hdr, rs, &["get_str"], &[]);
990}
991
992#[test]
993fn test_cycle_nonpod_with_str_by_ref() {
994 let cxx = indoc! {"
995 uint32_t take_bob(const Bob& a) {
996 return a.a;
997 }
998 std::unique_ptr<Bob> make_bob() {
999 auto a = std::make_unique<Bob>();
1000 a->a = 32;
1001 a->b = \"hello\";
1002 return a;
1003 }
1004 "};
1005 let hdr = indoc! {"
1006 #include <cstdint>
1007 #include <string>
1008 #include <memory>
1009 struct Bob {
1010 uint32_t a;
1011 std::string b;
1012 };
1013 uint32_t take_bob(const Bob& a);
1014 std::unique_ptr<Bob> make_bob();
1015 "};
1016 let rs = quote! {
1017 let a = ffi::make_bob();
1018 assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 32);
1019 };
1020 run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
1021}
1022
1023#[test]
1024fn test_make_up() {
1025 let cxx = indoc! {"
1026 Bob::Bob() : a(3) {
1027 }
1028 uint32_t take_bob(const Bob& a) {
1029 return a.a;
1030 }
1031 "};
1032 let hdr = indoc! {"
1033 #include <cstdint>
1034 class Bob {
1035 public:
1036 Bob();
1037 uint32_t a;
1038 };
1039 uint32_t take_bob(const Bob& a);
1040 "};
1041 let rs = quote! {
1042 let a = ffi::Bob::new().within_unique_ptr(); // TODO test with all sorts of arguments.
1043 assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 3);
1044 };
1045 run_test(cxx, hdr, rs, &["Bob", "take_bob"], &[]);
1046}
1047
1048#[test]
1049fn test_make_up_with_args() {
1050 let cxx = indoc! {"
1051 Bob::Bob(uint32_t a0, uint32_t b0)
1052 : a(a0), b(b0) {}
1053 uint32_t take_bob(const Bob& a) {
1054 return a.a;
1055 }
1056 "};
1057 let hdr = indoc! {"
1058 #include <cstdint>
1059 struct Bob {
1060 Bob(uint32_t a, uint32_t b);
1061 uint32_t a;
1062 uint32_t b;
1063 };
1064 uint32_t take_bob(const Bob& a);
1065 "};
1066 let rs = quote! {
1067 let a = ffi::Bob::new(12, 13).within_unique_ptr();
1068 assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 12);
1069 };
1070 run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
1071}
1072
1073#[test]
1074#[ignore] // because we don't support unique_ptrs to primitives
1075fn test_make_up_int() {
1076 let cxx = indoc! {"
1077 Bob::Bob(uint32_t a) : b(a) {
1078 }
1079 "};
1080 let hdr = indoc! {"
1081 #include <cstdint>
1082 class Bob {
1083 public:
1084 Bob(uint32_t a);
1085 uint32_t b;
1086 };
1087 "};
1088 let rs = quote! {
1089 let a = ffi::Bob::new(3).within_unique_ptr();
1090 assert_eq!(a.as_ref().unwrap().b, 3);
1091 };
1092 run_test(cxx, hdr, rs, &["Bob"], &[]);
1093}
1094
1095#[test]
1096fn test_enum_with_funcs() {
1097 let cxx = indoc! {"
1098 Bob give_bob() {
1099 return Bob::BOB_VALUE_2;
1100 }
1101 "};
1102 let hdr = indoc! {"
1103 #include <cstdint>
1104 enum Bob {
1105 BOB_VALUE_1,
1106 BOB_VALUE_2,
1107 };
1108 Bob give_bob();
1109 "};
1110 let rs = quote! {
1111 let a = ffi::Bob::BOB_VALUE_2;
1112 let b = ffi::give_bob();
1113 assert!(a == b);
1114 };
1115 run_test(cxx, hdr, rs, &["Bob", "give_bob"], &[]);
1116}
1117
1118#[test]
1119fn test_re_export() {
1120 let cxx = indoc! {"
1121 Bob give_bob() {
1122 return Bob::BOB_VALUE_2;
1123 }
1124 "};
1125 let hdr = indoc! {"
1126 #include <cstdint>
1127 enum Bob {
1128 BOB_VALUE_1,
1129 BOB_VALUE_2,
1130 };
1131 Bob give_bob();
1132 "};
1133 let rs = quote! {
1134 let a = ffi::Bob::BOB_VALUE_2;
1135 let b = ffi::give_bob();
1136 assert!(a == b);
1137 };
1138 run_test_ex(
1139 cxx,
1140 hdr,
1141 rs,
1142 directives_from_lists(&["Bob", "give_bob"], &[], None),
1143 None,
1144 None,
1145 Some(quote! { pub use ffi::Bob; }),
1146 );
1147}
1148
1149#[test]
1150fn test_enum_no_funcs() {
1151 let cxx = indoc! {"
1152 "};
1153 let hdr = indoc! {"
1154 enum Bob {
1155 BOB_VALUE_1,
1156 BOB_VALUE_2,
1157 };
1158 "};
1159 let rs = quote! {
1160 let a = ffi::Bob::BOB_VALUE_1;
1161 let b = ffi::Bob::BOB_VALUE_2;
1162 assert!(a != b);
1163 };
1164 run_test(cxx, hdr, rs, &["Bob"], &[]);
1165}
1166
1167#[test]
1168fn test_enum_with_funcs_as_pod() {
1169 let cxx = indoc! {"
1170 Bob give_bob() {
1171 return Bob::BOB_VALUE_2;
1172 }
1173 "};
1174 let hdr = indoc! {"
1175 #include <cstdint>
1176 enum Bob {
1177 BOB_VALUE_1,
1178 BOB_VALUE_2,
1179 };
1180 Bob give_bob();
1181 "};
1182 let rs = quote! {
1183 let a = ffi::Bob::BOB_VALUE_2;
1184 let b = ffi::give_bob();
1185 assert!(a == b);
1186 };
1187 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
1188}
1189
1190#[test] // works, but causes compile warnings
1191fn test_take_pod_class_by_value() {
1192 let cxx = indoc! {"
1193 uint32_t take_bob(Bob a) {
1194 return a.a;
1195 }
1196 "};
1197 let hdr = indoc! {"
1198 #include <cstdint>
1199 class Bob {
1200 public:
1201 uint32_t a;
1202 uint32_t b;
1203 };
1204 uint32_t take_bob(Bob a);
1205 "};
1206 let rs = quote! {
1207 let a = ffi::Bob { a: 12, b: 13 };
1208 assert_eq!(ffi::take_bob(a), 12);
1209 };
1210 run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
1211}
1212
1213#[test]
1214fn test_pod_method() {
1215 let cxx = indoc! {"
1216 uint32_t Bob::get_bob() const {
1217 return a;
1218 }
1219 "};
1220 let hdr = indoc! {"
1221 #include <cstdint>
1222 struct Bob {
1223 public:
1224 uint32_t a;
1225 uint32_t b;
1226 uint32_t get_bob() const;
1227 };
1228 "};
1229 let rs = quote! {
1230 let a = ffi::Bob { a: 12, b: 13 };
1231 assert_eq!(a.get_bob(), 12);
1232 };
1233 run_test(cxx, hdr, rs, &[], &["Bob"]);
1234}
1235
1236#[test]
1237#[ignore] // https://github.com/google/autocxx/issues/723
1238fn test_constructors_for_specialized_types() {
1239 // bindgen sometimes makes such opaque types as type Bob = u32[2];
1240 let hdr = indoc! {"
1241 #include <cstdint>
1242 template<typename T>
1243 class A {
1244 uint32_t foo() { return 12; };
1245 private:
1246 T a[2];
1247 };
1248
1249 typedef A<uint32_t> B;
1250 typedef B C;
1251 "};
1252 let rs = quote! {
1253 let a = ffi::C::new().within_unique_ptr();
1254 assert_eq!(a.foo(), 12);
1255 };
1256 run_test("", hdr, rs, &["C"], &[]);
1257}
1258
1259#[test]
1260fn test_pod_mut_method() {
1261 let cxx = indoc! {"
1262 uint32_t Bob::get_bob() {
1263 return a;
1264 }
1265 "};
1266 let hdr = indoc! {"
1267 #include <cstdint>
1268 struct Bob {
1269 public:
1270 uint32_t a;
1271 uint32_t b;
1272 uint32_t get_bob();
1273 };
1274 "};
1275 let rs = quote! {
1276 let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
1277 assert_eq!(a.as_mut().get_bob(), 12);
1278 };
1279 run_test(cxx, hdr, rs, &[], &["Bob"]);
1280}
1281
1282#[test]
1283fn test_define_int() {
1284 let cxx = indoc! {"
1285 "};
1286 let hdr = indoc! {"
1287 #define BOB 3
1288 "};
1289 let rs = quote! {
1290 assert_eq!(ffi::BOB, 3);
1291 };
1292 run_test(cxx, hdr, rs, &["BOB"], &[]);
1293}
1294
1295#[test]
1296fn test_define_str() {
1297 let cxx = indoc! {"
1298 "};
1299 let hdr = indoc! {"
1300 #define BOB \"foo\"
1301 "};
1302 let rs = quote! {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07001303 assert_eq!(core::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
Brian Silverman4e662aa2022-05-11 23:10:19 -07001304 };
1305 run_test(cxx, hdr, rs, &["BOB"], &[]);
1306}
1307
1308#[test]
1309fn test_i32_const() {
1310 let cxx = indoc! {"
1311 "};
1312 let hdr = indoc! {"
1313 #include <cstdint>
1314 const uint32_t BOB = 3;
1315 "};
1316 let rs = quote! {
1317 assert_eq!(ffi::BOB, 3);
1318 };
1319 run_test(cxx, hdr, rs, &["BOB"], &[]);
1320}
1321
1322#[test]
1323fn test_negative_rs_nonsense() {
1324 // Really just testing the test infrastructure.
1325 let cxx = indoc! {"
1326 "};
1327 let hdr = indoc! {"
1328 #include <cstdint>
1329 const uint32_t BOB = 3;
1330 "};
1331 let rs = quote! {
1332 foo bar
1333 };
1334 run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
1335}
1336
1337#[test]
1338fn test_negative_cpp_nonsense() {
1339 // Really just testing the test infrastructure.
1340 let cxx = indoc! {"
1341 "};
1342 let hdr = indoc! {"
1343 #include <cstdint>
1344 const uint32_t BOB = CAT;
1345 "};
1346 let rs = quote! {
1347 assert_eq!(ffi::BOB, 3);
1348 };
1349 run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
1350}
1351
1352#[test]
1353fn test_negative_make_nonpod() {
1354 let cxx = indoc! {"
1355 uint32_t take_bob(const Bob& a) {
1356 return a.a;
1357 }
1358 std::unique_ptr<Bob> make_bob(uint32_t a) {
1359 auto b = std::make_unique<Bob>();
1360 b->a = a;
1361 return b;
1362 }
1363 "};
1364 let hdr = indoc! {"
1365 #include <cstdint>
1366 #include <memory>
1367 struct Bob {
1368 uint32_t a;
1369 };
1370 std::unique_ptr<Bob> make_bob(uint32_t a);
1371 uint32_t take_bob(const Bob& a);
1372 "};
1373 let rs = quote! {
1374 ffi::Bob {};
1375 };
1376 let rs2 = quote! {
1377 ffi::Bob { a: 12 };
1378 };
1379 let rs3 = quote! {
1380 ffi::Bob { do_not_attempt_to_allocate_nonpod_types: [] };
1381 };
1382 run_test_expect_fail(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
1383 run_test_expect_fail(cxx, hdr, rs2, &["take_bob", "Bob", "make_bob"], &[]);
1384 run_test_expect_fail(cxx, hdr, rs3, &["take_bob", "Bob", "make_bob"], &[]);
1385}
1386
1387#[test]
1388fn test_method_pass_pod_by_value() {
1389 let cxx = indoc! {"
1390 uint32_t Bob::get_bob(Anna) const {
1391 return a;
1392 }
1393 "};
1394 let hdr = indoc! {"
1395 #include <cstdint>
1396 struct Anna {
1397 uint32_t a;
1398 };
1399 struct Bob {
1400 public:
1401 uint32_t a;
1402 uint32_t b;
1403 uint32_t get_bob(Anna a) const;
1404 };
1405 "};
1406 let rs = quote! {
1407 let a = ffi::Anna { a: 14 };
1408 let b = ffi::Bob { a: 12, b: 13 };
1409 assert_eq!(b.get_bob(a), 12);
1410 };
1411 run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
1412}
1413
1414fn perform_asan_doom_test(into_raw: TokenStream, box_type: TokenStream) {
1415 if std::env::var_os("AUTOCXX_ASAN").is_none() {
1416 return;
1417 }
1418 // Testing that we get an asan fail when it's enabled.
1419 // Really just testing our CI is working to spot ASAN mistakes.
1420 let hdr = indoc! {"
1421 #include <cstddef>
1422 struct A {
1423 int a;
1424 };
1425 inline size_t how_big_is_a() {
1426 return sizeof(A);
1427 }
1428 "};
1429 let rs = quote! {
1430 let a = #box_type::emplace(ffi::A::new());
1431 unsafe {
1432 let a_raw = #into_raw;
1433 // Intentional memory unsafety. Don't @ me.
1434 let a_offset_into_doom = a_raw.offset(ffi::how_big_is_a().try_into().unwrap());
1435 a_offset_into_doom.write_bytes(0x69, 1);
1436 #box_type::from_raw(a_raw); // to delete. If we haven't yet crashed.
1437 }
1438 };
1439 run_test_expect_fail("", hdr, rs, &["A", "how_big_is_a"], &[]);
1440}
1441
1442#[test]
1443fn test_asan_working_as_expected_for_cpp_allocations() {
1444 perform_asan_doom_test(quote! { a.into_raw() }, quote! { UniquePtr })
1445}
1446
1447#[test]
1448fn test_asan_working_as_expected_for_rust_allocations() {
1449 perform_asan_doom_test(
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07001450 quote! { Box::into_raw(core::pin::Pin::into_inner_unchecked(a)) },
Brian Silverman4e662aa2022-05-11 23:10:19 -07001451 quote! { Box },
1452 )
1453}
1454
1455#[test]
1456fn test_inline_method() {
1457 let hdr = indoc! {"
1458 #include <cstdint>
1459 struct Anna {
1460 uint32_t a;
1461 };
1462 struct Bob {
1463 public:
1464 uint32_t a;
1465 uint32_t b;
1466 uint32_t get_bob(Anna) const {
1467 return a;
1468 }
1469 };
1470 "};
1471 let rs = quote! {
1472 let a = ffi::Anna { a: 14 };
1473 let b = ffi::Bob { a: 12, b: 13 };
1474 assert_eq!(b.get_bob(a), 12);
1475 };
1476 run_test("", hdr, rs, &[], &["Bob", "Anna"]);
1477}
1478
1479#[test]
1480fn test_method_pass_pod_by_reference() {
1481 let cxx = indoc! {"
1482 uint32_t Bob::get_bob(const Anna&) const {
1483 return a;
1484 }
1485 "};
1486 let hdr = indoc! {"
1487 #include <cstdint>
1488 struct Anna {
1489 uint32_t a;
1490 };
1491 struct Bob {
1492 public:
1493 uint32_t a;
1494 uint32_t b;
1495 uint32_t get_bob(const Anna& a) const;
1496 };
1497 "};
1498 let rs = quote! {
1499 let a = ffi::Anna { a: 14 };
1500 let b = ffi::Bob { a: 12, b: 13 };
1501 assert_eq!(b.get_bob(&a), 12);
1502 };
1503 run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
1504}
1505
1506#[test]
1507fn test_method_pass_pod_by_mut_reference() {
1508 let cxx = indoc! {"
1509 uint32_t Bob::get_bob(Anna&) const {
1510 return a;
1511 }
1512 "};
1513 let hdr = indoc! {"
1514 #include <cstdint>
1515 struct Anna {
1516 uint32_t a;
1517 };
1518 struct Bob {
1519 public:
1520 uint32_t a;
1521 uint32_t b;
1522 uint32_t get_bob(Anna& a) const;
1523 };
1524 "};
1525 let rs = quote! {
1526 let mut a = Box::pin(ffi::Anna { a: 14 });
1527 let b = ffi::Bob { a: 12, b: 13 };
1528 assert_eq!(b.get_bob(a.as_mut()), 12);
1529 };
1530 run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
1531}
1532
1533#[test]
1534fn test_method_pass_pod_by_up() {
1535 let cxx = indoc! {"
1536 uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
1537 return a;
1538 }
1539 "};
1540 let hdr = indoc! {"
1541 #include <cstdint>
1542 #include <memory>
1543 struct Anna {
1544 uint32_t a;
1545 };
1546 struct Bob {
1547 public:
1548 uint32_t a;
1549 uint32_t b;
1550 uint32_t get_bob(std::unique_ptr<Anna> z) const;
1551 };
1552 "};
1553 let rs = quote! {
1554 let a = ffi::Anna { a: 14 };
1555 let b = ffi::Bob { a: 12, b: 13 };
1556 assert_eq!(b.get_bob(cxx::UniquePtr::new(a)), 12);
1557 };
1558 run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
1559}
1560
1561#[test]
1562fn test_method_pass_nonpod_by_value() {
1563 let cxx = indoc! {"
1564 uint32_t Bob::get_bob(Anna) const {
1565 return a;
1566 }
1567 Anna give_anna() {
1568 Anna a;
1569 a.a = 10;
1570 return a;
1571 }
1572 "};
1573 let hdr = indoc! {"
1574 #include <cstdint>
1575 #include <string>
1576 struct Anna {
1577 uint32_t a;
1578 std::string b;
1579 };
1580 Anna give_anna();
1581 struct Bob {
1582 public:
1583 uint32_t a;
1584 uint32_t b;
1585 uint32_t get_bob(Anna a) const;
1586 };
1587 "};
1588 let rs = quote! {
1589 let a = ffi::give_anna().within_box();
1590 let b = ffi::Bob { a: 12, b: 13 };
1591 assert_eq!(b.get_bob(a), 12);
1592 };
1593 run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
1594}
1595
1596#[test]
1597fn test_pass_two_nonpod_by_value() {
1598 let cxx = indoc! {"
1599 void take_a(A, A) {
1600 }
1601 "};
1602 let hdr = indoc! {"
1603 #include <string>
1604 struct A {
1605 std::string b;
1606 };
1607 void take_a(A, A);
1608 "};
1609 let rs = quote! {
1610 let a = ffi::A::new().within_unique_ptr();
1611 let a2 = ffi::A::new().within_unique_ptr();
1612 ffi::take_a(a, a2);
1613 };
1614 run_test(cxx, hdr, rs, &["A", "take_a"], &[]);
1615}
1616
1617#[test]
1618fn test_issue_931() {
1619 let cxx = "";
1620 let hdr = indoc! {"
1621 namespace a {
1622 struct __cow_string {
1623 __cow_string();
1624 };
1625 class b {
1626 public:
1627 __cow_string c;
1628 };
1629 class j {
1630 public:
1631 b d;
1632 };
1633 template <typename> class e;
1634 } // namespace a
1635 template <typename> struct f {};
1636 namespace llvm {
1637 template <class> class g {
1638 union {
1639 f<a::j> h;
1640 };
1641 };
1642 class MemoryBuffer {
1643 public:
1644 g<a::e<MemoryBuffer>> i;
1645 };
1646 } // namespace llvm
1647 "};
1648 let rs = quote! {};
1649 run_test(cxx, hdr, rs, &["llvm::MemoryBuffer"], &[]);
1650}
1651
1652#[test]
1653fn test_issue_936() {
1654 let cxx = "";
1655 let hdr = indoc! {"
1656 struct a;
1657 class B {
1658 public:
1659 B(a &, bool);
1660 };
1661 "};
1662 let rs = quote! {};
1663 run_test(cxx, hdr, rs, &["B"], &[]);
1664}
1665
1666#[test]
1667fn test_method_pass_nonpod_by_value_with_up() {
1668 // Checks that existing UniquePtr params are not wrecked
1669 // by the conversion we do here.
1670 let cxx = indoc! {"
1671 uint32_t Bob::get_bob(Anna, std::unique_ptr<Anna>) const {
1672 return a;
1673 }
1674 Anna give_anna() {
1675 Anna a;
1676 a.a = 10;
1677 return a;
1678 }
1679 "};
1680 let hdr = indoc! {"
1681 #include <cstdint>
1682 #include <string>
1683 #include <memory>
1684 struct Anna {
1685 uint32_t a;
1686 std::string b;
1687 };
1688 Anna give_anna();
1689 struct Bob {
1690 public:
1691 uint32_t a;
1692 uint32_t b;
1693 uint32_t get_bob(Anna a, std::unique_ptr<Anna>) const;
1694 };
1695 "};
1696 let rs = quote! {
1697 let a = ffi::give_anna().within_unique_ptr();
1698 let a2 = ffi::give_anna().within_unique_ptr();
1699 let b = ffi::Bob { a: 12, b: 13 };
1700 assert_eq!(b.get_bob(a, a2), 12);
1701 };
1702 run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
1703}
1704
1705#[test]
1706fn test_issue_940() {
1707 let cxx = "";
1708 let hdr = indoc! {"
1709 template <class> class b;
1710 template <class = void> struct c;
1711 struct identity;
1712 template <class, class, class e, class> class f {
1713 using g = e;
1714 g h;
1715 };
1716 template <class i, class k = c<>, class l = b<i>>
1717 using j = f<i, identity, k, l>;
1718 class n;
1719 class RenderFrameHost {
1720 public:
1721 virtual void o(const j<n> &);
1722 virtual ~RenderFrameHost() {}
1723 };
1724 "};
1725 let rs = quote! {};
1726 run_test_ex(
1727 cxx,
1728 hdr,
1729 rs,
1730 directives_from_lists(&["RenderFrameHost"], &[], None),
1731 make_cpp17_adder(),
1732 None,
1733 None,
1734 );
1735}
1736
1737#[test]
1738fn test_method_pass_nonpod_by_reference() {
1739 let cxx = indoc! {"
1740 uint32_t Bob::get_bob(const Anna&) const {
1741 return a;
1742 }
1743 Anna give_anna() {
1744 Anna a;
1745 a.a = 10;
1746 return a;
1747 }
1748 "};
1749 let hdr = indoc! {"
1750 #include <cstdint>
1751 #include <string>
1752 struct Anna {
1753 uint32_t a;
1754 std::string b;
1755 };
1756 Anna give_anna();
1757 struct Bob {
1758 public:
1759 uint32_t a;
1760 uint32_t b;
1761 uint32_t get_bob(const Anna& a) const;
1762 };
1763 "};
1764 let rs = quote! {
1765 let a = ffi::give_anna().within_box();
1766 let b = ffi::Bob { a: 12, b: 13 };
1767 assert_eq!(b.get_bob(a.as_ref().get_ref()), 12);
1768 };
1769 run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
1770}
1771
1772#[test]
1773fn test_method_pass_nonpod_by_mut_reference() {
1774 let cxx = indoc! {"
1775 uint32_t Bob::get_bob(Anna&) const {
1776 return a;
1777 }
1778 Anna give_anna() {
1779 Anna a;
1780 a.a = 10;
1781 return a;
1782 }
1783 "};
1784 let hdr = indoc! {"
1785 #include <cstdint>
1786 #include <string>
1787 struct Anna {
1788 uint32_t a;
1789 std::string b;
1790 };
1791 Anna give_anna();
1792 struct Bob {
1793 public:
1794 uint32_t a;
1795 uint32_t b;
1796 uint32_t get_bob(Anna& a) const;
1797 };
1798 "};
1799 let rs = quote! {
1800 let mut a = ffi::give_anna().within_unique_ptr();
1801 let b = ffi::Bob { a: 12, b: 13 };
1802 assert_eq!(b.get_bob(a.as_mut().unwrap()), 12);
1803 };
1804 run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
1805}
1806
1807#[test]
1808fn test_method_pass_nonpod_by_up() {
1809 let cxx = indoc! {"
1810 uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
1811 return a;
1812 }
1813 Anna give_anna() {
1814 Anna a;
1815 a.a = 10;
1816 return a;
1817 }
1818 "};
1819 let hdr = indoc! {"
1820 #include <cstdint>
1821 #include <memory>
1822 #include <string>
1823 struct Anna {
1824 uint32_t a;
1825 std::string b;
1826 };
1827 Anna give_anna();
1828 struct Bob {
1829 public:
1830 uint32_t a;
1831 uint32_t b;
1832 uint32_t get_bob(std::unique_ptr<Anna> z) const;
1833 };
1834 "};
1835 let rs = quote! {
1836 let a = ffi::give_anna().within_unique_ptr();
1837 let b = ffi::Bob { a: 12, b: 13 };
1838 assert_eq!(b.get_bob(a), 12);
1839 };
1840 run_test(cxx, hdr, rs, &["give_anna"], &["Bob"]);
1841}
1842
1843#[test]
1844fn test_method_return_nonpod_by_value() {
1845 let cxx = indoc! {"
1846 Anna Bob::get_anna() const {
1847 Anna a;
1848 a.a = 12;
1849 return a;
1850 }
1851 "};
1852 let hdr = indoc! {"
1853 #include <cstdint>
1854 #include <string>
1855 struct Anna {
1856 uint32_t a;
1857 std::string b;
1858 };
1859 struct Bob {
1860 public:
1861 uint32_t a;
1862 uint32_t b;
1863 Anna get_anna() const;
1864 };
1865 "};
1866 let rs = quote! {
1867 let b = ffi::Bob { a: 12, b: 13 };
1868 let a = b.get_anna().within_unique_ptr();
1869 assert!(!a.is_null());
1870 };
1871 run_test(cxx, hdr, rs, &["Anna"], &["Bob"]);
1872}
1873
1874#[test]
1875fn test_pass_string_by_value() {
1876 let cxx = indoc! {"
1877 uint32_t measure_string(std::string z) {
1878 return z.length();
1879 }
1880 std::unique_ptr<std::string> get_msg() {
1881 return std::make_unique<std::string>(\"hello\");
1882 }
1883 "};
1884 let hdr = indoc! {"
1885 #include <cstdint>
1886 #include <string>
1887 #include <memory>
1888 uint32_t measure_string(std::string a);
1889 std::unique_ptr<std::string> get_msg();
1890 "};
1891 let rs = quote! {
1892 let a = ffi::get_msg();
1893 let c = ffi::measure_string(a);
1894 assert_eq!(c, 5);
1895 };
1896 run_test(cxx, hdr, rs, &["measure_string", "get_msg"], &[]);
1897}
1898
1899#[test]
1900fn test_return_string_by_value() {
1901 let cxx = indoc! {"
1902 std::string get_msg() {
1903 return \"hello\";
1904 }
1905 "};
1906 let hdr = indoc! {"
1907 #include <string>
1908 std::string get_msg();
1909 "};
1910 let rs = quote! {
1911 let a = ffi::get_msg();
1912 assert!(a.as_ref().unwrap() == "hello");
1913 };
1914 run_test(cxx, hdr, rs, &["get_msg"], &[]);
1915}
1916
1917#[test]
1918#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
1919fn test_method_pass_string_by_value() {
1920 let cxx = indoc! {"
1921 uint32_t Bob::measure_string(std::string z) const {
1922 return z.length();
1923 }
1924 std::unique_ptr<std::string> get_msg() {
1925 return std::make_unique<std::string>(\"hello\");
1926 }
1927 "};
1928 let hdr = indoc! {"
1929 #include <cstdint>
1930 #include <string>
1931 #include <memory>
1932 struct Bob {
1933 public:
1934 uint32_t a;
1935 uint32_t b;
1936 uint32_t measure_string(std::string a) const;
1937 };
1938 std::unique_ptr<std::string> get_msg();
1939 "};
1940 let rs = quote! {
1941 let a = ffi::get_msg();
1942 let b = ffi::Bob { a: 12, b: 13 };
1943 let c = b.measure_string(a);
1944 assert_eq!(c, 5);
1945 };
1946 run_test(cxx, hdr, rs, &["Bob", "get_msg"], &["Bob"]);
1947}
1948
1949#[test]
1950fn test_method_return_string_by_value() {
1951 let cxx = indoc! {"
1952 std::string Bob::get_msg() const {
1953 return \"hello\";
1954 }
1955 "};
1956 let hdr = indoc! {"
1957 #include <cstdint>
1958 #include <string>
1959 struct Bob {
1960 public:
1961 uint32_t a;
1962 uint32_t b;
1963 std::string get_msg() const;
1964 };
1965 "};
1966 let rs = quote! {
1967 let b = ffi::Bob { a: 12, b: 13 };
1968 let a = b.get_msg();
1969 assert!(a.as_ref().unwrap() == "hello");
1970 };
1971 run_test(cxx, hdr, rs, &[], &["Bob"]);
1972}
1973
1974#[test]
1975fn test_pass_rust_string_by_ref() {
1976 let cxx = indoc! {"
1977 uint32_t measure_string(const rust::String& z) {
1978 return std::string(z).length();
1979 }
1980 "};
1981 let hdr = indoc! {"
1982 #include <cstdint>
1983 #include <cxx.h>
1984 uint32_t measure_string(const rust::String& z);
1985 "};
1986 let rs = quote! {
1987 let c = ffi::measure_string(&"hello".to_string());
1988 assert_eq!(c, 5);
1989 };
1990 run_test(cxx, hdr, rs, &["measure_string"], &[]);
1991}
1992
1993#[test]
1994fn test_pass_rust_string_by_value() {
1995 let cxx = indoc! {"
1996 uint32_t measure_string(rust::String z) {
1997 return std::string(z).length();
1998 }
1999 "};
2000 let hdr = indoc! {"
2001 #include <cstdint>
2002 #include <cxx.h>
2003 uint32_t measure_string(rust::String z);
2004 "};
2005 let rs = quote! {
2006 let c = ffi::measure_string("hello".into());
2007 assert_eq!(c, 5);
2008 };
2009 run_test(cxx, hdr, rs, &["measure_string"], &[]);
2010}
2011
2012#[test]
2013fn test_pass_rust_str() {
2014 // passing by value is the only legal option
2015 let cxx = indoc! {"
2016 uint32_t measure_string(rust::Str z) {
2017 return std::string(z).length();
2018 }
2019 "};
2020 let hdr = indoc! {"
2021 #include <cstdint>
2022 #include <cxx.h>
2023 uint32_t measure_string(rust::Str z);
2024 "};
2025 let rs = quote! {
2026 let c = ffi::measure_string("hello");
2027 assert_eq!(c, 5);
2028 };
2029 run_test(cxx, hdr, rs, &["measure_string"], &[]);
2030}
2031
2032#[test]
2033fn test_multiple_classes_with_methods() {
2034 let hdr = indoc! {"
2035 #include <cstdint>
2036
2037 struct TrivialStruct {
2038 uint32_t val = 0;
2039
2040 uint32_t get() const;
2041 uint32_t inc();
2042 };
2043 TrivialStruct make_trivial_struct();
2044
2045 class TrivialClass {
2046 public:
2047 uint32_t get() const;
2048 uint32_t inc();
2049
2050 private:
2051 uint32_t val_ = 1;
2052 };
2053 TrivialClass make_trivial_class();
2054
2055 struct OpaqueStruct {
2056 // ~OpaqueStruct();
2057 uint32_t val = 2;
2058
2059 uint32_t get() const;
2060 uint32_t inc();
2061 };
2062 OpaqueStruct make_opaque_struct();
2063
2064 class OpaqueClass {
2065 public:
2066 // ~OpaqueClass();
2067 uint32_t get() const;
2068 uint32_t inc();
2069
2070 private:
2071 uint32_t val_ = 3;
2072 };
2073 OpaqueClass make_opaque_class();
2074 "};
2075 let cxx = indoc! {"
2076 TrivialStruct make_trivial_struct() { return {}; }
2077 TrivialClass make_trivial_class() { return {}; }
2078 OpaqueStruct make_opaque_struct() { return {}; }
2079 OpaqueClass make_opaque_class() { return {}; }
2080
2081 uint32_t TrivialStruct::get() const { return val;}
2082 uint32_t TrivialClass::get() const { return val_; }
2083 uint32_t OpaqueStruct::get() const { return val;}
2084 uint32_t OpaqueClass::get() const { return val_; }
2085
2086 uint32_t TrivialStruct::inc() { return ++val; }
2087 uint32_t TrivialClass::inc() { return ++val_; }
2088 uint32_t OpaqueStruct::inc() { return ++val; }
2089 uint32_t OpaqueClass::inc() { return ++val_; }
2090 "};
2091 let rs = quote! {
2092 use ffi::*;
2093
2094 let mut ts = Box::pin(make_trivial_struct());
2095 assert_eq!(ts.get(), 0);
2096 assert_eq!(ts.as_mut().inc(), 1);
2097 assert_eq!(ts.as_mut().inc(), 2);
2098
2099 let mut tc = Box::pin(make_trivial_class());
2100 assert_eq!(tc.get(), 1);
2101 assert_eq!(tc.as_mut().inc(), 2);
2102 assert_eq!(tc.as_mut().inc(), 3);
2103
2104 let mut os= make_opaque_struct().within_unique_ptr();
2105 assert_eq!(os.get(), 2);
2106 assert_eq!(os.pin_mut().inc(), 3);
2107 assert_eq!(os.pin_mut().inc(), 4);
2108
2109 let mut oc = make_opaque_class().within_unique_ptr();
2110 assert_eq!(oc.get(), 3);
2111 assert_eq!(oc.pin_mut().inc(), 4);
2112 assert_eq!(oc.pin_mut().inc(), 5);
2113 };
2114 run_test(
2115 cxx,
2116 hdr,
2117 rs,
2118 &[
2119 "make_trivial_struct",
2120 "make_trivial_class",
2121 "make_opaque_struct",
2122 "make_opaque_class",
2123 "OpaqueStruct",
2124 "OpaqueClass",
2125 ],
2126 &["TrivialStruct", "TrivialClass"],
2127 );
2128}
2129
2130#[test]
2131fn test_ns_return_struct() {
2132 let cxx = indoc! {"
2133 A::B::Bob give_bob() {
2134 A::B::Bob a;
2135 a.a = 3;
2136 a.b = 4;
2137 return a;
2138 }
2139 "};
2140 let hdr = indoc! {"
2141 #include <cstdint>
2142 namespace A {
2143 namespace B {
2144 struct Bob {
2145 uint32_t a;
2146 uint32_t b;
2147 };
2148 }
2149 }
2150 A::B::Bob give_bob();
2151 "};
2152 let rs = quote! {
2153 assert_eq!(ffi::give_bob().b, 4);
2154 };
2155 run_test(cxx, hdr, rs, &["give_bob"], &["A::B::Bob"]);
2156}
2157
2158#[test]
2159fn test_ns_take_struct() {
2160 let cxx = indoc! {"
2161 uint32_t take_bob(A::B::Bob a) {
2162 return a.a;
2163 }
2164 "};
2165 let hdr = indoc! {"
2166 #include <cstdint>
2167 namespace A {
2168 namespace B {
2169 struct Bob {
2170 uint32_t a;
2171 uint32_t b;
2172 };
2173 }
2174 }
2175 uint32_t take_bob(A::B::Bob a);
2176 "};
2177 let rs = quote! {
2178 let a = ffi::A::B::Bob { a: 12, b: 13 };
2179 assert_eq!(ffi::take_bob(a), 12);
2180 };
2181 run_test(cxx, hdr, rs, &["take_bob"], &["A::B::Bob"]);
2182}
2183
2184#[test]
2185fn test_ns_func() {
2186 let cxx = indoc! {"
2187 using namespace C;
2188 A::B::Bob C::give_bob() {
2189 A::B::Bob a;
2190 a.a = 3;
2191 a.b = 4;
2192 return a;
2193 }
2194 "};
2195 let hdr = indoc! {"
2196 #include <cstdint>
2197 namespace A {
2198 namespace B {
2199 struct Bob {
2200 uint32_t a;
2201 uint32_t b;
2202 };
2203 }
2204 }
2205 namespace C {
2206 ::A::B::Bob give_bob();
2207 }
2208 "};
2209 let rs = quote! {
2210 assert_eq!(ffi::C::give_bob().b, 4);
2211 };
2212 run_test(cxx, hdr, rs, &["C::give_bob"], &["A::B::Bob"]);
2213}
2214
2215#[test]
2216fn test_overload_constructors() {
2217 let cxx = indoc! {"
2218 Bob::Bob() {}
2219 Bob::Bob(uint32_t _a) :a(_a) {}
2220 "};
2221 let hdr = indoc! {"
2222 #include <cstdint>
2223 #include <memory>
2224 struct Bob {
2225 Bob();
2226 Bob(uint32_t a);
2227 uint32_t a;
2228 uint32_t b;
2229 };
2230 "};
2231 let rs = quote! {
2232 ffi::Bob::new().within_unique_ptr();
2233 ffi::Bob::new1(32).within_unique_ptr();
2234 };
2235 run_test(cxx, hdr, rs, &["Bob"], &[]);
2236}
2237
2238#[test]
2239fn test_overload_functions() {
2240 let cxx = indoc! {"
2241 void daft(uint32_t) {}
2242 void daft(uint8_t) {}
2243 void daft(std::string) {}
2244 void daft(Fred) {}
2245 void daft(Norma) {}
2246 "};
2247 let hdr = indoc! {"
2248 #include <cstdint>
2249 #include <string>
2250 struct Fred {
2251 uint32_t a;
2252 };
2253 struct Norma {
2254 Norma() {}
2255 uint32_t a;
2256 };
2257 void daft(uint32_t);
2258 void daft(uint8_t);
2259 void daft(std::string);
2260 void daft(Fred);
2261 void daft(Norma);
2262 "};
2263 let rs = quote! {
2264 use ffi::ToCppString;
2265 ffi::daft(32);
2266 ffi::daft1(8);
2267 ffi::daft2("hello".into_cpp());
2268 let b = ffi::Fred { a: 3 };
2269 ffi::daft3(b);
2270 let c = ffi::Norma::new().within_unique_ptr();
2271 ffi::daft4(c);
2272 };
2273 run_test(
2274 cxx,
2275 hdr,
2276 rs,
2277 &["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
2278 &["Fred"],
2279 );
2280}
2281
2282#[test]
2283#[ignore] // At present, bindgen generates two separate 'daft1'
2284 // functions here, and there's not much we can do about that.
2285fn test_overload_numeric_functions() {
2286 // Because bindgen deals with conflicting overloaded functions by
2287 // appending a numeric suffix, let's see if we can cope.
2288 let cxx = indoc! {"
2289 void daft1(uint32_t) {}
2290 void daft2(uint8_t) {}
2291 void daft(std::string) {}
2292 void daft(Fred) {}
2293 void daft(Norma) {}
2294 "};
2295 let hdr = indoc! {"
2296 #include <cstdint>
2297 #include <string>
2298 struct Fred {
2299 uint32_t a;
2300 };
2301 struct Norma {
2302 uint32_t a;
2303 };
2304 void daft1(uint32_t a);
2305 void daft2(uint8_t a);
2306 void daft(std::string a);
2307 void daft(Fred a);
2308 void daft(Norma a);
2309 "};
2310 let rs = quote! {
2311 use ffi::ToCppString;
2312 ffi::daft(32);
2313 ffi::daft1(8);
2314 ffi::daft2("hello".into_cpp());
2315 let b = ffi::Fred { a: 3 };
2316 ffi::daft3(b);
2317 let c = ffi::Norma::new().within_unique_ptr();
2318 ffi::daft4(c);
2319 };
2320 run_test(
2321 cxx,
2322 hdr,
2323 rs,
2324 &["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
2325 &["Fred"],
2326 );
2327}
2328
2329#[test]
2330fn test_overload_methods() {
2331 let cxx = indoc! {"
2332 void Bob::daft(uint32_t) const {}
2333 void Bob::daft(uint8_t) const {}
2334 void Bob::daft(std::string) const {}
2335 void Bob::daft(Fred) const {}
2336 void Bob::daft(Norma) const {}
2337 "};
2338 let hdr = indoc! {"
2339 #include <cstdint>
2340 #include <string>
2341 struct Fred {
2342 uint32_t a;
2343 };
2344 struct Norma {
2345 Norma() {}
2346 uint32_t a;
2347 };
2348 struct Bob {
2349 uint32_t a;
2350 void daft(uint32_t) const;
2351 void daft(uint8_t) const;
2352 void daft(std::string) const;
2353 void daft(Fred) const;
2354 void daft(Norma) const;
2355 };
2356 "};
2357 let rs = quote! {
2358 use ffi::ToCppString;
2359 let a = ffi::Bob { a: 12 };
2360 a.daft(32);
2361 a.daft1(8);
2362 a.daft2("hello".into_cpp());
2363 let b = ffi::Fred { a: 3 };
2364 a.daft3(b);
2365 let c = ffi::Norma::new().within_unique_ptr();
2366 a.daft4(c);
2367 };
2368 run_test(cxx, hdr, rs, &["Norma"], &["Fred", "Bob"]);
2369}
2370
2371#[test]
2372fn test_ns_constructor() {
2373 let cxx = indoc! {"
2374 A::Bob::Bob() {}
2375 "};
2376 let hdr = indoc! {"
2377 #include <cstdint>
2378 #include <memory>
2379 namespace A {
2380 struct Bob {
2381 Bob();
2382 uint32_t a;
2383 uint32_t b;
2384 };
2385 }
2386 "};
2387 let rs = quote! {
2388 ffi::A::Bob::new().within_unique_ptr();
2389 };
2390 run_test(cxx, hdr, rs, &["A::Bob"], &[]);
2391}
2392
2393#[test]
2394fn test_ns_up_direct() {
2395 let cxx = indoc! {"
2396 std::unique_ptr<A::Bob> A::get_bob() {
2397 A::Bob b;
2398 b.a = 2;
2399 b.b = 3;
2400 return std::make_unique<A::Bob>(b);
2401 }
2402 uint32_t give_bob(A::Bob bob) {
2403 return bob.a;
2404 }
2405 "};
2406 let hdr = indoc! {"
2407 #include <cstdint>
2408 #include <memory>
2409 namespace A {
2410 struct Bob {
2411 uint32_t a;
2412 uint32_t b;
2413 };
2414 std::unique_ptr<Bob> get_bob();
2415 }
2416 uint32_t give_bob(A::Bob bob);
2417 "};
2418 let rs = quote! {
2419 assert_eq!(ffi::give_bob(ffi::A::get_bob()), 2);
2420 };
2421 run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
2422}
2423
2424#[test]
2425fn test_ns_up_wrappers() {
2426 let cxx = indoc! {"
2427 A::Bob get_bob() {
2428 A::Bob b;
2429 b.a = 2;
2430 b.b = 3;
2431 return b;
2432 }
2433 uint32_t give_bob(A::Bob bob) {
2434 return bob.a;
2435 }
2436 "};
2437 let hdr = indoc! {"
2438 #include <cstdint>
2439 namespace A {
2440 struct Bob {
2441 uint32_t a;
2442 uint32_t b;
2443 };
2444 }
2445 A::Bob get_bob();
2446 uint32_t give_bob(A::Bob bob);
2447 "};
2448 let rs = quote! {
2449 assert_eq!(ffi::give_bob(as_new(ffi::get_bob())), 2);
2450 };
2451 run_test(cxx, hdr, rs, &["give_bob", "get_bob"], &[]);
2452}
2453
2454#[test]
2455fn test_ns_up_wrappers_in_up() {
2456 let cxx = indoc! {"
2457 A::Bob A::get_bob() {
2458 A::Bob b;
2459 b.a = 2;
2460 b.b = 3;
2461 return b;
2462 }
2463 uint32_t give_bob(A::Bob bob) {
2464 return bob.a;
2465 }
2466 "};
2467 let hdr = indoc! {"
2468 #include <cstdint>
2469 namespace A {
2470 struct Bob {
2471 uint32_t a;
2472 uint32_t b;
2473 };
2474 Bob get_bob();
2475 }
2476 uint32_t give_bob(A::Bob bob);
2477 "};
2478 let rs = quote! {
2479 assert_eq!(ffi::give_bob(as_new(ffi::A::get_bob())), 2);
2480 };
2481 run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
2482}
2483
2484#[test]
2485fn test_return_reference() {
2486 let cxx = indoc! {"
2487 const Bob& give_bob(const Bob& input_bob) {
2488 return input_bob;
2489 }
2490 "};
2491 let hdr = indoc! {"
2492 #include <cstdint>
2493 struct Bob {
2494 uint32_t a;
2495 uint32_t b;
2496 };
2497 const Bob& give_bob(const Bob& input_bob);
2498 "};
2499 let rs = quote! {
2500 let b = ffi::Bob { a: 3, b: 4 };
2501 assert_eq!(ffi::give_bob(&b).b, 4);
2502 };
2503 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
2504}
2505
2506#[test]
2507fn test_return_reference_non_pod() {
2508 let cxx = indoc! {"
2509 const Bob& give_bob(const Bob& input_bob) {
2510 return input_bob;
2511 }
2512 "};
2513 let hdr = indoc! {"
2514 #include <cstdint>
2515 struct Bob {
2516 uint32_t a;
2517 uint32_t b;
2518 };
2519 namespace A {
2520 void give_bob(); // force wrapper generation
2521 }
2522 const Bob& give_bob(const Bob& input_bob);
2523 "};
2524 let rs = quote! {};
2525 run_test(cxx, hdr, rs, &["give_bob", "Bob", "A::give_bob"], &[]);
2526}
2527
2528#[test]
2529fn test_return_reference_non_pod_string() {
2530 let cxx = indoc! {"
2531 const std::string& give_bob(const Bob& input_bob) {
2532 return input_bob.a;
2533 }
2534 "};
2535 let hdr = indoc! {"
2536 #include <string>
2537 struct Bob {
2538 std::string a;
2539 };
2540 // namespace A {
2541 // void give_bob(); // force wrapper generation
2542 // }
2543 const std::string& give_bob(const Bob& input_bob);
2544 "};
2545 let rs = quote! {};
2546 run_test(cxx, hdr, rs, &["give_bob", "Bob"], &[]);
2547}
2548
2549#[test]
2550fn test_member_return_reference() {
2551 let hdr = indoc! {"
2552 #include <string>
2553 class A {
2554 public:
2555 virtual const std::string& get_str() { return a; }
2556 virtual ~A() {}
2557 std::string a;
2558 };
2559 "};
2560 let rs = quote! {
2561 let mut b = ffi::A::new().within_unique_ptr();
2562 b.pin_mut().get_str();
2563 };
2564 run_test("", hdr, rs, &["A"], &[]);
2565}
2566
2567#[test]
2568fn test_destructor() {
2569 let hdr = indoc! {"
2570 struct WithDtor {
2571 ~WithDtor();
2572 };
2573 WithDtor make_with_dtor();
2574 "};
2575 let cxx = indoc! {"
2576 WithDtor::~WithDtor() {}
2577 WithDtor make_with_dtor() {
2578 return {};
2579 }
2580 "};
2581 let rs = quote! {
2582 use ffi::*;
2583 let with_dtor: cxx::UniquePtr<WithDtor> = make_with_dtor().within_unique_ptr();
2584 drop(with_dtor);
2585 };
2586 run_test(cxx, hdr, rs, &["WithDtor", "make_with_dtor"], &[]);
2587}
2588
2589#[test]
2590fn test_nested_with_destructor() {
2591 // Regression test, naming the destructor in the generated C++ is a bit tricky.
2592 let hdr = indoc! {"
2593 struct A {
2594 struct B {
2595 B() = default;
2596 ~B() = default;
2597 };
2598 };
2599 "};
2600 let rs = quote! {
2601 ffi::A_B::new().within_unique_ptr();
2602 };
2603 run_test("", hdr, rs, &["A", "A_B"], &[]);
2604}
2605
2606// Even without a `safety!`, we still need to generate a safe `fn drop`.
2607#[test]
2608fn test_destructor_no_safety() {
2609 let hdr = indoc! {"
2610 struct WithDtor {
2611 ~WithDtor();
2612 };
2613 "};
2614 let cxx = indoc! {"
2615 WithDtor::~WithDtor() {}
2616 "};
2617 let hexathorpe = Token![#](Span::call_site());
2618 let unexpanded_rust = quote! {
2619 use autocxx::prelude::*;
2620
2621 include_cpp!(
2622 #hexathorpe include "input.h"
2623 generate!("WithDtor")
2624 );
2625
2626 fn main() {}
2627 };
2628
2629 do_run_test_manual(cxx, hdr, unexpanded_rust, None, None).unwrap();
2630}
2631
2632#[test]
2633fn test_static_func() {
2634 let hdr = indoc! {"
2635 #include <cstdint>
2636 struct WithStaticMethod {
2637 static uint32_t call();
2638 };
2639 "};
2640 let cxx = indoc! {"
2641 uint32_t WithStaticMethod::call() {
2642 return 42;
2643 }
2644 "};
2645 let rs = quote! {
2646 assert_eq!(ffi::WithStaticMethod::call(), 42);
2647 };
2648 run_test(cxx, hdr, rs, &["WithStaticMethod"], &[]);
2649}
2650
2651#[test]
2652fn test_static_func_wrapper() {
2653 let hdr = indoc! {"
2654 #include <cstdint>
2655 #include <string>
2656 struct A {
2657 std::string a;
2658 static A CreateA(std::string a, std::string) {
2659 A c;
2660 c.a = a;
2661 return c;
2662 }
2663 };
2664 "};
2665 let rs = quote! {
2666 use ffi::ToCppString;
2667 ffi::A::CreateA("a".into_cpp(), "b".into_cpp());
2668 };
2669 run_test("", hdr, rs, &["A"], &[]);
2670}
2671
2672#[test]
2673fn test_give_pod_typedef_by_value() {
2674 let cxx = indoc! {"
2675 Horace give_bob() {
2676 Horace a;
2677 a.a = 3;
2678 a.b = 4;
2679 return a;
2680 }
2681 "};
2682 let hdr = indoc! {"
2683 #include <cstdint>
2684 struct Bob {
2685 uint32_t a;
2686 uint32_t b;
2687 };
2688 using Horace = Bob;
2689 Horace give_bob();
2690 "};
2691 let rs = quote! {
2692 assert_eq!(ffi::give_bob().b, 4);
2693 };
2694 run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
2695}
2696
2697#[ignore] // because we need to put some aliases in the output ffi mod.
2698#[test]
2699fn test_use_pod_typedef() {
2700 let cxx = indoc! {"
2701 "};
2702 let hdr = indoc! {"
2703 #include <cstdint>
2704 struct Bob {
2705 uint32_t a;
2706 uint32_t b;
2707 };
2708 using Horace = Bob;
2709 "};
2710 let rs = quote! {
2711 let h = Horace { a: 3, b: 4 };
2712 assert_eq!(h.b, 4);
2713 };
2714 run_test(cxx, hdr, rs, &[], &["Bob"]);
2715}
2716
2717#[test]
2718fn test_typedef_to_ns() {
2719 let hdr = indoc! {"
2720 #include <cstdint>
2721 namespace A {
2722 template<typename T>
2723 struct C {
2724 T* t;
2725 };
2726 typedef C<char> B;
2727 }
2728 "};
2729 let rs = quote! {};
2730 run_test("", hdr, rs, &["A::B"], &[]);
2731}
2732
2733#[ignore] // we don't yet allow typedefs to be listed in allow_pod
2734#[test]
2735fn test_use_pod_typedef_with_allowpod() {
2736 let cxx = indoc! {"
2737 "};
2738 let hdr = indoc! {"
2739 #include <cstdint>
2740 struct Bob {
2741 uint32_t a;
2742 uint32_t b;
2743 };
2744 using Horace = Bob;
2745 "};
2746 let rs = quote! {
2747 let h = Horace { a: 3, b: 4 };
2748 assert_eq!(h.b, 4);
2749 };
2750 run_test(cxx, hdr, rs, &[], &["Horace"]);
2751}
2752
2753#[test]
2754fn test_give_nonpod_typedef_by_value() {
2755 let cxx = indoc! {"
2756 Horace give_bob() {
2757 Horace a;
2758 a.a = 3;
2759 a.b = 4;
2760 return a;
2761 }
2762 "};
2763 let hdr = indoc! {"
2764 #include <cstdint>
2765 struct Bob {
2766 uint32_t a;
2767 uint32_t b;
2768 };
2769 using Horace = Bob;
2770 Horace give_bob();
2771 inline uint32_t take_horace(const Horace& horace) { return horace.b; }
2772 "};
2773 let rs = quote! {
2774 assert_eq!(ffi::take_horace(&moveit!(ffi::give_bob())), 4);
2775 };
2776 run_test(cxx, hdr, rs, &["give_bob", "take_horace"], &[]);
2777}
2778
2779#[test]
2780fn test_conflicting_static_functions() {
2781 let cxx = indoc! {"
2782 Bob Bob::create() { Bob a; return a; }
2783 Fred Fred::create() { Fred b; return b; }
2784 "};
2785 let hdr = indoc! {"
2786 #include <cstdint>
2787 struct Bob {
2788 Bob() : a(0) {}
2789 uint32_t a;
2790 static Bob create();
2791 };
2792 struct Fred {
2793 Fred() : b(0) {}
2794 uint32_t b;
2795 static Fred create();
2796 };
2797 "};
2798 let rs = quote! {
2799 ffi::Bob::create();
2800 ffi::Fred::create();
2801 };
2802 run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
2803}
2804
2805#[test]
2806fn test_conflicting_ns_up_functions() {
2807 let cxx = indoc! {"
2808 uint32_t A::create(C) { return 3; }
2809 uint32_t B::create(C) { return 4; }
2810 "};
2811 let hdr = indoc! {"
2812 #include <cstdint>
2813 struct C {
2814 C() {}
2815 uint32_t a;
2816 };
2817 namespace A {
2818 uint32_t create(C c);
2819 };
2820 namespace B {
2821 uint32_t create(C c);
2822 };
2823 "};
2824 let rs = quote! {
2825 let c = ffi::C::new().within_unique_ptr();
2826 let c2 = ffi::C::new().within_unique_ptr();
2827 assert_eq!(ffi::A::create(c), 3);
2828 assert_eq!(ffi::B::create(c2), 4);
2829 };
2830 run_test(cxx, hdr, rs, &["A::create", "B::create", "C"], &[]);
2831}
2832
2833#[test]
2834fn test_conflicting_methods() {
2835 let cxx = indoc! {"
2836 uint32_t Bob::get() const { return a; }
2837 uint32_t Fred::get() const { return b; }
2838 "};
2839 let hdr = indoc! {"
2840 #include <cstdint>
2841 struct Bob {
2842 uint32_t a;
2843 uint32_t get() const;
2844 };
2845 struct Fred {
2846 uint32_t b;
2847 uint32_t get() const;
2848 };
2849 "};
2850 let rs = quote! {
2851 let a = ffi::Bob { a: 10 };
2852 let b = ffi::Fred { b: 20 };
2853 assert_eq!(a.get(), 10);
2854 assert_eq!(b.get(), 20);
2855 };
2856 run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
2857}
2858
2859#[test]
2860// There's a bindgen bug here. bindgen generates
2861// functions called 'get' and 'get1' but then generates impl
2862// blocks which call 'get' and 'get'. By luck, we currently
2863// should not be broken by this, but at some point we should take
2864// the time to create a minimal bindgen test case and submit it
2865// as a bindgen bug.
2866fn test_conflicting_up_wrapper_methods_not_in_ns() {
2867 // Ensures the two names 'get' do not conflict in the flat
2868 // cxx::bridge mod namespace.
2869 let cxx = indoc! {"
2870 Bob::Bob() : a(\"hello\") {}
2871 Fred::Fred() : b(\"goodbye\") {}
2872 std::string Bob::get() const { return a; }
2873 std::string Fred::get() const { return b; }
2874 "};
2875 let hdr = indoc! {"
2876 #include <cstdint>
2877 #include <string>
2878 struct Bob {
2879 Bob();
2880 std::string a;
2881 std::string get() const;
2882 };
2883 struct Fred {
2884 Fred();
2885 std::string b;
2886 std::string get() const;
2887 };
2888 "};
2889 let rs = quote! {
2890 let a = ffi::Bob::new().within_unique_ptr();
2891 let b = ffi::Fred::new().within_unique_ptr();
2892 assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
2893 assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
2894 };
2895 run_test(cxx, hdr, rs, &["Bob", "Fred"], &[]);
2896}
2897
2898#[test]
2899fn test_conflicting_methods_in_ns() {
2900 let cxx = indoc! {"
2901 uint32_t A::Bob::get() const { return a; }
2902 uint32_t B::Fred::get() const { return b; }
2903 "};
2904 let hdr = indoc! {"
2905 #include <cstdint>
2906 namespace A {
2907 struct Bob {
2908 uint32_t a;
2909 uint32_t get() const;
2910 };
2911 }
2912 namespace B {
2913 struct Fred {
2914 uint32_t b;
2915 uint32_t get() const;
2916 };
2917 }
2918 "};
2919 let rs = quote! {
2920 let a = ffi::A::Bob { a: 10 };
2921 let b = ffi::B::Fred { b: 20 };
2922 assert_eq!(a.get(), 10);
2923 assert_eq!(b.get(), 20);
2924 };
2925 run_test(cxx, hdr, rs, &[], &["A::Bob", "B::Fred"]);
2926}
2927
2928#[test]
2929fn test_conflicting_up_wrapper_methods_in_ns() {
2930 let cxx = indoc! {"
2931 A::Bob::Bob() : a(\"hello\") {}
2932 B::Fred::Fred() : b(\"goodbye\") {}
2933 std::string A::Bob::get() const { return a; }
2934 std::string B::Fred::get() const { return b; }
2935 "};
2936 let hdr = indoc! {"
2937 #include <cstdint>
2938 #include <string>
2939 namespace A {
2940 struct Bob {
2941 Bob();
2942 std::string a;
2943 std::string get() const;
2944 };
2945 }
2946 namespace B {
2947 struct Fred {
2948 Fred();
2949 std::string b;
2950 std::string get() const;
2951 };
2952 }
2953 "};
2954 let rs = quote! {
2955 let a = ffi::A::Bob::new().within_unique_ptr();
2956 let b = ffi::B::Fred::new().within_unique_ptr();
2957 assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
2958 assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
2959 };
2960 run_test(cxx, hdr, rs, &["A::Bob", "B::Fred"], &[]);
2961}
2962
2963#[test]
2964fn test_ns_struct_pod_request() {
2965 let hdr = indoc! {"
2966 #include <cstdint>
2967 namespace A {
2968 struct Bob {
2969 uint32_t a;
2970 };
2971 }
2972 "};
2973 let rs = quote! {
2974 ffi::A::Bob { a: 12 };
2975 };
2976 run_test("", hdr, rs, &[], &["A::Bob"]);
2977}
2978
2979#[test]
2980fn test_conflicting_ns_funcs() {
2981 let cxx = indoc! {"
2982 uint32_t A::get() { return 10; }
2983 uint32_t B::get() { return 20; }
2984 "};
2985 let hdr = indoc! {"
2986 #include <cstdint>
2987 namespace A {
2988 uint32_t get();
2989 }
2990 namespace B {
2991 uint32_t get();
2992 }
2993 "};
2994 let rs = quote! {
2995 assert_eq!(ffi::A::get(), 10);
2996 assert_eq!(ffi::B::get(), 20);
2997 };
2998 run_test(cxx, hdr, rs, &["A::get", "B::get"], &[]);
2999}
3000
3001#[ignore]
3002// because currently we feed a flat namespace to cxx
3003// This would be relatively easy to enable now that we have the facility
3004// to add aliases to the 'use' statements we generate, plus
3005// bridge_name_tracker to pick a unique name. TODO.
3006#[test]
3007fn test_conflicting_ns_structs() {
3008 let hdr = indoc! {"
3009 #include <cstdint>
3010 namespace A {
3011 struct Bob {
3012 uint32_t a;
3013 };
3014 }
3015 namespace B {
3016 struct Bob {
3017 uint32_t a;
3018 };
3019 }
3020 "};
3021 let rs = quote! {
3022 ffi::A::Bob { a: 12 };
3023 ffi::B::Bob { b: 12 };
3024 };
3025 run_test("", hdr, rs, &[], &["A::Bob", "B::Bob"]);
3026}
3027
3028#[test]
3029fn test_make_string() {
3030 let hdr = indoc! {"
3031 #include <cstdint>
3032 struct Bob {
3033 uint32_t a;
3034 };
3035 "};
3036 let rs = quote! {
3037 use ffi::ToCppString;
3038 let a = "hello".into_cpp();
3039 assert_eq!(a.to_str().unwrap(), "hello");
3040 };
3041 run_test("", hdr, rs, &["Bob"], &[]);
3042}
3043
3044#[test]
3045fn test_string_make_unique() {
3046 let hdr = indoc! {"
3047 #include <string>
3048 inline void take_string(const std::string*) {};
3049 "};
3050 let rs = quote! {
3051 let s = ffi::make_string("");
3052 unsafe { ffi::take_string(s.as_ref().unwrap()) };
3053 };
3054 run_test("", hdr, rs, &["take_string"], &[]);
3055}
3056
3057#[test]
3058fn test_string_constant() {
3059 let hdr = indoc! {"
3060 #include <cstdint>
3061 const char* STRING = \"Foo\";
3062 "};
3063 let rs = quote! {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07003064 let a = core::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
Brian Silverman4e662aa2022-05-11 23:10:19 -07003065 assert_eq!(a, "Foo");
3066 };
3067 run_test("", hdr, rs, &["STRING"], &[]);
3068}
3069
3070#[test]
3071fn test_string_let_cxx_string() {
3072 let hdr = indoc! {"
3073 #include <string>
3074 inline void take_string(const std::string&) {};
3075 "};
3076 let rs = quote! {
3077 autocxx::cxx::let_cxx_string!(s = "hello");
3078 ffi::take_string(&s);
3079 };
3080 run_test("", hdr, rs, &["take_string"], &[]);
3081}
3082
3083#[test]
3084fn test_pod_constant_harmless_inside_type() {
3085 // Check that the presence of this constant doesn't break anything.
3086 let hdr = indoc! {"
3087 #include <cstdint>
3088 struct Bob {
3089 uint32_t a;
3090 };
3091 struct Anna {
3092 uint32_t a;
3093 const Bob BOB = Bob { 10 };
3094 };
3095 "};
3096 let rs = quote! {};
3097 run_test("", hdr, rs, &[], &["Anna"]);
3098}
3099
3100#[test]
3101#[ignore] // https://github.com/google/autocxx/issues/93
3102fn test_pod_constant() {
3103 let hdr = indoc! {"
3104 #include <cstdint>
3105 struct Bob {
3106 uint32_t a;
3107 };
3108 const Bob BOB = Bob { 10 };
3109 "};
3110 let rs = quote! {
3111 let a = &ffi::BOB;
3112 assert_eq!(a.a, 10);
3113 };
3114 run_test("", hdr, rs, &["BOB"], &["Bob"]);
3115}
3116
3117#[test]
3118fn test_pod_static_harmless_inside_type() {
3119 // Check that the presence of this constant doesn't break anything.
3120 // Remove this test when the following one is enabled.
3121 let hdr = indoc! {"
3122 #include <cstdint>
3123 struct Bob {
3124 uint32_t a;
3125 };
3126 struct Anna {
3127 uint32_t a;
3128 static Bob BOB;
3129 };
3130 Bob Anna::BOB = Bob { 10 };
3131 "};
3132 let rs = quote! {};
3133 run_test("", hdr, rs, &[], &["Anna"]);
3134}
3135
3136#[test]
3137#[ignore] // https://github.com/google/autocxx/issues/93
3138fn test_pod_static() {
3139 let hdr = indoc! {"
3140 #include <cstdint>
3141 struct Bob {
3142 uint32_t a;
3143 };
3144 static Bob BOB = Bob { 10 };
3145 "};
3146 let rs = quote! {
3147 let a = &ffi::BOB;
3148 assert_eq!(a.a, 10);
3149 };
3150 run_test("", hdr, rs, &["BOB"], &["Bob"]);
3151}
3152
3153#[test]
3154#[ignore] // this probably requires code generation on the C++
3155 // side. It's not at all clear how best to handle this.
3156fn test_non_pod_constant() {
3157 let hdr = indoc! {"
3158 #include <cstdint>
3159 #include <string>
3160 struct Bob {
3161 std::string a;
3162 std::string get() { return a };
3163 };
3164 const Bob BOB = Bob { \"hello\" };
3165 "};
3166 let rs = quote! {
3167 let a = ffi::BOB;
3168 // following line assumes that 'a' is a &Bob
3169 // but who knows how we'll really do this.
3170 assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
3171 };
3172 run_test("", hdr, rs, &["BOB"], &[]);
3173}
3174
3175#[test]
3176fn test_templated_typedef() {
3177 let hdr = indoc! {"
3178 #include <string>
3179 #include <cstdint>
3180
3181 template <typename STRING_TYPE> class BasicStringPiece {
3182 public:
3183 const STRING_TYPE* ptr_;
3184 size_t length_;
3185 };
3186 typedef BasicStringPiece<uint8_t> StringPiece;
3187
3188 struct Origin {
3189 Origin() {}
3190 StringPiece host;
3191 };
3192 "};
3193 let rs = quote! {
3194 ffi::Origin::new().within_unique_ptr();
3195 };
3196 run_test("", hdr, rs, &["Origin"], &[]);
3197}
3198
3199#[test]
3200fn test_struct_templated_typedef() {
3201 let hdr = indoc! {"
3202 #include <string>
3203 #include <cstdint>
3204
3205 struct Concrete {
3206 uint8_t a;
3207 };
3208 template <typename STRING_TYPE> class BasicStringPiece {
3209 public:
3210 const STRING_TYPE* ptr_;
3211 size_t length_;
3212 };
3213 typedef BasicStringPiece<Concrete> StringPiece;
3214
3215 struct Origin {
3216 Origin() {}
3217 StringPiece host;
3218 };
3219 "};
3220 let rs = quote! {
3221 ffi::Origin::new().within_unique_ptr();
3222 };
3223 run_test("", hdr, rs, &["Origin"], &[]);
3224}
3225
3226#[test]
3227fn test_enum_typedef() {
3228 let hdr = indoc! {"
3229 enum ConstraintSolverParameters_TrailCompression : int {
3230 ConstraintSolverParameters_TrailCompression_NO_COMPRESSION = 0,
3231 ConstraintSolverParameters_TrailCompression_COMPRESS_WITH_ZLIB = 1
3232 };
3233 typedef ConstraintSolverParameters_TrailCompression TrailCompression;
3234 "};
3235 let rs = quote! {
3236 let _ = ffi::TrailCompression::ConstraintSolverParameters_TrailCompression_NO_COMPRESSION;
3237 };
3238 run_test("", hdr, rs, &["TrailCompression"], &[]);
3239}
3240
3241#[test]
3242#[ignore] // https://github.com/google/autocxx/issues/264
3243fn test_conflicting_usings() {
3244 let hdr = indoc! {"
3245 #include <cstdint>
3246 #include <cstddef>
3247 typedef size_t diff;
3248 struct A {
3249 using diff = diff;
3250 diff a;
3251 };
3252 struct B {
3253 using diff = diff;
3254 diff a;
3255 };
3256 "};
3257 let rs = quote! {};
3258 run_test("", hdr, rs, &[], &["A", "B"]);
3259}
3260
3261#[test]
3262fn test_conflicting_usings_with_self_declaration1() {
3263 let hdr = indoc! {"
3264 #include <cstdint>
3265 #include <cstddef>
3266 struct common_params {
3267 using difference_type = ptrdiff_t;
3268 };
3269 template <typename Params>
3270 class btree_node {
3271 public:
3272 using difference_type = typename Params::difference_type;
3273 Params params;
3274 };
3275 template <typename Tree>
3276 class btree_container {
3277 public:
3278 using difference_type = typename Tree::difference_type;
3279 void clear() {}
3280 Tree b;
3281 uint32_t a;
3282 };
3283 typedef btree_container<btree_node<common_params>> my_tree;
3284 "};
3285 let rs = quote! {};
3286 run_test("", hdr, rs, &["my_tree"], &[]);
3287}
3288
3289#[test]
3290#[ignore] // https://github.com/google/autocxx/issues/106
3291fn test_string_templated_typedef() {
3292 let hdr = indoc! {"
3293 #include <string>
3294 #include <cstdint>
3295
3296 template <typename STRING_TYPE> class BasicStringPiece {
3297 public:
3298 const STRING_TYPE* ptr_;
3299 size_t length_;
3300 };
3301 typedef BasicStringPiece<std::string> StringPiece;
3302
3303 struct Origin {
3304 Origin() {}
3305 StringPiece host;
3306 };
3307 "};
3308 let rs = quote! {
3309 ffi::Origin::new().within_unique_ptr();
3310 };
3311 run_test("", hdr, rs, &["Origin"], &[]);
3312}
3313
3314#[test]
3315fn test_associated_type_problem() {
3316 // Regression test for a potential bindgen bug
3317 let hdr = indoc! {"
3318 namespace a {
3319 template <typename> class b {};
3320 } // namespace a
3321 class bl {
3322 public:
3323 a::b<bl> bm;
3324 };
3325 struct B {
3326 int a;
3327 };
3328 "};
3329 let rs = quote! {};
3330 run_test("", hdr, rs, &["B"], &[]);
3331}
3332
3333#[test]
3334fn test_two_type_constructors() {
3335 // https://github.com/google/autocxx/issues/877
3336 let hdr = indoc! {"
3337 struct A {
3338 int a;
3339 };
3340 struct B {
3341 int B;
3342 };
3343 "};
3344 let rs = quote! {};
3345 run_test("", hdr, rs, &["A", "B"], &[]);
3346}
3347
3348#[ignore] // https://github.com/rust-lang/rust-bindgen/issues/1924
3349#[test]
3350fn test_associated_type_templated_typedef_in_struct() {
3351 let hdr = indoc! {"
3352 #include <string>
3353 #include <cstdint>
3354
3355 template <typename STRING_TYPE> class BasicStringPiece {
3356 public:
3357 typedef size_t size_type;
3358 typedef typename STRING_TYPE::value_type value_type;
3359 const value_type* ptr_;
3360 size_type length_;
3361 };
3362
3363 typedef BasicStringPiece<std::string> StringPiece;
3364
3365 struct Origin {
3366 // void SetHost(StringPiece host);
3367 StringPiece host;
3368 };
3369 "};
3370 let rs = quote! {
3371 ffi::Origin::new().within_unique_ptr();
3372 };
3373 run_test("", hdr, rs, &["Origin"], &[]);
3374}
3375
3376#[test]
3377fn test_associated_type_templated_typedef() {
3378 let hdr = indoc! {"
3379 #include <string>
3380 #include <cstdint>
3381
3382 template <typename STRING_TYPE> class BasicStringPiece {
3383 public:
3384 typedef size_t size_type;
3385 typedef typename STRING_TYPE::value_type value_type;
3386 const value_type* ptr_;
3387 size_type length_;
3388 };
3389
3390 typedef BasicStringPiece<std::string> StringPiece;
3391
3392 struct Container {
3393 Container() {}
3394 const StringPiece& get_string_piece() const { return sp; }
3395 StringPiece sp;
3396 };
3397
3398 inline void take_string_piece(const StringPiece&) {}
3399 "};
3400 let rs = quote! {
3401 let sp = ffi::Container::new().within_box();
3402 ffi::take_string_piece(sp.get_string_piece());
3403 };
3404 run_test("", hdr, rs, &["take_string_piece", "Container"], &[]);
3405}
3406
3407#[test]
3408fn test_associated_type_templated_typedef_by_value_regular() {
3409 let hdr = indoc! {"
3410 #include <string>
3411 #include <cstdint>
3412
3413 template <typename STRING_TYPE> class BasicStringPiece {
3414 public:
3415 BasicStringPiece() : ptr_(nullptr), length_(0) {}
3416 typedef size_t size_type;
3417 typedef typename STRING_TYPE::value_type value_type;
3418 const value_type* ptr_;
3419 size_type length_;
3420 };
3421
3422 typedef BasicStringPiece<std::string> StringPiece;
3423
3424 inline StringPiece give_string_piece() {
3425 StringPiece s;
3426 return s;
3427 }
3428 inline void take_string_piece(StringPiece) {}
3429 "};
3430 let rs = quote! {
3431 let sp = ffi::give_string_piece();
3432 ffi::take_string_piece(sp);
3433 };
3434 run_test_ex(
3435 "",
3436 hdr,
3437 rs,
3438 quote! {
3439 generate!("take_string_piece")
3440 generate!("give_string_piece")
3441 instantiable!("StringPiece")
3442 },
3443 None,
3444 None,
3445 None,
3446 );
3447}
3448
3449#[test]
3450fn test_associated_type_templated_typedef_by_value_forward_declaration() {
3451 let hdr = indoc! {"
3452 #include <string>
3453 #include <cstdint>
3454
3455 template <typename STRING_TYPE> class BasicStringPiece;
3456
3457 typedef BasicStringPiece<std::string> StringPiece;
3458
3459 struct Container {
3460 StringPiece give_string_piece() const;
3461 void take_string_piece(StringPiece string_piece) const;
3462 const StringPiece& get_string_piece() const;
3463 uint32_t b;
3464 };
3465
3466 inline void take_string_piece_by_ref(const StringPiece&) {}
3467 "};
3468 let cpp = indoc! {"
3469 template <typename STRING_TYPE> class BasicStringPiece {
3470 public:
3471 BasicStringPiece() : ptr_(nullptr), length_(0) {}
3472 typedef size_t size_type;
3473 typedef typename STRING_TYPE::value_type value_type;
3474 const value_type* ptr_;
3475 size_type length_;
3476 };
3477
3478 StringPiece Container::give_string_piece() const {
3479 StringPiece s;
3480 return s;
3481 }
3482 void Container::take_string_piece(StringPiece) const {}
3483
3484 StringPiece a;
3485
3486 const StringPiece& Container::get_string_piece() const {
3487 return a;
3488 }
3489 "};
3490 // As this template is forward declared we shouldn't be able to pass it by
3491 // value, but we still want to be able to use it by reference.
3492 let rs = quote! {
3493 let cont = ffi::Container::new().within_box();
3494 ffi::take_string_piece_by_ref(cont.as_ref().get_string_piece());
3495 };
3496 run_test(
3497 cpp,
3498 hdr,
3499 rs,
3500 &["take_string_piece_by_ref", "Container"],
3501 &[],
3502 );
3503}
3504
3505#[test]
3506fn test_remove_cv_t_pathological() {
3507 let hdr = indoc! {"
3508 template <class _Ty>
3509 struct remove_cv {
3510 using type = _Ty;
3511 template <template <class> class _Fn>
3512 using _Apply = _Fn<_Ty>;
3513 };
3514
3515 template <class _Ty>
3516 struct remove_cv<const _Ty> {
3517 using type = _Ty;
3518 template <template <class> class _Fn>
3519 using _Apply = const _Fn<_Ty>;
3520 };
3521
3522 template <class _Ty>
3523 struct remove_cv<volatile _Ty> {
3524 using type = _Ty;
3525 template <template <class> class _Fn>
3526 using _Apply = volatile _Fn<_Ty>;
3527 };
3528
3529 template <class _Ty>
3530 struct remove_cv<const volatile _Ty> {
3531 using type = _Ty;
3532 template <template <class> class _Fn>
3533 using _Apply = const volatile _Fn<_Ty>;
3534 };
3535
3536 template <class _Ty>
3537 using remove_cv_t = typename remove_cv<_Ty>::type;
3538
3539 template <class _Ty>
3540 struct remove_reference {
3541 using type = _Ty;
3542 using _Const_thru_ref_type = const _Ty;
3543 };
3544
3545 template <class _Ty>
3546 struct remove_reference<_Ty&> {
3547 using type = _Ty;
3548 using _Const_thru_ref_type = const _Ty&;
3549 };
3550
3551 template <class _Ty>
3552 struct remove_reference<_Ty&&> {
3553 using type = _Ty;
3554 using _Const_thru_ref_type = const _Ty&&;
3555 };
3556
3557 template <class _Ty>
3558 using remove_reference_t = typename remove_reference<_Ty>::type;
3559
3560 template <class _Ty>
3561 using _Remove_cvref_t = remove_cv_t<remove_reference_t<_Ty>>;
3562 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07003563 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07003564}
3565
3566#[test]
3567fn test_foreign_ns_func_arg_pod() {
3568 let hdr = indoc! {"
3569 #include <cstdint>
3570 #include <memory>
3571 namespace A {
3572 struct Bob {
3573 uint32_t a;
3574 };
3575 }
3576 namespace B {
3577 inline uint32_t daft(A::Bob a) { return a.a; }
3578 }
3579 "};
3580 let rs = quote! {
3581 let a = ffi::A::Bob { a: 12 };
3582 assert_eq!(ffi::B::daft(a), 12);
3583 };
3584 run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
3585}
3586
3587#[test]
3588fn test_foreign_ns_func_arg_nonpod() {
3589 let hdr = indoc! {"
3590 #include <cstdint>
3591 #include <memory>
3592 namespace A {
3593 struct Bob {
3594 uint32_t a;
3595 Bob(uint32_t _a) :a(_a) {}
3596 };
3597 }
3598 namespace B {
3599 inline uint32_t daft(A::Bob a) { return a.a; }
3600 }
3601 "};
3602 let rs = quote! {
3603 let a = ffi::A::Bob::new(12).within_unique_ptr();
3604 assert_eq!(ffi::B::daft(a), 12);
3605 };
3606 run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
3607}
3608
3609#[test]
3610fn test_foreign_ns_meth_arg_pod() {
3611 let hdr = indoc! {"
3612 #include <cstdint>
3613 #include <memory>
3614 namespace A {
3615 struct Bob {
3616 uint32_t a;
3617 };
3618 }
3619 namespace B {
3620 struct C {
3621 uint32_t a;
3622 uint32_t daft(A::Bob a) const { return a.a; }
3623 };
3624 }
3625 "};
3626 let rs = quote! {
3627 let a = ffi::A::Bob { a: 12 };
3628 let b = ffi::B::C { a: 12 };
3629 assert_eq!(b.daft(a), 12);
3630 };
3631 run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
3632}
3633
3634#[test]
3635fn test_foreign_ns_meth_arg_nonpod() {
3636 let hdr = indoc! {"
3637 #include <cstdint>
3638 #include <memory>
3639 namespace A {
3640 struct Bob {
3641 uint32_t a;
3642 Bob(uint32_t _a) :a(_a) {}
3643 };
3644 }
3645 namespace B {
3646 struct C {
3647 uint32_t a;
3648 uint32_t daft(A::Bob a) const { return a.a; }
3649 };
3650 }
3651 "};
3652 let rs = quote! {
3653 let a = ffi::A::Bob::new(12).within_unique_ptr();
3654 let b = ffi::B::C { a: 12 };
3655 assert_eq!(b.daft(a), 12);
3656 };
3657 run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
3658}
3659
3660#[test]
3661fn test_foreign_ns_cons_arg_pod() {
3662 let hdr = indoc! {"
3663 #include <cstdint>
3664 #include <memory>
3665 namespace A {
3666 struct Bob {
3667 uint32_t a;
3668 };
3669 }
3670 namespace B {
3671 struct C {
3672 uint32_t a;
3673 C(const A::Bob& input) : a(input.a) {}
3674 };
3675 }
3676 "};
3677 let rs = quote! {
3678 let a = ffi::A::Bob { a: 12 };
3679 let b = ffi::B::C::new(&a).within_unique_ptr();
3680 assert_eq!(b.as_ref().unwrap().a, 12);
3681 };
3682 run_test("", hdr, rs, &[], &["B::C", "A::Bob"]);
3683}
3684
3685#[test]
3686fn test_foreign_ns_cons_arg_nonpod() {
3687 let hdr = indoc! {"
3688 #include <cstdint>
3689 #include <memory>
3690 namespace A {
3691 struct Bob {
3692 Bob(uint32_t _a) :a(_a) {}
3693 uint32_t a;
3694 };
3695 }
3696 namespace B {
3697 struct C {
3698 uint32_t a;
3699 C(const A::Bob& input) : a(input.a) {}
3700 };
3701 }
3702 "};
3703 let rs = quote! {
3704 let a = ffi::A::Bob::new(12).within_unique_ptr();
3705 let b = ffi::B::C::new(&a).within_unique_ptr();
3706 assert_eq!(b.as_ref().unwrap().a, 12);
3707 };
3708 run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
3709}
3710
3711#[test]
3712fn test_foreign_ns_func_ret_pod() {
3713 let hdr = indoc! {"
3714 #include <cstdint>
3715 #include <memory>
3716 namespace A {
3717 struct Bob {
3718 uint32_t a;
3719 };
3720 }
3721 namespace B {
3722 inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
3723 }
3724 "};
3725 let rs = quote! {
3726 assert_eq!(ffi::B::daft().a, 12);
3727 };
3728 run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
3729}
3730
3731#[test]
3732fn test_foreign_ns_func_ret_nonpod() {
3733 let hdr = indoc! {"
3734 #include <cstdint>
3735 #include <memory>
3736 namespace A {
3737 struct Bob {
3738 uint32_t a;
3739 };
3740 }
3741 namespace B {
3742 inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
3743 }
3744 "};
3745 let rs = quote! {
3746 ffi::B::daft().within_box().as_ref();
3747 };
3748 run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
3749}
3750
3751#[test]
3752fn test_foreign_ns_meth_ret_pod() {
3753 let hdr = indoc! {"
3754 #include <cstdint>
3755 #include <memory>
3756 namespace A {
3757 struct Bob {
3758 uint32_t a;
3759 };
3760 }
3761 namespace B {
3762 struct C {
3763 uint32_t a;
3764 A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
3765 };
3766 }
3767 "};
3768 let rs = quote! {
3769 let b = ffi::B::C { a: 12 };
3770 assert_eq!(b.daft().a, 12);
3771 };
3772 run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
3773}
3774
3775#[test]
3776fn test_foreign_ns_meth_ret_nonpod() {
3777 let hdr = indoc! {"
3778 #include <cstdint>
3779 #include <memory>
3780 namespace A {
3781 struct Bob {
3782 uint32_t a;
3783 };
3784 }
3785 namespace B {
3786 struct C {
3787 uint32_t a;
3788 A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
3789 };
3790 }
3791 "};
3792 let rs = quote! {
3793 let b = ffi::B::C { a: 14 };
3794 b.daft().within_unique_ptr().as_ref().unwrap();
3795 };
3796 run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
3797}
3798
3799#[test]
3800fn test_root_ns_func_arg_pod() {
3801 let hdr = indoc! {"
3802 #include <cstdint>
3803 #include <memory>
3804 struct Bob {
3805 uint32_t a;
3806 };
3807 namespace B {
3808 inline uint32_t daft(Bob a) { return a.a; }
3809 }
3810 "};
3811 let rs = quote! {
3812 let a = ffi::Bob { a: 12 };
3813 assert_eq!(ffi::B::daft(a), 12);
3814 };
3815 run_test("", hdr, rs, &["B::daft"], &["Bob"]);
3816}
3817
3818#[test]
3819fn test_root_ns_func_arg_nonpod() {
3820 let hdr = indoc! {"
3821 #include <cstdint>
3822 #include <memory>
3823 struct Bob {
3824 uint32_t a;
3825 Bob(uint32_t _a) :a(_a) {}
3826 };
3827 namespace B {
3828 inline uint32_t daft(Bob a) { return a.a; }
3829 }
3830 "};
3831 let rs = quote! {
3832 let a = ffi::Bob::new(12).within_unique_ptr();
3833 assert_eq!(ffi::B::daft(a), 12);
3834 };
3835 run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
3836}
3837
3838#[test]
3839fn test_root_ns_meth_arg_pod() {
3840 let hdr = indoc! {"
3841 #include <cstdint>
3842 #include <memory>
3843 struct Bob {
3844 uint32_t a;
3845 };
3846 namespace B {
3847 struct C {
3848 uint32_t a;
3849 uint32_t daft(Bob a) const { return a.a; }
3850 };
3851 }
3852 "};
3853 let rs = quote! {
3854 let a = ffi::Bob { a: 12 };
3855 let b = ffi::B::C { a: 12 };
3856 assert_eq!(b.daft(a), 12);
3857 };
3858 run_test("", hdr, rs, &[], &["Bob", "B::C"]);
3859}
3860
3861#[test]
3862fn test_root_ns_meth_arg_nonpod() {
3863 let hdr = indoc! {"
3864 #include <cstdint>
3865 #include <memory>
3866 struct Bob {
3867 uint32_t a;
3868 Bob(uint32_t _a) :a(_a) {}
3869 };
3870 namespace B {
3871 struct C {
3872 uint32_t a;
3873 uint32_t daft(Bob a) const { return a.a; }
3874 };
3875 }
3876 "};
3877 let rs = quote! {
3878 let a = ffi::Bob::new(12).within_unique_ptr();
3879 let b = ffi::B::C { a: 12 };
3880 assert_eq!(b.daft(a), 12);
3881 };
3882 run_test("", hdr, rs, &["Bob"], &["B::C"]);
3883}
3884
3885#[test]
3886fn test_root_ns_cons_arg_pod() {
3887 let hdr = indoc! {"
3888 #include <cstdint>
3889 #include <memory>
3890 struct Bob {
3891 uint32_t a;
3892 };
3893 namespace B {
3894 struct C {
3895 uint32_t a;
3896 C(const Bob& input) : a(input.a) {}
3897 };
3898 }
3899 "};
3900 let rs = quote! {
3901 let a = ffi::Bob { a: 12 };
3902 let b = ffi::B::C::new(&a).within_unique_ptr();
3903 assert_eq!(b.as_ref().unwrap().a, 12);
3904 };
3905 run_test("", hdr, rs, &[], &["B::C", "Bob"]);
3906}
3907
3908#[test]
3909fn test_root_ns_cons_arg_nonpod() {
3910 let hdr = indoc! {"
3911 #include <cstdint>
3912 #include <memory>
3913 struct Bob {
3914 Bob(uint32_t _a) :a(_a) {}
3915 uint32_t a;
3916 };
3917 namespace B {
3918 struct C {
3919 uint32_t a;
3920 C(const Bob& input) : a(input.a) {}
3921 };
3922 }
3923 "};
3924 let rs = quote! {
3925 let a = ffi::Bob::new(12).within_unique_ptr();
3926 let b = ffi::B::C::new(&a).within_unique_ptr();
3927 assert_eq!(b.as_ref().unwrap().a, 12);
3928 };
3929 run_test("", hdr, rs, &["Bob"], &["B::C"]);
3930}
3931
3932#[test]
3933fn test_root_ns_func_ret_pod() {
3934 let hdr = indoc! {"
3935 #include <cstdint>
3936 #include <memory>
3937 struct Bob {
3938 uint32_t a;
3939 };
3940 namespace B {
3941 inline Bob daft() { Bob bob; bob.a = 12; return bob; }
3942 }
3943 "};
3944 let rs = quote! {
3945 assert_eq!(ffi::B::daft().a, 12);
3946 };
3947 run_test("", hdr, rs, &["B::daft"], &["Bob"]);
3948}
3949
3950#[test]
3951fn test_root_ns_func_ret_nonpod() {
3952 let hdr = indoc! {"
3953 #include <cstdint>
3954 #include <memory>
3955 struct Bob {
3956 uint32_t a;
3957 };
3958 namespace B {
3959 inline Bob daft() { Bob bob; bob.a = 12; return bob; }
3960 }
3961 "};
3962 let rs = quote! {
3963 ffi::B::daft().within_unique_ptr().as_ref().unwrap();
3964 };
3965 run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
3966}
3967
3968#[test]
3969fn test_root_ns_meth_ret_pod() {
3970 let hdr = indoc! {"
3971 #include <cstdint>
3972 #include <memory>
3973 struct Bob {
3974 uint32_t a;
3975 };
3976 namespace B {
3977 struct C {
3978 uint32_t a;
3979 Bob daft() const { Bob bob; bob.a = 12; return bob; }
3980 };
3981 }
3982 "};
3983 let rs = quote! {
3984 let b = ffi::B::C { a: 12 };
3985 assert_eq!(b.daft().a, 12);
3986 };
3987 run_test("", hdr, rs, &[], &["Bob", "B::C"]);
3988}
3989
3990#[test]
3991fn test_root_ns_meth_ret_nonpod() {
3992 let hdr = indoc! {"
3993 #include <cstdint>
3994 #include <memory>
3995 struct Bob {
3996 uint32_t a;
3997 };
3998 namespace B {
3999 struct C {
4000 uint32_t a;
4001 Bob daft() const { Bob bob; bob.a = 12; return bob; }
4002 };
4003 }
4004 "};
4005 let rs = quote! {
4006 let b = ffi::B::C { a: 12 };
4007 b.daft().within_unique_ptr().as_ref().unwrap();
4008 };
4009 run_test("", hdr, rs, &["Bob"], &["B::C"]);
4010}
4011
4012#[test]
4013fn test_forward_declaration() {
4014 let hdr = indoc! {"
4015 #include <cstdint>
4016 #include <memory>
4017 struct A;
4018 struct B {
4019 B() : a(0) {}
4020 uint32_t a;
4021 void daft(const A&) const {}
4022 static B daft3(const A&) { B b; return b; }
4023 A daft4();
4024 std::unique_ptr<A> daft5();
4025 const std::unique_ptr<A>& daft6();
4026 };
4027 A* get_a();
4028 void delete_a(A*);
4029 "};
4030 let cpp = indoc! {"
4031 struct A {
4032 A() : a(0) {}
4033 uint32_t a;
4034 };
4035 A* get_a() {
4036 return new A();
4037 }
4038 void delete_a(A* a) {
4039 delete a;
4040 }
4041 A B::daft4() {
4042 A a;
4043 return a;
4044 }
4045 std::unique_ptr<A> B::daft5() {
4046 return std::make_unique<A>();
4047 }
4048 std::unique_ptr<A> fixed;
4049 const std::unique_ptr<A>& B::daft6() {
4050 return fixed;
4051 }
4052 "};
4053 let rs = quote! {
4054 let b = ffi::B::new().within_unique_ptr();
4055 let a = ffi::get_a();
4056 b.daft(unsafe { a.as_ref().unwrap() });
4057 unsafe { ffi::delete_a(a) };
4058 };
4059 run_test(cpp, hdr, rs, &["B", "get_a", "delete_a"], &[]);
4060}
4061
4062#[test]
4063fn test_ulong() {
4064 let hdr = indoc! {"
4065 inline unsigned long daft(unsigned long a) { return a; }
4066 "};
4067 let rs = quote! {
4068 assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
4069 };
4070 run_test("", hdr, rs, &["daft"], &[]);
4071}
4072
4073#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4074#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
4075#[test]
4076fn test_typedef_to_ulong() {
4077 let hdr = indoc! {"
4078 typedef unsigned long fiddly;
4079 inline fiddly daft(fiddly a) { return a; }
4080 "};
4081 let rs = quote! {
4082 assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
4083 };
4084 run_test("", hdr, rs, &["daft"], &[]);
4085}
4086
4087#[test]
4088fn test_generate_typedef_to_ulong() {
4089 let hdr = indoc! {"
4090 #include <cstdint>
4091 typedef uint32_t fish_t;
4092 "};
4093 let rs = quote! {
4094 let _: ffi::fish_t;
4095 };
4096 run_test("", hdr, rs, &[], &["fish_t"]);
4097}
4098
4099#[test]
4100fn test_ulong_method() {
4101 let hdr = indoc! {"
4102 class A {
4103 public:
4104 A() {};
4105 unsigned long daft(unsigned long a) const { return a; }
4106 };
4107 "};
4108 let rs = quote! {
4109 let a = ffi::A::new().within_unique_ptr();
4110 assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
4111 };
4112 run_test("", hdr, rs, &["A"], &[]);
4113}
4114
4115#[test]
4116fn test_ulong_wrapped_method() {
4117 let hdr = indoc! {"
4118 #include <cstdint>
4119 struct B {
4120 B() {};
4121 uint32_t a;
4122 };
4123 class A {
4124 public:
4125 A() {};
4126 unsigned long daft(unsigned long a, B) const { return a; }
4127 };
4128 "};
4129 let rs = quote! {
4130 let b = ffi::B::new().within_unique_ptr();
4131 let a = ffi::A::new().within_unique_ptr();
4132 assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34), b), autocxx::c_ulong(34));
4133 };
4134 run_test("", hdr, rs, &["A", "B"], &[]);
4135}
4136
4137#[test]
4138fn test_reserved_name() {
4139 let hdr = indoc! {"
4140 #include <cstdint>
4141 inline uint32_t async(uint32_t a) { return a; }
4142 "};
4143 let rs = quote! {
4144 assert_eq!(ffi::async_(34), 34);
4145 };
4146 run_test("", hdr, rs, &["async_"], &[]);
4147}
4148
4149#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4150#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
4151#[test]
4152fn test_nested_type() {
4153 // Test that we can import APIs that use nested types.
4154 // As a regression test, we also test that the nested type `A::B` doesn't conflict with the
4155 // top-level type `B`. This used to cause compile errors.
4156 let hdr = indoc! {"
4157 struct A {
4158 A() {}
4159 struct B {
4160 B() {}
4161 };
4162 enum C {};
4163 using D = int;
4164 };
4165 struct B {
4166 B() {}
4167 void method_on_top_level_type() const {}
4168 };
4169 void take_A_B(A::B);
4170 void take_A_C(A::C);
4171 void take_A_D(A::D);
4172 "};
4173 let rs = quote! {
4174 let _ = ffi::A::new().within_unique_ptr();
4175 let b = ffi::B::new().within_unique_ptr();
4176 b.as_ref().unwrap().method_on_top_level_type();
4177 };
4178 run_test("", hdr, rs, &["A", "B", "take_A_B", "take_A_C"], &[]);
4179}
4180
4181#[test]
4182fn test_nested_type_in_namespace() {
4183 // Test that we can import APIs that use nested types in a namespace.
4184 // We can't make this part of the previous test as autocxx drops the
4185 // namespace, so `A::B` and `N::A::B` would be imported as the same
4186 // type.
4187 let hdr = indoc! {"
4188 namespace N {
4189 struct A {
4190 A() {}
4191 struct B {
4192 B() {}
4193 };
4194 };
4195 };
4196 void take_A_B(N::A::B);
4197 "};
4198 let rs = quote! {};
4199 run_test("", hdr, rs, &["take_A_B"], &[]);
4200}
4201
4202#[test]
4203fn test_nested_enum_in_namespace() {
4204 let hdr = indoc! {"
4205 namespace N {
4206 struct A {
4207 A() {}
4208 enum B {
4209 C,
4210 D,
4211 };
4212 };
4213 };
4214 void take_A_B(N::A::B);
4215 "};
4216 let rs = quote! {};
4217 run_test("", hdr, rs, &["take_A_B"], &[]);
4218}
4219
4220#[test]
4221fn test_abstract_nested_type() {
4222 let hdr = indoc! {"
4223 namespace N {
4224 class A {
4225 public:
4226 A() {}
4227 class B {
4228 private:
4229 B() {}
4230 public:
4231 virtual ~B() {}
4232 virtual void Foo() = 0;
4233 };
4234 };
4235 };
4236 void take_A_B(const N::A::B&);
4237 "};
4238 let rs = quote! {};
4239 run_test("", hdr, rs, &["take_A_B", "N::A_B"], &[]);
4240}
4241
4242#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07004243fn test_nested_unnamed_enum() {
4244 let hdr = indoc! {"
4245 namespace N {
4246 struct A {
4247 enum {
4248 LOW_VAL = 1,
4249 HIGH_VAL = 1000,
4250 };
4251 };
4252 }
4253 "};
4254 run_test_ex(
4255 "",
4256 hdr,
4257 quote! {},
4258 quote! { generate_ns!("N")},
4259 None,
4260 None,
4261 None,
4262 );
4263}
4264
4265#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07004266fn test_nested_type_constructor() {
4267 let hdr = indoc! {"
4268 #include <string>
4269 class A {
4270 public:
4271 class B {
4272 public:
4273 B(const std::string&) {}
4274 int b;
4275 };
4276 int a;
4277 };
4278 "};
4279 let rs = quote! {
4280 ffi::A_B::new(&ffi::make_string("Hello")).within_unique_ptr();
4281 };
4282 run_test("", hdr, rs, &["A_B"], &[]);
4283}
4284
4285#[test]
4286fn test_generic_type() {
4287 let hdr = indoc! {"
4288 #include <cstdint>
4289 #include <string>
4290 template<typename TY>
4291 struct Container {
4292 Container(TY a_) : a(a_) {}
4293 TY a;
4294 };
4295 struct Secondary {
4296 Secondary() {}
4297 void take_a(const Container<char>) const {}
4298 void take_b(const Container<uint16_t>) const {}
4299 uint16_t take_c(std::string a) const { return 10 + a.size(); }
4300 };
4301 "};
4302 let rs = quote! {
4303 use ffi::ToCppString;
4304 let item = ffi::Secondary::new().within_unique_ptr();
4305 assert_eq!(item.take_c("hello".into_cpp()), 15)
4306 };
4307 run_test("", hdr, rs, &["Secondary"], &[]);
4308}
4309
4310#[test]
4311fn test_cycle_generic_type() {
4312 let hdr = indoc! {"
4313 #include <cstdint>
4314 template<typename TY>
4315 struct Container {
4316 Container(TY a_) : a(a_) {}
4317 TY a;
4318 };
4319 inline Container<char> make_thingy() {
4320 Container<char> a('a');
4321 return a;
4322 }
4323 typedef Container<char> Concrete;
4324 inline uint32_t take_thingy(Concrete a) {
4325 return a.a;
4326 }
4327 "};
4328 let rs = quote! {
4329 assert_eq!(ffi::take_thingy(ffi::make_thingy()), 'a' as u32)
4330 };
4331 run_test("", hdr, rs, &["take_thingy", "make_thingy"], &[]);
4332}
4333
4334#[test]
4335fn test_virtual_fns() {
4336 let hdr = indoc! {"
4337 #include <cstdint>
4338 class A {
4339 public:
4340 A(uint32_t num) : b(num) {}
4341 virtual uint32_t foo(uint32_t a) { return a+1; };
4342 virtual ~A() {}
4343 uint32_t b;
4344 };
4345 class B: public A {
4346 public:
4347 B() : A(3), c(4) {}
4348 virtual uint32_t foo(uint32_t a) { return a+2; };
4349 uint32_t c;
4350 };
4351 "};
4352 let rs = quote! {
4353 let mut a = ffi::A::new(12).within_unique_ptr();
4354 assert_eq!(a.pin_mut().foo(2), 3);
4355 let mut b = ffi::B::new().within_unique_ptr();
4356 assert_eq!(b.pin_mut().foo(2), 4);
4357 };
4358 run_test("", hdr, rs, &["A", "B"], &[]);
4359}
4360
4361#[test]
4362fn test_const_virtual_fns() {
4363 let hdr = indoc! {"
4364 #include <cstdint>
4365 class A {
4366 public:
4367 A(uint32_t num) : b(num) {}
4368 virtual uint32_t foo(uint32_t a) const { return a+1; };
4369 virtual ~A() {}
4370 uint32_t b;
4371 };
4372 class B: public A {
4373 public:
4374 B() : A(3), c(4) {}
4375 virtual uint32_t foo(uint32_t a) const { return a+2; };
4376 uint32_t c;
4377 };
4378 "};
4379 let rs = quote! {
4380 let a = ffi::A::new(12).within_unique_ptr();
4381 assert_eq!(a.foo(2), 3);
4382 let b = ffi::B::new().within_unique_ptr();
4383 assert_eq!(b.foo(2), 4);
4384 };
4385 run_test("", hdr, rs, &["A", "B"], &[]);
4386}
4387
4388#[test]
4389#[ignore] // https://github.com/google/autocxx/issues/197
4390fn test_virtual_fns_inheritance() {
4391 let hdr = indoc! {"
4392 #include <cstdint>
4393 class A {
4394 public:
4395 A(uint32_t num) : b(num) {}
4396 virtual uint32_t foo(uint32_t a) { return a+1; };
4397 virtual ~A() {}
4398 uint32_t b;
4399 };
4400 class B: public A {
4401 public:
4402 B() : A(3), c(4) {}
4403 uint32_t c;
4404 };
4405 "};
4406 let rs = quote! {
4407 let mut b = ffi::B::new().within_unique_ptr();
4408 assert_eq!(b.pin_mut().foo(2), 3);
4409 };
4410 run_test("", hdr, rs, &["B"], &[]);
4411}
4412
4413#[test]
4414fn test_vector_cycle_up() {
4415 let hdr = indoc! {"
4416 #include <cstdint>
4417 #include <vector>
4418 #include <memory>
4419 struct A {
4420 uint32_t a;
4421 };
4422 inline uint32_t take_vec(std::unique_ptr<std::vector<A>> many_as) {
4423 return many_as->size();
4424 }
4425 inline std::unique_ptr<std::vector<A>> get_vec() {
4426 auto items = std::make_unique<std::vector<A>>();
4427 items->push_back(A { 3 });
4428 items->push_back(A { 4 });
4429 return items;
4430 }
4431 "};
4432 let rs = quote! {
4433 let v = ffi::get_vec();
4434 assert_eq!(v.as_ref().unwrap().is_empty(), false);
4435 assert_eq!(ffi::take_vec(v), 2);
4436 };
4437 run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
4438}
4439
4440#[test]
4441fn test_vector_cycle_bare() {
4442 let hdr = indoc! {"
4443 #include <cstdint>
4444 #include <vector>
4445 struct A {
4446 uint32_t a;
4447 };
4448 inline uint32_t take_vec(std::vector<A> many_as) {
4449 return many_as.size();
4450 }
4451 inline std::vector<A> get_vec() {
4452 std::vector<A> items;
4453 items.push_back(A { 3 });
4454 items.push_back(A { 4 });
4455 return items;
4456 }
4457 "};
4458 let rs = quote! {
4459 assert_eq!(ffi::take_vec(ffi::get_vec()), 2);
4460 };
4461 run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
4462}
4463
4464#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07004465fn test_cycle_up_of_vec() {
4466 let hdr = indoc! {"
4467 #include <cstdint>
4468 #include <vector>
4469 #include <memory>
4470 struct A {
4471 uint32_t a;
4472 };
4473 inline std::unique_ptr<std::vector<A>> take_vec(std::unique_ptr<std::vector<A>> a) {
4474 return a;
4475 }
4476 inline std::unique_ptr<std::vector<A>> get_vec() {
4477 std::unique_ptr<std::vector<A>> items = std::make_unique<std::vector<A>>();
4478 items->push_back(A { 3 });
4479 items->push_back(A { 4 });
4480 return items;
4481 }
4482 "};
4483 let rs = quote! {
4484 ffi::take_vec(ffi::get_vec());
4485 };
4486 run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
4487}
4488
4489#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07004490fn test_typedef_to_std() {
4491 let hdr = indoc! {"
4492 #include <string>
James Kuszmaul850a4752024-02-14 20:27:12 -08004493 #include <cstdint>
Brian Silverman4e662aa2022-05-11 23:10:19 -07004494 typedef std::string my_string;
4495 inline uint32_t take_str(my_string a) {
4496 return a.size();
4497 }
4498 "};
4499 let rs = quote! {
4500 use ffi::ToCppString;
4501 assert_eq!(ffi::take_str("hello".into_cpp()), 5);
4502 };
4503 run_test("", hdr, rs, &["take_str"], &[]);
4504}
4505
4506#[test]
4507fn test_typedef_to_up_in_fn_call() {
4508 let hdr = indoc! {"
4509 #include <string>
4510 #include <memory>
4511 typedef std::unique_ptr<std::string> my_string;
4512 inline uint32_t take_str(my_string a) {
4513 return a->size();
4514 }
4515 "};
4516 let rs = quote! {
4517 use ffi::ToCppString;
4518 assert_eq!(ffi::take_str("hello".into_cpp()), 5);
4519 };
4520 run_test("", hdr, rs, &["take_str"], &[]);
4521}
4522
4523#[test]
4524fn test_typedef_in_pod_struct() {
4525 let hdr = indoc! {"
4526 #include <string>
James Kuszmaul850a4752024-02-14 20:27:12 -08004527 #include <cstdint>
Brian Silverman4e662aa2022-05-11 23:10:19 -07004528 typedef uint32_t my_int;
4529 struct A {
4530 my_int a;
4531 };
4532 inline uint32_t take_a(A a) {
4533 return a.a;
4534 }
4535 "};
4536 let rs = quote! {
4537 let a = ffi::A {
4538 a: 32,
4539 };
4540 assert_eq!(ffi::take_a(a), 32);
4541 };
4542 run_test("", hdr, rs, &["take_a"], &["A"]);
4543}
4544
4545#[test]
4546fn test_cint_in_pod_struct() {
4547 let hdr = indoc! {"
4548 #include <string>
James Kuszmaul850a4752024-02-14 20:27:12 -08004549 #include <cstdint>
Brian Silverman4e662aa2022-05-11 23:10:19 -07004550 struct A {
4551 int a;
4552 };
4553 inline uint32_t take_a(A a) {
4554 return a.a;
4555 }
4556 "};
4557 let rs = quote! {
4558 let a = ffi::A {
4559 a: 32,
4560 };
4561 assert_eq!(ffi::take_a(a), 32);
4562 };
4563 run_test("", hdr, rs, &["take_a"], &["A"]);
4564}
4565
4566#[test]
4567fn test_string_in_struct() {
4568 let hdr = indoc! {"
4569 #include <string>
4570 #include <memory>
4571 struct A {
4572 std::string a;
4573 };
4574 inline A make_a(std::string b) {
4575 A bob;
4576 bob.a = b;
4577 return bob;
4578 }
4579 inline uint32_t take_a(A a) {
4580 return a.a.size();
4581 }
4582 "};
4583 let rs = quote! {
4584 use ffi::ToCppString;
4585 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4586 };
4587 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4588}
4589
4590#[test]
4591#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4592fn test_up_in_struct() {
4593 let hdr = indoc! {"
4594 #include <string>
4595 #include <memory>
4596 struct A {
4597 std::unique_ptr<std::string> a;
4598 };
4599 inline A make_a(std::string b) {
4600 A bob;
4601 bob.a = std::make_unique<std::string>(b);
4602 return bob;
4603 }
4604 inline uint32_t take_a(A a) {
4605 return a.a->size();
4606 }
4607 "};
4608 let rs = quote! {
4609 use ffi::ToCppString;
4610 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4611 };
4612 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4613}
4614
4615#[test]
4616fn test_typedef_to_std_in_struct() {
4617 let hdr = indoc! {"
4618 #include <string>
James Kuszmaul850a4752024-02-14 20:27:12 -08004619 #include <cstdint>
Brian Silverman4e662aa2022-05-11 23:10:19 -07004620 typedef std::string my_string;
4621 struct A {
4622 my_string a;
4623 };
4624 inline A make_a(std::string b) {
4625 A bob;
4626 bob.a = b;
4627 return bob;
4628 }
4629 inline uint32_t take_a(A a) {
4630 return a.a.size();
4631 }
4632 "};
4633 let rs = quote! {
4634 use ffi::ToCppString;
4635 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4636 };
4637 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4638}
4639
4640#[test]
4641#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4642fn test_typedef_to_up_in_struct() {
4643 let hdr = indoc! {"
4644 #include <string>
4645 #include <memory>
4646 typedef std::unique_ptr<std::string> my_string;
4647 struct A {
4648 my_string a;
4649 };
4650 inline A make_a(std::string b) {
4651 A bob;
4652 bob.a = std::make_unique<std::string>(b);
4653 return bob;
4654 }
4655 inline uint32_t take_a(A a) {
4656 return a.a->size();
4657 }
4658 "};
4659 let rs = quote! {
4660 use ffi::ToCppString;
4661 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4662 };
4663 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4664}
4665
4666#[test]
4667fn test_float() {
4668 let hdr = indoc! {"
4669 inline float daft(float a) { return a; }
4670 "};
4671 let rs = quote! {
4672 assert_eq!(ffi::daft(34.0f32), 34.0f32);
4673 };
4674 run_test("", hdr, rs, &["daft"], &[]);
4675}
4676
4677#[test]
4678fn test_double() {
4679 let hdr = indoc! {"
4680 inline double daft(double a) { return a; }
4681 "};
4682 let rs = quote! {
4683 assert_eq!(ffi::daft(34.0f64), 34.0f64);
4684 };
4685 run_test("", hdr, rs, &["daft"], &[]);
4686}
4687
4688#[test]
4689fn test_issues_217_222() {
4690 let hdr = indoc! {"
4691 #include <string>
4692 #include <cstdint>
4693 #include <cstddef>
4694
4695 template <typename STRING_TYPE> class BasicStringPiece {
4696 public:
4697 typedef size_t size_type;
4698 typedef typename STRING_TYPE::traits_type traits_type;
4699 typedef typename STRING_TYPE::value_type value_type;
4700 typedef const value_type* pointer;
4701 typedef const value_type& reference;
4702 typedef const value_type& const_reference;
4703 typedef ptrdiff_t difference_type;
4704 typedef const value_type* const_iterator;
4705 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4706 static const size_type npos;
4707 };
4708
4709 template<typename CHAR>
4710 class Replacements {
4711 public:
4712 Replacements() {
4713 }
4714 void SetScheme(const CHAR*) {
4715 }
4716 uint16_t a;
4717 };
4718
4719 struct Component {
4720 uint16_t a;
4721 };
4722
4723 template <typename STR>
4724 class StringPieceReplacements : public Replacements<typename STR::value_type> {
4725 private:
4726 using CharT = typename STR::value_type;
4727 using StringPieceT = BasicStringPiece<STR>;
4728 using ParentT = Replacements<CharT>;
4729 using SetterFun = void (ParentT::*)(const CharT*, const Component&);
4730 void SetImpl(SetterFun, StringPieceT) {
4731 }
4732 public:
4733 void SetSchemeStr(const CharT* str) { SetImpl(&ParentT::SetScheme, str); }
4734 };
4735
4736 class GURL {
4737 public:
4738 typedef StringPieceReplacements<std::string> UrlReplacements;
4739 GURL() {}
4740 GURL ReplaceComponents(const Replacements<char>&) const {
4741 return GURL();
4742 }
4743 uint16_t a;
4744 };
4745 "};
4746 let rs = quote! {
4747 ffi::GURL::new().within_unique_ptr();
4748 };
4749 // The block! directives here are to avoid running into
4750 // https://github.com/rust-lang/rust-bindgen/pull/1975
4751 run_test_ex(
4752 "",
4753 hdr,
4754 rs,
4755 quote! { generate!("GURL") block!("StringPiece") block!("Replacements") },
4756 None,
4757 None,
4758 None,
4759 );
4760}
4761
4762#[test]
4763#[ignore] // https://github.com/rust-lang/rust-bindgen/pull/1975, https://github.com/google/autocxx/issues/106
4764fn test_dependent_qualified_type() {
4765 let hdr = indoc! {"
4766 #include <stddef.h>
4767 struct MyString {
4768 typedef char value_type;
4769 };
4770 template<typename T> struct MyStringView {
4771 typedef typename T::value_type view_value_type;
4772 const view_value_type* start;
4773 size_t length;
4774 };
4775 const char* HELLO = \"hello\";
4776 inline MyStringView<MyString> make_string_view() {
4777 MyStringView<MyString> r;
4778 r.start = HELLO;
4779 r.length = 2;
4780 return r;
4781 }
4782 inline size_t take_string_view(const MyStringView<MyString>& bit) {
4783 return bit.length;
4784 }
4785 "};
4786 let rs = quote! {
4787 let sv = ffi::make_string_view();
4788 assert_eq!(ffi::take_string_view(sv.as_ref().unwrap()), 2);
4789 };
4790 run_test("", hdr, rs, &["take_string_view", "make_string_view"], &[]);
4791}
4792
4793#[test]
4794fn test_simple_dependent_qualified_type() {
4795 // bindgen seems to cope with this case just fine
4796 let hdr = indoc! {"
4797 #include <stddef.h>
4798 #include <stdint.h>
4799 struct MyString {
4800 typedef char value_type;
4801 };
4802 template<typename T> struct MyStringView {
4803 typedef typename T::value_type view_value_type;
4804 const view_value_type* start;
4805 size_t length;
4806 };
4807 typedef MyStringView<MyString>::view_value_type MyChar;
4808 inline MyChar make_char() {
4809 return 'a';
4810 }
4811 inline uint32_t take_char(MyChar c) {
4812 return static_cast<unsigned char>(c);
4813 }
4814 "};
4815 let rs = quote! {
4816 let c = ffi::make_char();
4817 assert_eq!(ffi::take_char(c), 97);
4818 };
4819 run_test("", hdr, rs, &["make_char", "take_char"], &[]);
4820}
4821
4822#[test]
4823fn test_ignore_dependent_qualified_type() {
4824 let hdr = indoc! {"
4825 #include <stddef.h>
4826 struct MyString {
4827 typedef char value_type;
4828 };
4829 template<typename T> struct MyStringView {
4830 typedef typename T::value_type view_value_type;
4831 const view_value_type* start;
4832 size_t length;
4833 };
4834 MyStringView<MyString> make_string_view();
4835 struct B {
4836 B() {}
4837 inline size_t take_string_view(const MyStringView<MyString> bit) {
4838 return bit.length;
4839 }
4840 };
4841 "};
4842 let cpp = indoc! {"
4843 const char* HELLO = \"hello\";
4844 MyStringView<MyString> make_string_view() {
4845 MyStringView<MyString> r;
4846 r.start = HELLO;
4847 r.length = 2;
4848 return r;
4849 }
4850 "};
4851 let rs = quote! {
4852 ffi::B::new().within_unique_ptr();
4853 };
4854 run_test(cpp, hdr, rs, &["B"], &[]);
4855}
4856
4857#[test]
4858fn test_ignore_dependent_qualified_type_reference() {
4859 let hdr = indoc! {"
4860 #include <stddef.h>
4861 struct MyString {
4862 typedef char value_type;
4863 };
4864 template<typename T> struct MyStringView {
4865 typedef typename T::value_type view_value_type;
4866 const view_value_type* start;
4867 size_t length;
4868 };
4869 MyStringView<MyString> make_string_view();
4870 struct B {
4871 B() {}
4872 inline size_t take_string_view(const MyStringView<MyString>& bit) {
4873 return bit.length;
4874 }
4875 };
4876 "};
4877 let cpp = indoc! {"
4878 const char* HELLO = \"hello\";
4879 MyStringView<MyString> make_string_view() {
4880 MyStringView<MyString> r;
4881 r.start = HELLO;
4882 r.length = 2;
4883 return r;
4884 }
4885 "};
4886 let rs = quote! {
4887 ffi::B::new().within_unique_ptr();
4888 };
4889 run_test(cpp, hdr, rs, &["B"], &[]);
4890}
4891
4892#[test]
4893fn test_specialization() {
4894 let hdr = indoc! {"
4895 #include <stddef.h>
4896 #include <stdint.h>
4897 #include <string>
4898 #include <type_traits>
4899
4900 template <typename T, bool = std::is_trivially_destructible<T>::value>
4901 struct OptionalStorageBase {
4902 T value_;
4903 };
4904
4905 template <typename T,
4906 bool = std::is_trivially_copy_constructible<T>::value,
4907 bool = std::is_trivially_move_constructible<T>::value>
4908 struct OptionalStorage : OptionalStorageBase<T> {};
4909
4910 template <typename T>
4911 struct OptionalStorage<T,
4912 true /* trivially copy constructible */,
4913 false /* trivially move constructible */>
4914 : OptionalStorageBase<T> {
4915 };
4916
4917 template <typename T>
4918 struct OptionalStorage<T,
4919 false /* trivially copy constructible */,
4920 true /* trivially move constructible */>
4921 : OptionalStorageBase<T> {
4922 };
4923
4924 template <typename T>
4925 struct OptionalStorage<T,
4926 true /* trivially copy constructible */,
4927 true /* trivially move constructible */>
4928 : OptionalStorageBase<T> {
4929 };
4930
4931 template <typename T>
4932 class OptionalBase {
4933 private:
4934 OptionalStorage<T> storage_;
4935 };
4936
4937 template <typename T>
4938 class Optional : public OptionalBase<T> {
4939
4940 };
4941
4942 struct B {
4943 B() {}
4944 void take_optional(Optional<std::string>) {}
4945 uint32_t a;
4946 };
4947 "};
4948 let rs = quote! {
4949 ffi::B::new().within_unique_ptr();
4950 };
4951 run_test("", hdr, rs, &["B"], &[]);
4952}
4953
4954#[test]
4955fn test_private_constructor_make_unique() {
4956 let hdr = indoc! {"
4957 #include <stdint.h>
4958 struct A {
4959 private:
4960 A() {};
4961 public:
4962 uint32_t a;
4963 };
4964 "};
4965 let rs = quote! {};
4966 run_test("", hdr, rs, &["A"], &[]);
4967}
4968
4969#[test]
4970#[ignore] // https://github.com/google/autocxx/issues/266
4971fn test_take_array() {
4972 let hdr = indoc! {"
4973 #include <cstdint>
4974 uint32_t take_array(const uint32_t a[4]) {
4975 return a[0] + a[2];
4976 }
4977 "};
4978 let rs = quote! {
4979 let c: [u32; 4usize] = [ 10, 20, 30, 40 ];
4980 let c = c as *const [_];
4981 assert_eq!(ffi::take_array(&c), 40);
4982 };
4983 run_test("", hdr, rs, &["take_array"], &[]);
4984}
4985
4986#[test]
4987fn test_take_array_in_struct() {
4988 let hdr = indoc! {"
4989 #include <cstdint>
4990 struct data {
4991 char a[4];
4992 };
4993 uint32_t take_array(const data a) {
4994 return a.a[0] + a.a[2];
4995 }
4996 "};
4997 let rs = quote! {
4998 let c = ffi::data { a: [ 10, 20, 30, 40 ] };
4999 assert_eq!(ffi::take_array(c), 40);
5000 };
5001 run_test("", hdr, rs, &["take_array"], &["data"]);
5002}
5003
5004#[test]
James Kuszmaul850a4752024-02-14 20:27:12 -08005005fn test_take_struct_built_array_in_function() {
5006 let hdr = indoc! {"
5007 #include <cstdint>
5008 struct data {
5009 char a[4];
5010 };
5011 uint32_t take_array(char a[4]) {
5012 return a[0] + a[2];
5013 }
5014 "};
5015 let rs = quote! {
5016 let mut c = ffi::data { a: [ 10, 20, 30, 40 ] };
5017 unsafe {
5018 assert_eq!(ffi::take_array(c.a.as_mut_ptr()), 40);
5019 }
5020 };
5021 run_test("", hdr, rs, &["take_array"], &["data"]);
5022}
5023
5024#[test]
5025fn test_take_array_in_function() {
5026 let hdr = indoc! {"
5027 #include <cstdint>
5028 uint32_t take_array(char a[4]) {
5029 return a[0] + a[2];
5030 }
5031 "};
5032 let rs = quote! {
5033 let mut a: [i8; 4] = [ 10, 20, 30, 40 ];
5034 unsafe {
5035 assert_eq!(ffi::take_array(a.as_mut_ptr()), 40);
5036 }
5037 };
5038 run_test("", hdr, rs, &["take_array"], &[]);
5039}
5040
5041#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07005042fn test_union_ignored() {
5043 let hdr = indoc! {"
5044 #include <cstdint>
5045 union A {
5046 uint32_t a;
5047 float b;
5048 };
5049 struct B {
5050 B() :a(1) {}
5051 uint32_t take_union(A) const {
5052 return 3;
5053 }
5054 uint32_t get_a() const { return 2; }
5055 uint32_t a;
5056 };
5057 "};
5058 let rs = quote! {
5059 let b = ffi::B::new().within_unique_ptr();
5060 assert_eq!(b.get_a(), 2);
5061 };
5062 run_test("", hdr, rs, &["B"], &[]);
5063}
5064
5065#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07005066fn test_union_nonpod() {
5067 let hdr = indoc! {"
5068 #include <cstdint>
5069 union A {
5070 uint32_t a;
5071 float b;
5072 };
5073 "};
5074 let rs = quote! {};
5075 run_test("", hdr, rs, &["A"], &[]);
5076}
5077
5078#[test]
5079fn test_union_pod() {
5080 let hdr = indoc! {"
5081 #include <cstdint>
5082 union A {
5083 uint32_t a;
5084 float b;
5085 };
5086 "};
5087 let rs = quote! {};
5088 run_test_expect_fail("", hdr, rs, &[], &["A"]);
5089}
5090
5091#[test]
5092fn test_type_aliased_anonymous_union_ignored() {
5093 let hdr = indoc! {"
5094 #include <cstdint>
5095 namespace test {
5096 typedef union {
5097 int a;
5098 } Union;
5099 };
5100 "};
5101 let rs = quote! {};
5102 run_test("", hdr, rs, &["test::Union"], &[]);
5103}
5104
5105#[test]
5106fn test_type_aliased_anonymous_struct_ignored() {
5107 let hdr = indoc! {"
5108 #include <cstdint>
5109 namespace test {
5110 typedef struct {
5111 int a;
5112 } Struct;
5113 };
5114 "};
5115 let rs = quote! {};
5116 run_test("", hdr, rs, &["test::Struct"], &[]);
5117}
5118
5119#[test]
5120fn test_type_aliased_anonymous_nested_struct_ignored() {
5121 let hdr = indoc! {"
5122 #include <cstdint>
5123 namespace test {
5124 struct Outer {
5125 typedef struct {
5126 int a;
5127 } Struct;
5128 int b;
5129 };
5130 };
5131 "};
5132 let rs = quote! {};
5133 run_test("", hdr, rs, &["test::Outer_Struct"], &[]);
5134}
5135
5136#[ignore] // https://github.com/google/autocxx/issues/1251
5137#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07005138fn test_double_underscores_ignored() {
5139 let hdr = indoc! {"
5140 #include <cstdint>
5141 struct __FOO {
5142 uint32_t a;
5143 };
5144 struct B {
5145 B() :a(1) {}
5146 uint32_t take_foo(__FOO) const {
5147 return 3;
5148 }
5149 void do__something() const { }
5150 uint32_t get_a() const { return 2; }
5151 uint32_t a;
5152 };
5153
5154 struct __default { __default() = default; };
5155 struct __destructor { ~__destructor() = default; };
5156 struct __copy { __copy(const __copy&) = default; };
5157 struct __copy_operator { __copy_operator &operator=(const __copy_operator&) = default; };
5158 struct __move { __move(__move&&) = default; };
5159 struct __move_operator { __move_operator &operator=(const __move_operator&) = default; };
5160 "};
5161 let rs = quote! {
5162 let b = ffi::B::new().within_unique_ptr();
5163 assert_eq!(b.get_a(), 2);
5164 };
5165 run_test(
5166 "",
5167 hdr,
5168 rs,
5169 &[
5170 "B",
5171 "__default",
5172 "__destructor",
5173 "__copy",
5174 "__copy_operator",
5175 "__move",
5176 "__move_operator",
5177 ],
5178 &[],
5179 );
5180}
5181
5182// This test fails on Windows gnu but not on Windows msvc
5183#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
5184#[test]
5185fn test_double_underscore_typedef_ignored() {
5186 let hdr = indoc! {"
5187 #include <cstdint>
5188 typedef int __int32_t;
5189 typedef __int32_t __darwin_pid_t;
5190 typedef __darwin_pid_t pid_t;
5191 struct B {
5192 B() :a(1) {}
5193 uint32_t take_foo(pid_t) const {
5194 return 3;
5195 }
5196 uint32_t get_a() const { return 2; }
5197 uint32_t a;
5198 };
5199 "};
5200 let rs = quote! {
5201 let b = ffi::B::new().within_unique_ptr();
5202 assert_eq!(b.get_a(), 2);
5203 };
5204 run_test("", hdr, rs, &["B"], &[]);
5205}
5206
5207#[test]
5208fn test_double_underscores_fn_namespace() {
5209 let hdr = indoc! {"
5210 namespace __B {
5211 inline void a() {}
5212 };
5213 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07005214 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07005215}
5216
5217#[test]
5218fn test_typedef_to_ptr_is_marked_unsafe() {
5219 let hdr = indoc! {"
5220 struct _xlocalefoo; /* forward reference */
5221 typedef struct _xlocalefoo * locale_tfoo;
5222 extern \"C\" {
5223 locale_tfoo duplocalefoo(locale_tfoo);
5224 }
5225 "};
5226 let rs = quote! {};
5227 run_test("", hdr, rs, &["duplocalefoo"], &[]);
5228}
5229
5230#[test]
5231fn test_issue_264() {
5232 let hdr = indoc! {"
5233 namespace a {
5234 typedef int b;
5235 //inline namespace c {}
5236 template <typename> class aa;
5237 inline namespace c {
5238 template <typename d, typename = d, typename = aa<d>> class e;
5239 }
5240 typedef e<char> f;
5241 template <typename g, typename, template <typename> typename> struct h {
5242 using i = g;
5243 };
5244 template <typename g, template <typename> class k> using j = h<g, void, k>;
5245 template <typename g, template <typename> class k>
5246 using m = typename j<g, k>::i;
5247 template <typename> struct l { typedef b ab; };
5248 template <typename p> class aa {
5249 public:
5250 typedef p n;
5251 };
5252 struct r {
5253 template <typename p> using o = typename p::c;
5254 };
5255 template <typename ad> struct u : r {
5256 typedef typename ad::n n;
5257 using ae = m<n, o>;
5258 template <typename af, typename> struct v { using i = typename l<f>::ab; };
5259 using ab = typename v<ad, ae>::i;
5260 };
5261 } // namespace a
5262 namespace q {
5263 template <typename ad> struct w : a::u<ad> {};
5264 } // namespace q
5265 namespace a {
5266 inline namespace c {
5267 template <typename, typename, typename ad> class e {
5268 typedef q::w<ad> s;
5269 public:
5270 typedef typename s::ab ab;
5271 };
5272 } // namespace c
5273 } // namespace a
5274 namespace ag {
5275 namespace ah {
5276 typedef a::f::ab t;
5277 class ai {
5278 public:
5279 t aj;
5280 };
5281 class al;
5282 namespace am {
5283 class an {
5284 public:
5285 void ao(ai);
5286 };
5287 } // namespace am
5288 class ap {
5289 public:
5290 al aq();
5291 };
5292 class ar {
5293 public:
5294 am::an as;
5295 };
5296 class al {
5297 public:
5298 ar at;
5299 };
5300 struct au {
5301 ap av;
5302 };
5303 } // namespace ah
5304 } // namespace ag
5305 namespace operations_research {
5306 class aw {
5307 public:
5308 ag::ah::au ax;
5309 };
5310 class Solver {
5311 public:
5312 aw ay;
5313 };
5314 } // namespace operations_research
5315 "};
5316 let rs = quote! {};
5317 run_test_ex(
5318 "",
5319 hdr,
5320 rs,
5321 directives_from_lists(&["operations_research::Solver"], &[], None),
5322 make_cpp17_adder(),
5323 None,
5324 None,
5325 );
5326}
5327
5328#[test]
5329fn test_unexpected_use() {
5330 // https://github.com/google/autocxx/issues/303
5331 let hdr = indoc! {"
5332 typedef int a;
5333 namespace b {
5334 namespace c {
5335 enum d : a;
5336 }
5337 } // namespace b
5338 namespace {
5339 using d = b::c::d;
5340 }
5341 namespace content {
5342 class RenderFrameHost {
5343 public:
5344 RenderFrameHost() {}
5345 d e;
5346 };
5347 } // namespace content
5348 "};
5349 let rs = quote! {
5350 let _ = ffi::content::RenderFrameHost::new().within_unique_ptr();
5351 };
5352 run_test("", hdr, rs, &["content::RenderFrameHost"], &[]);
5353}
5354
5355#[test]
5356fn test_get_pure_virtual() {
5357 let hdr = indoc! {"
5358 #include <cstdint>
5359 class A {
5360 public:
5361 virtual ~A() {}
5362 virtual uint32_t get_val() const = 0;
5363 };
5364 class B : public A {
5365 public:
5366 virtual uint32_t get_val() const { return 3; }
5367 };
5368 const B b;
5369 inline const A* get_a() { return &b; };
5370 "};
5371 let rs = quote! {
5372 let a = ffi::get_a();
5373 let a_ref = unsafe { a.as_ref() }.unwrap();
5374 assert_eq!(a_ref.get_val(), 3);
5375 };
5376 run_test("", hdr, rs, &["A", "get_a"], &[]);
5377}
5378
5379#[test]
5380fn test_abstract_class_no_make_unique() {
5381 // We shouldn't generate a new().within_unique_ptr() for abstract classes.
5382 // The test is successful if the bindings compile, i.e. if autocxx doesn't
5383 // attempt to instantiate the class.
5384 let hdr = indoc! {"
5385 class A {
5386 public:
5387 A() {}
5388 virtual ~A() {}
5389 virtual void foo() const = 0;
5390 };
5391 "};
5392 let rs = quote! {};
5393 run_test("", hdr, rs, &["A"], &[]);
5394}
5395
5396#[test]
5397fn test_derived_abstract_class_no_make_unique() {
5398 let hdr = indoc! {"
5399 class A {
5400 public:
5401 A();
5402 virtual ~A() {}
5403 virtual void foo() const = 0;
5404 };
5405
5406 class B : public A {
5407 public:
5408 B();
5409 };
5410 "};
5411 let rs = quote! {};
5412 run_test("", hdr, rs, &["A", "B"], &[]);
5413}
5414
5415#[test]
5416fn test_recursive_derived_abstract_class_no_make_unique() {
5417 let hdr = indoc! {"
5418 class A {
5419 public:
5420 A() {}
5421 virtual ~A() {}
5422 virtual void foo() const = 0;
5423 };
5424
5425 class B : public A {
5426 public:
5427 B() {};
5428 };
5429
5430 class C : public B {
5431 public:
5432 C() {};
5433 };
5434 "};
5435 let rs = quote! {};
5436 run_test("", hdr, rs, &["A", "B", "C"], &[]);
5437}
5438
5439#[test]
5440fn test_derived_abstract_class_with_no_allowlisting_no_make_unique() {
5441 let hdr = indoc! {"
5442 class A {
5443 public:
5444 A();
5445 virtual ~A() {}
5446 virtual void foo() const = 0;
5447 };
5448
5449 class B : public A {
5450 public:
5451 B();
5452 };
5453 "};
5454 let rs = quote! {};
5455 run_test("", hdr, rs, &["B"], &[]);
5456}
5457
5458#[test]
5459fn test_vector_of_pointers() {
5460 // Just ensures the troublesome API is ignored
5461 let hdr = indoc! {"
5462 #include <vector>
5463 namespace operations_research {
5464 class a;
5465 class Solver {
5466 public:
5467 struct b c(std::vector<a *>);
5468 };
5469 class a {};
5470 } // namespace operations_research
5471 "};
5472 let rs = quote! {};
5473 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5474}
5475
5476#[test]
5477fn test_vec_and_up_of_primitives() {
5478 let hdr = indoc! {"
5479 #include <vector>
5480 #include <memory>
5481 #include <cstdint>
5482 class Value {
5483 public:
5484 Value(std::vector<uint32_t>) {} // OK
5485 Value(std::unique_ptr<uint32_t>) {} // should be ignored
5486 Value(std::vector<int>) {} // should be ignored
5487 Value(std::unique_ptr<int>) {} // should be ignored
5488 Value(std::vector<char>) {} // should be ignored
5489 Value(std::unique_ptr<char>) {} // should be ignored
5490 Value(std::vector<float>) {} // OK
5491 Value(std::unique_ptr<float>) {} // should be ignored
5492 Value(std::vector<bool>) {} // should be ignored
5493 Value(std::unique_ptr<bool>) {} // should be ignored
5494 Value(std::vector<size_t>) {} // OK
5495 Value(std::unique_ptr<size_t>) {} // should be ignored
5496 };
5497 inline std::vector<uint32_t> make_vec_uint32_t() {
5498 std::vector<uint32_t> a;
5499 return a;
5500 }
5501 inline std::vector<float> make_vec_float() {
5502 std::vector<float> a;
5503 return a;
5504 }
5505 inline std::vector<size_t> make_vec_size_t() {
5506 std::vector<size_t> a;
5507 return a;
5508 }
5509 "};
5510 let rs = quote! {
5511 ffi::Value::new(ffi::make_vec_uint32_t()).within_box();
5512 ffi::Value::new6(ffi::make_vec_float()).within_box();
5513 ffi::Value::new10(ffi::make_vec_size_t()).within_box();
5514 };
5515 run_test(
5516 "",
5517 hdr,
5518 rs,
5519 &[
5520 "Value",
5521 "make_vec_uint32_t",
5522 "make_vec_float",
5523 "make_vec_size_t",
5524 ],
5525 &[],
5526 );
5527}
5528
5529#[test]
5530fn test_pointer_to_pointer() {
5531 // Just ensures the troublesome API is ignored
5532 let hdr = indoc! {"
5533 namespace operations_research {
5534 class a;
5535 class Solver {
5536 public:
5537 struct b c(a **);
5538 };
5539 class a {};
5540 } // namespace operations_research
5541 "};
5542 let rs = quote! {};
5543 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5544}
5545
5546#[test]
5547fn test_defines_effective() {
5548 let hdr = indoc! {"
5549 #include <cstdint>
5550 #ifdef FOO
5551 inline uint32_t a() { return 4; }
5552 #endif
5553 "};
5554 let rs = quote! {
5555 ffi::a();
5556 };
5557 run_test_ex(
5558 "",
5559 hdr,
5560 rs,
5561 quote! { generate!("a") },
5562 make_clang_arg_adder(&["-DFOO"]),
5563 None,
5564 None,
5565 );
5566}
5567
5568#[test]
5569#[ignore] // https://github.com/google/autocxx/issues/227
5570fn test_function_pointer_template() {
5571 let hdr = indoc! {"
5572 typedef int a;
5573 namespace std {
5574 template <typename> class b;
5575 }
5576 typedef a c;
5577 namespace operations_research {
5578 class d;
5579 class Solver {
5580 public:
5581 typedef std::b<c()> IndexEvaluator3;
5582 d e(IndexEvaluator3);
5583 };
5584 class d {};
5585 } // namespace operations_research
5586 "};
5587 let rs = quote! {};
5588 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5589}
5590
5591#[test]
5592fn test_cvoid() {
5593 let hdr = indoc! {"
5594 #include <memory>
5595 #include <cstdint>
5596 inline void* a() {
5597 return static_cast<void*>(new int(3));
5598 }
5599 inline uint32_t b(void* p) {
5600 int* p_int = static_cast<int*>(p);
5601 auto val = *p_int;
5602 delete p_int;
5603 return val;
5604 }
5605 "};
5606 let rs = quote! {
5607 let ptr = ffi::a();
5608 let res = unsafe { ffi::b(ptr) };
5609 assert_eq!(res, 3);
5610 };
5611 run_test("", hdr, rs, &["a", "b"], &[]);
5612}
5613
5614#[test]
5615fn test_c_schar() {
5616 let hdr = indoc! {"
5617 inline signed char a() {
5618 return 8;
5619 }
5620 "};
5621 let rs = quote! {
5622 assert_eq!(ffi::a(), 8);
5623 };
5624 run_test("", hdr, rs, &["a"], &[]);
5625}
5626
5627#[test]
5628fn test_c_uchar() {
5629 let hdr = indoc! {"
5630 inline unsigned char a() {
5631 return 8;
5632 }
5633 "};
5634 let rs = quote! {
5635 assert_eq!(ffi::a(), 8);
5636 };
5637 run_test("", hdr, rs, &["a"], &[]);
5638}
5639
5640#[test]
5641fn test_c_ulonglong() {
5642 // We don't test all the different variable-length integer types which we populate.
5643 // If one works, they probably all do. Hopefully.
5644 let hdr = indoc! {"
5645 inline unsigned long long a() {
5646 return 8;
5647 }
5648 "};
5649 let rs = quote! {
5650 assert_eq!(ffi::a(), autocxx::c_ulonglong(8));
5651 };
5652 run_test("", hdr, rs, &["a"], &[]);
5653}
5654
5655#[test]
5656fn test_string_transparent_function() {
5657 let hdr = indoc! {"
5658 #include <string>
5659 #include <cstdint>
5660 inline uint32_t take_string(std::string a) { return a.size(); }
5661 "};
5662 let rs = quote! {
5663 assert_eq!(ffi::take_string("hello"), 5);
5664 };
5665 run_test("", hdr, rs, &["take_string"], &[]);
5666}
5667
5668#[test]
5669fn test_string_transparent_method() {
5670 let hdr = indoc! {"
5671 #include <string>
5672 #include <cstdint>
5673 struct A {
5674 A() {}
5675 inline uint32_t take_string(std::string a) const { return a.size(); }
5676 };
5677 "};
5678 let rs = quote! {
5679 let a = ffi::A::new().within_unique_ptr();
5680 assert_eq!(a.take_string("hello"), 5);
5681 };
5682 run_test("", hdr, rs, &["A"], &[]);
5683}
5684
5685#[test]
5686fn test_string_transparent_static_method() {
5687 let hdr = indoc! {"
5688 #include <string>
5689 #include <cstdint>
5690 struct A {
5691 A() {}
5692 static inline uint32_t take_string(std::string a) { return a.size(); }
5693 };
5694 "};
5695 let rs = quote! {
5696 assert_eq!(ffi::A::take_string("hello"), 5);
5697 };
5698 run_test("", hdr, rs, &["A"], &[]);
5699}
5700
5701#[test]
5702#[ignore] // https://github.com/google/autocxx/issues/490
5703fn test_issue_490() {
5704 let hdr = indoc! {"
5705 typedef int a;
5706 typedef long unsigned size_t;
5707 namespace std {
5708 namespace {
5709 using ::size_t;
5710 template <class b, b c> struct g { static const b value = c; };
5711 template <bool d> using e = g<bool, d>;
5712 typedef e<true> true_type;
5713 template <size_t, size_t> struct ag {};
5714 template <class b> typename b ::h move();
5715 template <class> class allocator;
5716 template <class> class vector;
5717 } // namespace
5718 } // namespace std
5719 void *operator new(size_t, void *);
5720 namespace std {
5721 namespace {
5722 template <class> struct iterator;
5723 template <class b, class> struct ay { using h = b *; };
5724 template <class b> struct bj { b bk; };
5725 template <class bm, class> class bn : bj<bm> {};
5726 template <class b, class i = b> class unique_ptr {
5727 typedef i bp;
5728 typedef typename ay<b, bp>::h bh;
5729 bn<bh, bp> bq;
5730
5731 public:
5732 unique_ptr();
5733 unique_ptr(bh);
5734 bh get() const;
5735 bh release();
5736 };
5737 template <class = void> struct bt;
5738 } // namespace
5739 } // namespace std
5740 typedef a bv;
5741 namespace absl {
5742 template <typename ce> class cj {
5743 public:
5744 using bh = ce *;
5745 using iterator = bh;
5746 };
5747 namespace j {
5748 template <class ce> struct cp {
5749 using k = ce;
5750 using cq = std::bt<>;
5751 };
5752 template <class ce> using cr = typename cp<ce>::k;
5753 template <class ce> using cs = typename cp<ce>::cq;
5754 template <class, class, class, class> class ct {
5755 public:
5756 class iterator {};
5757 class cu {
5758 cu(iterator);
5759 iterator cv;
5760 };
5761 };
5762 template <typename> struct cw;
5763 } // namespace j
5764 template <class ce, class k = j::cr<ce>, class cq = j::cs<ce>,
5765 class cx = std::allocator<ce>>
5766 class cy : public j::ct<j::cw<ce>, k, cq, cx> {};
5767 } // namespace absl
5768 namespace cz {
5769 template <typename da> class db { std::ag<sizeof(a), alignof(da)> c; };
5770 } // namespace cz
5771 namespace spanner {
5772 class l;
5773 class ColumnList {
5774 public:
5775 typedef absl::cj<l>::iterator iterator;
5776 iterator begin();
5777 };
5778 class dd {
5779 union {
5780 cz::db<absl::cy<bv>::cu> e;
5781 };
5782 };
5783 class Row {
5784 public:
5785 bool f(dd);
5786 };
5787 } // namespace spanner
5788 "};
5789 let rs = quote! {};
5790 run_test("", hdr, rs, &["spanner::Row", "spanner::ColumnList"], &[]);
5791}
5792
5793#[test]
5794fn test_immovable_object() {
5795 let hdr = indoc! {"
5796 class A {
5797 public:
5798 A();
5799 A(A&&) = delete;
5800 };
5801
5802 class B{
5803 public:
5804 B();
5805 B(const B&) = delete;
5806 };
5807 "};
5808 let rs = quote! {};
5809 run_test("", hdr, rs, &["A", "B"], &[]);
5810}
5811
5812#[test]
5813fn test_struct_with_reference() {
5814 let hdr = indoc! {"
5815 #include <cstdint>
5816 #include <utility>
5817 struct A {
5818 uint32_t a;
5819 };
5820 struct B {
5821 B(const A& param) : a(param) {}
5822 const A& a;
5823 };
5824 "};
5825 let rs = quote! {};
5826 run_test("", hdr, rs, &["A", "B"], &[]);
5827}
5828
5829#[test]
5830fn test_struct_with_rvalue() {
5831 let hdr = indoc! {"
5832 #include <cstdint>
5833 #include <utility>
5834 struct A {
5835 uint32_t a;
5836 };
5837 struct B {
5838 B(A&& param) : a(std::move(param)) {}
5839 A&& a;
5840 };
5841 "};
5842 let rs = quote! {};
5843 run_test("", hdr, rs, &["A", "B"], &[]);
5844}
5845
5846#[test]
5847fn test_immovable_nested_object() {
5848 let hdr = indoc! {"
5849 struct C {
5850 class A {
5851 public:
5852 A();
5853 A(A&&) = delete;
5854 };
5855
5856 class B{
5857 public:
5858 B();
5859 B(const B&) = delete;
5860 };
5861 };
5862 "};
5863 let rs = quote! {};
5864 run_test("", hdr, rs, &["C_A", "C_B"], &[]);
5865}
5866
5867#[test]
5868fn test_type_called_type() {
5869 let hdr = indoc! {"
5870 namespace a {
5871 template<int _Len>
5872 struct b
5873 {
5874 union type
5875 {
5876 unsigned char __data[_Len];
5877 struct foo {
5878 int a;
5879 };
5880 };
5881 };
5882 }
5883 inline void take_type(a::b<4>::type) {}
5884 "};
5885 let rs = quote! {};
5886 run_test("", hdr, rs, &["take_type"], &[]);
5887}
5888
5889#[test]
5890fn test_bridge_conflict_ty() {
5891 let hdr = indoc! {"
5892 namespace a {
5893 struct Key { int a; };
5894 }
5895 namespace b {
5896 struct Key { int a; };
5897 }
5898 "};
5899 let rs = quote! {};
5900 run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
5901}
5902
5903#[test]
5904fn test_bridge_conflict_ty_fn() {
5905 let hdr = indoc! {"
5906 namespace a {
5907 struct Key { int a; };
5908 }
5909 namespace b {
5910 inline void Key() {}
5911 }
5912 "};
5913 let rs = quote! {};
5914 run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
5915}
5916
5917#[test]
5918fn test_issue_506() {
5919 let hdr = indoc! {"
5920 namespace std {
5921 template <class, class> class am;
5922 typedef am<char, char> an;
5923 } // namespace std
5924 namespace be {
5925 class bf {
5926 virtual std::an bg() = 0;
5927 };
5928 class bh : bf {};
5929 } // namespace be
5930 namespace spanner {
5931 class Database;
5932 class Row {
5933 public:
5934 Row(be::bh *);
5935 };
5936 } // namespace spanner
5937 "};
5938 let rs = quote! {};
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07005939 run_test_ex(
5940 "",
5941 hdr,
5942 rs,
5943 directives_from_lists(&["spanner::Database", "spanner::Row"], &[], None),
5944 // This is normally a valid warning for generating bindings for this code, but we're doing
5945 // it on purpose as a regression test on minimized code so we'll just ignore it.
5946 make_clang_optional_arg_adder(&[], &["-Wno-delete-abstract-non-virtual-dtor"]),
5947 None,
5948 None,
5949 );
Brian Silverman4e662aa2022-05-11 23:10:19 -07005950}
5951
5952#[test]
5953fn test_private_inheritance() {
5954 let hdr = indoc! {"
5955 class A {
5956 public:
5957 void foo() {}
5958 int a;
5959 };
5960 class B : A {
5961 public:
5962 void bar() {}
5963 int b;
5964 };
5965 "};
5966 let rs = quote! {};
5967 run_test("", hdr, rs, &["A", "B"], &[]);
5968}
5969
5970#[test]
5971fn test_error_generated_for_static_data() {
5972 let hdr = indoc! {"
5973 #include <cstdint>
5974 struct A {
5975 A() {}
5976 uint32_t a;
5977 };
5978 static A FOO = A();
5979 "};
5980 let rs = quote! {};
5981 run_test_ex(
5982 "",
5983 hdr,
5984 rs,
5985 quote! { generate!("FOO")},
5986 None,
5987 Some(make_error_finder("FOO")),
5988 None,
5989 );
5990}
5991
5992#[test]
5993fn test_error_generated_for_array_dependent_function() {
5994 let hdr = indoc! {"
5995 #include <cstdint>
5996 #include <functional>
5997 inline void take_func(std::function<bool(const uint32_t number)>) {
5998 }
5999 "};
6000 let rs = quote! {};
6001 run_test_ex(
6002 "",
6003 hdr,
6004 rs,
6005 quote! { generate! ("take_func")},
6006 None,
6007 Some(make_error_finder("take_func")),
6008 None,
6009 );
6010}
6011
6012#[test]
6013#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
6014#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
6015fn test_error_generated_for_array_dependent_method() {
6016 let hdr = indoc! {"
6017 #include <cstdint>
6018 #include <functional>
6019 struct A {
6020 void take_func(std::function<bool(const uint32_t number)>) {
6021 }
6022 };
6023 "};
6024 let rs = quote! {};
6025 run_test_ex(
6026 "",
6027 hdr,
6028 rs,
6029 quote! { generate! ("A")},
6030 None,
6031 Some(make_string_finder(
6032 ["take_func", "couldn't be generated"]
6033 .map(|s| s.to_string())
6034 .to_vec(),
6035 )),
6036 None,
6037 );
6038}
6039
6040#[test]
6041fn test_error_generated_for_pod_with_nontrivial_destructor() {
6042 // take_a is necessary here because cxx won't generate the required
6043 // static assertions unless the type is actually used in some context
6044 // where cxx needs to decide it's trivial or non-trivial.
6045 let hdr = indoc! {"
6046 #include <cstdint>
6047 #include <functional>
6048 struct A {
6049 ~A() {}
6050 };
6051 inline void take_a(A) {}
6052 "};
6053 let rs = quote! {};
6054 run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
6055}
6056
6057#[test]
6058fn test_error_generated_for_pod_with_nontrivial_move_constructor() {
6059 // take_a is necessary here because cxx won't generate the required
6060 // static assertions unless the type is actually used in some context
6061 // where cxx needs to decide it's trivial or non-trivial.
6062 let hdr = indoc! {"
6063 #include <cstdint>
6064 #include <functional>
6065 struct A {
6066 A() = default;
6067 A(A&&) {}
6068 };
6069 inline void take_a(A) {}
6070 "};
6071 let rs = quote! {};
6072 run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
6073}
6074
6075#[test]
6076fn test_double_destruction() {
6077 let hdr = indoc! {"
6078 #include <stdio.h>
6079 #include <stdlib.h>
6080 // A simple type to let Rust verify the destructor is run.
6081 struct NotTriviallyDestructible {
6082 NotTriviallyDestructible() = default;
6083 NotTriviallyDestructible(const NotTriviallyDestructible&) = default;
6084 NotTriviallyDestructible(NotTriviallyDestructible&&) = default;
6085
6086 ~NotTriviallyDestructible() {}
6087 };
6088
6089 struct ExplicitlyDefaulted {
6090 ExplicitlyDefaulted() = default;
6091 ~ExplicitlyDefaulted() = default;
6092
6093 NotTriviallyDestructible flag;
6094 };
6095 "};
6096 let rs = quote! {
6097 moveit! {
6098 let mut moveit_t = ffi::ExplicitlyDefaulted::new();
6099 }
6100 };
6101 match do_run_test(
6102 "",
6103 hdr,
6104 rs,
6105 directives_from_lists(
6106 &[],
6107 &["NotTriviallyDestructible", "ExplicitlyDefaulted"],
6108 None,
6109 ),
6110 None,
6111 None,
6112 None,
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006113 "unsafe_ffi",
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07006114 None,
Brian Silverman4e662aa2022-05-11 23:10:19 -07006115 ) {
6116 Err(TestError::CppBuild(_)) => {} // be sure this fails due to a static_assert
6117 // rather than some runtime problem
6118 _ => panic!("Test didn't fail as expected"),
6119 };
6120}
6121
6122#[test]
6123fn test_keyword_function() {
6124 let hdr = indoc! {"
6125 inline void move(int) {};
6126 "};
6127 let rs = quote! {};
6128 run_test("", hdr, rs, &["move_"], &[]);
6129}
6130
6131#[test]
6132fn test_keyword_method() {
6133 let hdr = indoc! {"
6134 struct A {
6135 int a;
6136 inline void move() {};
6137 };
6138 "};
6139 let rs = quote! {};
6140 run_test("", hdr, rs, &["A"], &[]);
6141}
6142
6143#[test]
6144fn test_doc_passthru() {
6145 let hdr = indoc! {"
6146 #include <cstdint>
6147 /// Elephants!
6148 struct A {
6149 uint32_t a;
6150 };
6151 /// Giraffes!
6152 struct B {
6153 uint32_t a;
6154 };
6155 /// Rhinos!
6156 inline uint32_t get_a() { return 3; }
6157 "};
6158 let rs = quote! {};
6159 run_test_ex(
6160 "",
6161 hdr,
6162 rs,
6163 directives_from_lists(&["A", "get_a"], &["B"], None),
6164 None,
6165 Some(make_string_finder(
6166 ["Giraffes", "Elephants", "Rhinos"]
6167 .map(|s| s.to_string())
6168 .to_vec(),
6169 )),
6170 None,
6171 );
6172}
6173
6174#[test]
6175fn test_closure() {
6176 // Ensuring presence of this closure doesn't break other things
6177 let hdr = indoc! {"
6178 #include <functional>
6179 #include <cstdint>
6180
6181 inline bool take_closure(std::function<bool(const uint32_t number)> fn) {
6182 return fn(5);
6183 }
6184 inline uint32_t get_a() {
6185 return 3;
6186 }
6187 "};
6188 let rs = quote! {
6189 assert_eq!(ffi::get_a(), 3);
6190 };
6191 run_test("", hdr, rs, &["get_a"], &[]);
6192}
6193
6194#[test]
6195fn test_multiply_nested_inner_type() {
6196 let hdr = indoc! {"
6197 struct Turkey {
6198 struct Duck {
6199 struct Hen {
6200 int wings;
6201 };
6202 struct HenWithDefault {
6203 HenWithDefault() = default;
6204 int wings;
6205 };
6206 struct HenWithDestructor {
6207 ~HenWithDestructor() = default;
6208 int wings;
6209 };
6210 struct HenWithCopy {
6211 HenWithCopy() = default;
6212 HenWithCopy(const HenWithCopy&) = default;
6213 int wings;
6214 };
6215 struct HenWithMove {
6216 HenWithMove() = default;
6217 HenWithMove(HenWithMove&&) = default;
6218 int wings;
6219 };
6220 };
6221 };
6222 "};
6223 let rs = quote! {
6224 ffi::Turkey_Duck_Hen::new().within_unique_ptr();
6225 ffi::Turkey_Duck_HenWithDefault::new().within_unique_ptr();
6226 ffi::Turkey_Duck_HenWithDestructor::new().within_unique_ptr();
6227 ffi::Turkey_Duck_HenWithCopy::new().within_unique_ptr();
6228 ffi::Turkey_Duck_HenWithMove::new().within_unique_ptr();
6229
6230 moveit! {
6231 let hen = ffi::Turkey_Duck_Hen::new();
6232 let moved_hen = autocxx::moveit::new::mov(hen);
6233 let _copied_hen = autocxx::moveit::new::copy(moved_hen);
6234
6235 let hen = ffi::Turkey_Duck_HenWithDefault::new();
6236 let moved_hen = autocxx::moveit::new::mov(hen);
6237 let _copied_hen = autocxx::moveit::new::copy(moved_hen);
6238
6239 let _hen = ffi::Turkey_Duck_HenWithDestructor::new();
6240
6241 let hen = ffi::Turkey_Duck_HenWithCopy::new();
6242 let _copied_hen = autocxx::moveit::new::copy(hen);
6243
6244 let hen = ffi::Turkey_Duck_HenWithMove::new();
6245 let _moved_hen = autocxx::moveit::new::mov(hen);
6246 }
6247 };
6248 run_test(
6249 "",
6250 hdr,
6251 rs,
6252 &[],
6253 &[
6254 "Turkey_Duck_Hen",
6255 "Turkey_Duck_HenWithDefault",
6256 "Turkey_Duck_HenWithDestructor",
6257 "Turkey_Duck_HenWithCopy",
6258 "Turkey_Duck_HenWithMove",
6259 ],
6260 );
6261}
6262
6263#[test]
6264fn test_underscored_namespace_for_inner_type() {
6265 let hdr = indoc! {"
6266 namespace __foo {
6267 struct daft {
6268 struct bob {
6269 int a;
6270 };
6271 int a;
6272 };
6273 }
6274 inline void bar(__foo::daft::bob) {}
6275 "};
6276 let rs = quote! {};
6277 run_test("", hdr, rs, &["bar"], &[]);
6278}
6279
6280#[test]
6281fn test_blocklist_not_overly_broad() {
6282 // This is a regression test. We used to block anything that starts with "rust" or "std",
6283 // not just items in the "rust" and "std" namespaces. We therefore test that functions starting
6284 // with "rust" or "std" get imported.
6285 let hdr = indoc! {"
6286 inline void rust_func() { }
6287 inline void std_func() { }
6288 "};
6289 let rs = quote! {
6290 ffi::rust_func();
6291 ffi::std_func();
6292 };
6293 run_test("", hdr, rs, &["rust_func", "std_func"], &[]);
6294}
6295
6296#[test]
6297#[ignore] // https://github.com/google/autocxx/issues/837
6298fn test_ref_qualified_method() {
6299 let hdr = indoc! {"
6300 struct A {
6301 void foo() & {}
6302 };
6303 "};
6304 let rs = quote! {
6305 A::new().within_unique_ptr().foo();
6306 };
6307 run_test("", hdr, rs, &["A"], &[]);
6308}
6309
6310#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
6311#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
6312#[test]
6313fn test_stringview() {
6314 // Test that APIs using std::string_view do not otherwise cause errors.
6315 let hdr = indoc! {"
6316 #include <string_view>
6317 #include <string>
6318 void take_string_view(std::string_view) {}
6319 std::string_view return_string_view(const std::string& a) { return std::string_view(a); }
6320 "};
6321 let rs = quote! {};
6322 run_test_ex(
6323 "",
6324 hdr,
6325 rs,
6326 directives_from_lists(&["take_string_view", "return_string_view"], &[], None),
6327 make_cpp17_adder(),
6328 None,
6329 None,
6330 );
6331}
6332
6333#[test]
6334fn test_include_cpp_alone() {
6335 let hdr = indoc! {"
6336 #include <cstdint>
6337 inline uint32_t give_int() {
6338 return 5;
6339 }
6340 "};
6341 let hexathorpe = Token![#](Span::call_site());
6342 let rs = quote! {
6343 use autocxx::include_cpp;
6344 include_cpp! {
6345 #hexathorpe include "input.h"
6346 safety!(unsafe_ffi)
6347 generate!("give_int")
6348 }
6349 fn main() {
6350 assert_eq!(ffi::give_int(), 5);
6351 }
6352 };
6353 do_run_test_manual("", hdr, rs, None, None).unwrap();
6354}
6355
6356#[test]
6357fn test_include_cpp_in_path() {
6358 let hdr = indoc! {"
6359 #include <cstdint>
6360 inline uint32_t give_int() {
6361 return 5;
6362 }
6363 "};
6364 let hexathorpe = Token![#](Span::call_site());
6365 let rs = quote! {
6366 autocxx::include_cpp! {
6367 #hexathorpe include "input.h"
6368 safety!(unsafe_ffi)
6369 generate!("give_int")
6370 }
6371 fn main() {
6372 assert_eq!(ffi::give_int(), 5);
6373 }
6374 };
6375 do_run_test_manual("", hdr, rs, None, None).unwrap();
6376}
6377
6378#[test]
6379fn test_bitset() {
6380 let hdr = indoc! {"
6381 #include <cstddef>
6382 template <size_t _N_words, size_t _Size>
6383 class __bitset
6384 {
6385 public:
6386 typedef size_t __storage_type;
6387 __storage_type __first_[_N_words];
6388 inline bool all() {
6389 return false;
6390 }
6391 };
6392
6393 template <size_t _Size>
6394 class bitset
6395 : private __bitset<_Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1, _Size>
6396 {
6397 public:
6398 static const unsigned __n_words = _Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1;
6399 typedef __bitset<__n_words, _Size> base;
6400 bool all() const noexcept;
6401 };
6402
6403
6404 typedef bitset<1> mybitset;
6405 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006406 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006407}
6408
6409#[test]
6410fn test_cint_vector() {
6411 let hdr = indoc! {"
6412 #include <vector>
6413 #include <cstdint>
6414 inline std::vector<int32_t> give_vec() {
6415 return std::vector<int32_t> {1,2};
6416 }
6417 "};
6418
6419 let rs = quote! {
6420 assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[1,2]);
6421 };
6422
6423 run_test("", hdr, rs, &["give_vec"], &[]);
6424}
6425
6426#[test]
6427#[ignore] // https://github.com/google/autocxx/issues/422
6428fn test_int_vector() {
6429 let hdr = indoc! {"
6430 #include <vector>
6431 std::vector<int> give_vec() {
6432 return std::vector<int> {1,2};
6433 }
6434 "};
6435
6436 let rs = quote! {
6437 assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]);
6438 };
6439
6440 run_test("", hdr, rs, &["give_vec"], &[]);
6441}
6442
6443#[test]
6444fn test_size_t() {
6445 let hdr = indoc! {"
6446 #include <cstddef>
6447 inline size_t get_count() { return 7; }
6448 "};
6449
6450 let rs = quote! {
6451 ffi::get_count();
6452 };
6453
6454 run_test_ex(
6455 "",
6456 hdr,
6457 rs,
6458 directives_from_lists(&["get_count"], &[], None),
6459 None,
6460 Some(make_rust_code_finder(vec![
6461 quote! {fn get_count() -> usize},
6462 ])),
6463 None,
6464 );
6465}
6466
6467#[test]
6468fn test_deleted_function() {
6469 // We shouldn't generate bindings for deleted functions.
6470 // The test is successful if the bindings compile, i.e. if autocxx doesn't
6471 // attempt to call the deleted function.
6472 let hdr = indoc! {"
6473 class A {
6474 public:
6475 void foo() = delete;
6476 };
6477 "};
6478 let rs = quote! {};
6479 run_test("", hdr, rs, &["A"], &[]);
6480}
6481
6482#[test]
6483fn test_ignore_move_constructor() {
6484 let hdr = indoc! {"
6485 class A {
6486 public:
6487 A() {}
6488 A(A&&) {};
6489 };
6490 "};
6491 let rs = quote! {};
6492 run_test("", hdr, rs, &["A"], &[]);
6493}
6494
6495#[test]
6496fn test_ignore_function_with_rvalue_ref() {
6497 let hdr = indoc! {"
6498 #include <string>
6499
6500 void moveme(std::string &&);
6501 "};
6502 let rs = quote! {};
6503 run_test("", hdr, rs, &["moveme"], &[]);
6504}
6505
6506#[test]
6507fn test_take_nonpod_rvalue_from_up() {
6508 let hdr = indoc! {"
6509 #include <string>
6510 struct A {
6511 std::string a;
6512 };
6513 inline void take_a(A&&) {};
6514 "};
6515 let rs = quote! {
6516 let a = ffi::A::new().within_unique_ptr();
6517 ffi::take_a(a);
6518
6519 let a2 = ffi::A::new().within_box();
6520 ffi::take_a(a2);
6521 };
6522 run_test("", hdr, rs, &["A", "take_a"], &[]);
6523}
6524
6525#[test]
6526fn test_take_nonpod_rvalue_from_stack() {
6527 let hdr = indoc! {"
6528 #include <string>
6529 struct A {
6530 std::string a;
6531 };
6532 inline void take_a(A&&) {};
6533 "};
6534 let rs = quote! {
6535 moveit! { let a = ffi::A::new() };
6536 ffi::take_a(a);
6537 };
6538 run_test("", hdr, rs, &["A", "take_a"], &[]);
6539}
6540
6541#[test]
6542fn test_overloaded_ignored_function() {
6543 // When overloaded functions are ignored during import, the placeholder
6544 // functions generated for them should have unique names, just as they
6545 // would have if they had been imported successfully.
6546 // The test is successful if the bindings compile.
6547 let hdr = indoc! {"
6548 struct Blocked {};
6549 class A {
6550 public:
6551 void take_blocked(Blocked);
6552 void take_blocked(Blocked, int);
6553 };
6554 "};
6555 let rs = quote! {};
6556 run_test_ex(
6557 "",
6558 hdr,
6559 rs,
6560 quote! {
6561 generate!("A")
6562 block!("Blocked")
6563 },
6564 None,
6565 None,
6566 None,
6567 );
6568}
6569
6570#[test]
6571fn test_namespaced_constant() {
6572 let hdr = indoc! {"
6573 namespace A {
6574 const int kConstant = 3;
6575 }
6576 "};
6577 let rs = quote! {
6578 assert_eq!(ffi::A::kConstant, 3);
6579 };
6580 run_test("", hdr, rs, &["A::kConstant"], &[]);
6581}
6582
6583#[test]
6584fn test_issue_470_492() {
6585 let hdr = indoc! {"
6586 namespace std {
6587 template <bool, typename _Iftrue, typename _Iffalse> struct a;
6588 }
6589 template <typename> struct b;
6590 template <typename d> struct c {
6591 typedef std::a<b<d>::c, int, int> e;
6592 };
6593 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006594 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006595}
6596
6597#[test]
6598fn test_no_impl() {
6599 let hdr = indoc! {"
6600 struct A {
6601 int a;
6602 };
6603 "};
6604 let rs = quote! {};
6605 run_test_ex(
6606 "",
6607 hdr,
6608 rs,
6609 quote! {
6610 exclude_impls!()
6611 exclude_utilities!()
6612 generate!("A")
6613 },
6614 None,
6615 None,
6616 None,
6617 );
6618}
6619
6620#[test]
6621fn test_generate_all() {
6622 let hdr = indoc! {"
6623 #include <cstdint>
6624 inline uint32_t give_int() {
6625 return 5;
6626 }
6627 "};
6628 let rs = quote! {
6629 assert_eq!(ffi::give_int(), 5);
6630 };
6631 run_test_ex(
6632 "",
6633 hdr,
6634 rs,
6635 quote! {
6636 generate_all!()
6637 },
6638 None,
6639 None,
6640 None,
6641 );
6642}
6643
6644#[test]
6645fn test_std_thing() {
6646 let hdr = indoc! {"
6647 #include <cstdint>
6648 namespace std {
6649 struct A {
6650 uint8_t a;
6651 };
6652 }
6653 typedef char daft;
6654 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006655 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006656}
6657
6658#[test]
6659fn test_two_mods() {
6660 let hdr = indoc! {"
6661 #include <cstdint>
6662 struct A {
6663 uint32_t a;
6664 };
6665 inline A give_a() {
6666 A a;
6667 a.a = 5;
6668 return a;
6669 }
6670 inline uint32_t get_a(A a) {
6671 return a.a;
6672 }
6673 struct B {
6674 uint32_t a;
6675 };
6676 inline B give_b() {
6677 B a;
6678 a.a = 8;
6679 return a;
6680 }
6681 inline uint32_t get_b(B a) {
6682 return a.a;
6683 }
6684 "};
6685 let hexathorpe = Token![#](Span::call_site());
6686 let rs = quote! {
6687 use autocxx::prelude::*;
6688 include_cpp! {
6689 #hexathorpe include "input.h"
6690 safety!(unsafe_ffi)
6691 generate!("give_a")
6692 generate!("get_a")
6693 }
6694 include_cpp! {
6695 #hexathorpe include "input.h"
6696 name!(ffi2)
6697 generate!("give_b")
6698 generate!("get_b")
6699 }
6700 fn main() {
6701 let a = ffi::give_a().within_unique_ptr();
6702 assert_eq!(ffi::get_a(a), 5);
6703 let b = unsafe { ffi2::give_b().within_unique_ptr() };
6704 assert_eq!(unsafe { ffi2::get_b(b) }, 8);
6705 }
6706 };
6707 do_run_test_manual("", hdr, rs, None, None).unwrap();
6708}
6709
6710#[test]
6711fn test_manual_bridge() {
6712 let hdr = indoc! {"
6713 #include <cstdint>
6714 inline uint32_t give_int() {
6715 return 5;
6716 }
6717 inline uint32_t give_int2() {
6718 return 5;
6719 }
6720 "};
6721 let hexathorpe = Token![#](Span::call_site());
6722 let rs = quote! {
6723 autocxx::include_cpp! {
6724 #hexathorpe include "input.h"
6725 safety!(unsafe_ffi)
6726 generate!("give_int")
6727 }
6728 #[cxx::bridge]
6729 mod ffi2 {
6730 unsafe extern "C++" {
6731 include!("input.h");
6732 fn give_int2() -> u32;
6733 }
6734 }
6735 fn main() {
6736 assert_eq!(ffi::give_int(), 5);
6737 assert_eq!(ffi2::give_int2(), 5);
6738 }
6739 };
6740 do_run_test_manual("", hdr, rs, None, None).unwrap();
6741}
6742
6743#[test]
6744fn test_manual_bridge_mixed_types() {
6745 let hdr = indoc! {"
6746 #include <memory>
6747 struct A {
6748 int a;
6749 };
6750 inline int take_A(const A& a) {
6751 return a.a;
6752 }
6753 inline std::unique_ptr<A> give_A() {
6754 auto a = std::make_unique<A>();
6755 a->a = 5;
6756 return a;
6757 }
6758 "};
6759 let hexathorpe = Token![#](Span::call_site());
6760 let rs = quote! {
6761 use autocxx::prelude::*;
6762 autocxx::include_cpp! {
6763 #hexathorpe include "input.h"
6764 safety!(unsafe_ffi)
6765 generate!("take_A")
6766 generate!("A")
6767 }
6768 #[cxx::bridge]
6769 mod ffi2 {
6770 unsafe extern "C++" {
6771 include!("input.h");
6772 type A = crate::ffi::A;
6773 fn give_A() -> UniquePtr<A>;
6774 }
6775 }
6776 fn main() {
6777 let a = ffi2::give_A();
6778 assert_eq!(ffi::take_A(&a), autocxx::c_int(5));
6779 }
6780 };
6781 do_run_test_manual("", hdr, rs, None, None).unwrap();
6782}
6783
6784#[test]
6785fn test_extern_cpp_type_cxx_bridge() {
6786 let hdr = indoc! {"
6787 #include <cstdint>
6788 struct A {
6789 A() : a(0) {}
6790 int a;
6791 };
6792 inline void handle_a(const A&) {
6793 }
6794 inline A create_a() {
6795 A a;
6796 return a;
6797 }
6798 "};
6799 let hexathorpe = Token![#](Span::call_site());
6800 let rs = quote! {
6801 use autocxx::prelude::*;
6802 include_cpp! {
6803 #hexathorpe include "input.h"
6804 safety!(unsafe_ffi)
6805 generate!("handle_a")
6806 generate!("create_a")
6807 extern_cpp_opaque_type!("A", crate::ffi2::A)
6808 }
6809 #[cxx::bridge]
6810 pub mod ffi2 {
6811 unsafe extern "C++" {
6812 include!("input.h");
6813 type A;
6814 }
6815 impl UniquePtr<A> {}
6816 }
6817 fn main() {
6818 let a = ffi::create_a();
6819 ffi::handle_a(&a);
6820 }
6821 };
6822 do_run_test_manual("", hdr, rs, None, None).unwrap();
6823}
6824
6825#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07006826fn test_extern_cpp_type_different_name() {
6827 let hdr = indoc! {"
6828 #include <cstdint>
6829 struct A {
6830 A() : a(0) {}
6831 int a;
6832 };
6833 inline void handle_a(const A&) {
6834 }
6835 inline A create_a() {
6836 A a;
6837 return a;
6838 }
6839 "};
6840 let hexathorpe = Token![#](Span::call_site());
6841 let rs = quote! {
6842 use autocxx::prelude::*;
6843 include_cpp! {
6844 #hexathorpe include "input.h"
6845 safety!(unsafe_ffi)
6846 generate!("handle_a")
6847 generate!("create_a")
6848 extern_cpp_opaque_type!("A", crate::DifferentA)
6849 }
6850 #[cxx::bridge]
6851 pub mod ffi2 {
6852 unsafe extern "C++" {
6853 include!("input.h");
6854 type A;
6855 }
6856 impl UniquePtr<A> {}
6857 }
6858 pub use ffi2::A as DifferentA;
6859 fn main() {
6860 let a = ffi::create_a();
6861 ffi::handle_a(&a);
6862 }
6863 };
6864 do_run_test_manual("", hdr, rs, None, None).unwrap();
6865}
6866
6867#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07006868fn test_extern_cpp_type_two_include_cpp() {
6869 let hdr = indoc! {"
6870 #include <cstdint>
6871 struct A {
6872 A() : a(0) {}
6873 int a;
6874 };
6875 enum B {
6876 VARIANT,
6877 };
6878 inline void handle_a(const A&) {
6879 }
6880 inline A create_a(B) {
6881 A a;
6882 return a;
6883 }
6884 "};
6885 let hexathorpe = Token![#](Span::call_site());
6886 let rs = quote! {
6887 pub mod base {
6888 autocxx::include_cpp! {
6889 #hexathorpe include "input.h"
6890 name!(ffi2)
6891 safety!(unsafe_ffi)
6892 generate!("A")
6893 generate!("B")
6894 }
6895 pub use ffi2::*;
6896 }
6897 pub mod dependent {
6898 autocxx::include_cpp! {
6899 #hexathorpe include "input.h"
6900 safety!(unsafe_ffi)
6901 generate!("handle_a")
6902 generate!("create_a")
6903 extern_cpp_type!("A", crate::base::A)
6904 extern_cpp_type!("B", super::super::base::B)
6905 pod!("B")
6906 }
6907 pub use ffi::*;
6908 }
6909 fn main() {
6910 use autocxx::prelude::*;
6911 let a = dependent::create_a(base::B::VARIANT).within_box();
6912 dependent::handle_a(&a);
6913 }
6914 };
6915 do_run_test_manual("", hdr, rs, None, None).unwrap();
6916}
6917
6918#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006919/// Tests extern_cpp_type with a type inside a namespace.
6920fn test_extern_cpp_type_namespace() {
6921 let hdr = indoc! {"
6922 #include <cstdint>
6923 namespace b {
6924 struct B {
6925 B() {}
6926 };
6927 } // namespace b
6928 struct A {
6929 A() {}
6930 b::B make_b() { return b::B(); }
6931 };
6932 "};
6933 let hexathorpe = Token![#](Span::call_site());
6934 let rs = quote! {
6935 pub mod b {
6936 autocxx::include_cpp! {
6937 #hexathorpe include "input.h"
6938 safety!(unsafe_ffi)
6939 name!(ffi_b)
6940 generate_pod!("b::B")
6941 }
6942 pub use ffi_b::b::B;
6943 }
6944 pub mod a {
6945 autocxx::include_cpp! {
6946 #hexathorpe include "input.h"
6947 safety!(unsafe_ffi)
6948 name!(ffi_a)
6949 generate_pod!("A")
6950 extern_cpp_type!("b::B", crate::b::B)
6951 }
6952 pub use ffi_a::A;
6953 }
6954 fn main() {
6955 use autocxx::prelude::*;
6956 let _ = crate::a::A::new().within_unique_ptr().as_mut().unwrap().make_b();
6957 }
6958 };
6959 do_run_test_manual("", hdr, rs, None, None).unwrap();
6960}
6961
6962#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07006963#[ignore] // because we currently require UniquePtrTarget which this can't implement
6964fn test_extern_cpp_type_manual() {
6965 let hdr = indoc! {"
6966 #include <cstdint>
6967 struct A {
6968 int a;
6969 };
6970 inline void handle_a(const A& a) {
6971 }
6972 inline A create_a() {
6973 A a;
6974 return a;
6975 }
6976 "};
6977 let hexathorpe = Token![#](Span::call_site());
6978 let rs = quote! {
6979 autocxx::include_cpp! {
6980 #hexathorpe include "input.h"
6981 safety!(unsafe_ffi)
6982 generate!("handle_a")
6983 generate!("create_a")
6984 extern_cpp_type!("A", crate::ffi2::A)
6985 }
6986 pub mod ffi2 {
6987 use autocxx::cxx::{type_id, ExternType};
6988 #[repr(C)]
6989 pub struct A {
6990 a: std::os::raw::c_int
6991 }
6992 unsafe impl ExternType for A {
6993 type Kind = autocxx::cxx::kind::Opaque;
6994 type Id = type_id!("A");
6995 }
6996
6997 }
6998 fn main() {
6999 let a = ffi2::A { a: 3 };
7000 ffi::handle_a(&a);
7001 }
7002 };
7003 do_run_test_manual("", hdr, rs, None, None).unwrap();
7004}
7005
7006#[test]
7007fn test_issue486() {
7008 let hdr = indoc! {"
7009 namespace a {
7010 namespace spanner {
7011 class Key;
7012 }
7013 } // namespace a
7014 namespace spanner {
7015 class Key {
7016 public:
7017 bool b(a::spanner::Key &);
7018 };
7019 } // namespace spanner
7020 "};
7021 let rs = quote! {};
7022 run_test("", hdr, rs, &["spanner::Key"], &[]);
7023}
7024
7025#[test]
7026#[ignore]
7027fn test_issue616() {
7028 let hdr = indoc! {"
7029 namespace N {
7030 template <typename> class B{};
7031 template <typename c> class C {
7032 public:
7033 using U = B<c>;
7034 };
7035 }
7036 class A : N::C<A> {
7037 U u;
7038 };
7039 "};
7040 let rs = quote! {};
7041 run_test("", hdr, rs, &["A"], &[]);
7042}
7043
7044#[test]
7045fn test_shared_ptr() {
7046 let hdr = indoc! {"
7047 #include <memory>
7048 struct A {
7049 int a;
7050 };
7051 inline std::shared_ptr<A> make_shared_int() {
7052 return std::make_shared<A>(A { 3 });
7053 }
7054 inline int take_shared_int(std::shared_ptr<A> a) {
7055 return a->a;
7056 }
7057 inline std::weak_ptr<A> shared_to_weak(std::shared_ptr<A> a) {
7058 return std::weak_ptr<A>(a);
7059 }
7060 "};
7061 let rs = quote! {
7062 let a = ffi::make_shared_int();
7063 assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
7064 ffi::shared_to_weak(a).upgrade();
7065 };
7066 run_test(
7067 "",
7068 hdr,
7069 rs,
7070 &["make_shared_int", "take_shared_int", "shared_to_weak"],
7071 &[],
7072 );
7073}
7074
7075#[test]
7076#[ignore] // https://github.com/google/autocxx/issues/799
7077fn test_shared_ptr_const() {
7078 let hdr = indoc! {"
7079 #include <memory>
7080 inline std::shared_ptr<const int> make_shared_int() {
7081 return std::make_shared<const int>(3);
7082 }
7083 inline int take_shared_int(std::shared_ptr<const int> a) {
7084 return *a;
7085 }
7086 "};
7087 let rs = quote! {
7088 let a = ffi::make_shared_int();
7089 assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
7090 };
7091 run_test("", hdr, rs, &["make_shared_int", "take_shared_int"], &[]);
7092}
7093
7094#[test]
7095fn test_rust_reference() {
7096 let hdr = indoc! {"
7097 #include <cstdint>
7098
7099 struct RustType;
7100 inline uint32_t take_rust_reference(const RustType&) {
7101 return 4;
7102 }
7103 "};
7104 let rs = quote! {
7105 let foo = RustType(3);
7106 assert_eq!(ffi::take_rust_reference(&foo), 4);
7107 };
7108 run_test_ex(
7109 "",
7110 hdr,
7111 rs,
7112 quote! {
7113 generate!("take_rust_reference")
7114 extern_rust_type!(RustType)
7115 },
7116 None,
7117 None,
7118 Some(quote! {
7119 pub struct RustType(i32);
7120 }),
7121 );
7122}
7123
7124#[test]
7125fn test_rust_reference_autodiscover() {
7126 let hdr = indoc! {"
7127 #include <cstdint>
7128
7129 struct RustType;
7130 inline uint32_t take_rust_reference(const RustType&) {
7131 return 4;
7132 }
7133 "};
7134 let rs = quote! {
7135 let foo = RustType(3);
7136 let result = ffi::take_rust_reference(&foo);
7137 assert_eq!(result, 4);
7138 };
7139 run_test_ex(
7140 "",
7141 hdr,
7142 rs,
7143 quote! {},
7144 Some(Box::new(EnableAutodiscover)),
7145 None,
7146 Some(quote! {
7147 #[autocxx::extern_rust::extern_rust_type]
7148 pub struct RustType(i32);
7149 }),
7150 );
7151}
7152
7153#[test]
7154fn test_pass_thru_rust_reference() {
7155 let hdr = indoc! {"
7156 #include <cstdint>
7157
7158 struct RustType;
7159 inline const RustType& pass_rust_reference(const RustType& a) {
7160 return a;
7161 }
7162 "};
7163 let rs = quote! {
7164 let foo = RustType(3);
7165 assert_eq!(ffi::pass_rust_reference(&foo).0, 3);
7166 };
7167 run_test_ex(
7168 "",
7169 hdr,
7170 rs,
7171 quote! {
7172 generate!("pass_rust_reference")
7173 extern_rust_type!(RustType)
7174 },
7175 None,
7176 None,
7177 Some(quote! {
7178 pub struct RustType(i32);
7179 }),
7180 );
7181}
7182
7183#[test]
7184fn test_extern_rust_method() {
7185 let hdr = indoc! {"
7186 #include <cstdint>
7187 struct RustType;
7188 uint32_t examine(const RustType& foo);
7189 "};
7190 let cxx = indoc! {"
7191 uint32_t examine(const RustType& foo) {
7192 return foo.get();
7193 }"};
7194 let rs = quote! {
7195 let a = RustType(74);
7196 assert_eq!(ffi::examine(&a), 74);
7197 };
7198 run_test_ex(
7199 cxx,
7200 hdr,
7201 rs,
7202 directives_from_lists(&["examine"], &[], None),
7203 Some(Box::new(EnableAutodiscover)),
7204 None,
7205 Some(quote! {
7206 #[autocxx::extern_rust::extern_rust_type]
7207 pub struct RustType(i32);
7208 impl RustType {
7209 #[autocxx::extern_rust::extern_rust_function]
7210 pub fn get(&self) -> i32 {
7211 return self.0
7212 }
7213 }
7214 }),
7215 );
7216}
7217
7218#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007219fn test_extern_rust_fn_callback() {
7220 let hdr = indoc! {"
7221 struct a {};
7222 "};
7223 let hexathorpe = Token![#](Span::call_site());
7224 let rs = quote! {
7225 autocxx::include_cpp! {
7226 #hexathorpe include "input.h"
7227 safety!(unsafe_ffi)
7228 generate!("a")
7229 }
7230
7231 use ffi::a;
7232 use std::pin::Pin;
7233
7234 #[autocxx::extern_rust::extern_rust_function]
7235 pub fn called_from_cpp(_a: Pin<&mut a>) {}
7236
7237 fn main() {}
7238 };
7239 do_run_test_manual("", hdr, rs, None, None).unwrap();
7240}
7241
7242// TODO: there are various other tests for extern_rust_fn we should add:
7243// 1) taking mutable and immutable references
7244// 2) ensuring that types on which the signature depends as receiver,
7245// parameters and return are not garbage collected
7246
7247#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007248fn test_rust_reference_no_autodiscover() {
7249 let hdr = indoc! {"
7250 #include <cstdint>
7251
7252 struct RustType;
7253 inline uint32_t take_rust_reference(const RustType&) {
7254 return 4;
7255 }
7256 "};
7257 let rs = quote! {
7258 let foo = RustType(3);
7259 let result = ffi::take_rust_reference(&foo);
7260 assert_eq!(result, 4);
7261 };
7262 run_test_ex(
7263 "",
7264 hdr,
7265 rs,
7266 directives_from_lists(&["take_rust_reference"], &[], None),
7267 None,
7268 None,
7269 Some(quote! {
7270 #[autocxx::extern_rust::extern_rust_type]
7271 pub struct RustType(i32);
7272 }),
7273 );
7274}
7275
7276#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007277fn test_rust_box() {
7278 let hdr = indoc! {"
7279 #include <cstdint>
7280 #include <cxx.h>
7281
7282 struct RustType;
7283 inline uint32_t take_rust_box(rust::Box<RustType>) {
7284 return 4;
7285 }
7286 "};
7287 let rs = quote! {
7288 let foo = Box::new(RustType(3));
7289 let result = ffi::take_rust_box(foo);
7290 assert_eq!(result, 4);
7291 };
7292 run_test_ex(
7293 "",
7294 hdr,
7295 rs,
7296 directives_from_lists(&["take_rust_box"], &[], None),
7297 None,
7298 None,
7299 Some(quote! {
7300 #[autocxx::extern_rust::extern_rust_type]
7301 pub struct RustType(i32);
7302 }),
7303 );
7304}
7305
7306#[test]
7307fn test_rust_reference_no_autodiscover_no_usage() {
7308 let rs = quote! {
7309 let _ = RustType(3);
7310 };
7311 run_test_ex(
7312 "",
7313 "",
7314 rs,
7315 directives_from_lists(&[], &[], None),
7316 None,
7317 None,
7318 Some(quote! {
7319 #[autocxx::extern_rust::extern_rust_type]
7320 pub struct RustType(i32);
7321 }),
7322 );
7323}
7324
7325#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007326#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
7327// TODO - replace make_clang_arg_adder with something that knows how to add an MSVC-suitable
7328// directive for the cc build.
7329fn test_cpp17() {
7330 let hdr = indoc! {"
7331 static_assert(__cplusplus >= 201703L, \"This file expects a C++17 compatible compiler.\");
7332 inline void foo() {}
7333 "};
7334 run_test_ex(
7335 "",
7336 hdr,
7337 quote! {
7338 ffi::foo();
7339 },
7340 quote! {
7341 generate!("foo")
7342 },
7343 make_cpp17_adder(),
7344 None,
7345 None,
7346 );
7347}
7348
7349#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007350fn test_box_extern_rust_type() {
Brian Silverman4e662aa2022-05-11 23:10:19 -07007351 let hdr = indoc! {"
7352 #include <cxx.h>
7353 struct Foo;
7354 inline void take_box(rust::Box<Foo>) {
7355 }
7356 "};
7357 run_test_ex(
7358 "",
7359 hdr,
7360 quote! {
7361 ffi::take_box(Box::new(Foo { a: "Hello".into() }))
7362 },
7363 quote! {
7364 generate!("take_box")
7365 extern_rust_type!(Foo)
7366 },
7367 None,
7368 None,
7369 Some(quote! {
7370 pub struct Foo {
7371 a: String,
7372 }
7373 }),
7374 );
7375}
7376
7377#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007378fn test_box_return_placement_new() {
7379 let hdr = indoc! {"
7380 #include <cxx.h>
7381 struct Foo;
7382 struct Foo2;
7383 struct Ret {};
7384 inline Ret take_box(rust::Box<Foo>, rust::Box<Foo2>) {
7385 return Ret{};
7386 }
7387 "};
7388 run_test_ex(
7389 "",
7390 hdr,
7391 quote! {
7392 let _ = ffi::take_box(
7393 Box::new(Foo { a: "Hello".into() }),
7394 Box::new(bar::Foo2 { a: "Goodbye".into() })
7395 );
7396 },
7397 quote! {
7398 generate!("take_box")
7399 extern_rust_type!(Foo)
7400 generate!("Ret")
7401 },
7402 None,
7403 None,
7404 Some(quote! {
7405 pub struct Foo {
7406 a: String,
7407 }
7408 mod bar {
7409 #[autocxx::extern_rust::extern_rust_type]
7410 pub struct Foo2 {
7411 pub a: String,
7412 }
7413 }
7414 }),
7415 );
7416}
7417
7418#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007419fn test_box_via_extern_rust() {
7420 let hdr = indoc! {"
7421 #include <cxx.h>
7422 struct Foo;
7423 inline void take_box(rust::Box<Foo>) {
7424 }
7425 "};
7426 run_test_ex(
7427 "",
7428 hdr,
7429 quote! {
7430 ffi::take_box(Box::new(Foo { a: "Hello".into() }))
7431 },
7432 quote! {},
7433 Some(Box::new(EnableAutodiscover)),
7434 None,
7435 Some(quote! {
7436 #[autocxx::extern_rust::extern_rust_type]
7437 pub struct Foo {
7438 a: String,
7439 }
7440 }),
7441 );
7442}
7443
7444#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007445fn test_box_via_extern_rust_no_include_cpp() {
7446 let hdr = indoc! {"
7447 #include <cxx.h>
7448 struct Foo;
7449 inline void take_box(rust::Box<Foo>) {
7450 }
7451 "};
7452 do_run_test_manual(
7453 "",
7454 hdr,
7455 quote! {
7456 #[autocxx::extern_rust::extern_rust_type]
7457 pub struct Foo {
7458 a: String,
7459 }
7460
7461 fn main() {
7462 }
7463 },
7464 Some(Box::new(EnableAutodiscover)),
7465 None,
7466 )
7467 .unwrap();
7468}
7469
7470#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007471fn test_box_via_extern_rust_in_mod() {
7472 let hdr = indoc! {"
7473 #include <cxx.h>
7474 struct Foo;
7475 inline void take_box(rust::Box<Foo>) {
7476 }
7477 "};
7478 run_test_ex(
7479 "",
7480 hdr,
7481 quote! {
7482 ffi::take_box(Box::new(bar::Foo { a: "Hello".into() }))
7483 },
7484 quote! {},
7485 Some(Box::new(EnableAutodiscover)),
7486 None,
7487 Some(quote! {
7488 mod bar {
7489 #[autocxx::extern_rust::extern_rust_type]
7490 pub struct Foo {
7491 pub a: String,
7492 }
7493 }
7494 }),
7495 );
7496}
7497
7498#[test]
7499fn test_extern_rust_fn_simple() {
7500 let cpp = indoc! {"
7501 void foo() {
7502 my_rust_fun();
7503 }
7504 "};
7505 let hdr = indoc! {"
7506 #include <cxx.h>
7507 inline void do_thing() {}
7508 "};
7509 run_test_ex(
7510 cpp,
7511 hdr,
7512 quote! {
7513 ffi::do_thing();
7514 },
7515 quote! {
7516 generate!("do_thing")
7517 },
7518 Some(Box::new(EnableAutodiscover)),
7519 None,
7520 Some(quote! {
7521 #[autocxx::extern_rust::extern_rust_function]
7522 fn my_rust_fun() {
7523 }
7524 }),
7525 );
7526}
7527
7528#[test]
7529fn test_extern_rust_fn_in_mod() {
7530 let hdr = indoc! {"
7531 #include <cxx.h>
7532 inline void do_thing() {}
7533 "};
7534 run_test_ex(
7535 "",
7536 hdr,
7537 quote! {},
7538 quote! {
7539 generate!("do_thing")
7540 },
7541 Some(Box::new(EnableAutodiscover)),
7542 None,
7543 Some(quote! {
7544 mod bar {
7545 #[autocxx::extern_rust::extern_rust_function]
7546 pub fn my_rust_fun() {
7547
7548 }
7549 }
7550 }),
7551 );
7552}
7553
7554#[test]
7555fn test_issue_956() {
7556 let hdr = indoc! {"
7557 #include <cstdint>
7558 inline void take_int(int&) {}
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007559 inline void take_uint16(uint16_t) {}
7560 inline void take_us(unsigned short) {}
7561 inline void take_char16(char16_t) {}
7562 inline void take_uint16_ref(uint16_t&) {}
7563 inline void take_char16_ref(char16_t &) {}
Brian Silverman4e662aa2022-05-11 23:10:19 -07007564 "};
7565 run_test(
7566 "",
7567 hdr,
7568 quote! {},
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007569 &[
7570 "take_int",
7571 "take_uint16",
7572 "take_char16",
7573 "take_uint16_ref",
7574 "take_char16_ref",
7575 "take_us",
7576 ],
Brian Silverman4e662aa2022-05-11 23:10:19 -07007577 &[],
7578 );
7579}
7580
7581#[test]
7582fn test_extern_rust_fn_no_autodiscover() {
7583 let hdr = indoc! {"
7584 #include <cxx.h>
7585 "};
7586 let cpp = indoc! {"
7587 void call_it() {
7588 my_rust_fun();
7589 }
7590 "};
7591 run_test_ex(
7592 cpp,
7593 hdr,
7594 quote! {},
7595 quote! {},
7596 None,
7597 None,
7598 Some(quote! {
7599 mod bar {
7600 #[autocxx::extern_rust::extern_rust_function]
7601 pub fn my_rust_fun() {
7602
7603 }
7604 }
7605 }),
7606 );
7607}
7608
7609#[test]
7610fn test_pv_subclass_mut() {
7611 let hdr = indoc! {"
7612 #include <cstdint>
7613
7614 class Observer {
7615 public:
7616 Observer() {}
7617 virtual void foo() = 0;
7618 virtual ~Observer() {}
7619 };
7620 inline void bar() {}
7621 "};
7622 run_test_ex(
7623 "",
7624 hdr,
7625 quote! {
7626 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7627 },
7628 quote! {
7629 generate!("bar")
7630 subclass!("Observer",MyObserver)
7631 },
7632 None,
7633 None,
7634 Some(quote! {
7635 use autocxx::subclass::CppSubclass;
7636 use ffi::Observer_methods;
7637 #[autocxx::subclass::subclass]
7638 pub struct MyObserver {
7639 a: u32
7640 }
7641 impl Observer_methods for MyObserver {
7642 fn foo(&mut self) {
7643 }
7644 }
7645 }),
7646 );
7647}
7648
7649#[test]
7650fn test_pv_subclass_const() {
7651 let hdr = indoc! {"
7652 #include <cstdint>
7653
7654 class Observer {
7655 public:
7656 Observer() {}
7657 virtual void foo() const = 0;
7658 virtual ~Observer() {}
7659 };
7660 inline void bar() {}
7661 "};
7662 run_test_ex(
7663 "",
7664 hdr,
7665 quote! {
7666 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7667 },
7668 quote! {
7669 generate!("bar")
7670 subclass!("Observer",MyObserver)
7671 },
7672 None,
7673 None,
7674 Some(quote! {
7675 use autocxx::subclass::CppSubclass;
7676 use ffi::Observer_methods;
7677 #[autocxx::subclass::subclass]
7678 pub struct MyObserver {
7679 a: u32
7680 }
7681 impl Observer_methods for MyObserver {
7682 fn foo(&self) {
7683 }
7684 }
7685 }),
7686 );
7687}
7688
7689#[test]
7690fn test_pv_subclass_calls_impossible() {
7691 let hdr = indoc! {"
7692 #include <cstdint>
7693
7694 class Observer {
7695 public:
7696 Observer() {}
7697 virtual void foo() const = 0;
7698 virtual ~Observer() {}
7699 };
7700 inline void bar() {}
7701 "};
7702 run_test_expect_fail_ex(
7703 "",
7704 hdr,
7705 quote! {
7706 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7707 },
7708 quote! {
7709 generate!("bar")
7710 subclass!("Observer",MyObserver)
7711 },
7712 None,
7713 None,
7714 Some(quote! {
7715 use autocxx::subclass::CppSubclass;
7716 use ffi::Observer_methods;
7717 #[autocxx::subclass::subclass]
7718 pub struct MyObserver {
7719 a: u32
7720 }
7721 impl Observer_methods for MyObserver {
7722 fn foo(&self) {
7723 use ffi::Observer_supers;
7724 self.foo_super()
7725 }
7726 }
7727 }),
7728 );
7729}
7730
7731#[test]
7732fn test_pv_subclass_not_pub() {
7733 let hdr = indoc! {"
7734 #include <cstdint>
7735
7736 class Observer {
7737 public:
7738 Observer() {}
7739 virtual void foo() const = 0;
7740 virtual ~Observer() {}
7741 };
7742 inline void bar() {}
7743 "};
7744 run_test_expect_fail_ex(
7745 "",
7746 hdr,
7747 quote! {
7748 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7749 },
7750 quote! {
7751 generate!("bar")
7752 subclass!("Observer",MyObserver)
7753 },
7754 None,
7755 None,
7756 Some(quote! {
7757 use autocxx::subclass::CppSubclass;
7758 use ffi::Observer_methods;
7759 #[autocxx::subclass::subclass]
7760 struct MyObserver {
7761 a: u32
7762 }
7763 impl Observer_methods for MyObserver {
7764 fn foo(&self) {
7765 }
7766 }
7767 }),
7768 );
7769}
7770
7771#[test]
7772fn test_pv_subclass_ptr_param() {
7773 let hdr = indoc! {"
7774 #include <cstdint>
7775 struct A {
7776 uint8_t a;
7777 };
7778
7779 class Observer {
7780 public:
7781 Observer() {}
7782 virtual void foo(const A*) const {};
7783 virtual ~Observer() {}
7784 };
7785 "};
7786 run_test_ex(
7787 "",
7788 hdr,
7789 quote! {
7790 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7791 },
7792 quote! {
7793 generate!("A")
7794 subclass!("Observer",MyObserver)
7795 },
7796 None,
7797 None,
7798 Some(quote! {
7799 use autocxx::subclass::CppSubclass;
7800 use ffi::Observer_methods;
7801 #[autocxx::subclass::subclass]
7802 pub struct MyObserver {
7803 a: u32
7804 }
7805 impl Observer_methods for MyObserver {
7806 unsafe fn foo(&self, a: *const ffi::A) {
7807 use ffi::Observer_supers;
7808 self.foo_super(a)
7809 }
7810 }
7811 }),
7812 );
7813}
7814
7815#[test]
James Kuszmaul850a4752024-02-14 20:27:12 -08007816fn test_pv_subclass_opaque_param() {
7817 let hdr = indoc! {"
7818 #include <cstdint>
7819
7820 typedef uint32_t MyUnsupportedType[4];
7821
7822 struct MySupportedType {
7823 uint32_t a;
7824 };
7825
7826 class MySuperType {
7827 public:
7828 virtual void foo(const MyUnsupportedType* foo, const MySupportedType* bar) const = 0;
7829 virtual ~MySuperType() = default;
7830 };
7831 "};
7832 run_test_ex(
7833 "",
7834 hdr,
7835 quote! {
7836 MySubType::new_rust_owned(MySubType { a: 3, cpp_peer: Default::default() });
7837 },
7838 quote! {
7839 subclass!("MySuperType",MySubType)
7840 extern_cpp_opaque_type!("MyUnsupportedType", crate::ffi2::MyUnsupportedType)
7841 },
7842 None,
7843 None,
7844 Some(quote! {
7845
7846 #[cxx::bridge]
7847 pub mod ffi2 {
7848 unsafe extern "C++" {
7849 include!("input.h");
7850 type MyUnsupportedType;
7851 }
7852 }
7853 use autocxx::subclass::CppSubclass;
7854 use ffi::MySuperType_methods;
7855 #[autocxx::subclass::subclass]
7856 pub struct MySubType {
7857 a: u32
7858 }
7859 impl MySuperType_methods for MySubType {
7860 unsafe fn foo(&self, _foo: *const ffi2::MyUnsupportedType, _bar: *const ffi::MySupportedType) {
7861 }
7862 }
7863 }),
7864 );
7865}
7866
7867#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007868fn test_pv_subclass_return() {
7869 let hdr = indoc! {"
7870 #include <cstdint>
7871
7872 class Observer {
7873 public:
7874 Observer() {}
7875 virtual uint32_t foo() const = 0;
7876 virtual ~Observer() {}
7877 };
7878 inline void bar() {}
7879 "};
7880 run_test_ex(
7881 "",
7882 hdr,
7883 quote! {
7884 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7885 },
7886 quote! {
7887 generate!("bar")
7888 subclass!("Observer",MyObserver)
7889 },
7890 None,
7891 None,
7892 Some(quote! {
7893 use autocxx::subclass::CppSubclass;
7894 use ffi::Observer_methods;
7895 #[autocxx::subclass::subclass]
7896 pub struct MyObserver {
7897 a: u32
7898 }
7899 impl Observer_methods for MyObserver {
7900 fn foo(&self) -> u32 {
7901 4
7902 }
7903 }
7904 }),
7905 );
7906}
7907
7908#[test]
7909fn test_pv_subclass_passed_to_fn() {
7910 let hdr = indoc! {"
7911 #include <cstdint>
7912
7913 class Observer {
7914 public:
7915 Observer() {}
7916 virtual uint32_t foo() const = 0;
7917 virtual ~Observer() {}
7918 };
7919 inline void take_observer(const Observer&) {}
7920 "};
7921 run_test_ex(
7922 "",
7923 hdr,
7924 quote! {
7925 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7926 ffi::take_observer(o.borrow().as_ref());
7927 },
7928 quote! {
7929 generate!("take_observer")
7930 subclass!("Observer",MyObserver)
7931 },
7932 None,
7933 None,
7934 Some(quote! {
7935 use autocxx::subclass::CppSubclass;
7936 use ffi::Observer_methods;
7937 #[autocxx::subclass::subclass]
7938 pub struct MyObserver {
7939 a: u32
7940 }
7941 impl Observer_methods for MyObserver {
7942 fn foo(&self) -> u32 {
7943 4
7944 }
7945 }
7946 }),
7947 );
7948}
7949
7950#[test]
7951fn test_pv_subclass_derive_defaults() {
7952 let hdr = indoc! {"
7953 #include <cstdint>
7954
7955 class Observer {
7956 public:
7957 Observer() {}
7958 virtual uint32_t foo() const = 0;
7959 virtual ~Observer() {}
7960 };
7961 inline void take_observer(const Observer&) {}
7962 "};
7963 run_test_ex(
7964 "",
7965 hdr,
7966 quote! {
7967 use autocxx::subclass::CppSubclassDefault;
7968 let o = MyObserver::default_rust_owned();
7969 ffi::take_observer(o.borrow().as_ref());
7970 },
7971 quote! {
7972 generate!("take_observer")
7973 subclass!("Observer",MyObserver)
7974 },
7975 None,
7976 None,
7977 Some(quote! {
7978 #[autocxx::subclass::subclass]
7979 #[derive(Default)]
7980 pub struct MyObserver {
7981 a: u32
7982 }
7983 impl ffi::Observer_methods for MyObserver {
7984 fn foo(&self) -> u32 {
7985 4
7986 }
7987 }
7988 }),
7989 );
7990}
7991
7992#[test]
7993fn test_non_pv_subclass_simple() {
7994 let hdr = indoc! {"
7995 #include <cstdint>
7996
7997 class Observer {
7998 public:
7999 Observer() {}
8000 virtual void foo() const {}
8001 virtual ~Observer() {}
8002 };
8003 inline void bar() {}
8004 "};
8005 run_test_ex(
8006 "",
8007 hdr,
8008 quote! {
8009 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8010 obs.borrow().foo();
8011 },
8012 quote! {
8013 generate!("bar")
8014 subclass!("Observer",MyObserver)
8015 },
8016 None,
8017 None,
8018 Some(quote! {
8019 use autocxx::subclass::CppSubclass;
8020 use ffi::Observer_methods;
8021 #[autocxx::subclass::subclass]
8022 pub struct MyObserver {
8023 a: u32
8024 }
8025 impl Observer_methods for MyObserver {
8026 }
8027 }),
8028 );
8029}
8030
8031#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07008032/// Tests the Rust code generated for subclasses when there's a `std` module in scope representing
8033/// the C++ `std` namespace. This breaks if any of the generated Rust code fails to fully qualify
8034/// its references to the Rust `std`.
8035fn test_subclass_with_std() {
8036 let hdr = indoc! {"
8037 #include <cstdint>
8038 #include <chrono>
8039
8040 class Observer {
8041 public:
8042 Observer() {}
8043 virtual void foo() const {}
8044 virtual ~Observer() {}
8045
8046 void unused(std::chrono::nanoseconds) {}
8047 };
8048 "};
8049 run_test_ex(
8050 "",
8051 hdr,
8052 quote! {
8053 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8054 obs.borrow().foo();
8055 },
8056 quote! {
8057 subclass!("Observer",MyObserver)
8058 },
8059 None,
8060 None,
8061 Some(quote! {
8062 use autocxx::subclass::CppSubclass;
8063 use ffi::Observer_methods;
8064 #[autocxx::subclass::subclass]
8065 pub struct MyObserver {
8066 a: u32
8067 }
8068 impl Observer_methods for MyObserver {
8069 }
8070 }),
8071 );
8072}
8073
8074#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07008075fn test_two_subclasses() {
8076 let hdr = indoc! {"
8077 #include <cstdint>
8078
8079 class Observer {
8080 public:
8081 Observer() {}
8082 virtual void foo() const {}
8083 virtual ~Observer() {}
8084 };
8085 inline void bar() {}
8086 "};
8087 run_test_ex(
8088 "",
8089 hdr,
8090 quote! {
8091 let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
8092 obs.borrow().foo();
8093 let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
8094 obs.borrow().foo();
8095 },
8096 quote! {
8097 generate!("bar")
8098 subclass!("Observer",MyObserverA)
8099 subclass!("Observer",MyObserverB)
8100 },
8101 None,
8102 None,
8103 Some(quote! {
8104 use autocxx::subclass::CppSubclass;
8105 use ffi::Observer_methods;
8106 #[autocxx::subclass::subclass]
8107 pub struct MyObserverA {
8108 a: u32
8109 }
8110 impl Observer_methods for MyObserverA {
8111 }
8112 #[autocxx::subclass::subclass]
8113 pub struct MyObserverB {
8114 a: u32
8115 }
8116 impl Observer_methods for MyObserverB {
8117 }
8118 }),
8119 );
8120}
8121
8122#[test]
8123fn test_two_superclasses_with_same_name_method() {
8124 let hdr = indoc! {"
8125 #include <cstdint>
8126
8127 class ObserverA {
8128 public:
8129 ObserverA() {}
8130 virtual void foo() const {}
8131 virtual ~ObserverA() {}
8132 };
8133
8134 class ObserverB {
8135 public:
8136 ObserverB() {}
8137 virtual void foo() const {}
8138 virtual ~ObserverB() {}
8139 };
8140 inline void bar() {}
8141 "};
8142 run_test_ex(
8143 "",
8144 hdr,
8145 quote! {
8146 let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
8147 obs.borrow().foo();
8148 let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
8149 obs.borrow().foo();
8150 },
8151 quote! {
8152 generate!("bar")
8153 subclass!("ObserverA",MyObserverA)
8154 subclass!("ObserverB",MyObserverB)
8155 },
8156 None,
8157 None,
8158 Some(quote! {
8159 use autocxx::subclass::CppSubclass;
8160 use ffi::ObserverA_methods;
8161 use ffi::ObserverB_methods;
8162 #[autocxx::subclass::subclass]
8163 pub struct MyObserverA {
8164 a: u32
8165 }
8166 impl ObserverA_methods for MyObserverA {
8167 }
8168 #[autocxx::subclass::subclass]
8169 pub struct MyObserverB {
8170 a: u32
8171 }
8172 impl ObserverB_methods for MyObserverB {
8173 }
8174 }),
8175 );
8176}
8177
8178#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07008179fn test_subclass_no_safety() {
8180 let hdr = indoc! {"
8181 #include <cstdint>
8182
8183 class Observer {
8184 public:
8185 Observer() {}
8186 virtual void foo() = 0;
8187 virtual ~Observer() {}
8188 };
8189 "};
8190 let hexathorpe = Token![#](Span::call_site());
8191 let unexpanded_rust = quote! {
8192 use autocxx::prelude::*;
8193
8194 include_cpp!(
8195 #hexathorpe include "input.h"
8196 subclass!("Observer",MyObserver)
8197 );
8198
8199 use ffi::Observer_methods;
8200 #hexathorpe [autocxx::subclass::subclass]
8201 pub struct MyObserver;
8202 impl Observer_methods for MyObserver {
8203 unsafe fn foo(&mut self) {}
8204 }
8205
8206 use autocxx::subclass::{CppSubclass, CppPeerConstructor, CppSubclassRustPeerHolder};
8207 use cxx::UniquePtr;
8208 impl CppPeerConstructor<ffi::MyObserverCpp> for MyObserver {
8209 fn make_peer(
8210 &mut self,
8211 peer_holder: CppSubclassRustPeerHolder<Self>,
8212 ) -> UniquePtr<ffi::MyObserverCpp> {
8213 UniquePtr::emplace(unsafe { ffi::MyObserverCpp::new(peer_holder) })
8214 }
8215 }
8216
8217 fn main() {
8218 let obs = MyObserver::new_rust_owned(MyObserver { cpp_peer: Default::default() });
8219 unsafe { obs.borrow_mut().foo() };
8220 }
8221 };
8222
8223 do_run_test_manual("", hdr, unexpanded_rust, None, None).unwrap()
8224}
8225
8226#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07008227fn test_pv_protected_constructor() {
8228 let hdr = indoc! {"
8229 #include <cstdint>
8230
8231 class Observer {
8232 protected:
8233 Observer() {}
8234 public:
8235 virtual void foo() const {}
8236 virtual ~Observer() {}
8237 };
8238 inline void bar() {}
8239 "};
8240 run_test_ex(
8241 "",
8242 hdr,
8243 quote! {
8244 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8245 obs.borrow().foo();
8246 },
8247 quote! {
8248 generate!("bar")
8249 subclass!("Observer",MyObserver)
8250 },
8251 None,
8252 None,
8253 Some(quote! {
8254 use autocxx::subclass::CppSubclass;
8255 use ffi::Observer_methods;
8256 #[autocxx::subclass::subclass]
8257 pub struct MyObserver {
8258 a: u32
8259 }
8260 impl Observer_methods for MyObserver {
8261 }
8262 }),
8263 );
8264}
8265
8266#[test]
8267fn test_pv_protected_method() {
8268 let hdr = indoc! {"
8269 #include <cstdint>
8270
8271 class Observer {
8272 public:
8273 Observer() {}
8274 virtual void foo() const {}
8275 virtual ~Observer() {}
8276 protected:
8277 virtual void baz() const {}
8278 };
8279 inline void bar() {}
8280 "};
8281 run_test_ex(
8282 "",
8283 hdr,
8284 quote! {
8285 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8286 obs.borrow().foo();
8287 },
8288 quote! {
8289 generate!("bar")
8290 subclass!("Observer",MyObserver)
8291 },
8292 None,
8293 None,
8294 Some(quote! {
8295 use autocxx::subclass::CppSubclass;
8296 use ffi::Observer_methods;
8297 #[autocxx::subclass::subclass]
8298 pub struct MyObserver {
8299 a: u32
8300 }
8301 impl Observer_methods for MyObserver {
8302 fn baz(&self) {
8303 }
8304
8305 fn foo(&self) {
8306 use ffi::Observer_supers;
8307 self.baz_super()
8308 }
8309 }
8310 }),
8311 );
8312}
8313
8314#[test]
8315fn test_pv_subclass_allocation_not_self_owned() {
8316 let hdr = indoc! {"
8317 #include <cstdint>
8318 extern \"C\" void mark_freed() noexcept;
8319 extern \"C\" void mark_allocated() noexcept;
8320
8321 class TestObserver {
8322 public:
8323 TestObserver() {
8324 mark_allocated();
8325 }
8326 virtual void a() const = 0;
8327 virtual ~TestObserver() {
8328 mark_freed();
8329 }
8330 };
8331 inline void TriggerTestObserverA(const TestObserver& obs) {
8332 obs.a();
8333 }
8334 "};
8335 run_test_ex(
8336 "",
8337 hdr,
8338 quote! {
8339 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8340 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8341 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8342
8343 // Test when owned by C++
8344 let obs = MyTestObserver::new_cpp_owned(
8345 MyTestObserver::new()
8346 );
8347 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8348 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8349 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8350 let obs_superclass = obs.as_ref().unwrap(); // &subclass
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008351 let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
Brian Silverman4e662aa2022-05-11 23:10:19 -07008352 ffi::TriggerTestObserverA(obs_superclass);
8353 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008354 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008355 Lazy::force(&STATUS).lock().unwrap().a_called = false;
8356 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8357 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8358 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8359
8360 // Test when owned by Rust
8361 let obs = MyTestObserver::new_rust_owned(
8362 MyTestObserver::new()
8363 );
8364 //let cpp_peer_ptr = unsafe { obs.borrow_mut().peer_mut().get_unchecked_mut() as *mut ffi::MyTestObserverCpp };
8365 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8366 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8367 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8368 ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
8369 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8370 Lazy::force(&STATUS).lock().unwrap().a_called = false;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008371 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008372 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8373 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8374 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8375 },
8376 quote! {
8377 generate!("TriggerTestObserverA")
8378 subclass!("TestObserver",MyTestObserver)
8379 },
8380 None,
8381 None,
8382 Some(quote! {
8383 use once_cell::sync::Lazy;
8384 use std::sync::Mutex;
8385
8386 use autocxx::subclass::CppSubclass;
8387 use ffi::TestObserver_methods;
8388 #[autocxx::subclass::subclass]
8389 pub struct MyTestObserver {
8390 data: ExternalEngine,
8391 }
8392 impl TestObserver_methods for MyTestObserver {
8393 fn a(&self) {
8394 self.data.do_something();
8395 }
8396 }
8397 impl MyTestObserver {
8398 fn new() -> Self {
8399 Self {
8400 cpp_peer: Default::default(),
8401 data: ExternalEngine::default(),
8402 }
8403 }
8404 }
8405
8406 #[no_mangle]
8407 pub fn mark_allocated() {
8408 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
8409 }
8410
8411 #[no_mangle]
8412 pub fn mark_freed() {
8413 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
8414 }
8415
8416 #[derive(Default)]
8417 struct Status {
8418 cpp_allocated: bool,
8419 rust_allocated: bool,
8420 a_called: bool,
8421 }
8422
8423 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8424
8425 pub struct ExternalEngine;
8426
8427 impl ExternalEngine {
8428 fn do_something(&self) {
8429 Lazy::force(&STATUS).lock().unwrap().a_called = true;
8430 }
8431 }
8432
8433 impl Default for ExternalEngine {
8434 fn default() -> Self {
8435 Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
8436 ExternalEngine
8437 }
8438 }
8439
8440 impl Drop for ExternalEngine {
8441 fn drop(&mut self) {
8442 Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
8443 }
8444 }
8445 }),
8446 );
8447}
8448
8449#[test]
8450fn test_pv_subclass_allocation_self_owned() {
8451 let hdr = indoc! {"
8452 #include <cstdint>
8453 extern \"C\" void mark_freed() noexcept;
8454 extern \"C\" void mark_allocated() noexcept;
8455
8456 class TestObserver {
8457 public:
8458 TestObserver() {
8459 mark_allocated();
8460 }
8461 virtual void a() const = 0;
8462 virtual ~TestObserver() {
8463 mark_freed();
8464 }
8465 };
8466 inline void TriggerTestObserverA(const TestObserver& obs) {
8467 const_cast<TestObserver&>(obs).a();
8468 }
8469 "};
8470 run_test_ex(
8471 "",
8472 hdr,
8473 quote! {
8474 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8475 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8476 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8477
8478 // Test when owned by C++
8479 let obs = MyTestObserver::new_cpp_owned(
8480 MyTestObserver::new(false)
8481 );
8482 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8483 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8484 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8485 let obs_superclass = obs.as_ref().unwrap(); // &subclass
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008486 let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
Brian Silverman4e662aa2022-05-11 23:10:19 -07008487
8488 ffi::TriggerTestObserverA(obs_superclass);
8489 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008490 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008491 Lazy::force(&STATUS).lock().unwrap().a_called = false;
8492 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8493 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8494 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8495
8496 // Test when owned by Rust
8497 let obs = MyTestObserver::new_rust_owned(
8498 MyTestObserver::new(false)
8499 );
8500 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8501 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8502 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8503 ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
8504
8505 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8506 Lazy::force(&STATUS).lock().unwrap().a_called = false;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008507 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008508 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8509 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8510 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8511
8512 // Test when self-owned
8513 let obs = MyTestObserver::new_self_owned(
8514 MyTestObserver::new(true)
8515 );
8516 let obs_superclass_ptr: *const ffi::TestObserver = obs.as_ref().borrow().as_ref();
8517 // Retain just a pointer on the Rust side, so there is no Rust-side
8518 // ownership.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008519 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008520 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8521 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8522 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8523 ffi::TriggerTestObserverA(unsafe { obs_superclass_ptr.as_ref().unwrap() });
8524
8525 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8526 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8527 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8528 },
8529 quote! {
8530 generate!("TriggerTestObserverA")
8531 subclass!("TestObserver",MyTestObserver)
8532 },
8533 None,
8534 None,
8535 Some(quote! {
8536 use once_cell::sync::Lazy;
8537 use std::sync::Mutex;
8538
8539 use autocxx::subclass::CppSubclass;
8540 use autocxx::subclass::CppSubclassSelfOwned;
8541 use ffi::TestObserver_methods;
8542 #[autocxx::subclass::subclass(self_owned)]
8543 pub struct MyTestObserver {
8544 data: ExternalEngine,
8545 self_owning: bool,
8546 }
8547 impl TestObserver_methods for MyTestObserver {
8548 fn a(&self) {
8549 self.data.do_something();
8550 if self.self_owning {
8551 self.delete_self();
8552 }
8553 }
8554 }
8555 impl MyTestObserver {
8556 fn new(self_owning: bool) -> Self {
8557 Self {
8558 cpp_peer: Default::default(),
8559 data: ExternalEngine::default(),
8560 self_owning,
8561 }
8562 }
8563 }
8564
8565 #[no_mangle]
8566 pub fn mark_allocated() {
8567 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
8568 }
8569
8570 #[no_mangle]
8571 pub fn mark_freed() {
8572 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
8573 }
8574
8575 #[derive(Default)]
8576 struct Status {
8577 cpp_allocated: bool,
8578 rust_allocated: bool,
8579 a_called: bool,
8580 }
8581
8582 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8583
8584 pub struct ExternalEngine;
8585
8586 impl ExternalEngine {
8587 fn do_something(&self) {
8588 Lazy::force(&STATUS).lock().unwrap().a_called = true;
8589 }
8590 }
8591
8592 impl Default for ExternalEngine {
8593 fn default() -> Self {
8594 Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
8595 ExternalEngine
8596 }
8597 }
8598
8599 impl Drop for ExternalEngine {
8600 fn drop(&mut self) {
8601 Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
8602 }
8603 }
8604 }),
8605 );
8606}
8607
8608#[test]
8609fn test_pv_subclass_calls() {
8610 let hdr = indoc! {"
8611 #include <cstdint>
8612 extern \"C\" void mark_c_called() noexcept;
8613 extern \"C\" void mark_d_called() noexcept;
8614 extern \"C\" void mark_e_called() noexcept;
8615 extern \"C\" void mark_f_called() noexcept;
8616 extern \"C\" void mark_g_called() noexcept;
8617 extern \"C\" void mark_h_called() noexcept;
8618
8619 class TestObserver {
8620 public:
8621 TestObserver() {}
8622 virtual uint32_t a(uint32_t) const = 0;
8623 virtual uint32_t b(uint32_t) = 0;
8624 virtual uint32_t c(uint32_t) const { mark_c_called(); return 0; };
8625 virtual uint32_t d(uint32_t) { mark_d_called(); return 0; };
8626 virtual uint32_t e(uint32_t) const { mark_e_called(); return 0; };
8627 virtual uint32_t f(uint32_t) { mark_f_called(); return 0; };
8628 virtual uint32_t g(uint32_t) const { mark_g_called(); return 0; };
8629 virtual uint32_t h(uint32_t) { mark_h_called(); return 0; };
8630 virtual ~TestObserver() {}
8631 };
8632
8633 extern TestObserver* obs;
8634
8635 inline void register_observer(TestObserver& a) {
8636 obs = &a;
8637 }
8638 inline uint32_t call_a(uint32_t param) {
8639 return obs->a(param);
8640 }
8641 inline uint32_t call_b(uint32_t param) {
8642 return obs->b(param);
8643 }
8644 inline uint32_t call_c(uint32_t param) {
8645 return obs->c(param);
8646 }
8647 inline uint32_t call_d(uint32_t param) {
8648 return obs->d(param);
8649 }
8650 inline uint32_t call_e(uint32_t param) {
8651 return obs->e(param);
8652 }
8653 inline uint32_t call_f(uint32_t param) {
8654 return obs->f(param);
8655 }
8656 inline uint32_t call_g(uint32_t param) {
8657 return obs->g(param);
8658 }
8659 inline uint32_t call_h(uint32_t param) {
8660 return obs->h(param);
8661 }
8662 "};
8663 run_test_ex(
8664 "TestObserver* obs;",
8665 hdr,
8666 quote! {
8667 let obs = MyTestObserver::new_rust_owned(
8668 MyTestObserver::default()
8669 );
8670 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
8671 assert_eq!(ffi::call_a(1), 2);
8672 assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called);
8673 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8674
8675 assert_eq!(ffi::call_b(1), 3);
8676 assert!(Lazy::force(&STATUS).lock().unwrap().sub_b_called);
8677 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8678
8679 assert_eq!(ffi::call_c(1), 4);
8680 assert!(Lazy::force(&STATUS).lock().unwrap().sub_c_called);
8681 assert!(!Lazy::force(&STATUS).lock().unwrap().super_c_called);
8682 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8683
8684 assert_eq!(ffi::call_d(1), 5);
8685 assert!(Lazy::force(&STATUS).lock().unwrap().sub_d_called);
8686 assert!(!Lazy::force(&STATUS).lock().unwrap().super_d_called);
8687 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8688
8689 assert_eq!(ffi::call_e(1), 0);
8690 assert!(Lazy::force(&STATUS).lock().unwrap().sub_e_called);
8691 assert!(Lazy::force(&STATUS).lock().unwrap().super_e_called);
8692 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8693
8694 assert_eq!(ffi::call_f(1), 0);
8695 assert!(Lazy::force(&STATUS).lock().unwrap().sub_f_called);
8696 assert!(Lazy::force(&STATUS).lock().unwrap().super_f_called);
8697 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8698
8699 assert_eq!(ffi::call_g(1), 0);
8700 assert!(Lazy::force(&STATUS).lock().unwrap().super_g_called);
8701 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8702
8703 assert_eq!(ffi::call_h(1), 0);
8704 assert!(Lazy::force(&STATUS).lock().unwrap().super_h_called);
8705 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8706 },
8707 quote! {
8708 generate!("register_observer")
8709 generate!("call_a")
8710 generate!("call_b")
8711 generate!("call_c")
8712 generate!("call_d")
8713 generate!("call_e")
8714 generate!("call_f")
8715 generate!("call_g")
8716 generate!("call_h")
8717 subclass!("TestObserver",MyTestObserver)
8718 },
8719 None,
8720 None,
8721 Some(quote! {
8722 use once_cell::sync::Lazy;
8723 use std::sync::Mutex;
8724
8725 use autocxx::subclass::CppSubclass;
8726 use ffi::TestObserver_methods;
8727 #[autocxx::subclass::subclass]
8728 #[derive(Default)]
8729 pub struct MyTestObserver {
8730 }
8731 impl TestObserver_methods for MyTestObserver {
8732
8733 // a and b are pure virtual
8734 fn a(&self, param: u32) -> u32 {
8735 Lazy::force(&STATUS).lock().unwrap().sub_a_called = true;
8736 param + 1
8737 }
8738 fn b(&mut self, param: u32) -> u32 {
8739 Lazy::force(&STATUS).lock().unwrap().sub_b_called = true;
8740 param + 2
8741 }
8742
8743 // c and d we override the superclass
8744 fn c(&self, param: u32) -> u32 {
8745 Lazy::force(&STATUS).lock().unwrap().sub_c_called = true;
8746 param + 3
8747 }
8748 fn d(&mut self, param: u32) -> u32 {
8749 Lazy::force(&STATUS).lock().unwrap().sub_d_called = true;
8750 param + 4
8751 }
8752
8753 // e and f we call through to the superclass
8754 fn e(&self, param: u32) -> u32 {
8755 Lazy::force(&STATUS).lock().unwrap().sub_e_called = true;
8756 self.peer().e_super(param)
8757 }
8758 fn f(&mut self, param: u32) -> u32 {
8759 Lazy::force(&STATUS).lock().unwrap().sub_f_called = true;
8760 self.peer_mut().f_super(param)
8761 }
8762
8763 // g and h we do not do anything, so calls should only call
8764 // the superclass
8765 }
8766
8767 #[no_mangle]
8768 pub fn mark_c_called() {
8769 Lazy::force(&STATUS).lock().unwrap().super_c_called = true;
8770 }
8771 #[no_mangle]
8772 pub fn mark_d_called() {
8773 Lazy::force(&STATUS).lock().unwrap().super_d_called = true;
8774 }
8775 #[no_mangle]
8776 pub fn mark_e_called() {
8777 Lazy::force(&STATUS).lock().unwrap().super_e_called = true;
8778 }
8779 #[no_mangle]
8780 pub fn mark_f_called() {
8781 Lazy::force(&STATUS).lock().unwrap().super_f_called = true;
8782 }
8783 #[no_mangle]
8784 pub fn mark_g_called() {
8785 Lazy::force(&STATUS).lock().unwrap().super_g_called = true;
8786 }
8787 #[no_mangle]
8788 pub fn mark_h_called() {
8789 Lazy::force(&STATUS).lock().unwrap().super_h_called = true;
8790 }
8791
8792 #[derive(Default)]
8793 struct Status {
8794 super_c_called: bool,
8795 super_d_called: bool,
8796 super_e_called: bool,
8797 super_f_called: bool,
8798 super_g_called: bool,
8799 super_h_called: bool,
8800 sub_a_called: bool,
8801 sub_b_called: bool,
8802 sub_c_called: bool,
8803 sub_d_called: bool,
8804 sub_e_called: bool,
8805 sub_f_called: bool,
8806 }
8807
8808 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8809 }),
8810 );
8811}
8812
8813#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07008814fn test_pv_subclass_as_superclass() {
8815 let hdr = indoc! {"
8816 #include <cstdint>
8817 #include <memory>
8818
8819 class TestObserver {
8820 public:
8821 TestObserver() {}
8822 virtual void a() const = 0;
8823 virtual ~TestObserver() {}
8824 };
8825
8826 inline void call_observer(std::unique_ptr<TestObserver> obs) { obs->a(); }
8827 "};
8828 run_test_ex(
8829 "",
8830 hdr,
8831 quote! {
8832 use autocxx::subclass::CppSubclass;
8833 let obs = MyTestObserver::new_cpp_owned(
8834 MyTestObserver::default()
8835 );
8836 let obs = MyTestObserver::as_TestObserver_unique_ptr(obs);
8837 assert!(!Lazy::force(&STATUS).lock().unwrap().dropped);
8838 ffi::call_observer(obs);
8839 assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called);
8840 assert!(Lazy::force(&STATUS).lock().unwrap().dropped);
8841 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8842 },
8843 quote! {
8844 generate!("call_observer")
8845 subclass!("TestObserver",MyTestObserver)
8846 },
8847 None,
8848 None,
8849 Some(quote! {
8850 use once_cell::sync::Lazy;
8851 use std::sync::Mutex;
8852
8853 use ffi::TestObserver_methods;
8854 #[autocxx::subclass::subclass]
8855 #[derive(Default)]
8856 pub struct MyTestObserver {
8857 }
8858 impl TestObserver_methods for MyTestObserver {
8859 fn a(&self) {
8860 assert!(!Lazy::force(&STATUS).lock().unwrap().dropped);
8861 Lazy::force(&STATUS).lock().unwrap().sub_a_called = true;
8862 }
8863 }
8864 impl Drop for MyTestObserver {
8865 fn drop(&mut self) {
8866 Lazy::force(&STATUS).lock().unwrap().dropped = true;
8867 }
8868 }
8869
8870 #[derive(Default)]
8871 struct Status {
8872 sub_a_called: bool,
8873 dropped: bool,
8874 }
8875
8876 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8877 }),
8878 );
8879}
8880
8881#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07008882fn test_cycle_nonpod_simple() {
8883 let hdr = indoc! {"
8884 #include <string>
8885 struct NonPod {
8886 std::string a;
8887 };
8888 inline NonPod make_non_pod(std::string a) {
8889 NonPod p;
8890 p.a = a;
8891 return p;
8892 }
8893 inline NonPod call_n(NonPod param) {
8894 return param;
8895 }
8896 "};
8897 let rs = quote! {
8898 let nonpod = ffi::make_non_pod("hello").within_unique_ptr();
8899 ffi::call_n(nonpod).within_unique_ptr();
8900 };
8901 run_test("", hdr, rs, &["NonPod", "make_non_pod", "call_n"], &[])
8902}
8903
8904#[test]
8905fn test_pv_subclass_types() {
8906 let hdr = indoc! {"
8907 #include <cstdint>
8908 #include <string>
8909 #include <vector>
8910
8911 struct Fwd;
8912 struct Pod {
8913 uint32_t a;
8914 };
8915 struct NonPod {
8916 std::string a;
8917 };
8918 class TestObserver {
8919 public:
8920 TestObserver() {}
8921 virtual std::string s(std::string p) const { return p; }
8922 virtual Pod p(Pod p) const { return p; }
8923 virtual NonPod n(NonPod p) const { return p; }
8924 virtual void f(const Fwd&) const { }
8925 virtual std::vector<NonPod> v(std::vector<NonPod> v) const { return v; }
8926 virtual const std::vector<NonPod>& vr(const std::vector<NonPod>& vr) const { return vr; }
8927 virtual const std::vector<Fwd>& vfr(const std::vector<Fwd>& vfr) const { return vfr; }
8928 virtual ~TestObserver() {}
8929 };
8930
8931 extern TestObserver* obs;
8932
8933 inline void register_observer(TestObserver& a) {
8934 obs = &a;
8935 }
8936 inline std::string call_s(std::string param) {
8937 return obs->s(param);
8938 }
8939 inline Pod call_p(Pod param) {
8940 return obs->p(param);
8941 }
8942 inline NonPod call_n(NonPod param) {
8943 return obs->n(param);
8944 }
8945 inline NonPod make_non_pod(std::string a) {
8946 NonPod p;
8947 p.a = a;
8948 return p;
8949 }
8950 "};
8951 run_test_ex(
8952 "TestObserver* obs;",
8953 hdr,
8954 quote! {
8955 let obs = MyTestObserver::new_rust_owned(
8956 MyTestObserver::default()
8957 );
8958 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
8959 ffi::call_p(ffi::Pod { a: 3 });
8960 ffi::call_s("hello");
8961 ffi::call_n(ffi::make_non_pod("goodbye").within_unique_ptr());
8962 },
8963 quote! {
8964 generate!("register_observer")
8965 generate!("call_s")
8966 generate!("call_n")
8967 generate!("call_p")
8968 generate!("NonPod")
8969 generate!("make_non_pod")
8970 generate_pod!("Pod")
8971 subclass!("TestObserver",MyTestObserver)
8972 },
8973 None,
8974 None,
8975 Some(quote! {
8976 use autocxx::subclass::CppSubclass;
8977 use ffi::TestObserver_methods;
8978 #[autocxx::subclass::subclass]
8979 #[derive(Default)]
8980 pub struct MyTestObserver {
8981 }
8982 impl TestObserver_methods for MyTestObserver {
8983 fn s(&self, p: cxx::UniquePtr<cxx::CxxString>) -> cxx::UniquePtr<cxx::CxxString> {
8984 self.peer().s_super(p)
8985 }
8986
8987 fn p(&self, p: ffi::Pod) -> ffi::Pod {
8988 self.peer().p_super(p)
8989 }
8990
8991 fn n(&self, p: cxx::UniquePtr<ffi::NonPod>) -> cxx::UniquePtr<ffi::NonPod> {
8992 self.peer().n_super(p)
8993 }
8994 }
8995 }),
8996 );
8997}
8998
8999#[test]
9000fn test_pv_subclass_constructors() {
9001 // Also tests a Rust-side subclass type which is an empty struct
9002 let hdr = indoc! {"
9003 #include <cstdint>
9004 #include <string>
9005
9006 class TestObserver {
9007 public:
9008 TestObserver() {}
9009 TestObserver(uint8_t) {}
9010 TestObserver(std::string) {}
9011 virtual void call() const { }
9012 virtual ~TestObserver() {}
9013 };
9014
9015 extern TestObserver* obs;
9016
9017 inline void register_observer(TestObserver& a) {
9018 obs = &a;
9019 }
9020 inline void do_a_thing() {
9021 return obs->call();
9022 }
9023 "};
9024 run_test_ex(
9025 "TestObserver* obs;",
9026 hdr,
9027 quote! {
9028 let obs = MyTestObserver::new_rust_owned(
9029 MyTestObserver::default()
9030 );
9031 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
9032 ffi::do_a_thing();
9033 },
9034 quote! {
9035 generate!("register_observer")
9036 generate!("do_a_thing")
9037 subclass!("TestObserver",MyTestObserver)
9038 },
9039 None,
9040 None,
9041 Some(quote! {
9042 use autocxx::subclass::prelude::*;
9043 #[subclass]
9044 #[derive(Default)]
9045 pub struct MyTestObserver;
9046 impl ffi::TestObserver_methods for MyTestObserver {
9047 fn call(&self) {
9048 self.peer().call_super()
9049 }
9050 }
9051 impl CppPeerConstructor<ffi::MyTestObserverCpp> for MyTestObserver {
9052 fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> cxx::UniquePtr<ffi::MyTestObserverCpp> {
9053 ffi::MyTestObserverCpp::new1(peer_holder, 3u8).within_unique_ptr()
9054 }
9055 }
9056 }),
9057 );
9058}
9059
9060#[test]
9061fn test_pv_subclass_fancy_constructor() {
9062 let hdr = indoc! {"
9063 #include <cstdint>
9064
9065 class Observer {
9066 public:
9067 Observer(uint8_t) {}
9068 virtual uint32_t foo() const = 0;
9069 virtual ~Observer() {}
9070 };
9071 inline void take_observer(const Observer&) {}
9072 "};
9073 run_test_expect_fail_ex(
9074 "",
9075 hdr,
9076 quote! {
9077 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() }, ffi::MyObserverCpp::make_unique);
9078 ffi::take_observer(o.borrow().as_ref());
9079 },
9080 quote! {
9081 generate!("take_observer")
9082 subclass!("Observer",MyObserver)
9083 },
9084 None,
9085 None,
9086 Some(quote! {
9087 use autocxx::subclass::CppSubclass;
9088 use ffi::Observer_methods;
9089 #[autocxx::subclass::subclass]
9090 pub struct MyObserver {
9091 a: u32
9092 }
9093 impl Observer_methods for MyObserver {
9094 fn foo(&self) -> u32 {
9095 4
9096 }
9097 }
9098 }),
9099 );
9100}
9101
9102#[test]
9103fn test_non_pv_subclass_overloads() {
9104 let hdr = indoc! {"
9105 #include <cstdint>
9106 #include <string>
9107
9108 class TestObserver {
9109 public:
9110 TestObserver() {}
9111 virtual void call(uint8_t) const {}
9112 virtual void call(std::string) const {}
9113 virtual ~TestObserver() {}
9114 };
9115
9116 extern TestObserver* obs;
9117
9118 inline void register_observer(TestObserver& a) {
9119 obs = &a;
9120 }
9121 inline void do_a_thing() {
9122 return obs->call(8);
9123 }
9124 "};
9125 run_test_ex(
9126 "TestObserver* obs;",
9127 hdr,
9128 quote! {
9129 let obs = MyTestObserver::new_rust_owned(
9130 MyTestObserver::default()
9131 );
9132 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
9133 ffi::do_a_thing();
9134 },
9135 quote! {
9136 generate!("register_observer")
9137 generate!("do_a_thing")
9138 subclass!("TestObserver",MyTestObserver)
9139 },
9140 None,
9141 None,
9142 Some(quote! {
9143 use autocxx::subclass::prelude::*;
9144 #[subclass]
9145 #[derive(Default)]
9146 pub struct MyTestObserver;
9147 impl ffi::TestObserver_methods for MyTestObserver {
9148 fn call(&self, a: u8) {
9149 self.peer().call_super(a)
9150 }
9151 fn call1(&self, a: cxx::UniquePtr<cxx::CxxString>) {
9152 self.peer().call1_super(a)
9153 }
9154 }
9155 }),
9156 );
9157}
9158
9159#[test]
9160fn test_pv_subclass_overrides() {
9161 let hdr = indoc! {"
9162 #include <cstdint>
9163 #include <string>
9164
9165 class TestObserver {
9166 public:
9167 TestObserver() {}
9168 virtual void call(uint8_t) const = 0;
9169 virtual void call(std::string) const = 0;
9170 virtual ~TestObserver() {}
9171 };
9172
9173 extern TestObserver* obs;
9174
9175 inline void register_observer(TestObserver& a) {
9176 obs = &a;
9177 }
9178 inline void do_a_thing() {
9179 return obs->call(8);
9180 }
9181 "};
9182 run_test_ex(
9183 "TestObserver* obs;",
9184 hdr,
9185 quote! {
9186 let obs = MyTestObserver::new_rust_owned(
9187 MyTestObserver::default()
9188 );
9189 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
9190 ffi::do_a_thing();
9191 },
9192 quote! {
9193 generate!("register_observer")
9194 generate!("do_a_thing")
9195 subclass!("TestObserver",MyTestObserver)
9196 },
9197 None,
9198 None,
9199 Some(quote! {
9200 use autocxx::subclass::prelude::*;
9201 #[subclass]
9202 #[derive(Default)]
9203 pub struct MyTestObserver;
9204 impl ffi::TestObserver_methods for MyTestObserver {
9205 fn call(&self, _a: u8) {
9206 }
9207 fn call1(&self, _a: cxx::UniquePtr<cxx::CxxString>) {
9208 }
9209 }
9210 }),
9211 );
9212}
9213
9214#[test]
9215fn test_pv_subclass_namespaced_superclass() {
9216 let hdr = indoc! {"
9217 #include <cstdint>
9218
9219 namespace a {
9220 class Observer {
9221 public:
9222 Observer() {}
9223 virtual uint32_t foo() const = 0;
9224 virtual ~Observer() {}
9225 };
9226 }
9227 inline void take_observer(const a::Observer&) {}
9228 "};
9229 run_test_ex(
9230 "",
9231 hdr,
9232 quote! {
9233 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
9234 ffi::take_observer(o.borrow().as_ref());
9235 },
9236 quote! {
9237 generate!("take_observer")
9238 subclass!("a::Observer",MyObserver)
9239 },
9240 None,
9241 None,
9242 Some(quote! {
9243 use autocxx::subclass::CppSubclass;
9244 #[autocxx::subclass::subclass]
9245 pub struct MyObserver {
9246 a: u32
9247 }
9248 impl ffi::a::Observer_methods for MyObserver {
9249 fn foo(&self) -> u32 {
9250 4
9251 }
9252 }
9253 }),
9254 );
9255}
9256
9257#[test]
9258fn test_no_constructor_make_unique() {
9259 let hdr = indoc! {"
9260 #include <stdint.h>
9261 struct A {
9262 uint32_t a;
9263 };
9264 "};
9265 let rs = quote! {
9266 ffi::A::new().within_unique_ptr();
9267 };
9268 run_test("", hdr, rs, &["A"], &[]);
9269}
9270
9271#[test]
9272fn test_constructor_moveit() {
9273 let hdr = indoc! {"
9274 #include <stdint.h>
9275 #include <string>
9276 struct A {
9277 A() {}
9278 void set(uint32_t val) { a = val; }
9279 uint32_t get() const { return a; }
9280 uint32_t a;
9281 std::string so_we_are_non_trivial;
9282 };
9283 "};
9284 let rs = quote! {
9285 moveit! {
9286 let mut stack_obj = ffi::A::new();
9287 }
9288 stack_obj.as_mut().set(42);
9289 assert_eq!(stack_obj.get(), 42);
9290 };
9291 run_test("", hdr, rs, &["A"], &[]);
9292}
9293
9294#[test]
9295fn test_move_out_of_uniqueptr() {
9296 let hdr = indoc! {"
9297 #include <stdint.h>
9298 #include <string>
9299 struct A {
9300 A() {}
9301 std::string so_we_are_non_trivial;
9302 };
9303 inline A get_a() {
9304 A a;
9305 return a;
9306 }
9307 "};
9308 let rs = quote! {
9309 let a = ffi::get_a().within_unique_ptr();
9310 moveit! {
9311 let _stack_obj = autocxx::moveit::new::mov(a);
9312 }
9313 };
9314 run_test("", hdr, rs, &["A", "get_a"], &[]);
9315}
9316
9317#[test]
9318fn test_implicit_constructor_with_typedef_field() {
9319 let hdr = indoc! {"
9320 #include <stdint.h>
9321 #include <string>
9322 struct B {
9323 uint32_t b;
9324 };
9325 typedef struct B C;
9326 struct A {
9327 B field;
9328 uint32_t a;
9329 std::string so_we_are_non_trivial;
9330 };
9331 "};
9332 let rs = quote! {
9333 moveit! {
9334 let mut stack_obj = ffi::A::new();
9335 }
9336 };
9337 run_test("", hdr, rs, &["A"], &[]);
9338}
9339
9340#[test]
9341fn test_implicit_constructor_with_array_field() {
9342 let hdr = indoc! {"
9343 #include <stdint.h>
9344 #include <string>
9345 struct A {
9346 uint32_t a[3];
9347 std::string so_we_are_non_trivial;
9348 };
9349 "};
9350 let rs = quote! {
9351 moveit! {
9352 let mut _stack_obj = ffi::A::new();
9353 }
9354 };
9355 run_test("", hdr, rs, &["A"], &[]);
9356}
9357
9358#[test]
9359fn test_implicit_constructor_moveit() {
9360 let hdr = indoc! {"
9361 #include <stdint.h>
9362 #include <string>
9363 struct A {
9364 void set(uint32_t val) { a = val; }
9365 uint32_t get() const { return a; }
9366 uint32_t a;
9367 std::string so_we_are_non_trivial;
9368 };
9369 "};
9370 let rs = quote! {
9371 moveit! {
9372 let mut stack_obj = ffi::A::new();
9373 }
9374 stack_obj.as_mut().set(42);
9375 assert_eq!(stack_obj.get(), 42);
9376 };
9377 run_test("", hdr, rs, &["A"], &[]);
9378}
9379
9380#[test]
9381fn test_pass_by_value_moveit() {
9382 let hdr = indoc! {"
9383 #include <stdint.h>
9384 #include <string>
9385 struct A {
9386 void set(uint32_t val) { a = val; }
9387 uint32_t a;
9388 std::string so_we_are_non_trivial;
9389 };
9390 inline void take_a(A) {}
9391 struct B {
9392 B() {}
9393 B(const B&) {}
9394 B(B&&) {}
9395 std::string so_we_are_non_trivial;
9396 };
9397 inline void take_b(B) {}
9398 "};
9399 let rs = quote! {
9400 moveit! {
9401 let mut stack_obj = ffi::A::new();
9402 }
9403 stack_obj.as_mut().set(42);
9404 ffi::take_a(&*stack_obj);
9405 ffi::take_a(as_copy(stack_obj.as_ref()));
9406 ffi::take_a(as_copy(stack_obj.as_ref()));
9407 // A has no move constructor so we can't consume it.
9408
9409 let heap_obj = ffi::A::new().within_unique_ptr();
9410 ffi::take_a(heap_obj.as_ref().unwrap());
9411 ffi::take_a(&heap_obj);
9412 ffi::take_a(autocxx::as_copy(heap_obj.as_ref().unwrap()));
9413 ffi::take_a(heap_obj); // consume
9414
9415 let heap_obj2 = ffi::A::new().within_box();
9416 ffi::take_a(heap_obj2.as_ref().get_ref());
9417 ffi::take_a(&heap_obj2);
9418 ffi::take_a(autocxx::as_copy(heap_obj2.as_ref().get_ref()));
9419 ffi::take_a(heap_obj2); // consume
9420
9421 moveit! {
9422 let mut stack_obj = ffi::B::new();
9423 }
9424 ffi::take_b(&*stack_obj);
9425 ffi::take_b(as_copy(stack_obj.as_ref()));
9426 ffi::take_b(as_copy(stack_obj.as_ref()));
9427 ffi::take_b(as_mov(stack_obj)); // due to move constructor
9428
9429 // Test direct-from-New-to-param.
9430 ffi::take_b(as_new(ffi::B::new()));
9431 };
9432 run_test("", hdr, rs, &["A", "take_a", "B", "take_b"], &[]);
9433}
9434
9435#[test]
9436fn test_nonconst_reference_parameter() {
9437 let hdr = indoc! {"
9438 #include <stdint.h>
9439 #include <string>
9440
9441 // Force generating a wrapper for the second `take_a`.
9442 struct NOP { void take_a() {}; };
9443
9444 struct A {
9445 std::string so_we_are_non_trivial;
9446 };
9447 inline void take_a(A&) {}
9448 "};
9449 let rs = quote! {
9450 let mut heap_obj = ffi::A::new().within_unique_ptr();
9451 ffi::take_a(heap_obj.pin_mut());
9452 };
9453 run_test("", hdr, rs, &["NOP", "A", "take_a"], &[]);
9454}
9455
9456#[test]
9457fn test_nonconst_reference_method_parameter() {
9458 let hdr = indoc! {"
9459 #include <stdint.h>
9460 #include <string>
9461
9462 // Force generating a wrapper for the second `take_a`.
9463 struct NOP { void take_a() {}; };
9464
9465 struct A {
9466 std::string so_we_are_non_trivial;
9467 };
9468 struct B {
9469 inline void take_a(A&) const {}
9470 };
9471 "};
9472 let rs = quote! {
9473 let mut a = ffi::A::new().within_unique_ptr();
9474 let b = ffi::B::new().within_unique_ptr();
9475 b.take_a(a.pin_mut());
9476 };
9477 run_test("", hdr, rs, &["NOP", "A", "B"], &[]);
9478}
9479
9480fn destruction_test(ident: proc_macro2::Ident, extra_bit: Option<TokenStream>) {
9481 let hdr = indoc! {"
9482 #include <stdint.h>
9483 #include <string>
9484 extern bool gConstructed;
9485 struct A {
9486 A() { gConstructed = true; }
9487 virtual ~A() { gConstructed = false; }
9488 void set(uint32_t val) { a = val; }
9489 uint32_t get() const { return a; }
9490 uint32_t a;
9491 std::string so_we_are_non_trivial;
9492 };
9493 inline bool is_constructed() { return gConstructed; }
9494 struct B: public A {
9495 uint32_t b;
9496 };
9497 "};
9498 let cpp = indoc! {"
9499 bool gConstructed = false;
9500 "};
9501 let rs = quote! {
9502 assert!(!ffi::is_constructed());
9503 {
9504 moveit! {
9505 let mut _stack_obj = ffi::#ident::new();
9506 }
9507 assert!(ffi::is_constructed());
9508 #extra_bit
9509 }
9510 assert!(!ffi::is_constructed());
9511 };
9512 run_test(cpp, hdr, rs, &[&ident.to_string(), "is_constructed"], &[]);
9513}
9514
9515#[test]
9516fn test_destructor_moveit() {
9517 destruction_test(
9518 parse_quote! { A },
9519 Some(quote! {
9520 _stack_obj.as_mut().set(42);
9521 assert_eq!(_stack_obj.get(), 42);
9522 }),
9523 );
9524}
9525
9526#[test]
9527fn test_destructor_derived_moveit() {
9528 destruction_test(parse_quote! { B }, None);
9529}
9530
9531#[test]
9532fn test_copy_and_move_constructor_moveit() {
9533 let hdr = indoc! {"
9534 #include <stdint.h>
9535 #include <string>
9536 struct A {
9537 A() {}
9538 A(const A& other) : a(other.a+1) {}
9539 A(A&& other) : a(other.a+2) { other.a = 666; }
9540 void set(uint32_t val) { a = val; }
9541 uint32_t get() const { return a; }
9542 uint32_t a;
9543 std::string so_we_are_non_trivial;
9544 };
9545 "};
9546 let rs = quote! {
9547 moveit! {
9548 let mut stack_obj = ffi::A::new();
9549 }
9550 stack_obj.as_mut().set(42);
9551 moveit! {
9552 let stack_obj2 = autocxx::moveit::new::copy(stack_obj.as_ref());
9553 }
9554 assert_eq!(stack_obj2.get(), 43);
9555 assert_eq!(stack_obj.get(), 42);
9556 moveit! {
9557 let stack_obj3 = autocxx::moveit::new::mov(stack_obj);
9558 }
9559 assert_eq!(stack_obj3.get(), 44);
9560 // Following line prevented by moveit, even though it would
9561 // be possible in C++.
9562 // assert_eq!(stack_obj.get(), 666);
9563 };
9564 run_test("", hdr, rs, &["A"], &[]);
9565}
9566
9567// This test fails on Windows gnu but not on Windows msvc
9568#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
9569#[test]
9570fn test_uniqueptr_moveit() {
9571 let hdr = indoc! {"
9572 #include <stdint.h>
9573 #include <string>
9574 struct A {
9575 A() {}
9576 void set(uint32_t val) { a = val; }
9577 uint32_t get() const { return a; }
9578 uint32_t a;
9579 std::string so_we_are_non_trivial;
9580 };
9581 "};
9582 let rs = quote! {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009583 use autocxx::moveit::Emplace;
Brian Silverman4e662aa2022-05-11 23:10:19 -07009584 let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
9585 up_obj.as_mut().unwrap().set(42);
9586 assert_eq!(up_obj.get(), 42);
9587 };
9588 run_test("", hdr, rs, &["A"], &[]);
9589}
9590
9591// This test fails on Windows gnu but not on Windows msvc
9592#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
9593#[test]
9594fn test_various_emplacement() {
9595 let hdr = indoc! {"
9596 #include <stdint.h>
9597 #include <string>
9598 struct A {
9599 A() {}
9600 void set(uint32_t val) { a = val; }
9601 uint32_t get() const { return a; }
9602 uint32_t a;
9603 std::string so_we_are_non_trivial;
9604 };
9605 "};
9606 let rs = quote! {
Brian Silverman4e662aa2022-05-11 23:10:19 -07009607 use autocxx::moveit::Emplace;
9608 let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
9609 up_obj.pin_mut().set(666);
9610 // Can't current move out of a UniquePtr
9611 let mut box_obj = Box::emplace(ffi::A::new());
9612 box_obj.as_mut().set(667);
9613 let box_obj2 = Box::emplace(autocxx::moveit::new::mov(box_obj));
9614 moveit! { let back_on_stack = autocxx::moveit::new::mov(box_obj2); }
9615 assert_eq!(back_on_stack.get(), 667);
9616 };
9617 run_test("", hdr, rs, &["A"], &[]);
9618}
9619
9620#[test]
9621fn test_emplace_uses_overridden_new_and_delete() {
9622 let hdr = indoc! {"
9623 #include <stdint.h>
9624 #include <string>
9625 struct A {
9626 A() {}
9627 void* operator new(size_t count);
9628 void operator delete(void* ptr) noexcept;
9629 void* operator new(size_t count, void* ptr);
9630 std::string so_we_are_non_trivial;
9631 };
9632 void reset_flags();
9633 bool was_new_called();
9634 bool was_delete_called();
9635 "};
9636 let cxx = indoc! {"
9637 bool new_called;
9638 bool delete_called;
9639 void reset_flags() {
9640 new_called = false;
9641 delete_called = false;
9642 }
9643 void* A::operator new(size_t count) {
9644 new_called = true;
9645 return ::operator new(count);
9646 }
9647 void* A::operator new(size_t count, void* ptr) {
9648 return ::operator new(count, ptr);
9649 }
9650 void A::operator delete(void* ptr) noexcept {
9651 delete_called = true;
9652 ::operator delete(ptr);
9653 }
9654 bool was_new_called() {
9655 return new_called;
9656 }
9657 bool was_delete_called() {
9658 return delete_called;
9659 }
9660 "};
9661 let rs = quote! {
9662 ffi::reset_flags();
9663 {
9664 let _ = ffi::A::new().within_unique_ptr();
9665 assert!(ffi::was_new_called());
9666 }
9667 assert!(ffi::was_delete_called());
9668 ffi::reset_flags();
9669 {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009670 use autocxx::moveit::Emplace;
Brian Silverman4e662aa2022-05-11 23:10:19 -07009671 let _ = cxx::UniquePtr::emplace(ffi::A::new());
9672 }
9673 assert!(ffi::was_delete_called());
9674 };
9675 run_test(
9676 cxx,
9677 hdr,
9678 rs,
9679 &["A", "reset_flags", "was_new_called", "was_delete_called"],
9680 &[],
9681 );
9682}
9683
9684#[test]
9685fn test_pass_by_reference_to_value_param() {
9686 let hdr = indoc! {"
9687 #include <stdint.h>
9688 #include <string>
9689 struct A {
9690 A() : count(0) {}
9691 std::string so_we_are_non_trivial;
9692 uint32_t count;
9693 };
9694 void take_a(A a) {
9695 a.count++;
9696 }
9697 uint32_t report_on_a(const A& a) {
9698 return a.count;
9699 }
9700 "};
9701 let rs = quote! {
9702 let a = ffi::A::new().within_unique_ptr();
9703 ffi::take_a(a.as_ref().unwrap());
9704 ffi::take_a(&a); // syntactic sugar
9705 assert_eq!(ffi::report_on_a(&a), 0); // should have acted upon copies
9706 };
9707 run_test("", hdr, rs, &["A", "take_a", "report_on_a"], &[]);
9708}
9709
9710#[test]
9711fn test_explicit_everything() {
9712 let hdr = indoc! {"
9713 #include <stdint.h>
9714 #include <string>
9715 struct A {
9716 A() {} // default constructor
9717 A(A&&) {} // move constructor
9718 A(const A&) {} // copy constructor
9719 A& operator=(const A&) { return *this; } // copy assignment operator
9720 A& operator=(A&&) { return *this; } // move assignment operator
9721 ~A() {} // destructor
9722 void set(uint32_t val) { a = val; }
9723 uint32_t get() const { return a; }
9724 uint32_t a;
9725 std::string so_we_are_non_trivial;
9726 };
9727 "};
9728 let rs = quote! {};
9729 run_test("", hdr, rs, &["A"], &[]);
9730}
9731
9732#[test]
9733fn test_generate_ns() {
9734 let hdr = indoc! {"
9735 namespace A {
9736 inline void foo() {}
9737 inline void bar() {}
9738 }
9739 namespace B {
9740 inline void baz() {}
9741 }
9742 "};
9743 let rs = quote! {
9744 ffi::A::foo();
9745 };
9746 run_test_ex(
9747 "",
9748 hdr,
9749 rs,
9750 quote! {
9751 generate_ns!("A")
9752 safety!(unsafe_ffi)
9753 },
9754 None,
9755 None,
9756 None,
9757 );
9758}
9759
9760#[test]
9761fn test_no_constructor_make_unique_ns() {
9762 let hdr = indoc! {"
9763 #include <stdint.h>
9764 namespace B {
9765 struct A {
9766 uint32_t a;
9767 };
9768 }
9769 "};
9770 let rs = quote! {
9771 ffi::B::A::new().within_unique_ptr();
9772 };
9773 run_test("", hdr, rs, &["B::A"], &[]);
9774}
9775
9776#[test]
9777fn test_no_constructor_pod_make_unique() {
9778 let hdr = indoc! {"
9779 #include <stdint.h>
9780 struct A {
9781 uint32_t a;
9782 };
9783 "};
9784 let rs = quote! {
9785 ffi::A::new().within_unique_ptr();
9786 };
9787 run_test("", hdr, rs, &[], &["A"]);
9788}
9789
9790#[test]
9791fn test_no_constructor_pv() {
9792 let hdr = indoc! {"
9793 #include <stdint.h>
9794 class A {
9795 public:
9796 virtual ~A() {}
9797 virtual void foo() = 0;
9798 };
9799 "};
9800 let rs = quote! {};
9801 run_test("", hdr, rs, &["A"], &[]);
9802}
9803
9804#[test]
9805fn test_suppress_system_includes() {
9806 let hdr = indoc! {"
9807 #include <stdint.h>
9808 #include <string>
9809 inline void a() {};
9810 "};
9811 let rs = quote! {};
9812 run_test_ex(
9813 "",
9814 hdr,
9815 rs,
9816 quote! { generate("a")},
9817 Some(Box::new(SetSuppressSystemHeaders)),
9818 Some(Box::new(NoSystemHeadersChecker)),
9819 None,
9820 );
9821}
9822
9823#[test]
9824fn test_no_rvo_move() {
9825 let hdr = indoc! {"
9826 #include <memory>
9827 class A {
9828 public:
9829 static std::unique_ptr<A> create() { return std::make_unique<A>(); }
9830 };
9831 "};
9832 let rs = quote! {
9833 ffi::A::create();
9834 };
9835 run_test_ex(
9836 "",
9837 hdr,
9838 rs,
9839 quote! { generate!("A") },
9840 None,
9841 Some(Box::new(CppMatcher::new(
9842 &["return A::create();"],
9843 &["return std::move(A::create());"],
9844 ))),
9845 None,
9846 );
9847}
9848
9849#[test]
9850fn test_abstract_up() {
9851 let hdr = indoc! {"
9852 #include <memory>
9853 class A {
9854 public:
9855 virtual void foo() const = 0;
9856 virtual ~A() {}
9857 };
9858 class B : public A {
9859 public:
9860 void foo() const {}
9861 };
9862 inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
9863 "};
9864 let rs = quote! {
9865 let a = ffi::get_a();
9866 a.foo();
9867 };
9868 run_test("", hdr, rs, &["A", "get_a"], &[]);
9869}
9870
9871#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009872fn test_abstract_up_multiple_bridge() {
9873 let hdr = indoc! {"
9874 #include <memory>
9875 class A {
9876 public:
9877 virtual void foo() const = 0;
9878 virtual ~A() {}
9879 };
9880 class B : public A {
9881 public:
9882 void foo() const {}
9883 };
9884 inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
9885 "};
9886 let hexathorpe = Token![#](Span::call_site());
9887 let rs = quote! {
9888 autocxx::include_cpp! {
9889 #hexathorpe include "input.h"
9890 safety!(unsafe_ffi)
9891 generate!("A")
9892 }
9893 autocxx::include_cpp! {
9894 #hexathorpe include "input.h"
9895 safety!(unsafe_ffi)
9896 name!(ffi2)
9897 extern_cpp_type!("A", crate::ffi::A)
9898 generate!("get_a")
9899 }
9900 fn main() {
9901 let a = ffi2::get_a();
9902 a.foo();
9903 }
9904 };
9905 do_run_test_manual("", hdr, rs, None, None).unwrap();
9906}
9907
9908#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07009909fn test_abstract_private() {
9910 let hdr = indoc! {"
9911 #include <memory>
9912 class A {
9913 virtual void foo() const = 0;
9914 public:
9915 virtual ~A() {}
9916 };
9917 "};
9918 let rs = quote! {};
9919 run_test("", hdr, rs, &["A"], &[]);
9920}
9921
9922#[test]
9923fn test_abstract_issue_979() {
9924 let hdr = indoc! {"
9925 class Test {
9926 virtual ~Test() {}
9927 virtual void TestBody() = 0;
9928 };
9929 "};
9930 let rs = quote! {};
9931 run_test("", hdr, rs, &["Test"], &[]);
9932}
9933
9934#[test]
9935fn test_class_having_protected_method() {
9936 let hdr = indoc! {"
9937 #include <cstdint>
9938 class A {
9939 protected:
9940 inline uint32_t protected_method() { return 0; }
9941 };
9942 "};
9943 let rs = quote! {};
9944 run_test("", hdr, rs, &[], &["A"]);
9945}
9946
9947#[test]
9948fn test_protected_inner_class() {
9949 let hdr = indoc! {"
9950 #include <cstdint>
9951 inline uint32_t DoMath(uint32_t a) {
9952 return a * 3;
9953 }
9954
9955 class A {
9956 protected:
9957 inline uint32_t protected_method() { return 0; }
9958
9959 struct B {
9960 int x;
9961 };
9962
9963 inline B protected_method_2() {
9964 return { 0 };
9965 }
9966 };
9967 "};
9968 let rs = quote! {};
9969 run_test("", hdr, rs, &["A"], &[]);
9970}
9971
9972#[test]
9973fn test_private_inner_class() {
9974 let hdr = indoc! {"
9975 #include <cstdint>
9976 inline uint32_t DoMath(uint32_t a) {
9977 return a * 3;
9978 }
9979
9980 class A {
9981 protected:
9982 inline uint32_t protected_method() { return 0; }
9983
9984 private:
9985 struct B {
9986 int x;
9987 };
9988
9989 inline B private_method_2() {
9990 return { 0 };
9991 }
9992 };
9993 "};
9994 let rs = quote! {};
9995 run_test("", hdr, rs, &["A"], &[]);
9996}
9997
9998#[test]
9999fn test_class_having_private_method() {
10000 let hdr = indoc! {"
10001 #include <cstdint>
10002 class A {
10003 private:
10004 inline uint32_t private_method() { return 0; }
10005 };
10006 "};
10007 let rs = quote! {};
10008 run_test("", hdr, rs, &[], &["A"]);
10009}
10010
10011#[test]
10012#[ignore] // https://github.com/google/autocxx/issues/787
10013fn test_chrono_problem() {
10014 let hdr = indoc! {"
10015 #include <chrono>
10016 struct Clock {
10017 typedef std::chrono::nanoseconds duration;
10018 };
10019 struct Class {
10020 int a() { return 42; }
10021 std::chrono::time_point<Clock> b();
10022 };
10023 "};
10024 let rs = quote! {};
10025 run_test("", hdr, rs, &[], &["Class"]);
10026}
10027
10028fn size_and_alignment_test(pod: bool) {
10029 static TYPES: [(&str, &str); 6] = [
10030 ("A", "struct A { uint8_t a; };"),
10031 ("B", "struct B { uint32_t a; };"),
10032 ("C", "struct C { uint64_t a; };"),
10033 ("D", "enum D { Z, X };"),
10034 ("E", "struct E { uint8_t a; uint32_t b; };"),
10035 ("F", "struct F { uint32_t a; uint8_t b; };"),
10036 ];
10037 let type_definitions = TYPES.iter().map(|(_, def)| *def).join("\n");
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010038 let function_definitions = TYPES.iter().map(|(name, _)| format!("inline size_t get_sizeof_{name}() {{ return sizeof({name}); }}\ninline size_t get_alignof_{name}() {{ return alignof({name}); }}\n")).join("\n");
Brian Silverman4e662aa2022-05-11 23:10:19 -070010039 let hdr = format!(
10040 indoc! {"
10041 #include <cstdint>
10042 #include <cstddef>
10043 {}
10044 {}
10045 "},
10046 type_definitions, function_definitions
10047 );
10048 #[allow(clippy::unnecessary_to_owned)] // wrongly triggers on into_iter() below
10049 let allowlist_fns: Vec<String> = TYPES
10050 .iter()
10051 .flat_map(|(name, _)| {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010052 [format!("get_sizeof_{name}"), format!("get_alignof_{name}")]
10053 .to_vec()
10054 .into_iter()
Brian Silverman4e662aa2022-05-11 23:10:19 -070010055 })
10056 .collect_vec();
10057 let allowlist_types: Vec<String> = TYPES.iter().map(|(name, _)| name.to_string()).collect_vec();
10058 let allowlist_both = allowlist_types
10059 .iter()
10060 .cloned()
10061 .chain(allowlist_fns.iter().cloned())
10062 .collect_vec();
10063 let allowlist_types: Vec<&str> = allowlist_types.iter().map(AsRef::as_ref).collect_vec();
10064 let allowlist_fns: Vec<&str> = allowlist_fns.iter().map(AsRef::as_ref).collect_vec();
10065 let allowlist_both: Vec<&str> = allowlist_both.iter().map(AsRef::as_ref).collect_vec();
10066 let rs = TYPES.iter().fold(quote! {}, |mut accumulator, (name, _)| {
10067 let get_align_symbol =
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010068 proc_macro2::Ident::new(&format!("get_alignof_{name}"), Span::call_site());
Brian Silverman4e662aa2022-05-11 23:10:19 -070010069 let get_size_symbol =
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010070 proc_macro2::Ident::new(&format!("get_sizeof_{name}"), Span::call_site());
Brian Silverman4e662aa2022-05-11 23:10:19 -070010071 let type_symbol = proc_macro2::Ident::new(name, Span::call_site());
10072 accumulator.extend(quote! {
10073 let c_size = ffi::#get_size_symbol();
10074 let c_align = ffi::#get_align_symbol();
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010075 assert_eq!(core::mem::size_of::<ffi::#type_symbol>(), c_size);
10076 assert_eq!(core::mem::align_of::<ffi::#type_symbol>(), c_align);
Brian Silverman4e662aa2022-05-11 23:10:19 -070010077 });
10078 accumulator
10079 });
10080 if pod {
10081 run_test("", &hdr, rs, &allowlist_fns, &allowlist_types);
10082 } else {
10083 run_test("", &hdr, rs, &allowlist_both, &[]);
10084 }
10085}
10086
10087#[test]
10088fn test_sizes_and_alignment_nonpod() {
10089 size_and_alignment_test(false)
10090}
10091
10092#[test]
10093fn test_sizes_and_alignment_pod() {
10094 size_and_alignment_test(true)
10095}
10096
10097#[test]
10098fn test_nested_class_methods() {
10099 let hdr = indoc! {"
10100 #include <cstdint>
10101 class A {
10102 public:
10103 virtual ~A() {}
10104 struct B {
10105 virtual void b() const {}
10106 };
10107 virtual void a() const {}
10108 struct C {
10109 virtual void b() const {}
10110 };
10111 virtual void c() const {}
10112 struct D {
10113 virtual void b() const {}
10114 };
10115 };
10116 "};
10117 let rs = quote! {
10118 let a = ffi::A::new().within_unique_ptr();
10119 a.a();
10120 a.c();
10121 };
10122 run_test("", hdr, rs, &["A"], &[]);
10123}
10124
10125#[test]
10126fn test_call_superclass() {
10127 let hdr = indoc! {"
10128 #include <memory>
10129 class A {
10130 public:
10131 virtual void foo() const {};
10132 virtual ~A() {}
10133 };
10134 class B : public A {
10135 public:
10136 void bar() const {}
10137 };
10138 inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
10139 "};
10140 let rs = quote! {
10141 let b = ffi::get_b();
10142 b.as_ref().unwrap().as_ref().foo();
10143 };
10144 run_test("", hdr, rs, &["A", "B", "get_b"], &[]);
10145}
10146
10147#[test]
10148fn test_pass_superclass() {
10149 let hdr = indoc! {"
10150 #include <memory>
10151 class A {
10152 public:
10153 virtual void foo() const {};
10154 virtual ~A() {}
10155 };
10156 class B : public A {
10157 public:
10158 void bar() const {}
10159 };
10160 inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
10161 inline void take_a(const A&) {}
10162 "};
10163 let rs = quote! {
10164 let b = ffi::get_b();
10165 ffi::take_a(b.as_ref().unwrap().as_ref());
10166 };
10167 run_test("", hdr, rs, &["A", "B", "get_b", "take_a"], &[]);
10168}
10169
10170#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010171fn test_issue_1238() {
10172 let hdr = indoc! {"
10173 class b;
10174 class c;
10175 class f {
10176 b d();
10177 };
10178 class S2E {
10179 public:
10180 f e;
10181 b &d(c *) const;
10182 };
10183 "};
10184 let rs = quote! {};
10185 run_test("", hdr, rs, &["S2E"], &[]);
10186}
10187
10188#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -070010189fn test_issue486_multi_types() {
10190 let hdr = indoc! {"
10191 namespace a {
10192 namespace spanner {
10193 struct Key {};
10194 }
10195 } // namespace a
10196 namespace b {
10197 namespace spanner {
10198 typedef int Key;
10199 }
10200 } // namespace b
10201 namespace c {
10202 namespace spanner {
10203 enum Key { A, B };
10204 }
10205 } // namespace c
10206 namespace spanner {
10207 class Key {
10208 public:
10209 bool a(a::spanner::Key &);
10210 bool b(b::spanner::Key &);
10211 bool c(c::spanner::Key &);
10212 };
10213 } // namespace spanner
10214 "};
10215 let rs = quote! {};
10216 run_test(
10217 "",
10218 hdr,
10219 rs,
10220 &["spanner::Key", "a::spanner::Key", "b::spanner::Key"],
10221 &[],
10222 );
10223}
10224
10225#[test]
10226/// Tests types with various forms of copy, move, and default constructors. Calls the things which
10227/// should be generated, and will produce C++ compile failures if other wrappers are generated.
10228///
10229/// Specifically, we can have the cross product of any of these:
10230/// * Explicitly deleted
10231/// * Implicitly defaulted
10232/// * User declared
10233/// * Explicitly defaulted
10234/// Not handled yet: https://github.com/google/autocxx/issues/815.
10235/// Once this is handled, add equivalents of all the implicitly defaulted cases, at all
10236/// visibility levels.
10237/// applied to each of these:
10238/// * Default constructor
10239/// * Copy constructor
10240/// * Move constructor
10241/// in any of these:
10242/// * The class itself
10243/// * A base class
10244/// * A field of the class
10245/// * A field of a base class
10246/// with any of these access modifiers:
10247/// * private (impossible for implicitly defaulted)
10248/// * protected (impossible for implicitly defaulted)
10249/// * public
10250///
10251/// Various combinations of these lead to the default versions being deleted. The move and copy
10252/// ones also interact with each other in various ways.
10253///
10254/// TODO: Remove all the `int x` members after https://github.com/google/autocxx/issues/832 is
10255/// fixed.
10256fn test_implicit_constructor_rules() {
10257 let cxx = "";
10258 let hdr = indoc! {"
10259 struct AllImplicitlyDefaulted {
10260 void a() const {}
10261 };
10262
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010263 struct AllExplicitlyDefaulted {
10264 AllExplicitlyDefaulted() = default;
10265 AllExplicitlyDefaulted(const AllExplicitlyDefaulted&) = default;
10266 AllExplicitlyDefaulted(AllExplicitlyDefaulted&&) = default;
10267 void a() const {};
10268 };
10269
Brian Silverman4e662aa2022-05-11 23:10:19 -070010270 struct PublicDeleted {
10271 PublicDeleted() = delete;
10272 PublicDeleted(const PublicDeleted&) = delete;
10273 PublicDeleted(PublicDeleted&&) = delete;
10274
10275 void a() const {}
10276
10277 int x;
10278 };
10279 struct PublicDeletedDefault {
10280 PublicDeletedDefault() = delete;
10281
10282 void a() const {}
10283
10284 int x;
10285 };
10286 struct PublicDeletedCopy {
10287 PublicDeletedCopy() = default;
10288 PublicDeletedCopy(const PublicDeletedCopy&) = delete;
10289
10290 void a() const {}
10291
10292 int x;
10293 };
10294 struct PublicDeletedCopyNoDefault {
10295 PublicDeletedCopyNoDefault(const PublicDeletedCopyNoDefault&) = delete;
10296
10297 void a() const {}
10298
10299 int x;
10300 };
10301 struct PublicMoveDeletedCopy {
10302 PublicMoveDeletedCopy() = default;
10303 PublicMoveDeletedCopy(const PublicMoveDeletedCopy&) = delete;
10304 PublicMoveDeletedCopy(PublicMoveDeletedCopy&&) = default;
10305
10306 void a() const {}
10307
10308 int x;
10309 };
10310 struct PublicDeletedMove {
10311 PublicDeletedMove() = default;
10312 PublicDeletedMove(PublicDeletedMove&&) = delete;
10313
10314 void a() const {}
10315
10316 int x;
10317 };
10318 struct PublicDeletedDestructor {
10319 PublicDeletedDestructor() = default;
10320 ~PublicDeletedDestructor() = delete;
10321
10322 void a() const {}
10323
10324 int x;
10325 };
10326 struct PublicDestructor {
10327 PublicDestructor() = default;
10328 ~PublicDestructor() = default;
10329
10330 void a() const {}
10331
10332 int x;
10333 };
10334
10335 struct ProtectedDeleted {
10336 void a() const {}
10337
10338 int x;
10339
10340 protected:
10341 ProtectedDeleted() = delete;
10342 ProtectedDeleted(const ProtectedDeleted&) = delete;
10343 ProtectedDeleted(ProtectedDeleted&&) = delete;
10344 };
10345 struct ProtectedDeletedDefault {
10346 void a() const {}
10347
10348 int x;
10349
10350 protected:
10351 ProtectedDeletedDefault() = delete;
10352 };
10353 struct ProtectedDeletedCopy {
10354 ProtectedDeletedCopy() = default;
10355
10356 void a() const {}
10357
10358 int x;
10359
10360 protected:
10361 ProtectedDeletedCopy(const ProtectedDeletedCopy&) = delete;
10362 };
10363 struct ProtectedDeletedCopyNoDefault {
10364 void a() const {}
10365
10366 int x;
10367
10368 protected:
10369 ProtectedDeletedCopyNoDefault(const ProtectedDeletedCopyNoDefault&) = delete;
10370 };
10371 struct ProtectedMoveDeletedCopy {
10372 ProtectedMoveDeletedCopy() = default;
10373
10374 void a() const {}
10375
10376 int x;
10377
10378 protected:
10379 ProtectedMoveDeletedCopy(const ProtectedMoveDeletedCopy&) = delete;
10380 ProtectedMoveDeletedCopy(ProtectedMoveDeletedCopy&&) = default;
10381 };
10382 struct ProtectedDeletedMove {
10383 ProtectedDeletedMove() = default;
10384
10385 void a() const {}
10386
10387 int x;
10388
10389 protected:
10390 ProtectedDeletedMove(ProtectedDeletedMove&&) = delete;
10391 };
10392 struct ProtectedDeletedDestructor {
10393 ProtectedDeletedDestructor() = default;
10394
10395 void a() const {}
10396
10397 int x;
10398
10399 protected:
10400 ~ProtectedDeletedDestructor() = delete;
10401 };
10402 struct ProtectedDestructor {
10403 ProtectedDestructor() = default;
10404
10405 void a() const {}
10406
10407 int x;
10408
10409 protected:
10410 ~ProtectedDestructor() = default;
10411 };
10412
10413 struct PrivateDeleted {
10414 void a() const {}
10415
10416 int x;
10417
10418 private:
10419 PrivateDeleted() = delete;
10420 PrivateDeleted(const PrivateDeleted&) = delete;
10421 PrivateDeleted(PrivateDeleted&&) = delete;
10422 };
10423 struct PrivateDeletedDefault {
10424 void a() const {}
10425
10426 int x;
10427
10428 private:
10429 PrivateDeletedDefault() = delete;
10430 };
10431 struct PrivateDeletedCopy {
10432 PrivateDeletedCopy() = default;
10433
10434 void a() const {}
10435
10436 int x;
10437
10438 private:
10439 PrivateDeletedCopy(const PrivateDeletedCopy&) = delete;
10440 };
10441 struct PrivateDeletedCopyNoDefault {
10442 void a() const {}
10443
10444 int x;
10445
10446 private:
10447 PrivateDeletedCopyNoDefault(const PrivateDeletedCopyNoDefault&) = delete;
10448 };
10449 struct PrivateMoveDeletedCopy {
10450 PrivateMoveDeletedCopy() = default;
10451
10452 void a() const {}
10453
10454 int x;
10455
10456 private:
10457 PrivateMoveDeletedCopy(const PrivateMoveDeletedCopy&) = delete;
10458 PrivateMoveDeletedCopy(PrivateMoveDeletedCopy&&) = default;
10459 };
10460 struct PrivateDeletedMove {
10461 PrivateDeletedMove() = default;
10462
10463 void a() const {}
10464
10465 int x;
10466
10467 private:
10468 PrivateDeletedMove(PrivateDeletedMove&&) = delete;
10469 };
10470 struct PrivateDeletedDestructor {
10471 PrivateDeletedDestructor() = default;
10472
10473 void a() const {}
10474
10475 int x;
10476
10477 private:
10478 ~PrivateDeletedDestructor() = delete;
10479 };
10480 struct PrivateDestructor {
10481 PrivateDestructor() = default;
10482
10483 void a() const {}
10484
10485 int x;
10486
10487 private:
10488 ~PrivateDestructor() = default;
10489 };
10490
10491 struct NonConstCopy {
10492 NonConstCopy() = default;
10493
10494 NonConstCopy(NonConstCopy&) {}
10495 NonConstCopy(NonConstCopy&&) = default;
10496
10497 void a() const {}
10498 };
10499 struct TwoCopy {
10500 TwoCopy() = default;
10501
10502 TwoCopy(TwoCopy&) {}
10503 TwoCopy(const TwoCopy&) {}
10504 TwoCopy(TwoCopy&&) = default;
10505
10506 void a() const {}
10507 };
10508
10509 struct MemberPointerDeleted {
10510 PublicDeleted *x;
10511
10512 void a() const {}
10513 };
10514
10515 struct MemberConstPointerDeleted {
10516 PublicDeleted *const x;
10517
10518 void a() const {}
10519 };
10520
10521 struct MemberConst {
10522 const int x;
10523
10524 void a() const {}
10525 };
10526
10527 struct MemberReferenceDeleted {
10528 PublicDeleted &x;
10529
10530 void a() const {}
10531 };
10532
10533 struct MemberConstReferenceDeleted {
10534 const PublicDeleted &x;
10535
10536 void a() const {}
10537 };
10538
10539 struct MemberReference {
10540 int &x;
10541
10542 void a() const {}
10543 };
10544
10545 struct MemberConstReference {
10546 const int &x;
10547
10548 void a() const {}
10549 };
10550
10551 struct MemberRvalueReferenceDeleted {
10552 PublicDeleted &&x;
10553
10554 void a() const {}
10555 };
10556
10557 struct MemberRvalueReference {
10558 int &&x;
10559
10560 void a() const {}
10561 };
10562
10563 struct BasePublicDeleted : public PublicDeleted {};
10564 struct BasePublicDeletedDefault : public PublicDeletedDefault {};
10565 struct BasePublicDeletedCopy : public PublicDeletedCopy {};
10566 struct BasePublicDeletedCopyNoDefault : public PublicDeletedCopyNoDefault { };
10567 struct BasePublicMoveDeletedCopy : public PublicMoveDeletedCopy {};
10568 struct BasePublicDeletedMove : public PublicDeletedMove {};
10569 struct BasePublicDeletedDestructor : public PublicDeletedDestructor {};
10570 struct BasePublicDestructor : public PublicDestructor {};
10571
10572 struct MemberPublicDeleted {
10573 void a() const {}
10574
10575 PublicDeleted member;
10576 };
10577 struct MemberPublicDeletedDefault {
10578 void a() const {}
10579
10580 PublicDeletedDefault member;
10581 };
10582 struct MemberPublicDeletedCopy {
10583 void a() const {}
10584
10585 PublicDeletedCopy member;
10586 };
10587 struct MemberPublicDeletedCopyNoDefault {
10588 void a() const {}
10589
10590 PublicDeletedCopyNoDefault member;
10591 };
10592 struct MemberPublicMoveDeletedCopy {
10593 void a() const {}
10594
10595 PublicMoveDeletedCopy member;
10596 };
10597 struct MemberPublicDeletedMove {
10598 void a() const {}
10599
10600 PublicDeletedMove member;
10601 };
10602 struct MemberPublicDeletedDestructor {
10603 void a() const {}
10604
10605 PublicDeletedDestructor member;
10606 };
10607 struct MemberPublicDestructor {
10608 void a() const {}
10609
10610 PublicDestructor member;
10611 };
10612
10613 struct BaseMemberPublicDeleted : public MemberPublicDeleted {};
10614 struct BaseMemberPublicDeletedDefault : public MemberPublicDeletedDefault {};
10615 struct BaseMemberPublicDeletedCopy : public MemberPublicDeletedCopy {};
10616 struct BaseMemberPublicDeletedCopyNoDefault : public MemberPublicDeletedCopyNoDefault {};
10617 struct BaseMemberPublicMoveDeletedCopy : public MemberPublicMoveDeletedCopy {};
10618 struct BaseMemberPublicDeletedMove : public MemberPublicDeletedMove {};
10619 struct BaseMemberPublicDeletedDestructor : public MemberPublicDeletedDestructor {};
10620 struct BaseMemberPublicDestructor : public MemberPublicDestructor {};
10621
10622 struct BaseProtectedDeleted : public ProtectedDeleted {};
10623 struct BaseProtectedDeletedDefault : public ProtectedDeletedDefault {};
10624 struct BaseProtectedDeletedCopy : public ProtectedDeletedCopy {};
10625 struct BaseProtectedDeletedCopyNoDefault : public ProtectedDeletedCopyNoDefault {};
10626 struct BaseProtectedMoveDeletedCopy : public ProtectedMoveDeletedCopy {};
10627 struct BaseProtectedDeletedMove : public ProtectedDeletedMove {};
10628 struct BaseProtectedDeletedDestructor : public ProtectedDeletedDestructor {};
10629 struct BaseProtectedDestructor : public ProtectedDestructor {};
10630
10631 struct MemberProtectedDeleted {
10632 void a() const {}
10633
10634 ProtectedDeleted member;
10635 };
10636 struct MemberProtectedDeletedDefault {
10637 void a() const {}
10638
10639 ProtectedDeletedDefault member;
10640 };
10641 struct MemberProtectedDeletedCopy {
10642 void a() const {}
10643
10644 ProtectedDeletedCopy member;
10645 };
10646 struct MemberProtectedDeletedCopyNoDefault {
10647 void a() const {}
10648
10649 ProtectedDeletedCopyNoDefault member;
10650 };
10651 struct MemberProtectedMoveDeletedCopy {
10652 void a() const {}
10653
10654 ProtectedMoveDeletedCopy member;
10655 };
10656 struct MemberProtectedDeletedMove {
10657 void a() const {}
10658
10659 ProtectedDeletedMove member;
10660 };
10661 struct MemberProtectedDeletedDestructor {
10662 void a() const {}
10663
10664 ProtectedDeletedDestructor member;
10665 };
10666 struct MemberProtectedDestructor {
10667 void a() const {}
10668
10669 ProtectedDestructor member;
10670 };
10671
10672 struct BaseMemberProtectedDeleted : public MemberProtectedDeleted {};
10673 struct BaseMemberProtectedDeletedDefault : public MemberProtectedDeletedDefault {};
10674 struct BaseMemberProtectedDeletedCopy : public MemberProtectedDeletedCopy {};
10675 struct BaseMemberProtectedDeletedCopyNoDefault : public MemberProtectedDeletedCopyNoDefault {};
10676 struct BaseMemberProtectedMoveDeletedCopy : public MemberProtectedMoveDeletedCopy {};
10677 struct BaseMemberProtectedDeletedMove : public MemberProtectedDeletedMove {};
10678 struct BaseMemberProtectedDeletedDestructor : public MemberProtectedDeletedDestructor {};
10679 struct BaseMemberProtectedDestructor : public MemberProtectedDestructor {};
10680
10681 struct BasePrivateDeleted : public PrivateDeleted {};
10682 struct BasePrivateDeletedDefault : public PrivateDeletedDefault {};
10683 struct BasePrivateDeletedCopy : public PrivateDeletedCopy {};
10684 struct BasePrivateDeletedCopyNoDefault : public PrivateDeletedCopyNoDefault {};
10685 struct BasePrivateMoveDeletedCopy : public PrivateMoveDeletedCopy {};
10686 struct BasePrivateDeletedMove : public PrivateDeletedMove {};
10687 struct BasePrivateDeletedDestructor : public PrivateDeletedDestructor {};
10688 struct BasePrivateDestructor : public PrivateDestructor {};
10689
10690 struct MemberPrivateDeleted {
10691 void a() const {}
10692
10693 PrivateDeleted member;
10694 };
10695 struct MemberPrivateDeletedDefault {
10696 void a() const {}
10697
10698 PrivateDeletedDefault member;
10699 };
10700 struct MemberPrivateDeletedCopy {
10701 void a() const {}
10702
10703 PrivateDeletedCopy member;
10704 };
10705 struct MemberPrivateDeletedCopyNoDefault {
10706 void a() const {}
10707
10708 PrivateDeletedCopyNoDefault member;
10709 };
10710 struct MemberPrivateMoveDeletedCopy {
10711 void a() const {}
10712
10713 PrivateMoveDeletedCopy member;
10714 };
10715 struct MemberPrivateDeletedMove {
10716 void a() const {}
10717
10718 PrivateDeletedMove member;
10719 };
10720 struct MemberPrivateDeletedDestructor {
10721 void a() const {}
10722
10723 PrivateDeletedDestructor member;
10724 };
10725 struct MemberPrivateDestructor {
10726 void a() const {}
10727
10728 PrivateDestructor member;
10729 };
10730
10731 struct BaseMemberPrivateDeleted : public MemberPrivateDeleted {};
10732 struct BaseMemberPrivateDeletedDefault : public MemberPrivateDeletedDefault {};
10733 struct BaseMemberPrivateDeletedCopy : public MemberPrivateDeletedCopy {};
10734 struct BaseMemberPrivateDeletedCopyNoDefault : public MemberPrivateDeletedCopyNoDefault {};
10735 struct BaseMemberPrivateMoveDeletedCopy : public MemberPrivateMoveDeletedCopy {};
10736 struct BaseMemberPrivateDeletedMove : public MemberPrivateDeletedMove {};
10737 struct BaseMemberPrivateDeletedDestructor : public MemberPrivateDeletedDestructor {};
10738 struct BaseMemberPrivateDestructor : public MemberPrivateDestructor {};
10739 "};
10740 let rs = quote! {
10741 // Some macros to test various operations on our types. Note that some of them define
10742 // functions which take arguments that the APIs defined in this test have no way to
10743 // produce, because we have C++ types which can't be constructed (for example). In a real
10744 // program, there might be other C++ APIs which can instantiate these types.
10745
10746 // TODO: https://github.com/google/autocxx/issues/829: Should this be merged with
10747 // `test_make_unique`? Currently types where the Rust wrappers permit this but not that
10748 // aren't running C++ destructors.
10749 macro_rules! test_constructible {
10750 [$t:ty] => {
10751 moveit! {
10752 let _moveit_t = <$t>::new();
10753 }
10754 }
10755 }
10756 macro_rules! test_make_unique {
10757 [$t:ty] => {
10758 let _unique_t = <$t>::new().within_unique_ptr();
10759 }
10760 }
10761 macro_rules! test_copyable {
10762 [$t:ty] => {
10763 {
10764 fn test_copyable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
10765 moveit! {
10766 let moveit_t = moveit_t;
10767 let _copied_t = autocxx::moveit::new::copy(moveit_t);
10768 }
10769 }
10770 }
10771 }
10772 }
10773 macro_rules! test_movable {
10774 [$t:ty] => {
10775 {
10776 fn test_movable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
10777 moveit! {
10778 let moveit_t = moveit_t;
10779 let _moved_t = autocxx::moveit::new::mov(moveit_t);
10780 }
10781 }
10782 }
10783 }
10784 }
10785 macro_rules! test_call_a {
10786 [$t:ty] => {
10787 {
10788 fn test_call_a(t: &$t) {
10789 t.a();
10790 }
10791 }
10792 }
10793 }
10794 macro_rules! test_call_a_as {
10795 [$t:ty, $parent:ty] => {
10796 {
10797 fn test_call_a(t: &$t) {
10798 let t: &$parent = t.as_ref();
10799 t.a();
10800 }
10801 }
10802 }
10803 }
10804
10805 test_constructible![ffi::AllImplicitlyDefaulted];
10806 test_make_unique![ffi::AllImplicitlyDefaulted];
10807 test_copyable![ffi::AllImplicitlyDefaulted];
10808 test_movable![ffi::AllImplicitlyDefaulted];
10809 test_call_a![ffi::AllImplicitlyDefaulted];
10810
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010811 test_constructible![ffi::AllExplicitlyDefaulted];
10812 test_make_unique![ffi::AllExplicitlyDefaulted];
10813 test_copyable![ffi::AllExplicitlyDefaulted];
10814 test_movable![ffi::AllExplicitlyDefaulted];
10815 test_call_a![ffi::AllExplicitlyDefaulted];
10816
Brian Silverman4e662aa2022-05-11 23:10:19 -070010817 test_call_a![ffi::PublicDeleted];
10818
10819 test_copyable![ffi::PublicDeletedDefault];
10820 test_movable![ffi::PublicDeletedDefault];
10821 test_call_a![ffi::PublicDeletedDefault];
10822
10823 test_constructible![ffi::PublicDeletedCopy];
10824 test_make_unique![ffi::PublicDeletedCopy];
10825 test_call_a![ffi::PublicDeletedCopy];
10826
10827 test_call_a![ffi::PublicDeletedCopyNoDefault];
10828
10829 test_constructible![ffi::PublicMoveDeletedCopy];
10830 test_make_unique![ffi::PublicMoveDeletedCopy];
10831 test_movable![ffi::PublicMoveDeletedCopy];
10832 test_call_a![ffi::PublicMoveDeletedCopy];
10833
10834 test_constructible![ffi::PublicDeletedMove];
10835 test_make_unique![ffi::PublicDeletedMove];
10836 test_call_a![ffi::PublicDeletedMove];
10837
10838 test_constructible![ffi::PublicDeletedDestructor];
10839 test_copyable![ffi::PublicDeletedDestructor];
10840 test_call_a![ffi::PublicDeletedDestructor];
10841
10842 test_constructible![ffi::PublicDestructor];
10843 test_make_unique![ffi::PublicDestructor];
10844 test_copyable![ffi::PublicDestructor];
10845 test_call_a![ffi::PublicDestructor];
10846
10847 test_call_a![ffi::ProtectedDeleted];
10848
10849 test_copyable![ffi::ProtectedDeletedDefault];
10850 test_movable![ffi::ProtectedDeletedDefault];
10851 test_call_a![ffi::ProtectedDeletedDefault];
10852
10853 test_constructible![ffi::ProtectedDeletedCopy];
10854 test_make_unique![ffi::ProtectedDeletedCopy];
10855 test_call_a![ffi::ProtectedDeletedCopy];
10856
10857 test_call_a![ffi::ProtectedDeletedCopyNoDefault];
10858
10859 test_constructible![ffi::ProtectedMoveDeletedCopy];
10860 test_make_unique![ffi::ProtectedMoveDeletedCopy];
10861 test_call_a![ffi::ProtectedMoveDeletedCopy];
10862
10863 test_constructible![ffi::ProtectedDeletedMove];
10864 test_make_unique![ffi::ProtectedDeletedMove];
10865 test_call_a![ffi::ProtectedDeletedMove];
10866
10867 test_constructible![ffi::ProtectedDeletedDestructor];
10868 test_copyable![ffi::ProtectedDeletedDestructor];
10869 test_call_a![ffi::ProtectedDeletedDestructor];
10870
10871 test_constructible![ffi::ProtectedDestructor];
10872 test_copyable![ffi::ProtectedDestructor];
10873 test_call_a![ffi::ProtectedDestructor];
10874
10875 test_call_a![ffi::PrivateDeleted];
10876
10877 test_copyable![ffi::PrivateDeletedDefault];
10878 test_movable![ffi::PrivateDeletedDefault];
10879 test_call_a![ffi::PrivateDeletedDefault];
10880
10881 test_constructible![ffi::PrivateDeletedCopy];
10882 test_make_unique![ffi::PrivateDeletedCopy];
10883 test_call_a![ffi::PrivateDeletedCopy];
10884
10885 test_call_a![ffi::PrivateDeletedCopyNoDefault];
10886
10887 test_constructible![ffi::PrivateMoveDeletedCopy];
10888 test_make_unique![ffi::PrivateMoveDeletedCopy];
10889 test_call_a![ffi::PrivateMoveDeletedCopy];
10890
10891 test_constructible![ffi::PrivateDeletedMove];
10892 test_make_unique![ffi::PrivateDeletedMove];
10893 test_call_a![ffi::PrivateDeletedMove];
10894
10895 test_constructible![ffi::PrivateDeletedDestructor];
10896 test_copyable![ffi::PrivateDeletedDestructor];
10897 test_call_a![ffi::PrivateDeletedDestructor];
10898
10899 test_constructible![ffi::PrivateDestructor];
10900 test_copyable![ffi::PrivateDestructor];
10901 test_call_a![ffi::PrivateDestructor];
10902
10903 test_constructible![ffi::NonConstCopy];
10904 test_make_unique![ffi::NonConstCopy];
10905 test_movable![ffi::NonConstCopy];
10906 test_call_a![ffi::NonConstCopy];
10907
10908 test_constructible![ffi::TwoCopy];
10909 test_make_unique![ffi::TwoCopy];
10910 test_copyable![ffi::TwoCopy];
10911 test_movable![ffi::TwoCopy];
10912 test_call_a![ffi::TwoCopy];
10913
10914 // TODO: https://github.com/google/autocxx/issues/865
10915 // Treat pointers and references differently so this has a default constructor.
10916 //test_constructible![ffi::MemberPointerDeleted];
10917 //test_make_unique![ffi::MemberPointerDeleted];
10918 test_copyable![ffi::MemberPointerDeleted];
10919 test_movable![ffi::MemberPointerDeleted];
10920 test_call_a![ffi::MemberPointerDeleted];
10921
10922 test_copyable![ffi::MemberConstPointerDeleted];
10923 test_movable![ffi::MemberConstPointerDeleted];
10924 test_call_a![ffi::MemberConstPointerDeleted];
10925
10926 //test_copyable![ffi::MemberConst];
10927 //test_movable![ffi::MemberConst];
10928 //test_call_a![ffi::MemberConst];
10929
10930 test_copyable![ffi::MemberReferenceDeleted];
10931 test_movable![ffi::MemberReferenceDeleted];
10932 test_call_a![ffi::MemberReferenceDeleted];
10933
10934 test_copyable![ffi::MemberConstReferenceDeleted];
10935 test_movable![ffi::MemberConstReferenceDeleted];
10936 test_call_a![ffi::MemberConstReferenceDeleted];
10937
10938 test_copyable![ffi::MemberReference];
10939 test_movable![ffi::MemberReference];
10940 test_call_a![ffi::MemberReference];
10941
10942 test_copyable![ffi::MemberConstReference];
10943 test_movable![ffi::MemberConstReference];
10944 test_call_a![ffi::MemberConstReference];
10945
10946 test_movable![ffi::MemberRvalueReferenceDeleted];
10947 test_call_a![ffi::MemberRvalueReferenceDeleted];
10948
10949 test_movable![ffi::MemberRvalueReference];
10950 test_call_a![ffi::MemberRvalueReference];
10951
10952 test_call_a_as![ffi::BasePublicDeleted, ffi::PublicDeleted];
10953
10954 test_copyable![ffi::BasePublicDeletedDefault];
10955 test_movable![ffi::BasePublicDeletedDefault];
10956 test_call_a_as![ffi::BasePublicDeletedDefault, ffi::PublicDeletedDefault];
10957
10958 test_constructible![ffi::BasePublicDeletedCopy];
10959 test_make_unique![ffi::BasePublicDeletedCopy];
10960 test_call_a_as![ffi::BasePublicDeletedCopy, ffi::PublicDeletedCopy];
10961
10962 test_call_a_as![ffi::BasePublicDeletedCopyNoDefault, ffi::PublicDeletedCopyNoDefault];
10963
10964 test_constructible![ffi::BasePublicMoveDeletedCopy];
10965 test_make_unique![ffi::BasePublicMoveDeletedCopy];
10966 test_movable![ffi::BasePublicMoveDeletedCopy];
10967 test_call_a_as![ffi::BasePublicMoveDeletedCopy, ffi::PublicMoveDeletedCopy];
10968
10969 test_constructible![ffi::BasePublicDeletedMove];
10970 test_make_unique![ffi::BasePublicDeletedMove];
10971 test_call_a_as![ffi::BasePublicDeletedMove, ffi::PublicDeletedMove];
10972
10973 test_call_a_as![ffi::BasePublicDeletedDestructor, ffi::PublicDeletedDestructor];
10974
10975 test_constructible![ffi::BasePublicDestructor];
10976 test_make_unique![ffi::BasePublicDestructor];
10977 test_copyable![ffi::BasePublicDestructor];
10978 test_call_a_as![ffi::BasePublicDestructor, ffi::PublicDestructor];
10979
10980 test_call_a![ffi::MemberPublicDeleted];
10981
10982 test_copyable![ffi::MemberPublicDeletedDefault];
10983 test_movable![ffi::MemberPublicDeletedDefault];
10984 test_call_a![ffi::MemberPublicDeletedDefault];
10985
10986 test_constructible![ffi::MemberPublicDeletedCopy];
10987 test_make_unique![ffi::MemberPublicDeletedCopy];
10988 test_call_a![ffi::MemberPublicDeletedCopy];
10989
10990 test_call_a![ffi::MemberPublicDeletedCopyNoDefault];
10991
10992 test_constructible![ffi::MemberPublicMoveDeletedCopy];
10993 test_make_unique![ffi::MemberPublicMoveDeletedCopy];
10994 test_movable![ffi::MemberPublicMoveDeletedCopy];
10995 test_call_a![ffi::MemberPublicMoveDeletedCopy];
10996
10997 test_constructible![ffi::MemberPublicDeletedMove];
10998 test_make_unique![ffi::MemberPublicDeletedMove];
10999 test_call_a![ffi::MemberPublicDeletedMove];
11000
11001 test_call_a![ffi::MemberPublicDeletedDestructor];
11002
11003 test_constructible![ffi::MemberPublicDestructor];
11004 test_make_unique![ffi::MemberPublicDestructor];
11005 test_copyable![ffi::MemberPublicDestructor];
11006 test_call_a![ffi::MemberPublicDestructor];
11007
11008 test_call_a_as![ffi::BaseMemberPublicDeleted, ffi::MemberPublicDeleted];
11009
11010 test_copyable![ffi::BaseMemberPublicDeletedDefault];
11011 test_movable![ffi::BaseMemberPublicDeletedDefault];
11012 test_call_a_as![ffi::BaseMemberPublicDeletedDefault, ffi::MemberPublicDeletedDefault];
11013
11014 test_constructible![ffi::BaseMemberPublicDeletedCopy];
11015 test_make_unique![ffi::BaseMemberPublicDeletedCopy];
11016 test_call_a_as![ffi::BaseMemberPublicDeletedCopy, ffi::MemberPublicDeletedCopy];
11017
11018 test_call_a_as![ffi::BaseMemberPublicDeletedCopyNoDefault, ffi::MemberPublicDeletedCopyNoDefault];
11019
11020 test_constructible![ffi::BaseMemberPublicMoveDeletedCopy];
11021 test_make_unique![ffi::BaseMemberPublicMoveDeletedCopy];
11022 test_movable![ffi::BaseMemberPublicMoveDeletedCopy];
11023 test_call_a_as![ffi::BaseMemberPublicMoveDeletedCopy, ffi::MemberPublicMoveDeletedCopy];
11024
11025 test_constructible![ffi::BaseMemberPublicDeletedMove];
11026 test_make_unique![ffi::BaseMemberPublicDeletedMove];
11027 test_call_a_as![ffi::BaseMemberPublicDeletedMove, ffi::MemberPublicDeletedMove];
11028
11029 test_call_a_as![ffi::BaseMemberPublicDeletedDestructor, ffi::MemberPublicDeletedDestructor];
11030
11031 test_constructible![ffi::BaseMemberPublicDestructor];
11032 test_make_unique![ffi::BaseMemberPublicDestructor];
11033 test_copyable![ffi::BaseMemberPublicDestructor];
11034 test_call_a_as![ffi::BaseMemberPublicDestructor, ffi::MemberPublicDestructor];
11035
11036 test_call_a_as![ffi::BaseProtectedDeleted, ffi::ProtectedDeleted];
11037
11038 test_copyable![ffi::BaseProtectedDeletedDefault];
11039 test_movable![ffi::BaseProtectedDeletedDefault];
11040 test_call_a_as![ffi::BaseProtectedDeletedDefault, ffi::ProtectedDeletedDefault];
11041
11042 test_constructible![ffi::BaseProtectedDeletedCopy];
11043 test_make_unique![ffi::BaseProtectedDeletedCopy];
11044 test_call_a_as![ffi::BaseProtectedDeletedCopy, ffi::ProtectedDeletedCopy];
11045
11046 test_call_a_as![ffi::BaseProtectedDeletedCopyNoDefault, ffi::ProtectedDeletedCopyNoDefault];
11047
11048 test_constructible![ffi::BaseProtectedMoveDeletedCopy];
11049 test_make_unique![ffi::BaseProtectedMoveDeletedCopy];
11050 test_movable![ffi::BaseProtectedMoveDeletedCopy];
11051 test_call_a_as![ffi::BaseProtectedMoveDeletedCopy, ffi::ProtectedMoveDeletedCopy];
11052
11053 test_constructible![ffi::BaseProtectedDeletedMove];
11054 test_make_unique![ffi::BaseProtectedDeletedMove];
11055 test_call_a_as![ffi::BaseProtectedDeletedMove, ffi::ProtectedDeletedMove];
11056
11057 test_call_a_as![ffi::BaseProtectedDeletedDestructor, ffi::ProtectedDeletedDestructor];
11058
11059 test_constructible![ffi::BaseProtectedDestructor];
11060 test_make_unique![ffi::BaseProtectedDestructor];
11061 test_copyable![ffi::BaseProtectedDestructor];
11062 test_call_a_as![ffi::BaseProtectedDestructor, ffi::ProtectedDestructor];
11063
11064 test_call_a![ffi::MemberProtectedDeleted];
11065
11066 test_copyable![ffi::MemberProtectedDeletedDefault];
11067 test_movable![ffi::MemberProtectedDeletedDefault];
11068 test_call_a![ffi::MemberProtectedDeletedDefault];
11069
11070 test_constructible![ffi::MemberProtectedDeletedCopy];
11071 test_make_unique![ffi::MemberProtectedDeletedCopy];
11072 test_call_a![ffi::MemberProtectedDeletedCopy];
11073
11074 test_call_a![ffi::MemberProtectedDeletedCopyNoDefault];
11075
11076 test_constructible![ffi::MemberProtectedMoveDeletedCopy];
11077 test_make_unique![ffi::MemberProtectedMoveDeletedCopy];
11078 test_call_a![ffi::MemberProtectedMoveDeletedCopy];
11079
11080 test_constructible![ffi::MemberProtectedDeletedMove];
11081 test_make_unique![ffi::MemberProtectedDeletedMove];
11082 test_call_a![ffi::MemberProtectedDeletedMove];
11083
11084 test_call_a![ffi::MemberProtectedDeletedDestructor];
11085
11086 test_call_a![ffi::MemberProtectedDestructor];
11087
11088 test_call_a_as![ffi::BaseMemberProtectedDeleted, ffi::MemberProtectedDeleted];
11089
11090 test_copyable![ffi::BaseMemberProtectedDeletedDefault];
11091 test_movable![ffi::BaseMemberProtectedDeletedDefault];
11092 test_call_a_as![ffi::BaseMemberProtectedDeletedDefault, ffi::MemberProtectedDeletedDefault];
11093
11094 test_constructible![ffi::BaseMemberProtectedDeletedCopy];
11095 test_make_unique![ffi::BaseMemberProtectedDeletedCopy];
11096 test_call_a_as![ffi::BaseMemberProtectedDeletedCopy, ffi::MemberProtectedDeletedCopy];
11097
11098 test_call_a_as![ffi::BaseMemberProtectedDeletedCopyNoDefault, ffi::MemberProtectedDeletedCopyNoDefault];
11099
11100 test_constructible![ffi::BaseMemberProtectedMoveDeletedCopy];
11101 test_make_unique![ffi::BaseMemberProtectedMoveDeletedCopy];
11102 test_call_a_as![ffi::BaseMemberProtectedMoveDeletedCopy, ffi::MemberProtectedMoveDeletedCopy];
11103
11104 test_constructible![ffi::BaseMemberProtectedDeletedMove];
11105 test_make_unique![ffi::BaseMemberProtectedDeletedMove];
11106 test_call_a_as![ffi::BaseMemberProtectedDeletedMove, ffi::MemberProtectedDeletedMove];
11107
11108 test_call_a_as![ffi::BaseMemberProtectedDeletedDestructor, ffi::MemberProtectedDeletedDestructor];
11109
11110 test_call_a_as![ffi::BaseMemberProtectedDestructor, ffi::MemberProtectedDestructor];
11111
11112 test_call_a_as![ffi::BasePrivateDeleted, ffi::PrivateDeleted];
11113
11114 test_copyable![ffi::BasePrivateDeletedDefault];
11115 test_movable![ffi::BasePrivateDeletedDefault];
11116 test_call_a_as![ffi::BasePrivateDeletedDefault, ffi::PrivateDeletedDefault];
11117
11118 test_constructible![ffi::BasePrivateDeletedCopy];
11119 test_make_unique![ffi::BasePrivateDeletedCopy];
11120 test_call_a_as![ffi::BasePrivateDeletedCopy, ffi::PrivateDeletedCopy];
11121
11122 test_call_a_as![ffi::BasePrivateDeletedCopyNoDefault, ffi::PrivateDeletedCopyNoDefault];
11123
11124 test_constructible![ffi::BasePrivateMoveDeletedCopy];
11125 test_make_unique![ffi::BasePrivateMoveDeletedCopy];
11126 test_call_a_as![ffi::BasePrivateMoveDeletedCopy, ffi::PrivateMoveDeletedCopy];
11127
11128 test_constructible![ffi::BasePrivateDeletedMove];
11129 test_make_unique![ffi::BasePrivateDeletedMove];
11130 test_call_a_as![ffi::BasePrivateDeletedMove, ffi::PrivateDeletedMove];
11131
11132 test_call_a_as![ffi::BasePrivateDeletedDestructor, ffi::PrivateDeletedDestructor];
11133
11134 test_call_a_as![ffi::BasePrivateDestructor, ffi::PrivateDestructor];
11135
11136 test_call_a![ffi::MemberPrivateDeleted];
11137
11138 test_copyable![ffi::MemberPrivateDeletedDefault];
11139 test_movable![ffi::MemberPrivateDeletedDefault];
11140 test_call_a![ffi::MemberPrivateDeletedDefault];
11141
11142 test_constructible![ffi::MemberPrivateDeletedCopy];
11143 test_make_unique![ffi::MemberPrivateDeletedCopy];
11144 test_call_a![ffi::MemberPrivateDeletedCopy];
11145
11146 test_call_a![ffi::MemberPrivateDeletedCopyNoDefault];
11147
11148 test_constructible![ffi::MemberPrivateMoveDeletedCopy];
11149 test_make_unique![ffi::MemberPrivateMoveDeletedCopy];
11150 test_call_a![ffi::MemberPrivateMoveDeletedCopy];
11151
11152 test_constructible![ffi::MemberPrivateDeletedMove];
11153 test_make_unique![ffi::MemberPrivateDeletedMove];
11154 test_call_a![ffi::MemberPrivateDeletedMove];
11155
11156 test_call_a![ffi::MemberPrivateDeletedDestructor];
11157
11158 test_call_a![ffi::MemberPrivateDestructor];
11159
11160 test_call_a_as![ffi::BaseMemberPrivateDeleted, ffi::MemberPrivateDeleted];
11161
11162 test_copyable![ffi::BaseMemberPrivateDeletedDefault];
11163 test_movable![ffi::BaseMemberPrivateDeletedDefault];
11164 test_call_a_as![ffi::BaseMemberPrivateDeletedDefault, ffi::MemberPrivateDeletedDefault];
11165
11166 test_constructible![ffi::BaseMemberPrivateDeletedCopy];
11167 test_make_unique![ffi::BaseMemberPrivateDeletedCopy];
11168 test_call_a_as![ffi::BaseMemberPrivateDeletedCopy, ffi::MemberPrivateDeletedCopy];
11169
11170 test_call_a_as![ffi::BaseMemberPrivateDeletedCopyNoDefault, ffi::MemberPrivateDeletedCopyNoDefault];
11171
11172 test_constructible![ffi::BaseMemberPrivateMoveDeletedCopy];
11173 test_make_unique![ffi::BaseMemberPrivateMoveDeletedCopy];
11174 test_call_a_as![ffi::BaseMemberPrivateMoveDeletedCopy, ffi::MemberPrivateMoveDeletedCopy];
11175
11176 test_constructible![ffi::BaseMemberPrivateDeletedMove];
11177 test_make_unique![ffi::BaseMemberPrivateDeletedMove];
11178 test_call_a_as![ffi::BaseMemberPrivateDeletedMove, ffi::MemberPrivateDeletedMove];
11179
11180 test_call_a_as![ffi::BaseMemberPrivateDeletedDestructor, ffi::MemberPrivateDeletedDestructor];
11181
11182 test_call_a_as![ffi::BaseMemberPrivateDestructor, ffi::MemberPrivateDestructor];
11183 };
11184 run_test(
11185 cxx,
11186 hdr,
11187 rs,
11188 &[
11189 "AllImplicitlyDefaulted",
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011190 "AllExplicitlyDefaulted",
Brian Silverman4e662aa2022-05-11 23:10:19 -070011191 "PublicDeleted",
11192 "PublicDeletedDefault",
11193 "PublicDeletedCopy",
11194 "PublicDeletedCopyNoDefault",
11195 "PublicMoveDeletedCopy",
11196 "PublicDeletedMove",
11197 "PublicDeletedDestructor",
11198 "PublicDestructor",
11199 "ProtectedDeleted",
11200 "ProtectedDeletedDefault",
11201 "ProtectedDeletedCopy",
11202 "ProtectedDeletedCopyNoDefault",
11203 "ProtectedMoveDeletedCopy",
11204 "ProtectedDeletedMove",
11205 "ProtectedDeletedDestructor",
11206 "ProtectedDestructor",
11207 "PrivateDeleted",
11208 "PrivateDeletedDefault",
11209 "PrivateDeletedCopy",
11210 "PrivateDeletedCopyNoDefault",
11211 "PrivateMoveDeletedCopy",
11212 "PrivateDeletedMove",
11213 "PrivateDeletedDestructor",
11214 "PrivateDestructor",
11215 "NonConstCopy",
11216 "TwoCopy",
11217 "MemberPointerDeleted",
11218 "MemberConstPointerDeleted",
11219 // TODO: Handle top-level const on C++ members correctly.
11220 //"MemberConst",
11221 "MemberReferenceDeleted",
11222 "MemberConstReferenceDeleted",
11223 "MemberReference",
11224 "MemberConstReference",
11225 "MemberRvalueReferenceDeleted",
11226 "MemberRvalueReference",
11227 "BasePublicDeleted",
11228 "BasePublicDeletedDefault",
11229 "BasePublicDeletedCopy",
11230 "BasePublicDeletedCopyNoDefault",
11231 "BasePublicMoveDeletedCopy",
11232 "BasePublicDeletedMove",
11233 "BasePublicDeletedDestructor",
11234 "BasePublicDestructor",
11235 "MemberPublicDeleted",
11236 "MemberPublicDeletedDefault",
11237 "MemberPublicDeletedCopy",
11238 "MemberPublicDeletedCopyNoDefault",
11239 "MemberPublicMoveDeletedCopy",
11240 "MemberPublicDeletedMove",
11241 "MemberPublicDeletedDestructor",
11242 "MemberPublicDestructor",
11243 "BaseMemberPublicDeleted",
11244 "BaseMemberPublicDeletedDefault",
11245 "BaseMemberPublicDeletedCopy",
11246 "BaseMemberPublicDeletedCopyNoDefault",
11247 "BaseMemberPublicMoveDeletedCopy",
11248 "BaseMemberPublicDeletedMove",
11249 "BaseMemberPublicDeletedDestructor",
11250 "BaseMemberPublicDestructor",
11251 "BaseProtectedDeleted",
11252 "BaseProtectedDeletedDefault",
11253 "BaseProtectedDeletedCopy",
11254 "BaseProtectedDeletedCopyNoDefault",
11255 "BaseProtectedMoveDeletedCopy",
11256 "BaseProtectedDeletedMove",
11257 "BaseProtectedDeletedDestructor",
11258 "BaseProtectedDestructor",
11259 "MemberProtectedDeleted",
11260 "MemberProtectedDeletedDefault",
11261 "MemberProtectedDeletedCopy",
11262 "MemberProtectedDeletedCopyNoDefault",
11263 "MemberProtectedMoveDeletedCopy",
11264 "MemberProtectedDeletedMove",
11265 "MemberProtectedDeletedDestructor",
11266 "MemberProtectedDestructor",
11267 "BaseMemberProtectedDeleted",
11268 "BaseMemberProtectedDeletedDefault",
11269 "BaseMemberProtectedDeletedCopy",
11270 "BaseMemberProtectedDeletedCopyNoDefault",
11271 "BaseMemberProtectedMoveDeletedCopy",
11272 "BaseMemberProtectedDeletedMove",
11273 "BaseMemberProtectedDeletedDestructor",
11274 "BaseMemberProtectedDestructor",
11275 "BasePrivateDeleted",
11276 "BasePrivateDeletedDefault",
11277 "BasePrivateDeletedCopy",
11278 "BasePrivateDeletedCopyNoDefault",
11279 "BasePrivateMoveDeletedCopy",
11280 "BasePrivateDeletedMove",
11281 "BasePrivateDeletedDestructor",
11282 "BasePrivateDestructor",
11283 "MemberPrivateDeleted",
11284 "MemberPrivateDeletedDefault",
11285 "MemberPrivateDeletedCopy",
11286 "MemberPrivateDeletedCopyNoDefault",
11287 "MemberPrivateMoveDeletedCopy",
11288 "MemberPrivateDeletedMove",
11289 "MemberPrivateDeletedDestructor",
11290 "MemberPrivateDestructor",
11291 "BaseMemberPrivateDeleted",
11292 "BaseMemberPrivateDeletedDefault",
11293 "BaseMemberPrivateDeletedCopy",
11294 "BaseMemberPrivateDeletedCopyNoDefault",
11295 "BaseMemberPrivateMoveDeletedCopy",
11296 "BaseMemberPrivateDeletedMove",
11297 "BaseMemberPrivateDeletedDestructor",
11298 "BaseMemberPrivateDestructor",
11299 ],
11300 &[],
11301 );
11302}
11303
11304#[test]
11305/// Test that destructors hidden in various places are correctly called.
11306///
11307/// Some types are excluded because we know they behave poorly due to
11308/// https://github.com/google/autocxx/issues/829.
11309fn test_tricky_destructors() {
11310 let cxx = "";
11311 let hdr = indoc! {"
11312 #include <stdio.h>
11313 #include <stdlib.h>
11314 // A simple type to let Rust verify the destructor is run.
11315 struct DestructorFlag {
11316 DestructorFlag() = default;
11317 DestructorFlag(const DestructorFlag&) = default;
11318 DestructorFlag(DestructorFlag&&) = default;
11319
11320 ~DestructorFlag() {
11321 if (!flag) return;
11322 if (*flag) {
11323 fprintf(stderr, \"DestructorFlag is already set\\n\");
11324 abort();
11325 }
11326 *flag = true;
11327 // Note we deliberately do NOT clear the value of `flag`, to catch Rust calling
11328 // this destructor twice.
11329 }
11330
11331 bool *flag = nullptr;
11332 };
11333
11334 struct ImplicitlyDefaulted {
11335 DestructorFlag flag;
11336
11337 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11338 };
11339 struct ExplicitlyDefaulted {
11340 ExplicitlyDefaulted() = default;
11341 ~ExplicitlyDefaulted() = default;
11342
11343 DestructorFlag flag;
11344
11345 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11346 };
11347 struct Explicit {
11348 Explicit() = default;
11349 ~Explicit() {}
11350
11351 DestructorFlag flag;
11352
11353 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11354 };
11355
11356 struct BaseImplicitlyDefaulted : public ImplicitlyDefaulted {
11357 void set_flag(bool *flag_pointer) { ImplicitlyDefaulted::set_flag(flag_pointer); }
11358 };
11359 struct BaseExplicitlyDefaulted : public ExplicitlyDefaulted {
11360 void set_flag(bool *flag_pointer) { ExplicitlyDefaulted::set_flag(flag_pointer); }
11361 };
11362 struct BaseExplicit : public Explicit {
11363 void set_flag(bool *flag_pointer) { Explicit::set_flag(flag_pointer); }
11364 };
11365
11366 struct MemberImplicitlyDefaulted {
11367 ImplicitlyDefaulted member;
11368
11369 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11370 };
11371 struct MemberExplicitlyDefaulted {
11372 ExplicitlyDefaulted member;
11373
11374 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11375 };
11376 struct MemberExplicit {
11377 Explicit member;
11378
11379 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11380 };
11381
11382 struct BaseMemberImplicitlyDefaulted : public MemberImplicitlyDefaulted {
11383 void set_flag(bool *flag_pointer) { MemberImplicitlyDefaulted::set_flag(flag_pointer); }
11384 };
11385 struct BaseMemberExplicitlyDefaulted : public MemberExplicitlyDefaulted {
11386 void set_flag(bool *flag_pointer) { MemberExplicitlyDefaulted::set_flag(flag_pointer); }
11387 };
11388 struct BaseMemberExplicit : public MemberExplicit {
11389 void set_flag(bool *flag_pointer) { MemberExplicit::set_flag(flag_pointer); }
11390 };
11391 "};
11392 let rs = quote! {
11393 macro_rules! test_type {
11394 [$t:ty] => {
11395 let mut unique_t = <$t>::new().within_unique_ptr();
11396 let mut destructor_flag = false;
11397 unsafe {
11398 unique_t.pin_mut().set_flag(&mut destructor_flag);
11399 }
11400 std::mem::drop(unique_t);
11401 assert!(destructor_flag, "Destructor did not run with make_unique for {}", quote::quote!{$t});
11402
11403 moveit! {
11404 let mut moveit_t = <$t>::new();
11405 }
11406 let mut destructor_flag = false;
11407 unsafe {
11408 moveit_t.as_mut().set_flag(&mut destructor_flag);
11409 }
11410 std::mem::drop(moveit_t);
11411 assert!(destructor_flag, "Destructor did not run with moveit for {}", quote::quote!{$t});
11412 }
11413 }
11414
11415 test_type![ffi::ImplicitlyDefaulted];
11416 test_type![ffi::ExplicitlyDefaulted];
11417 test_type![ffi::Explicit];
11418 test_type![ffi::BaseImplicitlyDefaulted];
11419 test_type![ffi::BaseExplicitlyDefaulted];
11420 test_type![ffi::BaseExplicit];
11421 test_type![ffi::MemberImplicitlyDefaulted];
11422 test_type![ffi::MemberExplicitlyDefaulted];
11423 test_type![ffi::MemberExplicit];
11424 test_type![ffi::BaseMemberImplicitlyDefaulted];
11425 test_type![ffi::BaseMemberExplicitlyDefaulted];
11426 test_type![ffi::BaseMemberExplicit];
11427 };
11428 run_test(
11429 cxx,
11430 hdr,
11431 rs,
11432 &[
11433 "DestructorFlag",
11434 "ImplicitlyDefaulted",
11435 "ExplicitlyDefaulted",
11436 "Explicit",
11437 "BaseImplicitlyDefaulted",
11438 "BaseExplicitlyDefaulted",
11439 "BaseExplicit",
11440 "MemberImplicitlyDefaulted",
11441 "MemberExplicitlyDefaulted",
11442 "MemberExplicit",
11443 "BaseMemberImplicitlyDefaulted",
11444 "BaseMemberExplicitlyDefaulted",
11445 "BaseMemberExplicit",
11446 ],
11447 &[],
11448 );
11449}
11450
11451#[test]
11452fn test_concretize() {
11453 let hdr = indoc! {"
11454 #include <string>
11455 template<typename CONTENTS>
11456 class Container {
11457 private:
11458 CONTENTS* contents;
11459 };
11460 struct B {
11461 std::string a;
11462 };
11463 "};
11464 run_test_ex(
11465 "",
11466 hdr,
11467 quote! {},
11468 quote! {
11469 concrete!("Container<B>", ContainerOfB)
11470 generate!("B")
11471 },
11472 None,
11473 None,
11474 Some(quote! {
11475 struct HasAField {
11476 contents: ffi::ContainerOfB
11477 }
11478 }),
11479 );
11480}
11481
11482#[test]
11483fn test_doc_comments_survive() {
11484 let hdr = indoc! {"
11485 #include <cstdint>
11486 /// Struct line A
11487 /// Struct line B
11488 struct A { int b; };
11489
11490 /// POD struct line A
11491 /// POD struct line B
11492 struct B {
11493 /// Field line A
11494 /// Field line B
11495 uint32_t b;
11496
11497 /// Method line A
11498 /// Method line B
11499 void foo() {}
11500 };
11501
11502 /// Enum line A
11503 /// Enum line B
11504 enum C {
11505 /// Variant line A
11506 /// Variant line B
11507 VARIANT,
11508 };
11509
11510 /// Function line A
11511 /// Function line B
11512 inline void D() {}
11513 "};
11514
11515 let expected_messages = [
11516 "Struct",
11517 "POD struct",
11518 "Field",
11519 "Method",
11520 "Enum",
11521 "Variant",
11522 "Function",
11523 ]
11524 .into_iter()
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011525 .flat_map(|l| [format!("{l} line A"), format!("{l} line B")])
Brian Silverman4e662aa2022-05-11 23:10:19 -070011526 .collect_vec();
11527
11528 run_test_ex(
11529 "",
11530 hdr,
11531 quote! {},
11532 directives_from_lists(&["A", "C", "D"], &["B"], None),
11533 None,
11534 Some(make_string_finder(expected_messages)),
11535 None,
11536 );
11537}
11538
11539#[test]
11540fn optional_param_in_copy_constructor() {
11541 let hdr = indoc! {"
11542 struct A {
11543 A(const A &other, bool optional_arg = false);
11544 };
11545 "};
11546 run_test("", hdr, quote! {}, &["A"], &[]);
11547}
11548
11549#[test]
11550fn param_in_copy_constructor() {
11551 let hdr = indoc! {"
11552 struct A {
11553 A(const A &other, bool arg);
11554 };
11555 "};
11556 run_test("", hdr, quote! {}, &["A"], &[]);
11557}
11558
11559#[test]
11560fn test_variadic() {
11561 let hdr = indoc! {"
11562 class SomeClass{
11563 public:
11564 inline void foo(int, ... ) {}
11565 };
11566 "};
11567 run_test("", hdr, quote! {}, &["SomeClass"], &[]);
11568}
11569
11570#[test]
11571fn test_typedef_to_enum() {
11572 let hdr = indoc! {"
11573 enum b {};
11574 class c {
11575 public:
11576 typedef b d;
11577 d e();
11578 };
11579 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011580 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011581}
11582
11583#[test]
11584fn test_typedef_to_ns_enum() {
11585 let hdr = indoc! {"
11586 namespace a {
11587 enum b {};
11588 class c {
11589 public:
11590 typedef b d;
11591 d e();
11592 };
11593 } // namespace
11594 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011595 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011596}
11597
11598#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011599fn test_enum_in_ns() {
11600 let hdr = indoc! {"
11601 namespace a {
11602 enum b {};
11603 } // namespace
11604 "};
11605 run_test("", hdr, quote! {}, &["a::b"], &[]);
11606}
11607
11608#[test]
11609fn test_recursive_field() {
11610 let hdr = indoc! {"
11611 #include <memory>
11612 struct A {
11613 std::unique_ptr<A> a;
11614 };
11615 "};
11616 run_test("", hdr, quote! {}, &["A"], &[]);
11617}
11618
11619#[test]
11620fn test_recursive_field_indirect() {
11621 let hdr = indoc! {"
11622 #include <memory>
11623 struct B;
11624 struct A {
11625 std::unique_ptr<B> a;
11626 };
11627 struct B {
11628 std::unique_ptr<A> a1;
11629 A a2;
11630 };
11631 "};
11632 run_test("", hdr, quote! {}, &["A", "B"], &[]);
11633}
11634
11635#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -070011636fn test_typedef_unsupported_type_pub() {
11637 let hdr = indoc! {"
11638 #include <set>
11639 namespace NS{
11640 class cls{
11641 public:
11642 typedef std::set<int> InnerType;
11643 };
11644 }
11645 "};
11646
11647 run_test_ex(
11648 "",
11649 hdr,
11650 quote! {},
11651 quote! { generate_ns!("NS") },
11652 None,
11653 None,
11654 None,
11655 );
11656}
11657
11658#[test]
11659fn test_typedef_unsupported_type_pri() {
11660 let hdr = indoc! {"
11661 #include <set>
11662 namespace NS{
11663 class cls{
11664 private:
11665 typedef std::set<int> InnerType;
11666 };
11667 }
11668 "};
11669
11670 run_test_ex(
11671 "",
11672 hdr,
11673 quote! {},
11674 quote! { generate_ns!("NS") },
11675 None,
11676 None,
11677 None,
11678 );
11679}
11680
11681#[test]
11682fn test_array_trouble1() {
11683 let hdr = indoc! {"
11684 namespace a {
11685 template <typename b> struct array {
11686 typedef b c;
11687 typedef c d;
11688 };
11689 } // namespace a
11690 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011691 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011692}
11693
11694#[test]
11695fn test_array_trouble2() {
11696 let hdr = indoc! {"
11697 template <typename b> struct array {
11698 typedef b c;
11699 typedef c d;
11700 };
11701 "};
11702 run_test("", hdr, quote! {}, &["array_d"], &[]);
11703}
11704
11705#[test]
11706fn test_issue_1087a() {
11707 let hdr = indoc! {"
11708 template <typename _CharT> class a {
11709 _CharT b;
11710 };
11711 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011712 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011713}
11714
11715#[test]
11716fn test_issue_1087b() {
11717 let hdr = indoc! {"
11718 template <typename _CharT> class a {
11719 typedef _CharT b;
11720 b c;
11721 };
11722 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011723 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011724}
11725
11726#[test]
11727fn test_issue_1087c() {
11728 let hdr = indoc! {"
11729 namespace {
11730 namespace {
11731 template <typename _CharT> class a {
11732 typedef _CharT b;
11733 b c;
11734 };
11735 }
11736 }
11737 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011738 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011739}
11740
11741#[test]
11742fn test_issue_1089() {
11743 let hdr = indoc! {"
11744 namespace a {
11745 template <typename c, c> struct d;
11746 template <bool, typename, typename> struct ab;
11747 inline namespace {
11748 namespace ac {
11749 template <typename, template <typename> class, typename> struct bh;
11750 template <template <typename> class ad, typename... bi>
11751 using bj = bh<void, ad, bi...>;
11752 template <typename ad> using bk = typename ad::b;
11753 template <typename> struct bm;
11754 } // namespace ac
11755 template <typename ad>
11756 struct b : ab<ac::bj<ac::bk, ad>::e, ac::bm<ad>, d<bool, ad ::e>>::bg {};
11757 } // namespace
11758 } // namespace a
11759 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011760 run_generate_all_test(hdr);
11761}
11762
11763/// The problem here is that 'g' doesn't get annotated with
11764/// the unused_template semantic attribute.
11765/// This seems to be because both g and f have template
11766/// parameters, so they're all "used", but effectively cancel
11767/// out and thus bindgen generates
11768/// pub type g = root::b::f;
11769/// So, what we should do here is spot any typedef depending
11770/// on a template which takes template args, and reject that too.
11771/// Probably.
11772#[test]
11773#[ignore] // https://github.com/google/autocxx/pull/1094
11774fn test_issue_1094() {
11775 let hdr = indoc! {"
11776 namespace {
11777 typedef int a;
11778 }
11779 namespace b {
11780 template <typename> struct c;
11781 template <typename d, d e> using f = __make_integer_seq<c, d, e>;
11782 template <a e> using g = f<a, e>;
11783 } // namespace b
11784 "};
11785 run_generate_all_test(hdr);
11786}
11787
11788#[test]
11789fn test_issue_1096a() {
11790 let hdr = indoc! {"
11791 namespace a {
11792 class b {
11793 class c;
11794 };
11795 } // namespace a
11796 "};
11797 run_generate_all_test(hdr);
11798}
11799
11800#[test]
11801fn test_issue_1096b() {
11802 let hdr = indoc! {"
11803 namespace a {
11804 class b {
11805 public:
11806 class c;
11807 };
11808 } // namespace a
11809 "};
11810 run_generate_all_test(hdr);
11811}
11812
11813#[test]
11814fn test_issue_1096c() {
11815 let hdr = indoc! {"
11816 namespace a {
11817 class b {
11818 public:
11819 class c {
11820 public:
11821 int d;
11822 };
11823 };
11824 } // namespace a
11825 "};
11826 run_generate_all_test(hdr);
11827}
11828
11829#[test]
11830fn test_issue_1096d() {
11831 let hdr = indoc! {"
11832 namespace a {
11833 class b {
11834 private:
11835 class c {
11836 public:
11837 int d;
11838 };
11839 };
11840 } // namespace a
11841 "};
11842 run_generate_all_test(hdr);
11843}
11844
11845#[test]
11846fn test_issue_1096e() {
11847 let hdr = indoc! {"
11848 namespace a {
11849 class b {
11850 private:
11851 enum c {
11852 D,
11853 };
11854 };
11855 } // namespace a
11856 "};
11857 run_generate_all_test(hdr);
11858}
11859
11860/// Unclear why minimization resulted in this particular test case.
11861#[test]
11862#[ignore] // https://github.com/google/autocxx/pull/1097
11863fn test_issue_1097() {
11864 let hdr = indoc! {"
11865 namespace rust {
11866 inline namespace a {
11867 class Str {
11868 public:
11869 ~Str();
11870 };
11871 } // namespace a
11872 } // namespace rust
11873 "};
11874 run_generate_all_test(hdr);
11875}
11876
11877#[test]
11878fn test_issue_1098a() {
11879 let hdr = indoc! {"
11880 namespace {
11881 namespace {
11882 template <typename _CharT> class a {
11883 typedef _CharT b;
11884 b c;
11885 };
11886 template <typename _CharT> class d : a<_CharT> {};
11887 } // namespace
11888 } // namespace
11889 "};
11890 run_generate_all_test(hdr);
11891}
11892
11893/// Need to spot structs like this:
11894/// pub struct d<_CharT> {
11895/// _base: root::a<_CharT>,
11896/// }
11897/// and not create concrete types where the inner type is something from
11898/// the outer context.
11899#[test]
11900fn test_issue_1098b() {
11901 let hdr = indoc! {"
11902 template <typename _CharT> class a {
11903 typedef _CharT b;
11904 b c;
11905 };
11906 template <typename _CharT> class d : a<_CharT> {};
11907 "};
11908 run_generate_all_test(hdr);
11909}
11910
11911#[test]
11912fn test_issue_1098c() {
11913 let hdr = indoc! {"
11914 namespace {
11915 namespace {
11916 struct A {
11917 int a;
11918 };
11919 typedef A B;
11920 } // namespace
11921 } // namespace
11922 inline void take_b(const B&) {}
11923 "};
11924 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011925}
11926
11927#[test]
11928fn test_pass_rust_str_and_return_struct() {
11929 let cxx = indoc! {"
11930 A take_str_return_struct(rust::Str) {
11931 A a;
11932 return a;
11933 }
11934 "};
11935 let hdr = indoc! {"
11936 #include <cxx.h>
11937 struct A {};
11938 A take_str_return_struct(rust::Str);
11939 "};
11940 let rs = quote! {
11941 ffi::take_str_return_struct("hi");
11942 };
11943 run_test(cxx, hdr, rs, &["take_str_return_struct"], &[]);
11944}
11945
11946#[test]
11947fn test_issue_1065a() {
11948 let hdr = indoc! {"
11949 #include <memory>
11950 #include <vector>
11951
11952 template <typename at> class au {
11953 std::unique_ptr<at> aw;
11954 };
11955 class bb;
11956 using bc = au<bb>;
11957 class RenderFrameHost {
11958 public:
11959 virtual std::vector<bc> &bd() = 0;
11960 virtual ~RenderFrameHost() {}
11961 };
11962 "};
11963 let rs = quote! {};
11964 run_test("", hdr, rs, &["RenderFrameHost"], &[]);
11965}
11966
11967#[test]
11968fn test_issue_1065b() {
11969 let hdr = indoc! {"
11970 #include <memory>
11971 #include <vector>
11972
11973 class bb;
11974 using bc = std::unique_ptr<bb>;
11975 class RenderFrameHost {
11976 public:
11977 virtual std::vector<bc> &bd() = 0;
11978 virtual ~RenderFrameHost() {}
11979 };
11980 "};
11981 let rs = quote! {};
11982 run_test("", hdr, rs, &["RenderFrameHost"], &[]);
11983}
11984
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011985#[test]
11986fn test_issue_1081() {
11987 let hdr = indoc! {"
11988 namespace libtorrent {
11989 char version;
11990 }
11991 namespace libtorrent {
11992 struct session;
11993 }
11994 "};
11995 let rs = quote! {};
11996 run_test("", hdr, rs, &["libtorrent::session"], &[]);
11997}
11998
11999#[test]
12000#[ignore] // This test passes under all normal builds. However
12001 // it triggers a stack use-after-return in older versions of
12002 // libclang which is only detected under ASAN (obviously it
12003 // sometimes causes crashes the rest of the time).
12004 // This UaR does not occur when the same code is processed
12005 // with a HEAD version of clang itself as of June 2022. This
12006 // may mean that the UaR has been fixed in later versions of
12007 // the clang code, or that it only occurs when the code is used
12008 // in a libclang context (not a plain clang compilation context).
12009 // If the problem recurs, we should work out which of these is
12010 // the case.
12011fn test_issue_1125() {
12012 let hdr = indoc! {"
12013 namespace {
12014 namespace {
12015 template <class a> class b {
12016 typedef a c;
12017 struct {
12018 c : sizeof(c);
12019 };
12020 };
12021 } // namespace
12022 } // namespace
12023 "};
12024 run_test_ex(
12025 "",
12026 hdr,
12027 quote! {},
12028 quote! {
12029 generate_all!()
12030 },
12031 make_cpp17_adder(),
12032 None,
12033 None,
12034 );
12035}
12036
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070012037#[test]
12038fn test_issue_1143() {
12039 let hdr = indoc! {
12040 "namespace mapnik {
12041 class Map {
12042 public:
12043 int &a(long);
12044 };
12045 }"
12046 };
12047
12048 run_test("", hdr, quote! {}, &["mapnik::Map"], &[]);
12049}
12050
12051#[test]
12052fn test_issue_1170() {
12053 let hdr = indoc! {
12054 "#include <vector>
12055 struct a {
12056 enum b {} c;
12057 } Loc;
12058 struct Arch {
12059 std::vector<a> d();
12060 } DeterministicRNG;"
12061 };
12062 run_test("", hdr, quote! {}, &["Arch"], &[]);
12063}
12064
12065// https://github.com/google/autocxx/issues/774
12066#[test]
12067fn test_virtual_methods() {
12068 let hdr = indoc! {"
12069 #include <cstdint>
12070 #include <memory>
12071 class Base {
12072 public:
12073 Base() {}
12074 virtual ~Base() {}
12075
12076 virtual int a() = 0;
12077
12078 virtual void b(int) = 0;
12079 virtual void b(bool) = 0;
12080
12081 virtual int c() const = 0;
12082 virtual int c() = 0;
12083 };
12084 class FullyDefined : public Base {
12085 public:
12086 int a() { return 0; }
12087
12088 void b(int) { }
12089 void b(bool) { }
12090
12091 int c() const { return 1; }
12092 int c() { return 2; }
12093 };
12094 class Partial1 : public Base {
12095 public:
12096 int a() { return 0; }
12097
12098 void b(bool) {}
12099 };
12100
12101 class Partial2 : public Base {
12102 public:
12103 int a() { return 0; }
12104
12105 void b(int) { }
12106 void b(bool) { }
12107
12108 int c() const { return 1; }
12109 };
12110
12111 class Partial3 : public Base {
12112 public:
12113 int a() { return 0; }
12114
12115 void b(int) { }
12116
12117 int c() const { return 1; }
12118 int c() { return 2; }
12119 };
12120
12121 class Partial4 : public Base {
12122 public:
12123 int a() { return 0; }
12124
12125 void b(int) { }
12126 void b(bool) = 0;
12127
12128 int c() const { return 1; }
12129 int c() { return 2; }
12130 };
12131
12132 // TODO: currently this class cannot be detected as virtual as there
12133 // is no metadata captured to show that this destructor is virtual
12134 // uncommenting this (as well as corresponding sections below) gives a
12135 // 'instantiation of abstract class' error.
12136 // class Partial5 : public Base {
12137 // public:
12138 // ~Partial5() = 0;
12139
12140 // int a() { return 0; }
12141
12142 // void b(int) { }
12143 // void b(bool) { }
12144
12145 // int c() const { return 1; }
12146 // int c() { return 2; }
12147 // };
12148
12149 "};
12150 let rs = quote! {
12151 static_assertions::assert_impl_all!(ffi::FullyDefined: moveit::CopyNew);
12152 static_assertions::assert_not_impl_any!(ffi::Partial1: moveit::CopyNew);
12153 static_assertions::assert_not_impl_any!(ffi::Partial2: moveit::CopyNew);
12154 static_assertions::assert_not_impl_any!(ffi::Partial3: moveit::CopyNew);
12155 static_assertions::assert_not_impl_any!(ffi::Partial4: moveit::CopyNew);
12156 // static_assertions::assert_not_impl_any!(ffi::Partial5: moveit::CopyNew);
12157 let _c1 = ffi::FullyDefined::new().within_unique_ptr();
12158 };
12159 run_test(
12160 "",
12161 hdr,
12162 rs,
12163 &[
12164 "FullyDefined",
12165 "Partial1",
12166 "Partial2",
12167 "Partial3",
12168 "Partial4",
12169 // "Partial5"
12170 ],
12171 &[],
12172 );
12173}
12174
12175#[test]
12176fn test_issue_1192() {
12177 let hdr = indoc! {
12178 "#include <vector>
12179 #include <cstdint>
12180 template <typename B>
12181 struct A {
12182 B a;
12183 };
12184 struct VecThingy {
12185 A<uint32_t> contents[2];
12186 };
12187 struct MyStruct {
12188 VecThingy vec;
12189 };"
12190 };
12191 run_test_ex(
12192 "",
12193 hdr,
12194 quote! {},
12195 quote! {
12196
12197 extern_cpp_type!("VecThingy", crate::VecThingy)
12198 pod!("VecThingy")
12199
12200 generate_pod!("MyStruct")
12201 },
12202 None,
12203 None,
12204 Some(quote! {
12205 // VecThingy isn't necessarily 128 bits long.
12206 // This test doesn't actually allocate one.
12207 #[repr(transparent)]
12208 pub struct VecThingy(pub u128);
12209
12210 unsafe impl cxx::ExternType for VecThingy {
12211 type Id = cxx::type_id!("VecThingy");
12212 type Kind = cxx::kind::Trivial;
12213 }
12214 }),
12215 );
12216}
12217
12218#[test]
12219fn test_issue_1214() {
12220 let hdr = indoc! {"
12221 #include <cstdint>
12222 enum class C: uint16_t {
12223 A,
12224 B,
12225 };
12226 "};
12227 run_test("", hdr, quote! {}, &["C"], &[]);
12228}
12229
12230#[test]
12231fn test_issue_1229() {
12232 let hdr = indoc! {"
12233 struct Thing {
12234 float id;
12235
12236 Thing(float id) : id(id) {}
12237 };
12238
12239 struct Item {
12240 float id;
12241
12242 Item(float id) : id(id) {}
12243 };
12244 "};
12245 let hexathorpe = Token![#](Span::call_site());
12246 let rs = quote! {
12247 use autocxx::WithinUniquePtr;
12248
12249 autocxx::include_cpp! {
12250 #hexathorpe include "input.h"
12251 name!(thing)
12252 safety!(unsafe)
12253 generate!("Thing")
12254 }
12255 autocxx::include_cpp! {
12256 #hexathorpe include "input.h"
12257 name!(item)
12258 safety!(unsafe)
12259 generate!("Item")
12260 }
12261
12262 fn main() {
12263 let _thing = thing::Thing::new(15.).within_unique_ptr();
12264 let _item = item::Item::new(15.).within_unique_ptr();
12265 }
12266 };
12267
12268 do_run_test_manual("", hdr, rs, None, None).unwrap();
12269}
12270
12271#[test]
12272#[ignore] // https://github.com/google/autocxx/issues/1265
12273fn test_issue_1265() {
12274 let hdr = indoc! {"
12275 #include <string>
12276
12277 class Test
12278 {
12279 public:
12280 explicit Test(std::string string)
12281 : string(std::move(string))
12282 {
12283 }
12284
12285 Test() = delete;
12286
12287 [[nodiscard]] auto get_string() const -> std::string const& { return this->string; }
12288
12289 private:
12290 std::string string;
12291 };
12292 "};
12293 run_test_ex(
12294 "",
12295 hdr,
12296 quote! {
12297 run();
12298 },
12299 directives_from_lists(&["Test"], &[], None),
12300 None,
12301 None,
12302 Some(quote! {
12303 fn run() {
12304 let str0 = "string";
12305 let str1 = "another string";
12306 let ptr0 = UniquePtr::emplace(ffi::Test::new(str0));
12307 let ptr1 = UniquePtr::emplace(ffi::Test::new(str1));
12308 println!("0: {}", ptr0.get_string());
12309 println!("1: {}", ptr1.get_string());
12310 moveit!(let mut ref0 = &move *ptr0);
12311 moveit!(let mut ref1 = &move *ptr1);
12312 println!("0: {}", ref0.get_string());
12313 println!("1: {}", ref1.get_string());
12314 println!("swap");
12315 core::mem::swap(&mut *ref0, &mut *ref1);
12316 println!("0: {}", ref0.get_string());
12317 println!("1: {}", ref1.get_string());
12318 }
12319 }),
12320 )
12321}
12322
12323#[test]
12324fn test_ignore_va_list() {
12325 let hdr = indoc! {"
12326 #include <stdarg.h>
12327 class A {
12328 public:
12329 A() {}
12330 void fn(va_list) {}
12331 };
12332 "};
12333 let rs = quote! {};
12334 run_test("", hdr, rs, &["A"], &[]);
12335}
12336
James Kuszmaul850a4752024-02-14 20:27:12 -080012337#[test]
12338fn test_badly_named_alloc() {
12339 let hdr = indoc! {"
12340 #include <stdarg.h>
12341 class A {
12342 public:
12343 void alloc();
12344 };
12345 "};
12346 let rs = quote! {};
12347 run_test("", hdr, rs, &["A"], &[]);
12348}
12349
12350#[test]
12351fn test_cpp_union_pod() {
12352 let hdr = indoc! {"
12353 typedef unsigned long long UInt64_t;
12354 struct ManagedPtr_t_;
12355 typedef struct ManagedPtr_t_ ManagedPtr_t;
12356
12357 typedef int (*ManagedPtr_ManagerFunction_t)(
12358 ManagedPtr_t *managedPtr,
12359 const ManagedPtr_t *srcPtr,
12360 int operation);
12361
12362 typedef union {
12363 int intValue;
12364 void *ptr;
12365 } ManagedPtr_t_data_;
12366
12367 struct ManagedPtr_t_ {
12368 void *pointer;
12369 ManagedPtr_t_data_ userData[4];
12370 ManagedPtr_ManagerFunction_t manager;
12371 };
12372
12373 typedef struct CorrelationId_t_ {
12374 unsigned int size : 8;
12375 unsigned int valueType : 4;
12376 unsigned int classId : 16;
12377 unsigned int reserved : 4;
12378
12379 union {
12380 UInt64_t intValue;
12381 ManagedPtr_t ptrValue;
12382 } value;
12383 } CorrelationId_t;
12384 "};
12385 run_test("", hdr, quote! {}, &["CorrelationId_t_"], &[]);
12386 run_test_expect_fail("", hdr, quote! {}, &[], &["CorrelationId_t_"]);
12387}
12388
Brian Silverman4e662aa2022-05-11 23:10:19 -070012389// Yet to test:
12390// - Ifdef
12391// - Out param pointers
12392// - ExcludeUtilities
12393// - Struct fields which are typedefs
12394// Negative tests:
12395// - Private methods
12396// - Private fields